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