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