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 <sys/syslog.h>
51 #include <sys/sysctl.h>
53 #include "IOServicePrivate.h" // _IOServiceInterestNotifier
54 #include "IOServicePMPrivate.h"
57 #include <mach/shared_region.h>
60 #if defined(__i386__) || defined(__x86_64__)
62 #include "IOPMrootDomainInternal.h"
66 #define kIOPMrootDomainClass "IOPMrootDomain"
67 #define LOG_PREFIX "PMRD: "
70 do { kprintf(LOG_PREFIX x); IOLog(x); } while (false)
73 do { kprintf(LOG_PREFIX x); } while (false)
75 #define DLOG(x...) do { \
76 if (kIOLogPMRootDomain & gIOKitDebug) \
77 kprintf(LOG_PREFIX x); } while (false)
81 #define CHECK_THREAD_CONTEXT
82 #ifdef CHECK_THREAD_CONTEXT
83 static IOWorkLoop
* gIOPMWorkLoop
= 0;
84 #define ASSERT_GATED() \
86 if (gIOPMWorkLoop && gIOPMWorkLoop->inGate() != true) { \
87 panic("RootDomain: not inside PM gate"); \
91 #define ASSERT_GATED()
92 #endif /* CHECK_THREAD_CONTEXT */
95 (((_pendingCapability & (c)) == 0) && \
96 ((_currentCapability & (c)) != 0))
99 (((_currentCapability & (c)) == 0) && \
100 ((_pendingCapability & (c)) != 0))
102 #define CAP_CHANGE(c) \
103 (((_currentCapability ^ _pendingCapability) & (c)) != 0)
105 #define CAP_CURRENT(c) \
106 ((_currentCapability & (c)) != 0)
108 #define CAP_HIGHEST(c) \
109 ((_highestCapability & (c)) != 0)
111 #define DARK_TO_FULL_EVALUATE_CLAMSHELL 0
113 // Event types for IOPMPowerStateQueue::submitPowerEvent()
115 kPowerEventFeatureChanged
= 1, // 1
116 kPowerEventReceivedPowerNotification
, // 2
117 kPowerEventSystemBootCompleted
, // 3
118 kPowerEventSystemShutdown
, // 4
119 kPowerEventUserDisabledSleep
, // 5
120 kPowerEventRegisterSystemCapabilityClient
, // 6
121 kPowerEventRegisterKernelCapabilityClient
, // 7
122 kPowerEventPolicyStimulus
, // 8
123 kPowerEventAssertionCreate
, // 9
124 kPowerEventAssertionRelease
, // 10
125 kPowerEventAssertionSetLevel
, // 11
126 kPowerEventQueueSleepWakeUUID
, // 12
127 kPowerEventPublishSleepWakeUUID
// 13
130 // For evaluatePolicy()
131 // List of stimuli that affects the root domain policy.
133 kStimulusDisplayWranglerSleep
, // 0
134 kStimulusDisplayWranglerWake
, // 1
135 kStimulusAggressivenessChanged
, // 2
136 kStimulusDemandSystemSleep
, // 3
137 kStimulusAllowSystemSleepChanged
, // 4
138 kStimulusDarkWakeActivityTickle
, // 5
139 kStimulusDarkWakeEntry
, // 6
140 kStimulusDarkWakeReentry
, // 7
141 kStimulusDarkWakeEvaluate
// 8
145 IOReturn
OSKextSystemSleepOrWake( UInt32
);
148 static void idleSleepTimerExpired( thread_call_param_t
, thread_call_param_t
);
149 static void notifySystemShutdown( IOService
* root
, unsigned long event
);
150 static void handleAggressivesFunction( thread_call_param_t
, thread_call_param_t
);
151 static void pmEventTimeStamp(uint64_t *recordTS
);
153 // "IOPMSetSleepSupported" callPlatformFunction name
154 static const OSSymbol
*sleepSupportedPEFunction
= NULL
;
155 static const OSSymbol
*sleepMessagePEFunction
= NULL
;
157 #define kIOSleepSupportedKey "IOSleepSupported"
158 #define kIOPMSystemCapabilitiesKey "System Capabilities"
160 #define kRD_AllPowerSources (kIOPMSupportedOnAC \
161 | kIOPMSupportedOnBatt \
162 | kIOPMSupportedOnUPS)
166 // not idle around autowake time, secs
167 kAutoWakePreWindow
= 45,
168 kAutoWakePostWindow
= 15
171 #define kLocalEvalClamshellCommand (1 << 15)
181 #define ON_POWER kIOPMPowerOn
182 #define RESTART_POWER kIOPMRestart
183 #define SLEEP_POWER kIOPMAuxPowerOn
185 static IOPMPowerState ourPowerStates
[NUM_POWER_STATES
] =
187 {1, 0, 0, 0, 0,0,0,0,0,0,0,0},
188 {1, kIOPMRestartCapability
, kIOPMRestart
, RESTART_POWER
, 0,0,0,0,0,0,0,0},
189 {1, kIOPMSleepCapability
, kIOPMSleep
, SLEEP_POWER
, 0,0,0,0,0,0,0,0},
190 {1, kIOPMPowerOn
, kIOPMPowerOn
, ON_POWER
, 0,0,0,0,0,0,0,0}
193 #define kIOPMRootDomainWakeTypeMaintenance "Maintenance"
194 #define kIOPMRootDomainWakeTypeSleepTimer "SleepTimer"
195 #define kIOPMrootDomainWakeTypeLowBattery "LowBattery"
196 #define kIOPMRootDomainWakeTypeUser "User"
197 #define kIOPMRootDomainWakeTypeAlarm "Alarm"
198 #define kIOPMRootDomainWakeTypeNetwork "Network"
200 // Special interest that entitles the interested client from receiving
201 // all system messages. Only used by powerd.
203 #define kIOPMSystemCapabilityInterest "IOPMSystemCapabilityInterest"
208 #define AGGRESSIVES_LOCK() IOLockLock(featuresDictLock)
209 #define AGGRESSIVES_UNLOCK() IOLockUnlock(featuresDictLock)
211 #define kAggressivesMinValue 1
214 kAggressivesStateBusy
= 0x01,
215 kAggressivesStateQuickSpindown
= 0x02
218 struct AggressivesRecord
{
224 struct AggressivesRequest
{
230 AggressivesRecord record
;
235 kAggressivesRequestTypeService
= 1,
236 kAggressivesRequestTypeRecord
240 kAggressivesOptionSynchronous
= 0x00000001,
241 kAggressivesOptionQuickSpindownEnable
= 0x00000100,
242 kAggressivesOptionQuickSpindownDisable
= 0x00000200,
243 kAggressivesOptionQuickSpindownMask
= 0x00000300
247 kAggressivesRecordFlagModified
= 0x00000001,
248 kAggressivesRecordFlagMinValue
= 0x00000002
253 kDarkWakeFlagHIDTickleEarly
= 0x01, // hid tickle before gfx suppression
254 kDarkWakeFlagHIDTickleLate
= 0x02, // hid tickle after gfx suppression
255 kDarkWakeFlagHIDTickleNone
= 0x03, // hid tickle is not posted
256 kDarkWakeFlagHIDTickleMask
= 0x03,
257 kDarkWakeFlagIgnoreDiskIOInDark
= 0x04, // ignore disk idle in DW
258 kDarkWakeFlagIgnoreDiskIOAlways
= 0x08, // always ignore disk idle
259 kDarkWakeFlagIgnoreDiskIOMask
= 0x0C,
260 kDarkWakeFlagAlarmIsDark
= 0x0100
263 static IOPMrootDomain
* gRootDomain
;
264 static IONotifier
* gSysPowerDownNotifier
= 0;
265 static UInt32 gSleepOrShutdownPending
= 0;
266 static UInt32 gWillShutdown
= 0;
267 static UInt32 gPagingOff
= 0;
268 static UInt32 gSleepWakeUUIDIsSet
= false;
269 static uint32_t gAggressivesState
= 0;
270 static uint32_t gDarkWakeFlags
= kDarkWakeFlagHIDTickleNone
;
272 struct timeval gIOLastSleepTime
;
273 struct timeval gIOLastWakeTime
;
275 // Constants used as arguments to IOPMrootDomain::informCPUStateChange
276 #define kCPUUnknownIndex 9999999
283 const OSSymbol
*gIOPMStatsApplicationResponseTimedOut
;
284 const OSSymbol
*gIOPMStatsApplicationResponseCancel
;
285 const OSSymbol
*gIOPMStatsApplicationResponseSlow
;
289 * Opaque handle passed to clients of registerPMSettingController()
291 class PMSettingHandle
: public OSObject
293 OSDeclareFinalStructors( PMSettingHandle
)
294 friend class PMSettingObject
;
297 PMSettingObject
*pmso
;
303 * Internal object to track each PM setting controller
305 class PMSettingObject
: public OSObject
307 OSDeclareFinalStructors( PMSettingObject
)
308 friend class IOPMrootDomain
;
311 queue_head_t calloutQueue
;
313 IOPMrootDomain
*parent
;
314 PMSettingHandle
*pmsh
;
315 IOPMSettingControllerCallback func
;
318 uint32_t *publishedFeatureID
;
319 uint32_t settingCount
;
325 static PMSettingObject
*pmSettingObject(
326 IOPMrootDomain
*parent_arg
,
327 IOPMSettingControllerCallback handler_arg
,
328 OSObject
*target_arg
,
329 uintptr_t refcon_arg
,
330 uint32_t supportedPowerSources
,
331 const OSSymbol
*settings
[],
332 OSObject
**handle_obj
);
334 void dispatchPMSetting(const OSSymbol
*type
, OSObject
*object
);
335 void clientHandleFreed(void);
338 struct PMSettingCallEntry
{
343 #define PMSETTING_LOCK() IOLockLock(settingsCtrlLock)
344 #define PMSETTING_UNLOCK() IOLockUnlock(settingsCtrlLock)
345 #define PMSETTING_WAIT(p) IOLockSleep(settingsCtrlLock, p, THREAD_UNINT)
346 #define PMSETTING_WAKEUP(p) IOLockWakeup(settingsCtrlLock, p, true)
348 //*********************************************************************************
349 //*********************************************************************************
350 //*********************************************************************************
352 /* @class IOPMTimeline
353 * @astract Tracks & records PM activity.
354 * @discussion Intended for use only as a helper-class to IOPMrootDomain.
355 * Do not subclass or directly invoke iOPMTimeline
357 class IOPMTimeline
: public OSObject
359 OSDeclareDefaultStructors( IOPMTimeline
);
362 static IOPMTimeline
* timeline(IOPMrootDomain
*root_domain
);
364 bool setProperties(OSDictionary
*d
);
365 OSDictionary
*copyInfoDictionary(void);
367 IOReturn
recordSystemPowerEvent( PMEventDetails
*details
);
369 IOReturn
recordDetailedPowerEvent( PMEventDetails
*details
);
371 IOMemoryDescriptor
*getPMTraceMemoryDescriptor();
373 uint32_t getNumEventsLoggedThisPeriod();
374 void setNumEventsLoggedThisPeriod(uint32_t newCount
);
375 bool isSleepCycleInProgress();
376 void setSleepCycleInProgressFlag(bool flag
);
381 void setEventsTrackedCount(uint32_t newTracked
);
382 void setEventsRecordingLevel(uint32_t eventsTrackedBits
);
383 static uint32_t _atomicIndexIncrement(uint32_t *index
, uint32_t limit
);
386 kPMTimelineRecordTardyDrivers
= 1 << 0,
387 kPMTmielineRecordSystemEvents
= 1 << 1,
388 kPMTimelineRecordAllDrivers
= 1 << 2,
389 kPMTimelineRecordOff
= 0,
390 kPMTimelineRecordDefault
= 3,
391 kPMTimelineRecordDebug
= 7
394 // eventsRecordingLevel is a bitfield defining which PM driver events will get logged
395 // into the PM buffer.
396 uint32_t eventsRecordingLevel
;
398 // pmTraceMemoryDescriptor represents the memory block that IOPMTimeLine records PM trace points into.
399 IOBufferMemoryDescriptor
*pmTraceMemoryDescriptor
;
401 // Pointer to starting address in pmTraceMemoryDescriptor
402 IOPMSystemEventRecord
*traceBuffer
;
403 IOPMTraceBufferHeader
*hdr
;
405 uint16_t systemState
;
408 IOPMrootDomain
*owner
;
410 uint32_t numEventsLoggedThisPeriod
;
411 bool sleepCycleInProgress
;
414 OSDefineMetaClassAndStructors( IOPMTimeline
, OSObject
)
418 * Internal helper object for logging trace points to RTC
419 * IOPMrootDomain and only IOPMrootDomain should instantiate
420 * exactly one of these.
423 typedef void (*IOPMTracePointHandler
)(
424 void * target
, uint32_t code
, uint32_t data
);
426 class PMTraceWorker
: public OSObject
428 OSDeclareDefaultStructors(PMTraceWorker
)
430 typedef enum { kPowerChangeStart
, kPowerChangeCompleted
} change_t
;
432 static PMTraceWorker
*tracer( IOPMrootDomain
* );
433 void tracePCIPowerChange(change_t
, IOService
*, uint32_t, uint32_t);
434 void tracePoint(uint8_t phase
);
435 void tracePoint(uint8_t phase
, uint8_t data8
);
436 void traceDetail(uint32_t detail
);
437 void traceLoginWindowPhase(uint8_t phase
);
438 int recordTopLevelPCIDevice(IOService
*);
439 void RTC_TRACE(void);
440 virtual bool serialize(OSSerialize
*s
) const;
442 IOPMTracePointHandler tracePointHandler
;
443 void * tracePointTarget
;
445 IOPMrootDomain
*owner
;
446 IOLock
*pciMappingLock
;
447 OSArray
*pciDeviceBitMappings
;
449 uint8_t addedToRegistry
;
451 uint8_t loginWindowPhase
;
453 uint32_t traceData32
;
457 * PMAssertionsTracker
458 * Tracks kernel and user space PM assertions
460 class PMAssertionsTracker
: public OSObject
462 OSDeclareFinalStructors(PMAssertionsTracker
)
464 static PMAssertionsTracker
*pmAssertionsTracker( IOPMrootDomain
* );
466 IOReturn
createAssertion(IOPMDriverAssertionType
, IOPMDriverAssertionLevel
, IOService
*, const char *, IOPMDriverAssertionID
*);
467 IOReturn
releaseAssertion(IOPMDriverAssertionID
);
468 IOReturn
setAssertionLevel(IOPMDriverAssertionID
, IOPMDriverAssertionLevel
);
469 IOReturn
setUserAssertionLevels(IOPMDriverAssertionType
);
471 OSArray
*copyAssertionsArray(void);
472 IOPMDriverAssertionType
getActivatedAssertions(void);
473 IOPMDriverAssertionLevel
getAssertionLevel(IOPMDriverAssertionType
);
475 IOReturn
handleCreateAssertion(OSData
*);
476 IOReturn
handleReleaseAssertion(IOPMDriverAssertionID
);
477 IOReturn
handleSetAssertionLevel(IOPMDriverAssertionID
, IOPMDriverAssertionLevel
);
478 IOReturn
handleSetUserAssertionLevels(void * arg0
);
479 void publishProperties(void);
483 IOPMDriverAssertionID id
;
484 IOPMDriverAssertionType assertionBits
;
485 uint64_t createdTime
;
486 uint64_t modifiedTime
;
487 const OSSymbol
*ownerString
;
488 IOService
*ownerService
;
489 IOPMDriverAssertionLevel level
;
492 uint32_t tabulateProducerCount
;
493 uint32_t tabulateConsumerCount
;
495 PMAssertStruct
*detailsForID(IOPMDriverAssertionID
, int *);
498 IOPMrootDomain
*owner
;
499 OSArray
*assertionsArray
;
500 IOLock
*assertionsArrayLock
;
501 IOPMDriverAssertionID issuingUniqueID
__attribute__((aligned(8))); /* aligned for atomic access */
502 IOPMDriverAssertionType assertionsKernel
;
503 IOPMDriverAssertionType assertionsUser
;
504 IOPMDriverAssertionType assertionsCombined
;
507 OSDefineMetaClassAndFinalStructors(PMAssertionsTracker
, OSObject
);
511 * Internal helper object for Shutdown/Restart notifications.
513 #define kPMHaltMaxWorkers 8
514 #define kPMHaltTimeoutMS 100
516 class PMHaltWorker
: public OSObject
518 OSDeclareFinalStructors( PMHaltWorker
)
521 IOService
* service
; // service being worked on
522 AbsoluteTime startTime
; // time when work started
523 int depth
; // work on nubs at this PM-tree depth
524 int visits
; // number of nodes visited (debug)
526 bool timeout
; // service took too long
528 static PMHaltWorker
* worker( void );
529 static void main( void * arg
, wait_result_t waitResult
);
530 static void work( PMHaltWorker
* me
);
531 static void checkTimeout( PMHaltWorker
* me
, AbsoluteTime
* now
);
532 virtual void free( void );
535 OSDefineMetaClassAndFinalStructors( PMHaltWorker
, OSObject
)
538 #define super IOService
539 OSDefineMetaClassAndFinalStructors(IOPMrootDomain
, IOService
)
541 static void IOPMRootDomainWillShutdown(void)
543 if (OSCompareAndSwap(0, 1, &gWillShutdown
))
545 OSKext::willShutdown();
546 for (int i
= 0; i
< 100; i
++)
548 if (OSCompareAndSwap(0, 1, &gSleepOrShutdownPending
)) break;
556 IONotifier
* registerSleepWakeInterest(IOServiceInterestHandler handler
, void * self
, void * ref
)
558 return gRootDomain
->registerInterest( gIOGeneralInterest
, handler
, self
, ref
);
561 IONotifier
* registerPrioritySleepWakeInterest(IOServiceInterestHandler handler
, void * self
, void * ref
)
563 return gRootDomain
->registerInterest( gIOPriorityPowerStateInterest
, handler
, self
, ref
);
566 IOReturn
acknowledgeSleepWakeNotification(void * PMrefcon
)
568 return gRootDomain
->allowPowerChange ( (unsigned long)PMrefcon
);
571 IOReturn
vetoSleepWakeNotification(void * PMrefcon
)
573 return gRootDomain
->cancelPowerChange ( (unsigned long)PMrefcon
);
576 IOReturn
rootDomainRestart ( void )
578 return gRootDomain
->restartSystem();
581 IOReturn
rootDomainShutdown ( void )
583 return gRootDomain
->shutdownSystem();
586 void IOSystemShutdownNotification(void)
588 IOPMRootDomainWillShutdown();
589 if (OSCompareAndSwap(0, 1, &gPagingOff
))
592 gRootDomain
->handlePlatformHaltRestart(kPEPagingOff
);
597 int sync_internal(void);
601 A device is always in the highest power state which satisfies its driver,
602 its policy-maker, and any power children it has, but within the constraint
603 of the power state provided by its parent. The driver expresses its desire by
604 calling changePowerStateTo(), the policy-maker expresses its desire by calling
605 changePowerStateToPriv(), and the children express their desires by calling
606 requestPowerDomainState().
608 The Root Power Domain owns the policy for idle and demand sleep for the system.
609 It is a power-managed IOService just like the others in the system.
610 It implements several power states which map to what we see as Sleep and On.
612 The sleep policy is as follows:
613 1. Sleep is prevented if the case is open so that nobody will think the machine
614 is off and plug/unplug cards.
615 2. Sleep is prevented if the sleep timeout slider in the prefs panel is zero.
616 3. System cannot Sleep if some object in the tree is in a power state marked
617 kIOPMPreventSystemSleep.
619 These three conditions are enforced using the "driver clamp" by calling
620 changePowerStateTo(). For example, if the case is opened,
621 changePowerStateTo(ON_STATE) is called to hold the system on regardless
622 of the desires of the children of the root or the state of the other clamp.
624 Demand Sleep is initiated by pressing the front panel power button, closing
625 the clamshell, or selecting the menu item. In this case the root's parent
626 actually initiates the power state change so that the root domain has no
627 choice and does not give applications the opportunity to veto the change.
629 Idle Sleep occurs if no objects in the tree are in a state marked
630 kIOPMPreventIdleSleep. When this is true, the root's children are not holding
631 the root on, so it sets the "policy-maker clamp" by calling
632 changePowerStateToPriv(ON_STATE) to hold itself on until the sleep timer expires.
633 This timer is set for the difference between the sleep timeout slider and the
634 display dim timeout slider. When the timer expires, it releases its clamp and
635 now nothing is holding it awake, so it falls asleep.
637 Demand sleep is prevented when the system is booting. When preferences are
638 transmitted by the loginwindow at the end of boot, a flag is cleared,
639 and this allows subsequent Demand Sleep.
642 //******************************************************************************
644 IOPMrootDomain
* IOPMrootDomain::construct( void )
646 IOPMrootDomain
*root
;
648 root
= new IOPMrootDomain
;
655 //******************************************************************************
657 static void disk_sync_callout( thread_call_param_t p0
, thread_call_param_t p1
)
659 IOService
* rootDomain
= (IOService
*) p0
;
660 uint32_t notifyRef
= (uint32_t)(uintptr_t) p1
;
661 uint32_t powerState
= rootDomain
->getPowerState();
663 DLOG("disk_sync_callout ps=%u\n", powerState
);
665 if (ON_STATE
== powerState
)
668 IOHibernateSystemSleep();
675 IOHibernateSystemPostWake();
679 rootDomain
->allowPowerChange(notifyRef
);
680 DLOG("disk_sync_callout finish\n");
683 //******************************************************************************
685 static UInt32
computeDeltaTimeMS( const AbsoluteTime
* startTime
)
687 AbsoluteTime endTime
;
690 clock_get_uptime(&endTime
);
691 if (CMP_ABSOLUTETIME(&endTime
, startTime
) > 0)
693 SUB_ABSOLUTETIME(&endTime
, startTime
);
694 absolutetime_to_nanoseconds(endTime
, &nano
);
697 return (UInt32
)(nano
/ 1000000ULL);
700 //******************************************************************************
703 sysctl_sleepwaketime SYSCTL_HANDLER_ARGS
705 struct timeval
*swt
= (struct timeval
*)arg1
;
706 struct proc
*p
= req
->p
;
709 return sysctl_io_opaque(req
, swt
, sizeof(*swt
), NULL
);
710 } else if(proc_is64bit(p
)) {
711 struct user64_timeval t
;
712 t
.tv_sec
= swt
->tv_sec
;
713 t
.tv_usec
= swt
->tv_usec
;
714 return sysctl_io_opaque(req
, &t
, sizeof(t
), NULL
);
716 struct user32_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
);
723 static SYSCTL_PROC(_kern
, OID_AUTO
, sleeptime
,
724 CTLTYPE_STRUCT
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
725 &gIOLastSleepTime
, 0, sysctl_sleepwaketime
, "S,timeval", "");
727 static SYSCTL_PROC(_kern
, OID_AUTO
, waketime
,
728 CTLTYPE_STRUCT
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
729 &gIOLastWakeTime
, 0, sysctl_sleepwaketime
, "S,timeval", "");
734 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
736 int new_value
, changed
;
737 int error
= sysctl_io_number(req
, gWillShutdown
, sizeof(int), &new_value
, &changed
);
739 if (!gWillShutdown
&& (new_value
== 1)) {
740 IOPMRootDomainWillShutdown();
747 static SYSCTL_PROC(_kern
, OID_AUTO
, willshutdown
,
748 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
749 0, 0, sysctl_willshutdown
, "I", "");
754 sysctl_progressmeterenable
755 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
758 int new_value
, changed
;
760 error
= sysctl_io_number(req
, vc_progress_meter_enable
, sizeof(int), &new_value
, &changed
);
763 vc_enable_progressmeter(new_value
);
770 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
773 int new_value
, changed
;
775 error
= sysctl_io_number(req
, vc_progress_meter_value
, sizeof(int), &new_value
, &changed
);
778 vc_set_progressmeter(new_value
);
783 static SYSCTL_PROC(_kern
, OID_AUTO
, progressmeterenable
,
784 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
785 0, 0, sysctl_progressmeterenable
, "I", "");
787 static SYSCTL_PROC(_kern
, OID_AUTO
, progressmeter
,
788 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
789 0, 0, sysctl_progressmeter
, "I", "");
793 static SYSCTL_INT(_debug
, OID_AUTO
, darkwake
, CTLFLAG_RW
, &gDarkWakeFlags
, 0, "");
795 static const OSSymbol
* gIOPMSettingAutoWakeSecondsKey
;
796 static const OSSymbol
* gIOPMSettingDebugWakeRelativeKey
;
797 static const OSSymbol
* gIOPMSettingMaintenanceWakeCalendarKey
;
799 //******************************************************************************
802 //******************************************************************************
804 #define kRootDomainSettingsCount 16
806 bool IOPMrootDomain::start( IOService
* nub
)
808 OSIterator
*psIterator
;
809 OSDictionary
*tmpDict
;
810 IORootParent
* patriarch
;
815 gIOPMSettingAutoWakeSecondsKey
= OSSymbol::withCString(kIOPMSettingAutoWakeSecondsKey
);
816 gIOPMSettingDebugWakeRelativeKey
= OSSymbol::withCString(kIOPMSettingDebugWakeRelativeKey
);
817 gIOPMSettingMaintenanceWakeCalendarKey
=
818 OSSymbol::withCString(kIOPMSettingMaintenanceWakeCalendarKey
);
820 gIOPMStatsApplicationResponseTimedOut
= OSSymbol::withCString(kIOPMStatsResponseTimedOut
);
821 gIOPMStatsApplicationResponseCancel
= OSSymbol::withCString(kIOPMStatsResponseCancel
);
822 gIOPMStatsApplicationResponseSlow
= OSSymbol::withCString(kIOPMStatsResponseSlow
);
824 sleepSupportedPEFunction
= OSSymbol::withCString("IOPMSetSleepSupported");
825 sleepMessagePEFunction
= OSSymbol::withCString("IOPMSystemSleepMessage");
827 const OSSymbol
*settingsArr
[kRootDomainSettingsCount
] =
829 OSSymbol::withCString(kIOPMSettingSleepOnPowerButtonKey
),
830 gIOPMSettingAutoWakeSecondsKey
,
831 OSSymbol::withCString(kIOPMSettingAutoPowerSecondsKey
),
832 OSSymbol::withCString(kIOPMSettingAutoWakeCalendarKey
),
833 OSSymbol::withCString(kIOPMSettingAutoPowerCalendarKey
),
834 gIOPMSettingDebugWakeRelativeKey
,
835 OSSymbol::withCString(kIOPMSettingDebugPowerRelativeKey
),
836 OSSymbol::withCString(kIOPMSettingWakeOnRingKey
),
837 OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey
),
838 OSSymbol::withCString(kIOPMSettingWakeOnClamshellKey
),
839 OSSymbol::withCString(kIOPMSettingWakeOnACChangeKey
),
840 OSSymbol::withCString(kIOPMSettingTimeZoneOffsetKey
),
841 OSSymbol::withCString(kIOPMSettingDisplaySleepUsesDimKey
),
842 OSSymbol::withCString(kIOPMSettingMobileMotionModuleKey
),
843 OSSymbol::withCString(kIOPMSettingGraphicsSwitchKey
),
844 OSSymbol::withCString(kIOPMStateConsoleShutdown
)
847 PE_parse_boot_argn("darkwake", &gDarkWakeFlags
, sizeof(gDarkWakeFlags
));
849 queue_init(&aggressivesQueue
);
850 aggressivesThreadCall
= thread_call_allocate(handleAggressivesFunction
, this);
851 aggressivesData
= OSData::withCapacity(
852 sizeof(AggressivesRecord
) * (kPMLastAggressivenessType
+ 4));
854 featuresDictLock
= IOLockAlloc();
855 settingsCtrlLock
= IOLockAlloc();
856 setPMRootDomain(this);
858 extraSleepTimer
= thread_call_allocate(
859 idleSleepTimerExpired
,
860 (thread_call_param_t
) this);
862 diskSyncCalloutEntry
= thread_call_allocate(
864 (thread_call_param_t
) this);
866 setProperty(kIOSleepSupportedKey
, true);
868 bzero(&pmStats
, sizeof(pmStats
));
870 pmTracer
= PMTraceWorker::tracer(this);
872 pmAssertions
= PMAssertionsTracker::pmAssertionsTracker(this);
874 userDisabledAllSleep
= false;
875 systemBooting
= true;
877 idleSleepTimerPending
= false;
879 clamshellClosed
= false;
880 clamshellExists
= false;
881 clamshellDisabled
= true;
882 acAdaptorConnected
= true;
884 // Set the default system capabilities at boot.
885 _currentCapability
= kIOPMSystemCapabilityCPU
|
886 kIOPMSystemCapabilityGraphics
|
887 kIOPMSystemCapabilityAudio
|
888 kIOPMSystemCapabilityNetwork
;
890 _pendingCapability
= _currentCapability
;
891 _desiredCapability
= _currentCapability
;
892 _highestCapability
= _currentCapability
;
893 setProperty(kIOPMSystemCapabilitiesKey
, _currentCapability
, 64);
895 queuedSleepWakeUUIDString
= NULL
;
896 pmStatsAppResponses
= OSArray::withCapacity(5);
897 _statsNameKey
= OSSymbol::withCString(kIOPMStatsNameKey
);
898 _statsPIDKey
= OSSymbol::withCString(kIOPMStatsPIDKey
);
899 _statsTimeMSKey
= OSSymbol::withCString(kIOPMStatsTimeMSKey
);
900 _statsResponseTypeKey
= OSSymbol::withCString(kIOPMStatsApplicationResponseTypeKey
);
901 _statsMessageTypeKey
= OSSymbol::withCString(kIOPMStatsMessageTypeKey
);
903 idxPMCPUClamshell
= kCPUUnknownIndex
;
904 idxPMCPULimitedPower
= kCPUUnknownIndex
;
906 tmpDict
= OSDictionary::withCapacity(1);
907 setProperty(kRootDomainSupportedFeatures
, tmpDict
);
910 settingsCallbacks
= OSDictionary::withCapacity(1);
912 // Create a list of the valid PM settings that we'll relay to
913 // interested clients in setProperties() => setPMSetting()
914 allowedPMSettings
= OSArray::withObjects(
915 (const OSObject
**)settingsArr
,
916 kRootDomainSettingsCount
,
919 fPMSettingsDict
= OSDictionary::withCapacity(5);
921 PMinit(); // creates gIOPMWorkLoop
923 // Create IOPMPowerStateQueue used to queue external power
924 // events, and to handle those events on the PM work loop.
925 pmPowerStateQueue
= IOPMPowerStateQueue::PMPowerStateQueue(
926 this, OSMemberFunctionCast(IOEventSource::Action
, this,
927 &IOPMrootDomain::dispatchPowerEvent
));
928 getPMworkloop()->addEventSource(pmPowerStateQueue
);
929 #ifdef CHECK_THREAD_CONTEXT
930 gIOPMWorkLoop
= getPMworkloop();
933 // create our power parent
934 patriarch
= new IORootParent
;
936 patriarch
->attach(this);
937 patriarch
->start(this);
938 patriarch
->addPowerChild(this);
940 registerPowerDriver(this, ourPowerStates
, NUM_POWER_STATES
);
941 changePowerStateToPriv(ON_STATE
);
943 if (gIOKitDebug
& (kIOLogDriverPower1
| kIOLogDriverPower2
))
945 // Setup our PM logging & recording code
946 timeline
= IOPMTimeline::timeline(this);
948 OSDictionary
*tlInfo
= timeline
->copyInfoDictionary();
952 setProperty(kIOPMTimelineDictionaryKey
, tlInfo
);
958 // install power change handler
959 gSysPowerDownNotifier
= registerPrioritySleepWakeInterest( &sysPowerDownHandler
, this, 0);
962 // Register for a notification when IODisplayWrangler is published
963 if ((tmpDict
= serviceMatching("IODisplayWrangler")))
965 _displayWranglerNotifier
= addMatchingNotification(
966 gIOPublishNotification
, tmpDict
,
967 (IOServiceMatchingNotificationHandler
) &displayWranglerMatchPublished
,
973 const OSSymbol
*ucClassName
= OSSymbol::withCStringNoCopy("RootDomainUserClient");
974 setProperty(gIOUserClientClassKey
, (OSObject
*) ucClassName
);
975 ucClassName
->release();
977 // IOBacklightDisplay can take a long time to load at boot, or it may
978 // not load at all if you're booting with clamshell closed. We publish
979 // 'DisplayDims' here redundantly to get it published early and at all.
980 psIterator
= getMatchingServices( serviceMatching("IOPMPowerSource") );
981 if( psIterator
&& psIterator
->getNextObject() )
983 // There's at least one battery on the system, so we publish
984 // 'DisplayDims' support for the LCD.
985 publishFeature("DisplayDims");
988 psIterator
->release();
991 sysctl_register_oid(&sysctl__kern_sleeptime
);
992 sysctl_register_oid(&sysctl__kern_waketime
);
993 sysctl_register_oid(&sysctl__kern_willshutdown
);
995 sysctl_register_oid(&sysctl__kern_progressmeterenable
);
996 sysctl_register_oid(&sysctl__kern_progressmeter
);
997 #endif /* !CONFIG_EMBEDDED */
1000 IOHibernateSystemInit(this);
1003 registerService(); // let clients find us
1008 //******************************************************************************
1011 // Receive a setProperty call
1012 // The "System Boot" property means the system is completely booted.
1013 //******************************************************************************
1015 IOReturn
IOPMrootDomain::setProperties( OSObject
* props_obj
)
1017 IOReturn return_value
= kIOReturnSuccess
;
1018 OSDictionary
*dict
= OSDynamicCast(OSDictionary
, props_obj
);
1026 const OSSymbol
*publish_simulated_battery_string
= OSSymbol::withCString("SoftwareSimulatedBatteries");
1027 const OSSymbol
*boot_complete_string
= OSSymbol::withCString("System Boot Complete");
1028 const OSSymbol
*sys_shutdown_string
= OSSymbol::withCString("System Shutdown");
1029 const OSSymbol
*stall_halt_string
= OSSymbol::withCString("StallSystemAtHalt");
1030 const OSSymbol
*battery_warning_disabled_string
= OSSymbol::withCString("BatteryWarningsDisabled");
1031 const OSSymbol
*idle_seconds_string
= OSSymbol::withCString("System Idle Seconds");
1032 const OSSymbol
*sleepdisabled_string
= OSSymbol::withCString("SleepDisabled");
1033 const OSSymbol
*ondeck_sleepwake_uuid_string
= OSSymbol::withCString(kIOPMSleepWakeUUIDKey
);
1034 const OSSymbol
*loginwindow_tracepoint_string
= OSSymbol::withCString(kIOPMLoginWindowSecurityDebugKey
);
1035 const OSSymbol
*pmTimelineLogging_string
= OSSymbol::withCString(kIOPMTimelineDictionaryKey
);
1037 const OSSymbol
*hibernatemode_string
= OSSymbol::withCString(kIOHibernateModeKey
);
1038 const OSSymbol
*hibernatefile_string
= OSSymbol::withCString(kIOHibernateFileKey
);
1039 const OSSymbol
*hibernatefreeratio_string
= OSSymbol::withCString(kIOHibernateFreeRatioKey
);
1040 const OSSymbol
*hibernatefreetime_string
= OSSymbol::withCString(kIOHibernateFreeTimeKey
);
1045 return_value
= kIOReturnBadArgument
;
1049 if ((b
= OSDynamicCast(OSBoolean
, dict
->getObject(publish_simulated_battery_string
))))
1051 publishResource(publish_simulated_battery_string
, kOSBooleanTrue
);
1054 if ((n
= OSDynamicCast(OSNumber
, dict
->getObject(idle_seconds_string
))))
1056 setProperty(idle_seconds_string
, n
);
1057 idleSeconds
= n
->unsigned32BitValue();
1060 if (boot_complete_string
&& dict
->getObject(boot_complete_string
))
1062 pmPowerStateQueue
->submitPowerEvent( kPowerEventSystemBootCompleted
);
1065 if( battery_warning_disabled_string
&& dict
->getObject(battery_warning_disabled_string
))
1067 setProperty( battery_warning_disabled_string
, dict
->getObject(battery_warning_disabled_string
));
1070 if (pmTimelineLogging_string
&& (d
= OSDynamicCast(OSDictionary
, dict
->getObject(pmTimelineLogging_string
))))
1072 if (timeline
&& timeline
->setProperties(d
))
1074 OSDictionary
*tlInfo
= timeline
->copyInfoDictionary();
1076 setProperty(kIOPMTimelineDictionaryKey
, tlInfo
);
1082 if( sys_shutdown_string
&& (b
= OSDynamicCast(OSBoolean
, dict
->getObject(sys_shutdown_string
))))
1084 pmPowerStateQueue
->submitPowerEvent(kPowerEventSystemShutdown
, (void *) b
);
1087 if( stall_halt_string
&& (b
= OSDynamicCast(OSBoolean
, dict
->getObject(stall_halt_string
))) )
1089 setProperty(stall_halt_string
, b
);
1093 if ( hibernatemode_string
1094 && (n
= OSDynamicCast(OSNumber
, dict
->getObject(hibernatemode_string
))))
1096 setProperty(hibernatemode_string
, n
);
1098 if ( hibernatefreeratio_string
1099 && (n
= OSDynamicCast(OSNumber
, dict
->getObject(hibernatefreeratio_string
))))
1101 setProperty(hibernatefreeratio_string
, n
);
1103 if ( hibernatefreetime_string
1104 && (n
= OSDynamicCast(OSNumber
, dict
->getObject(hibernatefreetime_string
))))
1106 setProperty(hibernatefreetime_string
, n
);
1109 if ( hibernatefile_string
1110 && (str
= OSDynamicCast(OSString
, dict
->getObject(hibernatefile_string
))))
1112 setProperty(hibernatefile_string
, str
);
1116 if( sleepdisabled_string
1117 && (b
= OSDynamicCast(OSBoolean
, dict
->getObject(sleepdisabled_string
))) )
1119 setProperty(sleepdisabled_string
, b
);
1120 pmPowerStateQueue
->submitPowerEvent(kPowerEventUserDisabledSleep
, (void *) b
);
1122 if (ondeck_sleepwake_uuid_string
1123 && (obj
= dict
->getObject(ondeck_sleepwake_uuid_string
)))
1125 if(pmPowerStateQueue
) {
1127 pmPowerStateQueue
->submitPowerEvent(kPowerEventQueueSleepWakeUUID
, (void *)obj
);
1132 if (loginwindow_tracepoint_string
1133 && (n
= OSDynamicCast(OSNumber
, dict
->getObject(loginwindow_tracepoint_string
)))
1136 pmTracer
->traceLoginWindowPhase( n
->unsigned8BitValue() );
1139 if ((b
= OSDynamicCast(OSBoolean
, dict
->getObject(kIOPMDeepSleepEnabledKey
))))
1141 setProperty(kIOPMDeepSleepEnabledKey
, b
);
1143 if ((n
= OSDynamicCast(OSNumber
, dict
->getObject(kIOPMDeepSleepDelayKey
))))
1145 setProperty(kIOPMDeepSleepDelayKey
, n
);
1147 if ((b
= OSDynamicCast(OSBoolean
, dict
->getObject(kIOPMDestroyFVKeyOnStandbyKey
))))
1149 setProperty(kIOPMDestroyFVKeyOnStandbyKey
, b
);
1152 // Relay our allowed PM settings onto our registered PM clients
1153 for(i
= 0; i
< allowedPMSettings
->getCount(); i
++) {
1155 type
= (OSSymbol
*)allowedPMSettings
->getObject(i
);
1158 obj
= dict
->getObject(type
);
1161 if ((gIOPMSettingAutoWakeSecondsKey
== type
) && ((n
= OSDynamicCast(OSNumber
, obj
))))
1163 UInt32 rsecs
= n
->unsigned32BitValue();
1165 autoWakeStart
= autoWakeEnd
= 0;
1168 AbsoluteTime deadline
;
1169 clock_interval_to_deadline(rsecs
+ kAutoWakePostWindow
, kSecondScale
, &deadline
);
1170 autoWakeEnd
= AbsoluteTime_to_scalar(&deadline
);
1171 if (rsecs
> kAutoWakePreWindow
)
1172 rsecs
-= kAutoWakePreWindow
;
1175 clock_interval_to_deadline(rsecs
, kSecondScale
, &deadline
);
1176 autoWakeStart
= AbsoluteTime_to_scalar(&deadline
);
1179 if (gIOPMSettingDebugWakeRelativeKey
== type
)
1181 if ((n
= OSDynamicCast(OSNumber
, obj
)))
1182 _debugWakeSeconds
= n
->unsigned32BitValue();
1184 _debugWakeSeconds
= 0;
1187 return_value
= setPMSetting(type
, obj
);
1189 if(kIOReturnSuccess
!= return_value
) goto exit
;
1193 if(publish_simulated_battery_string
) publish_simulated_battery_string
->release();
1194 if(boot_complete_string
) boot_complete_string
->release();
1195 if(sys_shutdown_string
) sys_shutdown_string
->release();
1196 if(stall_halt_string
) stall_halt_string
->release();
1197 if(battery_warning_disabled_string
) battery_warning_disabled_string
->release();
1198 if(idle_seconds_string
) idle_seconds_string
->release();
1199 if(sleepdisabled_string
) sleepdisabled_string
->release();
1200 if(ondeck_sleepwake_uuid_string
) ondeck_sleepwake_uuid_string
->release();
1201 if(loginwindow_tracepoint_string
) loginwindow_tracepoint_string
->release();
1202 if(pmTimelineLogging_string
) pmTimelineLogging_string
->release();
1204 if(hibernatemode_string
) hibernatemode_string
->release();
1205 if(hibernatefile_string
) hibernatefile_string
->release();
1206 if(hibernatefreeratio_string
) hibernatefreeratio_string
->release();
1207 if(hibernatefreetime_string
) hibernatefreetime_string
->release();
1209 return return_value
;
1213 // MARK: Aggressiveness
1215 //******************************************************************************
1216 // setAggressiveness
1218 // Override IOService::setAggressiveness()
1219 //******************************************************************************
1221 IOReturn
IOPMrootDomain::setAggressiveness(
1223 unsigned long value
)
1225 return setAggressiveness( type
, value
, 0 );
1229 * Private setAggressiveness() with an internal options argument.
1231 IOReturn
IOPMrootDomain::setAggressiveness(
1233 unsigned long value
,
1234 IOOptionBits options
)
1236 AggressivesRequest
* entry
;
1237 AggressivesRequest
* request
;
1240 DLOG("setAggressiveness(%x) 0x%x = %u\n",
1241 (uint32_t) options
, (uint32_t) type
, (uint32_t) value
);
1243 request
= IONew(AggressivesRequest
, 1);
1245 return kIOReturnNoMemory
;
1247 memset(request
, 0, sizeof(*request
));
1248 request
->options
= options
;
1249 request
->dataType
= kAggressivesRequestTypeRecord
;
1250 request
->data
.record
.type
= (uint32_t) type
;
1251 request
->data
.record
.value
= (uint32_t) value
;
1255 // Update disk quick spindown flag used by getAggressiveness().
1256 // Never merge requests with quick spindown flags set.
1258 if (options
& kAggressivesOptionQuickSpindownEnable
)
1259 gAggressivesState
|= kAggressivesStateQuickSpindown
;
1260 else if (options
& kAggressivesOptionQuickSpindownDisable
)
1261 gAggressivesState
&= ~kAggressivesStateQuickSpindown
;
1264 // Coalesce requests with identical aggressives types.
1265 // Deal with callers that calls us too "aggressively".
1267 queue_iterate(&aggressivesQueue
, entry
, AggressivesRequest
*, chain
)
1269 if ((entry
->dataType
== kAggressivesRequestTypeRecord
) &&
1270 (entry
->data
.record
.type
== type
) &&
1271 ((entry
->options
& kAggressivesOptionQuickSpindownMask
) == 0))
1273 entry
->data
.record
.value
= value
;
1282 queue_enter(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
1285 AGGRESSIVES_UNLOCK();
1288 IODelete(request
, AggressivesRequest
, 1);
1290 if (options
& kAggressivesOptionSynchronous
)
1291 handleAggressivesRequests(); // not truly synchronous
1293 thread_call_enter(aggressivesThreadCall
);
1295 return kIOReturnSuccess
;
1298 //******************************************************************************
1299 // getAggressiveness
1301 // Override IOService::setAggressiveness()
1302 // Fetch the aggressiveness factor with the given type.
1303 //******************************************************************************
1305 IOReturn
IOPMrootDomain::getAggressiveness (
1307 unsigned long * outLevel
)
1313 return kIOReturnBadArgument
;
1317 // Disk quick spindown in effect, report value = 1
1319 if ((gAggressivesState
& kAggressivesStateQuickSpindown
) &&
1320 (type
== kPMMinutesToSpinDown
))
1322 value
= kAggressivesMinValue
;
1326 // Consult the pending request queue.
1330 AggressivesRequest
* entry
;
1332 queue_iterate(&aggressivesQueue
, entry
, AggressivesRequest
*, chain
)
1334 if ((entry
->dataType
== kAggressivesRequestTypeRecord
) &&
1335 (entry
->data
.record
.type
== type
) &&
1336 ((entry
->options
& kAggressivesOptionQuickSpindownMask
) == 0))
1338 value
= entry
->data
.record
.value
;
1345 // Consult the backend records.
1347 if (!source
&& aggressivesData
)
1349 AggressivesRecord
* record
;
1352 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
1353 record
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
1355 for (i
= 0; i
< count
; i
++, record
++)
1357 if (record
->type
== type
)
1359 value
= record
->value
;
1366 AGGRESSIVES_UNLOCK();
1370 DLOG("getAggressiveness(%d) 0x%x = %u\n",
1371 source
, (uint32_t) type
, value
);
1372 *outLevel
= (unsigned long) value
;
1373 return kIOReturnSuccess
;
1377 DLOG("getAggressiveness type 0x%x not found\n", (uint32_t) type
);
1378 *outLevel
= 0; // default return = 0, driver may not check for error
1379 return kIOReturnInvalid
;
1383 //******************************************************************************
1384 // joinAggressiveness
1386 // Request from IOService to join future aggressiveness broadcasts.
1387 //******************************************************************************
1389 IOReturn
IOPMrootDomain::joinAggressiveness(
1390 IOService
* service
)
1392 AggressivesRequest
* request
;
1394 if (!service
|| (service
== this))
1395 return kIOReturnBadArgument
;
1397 DLOG("joinAggressiveness %s %p\n", service
->getName(), service
);
1399 request
= IONew(AggressivesRequest
, 1);
1401 return kIOReturnNoMemory
;
1403 service
->retain(); // released by synchronizeAggressives()
1405 memset(request
, 0, sizeof(*request
));
1406 request
->dataType
= kAggressivesRequestTypeService
;
1407 request
->data
.service
= service
;
1410 queue_enter(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
1411 AGGRESSIVES_UNLOCK();
1413 thread_call_enter(aggressivesThreadCall
);
1415 return kIOReturnSuccess
;
1418 //******************************************************************************
1419 // handleAggressivesRequests
1421 // Backend thread processes all incoming aggressiveness requests in the queue.
1422 //******************************************************************************
1425 handleAggressivesFunction(
1426 thread_call_param_t param1
,
1427 thread_call_param_t param2
)
1431 ((IOPMrootDomain
*) param1
)->handleAggressivesRequests();
1435 void IOPMrootDomain::handleAggressivesRequests( void )
1437 AggressivesRecord
* start
;
1438 AggressivesRecord
* record
;
1439 AggressivesRequest
* request
;
1440 queue_head_t joinedQueue
;
1444 bool pingSelf
= false;
1448 if ((gAggressivesState
& kAggressivesStateBusy
) || !aggressivesData
||
1449 queue_empty(&aggressivesQueue
))
1452 gAggressivesState
|= kAggressivesStateBusy
;
1453 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
1454 start
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
1459 queue_init(&joinedQueue
);
1463 // Remove request from the incoming queue in FIFO order.
1464 queue_remove_first(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
1465 switch (request
->dataType
)
1467 case kAggressivesRequestTypeRecord
:
1468 // Update existing record if found.
1470 for (i
= 0, record
= start
; i
< count
; i
++, record
++)
1472 if (record
->type
== request
->data
.record
.type
)
1476 if (request
->options
& kAggressivesOptionQuickSpindownEnable
)
1478 if ((record
->flags
& kAggressivesRecordFlagMinValue
) == 0)
1481 record
->flags
|= (kAggressivesRecordFlagMinValue
|
1482 kAggressivesRecordFlagModified
);
1483 DLOG("disk spindown accelerated, was %u min\n",
1487 else if (request
->options
& kAggressivesOptionQuickSpindownDisable
)
1489 if (record
->flags
& kAggressivesRecordFlagMinValue
)
1492 record
->flags
|= kAggressivesRecordFlagModified
;
1493 record
->flags
&= ~kAggressivesRecordFlagMinValue
;
1494 DLOG("disk spindown restored to %u min\n",
1498 else if (record
->value
!= request
->data
.record
.value
)
1500 record
->value
= request
->data
.record
.value
;
1501 if ((record
->flags
& kAggressivesRecordFlagMinValue
) == 0)
1504 record
->flags
|= kAggressivesRecordFlagModified
;
1511 // No matching record, append a new record.
1513 ((request
->options
& kAggressivesOptionQuickSpindownDisable
) == 0))
1515 AggressivesRecord newRecord
;
1517 newRecord
.flags
= kAggressivesRecordFlagModified
;
1518 newRecord
.type
= request
->data
.record
.type
;
1519 newRecord
.value
= request
->data
.record
.value
;
1520 if (request
->options
& kAggressivesOptionQuickSpindownEnable
)
1522 newRecord
.flags
|= kAggressivesRecordFlagMinValue
;
1523 DLOG("disk spindown accelerated\n");
1526 aggressivesData
->appendBytes(&newRecord
, sizeof(newRecord
));
1528 // OSData may have switched to another (larger) buffer.
1529 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
1530 start
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
1534 // Finished processing the request, release it.
1535 IODelete(request
, AggressivesRequest
, 1);
1538 case kAggressivesRequestTypeService
:
1539 // synchronizeAggressives() will free request.
1540 queue_enter(&joinedQueue
, request
, AggressivesRequest
*, chain
);
1544 panic("bad aggressives request type %x\n", request
->dataType
);
1547 } while (!queue_empty(&aggressivesQueue
));
1549 // Release the lock to perform work, with busy flag set.
1550 if (!queue_empty(&joinedQueue
) || broadcast
)
1552 AGGRESSIVES_UNLOCK();
1553 if (!queue_empty(&joinedQueue
))
1554 synchronizeAggressives(&joinedQueue
, start
, count
);
1556 broadcastAggressives(start
, count
);
1560 // Remove the modified flag from all records.
1561 for (i
= 0, record
= start
; i
< count
; i
++, record
++)
1563 if ((record
->flags
& kAggressivesRecordFlagModified
) &&
1564 ((record
->type
== kPMMinutesToDim
) ||
1565 (record
->type
== kPMMinutesToSleep
)))
1568 record
->flags
&= ~kAggressivesRecordFlagModified
;
1571 // Check the incoming queue again since new entries may have been
1572 // added while lock was released above.
1574 } while (!queue_empty(&aggressivesQueue
));
1576 gAggressivesState
&= ~kAggressivesStateBusy
;
1579 AGGRESSIVES_UNLOCK();
1581 // Root domain is interested in system and display sleep slider changes.
1582 // Submit a power event to handle those changes on the PM work loop.
1584 if (pingSelf
&& pmPowerStateQueue
) {
1585 pmPowerStateQueue
->submitPowerEvent(
1586 kPowerEventPolicyStimulus
,
1587 (void *) kStimulusAggressivenessChanged
);
1591 //******************************************************************************
1592 // synchronizeAggressives
1594 // Push all known aggressiveness records to one or more IOService.
1595 //******************************************************************************
1597 void IOPMrootDomain::synchronizeAggressives(
1598 queue_head_t
* joinedQueue
,
1599 const AggressivesRecord
* array
,
1602 IOService
* service
;
1603 AggressivesRequest
* request
;
1604 const AggressivesRecord
* record
;
1605 IOPMDriverCallEntry callEntry
;
1609 while (!queue_empty(joinedQueue
))
1611 queue_remove_first(joinedQueue
, request
, AggressivesRequest
*, chain
);
1612 if (request
->dataType
== kAggressivesRequestTypeService
)
1613 service
= request
->data
.service
;
1617 IODelete(request
, AggressivesRequest
, 1);
1622 if (service
->assertPMDriverCall(&callEntry
))
1624 for (i
= 0, record
= array
; i
< count
; i
++, record
++)
1626 value
= record
->value
;
1627 if (record
->flags
& kAggressivesRecordFlagMinValue
)
1628 value
= kAggressivesMinValue
;
1630 _LOG("synchronizeAggressives 0x%x = %u to %s\n",
1631 record
->type
, value
, service
->getName());
1632 service
->setAggressiveness(record
->type
, value
);
1634 service
->deassertPMDriverCall(&callEntry
);
1636 service
->release(); // retained by joinAggressiveness()
1641 //******************************************************************************
1642 // broadcastAggressives
1644 // Traverse PM tree and call setAggressiveness() for records that have changed.
1645 //******************************************************************************
1647 void IOPMrootDomain::broadcastAggressives(
1648 const AggressivesRecord
* array
,
1651 IORegistryIterator
* iter
;
1652 IORegistryEntry
* entry
;
1653 IOPowerConnection
* connect
;
1654 IOService
* service
;
1655 const AggressivesRecord
* record
;
1656 IOPMDriverCallEntry callEntry
;
1660 iter
= IORegistryIterator::iterateOver(
1661 this, gIOPowerPlane
, kIORegistryIterateRecursively
);
1667 while ((entry
= iter
->getNextObject()))
1669 connect
= OSDynamicCast(IOPowerConnection
, entry
);
1670 if (!connect
|| !connect
->getReadyFlag())
1673 if ((service
= (IOService
*) connect
->copyChildEntry(gIOPowerPlane
)))
1675 if (service
->assertPMDriverCall(&callEntry
))
1677 for (i
= 0, record
= array
; i
< count
; i
++, record
++)
1679 if (record
->flags
& kAggressivesRecordFlagModified
)
1681 value
= record
->value
;
1682 if (record
->flags
& kAggressivesRecordFlagMinValue
)
1683 value
= kAggressivesMinValue
;
1684 _LOG("broadcastAggressives %x = %u to %s\n",
1685 record
->type
, value
, service
->getName());
1686 service
->setAggressiveness(record
->type
, value
);
1689 service
->deassertPMDriverCall(&callEntry
);
1695 while (!entry
&& !iter
->isValid());
1701 // MARK: System Sleep
1703 //******************************************************************************
1704 // startIdleSleepTimer
1706 //******************************************************************************
1708 void IOPMrootDomain::startIdleSleepTimer( uint32_t inSeconds
)
1710 AbsoluteTime deadline
;
1715 clock_interval_to_deadline(inSeconds
, kSecondScale
, &deadline
);
1716 thread_call_enter_delayed(extraSleepTimer
, deadline
);
1717 idleSleepTimerPending
= true;
1718 DLOG("idle timer set for %u seconds\n", inSeconds
);
1722 //******************************************************************************
1723 // cancelIdleSleepTimer
1725 //******************************************************************************
1727 void IOPMrootDomain::cancelIdleSleepTimer( void )
1730 if (idleSleepTimerPending
)
1732 DLOG("idle timer cancelled\n");
1733 thread_call_cancel(extraSleepTimer
);
1734 idleSleepTimerPending
= false;
1738 //******************************************************************************
1739 // idleSleepTimerExpired
1741 //******************************************************************************
1743 static void idleSleepTimerExpired(
1744 thread_call_param_t us
, thread_call_param_t
)
1746 ((IOPMrootDomain
*)us
)->handleSleepTimerExpiration();
1749 //******************************************************************************
1750 // handleSleepTimerExpiration
1752 // The time between the sleep idle timeout and the next longest one has elapsed.
1753 // It's time to sleep. Start that by removing the clamp that's holding us awake.
1754 //******************************************************************************
1756 void IOPMrootDomain::handleSleepTimerExpiration( void )
1758 if (!getPMworkloop()->inGate())
1760 getPMworkloop()->runAction(
1761 OSMemberFunctionCast(IOWorkLoop::Action
, this,
1762 &IOPMrootDomain::handleSleepTimerExpiration
),
1769 DLOG("sleep timer expired\n");
1772 idleSleepTimerPending
= false;
1774 clock_get_uptime(&time
);
1775 if ((AbsoluteTime_to_scalar(&time
) > autoWakeStart
) &&
1776 (AbsoluteTime_to_scalar(&time
) < autoWakeEnd
))
1778 thread_call_enter_delayed(extraSleepTimer
, *((AbsoluteTime
*) &autoWakeEnd
));
1782 setQuickSpinDownTimeout();
1783 adjustPowerState(true);
1786 //******************************************************************************
1787 // setQuickSpinDownTimeout
1789 //******************************************************************************
1791 void IOPMrootDomain::setQuickSpinDownTimeout( void )
1795 kPMMinutesToSpinDown
, 0, kAggressivesOptionQuickSpindownEnable
);
1798 //******************************************************************************
1799 // restoreUserSpinDownTimeout
1801 //******************************************************************************
1803 void IOPMrootDomain::restoreUserSpinDownTimeout( void )
1807 kPMMinutesToSpinDown
, 0, kAggressivesOptionQuickSpindownDisable
);
1810 //******************************************************************************
1813 //******************************************************************************
1816 IOReturn
IOPMrootDomain::sleepSystem( void )
1818 return sleepSystemOptions(NULL
);
1822 IOReturn
IOPMrootDomain::sleepSystemOptions( OSDictionary
*options
)
1824 /* sleepSystem is a public function, and may be called by any kernel driver.
1825 * And that's bad - drivers should sleep the system by calling
1826 * receivePowerNotification() instead. Drivers should not use sleepSystem.
1828 * Note that user space app calls to IOPMSleepSystem() will also travel
1829 * this code path and thus be correctly identified as software sleeps.
1832 if (options
&& options
->getObject("OSSwitch"))
1834 // Log specific sleep cause for OS Switch hibernation
1835 return privateSleepSystem( kIOPMSleepReasonOSSwitchHibernate
);
1837 return privateSleepSystem( kIOPMSleepReasonSoftware
);
1842 IOReturn
IOPMrootDomain::privateSleepSystem( uint32_t sleepReason
)
1844 static const char * IOPMSleepReasons
[] = {
1846 kIOPMClamshellSleepKey
,
1847 kIOPMPowerButtonSleepKey
,
1848 kIOPMSoftwareSleepKey
,
1849 kIOPMOSSwitchHibernationKey
,
1851 kIOPMLowPowerSleepKey
,
1852 kIOPMClamshellSleepKey
,
1853 kIOPMThermalEmergencySleepKey
,
1854 kIOPMMaintenanceSleepKey
1857 PMEventDetails
*details
;
1859 if (!checkSystemCanSleep())
1861 // Record why the system couldn't sleep
1862 details
= PMEventDetails::eventDetails(kIOPMEventTypeSleep
, NULL
,
1863 sleepReason
, kIOReturnNotPermitted
);
1865 recordAndReleasePMEvent( details
);
1866 return kIOReturnNotPermitted
;
1870 timeline
->setSleepCycleInProgressFlag(true);
1872 // Time to publish a UUID for the Sleep --> Wake cycle
1873 if(pmPowerStateQueue
) {
1874 pmPowerStateQueue
->submitPowerEvent(kPowerEventPublishSleepWakeUUID
, (void *)true);
1878 // Log the beginning of system sleep.
1879 details
= PMEventDetails::eventDetails(kIOPMEventTypeSleep
, NULL
,
1880 sleepReason
, kIOReturnSuccess
);
1882 recordAndReleasePMEvent( details
);
1884 // Record sleep cause in IORegistry
1885 lastSleepReason
= sleepReason
;
1886 sleepReason
-= (kIOPMSleepReasonClamshell
- 1);
1887 if (sleepReason
&& (sleepReason
< sizeof(IOPMSleepReasons
)/sizeof(IOPMSleepReasons
[0]))) {
1888 setProperty(kRootDomainSleepReasonKey
, IOPMSleepReasons
[sleepReason
]);
1891 if (pmPowerStateQueue
)
1892 pmPowerStateQueue
->submitPowerEvent(
1893 kPowerEventPolicyStimulus
,
1894 (void *) kStimulusDemandSystemSleep
);
1896 return kIOReturnSuccess
;
1899 IOReturn
IOPMrootDomain::recordPMEventGated(PMEventDetails
*record
)
1901 // If we don't have a place to log to, we can't actually
1902 // log anything. Chances are, the person who is asking us to do
1903 // the PM logging has forgotten to set the right bootflags
1905 return kIOReturnSuccess
;
1907 if(gIOPMWorkLoop
->inGate() == false) {
1909 IOReturn ret
= gIOPMWorkLoop
->runAction(
1910 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOPMrootDomain::recordPMEventGated
),
1917 // Now that we're guaranteed to be running in gate ...
1919 // Check the validity of the argument we are given
1921 return kIOReturnBadArgument
;
1923 // Record a driver event, or a system event
1924 if(record
->eventClassifier
== kIOPMEventClassDriverEvent
1925 || record
->eventClassifier
== kIOPMEventClassSystemEvent
)
1926 return this->recordPMEvent(record
);
1929 return kIOReturnBadArgument
;
1933 IOReturn
IOPMrootDomain::recordAndReleasePMEventGated(PMEventDetails
*record
)
1935 IOReturn ret
= kIOReturnBadArgument
;
1939 ret
= recordPMEventGated(record
);
1946 //******************************************************************************
1949 // This overrides powerChangeDone in IOService.
1950 //******************************************************************************
1952 void IOPMrootDomain::powerChangeDone( unsigned long previousPowerState
)
1954 PMEventDetails
*details
;
1957 DLOG("PowerChangeDone: %u->%u\n",
1958 (uint32_t) previousPowerState
, (uint32_t) getPowerState());
1960 switch ( getPowerState() )
1963 if (previousPowerState
!= ON_STATE
)
1966 details
= PMEventDetails::eventDetails(
1967 kIOPMEventTypeSleepDone
,
1972 recordAndReleasePMEvent( details
);
1974 // re-enable this timer for next sleep
1975 cancelIdleSleepTimer();
1978 clock_usec_t microsecs
;
1979 clock_get_calendar_microtime(&secs
, µsecs
);
1981 gIOLastSleepTime
.tv_sec
= secs
;
1982 gIOLastSleepTime
.tv_usec
= microsecs
;
1983 gIOLastWakeTime
.tv_sec
= 0;
1984 gIOLastWakeTime
.tv_usec
= 0;
1987 LOG("System %sSleep\n", gIOHibernateState
? "Safe" : "");
1989 IOHibernateSystemHasSlept();
1991 evaluateSystemSleepPolicyFinal();
1993 LOG("System Sleep\n");
1996 getPlatform()->sleepKernel();
1998 // The CPU(s) are off at this point,
1999 // Code will resume execution here upon wake.
2001 clock_get_uptime(&systemWakeTime
);
2004 IOHibernateSystemWake();
2007 // sleep transition complete
2008 gSleepOrShutdownPending
= 0;
2010 // trip the reset of the calendar clock
2011 clock_wakeup_calendar();
2014 LOG("System %sWake\n", gIOHibernateState
? "SafeSleep " : "");
2018 getPlatform()->PMLog(kIOPMrootDomainClass
, kPMLogSystemWake
, 0, 0);
2019 lowBatteryCondition
= false;
2020 lastSleepReason
= 0;
2022 // And start logging the wake event here
2023 // TODO: Publish the wakeReason string as an integer
2024 details
= PMEventDetails::eventDetails(
2030 recordAndReleasePMEvent( details
);
2037 #if defined(__i386__) || defined(__x86_64__)
2038 wranglerTickled
= false;
2039 graphicsSuppressed
= false;
2040 darkWakePostTickle
= false;
2041 logGraphicsClamp
= true;
2042 logWranglerTickle
= true;
2043 sleepTimerMaintenance
= false;
2045 OSString
* wakeType
= OSDynamicCast(
2046 OSString
, getProperty(kIOPMRootDomainWakeTypeKey
));
2047 OSString
* wakeReason
= OSDynamicCast(
2048 OSString
, getProperty(kIOPMRootDomainWakeReasonKey
));
2050 if (wakeType
&& wakeType
->isEqualTo(kIOPMrootDomainWakeTypeLowBattery
))
2052 lowBatteryCondition
= true;
2053 darkWakeMaintenance
= true;
2054 darkWakeToSleepASAP
= true;
2056 else if ((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) != 0)
2058 OSNumber
* hibOptions
= OSDynamicCast(
2059 OSNumber
, getProperty(kIOHibernateOptionsKey
));
2061 if (hibernateAborted
||
2063 !(hibOptions
->unsigned32BitValue() & kIOHibernateOptionDarkWake
))) ||
2064 ((_debugWakeSeconds
!= 0) &&
2065 ((gDarkWakeFlags
& kDarkWakeFlagAlarmIsDark
) == 0)) ||
2067 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeUser
) ||
2068 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeAlarm
))))
2070 wranglerTickled
= true;
2074 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeMaintenance
))
2076 darkWakeMaintenance
= true;
2077 darkWakeToSleepASAP
= true;
2081 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeSleepTimer
))
2083 darkWakeMaintenance
= true;
2084 darkWakeToSleepASAP
= true;
2085 sleepTimerMaintenance
= true;
2089 // Unidentified wake source, resume to full wake if debug
2090 // alarm is pending.
2092 if (_debugWakeSeconds
&& (!wakeReason
|| wakeReason
->isEqualTo("")))
2093 wranglerTickled
= true;
2095 darkWakeToSleepASAP
= true;
2100 // Post a HID tickle immediately - except for maintenance wake.
2102 if (hibernateAborted
|| !wakeType
||
2103 !wakeType
->isEqualTo(kIOPMRootDomainWakeTypeMaintenance
))
2105 wranglerTickled
= true;
2109 darkWakeMaintenance
= true;
2110 darkWakeToSleepASAP
= true;
2114 if (wranglerTickled
)
2116 else if (!darkWakeMaintenance
)
2118 // Early/late tickle for non-maintenance wake.
2119 if (((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
2120 kDarkWakeFlagHIDTickleEarly
) ||
2121 ((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
2122 kDarkWakeFlagHIDTickleLate
))
2124 darkWakePostTickle
= true;
2127 #else /* !__i386__ && !__x86_64__ */
2128 // stay awake for at least 30 seconds
2129 wranglerTickled
= true;
2130 startIdleSleepTimer(30);
2133 changePowerStateToPriv(ON_STATE
);
2137 bool wasPrevented
= childPreventSystemSleep
;
2139 details
= PMEventDetails::eventDetails(
2140 kIOPMEventTypeWakeDone
,
2145 recordAndReleasePMEvent( details
);
2147 if (previousPowerState
!= ON_STATE
)
2148 _debugWakeSeconds
= 0;
2150 // Update childPreventSystemSleep flag using the capability computed
2151 // by IOSevice::rebuildChildClampBits().
2153 childPreventSystemSleep
=
2154 ((currentCapability() & kIOPMChildClamp2
) != 0);
2156 if (wasPrevented
&& !childPreventSystemSleep
)
2158 evaluatePolicy( kStimulusDarkWakeEvaluate
);
2164 //******************************************************************************
2165 // requestPowerDomainState
2167 // Extend implementation in IOService. Running on PM work loop thread.
2169 // Examine children desires and initiate idle-sleep if all children are idle,
2170 // prevent idle and system sleep flags are not set.
2171 //******************************************************************************
2173 IOReturn
IOPMrootDomain::requestPowerDomainState (
2174 IOPMPowerFlags childDesire
,
2175 IOPowerConnection
* childConnection
,
2176 unsigned long specification
)
2180 IOPowerConnection
*connection
;
2181 IOPMPowerFlags mergedChildDesire
= 0;
2182 IOPMPowerFlags editedChildDesire
;
2183 IOPMPowerFlags thisDesire
;
2184 bool sleepASAP
= false;
2188 // Disregard disk I/O (anything besides the display wrangler) as a
2189 // factor in preventing idle sleep - based on a runtime setting.
2191 if ((gDarkWakeFlags
& kDarkWakeFlagIgnoreDiskIOAlways
) &&
2192 (kIOPMPreventIdleSleep
& childDesire
) &&
2193 (childConnection
!= wranglerConnection
))
2195 childDesire
&= ~kIOPMPreventIdleSleep
;
2198 // Force the child's input power requirement to 0 unless the prevent
2199 // idle-sleep flag is set. Nil input power flags maps to our state 0.
2200 // Our power clamp (deviceDesire) clamps the lowest power state at 2.
2202 editedChildDesire
= 0;
2203 if (childDesire
& kIOPMPreventIdleSleep
)
2204 editedChildDesire
|= (kIOPMPowerOn
| kIOPMPreventIdleSleep
);
2205 if (childDesire
& kIOPMPreventSystemSleep
)
2206 editedChildDesire
|= (kIOPMPowerOn
| kIOPMPreventSystemSleep
);
2208 iter
= getChildIterator(gIOPowerPlane
);
2211 while ( (next
= iter
->getNextObject()) )
2213 if ( (connection
= OSDynamicCast(IOPowerConnection
, next
)) )
2215 // Ignore child that are in the process of joining.
2216 if (connection
->getReadyFlag() == false)
2219 // OR in the child's input power requirements.
2220 // Is this connection attached to the child that called
2221 // requestPowerDomainState()?
2223 if (connection
== childConnection
)
2225 thisDesire
= editedChildDesire
;
2230 if (connection
->getPreventIdleSleepFlag())
2231 thisDesire
|= (kIOPMPowerOn
| kIOPMPreventIdleSleep
);
2232 if (connection
->getPreventSystemSleepFlag())
2233 thisDesire
|= (kIOPMPowerOn
| kIOPMPreventSystemSleep
);
2236 mergedChildDesire
|= thisDesire
;
2237 if (thisDesire
&& (kIOLogPMRootDomain
& gIOKitDebug
))
2240 (IOService
*) connection
->getChildEntry(gIOPowerPlane
);
2241 LOG("child %p, noIdle %d, noSleep %d - %s\n",
2243 ((thisDesire
& kIOPMPreventIdleSleep
) != 0),
2244 ((thisDesire
& kIOPMPreventSystemSleep
) != 0),
2245 child
? child
->getName() : "?");
2252 DLOG("mergedChildDesire 0x%lx, extraSleepDelay %ld\n",
2253 mergedChildDesire
, extraSleepDelay
);
2255 if ( !mergedChildDesire
&& !systemBooting
)
2259 changePowerStateToPriv(ON_STATE
);
2262 // stay awake for at least idleSeconds
2263 startIdleSleepTimer(idleSeconds
);
2266 else if (!extraSleepDelay
&& !idleSleepTimerPending
&& !systemDarkWake
)
2272 // Drop our power clamp to SLEEP_STATE when all children became idle,
2273 // and system sleep and display sleep slider values are equal.
2275 adjustPowerState(sleepASAP
);
2277 // If our power clamp has already dropped to SLEEP_STATE, and no child
2278 // is keeping us at ON_STATE, then the following will trigger idle sleep.
2280 return super::requestPowerDomainState(
2281 editedChildDesire
, childConnection
, specification
);
2284 //******************************************************************************
2287 // Override the superclass implementation to send a different message type.
2288 //******************************************************************************
2290 bool IOPMrootDomain::tellChangeDown( unsigned long stateNum
)
2292 DLOG("tellChangeDown %u->%u\n",
2293 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2295 if (SLEEP_STATE
== stateNum
)
2297 if (!ignoreTellChangeDown
)
2298 tracePoint( kIOPMTracePointSleepApplications
);
2300 tracePoint( kIOPMTracePointSleepPriorityClients
);
2303 if ((SLEEP_STATE
== stateNum
) && !ignoreTellChangeDown
)
2305 userActivityAtSleep
= userActivityCount
;
2306 hibernateAborted
= false;
2307 DLOG("tellChangeDown::userActivityAtSleep %d\n", userActivityAtSleep
);
2309 // Direct callout into OSKext so it can disable kext unloads
2310 // during sleep/wake to prevent deadlocks.
2311 OSKextSystemSleepOrWake( kIOMessageSystemWillSleep
);
2313 IOService::updateConsoleUsers(NULL
, kIOMessageSystemWillSleep
);
2315 // Notify platform that sleep has begun
2316 getPlatform()->callPlatformFunction(
2317 sleepMessagePEFunction
, false,
2318 (void *)(uintptr_t) kIOMessageSystemWillSleep
,
2321 // Two change downs are sent by IOServicePM. Ignore the 2nd.
2322 // But tellClientsWithResponse() must be called for both.
2323 ignoreTellChangeDown
= true;
2326 return super::tellClientsWithResponse( kIOMessageSystemWillSleep
);
2329 //******************************************************************************
2332 // Override the superclass implementation to send a different message type.
2333 // This must be idle sleep since we don't ask during any other power change.
2334 //******************************************************************************
2336 bool IOPMrootDomain::askChangeDown( unsigned long stateNum
)
2338 DLOG("askChangeDown %u->%u\n",
2339 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2341 // Don't log for dark wake entry
2342 if (kSystemTransitionSleep
== _systemTransitionType
)
2343 tracePoint( kIOPMTracePointSleepApplications
);
2345 return super::tellClientsWithResponse( kIOMessageCanSystemSleep
);
2348 //******************************************************************************
2349 // askChangeDownDone
2351 // Called by PM after all apps have responded to kIOMessageCanSystemSleep.
2352 // pmconfigd may create a deny sleep assertion before ack'ing.
2353 //******************************************************************************
2355 void IOPMrootDomain::askChangeDownDone(
2356 IOPMPowerChangeFlags
* inOutChangeFlags
, bool * cancel
)
2358 DLOG("askChangeDownDone(0x%x, %u) type %x, cap %x->%x\n",
2359 *inOutChangeFlags
, *cancel
,
2360 _systemTransitionType
,
2361 _currentCapability
, _pendingCapability
);
2363 if ((false == *cancel
) && (kSystemTransitionSleep
== _systemTransitionType
))
2365 // Dark->Sleep transition.
2366 // Check if there are any deny sleep assertions.
2367 // Full->Dark transition is never cancelled.
2369 if (!checkSystemCanSleep(true))
2371 // Cancel dark wake to sleep transition.
2372 // Must re-scan assertions upon entering dark wake.
2375 DLOG("cancel dark->sleep\n");
2380 //******************************************************************************
2383 // Notify registered applications and kernel clients that we are not dropping
2386 // We override the superclass implementation so we can send a different message
2387 // type to the client or application being notified.
2389 // This must be a vetoed idle sleep, since no other power change can be vetoed.
2390 //******************************************************************************
2392 void IOPMrootDomain::tellNoChangeDown( unsigned long stateNum
)
2394 DLOG("tellNoChangeDown %u->%u\n",
2395 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2397 if (idleSeconds
&& !wrangler
)
2399 // stay awake for at least idleSeconds
2400 startIdleSleepTimer(idleSeconds
);
2402 return tellClients( kIOMessageSystemWillNotSleep
);
2405 //******************************************************************************
2408 // Notify registered applications and kernel clients that we are raising power.
2410 // We override the superclass implementation so we can send a different message
2411 // type to the client or application being notified.
2412 //******************************************************************************
2414 void IOPMrootDomain::tellChangeUp( unsigned long stateNum
)
2416 OSData
*publishPMStats
= NULL
;
2418 DLOG("tellChangeUp %u->%u\n",
2419 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2421 ignoreTellChangeDown
= false;
2423 if ( stateNum
== ON_STATE
)
2425 // Direct callout into OSKext so it can disable kext unloads
2426 // during sleep/wake to prevent deadlocks.
2427 OSKextSystemSleepOrWake( kIOMessageSystemHasPoweredOn
);
2429 // Notify platform that sleep was cancelled or resumed.
2430 getPlatform()->callPlatformFunction(
2431 sleepMessagePEFunction
, false,
2432 (void *)(uintptr_t) kIOMessageSystemHasPoweredOn
,
2435 if (getPowerState() == ON_STATE
)
2437 // this is a quick wake from aborted sleep
2438 if (idleSeconds
&& !wrangler
)
2440 // stay awake for at least idleSeconds
2441 startIdleSleepTimer(idleSeconds
);
2443 tellClients( kIOMessageSystemWillPowerOn
);
2446 tracePoint( kIOPMTracePointWakeApplications
);
2447 publishPMStats
= OSData::withBytes(&pmStats
, sizeof(pmStats
));
2448 setProperty(kIOPMSleepStatisticsKey
, publishPMStats
);
2449 publishPMStats
->release();
2450 bzero(&pmStats
, sizeof(pmStats
));
2452 if (pmStatsAppResponses
)
2454 setProperty(kIOPMSleepStatisticsAppsKey
, pmStatsAppResponses
);
2455 pmStatsAppResponses
->release();
2456 pmStatsAppResponses
= OSArray::withCapacity(5);
2459 tellClients( kIOMessageSystemHasPoweredOn
);
2463 //******************************************************************************
2464 // sysPowerDownHandler
2466 // Perform a vfs sync before system sleep.
2467 //******************************************************************************
2469 IOReturn
IOPMrootDomain::sysPowerDownHandler(
2470 void * target
, void * refCon
,
2471 UInt32 messageType
, IOService
* service
,
2472 void * messageArgs
, vm_size_t argSize
)
2476 DLOG("sysPowerDownHandler message %s\n", getIOMessageString(messageType
));
2479 return kIOReturnUnsupported
;
2481 if (messageType
== kIOMessageSystemCapabilityChange
)
2483 IOPMSystemCapabilityChangeParameters
* params
=
2484 (IOPMSystemCapabilityChangeParameters
*) messageArgs
;
2486 // Interested applications have been notified of an impending power
2487 // change and have acked (when applicable).
2488 // This is our chance to save whatever state we can before powering
2490 // We call sync_internal defined in xnu/bsd/vfs/vfs_syscalls.c,
2493 DLOG("sysPowerDownHandler cap %x -> %x (flags %x)\n",
2494 params
->fromCapabilities
, params
->toCapabilities
,
2495 params
->changeFlags
);
2497 if ((params
->changeFlags
& kIOPMSystemCapabilityWillChange
) &&
2498 (params
->fromCapabilities
& kIOPMSystemCapabilityCPU
) &&
2499 (params
->toCapabilities
& kIOPMSystemCapabilityCPU
) == 0)
2501 // We will ack within 20 seconds
2502 params
->maxWaitForReply
= 20 * 1000 * 1000;
2504 gRootDomain
->evaluateSystemSleepPolicyEarly();
2506 // add in time we could spend freeing pages
2507 if (gRootDomain
->hibernateMode
&& !gRootDomain
->hibernateDisabled
)
2509 params
->maxWaitForReply
= kCapabilityClientMaxWait
;
2511 DLOG("sysPowerDownHandler timeout %d s\n", (int) (params
->maxWaitForReply
/ 1000 / 1000));
2514 if ( !OSCompareAndSwap( 0, 1, &gSleepOrShutdownPending
) )
2516 // Purposely delay the ack and hope that shutdown occurs quickly.
2517 // Another option is not to schedule the thread and wait for
2519 AbsoluteTime deadline
;
2520 clock_interval_to_deadline( 30, kSecondScale
, &deadline
);
2521 thread_call_enter1_delayed(
2522 gRootDomain
->diskSyncCalloutEntry
,
2523 (thread_call_param_t
) params
->notifyRef
,
2528 gRootDomain
->diskSyncCalloutEntry
,
2529 (thread_call_param_t
) params
->notifyRef
);
2533 if ((params
->changeFlags
& kIOPMSystemCapabilityDidChange
) &&
2534 (params
->toCapabilities
& kIOPMSystemCapabilityCPU
) &&
2535 (params
->fromCapabilities
& kIOPMSystemCapabilityCPU
) == 0)
2537 // We will ack within 110 seconds
2538 params
->maxWaitForReply
= 110 * 1000 * 1000;
2541 gRootDomain
->diskSyncCalloutEntry
,
2542 (thread_call_param_t
) params
->notifyRef
);
2545 ret
= kIOReturnSuccess
;
2551 //******************************************************************************
2552 // handleQueueSleepWakeUUID
2554 // Called from IOPMrootDomain when we're initiating a sleep,
2555 // or indirectly from PM configd when PM decides to clear the UUID.
2556 // PM clears the UUID several minutes after successful wake from sleep,
2557 // so that we might associate App spindumps with the immediately previous
2560 // @param obj has a retain on it. We're responsible for releasing that retain.
2561 //******************************************************************************
2563 void IOPMrootDomain::handleQueueSleepWakeUUID(OSObject
*obj
)
2565 OSString
*str
= NULL
;
2567 if (kOSBooleanFalse
== obj
)
2569 handlePublishSleepWakeUUID(NULL
);
2571 else if ((str
= OSDynamicCast(OSString
, obj
)))
2573 // This branch caches the UUID for an upcoming sleep/wake
2574 if (queuedSleepWakeUUIDString
) {
2575 queuedSleepWakeUUIDString
->release();
2576 queuedSleepWakeUUIDString
= NULL
;
2578 queuedSleepWakeUUIDString
= str
;
2579 queuedSleepWakeUUIDString
->retain();
2581 DLOG("SleepWake UUID queued: %s\n", queuedSleepWakeUUIDString
->getCStringNoCopy());
2590 //******************************************************************************
2591 // handlePublishSleepWakeUUID
2593 // Called from IOPMrootDomain when we're initiating a sleep,
2594 // or indirectly from PM configd when PM decides to clear the UUID.
2595 // PM clears the UUID several minutes after successful wake from sleep,
2596 // so that we might associate App spindumps with the immediately previous
2598 //******************************************************************************
2600 void IOPMrootDomain::handlePublishSleepWakeUUID( bool shouldPublish
)
2605 * Clear the current UUID
2607 if (gSleepWakeUUIDIsSet
)
2609 DLOG("SleepWake UUID cleared\n");
2611 OSString
*UUIDstring
= NULL
;
2614 (UUIDstring
= OSDynamicCast(OSString
, getProperty(kIOPMSleepWakeUUIDKey
))))
2616 PMEventDetails
*details
= PMEventDetails::eventDetails(kIOPMEventTypeUUIDClear
,
2617 UUIDstring
->getCStringNoCopy(), NULL
, 0);
2619 timeline
->recordSystemPowerEvent( details
);
2622 timeline
->setNumEventsLoggedThisPeriod(0);
2625 gSleepWakeUUIDIsSet
= false;
2627 removeProperty(kIOPMSleepWakeUUIDKey
);
2628 messageClients(kIOPMMessageSleepWakeUUIDChange
, kIOPMMessageSleepWakeUUIDCleared
);
2632 * Optionally, publish a new UUID
2634 if (queuedSleepWakeUUIDString
&& shouldPublish
) {
2636 OSString
*publishThisUUID
= NULL
;
2638 publishThisUUID
= queuedSleepWakeUUIDString
;
2639 publishThisUUID
->retain();
2642 PMEventDetails
*details
;
2643 details
= PMEventDetails::eventDetails(kIOPMEventTypeUUIDSet
,
2644 publishThisUUID
->getCStringNoCopy(), NULL
, 0);
2646 timeline
->recordSystemPowerEvent( details
);
2651 if (publishThisUUID
)
2653 setProperty(kIOPMSleepWakeUUIDKey
, publishThisUUID
);
2654 publishThisUUID
->release();
2657 gSleepWakeUUIDIsSet
= true;
2658 messageClients(kIOPMMessageSleepWakeUUIDChange
, kIOPMMessageSleepWakeUUIDSet
);
2660 queuedSleepWakeUUIDString
->release();
2661 queuedSleepWakeUUIDString
= NULL
;
2665 //******************************************************************************
2666 // changePowerStateTo & changePowerStateToPriv
2668 // Override of these methods for logging purposes.
2669 //******************************************************************************
2671 IOReturn
IOPMrootDomain::changePowerStateTo( unsigned long ordinal
)
2673 return kIOReturnUnsupported
; // ignored
2676 IOReturn
IOPMrootDomain::changePowerStateToPriv( unsigned long ordinal
)
2678 DLOG("changePowerStateToPriv(%lu)\n", ordinal
);
2680 if ((ordinal
!= ON_STATE
) && (ordinal
!= SLEEP_STATE
))
2681 return kIOReturnUnsupported
;
2683 return super::changePowerStateToPriv(ordinal
);
2686 //******************************************************************************
2689 //******************************************************************************
2691 bool IOPMrootDomain::activitySinceSleep(void)
2693 return (userActivityCount
!= userActivityAtSleep
);
2696 bool IOPMrootDomain::abortHibernation(void)
2698 bool ret
= activitySinceSleep();
2700 if (ret
&& !hibernateAborted
)
2702 DLOG("activitySinceSleep ABORT [%d, %d]\n", userActivityCount
, userActivityAtSleep
);
2703 hibernateAborted
= true;
2709 hibernate_should_abort(void)
2712 return (gRootDomain
->abortHibernation());
2717 //******************************************************************************
2718 // sleepOnClamshellClosed
2720 // contains the logic to determine if the system should sleep when the clamshell
2722 //******************************************************************************
2724 bool IOPMrootDomain::shouldSleepOnClamshellClosed( void )
2726 if (!clamshellExists
)
2729 DLOG("clamshell closed %d, disabled %d, desktopMode %d, ac %d\n",
2730 clamshellClosed
, clamshellDisabled
, desktopMode
, acAdaptorConnected
);
2732 return ( !clamshellDisabled
&& !(desktopMode
&& acAdaptorConnected
) );
2735 void IOPMrootDomain::sendClientClamshellNotification( void )
2737 /* Only broadcast clamshell alert if clamshell exists. */
2738 if (!clamshellExists
)
2741 setProperty(kAppleClamshellStateKey
,
2742 clamshellClosed
? kOSBooleanTrue
: kOSBooleanFalse
);
2744 setProperty(kAppleClamshellCausesSleepKey
,
2745 shouldSleepOnClamshellClosed() ? kOSBooleanTrue
: kOSBooleanFalse
);
2747 /* Argument to message is a bitfiel of
2748 * ( kClamshellStateBit | kClamshellSleepBit )
2750 messageClients(kIOPMMessageClamshellStateChange
,
2751 (void *) ( (clamshellClosed
? kClamshellStateBit
: 0)
2752 | ( shouldSleepOnClamshellClosed() ? kClamshellSleepBit
: 0)) );
2755 //******************************************************************************
2756 // getSleepSupported
2759 //******************************************************************************
2761 IOOptionBits
IOPMrootDomain::getSleepSupported( void )
2763 return( platformSleepSupport
);
2766 //******************************************************************************
2767 // setSleepSupported
2770 //******************************************************************************
2772 void IOPMrootDomain::setSleepSupported( IOOptionBits flags
)
2774 DLOG("setSleepSupported(%x)\n", (uint32_t) flags
);
2775 OSBitOrAtomic(flags
, &platformSleepSupport
);
2778 //******************************************************************************
2782 //******************************************************************************
2784 void IOPMrootDomain::wakeFromDoze( void )
2786 // Preserve symbol for familes (IOUSBFamily and IOGraphics)
2792 //******************************************************************************
2795 // Adds a new feature to the supported features dictionary
2796 //******************************************************************************
2798 void IOPMrootDomain::publishFeature( const char * feature
)
2800 publishFeature(feature
, kRD_AllPowerSources
, NULL
);
2803 //******************************************************************************
2804 // publishFeature (with supported power source specified)
2806 // Adds a new feature to the supported features dictionary
2807 //******************************************************************************
2809 void IOPMrootDomain::publishFeature(
2810 const char *feature
,
2811 uint32_t supportedWhere
,
2812 uint32_t *uniqueFeatureID
)
2814 static uint16_t next_feature_id
= 500;
2816 OSNumber
*new_feature_data
= NULL
;
2817 OSNumber
*existing_feature
= NULL
;
2818 OSArray
*existing_feature_arr
= NULL
;
2819 OSObject
*osObj
= NULL
;
2820 uint32_t feature_value
= 0;
2822 supportedWhere
&= kRD_AllPowerSources
; // mask off any craziness!
2824 if(!supportedWhere
) {
2825 // Feature isn't supported anywhere!
2829 if(next_feature_id
> 5000) {
2830 // Far, far too many features!
2834 if(featuresDictLock
) IOLockLock(featuresDictLock
);
2836 OSDictionary
*features
=
2837 (OSDictionary
*) getProperty(kRootDomainSupportedFeatures
);
2839 // Create new features dict if necessary
2840 if ( features
&& OSDynamicCast(OSDictionary
, features
)) {
2841 features
= OSDictionary::withDictionary(features
);
2843 features
= OSDictionary::withCapacity(1);
2846 // Create OSNumber to track new feature
2848 next_feature_id
+= 1;
2849 if( uniqueFeatureID
) {
2850 // We don't really mind if the calling kext didn't give us a place
2851 // to stash their unique id. Many kexts don't plan to unload, and thus
2852 // have no need to remove themselves later.
2853 *uniqueFeatureID
= next_feature_id
;
2856 feature_value
= (uint32_t)next_feature_id
;
2857 feature_value
<<= 16;
2858 feature_value
+= supportedWhere
;
2860 new_feature_data
= OSNumber::withNumber(
2861 (unsigned long long)feature_value
, 32);
2863 // Does features object already exist?
2864 if( (osObj
= features
->getObject(feature
)) )
2866 if(( existing_feature
= OSDynamicCast(OSNumber
, osObj
) ))
2868 // We need to create an OSArray to hold the now 2 elements.
2869 existing_feature_arr
= OSArray::withObjects(
2870 (const OSObject
**)&existing_feature
, 1, 2);
2871 } else if(( existing_feature_arr
= OSDynamicCast(OSArray
, osObj
) ))
2873 // Add object to existing array
2874 existing_feature_arr
= OSArray::withArray(
2875 existing_feature_arr
,
2876 existing_feature_arr
->getCount() + 1);
2879 if (existing_feature_arr
)
2881 existing_feature_arr
->setObject(new_feature_data
);
2882 features
->setObject(feature
, existing_feature_arr
);
2883 existing_feature_arr
->release();
2884 existing_feature_arr
= 0;
2887 // The easy case: no previously existing features listed. We simply
2888 // set the OSNumber at key 'feature' and we're on our way.
2889 features
->setObject(feature
, new_feature_data
);
2892 new_feature_data
->release();
2894 setProperty(kRootDomainSupportedFeatures
, features
);
2896 features
->release();
2898 if(featuresDictLock
) IOLockUnlock(featuresDictLock
);
2900 // Notify EnergySaver and all those in user space so they might
2901 // re-populate their feature specific UI
2902 if(pmPowerStateQueue
) {
2903 pmPowerStateQueue
->submitPowerEvent( kPowerEventFeatureChanged
);
2907 //******************************************************************************
2908 // removePublishedFeature
2910 // Removes previously published feature
2911 //******************************************************************************
2913 IOReturn
IOPMrootDomain::removePublishedFeature( uint32_t removeFeatureID
)
2915 IOReturn ret
= kIOReturnError
;
2916 uint32_t feature_value
= 0;
2917 uint16_t feature_id
= 0;
2918 bool madeAChange
= false;
2920 OSSymbol
*dictKey
= NULL
;
2921 OSCollectionIterator
*dictIterator
= NULL
;
2922 OSArray
*arrayMember
= NULL
;
2923 OSNumber
*numberMember
= NULL
;
2924 OSObject
*osObj
= NULL
;
2925 OSNumber
*osNum
= NULL
;
2926 OSArray
*arrayMemberCopy
;
2928 if(featuresDictLock
) IOLockLock(featuresDictLock
);
2930 OSDictionary
*features
=
2931 (OSDictionary
*) getProperty(kRootDomainSupportedFeatures
);
2933 if ( features
&& OSDynamicCast(OSDictionary
, features
) )
2935 // Any modifications to the dictionary are made to the copy to prevent
2936 // races & crashes with userland clients. Dictionary updated
2937 // automically later.
2938 features
= OSDictionary::withDictionary(features
);
2941 ret
= kIOReturnNotFound
;
2945 // We iterate 'features' dictionary looking for an entry tagged
2946 // with 'removeFeatureID'. If found, we remove it from our tracking
2947 // structures and notify the OS via a general interest message.
2949 dictIterator
= OSCollectionIterator::withCollection(features
);
2954 while( (dictKey
= OSDynamicCast(OSSymbol
, dictIterator
->getNextObject())) )
2956 osObj
= features
->getObject(dictKey
);
2958 // Each Feature is either tracked by an OSNumber
2959 if( osObj
&& (numberMember
= OSDynamicCast(OSNumber
, osObj
)) )
2961 feature_value
= numberMember
->unsigned32BitValue();
2962 feature_id
= (uint16_t)(feature_value
>> 16);
2964 if( feature_id
== (uint16_t)removeFeatureID
)
2967 features
->removeObject(dictKey
);
2972 // Or tracked by an OSArray of OSNumbers
2973 } else if( osObj
&& (arrayMember
= OSDynamicCast(OSArray
, osObj
)) )
2975 unsigned int arrayCount
= arrayMember
->getCount();
2977 for(unsigned int i
=0; i
<arrayCount
; i
++)
2979 osNum
= OSDynamicCast(OSNumber
, arrayMember
->getObject(i
));
2984 feature_value
= osNum
->unsigned32BitValue();
2985 feature_id
= (uint16_t)(feature_value
>> 16);
2987 if( feature_id
== (uint16_t)removeFeatureID
)
2990 if( 1 == arrayCount
) {
2991 // If the array only contains one element, remove
2993 features
->removeObject(dictKey
);
2995 // Otherwise remove the element from a copy of the array.
2996 arrayMemberCopy
= OSArray::withArray(arrayMember
);
2997 if (arrayMemberCopy
)
2999 arrayMemberCopy
->removeObject(i
);
3000 features
->setObject(dictKey
, arrayMemberCopy
);
3001 arrayMemberCopy
->release();
3012 dictIterator
->release();
3016 ret
= kIOReturnSuccess
;
3018 setProperty(kRootDomainSupportedFeatures
, features
);
3020 // Notify EnergySaver and all those in user space so they might
3021 // re-populate their feature specific UI
3022 if(pmPowerStateQueue
) {
3023 pmPowerStateQueue
->submitPowerEvent( kPowerEventFeatureChanged
);
3026 ret
= kIOReturnNotFound
;
3030 if(features
) features
->release();
3031 if(featuresDictLock
) IOLockUnlock(featuresDictLock
);
3035 //******************************************************************************
3036 // setPMSetting (private)
3038 // Internal helper to relay PM settings changes from user space to individual
3039 // drivers. Should be called only by IOPMrootDomain::setProperties.
3040 //******************************************************************************
3042 IOReturn
IOPMrootDomain::setPMSetting(
3043 const OSSymbol
*type
,
3046 PMSettingCallEntry
*entries
= 0;
3047 OSArray
*chosen
= 0;
3048 const OSArray
*array
;
3049 PMSettingObject
*pmso
;
3050 thread_t thisThread
;
3051 int i
, j
, count
, capacity
;
3054 return kIOReturnBadArgument
;
3058 // Update settings dict so changes are visible from copyPMSetting().
3059 fPMSettingsDict
->setObject(type
, object
);
3061 // Prep all PMSetting objects with the given 'type' for callout.
3062 array
= (const OSArray
*) settingsCallbacks
->getObject(type
);
3063 if (!array
|| ((capacity
= array
->getCount()) == 0))
3066 // Array to retain PMSetting objects targeted for callout.
3067 chosen
= OSArray::withCapacity(capacity
);
3069 goto unlock_exit
; // error
3071 entries
= IONew(PMSettingCallEntry
, capacity
);
3073 goto unlock_exit
; // error
3074 memset(entries
, 0, sizeof(PMSettingCallEntry
) * capacity
);
3076 thisThread
= current_thread();
3078 for (i
= 0, j
= 0; i
<capacity
; i
++)
3080 pmso
= (PMSettingObject
*) array
->getObject(i
);
3083 entries
[j
].thread
= thisThread
;
3084 queue_enter(&pmso
->calloutQueue
, &entries
[j
], PMSettingCallEntry
*, link
);
3085 chosen
->setObject(pmso
);
3094 // Call each pmso in the chosen array.
3095 for (i
=0; i
<count
; i
++)
3097 pmso
= (PMSettingObject
*) chosen
->getObject(i
);
3098 pmso
->dispatchPMSetting(type
, object
);
3102 for (i
=0; i
<count
; i
++)
3104 pmso
= (PMSettingObject
*) chosen
->getObject(i
);
3105 queue_remove(&pmso
->calloutQueue
, &entries
[i
], PMSettingCallEntry
*, link
);
3106 if (pmso
->waitThread
)
3108 PMSETTING_WAKEUP(pmso
);
3114 if (chosen
) chosen
->release();
3115 if (entries
) IODelete(entries
, PMSettingCallEntry
, capacity
);
3117 return kIOReturnSuccess
;
3120 //******************************************************************************
3121 // copyPMSetting (public)
3123 // Allows kexts to safely read setting values, without being subscribed to
3125 //******************************************************************************
3127 OSObject
* IOPMrootDomain::copyPMSetting(
3128 OSSymbol
*whichSetting
)
3130 OSObject
*obj
= NULL
;
3132 if(!whichSetting
) return NULL
;
3135 obj
= fPMSettingsDict
->getObject(whichSetting
);
3144 //******************************************************************************
3145 // registerPMSettingController (public)
3147 // direct wrapper to registerPMSettingController with uint32_t power source arg
3148 //******************************************************************************
3150 IOReturn
IOPMrootDomain::registerPMSettingController(
3151 const OSSymbol
* settings
[],
3152 IOPMSettingControllerCallback func
,
3157 return registerPMSettingController(
3159 (kIOPMSupportedOnAC
| kIOPMSupportedOnBatt
| kIOPMSupportedOnUPS
),
3160 func
, target
, refcon
, handle
);
3163 //******************************************************************************
3164 // registerPMSettingController (public)
3166 // Kexts may register for notifications when a particular setting is changed.
3167 // A list of settings is available in IOPM.h.
3169 // * settings - An OSArray containing OSSymbols. Caller should populate this
3170 // array with a list of settings caller wants notifications from.
3171 // * func - A C function callback of the type IOPMSettingControllerCallback
3172 // * target - caller may provide an OSObject *, which PM will pass as an
3173 // target to calls to "func"
3174 // * refcon - caller may provide an void *, which PM will pass as an
3175 // argument to calls to "func"
3176 // * handle - This is a return argument. We will populate this pointer upon
3177 // call success. Hold onto this and pass this argument to
3178 // IOPMrootDomain::deRegisterPMSettingCallback when unloading your kext
3180 // kIOReturnSuccess on success
3181 //******************************************************************************
3183 IOReturn
IOPMrootDomain::registerPMSettingController(
3184 const OSSymbol
* settings
[],
3185 uint32_t supportedPowerSources
,
3186 IOPMSettingControllerCallback func
,
3191 PMSettingObject
*pmso
= NULL
;
3192 OSObject
*pmsh
= NULL
;
3193 OSArray
*list
= NULL
;
3196 if (NULL
== settings
||
3200 return kIOReturnBadArgument
;
3203 pmso
= PMSettingObject::pmSettingObject(
3204 (IOPMrootDomain
*) this, func
, target
,
3205 refcon
, supportedPowerSources
, settings
, &pmsh
);
3209 return kIOReturnInternalError
;
3213 for (i
=0; settings
[i
]; i
++)
3215 list
= (OSArray
*) settingsCallbacks
->getObject(settings
[i
]);
3217 // New array of callbacks for this setting
3218 list
= OSArray::withCapacity(1);
3219 settingsCallbacks
->setObject(settings
[i
], list
);
3223 // Add caller to the callback list
3224 list
->setObject(pmso
);
3228 // Return handle to the caller, the setting object is private.
3231 return kIOReturnSuccess
;
3234 //******************************************************************************
3235 // deregisterPMSettingObject (private)
3237 // Only called from PMSettingObject.
3238 //******************************************************************************
3240 void IOPMrootDomain::deregisterPMSettingObject( PMSettingObject
* pmso
)
3242 thread_t thisThread
= current_thread();
3243 PMSettingCallEntry
*callEntry
;
3244 OSCollectionIterator
*iter
;
3252 pmso
->disabled
= true;
3254 // Wait for all callout threads to finish.
3257 queue_iterate(&pmso
->calloutQueue
, callEntry
, PMSettingCallEntry
*, link
)
3259 if (callEntry
->thread
!= thisThread
)
3267 assert(0 == pmso
->waitThread
);
3268 pmso
->waitThread
= thisThread
;
3269 PMSETTING_WAIT(pmso
);
3270 pmso
->waitThread
= 0;
3274 // Search each PM settings array in the kernel.
3275 iter
= OSCollectionIterator::withCollection(settingsCallbacks
);
3278 while ((sym
= OSDynamicCast(OSSymbol
, iter
->getNextObject())))
3280 array
= (OSArray
*) settingsCallbacks
->getObject(sym
);
3281 index
= array
->getNextIndexOfObject(pmso
, 0);
3283 array
->removeObject(index
);
3294 //******************************************************************************
3295 // informCPUStateChange
3297 // Call into PM CPU code so that CPU power savings may dynamically adjust for
3298 // running on battery, with the lid closed, etc.
3300 // informCPUStateChange is a no-op on non x86 systems
3301 // only x86 has explicit support in the IntelCPUPowerManagement kext
3302 //******************************************************************************
3304 void IOPMrootDomain::informCPUStateChange(
3308 #if defined(__i386__) || defined(__x86_64__)
3310 pmioctlVariableInfo_t varInfoStruct
;
3312 const char *varNameStr
= NULL
;
3313 int32_t *varIndex
= NULL
;
3315 if (kInformAC
== type
) {
3316 varNameStr
= kIOPMRootDomainBatPowerCString
;
3317 varIndex
= &idxPMCPULimitedPower
;
3318 } else if (kInformLid
== type
) {
3319 varNameStr
= kIOPMRootDomainLidCloseCString
;
3320 varIndex
= &idxPMCPUClamshell
;
3325 // Set the new value!
3326 // pmCPUControl will assign us a new ID if one doesn't exist yet
3327 bzero(&varInfoStruct
, sizeof(pmioctlVariableInfo_t
));
3328 varInfoStruct
.varID
= *varIndex
;
3329 varInfoStruct
.varType
= vBool
;
3330 varInfoStruct
.varInitValue
= value
;
3331 varInfoStruct
.varCurValue
= value
;
3332 strncpy( (char *)varInfoStruct
.varName
,
3333 (const char *)varNameStr
,
3334 strlen(varNameStr
) + 1 );
3337 pmCPUret
= pmCPUControl( PMIOCSETVARINFO
, (void *)&varInfoStruct
);
3339 // pmCPU only assigns numerical id's when a new varName is specified
3341 && (*varIndex
== kCPUUnknownIndex
))
3343 // pmCPUControl has assigned us a new variable ID.
3344 // Let's re-read the structure we just SET to learn that ID.
3345 pmCPUret
= pmCPUControl( PMIOCGETVARNAMEINFO
, (void *)&varInfoStruct
);
3349 // Store it in idxPMCPUClamshell or idxPMCPULimitedPower
3350 *varIndex
= varInfoStruct
.varID
;
3356 #endif /* __i386__ || __x86_64__ */
3360 // MARK: Deep Sleep Policy
3364 //******************************************************************************
3365 // evaluateSystemSleepPolicy
3366 //******************************************************************************
3368 struct IOPMSystemSleepPolicyEntry
3370 uint32_t factorMask
;
3371 uint32_t factorBits
;
3372 uint32_t sleepFlags
;
3373 uint32_t wakeEvents
;
3376 struct IOPMSystemSleepPolicyTable
3378 uint8_t signature
[4];
3380 uint16_t entryCount
;
3381 IOPMSystemSleepPolicyEntry entries
[];
3385 kIOPMSleepFactorSleepTimerWake
= 0x00000001,
3386 kIOPMSleepFactorLidOpen
= 0x00000002,
3387 kIOPMSleepFactorACPower
= 0x00000004,
3388 kIOPMSleepFactorLowBattery
= 0x00000008,
3389 kIOPMSleepFactorDeepSleepNoDelay
= 0x00000010,
3390 kIOPMSleepFactorDeepSleepDemand
= 0x00000020,
3391 kIOPMSleepFactorDeepSleepDisable
= 0x00000040,
3392 kIOPMSleepFactorUSBExternalDevice
= 0x00000080,
3393 kIOPMSleepFactorBluetoothHIDDevice
= 0x00000100,
3394 kIOPMSleepFactorExternalMediaMounted
= 0x00000200,
3395 kIOPMSleepFactorDriverAssertBit5
= 0x00000400, /* Reserved for ThunderBolt */
3396 kIOPMSleepFactorDriverAssertBit6
= 0x00000800,
3397 kIOPMSleepFactorDriverAssertBit7
= 0x00001000
3400 bool IOPMrootDomain::evaluateSystemSleepPolicy( IOPMSystemSleepParameters
* p
)
3402 const IOPMSystemSleepPolicyTable
* pt
;
3403 OSObject
* prop
= 0;
3404 OSData
* policyData
;
3405 uint32_t currentFactors
;
3406 uint32_t deepSleepDelay
= 0;
3407 bool success
= false;
3409 if (getProperty(kIOPMDeepSleepEnabledKey
) != kOSBooleanTrue
)
3412 getSleepOption(kIOPMDeepSleepDelayKey
, &deepSleepDelay
);
3414 prop
= getServiceRoot()->copyProperty(kIOPlatformSystemSleepPolicyKey
);
3418 policyData
= OSDynamicCast(OSData
, prop
);
3420 (policyData
->getLength() < sizeof(IOPMSystemSleepPolicyTable
)))
3425 pt
= (const IOPMSystemSleepPolicyTable
*) policyData
->getBytesNoCopy();
3426 if ((pt
->signature
[0] != 'S') ||
3427 (pt
->signature
[1] != 'L') ||
3428 (pt
->signature
[2] != 'P') ||
3429 (pt
->signature
[3] != 'T') ||
3430 (pt
->version
!= 1) ||
3431 (pt
->entryCount
== 0))
3436 if ((policyData
->getLength() - sizeof(IOPMSystemSleepPolicyTable
)) !=
3437 (sizeof(IOPMSystemSleepPolicyEntry
) * pt
->entryCount
))
3443 if (getPMAssertionLevel(kIOPMDriverAssertionUSBExternalDeviceBit
) !=
3444 kIOPMDriverAssertionLevelOff
)
3445 currentFactors
|= kIOPMSleepFactorUSBExternalDevice
;
3446 if (getPMAssertionLevel(kIOPMDriverAssertionBluetoothHIDDevicePairedBit
) !=
3447 kIOPMDriverAssertionLevelOff
)
3448 currentFactors
|= kIOPMSleepFactorBluetoothHIDDevice
;
3449 if (getPMAssertionLevel(kIOPMDriverAssertionExternalMediaMountedBit
) !=
3450 kIOPMDriverAssertionLevelOff
)
3451 currentFactors
|= kIOPMSleepFactorExternalMediaMounted
;
3452 if (getPMAssertionLevel(kIOPMDriverAssertionReservedBit5
) != /* AssertionBit5 = Thunderbolt */
3453 kIOPMDriverAssertionLevelOff
)
3454 currentFactors
|= kIOPMSleepFactorDriverAssertBit5
;
3455 if (getPMAssertionLevel(kIOPMDriverAssertionReservedBit7
) !=
3456 kIOPMDriverAssertionLevelOff
)
3457 currentFactors
|= kIOPMSleepFactorDriverAssertBit7
;
3458 if (0 == deepSleepDelay
)
3459 currentFactors
|= kIOPMSleepFactorDeepSleepNoDelay
;
3460 if (!clamshellClosed
)
3461 currentFactors
|= kIOPMSleepFactorLidOpen
;
3462 if (acAdaptorConnected
)
3463 currentFactors
|= kIOPMSleepFactorACPower
;
3464 if (lowBatteryCondition
)
3465 currentFactors
|= kIOPMSleepFactorLowBattery
;
3466 if (sleepTimerMaintenance
)
3467 currentFactors
|= kIOPMSleepFactorSleepTimerWake
;
3470 if ((hibernateMode
& kIOHibernateModeOn
) == 0)
3471 currentFactors
|= kIOPMSleepFactorDeepSleepDisable
;
3472 else if ((hibernateMode
& kIOHibernateModeSleep
) == 0)
3473 currentFactors
|= kIOPMSleepFactorDeepSleepDemand
;
3475 DLOG("Sleep policy %u entries, current factors 0x%x\n",
3476 pt
->entryCount
, currentFactors
);
3478 for (uint32_t i
= 0; i
< pt
->entryCount
; i
++)
3480 const IOPMSystemSleepPolicyEntry
* policyEntry
= &pt
->entries
[i
];
3482 DLOG("factor mask 0x%08x, bits 0x%08x, flags 0x%08x, wake 0x%08x\n",
3483 policyEntry
->factorMask
, policyEntry
->factorBits
,
3484 policyEntry
->sleepFlags
, policyEntry
->wakeEvents
);
3486 if ((currentFactors
^ policyEntry
->factorBits
) & policyEntry
->factorMask
)
3487 continue; // mismatch, try next
3492 p
->sleepFlags
= policyEntry
->sleepFlags
;
3494 p
->wakeEvents
= policyEntry
->wakeEvents
;
3495 if (p
->sleepFlags
& kIOPMSleepFlagSleepTimerEnable
)
3497 p
->sleepTimer
= deepSleepDelay
;
3501 DLOG("matched policy entry %u\n", i
);
3513 void IOPMrootDomain::evaluateSystemSleepPolicyEarly( void )
3515 IOPMSystemSleepParameters params
;
3517 // Evaluate sleep policy before driver sleep phase.
3519 DLOG("%s\n", __FUNCTION__
);
3520 removeProperty(kIOPMSystemSleepParametersKey
);
3522 hibernateDisabled
= false;
3524 getSleepOption(kIOHibernateModeKey
, &hibernateMode
);
3526 if (!hibernateNoDefeat
&&
3527 evaluateSystemSleepPolicy(¶ms
) &&
3528 ((params
.sleepFlags
& kIOPMSleepFlagHibernate
) == 0))
3530 hibernateDisabled
= true;
3534 void IOPMrootDomain::evaluateSystemSleepPolicyFinal( void )
3536 IOPMSystemSleepParameters params
;
3537 OSData
* paramsData
;
3539 // Evaluate sleep policy after drivers but before platform sleep.
3541 DLOG("%s\n", __FUNCTION__
);
3543 if (evaluateSystemSleepPolicy(¶ms
))
3545 if ((hibernateDisabled
|| hibernateAborted
) &&
3546 (params
.sleepFlags
& kIOPMSleepFlagHibernate
))
3548 // Should hibernate but unable to or aborted.
3549 // Arm timer for a short sleep and retry or wake fully.
3551 params
.sleepFlags
&= ~kIOPMSleepFlagHibernate
;
3552 params
.sleepFlags
|= kIOPMSleepFlagSleepTimerEnable
;
3553 params
.sleepTimer
= 1;
3554 hibernateNoDefeat
= true;
3555 DLOG("wake in %u secs for hibernateDisabled %d, hibernateAborted %d\n",
3556 params
.sleepTimer
, hibernateDisabled
, hibernateAborted
);
3559 hibernateNoDefeat
= false;
3561 paramsData
= OSData::withBytes(¶ms
, sizeof(params
));
3564 setProperty(kIOPMSystemSleepParametersKey
, paramsData
);
3565 paramsData
->release();
3568 if (params
.sleepFlags
& kIOPMSleepFlagHibernate
)
3571 gIOHibernateMode
&= ~kIOHibernateModeSleep
;
3576 bool IOPMrootDomain::getHibernateSettings(
3577 uint32_t * hibernateMode
,
3578 uint32_t * hibernateFreeRatio
,
3579 uint32_t * hibernateFreeTime
)
3581 bool ok
= getSleepOption(kIOHibernateModeKey
, hibernateMode
);
3582 getSleepOption(kIOHibernateFreeRatioKey
, hibernateFreeRatio
);
3583 getSleepOption(kIOHibernateFreeTimeKey
, hibernateFreeTime
);
3584 if (hibernateDisabled
)
3586 DLOG("hibernateMode 0x%x\n", *hibernateMode
);
3590 bool IOPMrootDomain::getSleepOption( const char * key
, uint32_t * option
)
3592 OSObject
* optionsProp
;
3593 OSDictionary
* optionsDict
;
3598 optionsProp
= copyProperty(kRootDomainSleepOptionsKey
);
3599 optionsDict
= OSDynamicCast(OSDictionary
, optionsProp
);
3603 obj
= optionsDict
->getObject(key
);
3604 if (obj
) obj
->retain();
3608 obj
= copyProperty(key
);
3610 if (obj
&& (num
= OSDynamicCast(OSNumber
, obj
)))
3612 *option
= num
->unsigned32BitValue();
3619 optionsProp
->release();
3623 #endif /* HIBERNATION */
3626 // MARK: Shutdown and Restart
3628 //******************************************************************************
3629 // handlePlatformHaltRestart
3631 //******************************************************************************
3633 struct HaltRestartApplierContext
{
3634 IOPMrootDomain
* RootDomain
;
3635 unsigned long PowerState
;
3636 IOPMPowerFlags PowerFlags
;
3642 platformHaltRestartApplier( OSObject
* object
, void * context
)
3644 IOPowerStateChangeNotification notify
;
3645 HaltRestartApplierContext
* ctx
;
3646 AbsoluteTime startTime
;
3649 ctx
= (HaltRestartApplierContext
*) context
;
3651 memset(¬ify
, 0, sizeof(notify
));
3652 notify
.powerRef
= (void *)ctx
->Counter
;
3653 notify
.returnValue
= 0;
3654 notify
.stateNumber
= ctx
->PowerState
;
3655 notify
.stateFlags
= ctx
->PowerFlags
;
3657 clock_get_uptime(&startTime
);
3658 ctx
->RootDomain
->messageClient( ctx
->MessageType
, object
, (void *)¬ify
);
3659 deltaTime
= computeDeltaTimeMS(&startTime
);
3661 if ((deltaTime
> kPMHaltTimeoutMS
) ||
3662 (gIOKitDebug
& kIOLogPMRootDomain
))
3664 _IOServiceInterestNotifier
* notifier
;
3665 notifier
= OSDynamicCast(_IOServiceInterestNotifier
, object
);
3667 // IOService children of IOPMrootDomain are not instrumented.
3668 // Only IORootParent currently falls under that group.
3672 LOG("%s handler %p took %u ms\n",
3673 (ctx
->MessageType
== kIOMessageSystemWillPowerOff
) ? "PowerOff" :
3674 (ctx
->MessageType
== kIOMessageSystemPagingOff
) ? "PagingOff" : "Restart",
3675 notifier
->handler
, (uint32_t) deltaTime
);
3682 void IOPMrootDomain::handlePlatformHaltRestart( UInt32 pe_type
)
3684 HaltRestartApplierContext ctx
;
3685 AbsoluteTime startTime
;
3688 memset(&ctx
, 0, sizeof(ctx
));
3689 ctx
.RootDomain
= this;
3691 clock_get_uptime(&startTime
);
3695 case kPEUPSDelayHaltCPU
:
3696 ctx
.PowerState
= OFF_STATE
;
3697 ctx
.MessageType
= kIOMessageSystemWillPowerOff
;
3701 ctx
.PowerState
= RESTART_STATE
;
3702 ctx
.MessageType
= kIOMessageSystemWillRestart
;
3706 ctx
.PowerState
= ON_STATE
;
3707 ctx
.MessageType
= kIOMessageSystemPagingOff
;
3714 // Notify legacy clients
3715 applyToInterested(gIOPriorityPowerStateInterest
, platformHaltRestartApplier
, &ctx
);
3717 // For normal shutdown, turn off File Server Mode.
3718 if (kPEHaltCPU
== pe_type
)
3720 const OSSymbol
* setting
= OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey
);
3721 OSNumber
* num
= OSNumber::withNumber((unsigned long long) 0, 32);
3724 setPMSetting(setting
, num
);
3730 if (kPEPagingOff
!= pe_type
)
3732 // Notify in power tree order
3733 notifySystemShutdown(this, ctx
.MessageType
);
3736 deltaTime
= computeDeltaTimeMS(&startTime
);
3737 LOG("%s all drivers took %u ms\n",
3738 (ctx
.MessageType
== kIOMessageSystemWillPowerOff
) ? "PowerOff" :
3739 (ctx
.MessageType
== kIOMessageSystemPagingOff
) ? "PagingOff" : "Restart",
3740 (uint32_t) deltaTime
);
3743 //******************************************************************************
3746 //******************************************************************************
3748 IOReturn
IOPMrootDomain::shutdownSystem( void )
3750 return kIOReturnUnsupported
;
3753 //******************************************************************************
3756 //******************************************************************************
3758 IOReturn
IOPMrootDomain::restartSystem( void )
3760 return kIOReturnUnsupported
;
3764 // MARK: System Capability
3766 //******************************************************************************
3767 // tagPowerPlaneService
3769 // Running on PM work loop thread.
3770 //******************************************************************************
3772 void IOPMrootDomain::tagPowerPlaneService(
3773 IOService
* service
,
3774 IOPMActions
* actions
)
3777 bool isDisplayWrangler
;
3779 memset(actions
, 0, sizeof(*actions
));
3780 actions
->target
= this;
3782 if (service
== this)
3784 actions
->actionPowerChangeStart
=
3785 OSMemberFunctionCast(
3786 IOPMActionPowerChangeStart
, this,
3787 &IOPMrootDomain::handleOurPowerChangeStart
);
3789 actions
->actionPowerChangeDone
=
3790 OSMemberFunctionCast(
3791 IOPMActionPowerChangeDone
, this,
3792 &IOPMrootDomain::handleOurPowerChangeDone
);
3794 actions
->actionPowerChangeOverride
=
3795 OSMemberFunctionCast(
3796 IOPMActionPowerChangeOverride
, this,
3797 &IOPMrootDomain::overrideOurPowerChange
);
3802 isDisplayWrangler
= (0 != service
->metaCast("IODisplayWrangler"));
3803 if (isDisplayWrangler
)
3806 wranglerConnection
= (IOService
*) service
->getParentEntry(gIOPowerPlane
);
3809 isDisplayWrangler
= false;
3812 #if defined(__i386__) || defined(__x86_64__)
3813 if (isDisplayWrangler
)
3814 flags
|= kPMActionsFlagIsDisplayWrangler
;
3815 if (service
->getProperty("IOPMStrictTreeOrder"))
3816 flags
|= kPMActionsFlagIsGraphicsDevice
;
3817 if (service
->getProperty("IOPMUnattendedWakePowerState"))
3818 flags
|= kPMActionsFlagIsAudioDevice
;
3821 // Find the power connection object that is a child of the PCI host
3822 // bridge, and has a graphics/audio device attached below. Mark the
3823 // power branch for delayed child notifications.
3827 IORegistryEntry
* child
= service
;
3828 IORegistryEntry
* parent
= child
->getParentEntry(gIOPowerPlane
);
3830 while (child
!= this)
3832 if ((parent
== pciHostBridgeDriver
) ||
3835 if (OSDynamicCast(IOPowerConnection
, child
))
3837 IOPowerConnection
* conn
= (IOPowerConnection
*) child
;
3838 conn
->delayChildNotification
= true;
3843 parent
= child
->getParentEntry(gIOPowerPlane
);
3849 DLOG("%s tag flags %x\n", service
->getName(), flags
);
3850 actions
->parameter
|= flags
;
3851 actions
->actionPowerChangeOverride
=
3852 OSMemberFunctionCast(
3853 IOPMActionPowerChangeOverride
, this,
3854 &IOPMrootDomain::overridePowerChangeForUIService
);
3856 if (flags
& kPMActionsFlagIsDisplayWrangler
)
3858 actions
->actionActivityTickle
=
3859 OSMemberFunctionCast(
3860 IOPMActionActivityTickle
, this,
3861 &IOPMrootDomain::handleActivityTickleForDisplayWrangler
);
3866 // Locate the first PCI host bridge for PMTrace.
3867 if (!pciHostBridgeDevice
&& service
->metaCast("IOPCIBridge"))
3869 IOService
* provider
= service
->getProvider();
3870 if (OSDynamicCast(IOPlatformDevice
, provider
) &&
3871 provider
->inPlane(gIODTPlane
))
3873 pciHostBridgeDevice
= provider
;
3874 pciHostBridgeDriver
= service
;
3875 DLOG("PMTrace found PCI host bridge %s->%s\n",
3876 provider
->getName(), service
->getName());
3880 // Tag top-level PCI devices. The order of PMinit() call does not
3881 // change across boots and is used as the PCI bit number.
3882 if (pciHostBridgeDevice
&& service
->metaCast("IOPCIDevice"))
3884 // Would prefer to check built-in property, but tagPowerPlaneService()
3885 // is called before pciDevice->registerService().
3886 IORegistryEntry
* parent
= service
->getParentEntry(gIODTPlane
);
3887 if ((parent
== pciHostBridgeDevice
) && service
->getProperty("acpi-device"))
3889 int bit
= pmTracer
->recordTopLevelPCIDevice( service
);
3892 // Save the assigned bit for fast lookup.
3893 actions
->parameter
|= (bit
& kPMActionsPCIBitNumberMask
);
3895 actions
->actionPowerChangeStart
=
3896 OSMemberFunctionCast(
3897 IOPMActionPowerChangeStart
, this,
3898 &IOPMrootDomain::handlePowerChangeStartForPCIDevice
);
3900 actions
->actionPowerChangeDone
=
3901 OSMemberFunctionCast(
3902 IOPMActionPowerChangeDone
, this,
3903 &IOPMrootDomain::handlePowerChangeDoneForPCIDevice
);
3909 //******************************************************************************
3910 // PM actions for root domain
3911 //******************************************************************************
3913 void IOPMrootDomain::overrideOurPowerChange(
3914 IOService
* service
,
3915 IOPMActions
* actions
,
3916 unsigned long * inOutPowerState
,
3917 uint32_t * inOutChangeFlags
)
3919 uint32_t powerState
= (uint32_t) *inOutPowerState
;
3920 uint32_t changeFlags
= *inOutChangeFlags
;
3921 uint32_t currentPowerState
= (uint32_t) getPowerState();
3923 if ((currentPowerState
== powerState
) ||
3924 (changeFlags
& kIOPMParentInitiated
))
3926 // FIXME: cancel any parent change (unexpected)
3927 // Root parent is permanently pegged at max power,
3928 // kIOPMParentInitiated is unexpected.
3932 if (powerState
< currentPowerState
)
3934 if ((changeFlags
& kIOPMSkipAskPowerDown
) == 0)
3936 /* Convenient place to run any code at idle sleep time
3937 * IOPMrootDomain initiates an idle sleep here
3939 * Set last sleep cause accordingly.
3941 pmPowerStateQueue
->submitPowerEvent(kPowerEventPublishSleepWakeUUID
, (void *)true);
3943 lastSleepReason
= kIOPMSleepReasonIdle
;
3944 setProperty(kRootDomainSleepReasonKey
, kIOPMIdleSleepKey
);
3946 if (CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
3948 // Root domain is dropping power state ON->SLEEP.
3949 // If system is in full wake, first drop to dark wake.
3951 darkWakeToSleepASAP
= true;
3953 // Drop graphics capability.
3954 // No transition if system is already in dark wake.
3956 _desiredCapability
&= ~(
3957 kIOPMSystemCapabilityGraphics
|
3958 kIOPMSystemCapabilityAudio
);
3960 *inOutPowerState
= ON_STATE
;
3961 *inOutChangeFlags
|= kIOPMSynchronize
;
3963 // Revert device desire from SLEEP->ON.
3964 changePowerStateToPriv(ON_STATE
);
3969 void IOPMrootDomain::handleOurPowerChangeStart(
3970 IOService
* service
,
3971 IOPMActions
* actions
,
3972 uint32_t powerState
,
3973 uint32_t * inOutChangeFlags
)
3975 uint32_t changeFlags
= *inOutChangeFlags
;
3976 uint32_t currentPowerState
= (uint32_t) getPowerState();
3978 _systemTransitionType
= kSystemTransitionNone
;
3979 _systemMessageClientMask
= 0;
3980 capabilityLoss
= false;
3982 // 1. Explicit capability change.
3984 if (changeFlags
& kIOPMSynchronize
)
3986 if (powerState
== ON_STATE
)
3988 if (changeFlags
& kIOPMSyncNoChildNotify
)
3989 _systemTransitionType
= kSystemTransitionNewCapClient
;
3991 _systemTransitionType
= kSystemTransitionCapability
;
3995 // 2. Going to sleep (cancellation still possible).
3997 else if (powerState
< currentPowerState
)
3998 _systemTransitionType
= kSystemTransitionSleep
;
4000 // 3. Woke from (idle or demand) sleep.
4002 else if (!systemBooting
&&
4003 (changeFlags
& kIOPMSelfInitiated
) &&
4004 (powerState
> currentPowerState
))
4006 _systemTransitionType
= kSystemTransitionWake
;
4007 _desiredCapability
= kIOPMSystemCapabilityCPU
|
4008 kIOPMSystemCapabilityNetwork
;
4010 // Check for early HID events (e.g. LID open)
4011 if (wranglerTickled
)
4013 _desiredCapability
|= (
4014 kIOPMSystemCapabilityGraphics
|
4015 kIOPMSystemCapabilityAudio
);
4019 // Update pending wake capability at the beginning of every
4020 // state transition (including synchronize). This will become
4021 // the current capability at the end of the transition.
4023 if (kSystemTransitionSleep
== _systemTransitionType
)
4025 _pendingCapability
= 0;
4026 capabilityLoss
= true;
4028 else if (kSystemTransitionNewCapClient
!= _systemTransitionType
)
4030 _pendingCapability
= _desiredCapability
|
4031 kIOPMSystemCapabilityCPU
|
4032 kIOPMSystemCapabilityNetwork
;
4034 if (_pendingCapability
& kIOPMSystemCapabilityGraphics
)
4035 _pendingCapability
|= kIOPMSystemCapabilityAudio
;
4037 if ((kSystemTransitionCapability
== _systemTransitionType
) &&
4038 (_pendingCapability
== _currentCapability
))
4040 // Cancel the PM state change.
4041 _systemTransitionType
= kSystemTransitionNone
;
4042 *inOutChangeFlags
|= kIOPMNotDone
;
4044 if (__builtin_popcount(_pendingCapability
) <
4045 __builtin_popcount(_currentCapability
))
4046 capabilityLoss
= true;
4047 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
))
4048 rejectWranglerTickle
= true;
4051 // 1. Capability change.
4053 if (kSystemTransitionCapability
== _systemTransitionType
)
4055 // Dark to Full transition.
4056 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
))
4058 tracePoint( kIOPMTracePointDarkWakeExit
);
4059 wranglerSleepIgnored
= false;
4060 sleepTimerMaintenance
= false;
4061 hibernateNoDefeat
= false;
4062 _systemMessageClientMask
= kSystemMessageClientUser
;
4063 if ((_highestCapability
& kIOPMSystemCapabilityGraphics
) == 0)
4064 _systemMessageClientMask
|= kSystemMessageClientKernel
;
4066 tellClients(kIOMessageSystemWillPowerOn
);
4069 // Full to Dark transition.
4070 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
))
4072 tracePoint( kIOPMTracePointDarkWakeEntry
);
4073 *inOutChangeFlags
|= kIOPMSyncTellPowerDown
;
4074 _systemMessageClientMask
= kSystemMessageClientUser
;
4080 else if (kSystemTransitionSleep
== _systemTransitionType
)
4082 // Beginning of a system sleep transition.
4083 // Cancellation is still possible.
4084 tracePoint( kIOPMTracePointSleepStarted
, lastSleepReason
);
4086 _systemMessageClientMask
= kSystemMessageClientAll
;
4087 if ((_currentCapability
& kIOPMSystemCapabilityGraphics
) == 0)
4088 _systemMessageClientMask
&= ~kSystemMessageClientApp
;
4089 if ((_highestCapability
& kIOPMSystemCapabilityGraphics
) == 0)
4090 _systemMessageClientMask
&= ~kSystemMessageClientKernel
;
4092 // Optimization to ignore wrangler power down thus skipping
4093 // the disk spindown and arming the idle timer for demand sleep.
4095 if (changeFlags
& kIOPMIgnoreChildren
)
4097 wranglerSleepIgnored
= true;
4100 logWranglerTickle
= false;
4105 else if (kSystemTransitionWake
== _systemTransitionType
)
4107 wranglerSleepIgnored
= false;
4109 if (_pendingCapability
& kIOPMSystemCapabilityGraphics
)
4111 _systemMessageClientMask
= kSystemMessageClientAll
;
4115 _systemMessageClientMask
= kSystemMessageClientConfigd
;
4118 tracePoint( kIOPMTracePointWakeWillPowerOnClients
);
4119 tellClients(kIOMessageSystemWillPowerOn
);
4122 if ((kSystemTransitionNone
!= _systemTransitionType
) &&
4123 (kSystemTransitionNewCapClient
!= _systemTransitionType
))
4125 _systemStateGeneration
++;
4126 systemDarkWake
= false;
4128 DLOG("=== START (%u->%u, 0x%x) type %u, gen %u, msg %x, "
4130 currentPowerState
, powerState
, *inOutChangeFlags
,
4131 _systemTransitionType
, _systemStateGeneration
,
4132 _systemMessageClientMask
,
4133 _desiredCapability
, _currentCapability
, _pendingCapability
);
4137 void IOPMrootDomain::handleOurPowerChangeDone(
4138 IOService
* service
,
4139 IOPMActions
* actions
,
4140 uint32_t powerState
,
4141 uint32_t changeFlags
)
4143 if (kSystemTransitionNewCapClient
== _systemTransitionType
)
4145 _systemTransitionType
= kSystemTransitionNone
;
4149 if (_systemTransitionType
!= kSystemTransitionNone
)
4151 uint32_t currentPowerState
= (uint32_t) getPowerState();
4153 if (changeFlags
& kIOPMNotDone
)
4155 // Power down was cancelled or vetoed.
4156 _pendingCapability
= _currentCapability
;
4157 lastSleepReason
= 0;
4159 if (((_currentCapability
& kIOPMSystemCapabilityGraphics
) == 0) &&
4160 (_currentCapability
& kIOPMSystemCapabilityCPU
))
4162 pmPowerStateQueue
->submitPowerEvent(
4163 kPowerEventPolicyStimulus
,
4164 (void *) kStimulusDarkWakeReentry
,
4165 _systemStateGeneration
);
4168 // Revert device desire to max.
4169 changePowerStateToPriv(ON_STATE
);
4173 // Send message on dark wake to full wake promotion.
4174 // tellChangeUp() handles the normal SLEEP->ON case.
4176 if (kSystemTransitionCapability
== _systemTransitionType
)
4178 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
))
4180 tellClients(kIOMessageSystemHasPoweredOn
);
4181 #if DARK_TO_FULL_EVALUATE_CLAMSHELL
4182 // Re-evaluate clamshell state ourselves when graphics
4183 // will not get kIOMessageSystemHasPoweredOn.
4185 if (clamshellClosed
&&
4186 ((_systemMessageClientMask
& kSystemMessageClientKernel
) == 0))
4188 receivePowerNotification( kLocalEvalClamshellCommand
);
4192 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
))
4193 wranglerTickled
= false;
4196 // Reset state after exiting from dark wake.
4198 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
) ||
4199 CAP_LOSS(kIOPMSystemCapabilityCPU
))
4201 darkWakeMaintenance
= false;
4202 darkWakeToSleepASAP
= false;
4203 pciCantSleepValid
= false;
4204 rejectWranglerTickle
= false;
4207 // Entered dark mode.
4209 if (((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0) &&
4210 (_pendingCapability
& kIOPMSystemCapabilityCPU
))
4212 if (((gDarkWakeFlags
& kDarkWakeFlagIgnoreDiskIOInDark
) == 0) &&
4213 (kSystemTransitionWake
== _systemTransitionType
) &&
4214 (_debugWakeSeconds
== 0))
4216 OSObject
* prop
= copyProperty(kIOPMRootDomainWakeTypeKey
);
4219 OSString
* wakeType
= OSDynamicCast(OSString
, prop
);
4221 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeNetwork
))
4223 // Woke from network and entered dark wake.
4224 if (darkWakeToSleepASAP
)
4226 DLOG("cleared darkWakeToSleepASAP\n");
4227 darkWakeToSleepASAP
= false;
4234 // Queue an evaluation of whether to remain in dark wake,
4235 // and for how long. This serves the purpose of draining
4236 // any assertions from the queue.
4238 pmPowerStateQueue
->submitPowerEvent(
4239 kPowerEventPolicyStimulus
,
4240 (void *) kStimulusDarkWakeEntry
,
4241 _systemStateGeneration
);
4245 DLOG("=== FINISH (%u->%u, 0x%x) type %u, gen %u, msg %x, "
4246 "dcp %x:%x:%x, dbgtimer %u\n",
4247 currentPowerState
, powerState
, changeFlags
,
4248 _systemTransitionType
, _systemStateGeneration
,
4249 _systemMessageClientMask
,
4250 _desiredCapability
, _currentCapability
, _pendingCapability
,
4253 // Update current system capability.
4255 if (_currentCapability
!= _pendingCapability
)
4256 _currentCapability
= _pendingCapability
;
4258 // Update highest system capability.
4260 if (!CAP_CURRENT(kIOPMSystemCapabilityCPU
))
4261 _highestCapability
= 0; // reset at sleep state
4263 _highestCapability
|= _currentCapability
;
4265 if (darkWakePostTickle
&&
4266 (kSystemTransitionWake
== _systemTransitionType
) &&
4267 (gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
4268 kDarkWakeFlagHIDTickleLate
)
4270 darkWakePostTickle
= false;
4274 // Reset tracepoint at completion of capability change,
4275 // completion of wake transition, and aborted sleep transition.
4277 if ((_systemTransitionType
== kSystemTransitionCapability
) ||
4278 (_systemTransitionType
== kSystemTransitionWake
) ||
4279 ((_systemTransitionType
== kSystemTransitionSleep
) &&
4280 (changeFlags
& kIOPMNotDone
)))
4282 setProperty(kIOPMSystemCapabilitiesKey
, _currentCapability
, 64);
4283 tracePoint( kIOPMTracePointSystemUp
, 0 );
4286 _systemTransitionType
= kSystemTransitionNone
;
4287 _systemMessageClientMask
= 0;
4289 logGraphicsClamp
= false;
4293 //******************************************************************************
4294 // PM actions for graphics and audio.
4295 //******************************************************************************
4297 void IOPMrootDomain::overridePowerChangeForUIService(
4298 IOService
* service
,
4299 IOPMActions
* actions
,
4300 unsigned long * inOutPowerState
,
4301 uint32_t * inOutChangeFlags
)
4303 uint32_t powerState
= (uint32_t) *inOutPowerState
;
4304 uint32_t changeFlags
= (uint32_t) *inOutChangeFlags
;
4306 if (kSystemTransitionNone
== _systemTransitionType
)
4308 // Not in midst of a system transition.
4309 // Do not modify power limit enable state.
4311 else if ((actions
->parameter
& kPMActionsFlagLimitPower
) == 0)
4313 // Activate power limiter.
4315 if ((actions
->parameter
& kPMActionsFlagIsDisplayWrangler
) &&
4316 ((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0))
4318 actions
->parameter
|= kPMActionsFlagLimitPower
;
4320 else if ((actions
->parameter
& kPMActionsFlagIsAudioDevice
) &&
4321 ((_pendingCapability
& kIOPMSystemCapabilityAudio
) == 0))
4323 actions
->parameter
|= kPMActionsFlagLimitPower
;
4325 else if ((actions
->parameter
& kPMActionsFlagIsGraphicsDevice
) &&
4326 (_systemTransitionType
== kSystemTransitionSleep
))
4328 // For graphics devices, arm the limiter when entering
4329 // system sleep. Not when dropping to dark wake.
4330 actions
->parameter
|= kPMActionsFlagLimitPower
;
4333 if (actions
->parameter
& kPMActionsFlagLimitPower
)
4335 DLOG("+ plimit %s %p\n",
4336 service
->getName(), service
);
4341 // Remove power limit.
4343 if ((actions
->parameter
& (
4344 kPMActionsFlagIsDisplayWrangler
|
4345 kPMActionsFlagIsGraphicsDevice
)) &&
4346 (_pendingCapability
& kIOPMSystemCapabilityGraphics
))
4348 actions
->parameter
&= ~kPMActionsFlagLimitPower
;
4350 else if ((actions
->parameter
& kPMActionsFlagIsAudioDevice
) &&
4351 (_pendingCapability
& kIOPMSystemCapabilityAudio
))
4353 actions
->parameter
&= ~kPMActionsFlagLimitPower
;
4356 if ((actions
->parameter
& kPMActionsFlagLimitPower
) == 0)
4358 DLOG("- plimit %s %p\n",
4359 service
->getName(), service
);
4363 if (actions
->parameter
& kPMActionsFlagLimitPower
)
4365 uint32_t maxPowerState
= (uint32_t)(-1);
4367 if (changeFlags
& (kIOPMDomainDidChange
| kIOPMDomainWillChange
))
4369 // Enforce limit for system power/cap transitions.
4372 if (actions
->parameter
& kPMActionsFlagIsDisplayWrangler
)
4374 // Forces a 3->1 transition sequence
4375 if (changeFlags
& kIOPMDomainWillChange
)
4383 // Deny all self-initiated changes when power is limited.
4384 // Wrangler tickle should never defeat the limiter.
4386 maxPowerState
= service
->getPowerState();
4389 if (powerState
> maxPowerState
)
4391 DLOG("> plimit %s %p (%u->%u, 0x%x)\n",
4392 service
->getName(), service
, powerState
, maxPowerState
,
4394 *inOutPowerState
= maxPowerState
;
4396 if (darkWakePostTickle
&&
4397 (actions
->parameter
& kPMActionsFlagIsDisplayWrangler
) &&
4398 (changeFlags
& kIOPMDomainWillChange
) &&
4399 ((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
4400 kDarkWakeFlagHIDTickleEarly
))
4402 darkWakePostTickle
= false;
4407 if (!graphicsSuppressed
&& (changeFlags
& kIOPMDomainDidChange
))
4409 if (logGraphicsClamp
)
4414 clock_get_uptime(&now
);
4415 SUB_ABSOLUTETIME(&now
, &systemWakeTime
);
4416 absolutetime_to_nanoseconds(now
, &nsec
);
4417 MSG("Graphics suppressed %u ms\n",
4418 ((int)((nsec
) / 1000000ULL)));
4420 graphicsSuppressed
= true;
4425 void IOPMrootDomain::handleActivityTickleForDisplayWrangler(
4426 IOService
* service
,
4427 IOPMActions
* actions
)
4429 // Warning: Not running in PM work loop context - don't modify state !!!
4430 // Trap tickle directed to IODisplayWrangler while running with graphics
4431 // capability suppressed.
4433 assert(service
== wrangler
);
4435 if (service
== wrangler
)
4437 bool aborting
= ((lastSleepReason
== kIOPMSleepReasonIdle
)
4438 || (lastSleepReason
== kIOPMSleepReasonMaintenance
));
4440 userActivityCount
++;
4441 DLOG("display wrangler tickled1 %d lastSleepReason %d\n", userActivityCount
, lastSleepReason
);
4445 if (!wranglerTickled
&& !lowBatteryCondition
&&
4446 ((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0))
4448 DLOG("display wrangler tickled\n");
4449 if (kIOLogPMRootDomain
& gIOKitDebug
)
4450 OSReportWithBacktrace("Dark wake display tickle");
4451 if (pmPowerStateQueue
)
4453 pmPowerStateQueue
->submitPowerEvent(
4454 kPowerEventPolicyStimulus
,
4455 (void *) kStimulusDarkWakeActivityTickle
);
4460 //******************************************************************************
4461 // Approve usage of delayed child notification by PM.
4462 //******************************************************************************
4464 bool IOPMrootDomain::shouldDelayChildNotification(
4465 IOService
* service
)
4467 if (((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) != 0) &&
4469 (kSystemTransitionWake
== _systemTransitionType
))
4471 DLOG("%s: delay child notify\n", service
->getName());
4477 //******************************************************************************
4478 // PM actions for PCI device.
4479 //******************************************************************************
4481 void IOPMrootDomain::handlePowerChangeStartForPCIDevice(
4482 IOService
* service
,
4483 IOPMActions
* actions
,
4484 uint32_t powerState
,
4485 uint32_t * inOutChangeFlags
)
4487 pmTracer
->tracePCIPowerChange(
4488 PMTraceWorker::kPowerChangeStart
,
4489 service
, *inOutChangeFlags
,
4490 (actions
->parameter
& kPMActionsPCIBitNumberMask
));
4493 void IOPMrootDomain::handlePowerChangeDoneForPCIDevice(
4494 IOService
* service
,
4495 IOPMActions
* actions
,
4496 uint32_t powerState
,
4497 uint32_t changeFlags
)
4499 pmTracer
->tracePCIPowerChange(
4500 PMTraceWorker::kPowerChangeCompleted
,
4501 service
, changeFlags
,
4502 (actions
->parameter
& kPMActionsPCIBitNumberMask
));
4505 //******************************************************************************
4508 // Override IOService::registerInterest() to intercept special clients.
4509 //******************************************************************************
4511 IONotifier
* IOPMrootDomain::registerInterest(
4512 const OSSymbol
* typeOfInterest
,
4513 IOServiceInterestHandler handler
,
4514 void * target
, void * ref
)
4516 IONotifier
* notifier
;
4517 bool isSystemCapabilityClient
;
4518 bool isKernelCapabilityClient
;
4520 isSystemCapabilityClient
=
4522 typeOfInterest
->isEqualTo(kIOPMSystemCapabilityInterest
);
4524 isKernelCapabilityClient
=
4526 typeOfInterest
->isEqualTo(gIOPriorityPowerStateInterest
);
4528 if (isSystemCapabilityClient
)
4529 typeOfInterest
= gIOAppPowerStateInterest
;
4531 notifier
= super::registerInterest(typeOfInterest
, handler
, target
, ref
);
4532 if (notifier
&& pmPowerStateQueue
)
4534 if (isSystemCapabilityClient
)
4537 if (pmPowerStateQueue
->submitPowerEvent(
4538 kPowerEventRegisterSystemCapabilityClient
, notifier
) == false)
4539 notifier
->release();
4542 if (isKernelCapabilityClient
)
4545 if (pmPowerStateQueue
->submitPowerEvent(
4546 kPowerEventRegisterKernelCapabilityClient
, notifier
) == false)
4547 notifier
->release();
4554 //******************************************************************************
4555 // systemMessageFilter
4557 //******************************************************************************
4559 bool IOPMrootDomain::systemMessageFilter(
4560 void * object
, void * arg1
, void * arg2
, void * arg3
)
4562 const IOPMInterestContext
* context
= (const IOPMInterestContext
*) arg1
;
4563 bool isCapMsg
= (context
->messageType
== kIOMessageSystemCapabilityChange
);
4564 bool isCapClient
= false;
4568 if ((kSystemTransitionNewCapClient
== _systemTransitionType
) &&
4569 (!isCapMsg
|| !_joinedCapabilityClients
||
4570 !_joinedCapabilityClients
->containsObject((OSObject
*) object
)))
4573 // Capability change message for app and kernel clients.
4577 if ((context
->notifyType
== kNotifyPriority
) ||
4578 (context
->notifyType
== kNotifyCapabilityChangePriority
))
4581 if ((context
->notifyType
== kNotifyCapabilityChangeApps
) &&
4582 (object
== (void *) systemCapabilityNotifier
))
4588 IOPMSystemCapabilityChangeParameters
* capArgs
=
4589 (IOPMSystemCapabilityChangeParameters
*) arg2
;
4591 if (kSystemTransitionNewCapClient
== _systemTransitionType
)
4593 capArgs
->fromCapabilities
= 0;
4594 capArgs
->toCapabilities
= _currentCapability
;
4595 capArgs
->changeFlags
= 0;
4599 capArgs
->fromCapabilities
= _currentCapability
;
4600 capArgs
->toCapabilities
= _pendingCapability
;
4602 if (context
->isPreChange
)
4603 capArgs
->changeFlags
= kIOPMSystemCapabilityWillChange
;
4605 capArgs
->changeFlags
= kIOPMSystemCapabilityDidChange
;
4608 // Capability change messages only go to the PM configd plugin.
4609 // Wait for response post-change if capabilitiy is increasing.
4610 // Wait for response pre-change if capability is decreasing.
4612 if ((context
->notifyType
== kNotifyCapabilityChangeApps
) && arg3
&&
4613 ( (capabilityLoss
&& context
->isPreChange
) ||
4614 (!capabilityLoss
&& !context
->isPreChange
) ) )
4616 // app has not replied yet, wait for it
4617 *((OSObject
**) arg3
) = kOSBooleanFalse
;
4624 // Capability client will always see kIOMessageCanSystemSleep,
4625 // even for demand sleep.
4627 if ((kIOMessageCanSystemSleep
== context
->messageType
) ||
4628 (kIOMessageSystemWillNotSleep
== context
->messageType
))
4630 if (object
== (OSObject
*) systemCapabilityNotifier
)
4636 // Not idle sleep, don't ask apps.
4637 if (context
->changeFlags
& kIOPMSkipAskPowerDown
)
4643 // Reject capability change messages for legacy clients.
4644 // Reject legacy system sleep messages for capability client.
4646 if (isCapMsg
|| (object
== (OSObject
*) systemCapabilityNotifier
))
4651 // Filter system sleep messages.
4653 if ((context
->notifyType
== kNotifyApps
) &&
4654 (_systemMessageClientMask
& kSystemMessageClientApp
))
4658 else if ((context
->notifyType
== kNotifyPriority
) &&
4659 (_systemMessageClientMask
& kSystemMessageClientKernel
))
4666 if (allow
&& isCapMsg
&& _joinedCapabilityClients
)
4668 _joinedCapabilityClients
->removeObject((OSObject
*) object
);
4669 if (_joinedCapabilityClients
->getCount() == 0)
4671 DLOG("destroyed capability client set %p\n",
4672 _joinedCapabilityClients
);
4673 _joinedCapabilityClients
->release();
4674 _joinedCapabilityClients
= 0;
4681 //******************************************************************************
4682 // setMaintenanceWakeCalendar
4684 //******************************************************************************
4686 IOReturn
IOPMrootDomain::setMaintenanceWakeCalendar(
4687 const IOPMCalendarStruct
* calendar
)
4693 return kIOReturnBadArgument
;
4695 data
= OSData::withBytesNoCopy((void *) calendar
, sizeof(*calendar
));
4697 return kIOReturnNoMemory
;
4699 ret
= setPMSetting(gIOPMSettingMaintenanceWakeCalendarKey
, data
);
4706 // MARK: Display Wrangler
4708 //******************************************************************************
4709 // displayWranglerNotification
4711 // Handle the notification when the IODisplayWrangler changes power state.
4712 //******************************************************************************
4714 IOReturn
IOPMrootDomain::displayWranglerNotification(
4715 void * target
, void * refCon
,
4716 UInt32 messageType
, IOService
* service
,
4717 void * messageArgument
, vm_size_t argSize
)
4720 int displayPowerState
;
4721 IOPowerStateChangeNotification
* params
=
4722 (IOPowerStateChangeNotification
*) messageArgument
;
4724 if ((messageType
!= kIOMessageDeviceWillPowerOff
) &&
4725 (messageType
!= kIOMessageDeviceHasPoweredOn
))
4726 return kIOReturnUnsupported
;
4730 return kIOReturnUnsupported
;
4732 displayPowerState
= params
->stateNumber
;
4733 DLOG("DisplayWrangler message 0x%x, power state %d\n",
4734 (uint32_t) messageType
, displayPowerState
);
4736 switch (messageType
) {
4737 case kIOMessageDeviceWillPowerOff
:
4739 // Display wrangler has dropped power due to display idle
4740 // or force system sleep.
4745 // 1 Not visible to user
4746 // 0 Not visible to user
4748 if (displayPowerState
> 2)
4751 gRootDomain
->evaluatePolicy( kStimulusDisplayWranglerSleep
);
4754 case kIOMessageDeviceHasPoweredOn
:
4756 // Display wrangler has powered on due to user activity
4757 // or wake from sleep.
4759 if ( 4 != displayPowerState
)
4762 gRootDomain
->evaluatePolicy( kStimulusDisplayWranglerWake
);
4766 return kIOReturnUnsupported
;
4769 //*********************************************************************************
4770 // displayWranglerMatchPublished
4772 // Receives a notification when the IODisplayWrangler is published.
4773 // When it's published we install a power state change handler.
4774 //******************************************************************************
4776 bool IOPMrootDomain::displayWranglerMatchPublished(
4779 IOService
* newService
,
4780 IONotifier
* notifier __unused
)
4783 // found the display wrangler, now install a handler
4784 if( !newService
->registerInterest( gIOGeneralInterest
,
4785 &displayWranglerNotification
, target
, 0) )
4793 //******************************************************************************
4796 //******************************************************************************
4798 void IOPMrootDomain::reportUserInput( void )
4805 iter
= getMatchingServices(serviceMatching("IODisplayWrangler"));
4808 wrangler
= (IOService
*) iter
->getNextObject();
4814 wrangler
->activityTickle(0,0);
4821 //******************************************************************************
4824 // Notification on battery class IOPowerSource appearance
4825 //******************************************************************************
4827 bool IOPMrootDomain::batteryPublished(
4830 IOService
* resourceService
,
4831 IONotifier
* notifier __unused
)
4833 // rdar://2936060&4435589
4834 // All laptops have dimmable LCD displays
4835 // All laptops have batteries
4836 // So if this machine has a battery, publish the fact that the backlight
4837 // supports dimming.
4838 ((IOPMrootDomain
*)root_domain
)->publishFeature("DisplayDims");
4844 // MARK: System PM Policy
4846 //******************************************************************************
4847 // checkSystemCanSleep
4849 //******************************************************************************
4851 bool IOPMrootDomain::checkSystemCanSleep( IOOptionBits options
)
4855 // Conditions that prevent idle and demand system sleep.
4858 if (userDisabledAllSleep
)
4860 err
= 1; // 1. user-space sleep kill switch
4864 if (systemBooting
|| systemShutdown
)
4866 err
= 2; // 2. restart or shutdown in progress
4873 // Conditions above pegs the system at full wake.
4874 // Conditions below prevent system sleep but does not prevent
4875 // dark wake, and must be called from gated context.
4878 err
= 3; // 3. config does not support sleep
4882 if (lowBatteryCondition
)
4884 break; // always sleep on low battery
4887 if (childPreventSystemSleep
)
4889 err
= 4; // 4. child prevent system sleep clamp
4893 if (getPMAssertionLevel( kIOPMDriverAssertionCPUBit
) ==
4894 kIOPMDriverAssertionLevelOn
)
4896 err
= 5; // 5. CPU assertion
4900 if (pciCantSleepValid
)
4902 if (pciCantSleepFlag
)
4903 err
= 6; // 6. PCI card does not support PM (cached)
4906 else if (sleepSupportedPEFunction
&&
4907 CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
4910 OSBitAndAtomic(~kPCICantSleep
, &platformSleepSupport
);
4911 ret
= getPlatform()->callPlatformFunction(
4912 sleepSupportedPEFunction
, false,
4913 NULL
, NULL
, NULL
, NULL
);
4914 pciCantSleepValid
= true;
4915 pciCantSleepFlag
= false;
4916 if ((platformSleepSupport
& kPCICantSleep
) ||
4917 ((ret
!= kIOReturnSuccess
) && (ret
!= kIOReturnUnsupported
)))
4919 err
= 6; // 6. PCI card does not support PM
4920 pciCantSleepFlag
= true;
4929 DLOG("System sleep prevented by %d\n", err
);
4935 //******************************************************************************
4938 // Conditions that affect our wake/sleep decision has changed.
4939 // If conditions dictate that the system must remain awake, clamp power
4940 // state to max with changePowerStateToPriv(ON). Otherwise if sleepASAP
4941 // is TRUE, then remove the power clamp and allow the power state to drop
4943 //******************************************************************************
4945 void IOPMrootDomain::adjustPowerState( bool sleepASAP
)
4947 DLOG("adjustPowerState ps %u, asap %d, slider %ld\n",
4948 (uint32_t) getPowerState(), sleepASAP
, sleepSlider
);
4952 if ((sleepSlider
== 0) || !checkSystemCanSleep())
4954 changePowerStateToPriv(ON_STATE
);
4956 else if ( sleepASAP
)
4958 changePowerStateToPriv(SLEEP_STATE
);
4962 //******************************************************************************
4963 // dispatchPowerEvent
4965 // IOPMPowerStateQueue callback function. Running on PM work loop thread.
4966 //******************************************************************************
4968 void IOPMrootDomain::dispatchPowerEvent(
4969 uint32_t event
, void * arg0
, uint64_t arg1
)
4971 DLOG("power event %u args %p 0x%llx\n", event
, arg0
, arg1
);
4976 case kPowerEventFeatureChanged
:
4977 messageClients(kIOPMMessageFeatureChange
, this);
4980 case kPowerEventReceivedPowerNotification
:
4981 handlePowerNotification( (UInt32
)(uintptr_t) arg0
);
4984 case kPowerEventSystemBootCompleted
:
4987 systemBooting
= false;
4989 // If lid is closed, re-send lid closed notification
4990 // now that booting is complete.
4991 if ( clamshellClosed
)
4993 handlePowerNotification(kLocalEvalClamshellCommand
);
4995 evaluatePolicy( kStimulusAllowSystemSleepChanged
);
4999 case kPowerEventSystemShutdown
:
5000 if (kOSBooleanTrue
== (OSBoolean
*) arg0
)
5002 /* We set systemShutdown = true during shutdown
5003 to prevent sleep at unexpected times while loginwindow is trying
5004 to shutdown apps and while the OS is trying to transition to
5007 Set to true during shutdown, as soon as loginwindow shows
5008 the "shutdown countdown dialog", through individual app
5009 termination, and through black screen kernel shutdown.
5011 systemShutdown
= true;
5014 A shutdown was initiated, but then the shutdown
5015 was cancelled, clearing systemShutdown to false here.
5017 systemShutdown
= false;
5021 case kPowerEventUserDisabledSleep
:
5022 userDisabledAllSleep
= (kOSBooleanTrue
== (OSBoolean
*) arg0
);
5025 case kPowerEventRegisterSystemCapabilityClient
:
5026 if (systemCapabilityNotifier
)
5028 systemCapabilityNotifier
->release();
5029 systemCapabilityNotifier
= 0;
5033 systemCapabilityNotifier
= (IONotifier
*) arg0
;
5034 systemCapabilityNotifier
->retain();
5036 /* intentional fall-through */
5038 case kPowerEventRegisterKernelCapabilityClient
:
5039 if (!_joinedCapabilityClients
)
5040 _joinedCapabilityClients
= OSSet::withCapacity(8);
5043 IONotifier
* notify
= (IONotifier
*) arg0
;
5044 if (_joinedCapabilityClients
)
5046 _joinedCapabilityClients
->setObject(notify
);
5047 synchronizePowerTree( kIOPMSyncNoChildNotify
);
5053 case kPowerEventPolicyStimulus
:
5056 int stimulus
= (uintptr_t) arg0
;
5057 evaluatePolicy( stimulus
, (uint32_t) arg1
);
5061 case kPowerEventAssertionCreate
:
5063 pmAssertions
->handleCreateAssertion((OSData
*)arg0
);
5068 case kPowerEventAssertionRelease
:
5070 pmAssertions
->handleReleaseAssertion(arg1
);
5074 case kPowerEventAssertionSetLevel
:
5076 pmAssertions
->handleSetAssertionLevel(arg1
, (IOPMDriverAssertionLevel
)(uintptr_t)arg0
);
5080 case kPowerEventQueueSleepWakeUUID
:
5081 handleQueueSleepWakeUUID((OSObject
*)arg0
);
5083 case kPowerEventPublishSleepWakeUUID
:
5084 handlePublishSleepWakeUUID((bool)arg0
);
5089 //******************************************************************************
5090 // systemPowerEventOccurred
5092 // The power controller is notifying us of a hardware-related power management
5093 // event that we must handle.
5095 // systemPowerEventOccurred covers the same functionality that
5096 // receivePowerNotification does; it simply provides a richer API for conveying
5097 // more information.
5098 //******************************************************************************
5100 IOReturn
IOPMrootDomain::systemPowerEventOccurred(
5101 const OSSymbol
*event
,
5104 IOReturn attempt
= kIOReturnSuccess
;
5105 OSNumber
*newNumber
= NULL
;
5108 return kIOReturnBadArgument
;
5110 newNumber
= OSNumber::withNumber(intValue
, 8*sizeof(intValue
));
5112 return kIOReturnInternalError
;
5114 attempt
= systemPowerEventOccurred(event
, (OSObject
*)newNumber
);
5116 newNumber
->release();
5121 IOReturn
IOPMrootDomain::systemPowerEventOccurred(
5122 const OSSymbol
*event
,
5125 OSDictionary
*thermalsDict
= NULL
;
5126 bool shouldUpdate
= true;
5128 if (!event
|| !value
)
5129 return kIOReturnBadArgument
;
5132 // We reuse featuresDict Lock because it already exists and guards
5133 // the very infrequently used publish/remove feature mechanism; so there's zero rsk
5134 // of stepping on that lock.
5135 if (featuresDictLock
) IOLockLock(featuresDictLock
);
5137 thermalsDict
= (OSDictionary
*)getProperty(kIOPMRootDomainPowerStatusKey
);
5139 if (thermalsDict
&& OSDynamicCast(OSDictionary
, thermalsDict
)) {
5140 thermalsDict
= OSDictionary::withDictionary(thermalsDict
);
5142 thermalsDict
= OSDictionary::withCapacity(1);
5145 if (!thermalsDict
) {
5146 shouldUpdate
= false;
5150 thermalsDict
->setObject (event
, value
);
5152 setProperty (kIOPMRootDomainPowerStatusKey
, thermalsDict
);
5154 thermalsDict
->release();
5158 if (featuresDictLock
) IOLockUnlock(featuresDictLock
);
5161 messageClients (kIOPMMessageSystemPowerEventOccurred
, (void *)NULL
);
5163 return kIOReturnSuccess
;
5166 //******************************************************************************
5167 // receivePowerNotification
5169 // The power controller is notifying us of a hardware-related power management
5170 // event that we must handle. This may be a result of an 'environment' interrupt
5171 // from the power mgt micro.
5172 //******************************************************************************
5174 IOReturn
IOPMrootDomain::receivePowerNotification( UInt32 msg
)
5176 pmPowerStateQueue
->submitPowerEvent(
5177 kPowerEventReceivedPowerNotification
, (void *) msg
);
5178 return kIOReturnSuccess
;
5181 void IOPMrootDomain::handlePowerNotification( UInt32 msg
)
5183 bool eval_clamshell
= false;
5188 * Local (IOPMrootDomain only) eval clamshell command
5190 if (msg
& kLocalEvalClamshellCommand
)
5192 eval_clamshell
= true;
5198 if (msg
& kIOPMOverTemp
)
5200 MSG("PowerManagement emergency overtemp signal. Going to sleep!");
5201 privateSleepSystem (kIOPMSleepReasonThermalEmergency
);
5207 if (msg
& kIOPMSleepNow
)
5209 privateSleepSystem (kIOPMSleepReasonSoftware
);
5215 if (msg
& kIOPMPowerEmergency
)
5217 lowBatteryCondition
= true;
5218 privateSleepSystem (kIOPMSleepReasonLowPower
);
5224 if (msg
& kIOPMClamshellOpened
)
5226 // Received clamshel open message from clamshell controlling driver
5227 // Update our internal state and tell general interest clients
5228 clamshellClosed
= false;
5229 clamshellExists
= true;
5231 if (msg
& kIOPMSetValue
)
5237 informCPUStateChange(kInformLid
, 0);
5239 // Tell general interest clients
5240 sendClientClamshellNotification();
5242 bool aborting
= ((lastSleepReason
== kIOPMSleepReasonClamshell
)
5243 || (lastSleepReason
== kIOPMSleepReasonIdle
)
5244 || (lastSleepReason
== kIOPMSleepReasonMaintenance
));
5245 if (aborting
) userActivityCount
++;
5246 DLOG("clamshell tickled %d lastSleepReason %d\n", userActivityCount
, lastSleepReason
);
5251 * Send the clamshell interest notification since the lid is closing.
5253 if (msg
& kIOPMClamshellClosed
)
5255 // Received clamshel open message from clamshell controlling driver
5256 // Update our internal state and tell general interest clients
5257 clamshellClosed
= true;
5258 clamshellExists
= true;
5261 informCPUStateChange(kInformLid
, 1);
5263 // Tell general interest clients
5264 sendClientClamshellNotification();
5266 // And set eval_clamshell = so we can attempt
5267 eval_clamshell
= true;
5271 * Set Desktop mode (sent from graphics)
5273 * -> reevaluate lid state
5275 if (msg
& kIOPMSetDesktopMode
)
5277 desktopMode
= (0 != (msg
& kIOPMSetValue
));
5278 msg
&= ~(kIOPMSetDesktopMode
| kIOPMSetValue
);
5280 sendClientClamshellNotification();
5282 // Re-evaluate the lid state
5283 if( clamshellClosed
)
5285 eval_clamshell
= true;
5290 * AC Adaptor connected
5292 * -> reevaluate lid state
5294 if (msg
& kIOPMSetACAdaptorConnected
)
5296 acAdaptorConnected
= (0 != (msg
& kIOPMSetValue
));
5297 msg
&= ~(kIOPMSetACAdaptorConnected
| kIOPMSetValue
);
5300 informCPUStateChange(kInformAC
, !acAdaptorConnected
);
5302 // Tell BSD if AC is connected
5303 // 0 == external power source; 1 == on battery
5304 post_sys_powersource(acAdaptorConnected
? 0:1);
5306 sendClientClamshellNotification();
5308 // Re-evaluate the lid state
5309 if( clamshellClosed
)
5311 eval_clamshell
= true;
5316 * Enable Clamshell (external display disappear)
5318 * -> reevaluate lid state
5320 if (msg
& kIOPMEnableClamshell
)
5322 // Re-evaluate the lid state
5323 // System should sleep on external display disappearance
5324 // in lid closed operation.
5325 if( clamshellClosed
&& (true == clamshellDisabled
) )
5327 eval_clamshell
= true;
5330 clamshellDisabled
= false;
5332 sendClientClamshellNotification();
5336 * Disable Clamshell (external display appeared)
5337 * We don't bother re-evaluating clamshell state. If the system is awake,
5338 * the lid is probably open.
5340 if (msg
& kIOPMDisableClamshell
)
5342 clamshellDisabled
= true;
5344 sendClientClamshellNotification();
5348 * Evaluate clamshell and SLEEP if appropiate
5350 if ( eval_clamshell
&& shouldSleepOnClamshellClosed() )
5355 privateSleepSystem (kIOPMSleepReasonClamshell
);
5357 else if ( eval_clamshell
)
5359 evaluatePolicy(kStimulusDarkWakeEvaluate
);
5365 if (msg
& kIOPMPowerButton
)
5367 if (!wranglerAsleep
)
5369 OSString
*pbs
= OSString::withCString("DisablePowerButtonSleep");
5370 // Check that power button sleep is enabled
5372 if( kOSBooleanTrue
!= getProperty(pbs
))
5373 privateSleepSystem (kIOPMSleepReasonPowerButton
);
5381 //******************************************************************************
5384 // Evaluate root-domain policy in response to external changes.
5385 //******************************************************************************
5387 void IOPMrootDomain::evaluatePolicy( int stimulus
, uint32_t arg
)
5391 int idleSleepEnabled
: 1;
5392 int idleSleepDisabled
: 1;
5393 int displaySleep
: 1;
5394 int sleepDelayChanged
: 1;
5395 int evaluateDarkWake
: 1;
5400 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
5407 case kStimulusDisplayWranglerSleep
:
5408 if (!wranglerAsleep
)
5410 wranglerAsleep
= true;
5411 clock_get_uptime(&wranglerSleepTime
);
5412 flags
.bit
.displaySleep
= true;
5416 case kStimulusDisplayWranglerWake
:
5417 wranglerAsleep
= false;
5418 flags
.bit
.idleSleepDisabled
= true;
5421 case kStimulusAggressivenessChanged
:
5423 unsigned long minutesToIdleSleep
= 0;
5424 unsigned long minutesToDisplayDim
= 0;
5425 unsigned long minutesDelta
= 0;
5427 // Fetch latest display and system sleep slider values.
5428 getAggressiveness(kPMMinutesToSleep
, &minutesToIdleSleep
);
5429 getAggressiveness(kPMMinutesToDim
, &minutesToDisplayDim
);
5430 DLOG("aggressiveness changed: system %u->%u, display %u\n",
5431 (uint32_t) sleepSlider
,
5432 (uint32_t) minutesToIdleSleep
,
5433 (uint32_t) minutesToDisplayDim
);
5435 DLOG("idle time -> %ld secs (ena %d)\n",
5436 idleSeconds
, (minutesToIdleSleep
!= 0));
5438 if (0x7fffffff == minutesToIdleSleep
)
5439 minutesToIdleSleep
= idleSeconds
;
5441 // How long to wait before sleeping the system once
5442 // the displays turns off is indicated by 'extraSleepDelay'.
5444 if ( minutesToIdleSleep
> minutesToDisplayDim
)
5445 minutesDelta
= minutesToIdleSleep
- minutesToDisplayDim
;
5447 if ((sleepSlider
== 0) && (minutesToIdleSleep
!= 0))
5448 flags
.bit
.idleSleepEnabled
= true;
5450 if ((sleepSlider
!= 0) && (minutesToIdleSleep
== 0))
5451 flags
.bit
.idleSleepDisabled
= true;
5453 if ((minutesDelta
!= extraSleepDelay
) &&
5454 !flags
.bit
.idleSleepEnabled
&& !flags
.bit
.idleSleepDisabled
)
5455 flags
.bit
.sleepDelayChanged
= true;
5457 if (systemDarkWake
&& !darkWakeToSleepASAP
&&
5458 (flags
.bit
.idleSleepEnabled
|| flags
.bit
.idleSleepDisabled
))
5460 // Reconsider decision to remain in dark wake
5461 flags
.bit
.evaluateDarkWake
= true;
5464 sleepSlider
= minutesToIdleSleep
;
5465 extraSleepDelay
= minutesDelta
;
5468 case kStimulusDemandSystemSleep
:
5469 changePowerStateWithOverrideTo( SLEEP_STATE
);
5472 case kStimulusAllowSystemSleepChanged
:
5473 // FIXME: de-compose to change flags.
5477 case kStimulusDarkWakeActivityTickle
:
5478 if (false == wranglerTickled
)
5480 uint32_t options
= 0;
5481 IOService
* pciRoot
= 0;
5483 if (rejectWranglerTickle
)
5485 DLOG("rejected tickle, type %u capability %x:%x\n",
5486 _systemTransitionType
,
5487 _currentCapability
, _pendingCapability
);
5491 _desiredCapability
|=
5492 (kIOPMSystemCapabilityGraphics
|
5493 kIOPMSystemCapabilityAudio
);
5495 if ((kSystemTransitionWake
== _systemTransitionType
) &&
5496 !(_pendingCapability
& kIOPMSystemCapabilityGraphics
) &&
5497 !graphicsSuppressed
)
5499 DLOG("Promoting to full wake\n");
5501 // Elevate to full wake while waking up to dark wake.
5502 // PM will hold off notifying the graphics subsystem about
5503 // system wake as late as possible, so if a HID event does
5504 // arrive, we can turn on graphics on this wake cycle, and
5505 // not have to wait till the following cycle. That latency
5506 // can be huge on some systems. However, once any graphics
5507 // suppression has taken effect, it is too late. All other
5508 // graphics devices must be similarly suppressed. But the
5509 // delay till the following cycle should be very short.
5511 _pendingCapability
|=
5512 (kIOPMSystemCapabilityGraphics
|
5513 kIOPMSystemCapabilityAudio
);
5515 // Immediately bring up audio and graphics.
5516 pciRoot
= pciHostBridgeDriver
;
5518 // Notify clients about full wake.
5519 _systemMessageClientMask
= kSystemMessageClientAll
;
5520 tellClients(kIOMessageSystemWillPowerOn
);
5523 // Unsafe to cancel once graphics was powered.
5524 // If system woke from dark wake, the return to sleep can
5525 // be cancelled. But "awake -> dark -> sleep" transition
5526 // cannot be cancelled.
5528 if (!CAP_HIGHEST(kIOPMSystemCapabilityGraphics
)) {
5529 options
|= kIOPMSyncCancelPowerDown
;
5532 synchronizePowerTree( options
, pciRoot
);
5533 wranglerTickled
= true;
5534 // IOGraphics doesn't lit the display even though graphics
5535 // is enanbled in kIOMessageSystemCapabilityChange message(radar 9502104)
5536 // So, do an explicit activity tickle
5538 wrangler
->activityTickle(0,0);
5540 if (logWranglerTickle
)
5545 clock_get_uptime(&now
);
5546 SUB_ABSOLUTETIME(&now
, &systemWakeTime
);
5547 absolutetime_to_nanoseconds(now
, &nsec
);
5548 MSG("HID tickle %u ms\n",
5549 ((int)((nsec
) / 1000000ULL)));
5550 logWranglerTickle
= false;
5555 case kStimulusDarkWakeEntry
:
5556 case kStimulusDarkWakeReentry
:
5557 // Any system transitions since the last dark wake transition
5558 // will invalid the stimulus.
5560 if (arg
== _systemStateGeneration
)
5562 DLOG("dark wake entry\n");
5563 systemDarkWake
= true;
5564 wranglerAsleep
= true;
5565 clock_get_uptime(&wranglerSleepTime
);
5567 // Always accelerate disk spindown while in dark wake,
5568 // even if system does not support/allow sleep.
5570 cancelIdleSleepTimer();
5571 setQuickSpinDownTimeout();
5572 flags
.bit
.evaluateDarkWake
= true;
5576 case kStimulusDarkWakeEvaluate
:
5579 flags
.bit
.evaluateDarkWake
= true;
5581 #if !DARK_TO_FULL_EVALUATE_CLAMSHELL
5584 // Not through kLocalEvalClamshellCommand to avoid loop.
5585 if (clamshellClosed
&& shouldSleepOnClamshellClosed() &&
5586 checkSystemCanSleep(true))
5588 privateSleepSystem( kIOPMSleepReasonClamshell
);
5594 } /* switch(stimulus) */
5596 if (flags
.bit
.evaluateDarkWake
&& !wranglerTickled
)
5598 if (darkWakeToSleepASAP
||
5599 (clamshellClosed
&& !(desktopMode
&& acAdaptorConnected
)))
5601 // System currently in dark wake, and no children and
5602 // assertion prevent system sleep.
5604 if (checkSystemCanSleep(true))
5606 if (lowBatteryCondition
)
5608 lastSleepReason
= kIOPMSleepReasonLowPower
;
5609 setProperty(kRootDomainSleepReasonKey
, kIOPMLowPowerSleepKey
);
5611 else if (darkWakeMaintenance
)
5613 lastSleepReason
= kIOPMSleepReasonMaintenance
;
5614 setProperty(kRootDomainSleepReasonKey
, kIOPMMaintenanceSleepKey
);
5616 changePowerStateWithOverrideTo( SLEEP_STATE
);
5620 // Parked in dark wake, a tickle will return to full wake
5621 rejectWranglerTickle
= false;
5623 } else // non-maintenance (network) dark wake
5625 if (checkSystemCanSleep(true))
5627 // Release power clamp, and wait for children idle.
5628 adjustPowerState(true);
5632 changePowerStateToPriv(ON_STATE
);
5634 rejectWranglerTickle
= false;
5640 // The rest are irrelevant while system is in dark wake.
5644 if (flags
.bit
.displaySleep
|| flags
.bit
.sleepDelayChanged
)
5646 bool cancelQuickSpindown
= false;
5648 if (flags
.bit
.sleepDelayChanged
)
5650 DLOG("extra sleep timer changed\n");
5651 cancelIdleSleepTimer();
5652 cancelQuickSpindown
= true;
5656 DLOG("display sleep\n");
5659 if (wranglerAsleep
&& !wranglerSleepIgnored
)
5661 if ( extraSleepDelay
)
5663 // Start a timer here if the System Sleep timer is greater
5664 // than the Display Sleep timer.
5666 startIdleSleepTimer(gRootDomain
->extraSleepDelay
* 60);
5668 else if ( sleepSlider
)
5670 // Accelerate disk spindown if system sleep and display sleep
5671 // sliders are set to the same value (e.g. both set to 5 min),
5672 // and display is about to go dark. Check the system sleep is
5673 // not set to never sleep. Disk sleep setting is ignored.
5675 setQuickSpinDownTimeout();
5676 cancelQuickSpindown
= false;
5680 if (cancelQuickSpindown
)
5681 restoreUserSpinDownTimeout();
5684 if (flags
.bit
.idleSleepEnabled
)
5686 DLOG("idle sleep timer enabled\n");
5689 changePowerStateToPriv(ON_STATE
);
5692 startIdleSleepTimer( idleSeconds
);
5697 // Start idle sleep timer if wrangler went to sleep
5698 // while system sleep was disabled. Disk spindown is
5699 // accelerated upon timer expiration.
5705 uint32_t minutesSinceDisplaySleep
= 0;
5706 uint32_t sleepDelay
;
5708 clock_get_uptime(&now
);
5709 if (CMP_ABSOLUTETIME(&now
, &wranglerSleepTime
) > 0)
5711 SUB_ABSOLUTETIME(&now
, &wranglerSleepTime
);
5712 absolutetime_to_nanoseconds(now
, &nanos
);
5713 minutesSinceDisplaySleep
= nanos
/ (60000000000ULL);
5716 if (extraSleepDelay
> minutesSinceDisplaySleep
)
5718 sleepDelay
= extraSleepDelay
- minutesSinceDisplaySleep
;
5722 sleepDelay
= 1; // 1 min
5725 startIdleSleepTimer(sleepDelay
* 60);
5726 DLOG("display slept %u min, set idle timer to %u min\n",
5727 minutesSinceDisplaySleep
, sleepDelay
);
5732 if (flags
.bit
.idleSleepDisabled
)
5734 DLOG("idle sleep timer disabled\n");
5735 cancelIdleSleepTimer();
5736 restoreUserSpinDownTimeout();
5744 //******************************************************************************
5747 //******************************************************************************
5749 void IOPMrootDomain::pmStatsRecordEvent(
5751 AbsoluteTime timestamp
)
5753 bool starting
= eventIndex
& kIOPMStatsEventStartFlag
? true:false;
5754 bool stopping
= eventIndex
& kIOPMStatsEventStopFlag
? true:false;
5758 eventIndex
&= ~(kIOPMStatsEventStartFlag
| kIOPMStatsEventStopFlag
);
5760 absolutetime_to_nanoseconds(timestamp
, &nsec
);
5762 switch (eventIndex
) {
5763 case kIOPMStatsHibernateImageWrite
:
5765 pmStats
.hibWrite
.start
= nsec
;
5767 pmStats
.hibWrite
.stop
= nsec
;
5770 delta
= pmStats
.hibWrite
.stop
- pmStats
.hibWrite
.start
;
5771 IOLog("PMStats: Hibernate write took %qd ms\n", delta
/1000000ULL);
5774 case kIOPMStatsHibernateImageRead
:
5776 pmStats
.hibRead
.start
= nsec
;
5778 pmStats
.hibRead
.stop
= nsec
;
5781 delta
= pmStats
.hibRead
.stop
- pmStats
.hibRead
.start
;
5782 IOLog("PMStats: Hibernate read took %qd ms\n", delta
/1000000ULL);
5789 * Appends a record of the application response to
5790 * IOPMrootDomain::pmStatsAppResponses
5792 void IOPMrootDomain::pmStatsRecordApplicationResponse(
5793 const OSSymbol
*response
,
5799 OSDictionary
*responseDescription
= NULL
;
5800 OSNumber
*delayNum
= NULL
;
5801 OSNumber
*pidNum
= NULL
;
5802 OSNumber
*msgNum
= NULL
;
5803 const OSSymbol
*appname
;
5804 const OSSymbol
*entryName
;
5805 OSObject
*entryType
;
5808 if (!pmStatsAppResponses
|| pmStatsAppResponses
->getCount() > 50)
5812 while ((responseDescription
= (OSDictionary
*) pmStatsAppResponses
->getObject(i
++)))
5814 entryType
= responseDescription
->getObject(_statsResponseTypeKey
);
5815 entryName
= (OSSymbol
*) responseDescription
->getObject(_statsNameKey
);
5816 if (entryName
&& (entryType
== response
) && entryName
->isEqualTo(name
))
5818 OSNumber
* entryValue
;
5819 entryValue
= (OSNumber
*) responseDescription
->getObject(_statsTimeMSKey
);
5820 if (entryValue
&& (entryValue
->unsigned32BitValue() < delay_ms
))
5821 entryValue
->setValue(delay_ms
);
5826 responseDescription
= OSDictionary::withCapacity(5);
5827 if (responseDescription
)
5830 responseDescription
->setObject(_statsResponseTypeKey
, response
);
5833 if (messageType
!= 0) {
5834 msgNum
= OSNumber::withNumber(messageType
, 32);
5836 responseDescription
->setObject(_statsMessageTypeKey
, msgNum
);
5841 if (name
&& (strlen(name
) > 0))
5843 appname
= OSSymbol::withCString(name
);
5845 responseDescription
->setObject(_statsNameKey
, appname
);
5850 if (app_pid
!= -1) {
5851 pidNum
= OSNumber::withNumber(app_pid
, 32);
5853 responseDescription
->setObject(_statsPIDKey
, pidNum
);
5858 delayNum
= OSNumber::withNumber(delay_ms
, 32);
5860 responseDescription
->setObject(_statsTimeMSKey
, delayNum
);
5861 delayNum
->release();
5864 if (pmStatsAppResponses
) {
5865 pmStatsAppResponses
->setObject(responseDescription
);
5868 responseDescription
->release();
5874 // MARK: PMTraceWorker
5876 //******************************************************************************
5877 // TracePoint support
5879 //******************************************************************************
5881 #define kIOPMRegisterNVRAMTracePointHandlerKey \
5882 "IOPMRegisterNVRAMTracePointHandler"
5884 IOReturn
IOPMrootDomain::callPlatformFunction(
5885 const OSSymbol
* functionName
,
5886 bool waitForFunction
,
5887 void * param1
, void * param2
,
5888 void * param3
, void * param4
)
5890 if (pmTracer
&& functionName
&&
5891 functionName
->isEqualTo(kIOPMRegisterNVRAMTracePointHandlerKey
) &&
5892 !pmTracer
->tracePointHandler
&& !pmTracer
->tracePointTarget
)
5894 uint32_t tracePointPhases
, tracePointPCI
;
5895 uint64_t statusCode
;
5897 pmTracer
->tracePointHandler
= (IOPMTracePointHandler
) param1
;
5898 pmTracer
->tracePointTarget
= (void *) param2
;
5899 tracePointPCI
= (uint32_t)(uintptr_t) param3
;
5900 tracePointPhases
= (uint32_t)(uintptr_t) param4
;
5901 statusCode
= (((uint64_t)tracePointPCI
) << 32) | tracePointPhases
;
5902 if ((tracePointPhases
>> 24) != kIOPMTracePointSystemUp
)
5904 MSG("Sleep failure code 0x%08x 0x%08x\n",
5905 tracePointPCI
, tracePointPhases
);
5907 setProperty(kIOPMSleepWakeFailureCodeKey
, statusCode
, 64);
5908 pmTracer
->tracePointHandler( pmTracer
->tracePointTarget
, 0, 0 );
5910 return kIOReturnSuccess
;
5913 return super::callPlatformFunction(
5914 functionName
, waitForFunction
, param1
, param2
, param3
, param4
);
5917 void IOPMrootDomain::tracePoint( uint8_t point
)
5920 pmTracer
->tracePoint(point
);
5923 void IOPMrootDomain::tracePoint( uint8_t point
, uint8_t data
)
5926 pmTracer
->tracePoint(point
, data
);
5929 void IOPMrootDomain::traceDetail( uint32_t detail
)
5932 pmTracer
->traceDetail( detail
);
5935 //******************************************************************************
5936 // PMTraceWorker Class
5938 //******************************************************************************
5941 #define super OSObject
5942 OSDefineMetaClassAndStructors(PMTraceWorker
, OSObject
)
5944 #define kPMBestGuessPCIDevicesCount 25
5945 #define kPMMaxRTCBitfieldSize 32
5947 PMTraceWorker
*PMTraceWorker::tracer(IOPMrootDomain
*owner
)
5951 me
= OSTypeAlloc( PMTraceWorker
);
5952 if (!me
|| !me
->init())
5957 DLOG("PMTraceWorker %p\n", me
);
5959 // Note that we cannot instantiate the PCI device -> bit mappings here, since
5960 // the IODeviceTree has not yet been created by IOPlatformExpert. We create
5961 // this dictionary lazily.
5963 me
->pciDeviceBitMappings
= NULL
;
5964 me
->pciMappingLock
= IOLockAlloc();
5965 me
->tracePhase
= kIOPMTracePointSystemUp
;
5966 me
->loginWindowPhase
= 0;
5967 me
->traceData32
= 0;
5971 void PMTraceWorker::RTC_TRACE(void)
5973 if (tracePointHandler
&& tracePointTarget
)
5977 wordA
= (tracePhase
<< 24) | (loginWindowPhase
<< 16) |
5980 tracePointHandler( tracePointTarget
, traceData32
, wordA
);
5981 _LOG("RTC_TRACE wrote 0x%08x 0x%08x\n", traceData32
, wordA
);
5985 int PMTraceWorker::recordTopLevelPCIDevice(IOService
* pciDevice
)
5987 const OSSymbol
* deviceName
;
5990 IOLockLock(pciMappingLock
);
5992 if (!pciDeviceBitMappings
)
5994 pciDeviceBitMappings
= OSArray::withCapacity(kPMBestGuessPCIDevicesCount
);
5995 if (!pciDeviceBitMappings
)
5999 // Check for bitmask overflow.
6000 if (pciDeviceBitMappings
->getCount() >= kPMMaxRTCBitfieldSize
)
6003 if ((deviceName
= pciDevice
->copyName()) &&
6004 (pciDeviceBitMappings
->getNextIndexOfObject(deviceName
, 0) == (unsigned int)-1) &&
6005 pciDeviceBitMappings
->setObject(deviceName
))
6007 index
= pciDeviceBitMappings
->getCount() - 1;
6008 _LOG("PMTrace PCI array: set object %s => %d\n",
6009 deviceName
->getCStringNoCopy(), index
);
6012 deviceName
->release();
6013 if (!addedToRegistry
&& (index
>= 0))
6014 addedToRegistry
= owner
->setProperty("PCITopLevel", this);
6017 IOLockUnlock(pciMappingLock
);
6021 bool PMTraceWorker::serialize(OSSerialize
*s
) const
6024 if (pciDeviceBitMappings
)
6026 IOLockLock(pciMappingLock
);
6027 ok
= pciDeviceBitMappings
->serialize(s
);
6028 IOLockUnlock(pciMappingLock
);
6033 void PMTraceWorker::tracePoint(uint8_t phase
)
6035 // clear trace detail when phase begins
6036 if (tracePhase
!= phase
)
6041 DLOG("trace point 0x%02x\n", tracePhase
);
6045 void PMTraceWorker::tracePoint(uint8_t phase
, uint8_t data8
)
6047 // clear trace detail when phase begins
6048 if (tracePhase
!= phase
)
6054 DLOG("trace point 0x%02x 0x%02x\n", tracePhase
, traceData8
);
6058 void PMTraceWorker::traceDetail(uint32_t detail
)
6060 if (kIOPMTracePointSleepPriorityClients
!= tracePhase
)
6063 traceData32
= detail
;
6064 DLOG("trace point 0x%02x detail 0x%08x\n", tracePhase
, traceData32
);
6069 void PMTraceWorker::traceLoginWindowPhase(uint8_t phase
)
6071 loginWindowPhase
= phase
;
6073 DLOG("loginwindow tracepoint 0x%02x\n", loginWindowPhase
);
6077 void PMTraceWorker::tracePCIPowerChange(
6078 change_t type
, IOService
*service
, uint32_t changeFlags
, uint32_t bitNum
)
6081 uint32_t expectedFlag
;
6083 // Ignore PCI changes outside of system sleep/wake.
6084 if ((kIOPMTracePointSleepPowerPlaneDrivers
!= tracePhase
) &&
6085 (kIOPMTracePointWakePowerPlaneDrivers
!= tracePhase
))
6088 // Only record the WillChange transition when going to sleep,
6089 // and the DidChange on the way up.
6090 changeFlags
&= (kIOPMDomainWillChange
| kIOPMDomainDidChange
);
6091 expectedFlag
= (kIOPMTracePointSleepPowerPlaneDrivers
== tracePhase
) ?
6092 kIOPMDomainWillChange
: kIOPMDomainDidChange
;
6093 if (changeFlags
!= expectedFlag
)
6096 // Mark this device off in our bitfield
6097 if (bitNum
< kPMMaxRTCBitfieldSize
)
6099 bitMask
= (1 << bitNum
);
6101 if (kPowerChangeStart
== type
)
6103 traceData32
|= bitMask
;
6104 _LOG("PMTrace: Device %s started - bit %2d mask 0x%08x => 0x%08x\n",
6105 service
->getName(), bitNum
, bitMask
, traceData32
);
6109 traceData32
&= ~bitMask
;
6110 _LOG("PMTrace: Device %s finished - bit %2d mask 0x%08x => 0x%08x\n",
6111 service
->getName(), bitNum
, bitMask
, traceData32
);
6119 // MARK: PMHaltWorker
6121 //******************************************************************************
6122 // PMHaltWorker Class
6124 //******************************************************************************
6126 static unsigned int gPMHaltBusyCount
;
6127 static unsigned int gPMHaltIdleCount
;
6128 static int gPMHaltDepth
;
6129 static unsigned long gPMHaltEvent
;
6130 static IOLock
* gPMHaltLock
= 0;
6131 static OSArray
* gPMHaltArray
= 0;
6132 static const OSSymbol
* gPMHaltClientAcknowledgeKey
= 0;
6134 PMHaltWorker
* PMHaltWorker::worker( void )
6140 me
= OSTypeAlloc( PMHaltWorker
);
6141 if (!me
|| !me
->init())
6144 me
->lock
= IOLockAlloc();
6148 DLOG("PMHaltWorker %p\n", me
);
6149 me
->retain(); // thread holds extra retain
6150 if (KERN_SUCCESS
!= kernel_thread_start(&PMHaltWorker::main
, (void *) me
, &thread
))
6155 thread_deallocate(thread
);
6160 if (me
) me
->release();
6164 void PMHaltWorker::free( void )
6166 DLOG("PMHaltWorker free %p\n", this);
6172 return OSObject::free();
6175 void PMHaltWorker::main( void * arg
, wait_result_t waitResult
)
6177 PMHaltWorker
* me
= (PMHaltWorker
*) arg
;
6179 IOLockLock( gPMHaltLock
);
6181 me
->depth
= gPMHaltDepth
;
6182 IOLockUnlock( gPMHaltLock
);
6184 while (me
->depth
>= 0)
6186 PMHaltWorker::work( me
);
6188 IOLockLock( gPMHaltLock
);
6189 if (++gPMHaltIdleCount
>= gPMHaltBusyCount
)
6191 // This is the last thread to finish work on this level,
6192 // inform everyone to start working on next lower level.
6194 me
->depth
= gPMHaltDepth
;
6195 gPMHaltIdleCount
= 0;
6196 thread_wakeup((event_t
) &gPMHaltIdleCount
);
6200 // One or more threads are still working on this level,
6201 // this thread must wait.
6202 me
->depth
= gPMHaltDepth
- 1;
6204 IOLockSleep(gPMHaltLock
, &gPMHaltIdleCount
, THREAD_UNINT
);
6205 } while (me
->depth
!= gPMHaltDepth
);
6207 IOLockUnlock( gPMHaltLock
);
6210 // No more work to do, terminate thread
6211 DLOG("All done for worker: %p (visits = %u)\n", me
, me
->visits
);
6212 thread_wakeup( &gPMHaltDepth
);
6216 void PMHaltWorker::work( PMHaltWorker
* me
)
6218 IOService
* service
;
6220 AbsoluteTime startTime
;
6229 // Claim an unit of work from the shared pool
6230 IOLockLock( gPMHaltLock
);
6231 inner
= (OSSet
*)gPMHaltArray
->getObject(me
->depth
);
6234 service
= (IOService
*)inner
->getAnyObject();
6238 inner
->removeObject(service
);
6241 IOLockUnlock( gPMHaltLock
);
6243 break; // no more work at this depth
6245 clock_get_uptime(&startTime
);
6247 if (!service
->isInactive() &&
6248 service
->setProperty(gPMHaltClientAcknowledgeKey
, me
))
6250 IOLockLock(me
->lock
);
6251 me
->startTime
= startTime
;
6252 me
->service
= service
;
6253 me
->timeout
= false;
6254 IOLockUnlock(me
->lock
);
6256 service
->systemWillShutdown( gPMHaltEvent
);
6258 // Wait for driver acknowledgement
6259 IOLockLock(me
->lock
);
6260 while (service
->getProperty(gPMHaltClientAcknowledgeKey
))
6262 IOLockSleep(me
->lock
, me
, THREAD_UNINT
);
6265 timeout
= me
->timeout
;
6266 IOLockUnlock(me
->lock
);
6269 deltaTime
= computeDeltaTimeMS(&startTime
);
6270 if ((deltaTime
> kPMHaltTimeoutMS
) || timeout
||
6271 (gIOKitDebug
& kIOLogPMRootDomain
))
6273 LOG("%s driver %s (%p) took %u ms\n",
6274 (gPMHaltEvent
== kIOMessageSystemWillPowerOff
) ?
6275 "PowerOff" : "Restart",
6276 service
->getName(), service
,
6277 (uint32_t) deltaTime
);
6285 void PMHaltWorker::checkTimeout( PMHaltWorker
* me
, AbsoluteTime
* now
)
6288 AbsoluteTime startTime
;
6289 AbsoluteTime endTime
;
6293 IOLockLock(me
->lock
);
6294 if (me
->service
&& !me
->timeout
)
6296 startTime
= me
->startTime
;
6298 if (CMP_ABSOLUTETIME(&endTime
, &startTime
) > 0)
6300 SUB_ABSOLUTETIME(&endTime
, &startTime
);
6301 absolutetime_to_nanoseconds(endTime
, &nano
);
6303 if (nano
> 3000000000ULL)
6306 MSG("%s still waiting on %s\n",
6307 (gPMHaltEvent
== kIOMessageSystemWillPowerOff
) ?
6308 "PowerOff" : "Restart",
6309 me
->service
->getName());
6312 IOLockUnlock(me
->lock
);
6316 //******************************************************************************
6317 // acknowledgeSystemWillShutdown
6319 // Acknowledgement from drivers that they have prepared for shutdown/restart.
6320 //******************************************************************************
6322 void IOPMrootDomain::acknowledgeSystemWillShutdown( IOService
* from
)
6324 PMHaltWorker
* worker
;
6330 //DLOG("%s acknowledged\n", from->getName());
6331 prop
= from
->copyProperty( gPMHaltClientAcknowledgeKey
);
6334 worker
= (PMHaltWorker
*) prop
;
6335 IOLockLock(worker
->lock
);
6336 from
->removeProperty( gPMHaltClientAcknowledgeKey
);
6337 thread_wakeup((event_t
) worker
);
6338 IOLockUnlock(worker
->lock
);
6343 DLOG("%s acknowledged without worker property\n",
6349 //******************************************************************************
6350 // notifySystemShutdown
6352 // Notify all objects in PM tree that system will shutdown or restart
6353 //******************************************************************************
6356 notifySystemShutdown( IOService
* root
, unsigned long event
)
6358 #define PLACEHOLDER ((OSSet *)gPMHaltArray)
6359 IORegistryIterator
* iter
;
6360 IORegistryEntry
* entry
;
6363 PMHaltWorker
* workers
[kPMHaltMaxWorkers
];
6364 AbsoluteTime deadline
;
6365 unsigned int totalNodes
= 0;
6367 unsigned int rootDepth
;
6368 unsigned int numWorkers
;
6374 DLOG("%s event = %lx\n", __FUNCTION__
, event
);
6376 baseFunc
= OSMemberFunctionCast(void *, root
, &IOService::systemWillShutdown
);
6378 // Iterate the entire PM tree starting from root
6380 rootDepth
= root
->getDepth( gIOPowerPlane
);
6381 if (!rootDepth
) goto done
;
6383 // debug - for repeated test runs
6384 while (PMHaltWorker::metaClass
->getInstanceCount())
6389 gPMHaltArray
= OSArray::withCapacity(40);
6390 if (!gPMHaltArray
) goto done
;
6393 gPMHaltArray
->flushCollection();
6397 gPMHaltLock
= IOLockAlloc();
6398 if (!gPMHaltLock
) goto done
;
6401 if (!gPMHaltClientAcknowledgeKey
)
6403 gPMHaltClientAcknowledgeKey
=
6404 OSSymbol::withCStringNoCopy("PMShutdown");
6405 if (!gPMHaltClientAcknowledgeKey
) goto done
;
6408 gPMHaltEvent
= event
;
6410 // Depth-first walk of PM plane
6412 iter
= IORegistryIterator::iterateOver(
6413 root
, gIOPowerPlane
, kIORegistryIterateRecursively
);
6417 while ((entry
= iter
->getNextObject()))
6419 node
= OSDynamicCast(IOService
, entry
);
6424 OSMemberFunctionCast(void *, node
, &IOService::systemWillShutdown
))
6427 depth
= node
->getDepth( gIOPowerPlane
);
6428 if (depth
<= rootDepth
)
6433 // adjust to zero based depth
6434 depth
-= (rootDepth
+ 1);
6436 // gPMHaltArray is an array of containers, each container
6437 // refers to nodes with the same depth.
6439 count
= gPMHaltArray
->getCount();
6440 while (depth
>= count
)
6442 // expand array and insert placeholders
6443 gPMHaltArray
->setObject(PLACEHOLDER
);
6446 count
= gPMHaltArray
->getCount();
6449 inner
= (OSSet
*)gPMHaltArray
->getObject(depth
);
6450 if (inner
== PLACEHOLDER
)
6452 inner
= OSSet::withCapacity(40);
6455 gPMHaltArray
->replaceObject(depth
, inner
);
6460 // PM nodes that appear more than once in the tree will have
6461 // the same depth, OSSet will refuse to add the node twice.
6463 ok
= inner
->setObject(node
);
6466 DLOG("Skipped PM node %s\n", node
->getName());
6472 for (int i
= 0; (inner
= (OSSet
*)gPMHaltArray
->getObject(i
)); i
++)
6475 if (inner
!= PLACEHOLDER
)
6476 count
= inner
->getCount();
6477 DLOG("Nodes at depth %u = %u\n", i
, count
);
6480 // strip placeholders (not all depths are populated)
6482 for (int i
= 0; (inner
= (OSSet
*)gPMHaltArray
->getObject(i
)); )
6484 if (inner
== PLACEHOLDER
)
6486 gPMHaltArray
->removeObject(i
);
6489 count
= inner
->getCount();
6490 if (count
> numWorkers
)
6492 totalNodes
+= count
;
6496 if (gPMHaltArray
->getCount() == 0 || !numWorkers
)
6499 gPMHaltBusyCount
= 0;
6500 gPMHaltIdleCount
= 0;
6501 gPMHaltDepth
= gPMHaltArray
->getCount() - 1;
6503 // Create multiple workers (and threads)
6505 if (numWorkers
> kPMHaltMaxWorkers
)
6506 numWorkers
= kPMHaltMaxWorkers
;
6508 DLOG("PM nodes = %u, maxDepth = %u, workers = %u\n",
6509 totalNodes
, gPMHaltArray
->getCount(), numWorkers
);
6511 for (unsigned int i
= 0; i
< numWorkers
; i
++)
6512 workers
[i
] = PMHaltWorker::worker();
6514 // Wait for workers to exhaust all available work
6516 IOLockLock(gPMHaltLock
);
6517 while (gPMHaltDepth
>= 0)
6519 clock_interval_to_deadline(1000, kMillisecondScale
, &deadline
);
6521 waitResult
= IOLockSleepDeadline(
6522 gPMHaltLock
, &gPMHaltDepth
, deadline
, THREAD_UNINT
);
6523 if (THREAD_TIMED_OUT
== waitResult
)
6526 clock_get_uptime(&now
);
6528 IOLockUnlock(gPMHaltLock
);
6529 for (unsigned int i
= 0 ; i
< numWorkers
; i
++)
6532 PMHaltWorker::checkTimeout(workers
[i
], &now
);
6534 IOLockLock(gPMHaltLock
);
6537 IOLockUnlock(gPMHaltLock
);
6539 // Release all workers
6541 for (unsigned int i
= 0; i
< numWorkers
; i
++)
6544 workers
[i
]->release();
6545 // worker also retained by it's own thread
6549 DLOG("%s done\n", __FUNCTION__
);
6553 //*********************************************************************************
6554 // Sleep/Wake logging
6556 //*********************************************************************************
6558 IOMemoryDescriptor
*IOPMrootDomain::getPMTraceMemoryDescriptor(void)
6561 return timeline
->getPMTraceMemoryDescriptor();
6566 // Forwards external reports of detailed events to IOPMTimeline
6567 IOReturn
IOPMrootDomain::recordPMEvent(PMEventDetails
*details
)
6569 if (timeline
&& details
) {
6573 // Record a detailed driver power change event, or...
6574 if(details
->eventClassifier
== kIOPMEventClassDriverEvent
) {
6575 rc
= timeline
->recordDetailedPowerEvent( details
);
6578 // Record a system power management event
6579 else if(details
->eventClassifier
== kIOPMEventClassSystemEvent
) {
6580 rc
= timeline
->recordSystemPowerEvent( details
);
6583 return kIOReturnBadArgument
;
6586 // If we get to record this message, then we've reached the
6587 // end of another successful Sleep --> Wake cycle
6588 // At this point, we pat ourselves in the back and allow
6589 // our Sleep --> Wake UUID to be published
6590 if(details
->eventType
== kIOPMEventTypeWakeDone
) {
6591 timeline
->setSleepCycleInProgressFlag(false);
6595 // Check if its time to clear the timeline buffer
6596 if(getProperty(kIOPMSleepWakeUUIDKey)
6597 && timeline->isSleepCycleInProgress() == false
6598 && timeline->getNumEventsLoggedThisPeriod() > 500) {
6600 // Clear the old UUID
6601 if(pmPowerStateQueue) {
6602 pmPowerStateQueue->submitPowerEvent(kPowerEventPublishSleepWakeUUID, (void *)false );
6609 return kIOReturnNotReady
;
6612 IOReturn
IOPMrootDomain::recordAndReleasePMEvent(PMEventDetails
*details
)
6614 IOReturn ret
= kIOReturnBadArgument
;
6618 ret
= recordPMEvent(details
);
6625 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
6627 IOPMDriverAssertionID
IOPMrootDomain::createPMAssertion(
6628 IOPMDriverAssertionType whichAssertionBits
,
6629 IOPMDriverAssertionLevel assertionLevel
,
6630 IOService
*ownerService
,
6631 const char *ownerDescription
)
6634 IOPMDriverAssertionID newAssertion
;
6639 ret
= pmAssertions
->createAssertion(whichAssertionBits
, assertionLevel
, ownerService
, ownerDescription
, &newAssertion
);
6641 if (kIOReturnSuccess
== ret
)
6642 return newAssertion
;
6647 IOReturn
IOPMrootDomain::releasePMAssertion(IOPMDriverAssertionID releaseAssertion
)
6650 return kIOReturnInternalError
;
6652 return pmAssertions
->releaseAssertion(releaseAssertion
);
6655 IOReturn
IOPMrootDomain::setPMAssertionLevel(
6656 IOPMDriverAssertionID assertionID
,
6657 IOPMDriverAssertionLevel assertionLevel
)
6659 return pmAssertions
->setAssertionLevel(assertionID
, assertionLevel
);
6662 IOPMDriverAssertionLevel
IOPMrootDomain::getPMAssertionLevel(IOPMDriverAssertionType whichAssertion
)
6664 IOPMDriverAssertionType sysLevels
;
6666 if (!pmAssertions
|| whichAssertion
== 0)
6667 return kIOPMDriverAssertionLevelOff
;
6669 sysLevels
= pmAssertions
->getActivatedAssertions();
6671 // Check that every bit set in argument 'whichAssertion' is asserted
6672 // in the aggregate bits.
6673 if ((sysLevels
& whichAssertion
) == whichAssertion
)
6674 return kIOPMDriverAssertionLevelOn
;
6676 return kIOPMDriverAssertionLevelOff
;
6679 IOReturn
IOPMrootDomain::setPMAssertionUserLevels(IOPMDriverAssertionType inLevels
)
6682 return kIOReturnNotFound
;
6684 return pmAssertions
->setUserAssertionLevels(inLevels
);
6687 bool IOPMrootDomain::serializeProperties( OSSerialize
* s
) const
6691 pmAssertions
->publishProperties();
6693 return( IOService::serializeProperties(s
) );
6696 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
6699 // MARK: PMSettingHandle
6701 OSDefineMetaClassAndStructors( PMSettingHandle
, OSObject
)
6703 void PMSettingHandle::free( void )
6707 pmso
->clientHandleFreed();
6716 // MARK: PMSettingObject
6719 #define super OSObject
6720 OSDefineMetaClassAndFinalStructors( PMSettingObject
, OSObject
)
6723 * Static constructor/initializer for PMSettingObject
6725 PMSettingObject
*PMSettingObject::pmSettingObject(
6726 IOPMrootDomain
*parent_arg
,
6727 IOPMSettingControllerCallback handler_arg
,
6728 OSObject
*target_arg
,
6729 uintptr_t refcon_arg
,
6730 uint32_t supportedPowerSources
,
6731 const OSSymbol
* settings
[],
6732 OSObject
**handle_obj
)
6734 uint32_t settingCount
= 0;
6735 PMSettingObject
*pmso
= 0;
6736 PMSettingHandle
*pmsh
= 0;
6738 if ( !parent_arg
|| !handler_arg
|| !settings
|| !handle_obj
)
6741 // count OSSymbol entries in NULL terminated settings array
6742 while (settings
[settingCount
]) {
6745 if (0 == settingCount
)
6748 pmso
= new PMSettingObject
;
6749 if (!pmso
|| !pmso
->init())
6752 pmsh
= new PMSettingHandle
;
6753 if (!pmsh
|| !pmsh
->init())
6756 queue_init(&pmso
->calloutQueue
);
6757 pmso
->parent
= parent_arg
;
6758 pmso
->func
= handler_arg
;
6759 pmso
->target
= target_arg
;
6760 pmso
->refcon
= refcon_arg
;
6761 pmso
->settingCount
= settingCount
;
6763 pmso
->retain(); // handle holds a retain on pmso
6767 pmso
->publishedFeatureID
= (uint32_t *)IOMalloc(sizeof(uint32_t)*settingCount
);
6768 if (pmso
->publishedFeatureID
) {
6769 for (unsigned int i
=0; i
<settingCount
; i
++) {
6770 // Since there is now at least one listener to this setting, publish
6771 // PM root domain support for it.
6772 parent_arg
->publishFeature( settings
[i
]->getCStringNoCopy(),
6773 supportedPowerSources
, &pmso
->publishedFeatureID
[i
] );
6781 if (pmso
) pmso
->release();
6782 if (pmsh
) pmsh
->release();
6786 void PMSettingObject::free( void )
6788 if (publishedFeatureID
) {
6789 for (uint32_t i
=0; i
<settingCount
; i
++) {
6790 if (publishedFeatureID
[i
]) {
6791 parent
->removePublishedFeature( publishedFeatureID
[i
] );
6795 IOFree(publishedFeatureID
, sizeof(uint32_t) * settingCount
);
6801 void PMSettingObject::dispatchPMSetting( const OSSymbol
* type
, OSObject
* object
)
6803 (*func
)(target
, type
, object
, refcon
);
6806 void PMSettingObject::clientHandleFreed( void )
6808 parent
->deregisterPMSettingObject(this);
6812 // MARK: IOPMTimeline
6815 #define super OSObject
6817 //*********************************************************************************
6818 //*********************************************************************************
6819 //*********************************************************************************
6821 IOPMTimeline
*IOPMTimeline::timeline(IOPMrootDomain
*root_domain
)
6823 IOPMTimeline
*myself
;
6828 myself
= new IOPMTimeline
;
6831 myself
->owner
= root_domain
;
6838 bool IOPMTimeline::init(void)
6840 if (!super::init()) {
6844 logLock
= IOLockAlloc();
6846 // Fresh timeline, no events logged yet
6847 this->numEventsLoggedThisPeriod
= 0;
6848 this->sleepCycleInProgress
= false;
6850 //this->setEventsRecordingLevel(1); // TODO
6851 this->setEventsTrackedCount(kIOPMDefaultSystemEventsTracked
);
6856 void IOPMTimeline::free(void)
6858 if (pmTraceMemoryDescriptor
) {
6859 pmTraceMemoryDescriptor
->release();
6860 pmTraceMemoryDescriptor
= NULL
;
6863 IOLockFree(logLock
);
6868 IOMemoryDescriptor
*IOPMTimeline::getPMTraceMemoryDescriptor()
6870 return pmTraceMemoryDescriptor
;
6873 //*********************************************************************************
6874 //*********************************************************************************
6875 //*********************************************************************************
6877 bool IOPMTimeline::setProperties(OSDictionary
*d
)
6880 OSBoolean
*b
= NULL
;
6881 bool changed
= false;
6883 /* Changes size of detailed events buffer */
6884 n
= (OSNumber
*)d
->getObject(kIOPMTimelineSystemNumberTrackedKey
);
6885 if (OSDynamicCast(OSNumber
, n
))
6888 this->setEventsTrackedCount(n
->unsigned32BitValue());
6892 /* enables or disables system events */
6893 b
= (OSBoolean
*)d
->getObject(kIOPMTimelineEnabledKey
);
6897 this->setEventsRecordingLevel((int)(kOSBooleanTrue
== b
));
6903 //*********************************************************************************
6904 //*********************************************************************************
6905 //*********************************************************************************
6907 OSDictionary
*IOPMTimeline::copyInfoDictionary(void)
6909 OSDictionary
*out
= OSDictionary::withCapacity(3);
6915 n
= OSNumber::withNumber(hdr
->sizeEntries
, 32);
6916 out
->setObject(kIOPMTimelineSystemNumberTrackedKey
, n
);
6919 n
= OSNumber::withNumber(hdr
->sizeBytes
, 32);
6920 out
->setObject(kIOPMTimelineSystemBufferSizeKey
, n
);
6924 out
->setObject(kIOPMTimelineEnabledKey
, eventsRecordingLevel
? kOSBooleanTrue
: kOSBooleanFalse
);
6929 //*********************************************************************************
6930 //*********************************************************************************
6931 //*********************************************************************************
6933 /* IOPMTimeline::recordSystemPowerEvent()
6935 * Expected "type" arguments are listed in IOPMPrivate.h under enum "SystemEventTypes"
6936 * Type arguments include "system events", and "Intermediate events"
6938 * - System Events have paired "start" and "stop" events.
6939 * - A start event shall be followed by a stop event.
6940 * - Any number of Intermediate Events may fall between the
6941 * start and stop events.
6942 * - Intermediate events are meaningless outside the bounds of a system event's
6943 * start & stoup routines.
6944 * - It's invalid to record a Start event without a following Stop event; e.g. two
6945 * Start events without an intervenining Stop event is invalid.
6948 * - The first recorded system event shall be preceded by an entry with type == 0
6949 * - IOPMTimeline may choose not to record intermediate events while there's not
6950 * a system event in process.
6952 IOReturn
IOPMTimeline::recordSystemPowerEvent( PMEventDetails
*details
)
6954 static bool wakeDonePending
= true;
6955 IOPMSystemEventRecord
*record_to
= NULL
;
6956 OSString
*swUUIDKey
= NULL
;
6957 uint32_t useIndex
= 0;
6960 return kIOReturnBadArgument
;
6963 return kIOReturnNotReady
;
6965 if (details
->eventType
== kIOPMEventTypeWakeDone
)
6967 if(!wakeDonePending
)
6968 return kIOReturnBadArgument
;
6971 IOLockLock(logLock
);
6973 if (details
->eventType
== kIOPMEventTypeWake
) {
6974 wakeDonePending
= true;
6975 } else if (details
->eventType
== kIOPMEventTypeWakeDone
) {
6976 wakeDonePending
= false;
6979 systemState
= details
->eventType
;
6981 useIndex
= _atomicIndexIncrement(&hdr
->index
, hdr
->sizeEntries
);
6983 // The entry immediately after the latest entry (and thus
6984 // immediately before the first entry) shall have a type 0.
6985 if (useIndex
+ 1 >= hdr
->sizeEntries
) {
6986 traceBuffer
[useIndex
+ 1].eventType
= 0;
6988 traceBuffer
[0].eventType
= 0;
6991 record_to
= &traceBuffer
[useIndex
];
6992 bzero(record_to
, sizeof(IOPMSystemEventRecord
));
6995 record_to
->eventType
= details
->eventType
;
6996 record_to
->eventReason
= details
->reason
;
6997 record_to
->eventResult
= details
->result
;
6998 pmEventTimeStamp(&record_to
->timestamp
);
7000 // If caller doesn't provide a UUID, we'll use the UUID that's posted
7001 // on IOPMrootDomain under key kIOPMSleepWakeUUIDKey
7002 if (!details
->uuid
) {
7003 swUUIDKey
= OSDynamicCast(OSString
, owner
->copyProperty(kIOPMSleepWakeUUIDKey
));
7006 details
->uuid
= swUUIDKey
->getCStringNoCopy();
7010 strncpy(record_to
->uuid
, details
->uuid
, kMaxPMStringLength
);
7013 swUUIDKey
->release();
7015 numEventsLoggedThisPeriod
++;
7018 IOLockUnlock(logLock
);
7020 return kIOReturnSuccess
;
7024 //*********************************************************************************
7025 //*********************************************************************************
7026 //*********************************************************************************
7028 IOReturn
IOPMTimeline::recordDetailedPowerEvent( PMEventDetails
*details
)
7030 IOPMSystemEventRecord
*record_to
= NULL
;
7033 if (!details
->eventType
|| !details
->ownerName
)
7034 return kIOReturnBadArgument
;
7036 IOLockLock(logLock
);
7038 useIndex
= _atomicIndexIncrement(&hdr
->index
, hdr
->sizeEntries
);
7040 record_to
= (IOPMSystemEventRecord
*)&traceBuffer
[useIndex
];
7041 bzero(record_to
, sizeof(IOPMSystemEventRecord
));
7044 record_to
->eventType
= details
->eventType
;
7045 if (details
->ownerName
&& (strlen(details
->ownerName
) > 1)) {
7046 strlcpy( record_to
->ownerName
,
7048 sizeof(record_to
->ownerName
));
7051 record_to
->ownerDisambiguateID
= details
->ownerUnique
;
7053 if (details
->interestName
&& (strlen(details
->interestName
) > 1)) {
7054 strlcpy(record_to
->interestName
,
7055 details
->interestName
,
7056 sizeof(record_to
->interestName
));
7059 record_to
->oldState
= details
->oldState
;
7060 record_to
->newState
= details
->newState
;
7061 record_to
->eventResult
= details
->result
;
7062 record_to
->elapsedTimeUS
= details
->elapsedTimeUS
;
7063 pmEventTimeStamp(&record_to
->timestamp
);
7065 numEventsLoggedThisPeriod
++;
7068 IOLockUnlock(logLock
);
7069 return kIOReturnSuccess
;
7072 uint32_t IOPMTimeline::getNumEventsLoggedThisPeriod() {
7073 return this->numEventsLoggedThisPeriod
;
7076 void IOPMTimeline::setNumEventsLoggedThisPeriod(uint32_t newCount
) {
7077 this->numEventsLoggedThisPeriod
= newCount
;
7080 bool IOPMTimeline::isSleepCycleInProgress() {
7081 return this->sleepCycleInProgress
;
7084 void IOPMTimeline::setSleepCycleInProgressFlag(bool flag
) {
7085 this->sleepCycleInProgress
= flag
;
7087 //*********************************************************************************
7088 //*********************************************************************************
7089 //*********************************************************************************
7091 void IOPMTimeline::setEventsTrackedCount(uint32_t newTracked
)
7093 size_t make_buf_size
= 0;
7095 make_buf_size
= sizeof(IOPMTraceBufferHeader
) + (newTracked
* sizeof(IOPMSystemEventRecord
));
7097 IOLockLock(logLock
);
7099 if (pmTraceMemoryDescriptor
) {
7100 pmTraceMemoryDescriptor
->release();
7101 pmTraceMemoryDescriptor
= NULL
;
7107 if (0 == newTracked
)
7109 IOLog("IOPMrootDomain -> erased buffer.\n");
7113 pmTraceMemoryDescriptor
= IOBufferMemoryDescriptor::withOptions(
7114 kIOMemoryKernelUserShared
| kIODirectionIn
, make_buf_size
);
7116 if (!pmTraceMemoryDescriptor
)
7118 IOLog("IOPMRootDomain -> IOBufferMemoryDescriptor(%d) returns NULL\n", (int)make_buf_size
);
7122 pmTraceMemoryDescriptor
->prepare(kIODirectionIn
);
7124 // Header occupies the first sizeof(IOPMTraceBufferHeader) bytes
7125 hdr
= (IOPMTraceBufferHeader
*)pmTraceMemoryDescriptor
->getBytesNoCopy();
7127 // Recorded events occupy the remaining bulk of the buffer
7128 traceBuffer
= (IOPMSystemEventRecord
*)((uint8_t *)hdr
+ sizeof(IOPMTraceBufferHeader
));
7130 bzero(hdr
, make_buf_size
);
7132 hdr
->sizeBytes
= make_buf_size
;
7133 hdr
->sizeEntries
= newTracked
;
7135 IOLog("IOPMRootDomain -> IOBufferMemoryDescriptor(%d) returns bufferMB with address 0x%08x\n", (int)make_buf_size
, (unsigned int)(uintptr_t)traceBuffer
);
7138 IOLockUnlock(logLock
);
7141 //*********************************************************************************
7142 //*********************************************************************************
7143 //*********************************************************************************
7145 void IOPMTimeline::setEventsRecordingLevel(uint32_t eventsTrackedBits
)
7154 /* static helper to IOPMTimeline
7156 uint32_t IOPMTimeline::_atomicIndexIncrement(uint32_t *index
, uint32_t limit
)
7166 inc_index
= (was_index
+1)%limit
;
7167 } while (!OSCompareAndSwap(was_index
, inc_index
, index
));
7173 // MARK: PMAssertionsTracker
7175 //*********************************************************************************
7176 //*********************************************************************************
7177 //*********************************************************************************
7178 // class PMAssertionsTracker Implementation
7180 #define kAssertUniqueIDStart 500
7182 PMAssertionsTracker
*PMAssertionsTracker::pmAssertionsTracker( IOPMrootDomain
*rootDomain
)
7184 PMAssertionsTracker
*myself
;
7186 myself
= new PMAssertionsTracker
;
7190 myself
->owner
= rootDomain
;
7191 myself
->issuingUniqueID
= kAssertUniqueIDStart
;
7192 myself
->assertionsArray
= OSArray::withCapacity(5);
7193 myself
->assertionsKernel
= 0;
7194 myself
->assertionsUser
= 0;
7195 myself
->assertionsCombined
= 0;
7196 myself
->assertionsArrayLock
= IOLockAlloc();
7197 myself
->tabulateProducerCount
= myself
->tabulateConsumerCount
= 0;
7199 if (!myself
->assertionsArray
|| !myself
->assertionsArrayLock
)
7207 * - Update assertionsKernel to reflect the state of all
7208 * assertions in the kernel.
7209 * - Update assertionsCombined to reflect both kernel & user space.
7211 void PMAssertionsTracker::tabulate(void)
7215 PMAssertStruct
*_a
= NULL
;
7218 IOPMDriverAssertionType oldKernel
= assertionsKernel
;
7219 IOPMDriverAssertionType oldCombined
= assertionsCombined
;
7223 assertionsKernel
= 0;
7224 assertionsCombined
= 0;
7226 if (!assertionsArray
)
7229 if ((count
= assertionsArray
->getCount()))
7231 for (i
=0; i
<count
; i
++)
7233 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
7236 _a
= (PMAssertStruct
*)_d
->getBytesNoCopy();
7237 if (_a
&& (kIOPMDriverAssertionLevelOn
== _a
->level
))
7238 assertionsKernel
|= _a
->assertionBits
;
7243 tabulateProducerCount
++;
7244 assertionsCombined
= assertionsKernel
| assertionsUser
;
7246 if ((assertionsKernel
!= oldKernel
) ||
7247 (assertionsCombined
!= oldCombined
))
7249 owner
->messageClients(kIOPMMessageDriverAssertionsChanged
);
7251 if (((assertionsCombined
& kIOPMDriverAssertionPreventDisplaySleepBit
) != 0)
7252 && ((oldCombined
& kIOPMDriverAssertionPreventDisplaySleepBit
) == 0))
7254 /* We react to a new PreventDisplaySleep assertion by waking the display
7255 * with an activityTickle
7257 owner
->evaluatePolicy(kStimulusDarkWakeActivityTickle
);
7259 owner
->evaluatePolicy(kStimulusDarkWakeEvaluate
);
7264 void PMAssertionsTracker::publishProperties( void )
7266 OSArray
*assertionsSummary
= NULL
;
7268 if (tabulateConsumerCount
!= tabulateProducerCount
)
7270 IOLockLock(assertionsArrayLock
);
7272 tabulateConsumerCount
= tabulateProducerCount
;
7274 /* Publish the IOPMrootDomain property "DriverPMAssertionsDetailed"
7276 assertionsSummary
= copyAssertionsArray();
7277 if (assertionsSummary
)
7279 owner
->setProperty(kIOPMAssertionsDriverDetailedKey
, assertionsSummary
);
7280 assertionsSummary
->release();
7284 owner
->removeProperty(kIOPMAssertionsDriverDetailedKey
);
7287 /* Publish the IOPMrootDomain property "DriverPMAssertions"
7289 owner
->setProperty(kIOPMAssertionsDriverKey
, assertionsKernel
, 64);
7291 IOLockUnlock(assertionsArrayLock
);
7295 PMAssertionsTracker::PMAssertStruct
*PMAssertionsTracker::detailsForID(IOPMDriverAssertionID _id
, int *index
)
7297 PMAssertStruct
*_a
= NULL
;
7304 && (count
= assertionsArray
->getCount()))
7306 for (i
=0; i
<count
; i
++)
7308 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
7311 _a
= (PMAssertStruct
*)_d
->getBytesNoCopy();
7312 if (_a
&& (_id
== _a
->id
)) {
7329 /* PMAssertionsTracker::handleCreateAssertion
7330 * Perform assertion work on the PM workloop. Do not call directly.
7332 IOReturn
PMAssertionsTracker::handleCreateAssertion(OSData
*newAssertion
)
7338 IOLockLock(assertionsArrayLock
);
7339 assertionsArray
->setObject(newAssertion
);
7340 IOLockUnlock(assertionsArrayLock
);
7341 newAssertion
->release();
7345 return kIOReturnSuccess
;
7348 /* PMAssertionsTracker::createAssertion
7349 * createAssertion allocates memory for a new PM assertion, and affects system behavior, if
7352 IOReturn
PMAssertionsTracker::createAssertion(
7353 IOPMDriverAssertionType which
,
7354 IOPMDriverAssertionLevel level
,
7355 IOService
*serviceID
,
7356 const char *whoItIs
,
7357 IOPMDriverAssertionID
*outID
)
7359 OSData
*dataStore
= NULL
;
7360 PMAssertStruct track
;
7362 // Warning: trillions and trillions of created assertions may overflow the unique ID.
7363 track
.id
= OSIncrementAtomic64((SInt64
*) &issuingUniqueID
);
7364 track
.level
= level
;
7365 track
.assertionBits
= which
;
7366 track
.ownerString
= whoItIs
? OSSymbol::withCString(whoItIs
) : 0;
7367 track
.ownerService
= serviceID
;
7368 track
.modifiedTime
= 0;
7369 pmEventTimeStamp(&track
.createdTime
);
7371 dataStore
= OSData::withBytes(&track
, sizeof(PMAssertStruct
));
7374 if (track
.ownerString
)
7375 track
.ownerString
->release();
7376 return kIOReturnNoMemory
;
7381 if (owner
&& owner
->pmPowerStateQueue
) {
7382 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionCreate
, (void *)dataStore
);
7385 return kIOReturnSuccess
;
7388 /* PMAssertionsTracker::handleReleaseAssertion
7389 * Runs in PM workloop. Do not call directly.
7391 IOReturn
PMAssertionsTracker::handleReleaseAssertion(
7392 IOPMDriverAssertionID _id
)
7397 PMAssertStruct
*assertStruct
= detailsForID(_id
, &index
);
7400 return kIOReturnNotFound
;
7402 IOLockLock(assertionsArrayLock
);
7403 if (assertStruct
->ownerString
)
7404 assertStruct
->ownerString
->release();
7406 assertionsArray
->removeObject(index
);
7407 IOLockUnlock(assertionsArrayLock
);
7410 return kIOReturnSuccess
;
7413 /* PMAssertionsTracker::releaseAssertion
7414 * Releases an assertion and affects system behavior if appropiate.
7415 * Actual work happens on PM workloop.
7417 IOReturn
PMAssertionsTracker::releaseAssertion(
7418 IOPMDriverAssertionID _id
)
7420 if (owner
&& owner
->pmPowerStateQueue
) {
7421 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionRelease
, 0, _id
);
7423 return kIOReturnSuccess
;
7426 /* PMAssertionsTracker::handleSetAssertionLevel
7427 * Runs in PM workloop. Do not call directly.
7429 IOReturn
PMAssertionsTracker::handleSetAssertionLevel(
7430 IOPMDriverAssertionID _id
,
7431 IOPMDriverAssertionLevel _level
)
7433 PMAssertStruct
*assertStruct
= detailsForID(_id
, NULL
);
7437 if (!assertStruct
) {
7438 return kIOReturnNotFound
;
7441 IOLockLock(assertionsArrayLock
);
7442 pmEventTimeStamp(&assertStruct
->modifiedTime
);
7443 assertStruct
->level
= _level
;
7444 IOLockUnlock(assertionsArrayLock
);
7447 return kIOReturnSuccess
;
7450 /* PMAssertionsTracker::setAssertionLevel
7452 IOReturn
PMAssertionsTracker::setAssertionLevel(
7453 IOPMDriverAssertionID _id
,
7454 IOPMDriverAssertionLevel _level
)
7456 if (owner
&& owner
->pmPowerStateQueue
) {
7457 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionSetLevel
,
7458 (void *)_level
, _id
);
7461 return kIOReturnSuccess
;
7464 IOReturn
PMAssertionsTracker::handleSetUserAssertionLevels(void * arg0
)
7466 IOPMDriverAssertionType new_user_levels
= *(IOPMDriverAssertionType
*) arg0
;
7470 if (new_user_levels
!= assertionsUser
)
7472 assertionsUser
= new_user_levels
;
7473 DLOG("assertionsUser 0x%llx\n", assertionsUser
);
7477 return kIOReturnSuccess
;
7480 IOReturn
PMAssertionsTracker::setUserAssertionLevels(
7481 IOPMDriverAssertionType new_user_levels
)
7483 if (gIOPMWorkLoop
) {
7484 gIOPMWorkLoop
->runAction(
7485 OSMemberFunctionCast(
7488 &PMAssertionsTracker::handleSetUserAssertionLevels
),
7490 (void *) &new_user_levels
, 0, 0, 0);
7493 return kIOReturnSuccess
;
7497 OSArray
*PMAssertionsTracker::copyAssertionsArray(void)
7501 OSArray
*outArray
= NULL
;
7503 if (!assertionsArray
||
7504 (0 == (count
= assertionsArray
->getCount())) ||
7505 (NULL
== (outArray
= OSArray::withCapacity(count
))))
7510 for (i
=0; i
<count
; i
++)
7512 PMAssertStruct
*_a
= NULL
;
7514 OSDictionary
*details
= NULL
;
7516 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
7517 if (_d
&& (_a
= (PMAssertStruct
*)_d
->getBytesNoCopy()))
7519 OSNumber
*_n
= NULL
;
7521 details
= OSDictionary::withCapacity(7);
7525 outArray
->setObject(details
);
7528 _n
= OSNumber::withNumber(_a
->id
, 64);
7530 details
->setObject(kIOPMDriverAssertionIDKey
, _n
);
7533 _n
= OSNumber::withNumber(_a
->createdTime
, 64);
7535 details
->setObject(kIOPMDriverAssertionCreatedTimeKey
, _n
);
7538 _n
= OSNumber::withNumber(_a
->modifiedTime
, 64);
7540 details
->setObject(kIOPMDriverAssertionModifiedTimeKey
, _n
);
7543 _n
= OSNumber::withNumber((uintptr_t)_a
->ownerService
, 64);
7545 details
->setObject(kIOPMDriverAssertionOwnerServiceKey
, _n
);
7548 _n
= OSNumber::withNumber(_a
->level
, 64);
7550 details
->setObject(kIOPMDriverAssertionLevelKey
, _n
);
7553 _n
= OSNumber::withNumber(_a
->assertionBits
, 64);
7555 details
->setObject(kIOPMDriverAssertionAssertedKey
, _n
);
7559 if (_a
->ownerString
) {
7560 details
->setObject(kIOPMDriverAssertionOwnerStringKey
, _a
->ownerString
);
7569 IOPMDriverAssertionType
PMAssertionsTracker::getActivatedAssertions(void)
7571 return assertionsCombined
;
7574 IOPMDriverAssertionLevel
PMAssertionsTracker::getAssertionLevel(
7575 IOPMDriverAssertionType type
)
7577 if (type
&& ((type
& assertionsKernel
) == assertionsKernel
))
7579 return kIOPMDriverAssertionLevelOn
;
7581 return kIOPMDriverAssertionLevelOff
;
7585 //*********************************************************************************
7586 //*********************************************************************************
7587 //*********************************************************************************
7590 static void pmEventTimeStamp(uint64_t *recordTS
)
7598 // We assume tsec fits into 32 bits; 32 bits holds enough
7599 // seconds for 136 years since the epoch in 1970.
7600 clock_get_calendar_microtime(&tsec
, &tusec
);
7603 // Pack the sec & microsec calendar time into a uint64_t, for fun.
7605 *recordTS
|= (uint32_t)tusec
;
7606 *recordTS
|= ((uint64_t)tsec
<< 32);
7612 // MARK: IORootParent
7614 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
7616 OSDefineMetaClassAndFinalStructors(IORootParent
, IOService
)
7618 // The reason that root domain needs a root parent is to facilitate demand
7619 // sleep, since a power change from the root parent cannot be vetoed.
7621 // The above statement is no longer true since root domain now performs
7622 // demand sleep using overrides. But root parent remains to avoid changing
7623 // the power tree stacking. Root parent is parked at the max power state.
7626 static IOPMPowerState patriarchPowerStates
[2] =
7628 {1,0,ON_POWER
,0,0,0,0,0,0,0,0,0},
7629 {1,0,ON_POWER
,0,0,0,0,0,0,0,0,0},
7632 void IORootParent::initialize( void )
7636 bool IORootParent::start( IOService
* nub
)
7638 IOService::start(nub
);
7639 attachToParent( getRegistryRoot(), gIOPowerPlane
);
7641 registerPowerDriver(this, patriarchPowerStates
, 2);
7646 void IORootParent::shutDownSystem( void )
7650 void IORootParent::restartSystem( void )
7654 void IORootParent::sleepSystem( void )
7658 void IORootParent::dozeSystem( void )
7662 void IORootParent::sleepToDoze( void )
7666 void IORootParent::wakeSystem( void )
7670 OSObject
* IORootParent::copyProperty( const char * aKey
) const
7672 return (IOService::copyProperty(aKey
));