]> git.saurik.com Git - apple/xnu.git/blob - iokit/Kernel/IOPMrootDomain.cpp
xnu-1699.22.81.tar.gz
[apple/xnu.git] / iokit / Kernel / IOPMrootDomain.cpp
1 /*
2 * Copyright (c) 1998-2008 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
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.
14 *
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
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28 #include <libkern/c++/OSKext.h>
29 #include <libkern/c++/OSMetaClass.h>
30 #include <libkern/OSAtomic.h>
31 #include <libkern/OSDebug.h>
32 #include <IOKit/IOWorkLoop.h>
33 #include <IOKit/IOCommandGate.h>
34 #include <IOKit/IOPlatformExpert.h>
35 #include <IOKit/IOKitDebug.h>
36 #include <IOKit/IOTimeStamp.h>
37 #include <IOKit/pwr_mgt/IOPMlog.h>
38 #include <IOKit/pwr_mgt/RootDomain.h>
39 #include <IOKit/pwr_mgt/IOPMPrivate.h>
40 #include <IOKit/IODeviceTreeSupport.h>
41 #include <IOKit/IOMessage.h>
42 #include <IOKit/IOReturn.h>
43 #include "RootDomainUserClient.h"
44 #include "IOKit/pwr_mgt/IOPowerConnection.h"
45 #include "IOPMPowerStateQueue.h"
46 #include <IOKit/IOCatalogue.h>
47 #if HIBERNATION
48 #include <IOKit/IOHibernatePrivate.h>
49 #endif
50 #include <sys/syslog.h>
51 #include <sys/sysctl.h>
52 #include <sys/time.h>
53 #include "IOServicePrivate.h" // _IOServiceInterestNotifier
54 #include "IOServicePMPrivate.h"
55
56 __BEGIN_DECLS
57 #include <mach/shared_region.h>
58 __END_DECLS
59
60 #if defined(__i386__) || defined(__x86_64__)
61 __BEGIN_DECLS
62 #include "IOPMrootDomainInternal.h"
63 __END_DECLS
64 #endif
65
66 #define kIOPMrootDomainClass "IOPMrootDomain"
67 #define LOG_PREFIX "PMRD: "
68
69 #define MSG(x...) \
70 do { kprintf(LOG_PREFIX x); IOLog(x); } while (false)
71
72 #define LOG(x...) \
73 do { kprintf(LOG_PREFIX x); } while (false)
74
75 #define DLOG(x...) do { \
76 if (kIOLogPMRootDomain & gIOKitDebug) \
77 kprintf(LOG_PREFIX x); } while (false)
78
79 #define _LOG(x...)
80
81 #define CHECK_THREAD_CONTEXT
82 #ifdef CHECK_THREAD_CONTEXT
83 static IOWorkLoop * gIOPMWorkLoop = 0;
84 #define ASSERT_GATED() \
85 do { \
86 if (gIOPMWorkLoop && gIOPMWorkLoop->inGate() != true) { \
87 panic("RootDomain: not inside PM gate"); \
88 } \
89 } while(false)
90 #else
91 #define ASSERT_GATED()
92 #endif /* CHECK_THREAD_CONTEXT */
93
94 #define CAP_LOSS(c) \
95 (((_pendingCapability & (c)) == 0) && \
96 ((_currentCapability & (c)) != 0))
97
98 #define CAP_GAIN(c) \
99 (((_currentCapability & (c)) == 0) && \
100 ((_pendingCapability & (c)) != 0))
101
102 #define CAP_CHANGE(c) \
103 (((_currentCapability ^ _pendingCapability) & (c)) != 0)
104
105 #define CAP_CURRENT(c) \
106 ((_currentCapability & (c)) != 0)
107
108 #define CAP_HIGHEST(c) \
109 ((_highestCapability & (c)) != 0)
110
111 #define DARK_TO_FULL_EVALUATE_CLAMSHELL 0
112
113 // Event types for IOPMPowerStateQueue::submitPowerEvent()
114 enum {
115 kPowerEventFeatureChanged = 1, // 1
116 kPowerEventReceivedPowerNotification, // 2
117 kPowerEventSystemBootCompleted, // 3
118 kPowerEventSystemShutdown, // 4
119 kPowerEventUserDisabledSleep, // 5
120 kPowerEventRegisterSystemCapabilityClient, // 6
121 kPowerEventRegisterKernelCapabilityClient, // 7
122 kPowerEventPolicyStimulus, // 8
123 kPowerEventAssertionCreate, // 9
124 kPowerEventAssertionRelease, // 10
125 kPowerEventAssertionSetLevel, // 11
126 kPowerEventQueueSleepWakeUUID, // 12
127 kPowerEventPublishSleepWakeUUID // 13
128 };
129
130 // For evaluatePolicy()
131 // List of stimuli that affects the root domain policy.
132 enum {
133 kStimulusDisplayWranglerSleep, // 0
134 kStimulusDisplayWranglerWake, // 1
135 kStimulusAggressivenessChanged, // 2
136 kStimulusDemandSystemSleep, // 3
137 kStimulusAllowSystemSleepChanged, // 4
138 kStimulusDarkWakeActivityTickle, // 5
139 kStimulusDarkWakeEntry, // 6
140 kStimulusDarkWakeReentry, // 7
141 kStimulusDarkWakeEvaluate // 8
142 };
143
144 extern "C" {
145 IOReturn OSKextSystemSleepOrWake( UInt32 );
146 }
147
148 static void idleSleepTimerExpired( thread_call_param_t, thread_call_param_t );
149 static void notifySystemShutdown( IOService * root, unsigned long event );
150 static void handleAggressivesFunction( thread_call_param_t, thread_call_param_t );
151 static void pmEventTimeStamp(uint64_t *recordTS);
152
153 // "IOPMSetSleepSupported" callPlatformFunction name
154 static const OSSymbol *sleepSupportedPEFunction = NULL;
155 static const OSSymbol *sleepMessagePEFunction = NULL;
156
157 #define kIOSleepSupportedKey "IOSleepSupported"
158 #define kIOPMSystemCapabilitiesKey "System Capabilities"
159
160 #define kRD_AllPowerSources (kIOPMSupportedOnAC \
161 | kIOPMSupportedOnBatt \
162 | kIOPMSupportedOnUPS)
163
164 enum
165 {
166 // not idle around autowake time, secs
167 kAutoWakePreWindow = 45,
168 kAutoWakePostWindow = 15
169 };
170
171 #define kLocalEvalClamshellCommand (1 << 15)
172
173 enum {
174 OFF_STATE = 0,
175 RESTART_STATE = 1,
176 SLEEP_STATE = 2,
177 ON_STATE = 3,
178 NUM_POWER_STATES
179 };
180
181 #define ON_POWER kIOPMPowerOn
182 #define RESTART_POWER kIOPMRestart
183 #define SLEEP_POWER kIOPMAuxPowerOn
184
185 static IOPMPowerState ourPowerStates[NUM_POWER_STATES] =
186 {
187 {1, 0, 0, 0, 0,0,0,0,0,0,0,0},
188 {1, kIOPMRestartCapability, kIOPMRestart, RESTART_POWER, 0,0,0,0,0,0,0,0},
189 {1, kIOPMSleepCapability, kIOPMSleep, SLEEP_POWER, 0,0,0,0,0,0,0,0},
190 {1, kIOPMPowerOn, kIOPMPowerOn, ON_POWER, 0,0,0,0,0,0,0,0}
191 };
192
193 #define kIOPMRootDomainWakeTypeMaintenance "Maintenance"
194 #define kIOPMRootDomainWakeTypeSleepTimer "SleepTimer"
195 #define kIOPMrootDomainWakeTypeLowBattery "LowBattery"
196 #define kIOPMRootDomainWakeTypeUser "User"
197 #define kIOPMRootDomainWakeTypeAlarm "Alarm"
198 #define kIOPMRootDomainWakeTypeNetwork "Network"
199
200 // Special interest that entitles the interested client from receiving
201 // all system messages. Only used by powerd.
202 //
203 #define kIOPMSystemCapabilityInterest "IOPMSystemCapabilityInterest"
204
205 /*
206 * Aggressiveness
207 */
208 #define AGGRESSIVES_LOCK() IOLockLock(featuresDictLock)
209 #define AGGRESSIVES_UNLOCK() IOLockUnlock(featuresDictLock)
210
211 #define kAggressivesMinValue 1
212
213 enum {
214 kAggressivesStateBusy = 0x01,
215 kAggressivesStateQuickSpindown = 0x02
216 };
217
218 struct AggressivesRecord {
219 uint32_t flags;
220 uint32_t type;
221 uint32_t value;
222 };
223
224 struct AggressivesRequest {
225 queue_chain_t chain;
226 uint32_t options;
227 uint32_t dataType;
228 union {
229 IOService * service;
230 AggressivesRecord record;
231 } data;
232 };
233
234 enum {
235 kAggressivesRequestTypeService = 1,
236 kAggressivesRequestTypeRecord
237 };
238
239 enum {
240 kAggressivesOptionSynchronous = 0x00000001,
241 kAggressivesOptionQuickSpindownEnable = 0x00000100,
242 kAggressivesOptionQuickSpindownDisable = 0x00000200,
243 kAggressivesOptionQuickSpindownMask = 0x00000300
244 };
245
246 enum {
247 kAggressivesRecordFlagModified = 0x00000001,
248 kAggressivesRecordFlagMinValue = 0x00000002
249 };
250
251 // gDarkWakeFlags
252 enum {
253 kDarkWakeFlagHIDTickleEarly = 0x01, // hid tickle before gfx suppression
254 kDarkWakeFlagHIDTickleLate = 0x02, // hid tickle after gfx suppression
255 kDarkWakeFlagHIDTickleNone = 0x03, // hid tickle is not posted
256 kDarkWakeFlagHIDTickleMask = 0x03,
257 kDarkWakeFlagIgnoreDiskIOInDark = 0x04, // ignore disk idle in DW
258 kDarkWakeFlagIgnoreDiskIOAlways = 0x08, // always ignore disk idle
259 kDarkWakeFlagIgnoreDiskIOMask = 0x0C,
260 kDarkWakeFlagAlarmIsDark = 0x0100
261 };
262
263 static IOPMrootDomain * gRootDomain;
264 static IONotifier * gSysPowerDownNotifier = 0;
265 static UInt32 gSleepOrShutdownPending = 0;
266 static UInt32 gWillShutdown = 0;
267 static UInt32 gPagingOff = 0;
268 static UInt32 gSleepWakeUUIDIsSet = false;
269 static uint32_t gAggressivesState = 0;
270 static uint32_t gDarkWakeFlags = kDarkWakeFlagHIDTickleNone;
271 static bool gRAMDiskImageBoot = false;
272
273 struct timeval gIOLastSleepTime;
274 struct timeval gIOLastWakeTime;
275
276 // Constants used as arguments to IOPMrootDomain::informCPUStateChange
277 #define kCPUUnknownIndex 9999999
278 enum {
279 kInformAC = 0,
280 kInformLid = 1,
281 kInformableCount = 2
282 };
283
284 const OSSymbol *gIOPMStatsApplicationResponseTimedOut;
285 const OSSymbol *gIOPMStatsApplicationResponseCancel;
286 const OSSymbol *gIOPMStatsApplicationResponseSlow;
287
288 /*
289 * PMSettingHandle
290 * Opaque handle passed to clients of registerPMSettingController()
291 */
292 class PMSettingHandle : public OSObject
293 {
294 OSDeclareFinalStructors( PMSettingHandle )
295 friend class PMSettingObject;
296
297 private:
298 PMSettingObject *pmso;
299 void free(void);
300 };
301
302 /*
303 * PMSettingObject
304 * Internal object to track each PM setting controller
305 */
306 class PMSettingObject : public OSObject
307 {
308 OSDeclareFinalStructors( PMSettingObject )
309 friend class IOPMrootDomain;
310
311 private:
312 queue_head_t calloutQueue;
313 thread_t waitThread;
314 IOPMrootDomain *parent;
315 PMSettingHandle *pmsh;
316 IOPMSettingControllerCallback func;
317 OSObject *target;
318 uintptr_t refcon;
319 uint32_t *publishedFeatureID;
320 uint32_t settingCount;
321 bool disabled;
322
323 void free(void);
324
325 public:
326 static PMSettingObject *pmSettingObject(
327 IOPMrootDomain *parent_arg,
328 IOPMSettingControllerCallback handler_arg,
329 OSObject *target_arg,
330 uintptr_t refcon_arg,
331 uint32_t supportedPowerSources,
332 const OSSymbol *settings[],
333 OSObject **handle_obj);
334
335 void dispatchPMSetting(const OSSymbol *type, OSObject *object);
336 void clientHandleFreed(void);
337 };
338
339 struct PMSettingCallEntry {
340 queue_chain_t link;
341 thread_t thread;
342 };
343
344 #define PMSETTING_LOCK() IOLockLock(settingsCtrlLock)
345 #define PMSETTING_UNLOCK() IOLockUnlock(settingsCtrlLock)
346 #define PMSETTING_WAIT(p) IOLockSleep(settingsCtrlLock, p, THREAD_UNINT)
347 #define PMSETTING_WAKEUP(p) IOLockWakeup(settingsCtrlLock, p, true)
348
349 //*********************************************************************************
350 //*********************************************************************************
351 //*********************************************************************************
352
353 /* @class IOPMTimeline
354 * @astract Tracks & records PM activity.
355 * @discussion Intended for use only as a helper-class to IOPMrootDomain.
356 * Do not subclass or directly invoke iOPMTimeline
357 */
358 class IOPMTimeline : public OSObject
359 {
360 OSDeclareDefaultStructors( IOPMTimeline );
361
362 public:
363 static IOPMTimeline* timeline(IOPMrootDomain *root_domain);
364
365 bool setProperties(OSDictionary *d);
366 OSDictionary *copyInfoDictionary(void);
367
368 IOReturn recordSystemPowerEvent( PMEventDetails *details );
369
370 IOReturn recordDetailedPowerEvent( PMEventDetails *details );
371
372 IOMemoryDescriptor *getPMTraceMemoryDescriptor();
373
374 uint32_t getNumEventsLoggedThisPeriod();
375 void setNumEventsLoggedThisPeriod(uint32_t newCount);
376 bool isSleepCycleInProgress();
377 void setSleepCycleInProgressFlag(bool flag);
378 private:
379 bool init(void);
380 void free(void);
381
382 void setEventsTrackedCount(uint32_t newTracked);
383 void setEventsRecordingLevel(uint32_t eventsTrackedBits);
384 static uint32_t _atomicIndexIncrement(uint32_t *index, uint32_t limit);
385
386 enum {
387 kPMTimelineRecordTardyDrivers = 1 << 0,
388 kPMTmielineRecordSystemEvents = 1 << 1,
389 kPMTimelineRecordAllDrivers = 1 << 2,
390 kPMTimelineRecordOff = 0,
391 kPMTimelineRecordDefault = 3,
392 kPMTimelineRecordDebug = 7
393 };
394
395 // eventsRecordingLevel is a bitfield defining which PM driver events will get logged
396 // into the PM buffer.
397 uint32_t eventsRecordingLevel;
398
399 // pmTraceMemoryDescriptor represents the memory block that IOPMTimeLine records PM trace points into.
400 IOBufferMemoryDescriptor *pmTraceMemoryDescriptor;
401
402 // Pointer to starting address in pmTraceMemoryDescriptor
403 IOPMSystemEventRecord *traceBuffer;
404 IOPMTraceBufferHeader *hdr;
405
406 uint16_t systemState;
407
408 IOLock *logLock;
409 IOPMrootDomain *owner;
410
411 uint32_t numEventsLoggedThisPeriod;
412 bool sleepCycleInProgress;
413 };
414
415 OSDefineMetaClassAndStructors( IOPMTimeline, OSObject )
416
417 /*
418 * PMTraceWorker
419 * Internal helper object for logging trace points to RTC
420 * IOPMrootDomain and only IOPMrootDomain should instantiate
421 * exactly one of these.
422 */
423
424 typedef void (*IOPMTracePointHandler)(
425 void * target, uint32_t code, uint32_t data );
426
427 class PMTraceWorker : public OSObject
428 {
429 OSDeclareDefaultStructors(PMTraceWorker)
430 public:
431 typedef enum { kPowerChangeStart, kPowerChangeCompleted } change_t;
432
433 static PMTraceWorker *tracer( IOPMrootDomain * );
434 void tracePCIPowerChange(change_t, IOService *, uint32_t, uint32_t);
435 void tracePoint(uint8_t phase);
436 void tracePoint(uint8_t phase, uint8_t data8);
437 void traceDetail(uint32_t detail);
438 void traceLoginWindowPhase(uint8_t phase);
439 int recordTopLevelPCIDevice(IOService *);
440 void RTC_TRACE(void);
441 virtual bool serialize(OSSerialize *s) const;
442
443 IOPMTracePointHandler tracePointHandler;
444 void * tracePointTarget;
445 private:
446 IOPMrootDomain *owner;
447 IOLock *pciMappingLock;
448 OSArray *pciDeviceBitMappings;
449
450 uint8_t addedToRegistry;
451 uint8_t tracePhase;
452 uint8_t loginWindowPhase;
453 uint8_t traceData8;
454 uint32_t traceData32;
455 };
456
457 /*
458 * PMAssertionsTracker
459 * Tracks kernel and user space PM assertions
460 */
461 class PMAssertionsTracker : public OSObject
462 {
463 OSDeclareFinalStructors(PMAssertionsTracker)
464 public:
465 static PMAssertionsTracker *pmAssertionsTracker( IOPMrootDomain * );
466
467 IOReturn createAssertion(IOPMDriverAssertionType, IOPMDriverAssertionLevel, IOService *, const char *, IOPMDriverAssertionID *);
468 IOReturn releaseAssertion(IOPMDriverAssertionID);
469 IOReturn setAssertionLevel(IOPMDriverAssertionID, IOPMDriverAssertionLevel);
470 IOReturn setUserAssertionLevels(IOPMDriverAssertionType);
471
472 OSArray *copyAssertionsArray(void);
473 IOPMDriverAssertionType getActivatedAssertions(void);
474 IOPMDriverAssertionLevel getAssertionLevel(IOPMDriverAssertionType);
475
476 IOReturn handleCreateAssertion(OSData *);
477 IOReturn handleReleaseAssertion(IOPMDriverAssertionID);
478 IOReturn handleSetAssertionLevel(IOPMDriverAssertionID, IOPMDriverAssertionLevel);
479 IOReturn handleSetUserAssertionLevels(void * arg0);
480 void publishProperties(void);
481
482 private:
483 typedef struct {
484 IOPMDriverAssertionID id;
485 IOPMDriverAssertionType assertionBits;
486 uint64_t createdTime;
487 uint64_t modifiedTime;
488 const OSSymbol *ownerString;
489 IOService *ownerService;
490 IOPMDriverAssertionLevel level;
491 } PMAssertStruct;
492
493 uint32_t tabulateProducerCount;
494 uint32_t tabulateConsumerCount;
495
496 PMAssertStruct *detailsForID(IOPMDriverAssertionID, int *);
497 void tabulate(void);
498
499 IOPMrootDomain *owner;
500 OSArray *assertionsArray;
501 IOLock *assertionsArrayLock;
502 IOPMDriverAssertionID issuingUniqueID __attribute__((aligned(8))); /* aligned for atomic access */
503 IOPMDriverAssertionType assertionsKernel;
504 IOPMDriverAssertionType assertionsUser;
505 IOPMDriverAssertionType assertionsCombined;
506 };
507
508 OSDefineMetaClassAndFinalStructors(PMAssertionsTracker, OSObject);
509
510 /*
511 * PMHaltWorker
512 * Internal helper object for Shutdown/Restart notifications.
513 */
514 #define kPMHaltMaxWorkers 8
515 #define kPMHaltTimeoutMS 100
516
517 class PMHaltWorker : public OSObject
518 {
519 OSDeclareFinalStructors( PMHaltWorker )
520
521 public:
522 IOService * service; // service being worked on
523 AbsoluteTime startTime; // time when work started
524 int depth; // work on nubs at this PM-tree depth
525 int visits; // number of nodes visited (debug)
526 IOLock * lock;
527 bool timeout; // service took too long
528
529 static PMHaltWorker * worker( void );
530 static void main( void * arg, wait_result_t waitResult );
531 static void work( PMHaltWorker * me );
532 static void checkTimeout( PMHaltWorker * me, AbsoluteTime * now );
533 virtual void free( void );
534 };
535
536 OSDefineMetaClassAndFinalStructors( PMHaltWorker, OSObject )
537
538
539 #define super IOService
540 OSDefineMetaClassAndFinalStructors(IOPMrootDomain, IOService)
541
542 static void IOPMRootDomainWillShutdown(void)
543 {
544 if (OSCompareAndSwap(0, 1, &gWillShutdown))
545 {
546 OSKext::willShutdown();
547 for (int i = 0; i < 100; i++)
548 {
549 if (OSCompareAndSwap(0, 1, &gSleepOrShutdownPending)) break;
550 IOSleep( 100 );
551 }
552 }
553 }
554
555 extern "C"
556 {
557 IONotifier * registerSleepWakeInterest(IOServiceInterestHandler handler, void * self, void * ref)
558 {
559 return gRootDomain->registerInterest( gIOGeneralInterest, handler, self, ref );
560 }
561
562 IONotifier * registerPrioritySleepWakeInterest(IOServiceInterestHandler handler, void * self, void * ref)
563 {
564 return gRootDomain->registerInterest( gIOPriorityPowerStateInterest, handler, self, ref );
565 }
566
567 IOReturn acknowledgeSleepWakeNotification(void * PMrefcon)
568 {
569 return gRootDomain->allowPowerChange ( (unsigned long)PMrefcon );
570 }
571
572 IOReturn vetoSleepWakeNotification(void * PMrefcon)
573 {
574 return gRootDomain->cancelPowerChange ( (unsigned long)PMrefcon );
575 }
576
577 IOReturn rootDomainRestart ( void )
578 {
579 return gRootDomain->restartSystem();
580 }
581
582 IOReturn rootDomainShutdown ( void )
583 {
584 return gRootDomain->shutdownSystem();
585 }
586
587 void IOSystemShutdownNotification(void)
588 {
589 IOPMRootDomainWillShutdown();
590 if (OSCompareAndSwap(0, 1, &gPagingOff))
591 {
592 #if !CONFIG_EMBEDDED
593 gRootDomain->handlePlatformHaltRestart(kPEPagingOff);
594 #endif
595 }
596 }
597
598 int sync_internal(void);
599 }
600
601 /*
602 A device is always in the highest power state which satisfies its driver,
603 its policy-maker, and any power children it has, but within the constraint
604 of the power state provided by its parent. The driver expresses its desire by
605 calling changePowerStateTo(), the policy-maker expresses its desire by calling
606 changePowerStateToPriv(), and the children express their desires by calling
607 requestPowerDomainState().
608
609 The Root Power Domain owns the policy for idle and demand sleep for the system.
610 It is a power-managed IOService just like the others in the system.
611 It implements several power states which map to what we see as Sleep and On.
612
613 The sleep policy is as follows:
614 1. Sleep is prevented if the case is open so that nobody will think the machine
615 is off and plug/unplug cards.
616 2. Sleep is prevented if the sleep timeout slider in the prefs panel is zero.
617 3. System cannot Sleep if some object in the tree is in a power state marked
618 kIOPMPreventSystemSleep.
619
620 These three conditions are enforced using the "driver clamp" by calling
621 changePowerStateTo(). For example, if the case is opened,
622 changePowerStateTo(ON_STATE) is called to hold the system on regardless
623 of the desires of the children of the root or the state of the other clamp.
624
625 Demand Sleep is initiated by pressing the front panel power button, closing
626 the clamshell, or selecting the menu item. In this case the root's parent
627 actually initiates the power state change so that the root domain has no
628 choice and does not give applications the opportunity to veto the change.
629
630 Idle Sleep occurs if no objects in the tree are in a state marked
631 kIOPMPreventIdleSleep. When this is true, the root's children are not holding
632 the root on, so it sets the "policy-maker clamp" by calling
633 changePowerStateToPriv(ON_STATE) to hold itself on until the sleep timer expires.
634 This timer is set for the difference between the sleep timeout slider and the
635 display dim timeout slider. When the timer expires, it releases its clamp and
636 now nothing is holding it awake, so it falls asleep.
637
638 Demand sleep is prevented when the system is booting. When preferences are
639 transmitted by the loginwindow at the end of boot, a flag is cleared,
640 and this allows subsequent Demand Sleep.
641 */
642
643 //******************************************************************************
644
645 IOPMrootDomain * IOPMrootDomain::construct( void )
646 {
647 IOPMrootDomain *root;
648
649 root = new IOPMrootDomain;
650 if( root)
651 root->init();
652
653 return( root );
654 }
655
656 //******************************************************************************
657
658 static void disk_sync_callout( thread_call_param_t p0, thread_call_param_t p1 )
659 {
660 IOService * rootDomain = (IOService *) p0;
661 uint32_t notifyRef = (uint32_t)(uintptr_t) p1;
662 uint32_t powerState = rootDomain->getPowerState();
663
664 DLOG("disk_sync_callout ps=%u\n", powerState);
665
666 if (ON_STATE == powerState)
667 {
668 #if HIBERNATION
669 IOHibernateSystemSleep();
670 #endif
671 sync_internal();
672 }
673 #if HIBERNATION
674 else
675 {
676 IOHibernateSystemPostWake();
677 }
678 #endif
679
680 rootDomain->allowPowerChange(notifyRef);
681 DLOG("disk_sync_callout finish\n");
682 }
683
684 //******************************************************************************
685
686 static UInt32 computeDeltaTimeMS( const AbsoluteTime * startTime )
687 {
688 AbsoluteTime endTime;
689 UInt64 nano = 0;
690
691 clock_get_uptime(&endTime);
692 if (CMP_ABSOLUTETIME(&endTime, startTime) > 0)
693 {
694 SUB_ABSOLUTETIME(&endTime, startTime);
695 absolutetime_to_nanoseconds(endTime, &nano);
696 }
697
698 return (UInt32)(nano / 1000000ULL);
699 }
700
701 //******************************************************************************
702
703 static int
704 sysctl_sleepwaketime SYSCTL_HANDLER_ARGS
705 {
706 struct timeval *swt = (struct timeval *)arg1;
707 struct proc *p = req->p;
708
709 if (p == kernproc) {
710 return sysctl_io_opaque(req, swt, sizeof(*swt), NULL);
711 } else if(proc_is64bit(p)) {
712 struct user64_timeval t;
713 t.tv_sec = swt->tv_sec;
714 t.tv_usec = swt->tv_usec;
715 return sysctl_io_opaque(req, &t, sizeof(t), NULL);
716 } else {
717 struct user32_timeval t;
718 t.tv_sec = swt->tv_sec;
719 t.tv_usec = swt->tv_usec;
720 return sysctl_io_opaque(req, &t, sizeof(t), NULL);
721 }
722 }
723
724 static SYSCTL_PROC(_kern, OID_AUTO, sleeptime,
725 CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
726 &gIOLastSleepTime, 0, sysctl_sleepwaketime, "S,timeval", "");
727
728 static SYSCTL_PROC(_kern, OID_AUTO, waketime,
729 CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
730 &gIOLastWakeTime, 0, sysctl_sleepwaketime, "S,timeval", "");
731
732
733 static int
734 sysctl_willshutdown
735 (__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
736 {
737 int new_value, changed;
738 int error = sysctl_io_number(req, gWillShutdown, sizeof(int), &new_value, &changed);
739 if (changed) {
740 if (!gWillShutdown && (new_value == 1)) {
741 IOPMRootDomainWillShutdown();
742 } else
743 error = EINVAL;
744 }
745 return(error);
746 }
747
748 static SYSCTL_PROC(_kern, OID_AUTO, willshutdown,
749 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
750 0, 0, sysctl_willshutdown, "I", "");
751
752 #if !CONFIG_EMBEDDED
753
754 static int
755 sysctl_progressmeterenable
756 (__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
757 {
758 int error;
759 int new_value, changed;
760
761 error = sysctl_io_number(req, vc_progress_meter_enable, sizeof(int), &new_value, &changed);
762
763 if (changed)
764 vc_enable_progressmeter(new_value);
765
766 return (error);
767 }
768
769 static int
770 sysctl_progressmeter
771 (__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
772 {
773 int error;
774 int new_value, changed;
775
776 error = sysctl_io_number(req, vc_progress_meter_value, sizeof(int), &new_value, &changed);
777
778 if (changed)
779 vc_set_progressmeter(new_value);
780
781 return (error);
782 }
783
784 static SYSCTL_PROC(_kern, OID_AUTO, progressmeterenable,
785 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
786 0, 0, sysctl_progressmeterenable, "I", "");
787
788 static SYSCTL_PROC(_kern, OID_AUTO, progressmeter,
789 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
790 0, 0, sysctl_progressmeter, "I", "");
791
792 #endif
793
794 static SYSCTL_INT(_debug, OID_AUTO, darkwake, CTLFLAG_RW, &gDarkWakeFlags, 0, "");
795
796 static const OSSymbol * gIOPMSettingAutoWakeSecondsKey;
797 static const OSSymbol * gIOPMSettingDebugWakeRelativeKey;
798 static const OSSymbol * gIOPMSettingMaintenanceWakeCalendarKey;
799
800 //******************************************************************************
801 // start
802 //
803 //******************************************************************************
804
805 #define kRootDomainSettingsCount 16
806
807 bool IOPMrootDomain::start( IOService * nub )
808 {
809 OSIterator *psIterator;
810 OSDictionary *tmpDict;
811 IORootParent * patriarch;
812
813 super::start(nub);
814
815 gRootDomain = this;
816 gIOPMSettingAutoWakeSecondsKey = OSSymbol::withCString(kIOPMSettingAutoWakeSecondsKey);
817 gIOPMSettingDebugWakeRelativeKey = OSSymbol::withCString(kIOPMSettingDebugWakeRelativeKey);
818 gIOPMSettingMaintenanceWakeCalendarKey =
819 OSSymbol::withCString(kIOPMSettingMaintenanceWakeCalendarKey);
820
821 gIOPMStatsApplicationResponseTimedOut = OSSymbol::withCString(kIOPMStatsResponseTimedOut);
822 gIOPMStatsApplicationResponseCancel = OSSymbol::withCString(kIOPMStatsResponseCancel);
823 gIOPMStatsApplicationResponseSlow = OSSymbol::withCString(kIOPMStatsResponseSlow);
824
825 sleepSupportedPEFunction = OSSymbol::withCString("IOPMSetSleepSupported");
826 sleepMessagePEFunction = OSSymbol::withCString("IOPMSystemSleepMessage");
827
828 const OSSymbol *settingsArr[kRootDomainSettingsCount] =
829 {
830 OSSymbol::withCString(kIOPMSettingSleepOnPowerButtonKey),
831 gIOPMSettingAutoWakeSecondsKey,
832 OSSymbol::withCString(kIOPMSettingAutoPowerSecondsKey),
833 OSSymbol::withCString(kIOPMSettingAutoWakeCalendarKey),
834 OSSymbol::withCString(kIOPMSettingAutoPowerCalendarKey),
835 gIOPMSettingDebugWakeRelativeKey,
836 OSSymbol::withCString(kIOPMSettingDebugPowerRelativeKey),
837 OSSymbol::withCString(kIOPMSettingWakeOnRingKey),
838 OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey),
839 OSSymbol::withCString(kIOPMSettingWakeOnClamshellKey),
840 OSSymbol::withCString(kIOPMSettingWakeOnACChangeKey),
841 OSSymbol::withCString(kIOPMSettingTimeZoneOffsetKey),
842 OSSymbol::withCString(kIOPMSettingDisplaySleepUsesDimKey),
843 OSSymbol::withCString(kIOPMSettingMobileMotionModuleKey),
844 OSSymbol::withCString(kIOPMSettingGraphicsSwitchKey),
845 OSSymbol::withCString(kIOPMStateConsoleShutdown)
846 };
847
848 PE_parse_boot_argn("darkwake", &gDarkWakeFlags, sizeof(gDarkWakeFlags));
849
850 IORegistryEntry * chosenEntry = IORegistryEntry::fromPath("/chosen", gIODTPlane);
851 if (chosenEntry)
852 {
853 if (chosenEntry->getProperty("boot-ramdmg-size") &&
854 chosenEntry->getProperty("boot-ramdmg-extents"))
855 {
856 gRAMDiskImageBoot = true;
857 }
858 chosenEntry->release();
859 }
860
861 queue_init(&aggressivesQueue);
862 aggressivesThreadCall = thread_call_allocate(handleAggressivesFunction, this);
863 aggressivesData = OSData::withCapacity(
864 sizeof(AggressivesRecord) * (kPMLastAggressivenessType + 4));
865
866 featuresDictLock = IOLockAlloc();
867 settingsCtrlLock = IOLockAlloc();
868 setPMRootDomain(this);
869
870 extraSleepTimer = thread_call_allocate(
871 idleSleepTimerExpired,
872 (thread_call_param_t) this);
873
874 diskSyncCalloutEntry = thread_call_allocate(
875 &disk_sync_callout,
876 (thread_call_param_t) this);
877
878 setProperty(kIOSleepSupportedKey, true);
879
880 bzero(&pmStats, sizeof(pmStats));
881
882 pmTracer = PMTraceWorker::tracer(this);
883
884 pmAssertions = PMAssertionsTracker::pmAssertionsTracker(this);
885
886 userDisabledAllSleep = false;
887 systemBooting = true;
888 sleepSlider = 0;
889 idleSleepTimerPending = false;
890 wrangler = NULL;
891 clamshellClosed = false;
892 clamshellExists = false;
893 clamshellDisabled = true;
894 acAdaptorConnected = true;
895
896 // Set the default system capabilities at boot.
897 _currentCapability = kIOPMSystemCapabilityCPU |
898 kIOPMSystemCapabilityGraphics |
899 kIOPMSystemCapabilityAudio |
900 kIOPMSystemCapabilityNetwork;
901
902 _pendingCapability = _currentCapability;
903 _desiredCapability = _currentCapability;
904 _highestCapability = _currentCapability;
905 setProperty(kIOPMSystemCapabilitiesKey, _currentCapability, 64);
906
907 queuedSleepWakeUUIDString = NULL;
908 pmStatsAppResponses = OSArray::withCapacity(5);
909 _statsNameKey = OSSymbol::withCString(kIOPMStatsNameKey);
910 _statsPIDKey = OSSymbol::withCString(kIOPMStatsPIDKey);
911 _statsTimeMSKey = OSSymbol::withCString(kIOPMStatsTimeMSKey);
912 _statsResponseTypeKey = OSSymbol::withCString(kIOPMStatsApplicationResponseTypeKey);
913 _statsMessageTypeKey = OSSymbol::withCString(kIOPMStatsMessageTypeKey);
914
915 idxPMCPUClamshell = kCPUUnknownIndex;
916 idxPMCPULimitedPower = kCPUUnknownIndex;
917
918 tmpDict = OSDictionary::withCapacity(1);
919 setProperty(kRootDomainSupportedFeatures, tmpDict);
920 tmpDict->release();
921
922 settingsCallbacks = OSDictionary::withCapacity(1);
923
924 // Create a list of the valid PM settings that we'll relay to
925 // interested clients in setProperties() => setPMSetting()
926 allowedPMSettings = OSArray::withObjects(
927 (const OSObject **)settingsArr,
928 kRootDomainSettingsCount,
929 0);
930
931 fPMSettingsDict = OSDictionary::withCapacity(5);
932
933 PMinit(); // creates gIOPMWorkLoop
934
935 // Create IOPMPowerStateQueue used to queue external power
936 // events, and to handle those events on the PM work loop.
937 pmPowerStateQueue = IOPMPowerStateQueue::PMPowerStateQueue(
938 this, OSMemberFunctionCast(IOEventSource::Action, this,
939 &IOPMrootDomain::dispatchPowerEvent));
940 getPMworkloop()->addEventSource(pmPowerStateQueue);
941 #ifdef CHECK_THREAD_CONTEXT
942 gIOPMWorkLoop = getPMworkloop();
943 #endif
944
945 // create our power parent
946 patriarch = new IORootParent;
947 patriarch->init();
948 patriarch->attach(this);
949 patriarch->start(this);
950 patriarch->addPowerChild(this);
951
952 registerPowerDriver(this, ourPowerStates, NUM_POWER_STATES);
953 changePowerStateToPriv(ON_STATE);
954
955 if (gIOKitDebug & (kIOLogDriverPower1 | kIOLogDriverPower2))
956 {
957 // Setup our PM logging & recording code
958 timeline = IOPMTimeline::timeline(this);
959 if (timeline) {
960 OSDictionary *tlInfo = timeline->copyInfoDictionary();
961
962 if (tlInfo)
963 {
964 setProperty(kIOPMTimelineDictionaryKey, tlInfo);
965 tlInfo->release();
966 }
967 }
968 }
969
970 // install power change handler
971 gSysPowerDownNotifier = registerPrioritySleepWakeInterest( &sysPowerDownHandler, this, 0);
972
973 #if !NO_KERNEL_HID
974 // Register for a notification when IODisplayWrangler is published
975 if ((tmpDict = serviceMatching("IODisplayWrangler")))
976 {
977 _displayWranglerNotifier = addMatchingNotification(
978 gIOPublishNotification, tmpDict,
979 (IOServiceMatchingNotificationHandler) &displayWranglerMatchPublished,
980 this, 0);
981 tmpDict->release();
982 }
983 #endif
984
985 const OSSymbol *ucClassName = OSSymbol::withCStringNoCopy("RootDomainUserClient");
986 setProperty(gIOUserClientClassKey, (OSObject *) ucClassName);
987 ucClassName->release();
988
989 // IOBacklightDisplay can take a long time to load at boot, or it may
990 // not load at all if you're booting with clamshell closed. We publish
991 // 'DisplayDims' here redundantly to get it published early and at all.
992 psIterator = getMatchingServices( serviceMatching("IOPMPowerSource") );
993 if( psIterator && psIterator->getNextObject() )
994 {
995 // There's at least one battery on the system, so we publish
996 // 'DisplayDims' support for the LCD.
997 publishFeature("DisplayDims");
998 }
999 if(psIterator) {
1000 psIterator->release();
1001 }
1002
1003 sysctl_register_oid(&sysctl__kern_sleeptime);
1004 sysctl_register_oid(&sysctl__kern_waketime);
1005 sysctl_register_oid(&sysctl__kern_willshutdown);
1006 #if !CONFIG_EMBEDDED
1007 sysctl_register_oid(&sysctl__kern_progressmeterenable);
1008 sysctl_register_oid(&sysctl__kern_progressmeter);
1009 #endif /* !CONFIG_EMBEDDED */
1010
1011 #if HIBERNATION
1012 IOHibernateSystemInit(this);
1013 #endif
1014
1015 registerService(); // let clients find us
1016
1017 return true;
1018 }
1019
1020 //******************************************************************************
1021 // setProperties
1022 //
1023 // Receive a setProperty call
1024 // The "System Boot" property means the system is completely booted.
1025 //******************************************************************************
1026
1027 IOReturn IOPMrootDomain::setProperties( OSObject * props_obj )
1028 {
1029 IOReturn return_value = kIOReturnSuccess;
1030 OSDictionary *dict = OSDynamicCast(OSDictionary, props_obj);
1031 OSBoolean *b;
1032 OSNumber *n;
1033 OSDictionary *d;
1034 OSSymbol *type;
1035 OSObject *obj;
1036 unsigned int i;
1037
1038 const OSSymbol *publish_simulated_battery_string = OSSymbol::withCString("SoftwareSimulatedBatteries");
1039 const OSSymbol *boot_complete_string = OSSymbol::withCString("System Boot Complete");
1040 const OSSymbol *sys_shutdown_string = OSSymbol::withCString("System Shutdown");
1041 const OSSymbol *stall_halt_string = OSSymbol::withCString("StallSystemAtHalt");
1042 const OSSymbol *battery_warning_disabled_string = OSSymbol::withCString("BatteryWarningsDisabled");
1043 const OSSymbol *idle_seconds_string = OSSymbol::withCString("System Idle Seconds");
1044 const OSSymbol *sleepdisabled_string = OSSymbol::withCString("SleepDisabled");
1045 const OSSymbol *ondeck_sleepwake_uuid_string = OSSymbol::withCString(kIOPMSleepWakeUUIDKey);
1046 const OSSymbol *loginwindow_tracepoint_string = OSSymbol::withCString(kIOPMLoginWindowSecurityDebugKey);
1047 const OSSymbol *pmTimelineLogging_string = OSSymbol::withCString(kIOPMTimelineDictionaryKey);
1048 #if HIBERNATION
1049 const OSSymbol *hibernatemode_string = OSSymbol::withCString(kIOHibernateModeKey);
1050 const OSSymbol *hibernatefile_string = OSSymbol::withCString(kIOHibernateFileKey);
1051 const OSSymbol *hibernatefreeratio_string = OSSymbol::withCString(kIOHibernateFreeRatioKey);
1052 const OSSymbol *hibernatefreetime_string = OSSymbol::withCString(kIOHibernateFreeTimeKey);
1053 #endif
1054
1055 if (!dict)
1056 {
1057 return_value = kIOReturnBadArgument;
1058 goto exit;
1059 }
1060
1061 if ((b = OSDynamicCast(OSBoolean, dict->getObject(publish_simulated_battery_string))))
1062 {
1063 publishResource(publish_simulated_battery_string, kOSBooleanTrue);
1064 }
1065
1066 if ((n = OSDynamicCast(OSNumber, dict->getObject(idle_seconds_string))))
1067 {
1068 setProperty(idle_seconds_string, n);
1069 idleSeconds = n->unsigned32BitValue();
1070 }
1071
1072 if (boot_complete_string && dict->getObject(boot_complete_string))
1073 {
1074 pmPowerStateQueue->submitPowerEvent( kPowerEventSystemBootCompleted );
1075 }
1076
1077 if( battery_warning_disabled_string && dict->getObject(battery_warning_disabled_string))
1078 {
1079 setProperty( battery_warning_disabled_string, dict->getObject(battery_warning_disabled_string));
1080 }
1081
1082 if (pmTimelineLogging_string && (d = OSDynamicCast(OSDictionary, dict->getObject(pmTimelineLogging_string))))
1083 {
1084 if (timeline && timeline->setProperties(d))
1085 {
1086 OSDictionary *tlInfo = timeline->copyInfoDictionary();
1087 if (tlInfo) {
1088 setProperty(kIOPMTimelineDictionaryKey, tlInfo);
1089 tlInfo->release();
1090 }
1091 }
1092 }
1093
1094 if( sys_shutdown_string && (b = OSDynamicCast(OSBoolean, dict->getObject(sys_shutdown_string))))
1095 {
1096 pmPowerStateQueue->submitPowerEvent(kPowerEventSystemShutdown, (void *) b);
1097 }
1098
1099 if( stall_halt_string && (b = OSDynamicCast(OSBoolean, dict->getObject(stall_halt_string))) )
1100 {
1101 setProperty(stall_halt_string, b);
1102 }
1103
1104 #if HIBERNATION
1105 if ( hibernatemode_string
1106 && (n = OSDynamicCast(OSNumber, dict->getObject(hibernatemode_string))))
1107 {
1108 setProperty(hibernatemode_string, n);
1109 }
1110 if ( hibernatefreeratio_string
1111 && (n = OSDynamicCast(OSNumber, dict->getObject(hibernatefreeratio_string))))
1112 {
1113 setProperty(hibernatefreeratio_string, n);
1114 }
1115 if ( hibernatefreetime_string
1116 && (n = OSDynamicCast(OSNumber, dict->getObject(hibernatefreetime_string))))
1117 {
1118 setProperty(hibernatefreetime_string, n);
1119 }
1120 OSString *str;
1121 if ( hibernatefile_string
1122 && (str = OSDynamicCast(OSString, dict->getObject(hibernatefile_string))))
1123 {
1124 setProperty(hibernatefile_string, str);
1125 }
1126 #endif
1127
1128 if( sleepdisabled_string
1129 && (b = OSDynamicCast(OSBoolean, dict->getObject(sleepdisabled_string))) )
1130 {
1131 setProperty(sleepdisabled_string, b);
1132 pmPowerStateQueue->submitPowerEvent(kPowerEventUserDisabledSleep, (void *) b);
1133 }
1134 if (ondeck_sleepwake_uuid_string
1135 && (obj = dict->getObject(ondeck_sleepwake_uuid_string)))
1136 {
1137 if(pmPowerStateQueue) {
1138 obj->retain();
1139 pmPowerStateQueue->submitPowerEvent(kPowerEventQueueSleepWakeUUID, (void *)obj);
1140 }
1141
1142 }
1143
1144 if (loginwindow_tracepoint_string
1145 && (n = OSDynamicCast(OSNumber, dict->getObject(loginwindow_tracepoint_string)))
1146 && pmTracer)
1147 {
1148 pmTracer->traceLoginWindowPhase( n->unsigned8BitValue() );
1149 }
1150
1151 if ((b = OSDynamicCast(OSBoolean, dict->getObject(kIOPMDeepSleepEnabledKey))))
1152 {
1153 setProperty(kIOPMDeepSleepEnabledKey, b);
1154 }
1155 if ((n = OSDynamicCast(OSNumber, dict->getObject(kIOPMDeepSleepDelayKey))))
1156 {
1157 setProperty(kIOPMDeepSleepDelayKey, n);
1158 }
1159 if ((b = OSDynamicCast(OSBoolean, dict->getObject(kIOPMDestroyFVKeyOnStandbyKey))))
1160 {
1161 setProperty(kIOPMDestroyFVKeyOnStandbyKey, b);
1162 }
1163
1164 // Relay our allowed PM settings onto our registered PM clients
1165 for(i = 0; i < allowedPMSettings->getCount(); i++) {
1166
1167 type = (OSSymbol *)allowedPMSettings->getObject(i);
1168 if(!type) continue;
1169
1170 obj = dict->getObject(type);
1171 if(!obj) continue;
1172
1173 if ((gIOPMSettingAutoWakeSecondsKey == type) && ((n = OSDynamicCast(OSNumber, obj))))
1174 {
1175 UInt32 rsecs = n->unsigned32BitValue();
1176 if (!rsecs)
1177 autoWakeStart = autoWakeEnd = 0;
1178 else
1179 {
1180 AbsoluteTime deadline;
1181 clock_interval_to_deadline(rsecs + kAutoWakePostWindow, kSecondScale, &deadline);
1182 autoWakeEnd = AbsoluteTime_to_scalar(&deadline);
1183 if (rsecs > kAutoWakePreWindow)
1184 rsecs -= kAutoWakePreWindow;
1185 else
1186 rsecs = 0;
1187 clock_interval_to_deadline(rsecs, kSecondScale, &deadline);
1188 autoWakeStart = AbsoluteTime_to_scalar(&deadline);
1189 }
1190 }
1191 if (gIOPMSettingDebugWakeRelativeKey == type)
1192 {
1193 if ((n = OSDynamicCast(OSNumber, obj)))
1194 _debugWakeSeconds = n->unsigned32BitValue();
1195 else
1196 _debugWakeSeconds = 0;
1197 }
1198
1199 return_value = setPMSetting(type, obj);
1200
1201 if(kIOReturnSuccess != return_value) goto exit;
1202 }
1203
1204 exit:
1205 if(publish_simulated_battery_string) publish_simulated_battery_string->release();
1206 if(boot_complete_string) boot_complete_string->release();
1207 if(sys_shutdown_string) sys_shutdown_string->release();
1208 if(stall_halt_string) stall_halt_string->release();
1209 if(battery_warning_disabled_string) battery_warning_disabled_string->release();
1210 if(idle_seconds_string) idle_seconds_string->release();
1211 if(sleepdisabled_string) sleepdisabled_string->release();
1212 if(ondeck_sleepwake_uuid_string) ondeck_sleepwake_uuid_string->release();
1213 if(loginwindow_tracepoint_string) loginwindow_tracepoint_string->release();
1214 if(pmTimelineLogging_string) pmTimelineLogging_string->release();
1215 #if HIBERNATION
1216 if(hibernatemode_string) hibernatemode_string->release();
1217 if(hibernatefile_string) hibernatefile_string->release();
1218 if(hibernatefreeratio_string) hibernatefreeratio_string->release();
1219 if(hibernatefreetime_string) hibernatefreetime_string->release();
1220 #endif
1221 return return_value;
1222 }
1223
1224 // MARK: -
1225 // MARK: Aggressiveness
1226
1227 //******************************************************************************
1228 // setAggressiveness
1229 //
1230 // Override IOService::setAggressiveness()
1231 //******************************************************************************
1232
1233 IOReturn IOPMrootDomain::setAggressiveness(
1234 unsigned long type,
1235 unsigned long value )
1236 {
1237 return setAggressiveness( type, value, 0 );
1238 }
1239
1240 /*
1241 * Private setAggressiveness() with an internal options argument.
1242 */
1243 IOReturn IOPMrootDomain::setAggressiveness(
1244 unsigned long type,
1245 unsigned long value,
1246 IOOptionBits options )
1247 {
1248 AggressivesRequest * entry;
1249 AggressivesRequest * request;
1250 bool found = false;
1251
1252 DLOG("setAggressiveness(%x) 0x%x = %u\n",
1253 (uint32_t) options, (uint32_t) type, (uint32_t) value);
1254
1255 request = IONew(AggressivesRequest, 1);
1256 if (!request)
1257 return kIOReturnNoMemory;
1258
1259 memset(request, 0, sizeof(*request));
1260 request->options = options;
1261 request->dataType = kAggressivesRequestTypeRecord;
1262 request->data.record.type = (uint32_t) type;
1263 request->data.record.value = (uint32_t) value;
1264
1265 AGGRESSIVES_LOCK();
1266
1267 // Update disk quick spindown flag used by getAggressiveness().
1268 // Never merge requests with quick spindown flags set.
1269
1270 if (options & kAggressivesOptionQuickSpindownEnable)
1271 gAggressivesState |= kAggressivesStateQuickSpindown;
1272 else if (options & kAggressivesOptionQuickSpindownDisable)
1273 gAggressivesState &= ~kAggressivesStateQuickSpindown;
1274 else
1275 {
1276 // Coalesce requests with identical aggressives types.
1277 // Deal with callers that calls us too "aggressively".
1278
1279 queue_iterate(&aggressivesQueue, entry, AggressivesRequest *, chain)
1280 {
1281 if ((entry->dataType == kAggressivesRequestTypeRecord) &&
1282 (entry->data.record.type == type) &&
1283 ((entry->options & kAggressivesOptionQuickSpindownMask) == 0))
1284 {
1285 entry->data.record.value = value;
1286 found = true;
1287 break;
1288 }
1289 }
1290 }
1291
1292 if (!found)
1293 {
1294 queue_enter(&aggressivesQueue, request, AggressivesRequest *, chain);
1295 }
1296
1297 AGGRESSIVES_UNLOCK();
1298
1299 if (found)
1300 IODelete(request, AggressivesRequest, 1);
1301
1302 if (options & kAggressivesOptionSynchronous)
1303 handleAggressivesRequests(); // not truly synchronous
1304 else
1305 thread_call_enter(aggressivesThreadCall);
1306
1307 return kIOReturnSuccess;
1308 }
1309
1310 //******************************************************************************
1311 // getAggressiveness
1312 //
1313 // Override IOService::setAggressiveness()
1314 // Fetch the aggressiveness factor with the given type.
1315 //******************************************************************************
1316
1317 IOReturn IOPMrootDomain::getAggressiveness (
1318 unsigned long type,
1319 unsigned long * outLevel )
1320 {
1321 uint32_t value = 0;
1322 int source = 0;
1323
1324 if (!outLevel)
1325 return kIOReturnBadArgument;
1326
1327 AGGRESSIVES_LOCK();
1328
1329 // Disk quick spindown in effect, report value = 1
1330
1331 if ((gAggressivesState & kAggressivesStateQuickSpindown) &&
1332 (type == kPMMinutesToSpinDown))
1333 {
1334 value = kAggressivesMinValue;
1335 source = 1;
1336 }
1337
1338 // Consult the pending request queue.
1339
1340 if (!source)
1341 {
1342 AggressivesRequest * entry;
1343
1344 queue_iterate(&aggressivesQueue, entry, AggressivesRequest *, chain)
1345 {
1346 if ((entry->dataType == kAggressivesRequestTypeRecord) &&
1347 (entry->data.record.type == type) &&
1348 ((entry->options & kAggressivesOptionQuickSpindownMask) == 0))
1349 {
1350 value = entry->data.record.value;
1351 source = 2;
1352 break;
1353 }
1354 }
1355 }
1356
1357 // Consult the backend records.
1358
1359 if (!source && aggressivesData)
1360 {
1361 AggressivesRecord * record;
1362 int i, count;
1363
1364 count = aggressivesData->getLength() / sizeof(AggressivesRecord);
1365 record = (AggressivesRecord *) aggressivesData->getBytesNoCopy();
1366
1367 for (i = 0; i < count; i++, record++)
1368 {
1369 if (record->type == type)
1370 {
1371 value = record->value;
1372 source = 3;
1373 break;
1374 }
1375 }
1376 }
1377
1378 AGGRESSIVES_UNLOCK();
1379
1380 if (source)
1381 {
1382 DLOG("getAggressiveness(%d) 0x%x = %u\n",
1383 source, (uint32_t) type, value);
1384 *outLevel = (unsigned long) value;
1385 return kIOReturnSuccess;
1386 }
1387 else
1388 {
1389 DLOG("getAggressiveness type 0x%x not found\n", (uint32_t) type);
1390 *outLevel = 0; // default return = 0, driver may not check for error
1391 return kIOReturnInvalid;
1392 }
1393 }
1394
1395 //******************************************************************************
1396 // joinAggressiveness
1397 //
1398 // Request from IOService to join future aggressiveness broadcasts.
1399 //******************************************************************************
1400
1401 IOReturn IOPMrootDomain::joinAggressiveness(
1402 IOService * service )
1403 {
1404 AggressivesRequest * request;
1405
1406 if (!service || (service == this))
1407 return kIOReturnBadArgument;
1408
1409 DLOG("joinAggressiveness %s %p\n", service->getName(), service);
1410
1411 request = IONew(AggressivesRequest, 1);
1412 if (!request)
1413 return kIOReturnNoMemory;
1414
1415 service->retain(); // released by synchronizeAggressives()
1416
1417 memset(request, 0, sizeof(*request));
1418 request->dataType = kAggressivesRequestTypeService;
1419 request->data.service = service;
1420
1421 AGGRESSIVES_LOCK();
1422 queue_enter(&aggressivesQueue, request, AggressivesRequest *, chain);
1423 AGGRESSIVES_UNLOCK();
1424
1425 thread_call_enter(aggressivesThreadCall);
1426
1427 return kIOReturnSuccess;
1428 }
1429
1430 //******************************************************************************
1431 // handleAggressivesRequests
1432 //
1433 // Backend thread processes all incoming aggressiveness requests in the queue.
1434 //******************************************************************************
1435
1436 static void
1437 handleAggressivesFunction(
1438 thread_call_param_t param1,
1439 thread_call_param_t param2 )
1440 {
1441 if (param1)
1442 {
1443 ((IOPMrootDomain *) param1)->handleAggressivesRequests();
1444 }
1445 }
1446
1447 void IOPMrootDomain::handleAggressivesRequests( void )
1448 {
1449 AggressivesRecord * start;
1450 AggressivesRecord * record;
1451 AggressivesRequest * request;
1452 queue_head_t joinedQueue;
1453 int i, count;
1454 bool broadcast;
1455 bool found;
1456 bool pingSelf = false;
1457
1458 AGGRESSIVES_LOCK();
1459
1460 if ((gAggressivesState & kAggressivesStateBusy) || !aggressivesData ||
1461 queue_empty(&aggressivesQueue))
1462 goto unlock_done;
1463
1464 gAggressivesState |= kAggressivesStateBusy;
1465 count = aggressivesData->getLength() / sizeof(AggressivesRecord);
1466 start = (AggressivesRecord *) aggressivesData->getBytesNoCopy();
1467
1468 do
1469 {
1470 broadcast = false;
1471 queue_init(&joinedQueue);
1472
1473 do
1474 {
1475 // Remove request from the incoming queue in FIFO order.
1476 queue_remove_first(&aggressivesQueue, request, AggressivesRequest *, chain);
1477 switch (request->dataType)
1478 {
1479 case kAggressivesRequestTypeRecord:
1480 // Update existing record if found.
1481 found = false;
1482 for (i = 0, record = start; i < count; i++, record++)
1483 {
1484 if (record->type == request->data.record.type)
1485 {
1486 found = true;
1487
1488 if (request->options & kAggressivesOptionQuickSpindownEnable)
1489 {
1490 if ((record->flags & kAggressivesRecordFlagMinValue) == 0)
1491 {
1492 broadcast = true;
1493 record->flags |= (kAggressivesRecordFlagMinValue |
1494 kAggressivesRecordFlagModified);
1495 DLOG("disk spindown accelerated, was %u min\n",
1496 record->value);
1497 }
1498 }
1499 else if (request->options & kAggressivesOptionQuickSpindownDisable)
1500 {
1501 if (record->flags & kAggressivesRecordFlagMinValue)
1502 {
1503 broadcast = true;
1504 record->flags |= kAggressivesRecordFlagModified;
1505 record->flags &= ~kAggressivesRecordFlagMinValue;
1506 DLOG("disk spindown restored to %u min\n",
1507 record->value);
1508 }
1509 }
1510 else if (record->value != request->data.record.value)
1511 {
1512 record->value = request->data.record.value;
1513 if ((record->flags & kAggressivesRecordFlagMinValue) == 0)
1514 {
1515 broadcast = true;
1516 record->flags |= kAggressivesRecordFlagModified;
1517 }
1518 }
1519 break;
1520 }
1521 }
1522
1523 // No matching record, append a new record.
1524 if (!found &&
1525 ((request->options & kAggressivesOptionQuickSpindownDisable) == 0))
1526 {
1527 AggressivesRecord newRecord;
1528
1529 newRecord.flags = kAggressivesRecordFlagModified;
1530 newRecord.type = request->data.record.type;
1531 newRecord.value = request->data.record.value;
1532 if (request->options & kAggressivesOptionQuickSpindownEnable)
1533 {
1534 newRecord.flags |= kAggressivesRecordFlagMinValue;
1535 DLOG("disk spindown accelerated\n");
1536 }
1537
1538 aggressivesData->appendBytes(&newRecord, sizeof(newRecord));
1539
1540 // OSData may have switched to another (larger) buffer.
1541 count = aggressivesData->getLength() / sizeof(AggressivesRecord);
1542 start = (AggressivesRecord *) aggressivesData->getBytesNoCopy();
1543 broadcast = true;
1544 }
1545
1546 // Finished processing the request, release it.
1547 IODelete(request, AggressivesRequest, 1);
1548 break;
1549
1550 case kAggressivesRequestTypeService:
1551 // synchronizeAggressives() will free request.
1552 queue_enter(&joinedQueue, request, AggressivesRequest *, chain);
1553 break;
1554
1555 default:
1556 panic("bad aggressives request type %x\n", request->dataType);
1557 break;
1558 }
1559 } while (!queue_empty(&aggressivesQueue));
1560
1561 // Release the lock to perform work, with busy flag set.
1562 if (!queue_empty(&joinedQueue) || broadcast)
1563 {
1564 AGGRESSIVES_UNLOCK();
1565 if (!queue_empty(&joinedQueue))
1566 synchronizeAggressives(&joinedQueue, start, count);
1567 if (broadcast)
1568 broadcastAggressives(start, count);
1569 AGGRESSIVES_LOCK();
1570 }
1571
1572 // Remove the modified flag from all records.
1573 for (i = 0, record = start; i < count; i++, record++)
1574 {
1575 if ((record->flags & kAggressivesRecordFlagModified) &&
1576 ((record->type == kPMMinutesToDim) ||
1577 (record->type == kPMMinutesToSleep)))
1578 pingSelf = true;
1579
1580 record->flags &= ~kAggressivesRecordFlagModified;
1581 }
1582
1583 // Check the incoming queue again since new entries may have been
1584 // added while lock was released above.
1585
1586 } while (!queue_empty(&aggressivesQueue));
1587
1588 gAggressivesState &= ~kAggressivesStateBusy;
1589
1590 unlock_done:
1591 AGGRESSIVES_UNLOCK();
1592
1593 // Root domain is interested in system and display sleep slider changes.
1594 // Submit a power event to handle those changes on the PM work loop.
1595
1596 if (pingSelf && pmPowerStateQueue) {
1597 pmPowerStateQueue->submitPowerEvent(
1598 kPowerEventPolicyStimulus,
1599 (void *) kStimulusAggressivenessChanged );
1600 }
1601 }
1602
1603 //******************************************************************************
1604 // synchronizeAggressives
1605 //
1606 // Push all known aggressiveness records to one or more IOService.
1607 //******************************************************************************
1608
1609 void IOPMrootDomain::synchronizeAggressives(
1610 queue_head_t * joinedQueue,
1611 const AggressivesRecord * array,
1612 int count )
1613 {
1614 IOService * service;
1615 AggressivesRequest * request;
1616 const AggressivesRecord * record;
1617 IOPMDriverCallEntry callEntry;
1618 uint32_t value;
1619 int i;
1620
1621 while (!queue_empty(joinedQueue))
1622 {
1623 queue_remove_first(joinedQueue, request, AggressivesRequest *, chain);
1624 if (request->dataType == kAggressivesRequestTypeService)
1625 service = request->data.service;
1626 else
1627 service = 0;
1628
1629 IODelete(request, AggressivesRequest, 1);
1630 request = 0;
1631
1632 if (service)
1633 {
1634 if (service->assertPMDriverCall(&callEntry))
1635 {
1636 for (i = 0, record = array; i < count; i++, record++)
1637 {
1638 value = record->value;
1639 if (record->flags & kAggressivesRecordFlagMinValue)
1640 value = kAggressivesMinValue;
1641
1642 _LOG("synchronizeAggressives 0x%x = %u to %s\n",
1643 record->type, value, service->getName());
1644 service->setAggressiveness(record->type, value);
1645 }
1646 service->deassertPMDriverCall(&callEntry);
1647 }
1648 service->release(); // retained by joinAggressiveness()
1649 }
1650 }
1651 }
1652
1653 //******************************************************************************
1654 // broadcastAggressives
1655 //
1656 // Traverse PM tree and call setAggressiveness() for records that have changed.
1657 //******************************************************************************
1658
1659 void IOPMrootDomain::broadcastAggressives(
1660 const AggressivesRecord * array,
1661 int count )
1662 {
1663 IORegistryIterator * iter;
1664 IORegistryEntry * entry;
1665 IOPowerConnection * connect;
1666 IOService * service;
1667 const AggressivesRecord * record;
1668 IOPMDriverCallEntry callEntry;
1669 uint32_t value;
1670 int i;
1671
1672 iter = IORegistryIterator::iterateOver(
1673 this, gIOPowerPlane, kIORegistryIterateRecursively);
1674 if (iter)
1675 {
1676 do
1677 {
1678 iter->reset();
1679 while ((entry = iter->getNextObject()))
1680 {
1681 connect = OSDynamicCast(IOPowerConnection, entry);
1682 if (!connect || !connect->getReadyFlag())
1683 continue;
1684
1685 if ((service = (IOService *) connect->copyChildEntry(gIOPowerPlane)))
1686 {
1687 if (service->assertPMDriverCall(&callEntry))
1688 {
1689 for (i = 0, record = array; i < count; i++, record++)
1690 {
1691 if (record->flags & kAggressivesRecordFlagModified)
1692 {
1693 value = record->value;
1694 if (record->flags & kAggressivesRecordFlagMinValue)
1695 value = kAggressivesMinValue;
1696 _LOG("broadcastAggressives %x = %u to %s\n",
1697 record->type, value, service->getName());
1698 service->setAggressiveness(record->type, value);
1699 }
1700 }
1701 service->deassertPMDriverCall(&callEntry);
1702 }
1703 service->release();
1704 }
1705 }
1706 }
1707 while (!entry && !iter->isValid());
1708 iter->release();
1709 }
1710 }
1711
1712 // MARK: -
1713 // MARK: System Sleep
1714
1715 //******************************************************************************
1716 // startIdleSleepTimer
1717 //
1718 //******************************************************************************
1719
1720 void IOPMrootDomain::startIdleSleepTimer( uint32_t inSeconds )
1721 {
1722 AbsoluteTime deadline;
1723
1724 ASSERT_GATED();
1725 if (inSeconds)
1726 {
1727 clock_interval_to_deadline(inSeconds, kSecondScale, &deadline);
1728 thread_call_enter_delayed(extraSleepTimer, deadline);
1729 idleSleepTimerPending = true;
1730 DLOG("idle timer set for %u seconds\n", inSeconds);
1731 }
1732 }
1733
1734 //******************************************************************************
1735 // cancelIdleSleepTimer
1736 //
1737 //******************************************************************************
1738
1739 void IOPMrootDomain::cancelIdleSleepTimer( void )
1740 {
1741 ASSERT_GATED();
1742 if (idleSleepTimerPending)
1743 {
1744 DLOG("idle timer cancelled\n");
1745 thread_call_cancel(extraSleepTimer);
1746 idleSleepTimerPending = false;
1747 }
1748 }
1749
1750 //******************************************************************************
1751 // idleSleepTimerExpired
1752 //
1753 //******************************************************************************
1754
1755 static void idleSleepTimerExpired(
1756 thread_call_param_t us, thread_call_param_t )
1757 {
1758 ((IOPMrootDomain *)us)->handleSleepTimerExpiration();
1759 }
1760
1761 //******************************************************************************
1762 // handleSleepTimerExpiration
1763 //
1764 // The time between the sleep idle timeout and the next longest one has elapsed.
1765 // It's time to sleep. Start that by removing the clamp that's holding us awake.
1766 //******************************************************************************
1767
1768 void IOPMrootDomain::handleSleepTimerExpiration( void )
1769 {
1770 if (!getPMworkloop()->inGate())
1771 {
1772 getPMworkloop()->runAction(
1773 OSMemberFunctionCast(IOWorkLoop::Action, this,
1774 &IOPMrootDomain::handleSleepTimerExpiration),
1775 this);
1776 return;
1777 }
1778
1779 AbsoluteTime time;
1780
1781 DLOG("sleep timer expired\n");
1782 ASSERT_GATED();
1783
1784 idleSleepTimerPending = false;
1785
1786 clock_get_uptime(&time);
1787 if ((AbsoluteTime_to_scalar(&time) > autoWakeStart) &&
1788 (AbsoluteTime_to_scalar(&time) < autoWakeEnd))
1789 {
1790 thread_call_enter_delayed(extraSleepTimer, *((AbsoluteTime *) &autoWakeEnd));
1791 return;
1792 }
1793
1794 setQuickSpinDownTimeout();
1795 adjustPowerState(true);
1796 }
1797
1798 //******************************************************************************
1799 // setQuickSpinDownTimeout
1800 //
1801 //******************************************************************************
1802
1803 void IOPMrootDomain::setQuickSpinDownTimeout( void )
1804 {
1805 ASSERT_GATED();
1806 setAggressiveness(
1807 kPMMinutesToSpinDown, 0, kAggressivesOptionQuickSpindownEnable );
1808 }
1809
1810 //******************************************************************************
1811 // restoreUserSpinDownTimeout
1812 //
1813 //******************************************************************************
1814
1815 void IOPMrootDomain::restoreUserSpinDownTimeout( void )
1816 {
1817 ASSERT_GATED();
1818 setAggressiveness(
1819 kPMMinutesToSpinDown, 0, kAggressivesOptionQuickSpindownDisable );
1820 }
1821
1822 //******************************************************************************
1823 // sleepSystem
1824 //
1825 //******************************************************************************
1826
1827 /* public */
1828 IOReturn IOPMrootDomain::sleepSystem( void )
1829 {
1830 return sleepSystemOptions(NULL);
1831 }
1832
1833 /* private */
1834 IOReturn IOPMrootDomain::sleepSystemOptions( OSDictionary *options )
1835 {
1836 /* sleepSystem is a public function, and may be called by any kernel driver.
1837 * And that's bad - drivers should sleep the system by calling
1838 * receivePowerNotification() instead. Drivers should not use sleepSystem.
1839 *
1840 * Note that user space app calls to IOPMSleepSystem() will also travel
1841 * this code path and thus be correctly identified as software sleeps.
1842 */
1843
1844 if (options && options->getObject("OSSwitch"))
1845 {
1846 // Log specific sleep cause for OS Switch hibernation
1847 return privateSleepSystem( kIOPMSleepReasonOSSwitchHibernate);
1848 } else {
1849 return privateSleepSystem( kIOPMSleepReasonSoftware);
1850 }
1851 }
1852
1853 /* private */
1854 IOReturn IOPMrootDomain::privateSleepSystem( uint32_t sleepReason )
1855 {
1856 static const char * IOPMSleepReasons[] = {
1857 "",
1858 kIOPMClamshellSleepKey,
1859 kIOPMPowerButtonSleepKey,
1860 kIOPMSoftwareSleepKey,
1861 kIOPMOSSwitchHibernationKey,
1862 kIOPMIdleSleepKey,
1863 kIOPMLowPowerSleepKey,
1864 kIOPMClamshellSleepKey,
1865 kIOPMThermalEmergencySleepKey,
1866 kIOPMMaintenanceSleepKey
1867 };
1868
1869 PMEventDetails *details;
1870
1871 if (!checkSystemCanSleep())
1872 {
1873 // Record why the system couldn't sleep
1874 details = PMEventDetails::eventDetails(kIOPMEventTypeSleep, NULL,
1875 sleepReason, kIOReturnNotPermitted);
1876
1877 recordAndReleasePMEvent( details );
1878 return kIOReturnNotPermitted;
1879 }
1880
1881 if (timeline)
1882 timeline->setSleepCycleInProgressFlag(true);
1883
1884 // Time to publish a UUID for the Sleep --> Wake cycle
1885 if(pmPowerStateQueue) {
1886 pmPowerStateQueue->submitPowerEvent(kPowerEventPublishSleepWakeUUID, (void *)true);
1887 }
1888
1889
1890 // Log the beginning of system sleep.
1891 details = PMEventDetails::eventDetails(kIOPMEventTypeSleep, NULL,
1892 sleepReason, kIOReturnSuccess);
1893
1894 recordAndReleasePMEvent( details );
1895
1896 // Record sleep cause in IORegistry
1897 lastSleepReason = sleepReason;
1898 sleepReason -= (kIOPMSleepReasonClamshell - 1);
1899 if (sleepReason && (sleepReason < sizeof(IOPMSleepReasons)/sizeof(IOPMSleepReasons[0]))) {
1900 setProperty(kRootDomainSleepReasonKey, IOPMSleepReasons[sleepReason]);
1901 }
1902
1903 if (pmPowerStateQueue)
1904 pmPowerStateQueue->submitPowerEvent(
1905 kPowerEventPolicyStimulus,
1906 (void *) kStimulusDemandSystemSleep );
1907
1908 return kIOReturnSuccess;
1909 }
1910
1911 IOReturn IOPMrootDomain::recordPMEventGated(PMEventDetails *record)
1912 {
1913 // If we don't have a place to log to, we can't actually
1914 // log anything. Chances are, the person who is asking us to do
1915 // the PM logging has forgotten to set the right bootflags
1916 if(!timeline)
1917 return kIOReturnSuccess;
1918
1919 if(gIOPMWorkLoop->inGate() == false) {
1920
1921 IOReturn ret = gIOPMWorkLoop->runAction(
1922 OSMemberFunctionCast(IOWorkLoop::Action, this, &IOPMrootDomain::recordPMEventGated),
1923 (OSObject *)this,
1924 (void *)record);
1925
1926 return ret;
1927 }
1928 else {
1929 // Now that we're guaranteed to be running in gate ...
1930
1931 // Check the validity of the argument we are given
1932 if(!record)
1933 return kIOReturnBadArgument;
1934
1935 // Record a driver event, or a system event
1936 if(record->eventClassifier == kIOPMEventClassDriverEvent
1937 || record->eventClassifier == kIOPMEventClassSystemEvent)
1938 return this->recordPMEvent(record);
1939
1940 else
1941 return kIOReturnBadArgument;
1942 }
1943 }
1944
1945 IOReturn IOPMrootDomain::recordAndReleasePMEventGated(PMEventDetails *record)
1946 {
1947 IOReturn ret = kIOReturnBadArgument;
1948
1949 if (record)
1950 {
1951 ret = recordPMEventGated(record);
1952 record->release();
1953 }
1954
1955 return ret;
1956 }
1957
1958 //******************************************************************************
1959 // powerChangeDone
1960 //
1961 // This overrides powerChangeDone in IOService.
1962 //******************************************************************************
1963
1964 void IOPMrootDomain::powerChangeDone( unsigned long previousPowerState )
1965 {
1966 PMEventDetails *details;
1967
1968 ASSERT_GATED();
1969 DLOG("PowerChangeDone: %u->%u\n",
1970 (uint32_t) previousPowerState, (uint32_t) getPowerState());
1971
1972 switch ( getPowerState() )
1973 {
1974 case SLEEP_STATE: {
1975 if (previousPowerState != ON_STATE)
1976 break;
1977
1978 details = PMEventDetails::eventDetails(
1979 kIOPMEventTypeSleepDone,
1980 NULL,
1981 NULL,
1982 kIOReturnSuccess);
1983
1984 recordAndReleasePMEvent( details );
1985
1986 // re-enable this timer for next sleep
1987 cancelIdleSleepTimer();
1988
1989 clock_sec_t secs;
1990 clock_usec_t microsecs;
1991 clock_get_calendar_microtime(&secs, &microsecs);
1992 logtime(secs);
1993 gIOLastSleepTime.tv_sec = secs;
1994 gIOLastSleepTime.tv_usec = microsecs;
1995 gIOLastWakeTime.tv_sec = 0;
1996 gIOLastWakeTime.tv_usec = 0;
1997
1998 #if HIBERNATION
1999 LOG("System %sSleep\n", gIOHibernateState ? "Safe" : "");
2000
2001 IOHibernateSystemHasSlept();
2002
2003 evaluateSystemSleepPolicyFinal();
2004 #else
2005 LOG("System Sleep\n");
2006 #endif
2007
2008 getPlatform()->sleepKernel();
2009
2010 // The CPU(s) are off at this point,
2011 // Code will resume execution here upon wake.
2012
2013 clock_get_uptime(&systemWakeTime);
2014
2015 #if HIBERNATION
2016 IOHibernateSystemWake();
2017 #endif
2018
2019 // sleep transition complete
2020 gSleepOrShutdownPending = 0;
2021
2022 // trip the reset of the calendar clock
2023 clock_wakeup_calendar();
2024
2025 #if HIBERNATION
2026 LOG("System %sWake\n", gIOHibernateState ? "SafeSleep " : "");
2027 #endif
2028
2029 // log system wake
2030 getPlatform()->PMLog(kIOPMrootDomainClass, kPMLogSystemWake, 0, 0);
2031 lowBatteryCondition = false;
2032 lastSleepReason = 0;
2033
2034 // And start logging the wake event here
2035 // TODO: Publish the wakeReason string as an integer
2036 details = PMEventDetails::eventDetails(
2037 kIOPMEventTypeWake,
2038 NULL,
2039 0,
2040 kIOReturnSuccess);
2041
2042 recordAndReleasePMEvent( details );
2043
2044
2045 #ifndef __LP64__
2046 systemWake();
2047 #endif
2048
2049 #if defined(__i386__) || defined(__x86_64__)
2050 wranglerTickled = false;
2051 graphicsSuppressed = false;
2052 darkWakePostTickle = false;
2053 logGraphicsClamp = true;
2054 logWranglerTickle = true;
2055 sleepTimerMaintenance = false;
2056
2057 OSString * wakeType = OSDynamicCast(
2058 OSString, getProperty(kIOPMRootDomainWakeTypeKey));
2059 OSString * wakeReason = OSDynamicCast(
2060 OSString, getProperty(kIOPMRootDomainWakeReasonKey));
2061
2062 if (wakeType && wakeType->isEqualTo(kIOPMrootDomainWakeTypeLowBattery))
2063 {
2064 lowBatteryCondition = true;
2065 darkWakeMaintenance = true;
2066 darkWakeToSleepASAP = true;
2067 }
2068 else if ((gDarkWakeFlags & kDarkWakeFlagHIDTickleMask) != 0)
2069 {
2070 OSNumber * hibOptions = OSDynamicCast(
2071 OSNumber, getProperty(kIOHibernateOptionsKey));
2072
2073 if (hibernateAborted ||
2074 ((hibOptions &&
2075 !(hibOptions->unsigned32BitValue() & kIOHibernateOptionDarkWake))) ||
2076 ((_debugWakeSeconds != 0) &&
2077 ((gDarkWakeFlags & kDarkWakeFlagAlarmIsDark) == 0)) ||
2078 (wakeType && (
2079 wakeType->isEqualTo(kIOPMRootDomainWakeTypeUser) ||
2080 wakeType->isEqualTo(kIOPMRootDomainWakeTypeAlarm))))
2081 {
2082 wranglerTickled = true;
2083 }
2084 else
2085 if (wakeType &&
2086 wakeType->isEqualTo(kIOPMRootDomainWakeTypeMaintenance))
2087 {
2088 darkWakeMaintenance = true;
2089 darkWakeToSleepASAP = true;
2090 }
2091 else
2092 if (wakeType &&
2093 wakeType->isEqualTo(kIOPMRootDomainWakeTypeSleepTimer))
2094 {
2095 darkWakeMaintenance = true;
2096 darkWakeToSleepASAP = true;
2097 sleepTimerMaintenance = true;
2098 }
2099 else
2100 {
2101 // Unidentified wake source, resume to full wake if debug
2102 // alarm is pending.
2103
2104 if (_debugWakeSeconds && (!wakeReason || wakeReason->isEqualTo("")))
2105 wranglerTickled = true;
2106 else
2107 darkWakeToSleepASAP = true;
2108 }
2109 }
2110 else
2111 {
2112 // Post a HID tickle immediately - except for maintenance wake.
2113
2114 if (hibernateAborted || !wakeType ||
2115 !wakeType->isEqualTo(kIOPMRootDomainWakeTypeMaintenance))
2116 {
2117 wranglerTickled = true;
2118 }
2119 else
2120 {
2121 darkWakeMaintenance = true;
2122 darkWakeToSleepASAP = true;
2123 }
2124 }
2125
2126 if (wranglerTickled)
2127 reportUserInput();
2128 else if (!darkWakeMaintenance)
2129 {
2130 // Early/late tickle for non-maintenance wake.
2131 if (((gDarkWakeFlags & kDarkWakeFlagHIDTickleMask) ==
2132 kDarkWakeFlagHIDTickleEarly) ||
2133 ((gDarkWakeFlags & kDarkWakeFlagHIDTickleMask) ==
2134 kDarkWakeFlagHIDTickleLate))
2135 {
2136 darkWakePostTickle = true;
2137 }
2138 }
2139 #else /* !__i386__ && !__x86_64__ */
2140 // stay awake for at least 30 seconds
2141 wranglerTickled = true;
2142 startIdleSleepTimer(30);
2143 #endif
2144
2145 changePowerStateToPriv(ON_STATE);
2146 } break;
2147
2148 case ON_STATE: {
2149 bool wasPrevented = childPreventSystemSleep;
2150
2151 details = PMEventDetails::eventDetails(
2152 kIOPMEventTypeWakeDone,
2153 NULL,
2154 0,
2155 kIOReturnSuccess);
2156
2157 recordAndReleasePMEvent( details );
2158
2159 if (previousPowerState != ON_STATE)
2160 _debugWakeSeconds = 0;
2161
2162 // Update childPreventSystemSleep flag using the capability computed
2163 // by IOSevice::rebuildChildClampBits().
2164
2165 childPreventSystemSleep =
2166 ((currentCapability() & kIOPMChildClamp2) != 0);
2167
2168 if (wasPrevented && !childPreventSystemSleep)
2169 {
2170 evaluatePolicy( kStimulusDarkWakeEvaluate );
2171 }
2172 } break;
2173 }
2174 }
2175
2176 //******************************************************************************
2177 // requestPowerDomainState
2178 //
2179 // Extend implementation in IOService. Running on PM work loop thread.
2180 //
2181 // Examine children desires and initiate idle-sleep if all children are idle,
2182 // prevent idle and system sleep flags are not set.
2183 //******************************************************************************
2184
2185 IOReturn IOPMrootDomain::requestPowerDomainState (
2186 IOPMPowerFlags childDesire,
2187 IOPowerConnection * childConnection,
2188 unsigned long specification )
2189 {
2190 OSIterator *iter;
2191 OSObject *next;
2192 IOPowerConnection *connection;
2193 IOPMPowerFlags mergedChildDesire = 0;
2194 IOPMPowerFlags editedChildDesire;
2195 IOPMPowerFlags thisDesire;
2196 bool sleepASAP = false;
2197
2198 ASSERT_GATED();
2199
2200 // Disregard disk I/O (anything besides the display wrangler) as a
2201 // factor in preventing idle sleep - based on a runtime setting.
2202
2203 if ((gDarkWakeFlags & kDarkWakeFlagIgnoreDiskIOAlways) &&
2204 (kIOPMPreventIdleSleep & childDesire) &&
2205 (childConnection != wranglerConnection))
2206 {
2207 childDesire &= ~kIOPMPreventIdleSleep;
2208 }
2209
2210 // Force the child's input power requirement to 0 unless the prevent
2211 // idle-sleep flag is set. Nil input power flags maps to our state 0.
2212 // Our power clamp (deviceDesire) clamps the lowest power state at 2.
2213
2214 editedChildDesire = 0;
2215 if (childDesire & kIOPMPreventIdleSleep)
2216 editedChildDesire |= (kIOPMPowerOn | kIOPMPreventIdleSleep);
2217 if (childDesire & kIOPMPreventSystemSleep)
2218 editedChildDesire |= (kIOPMPowerOn | kIOPMPreventSystemSleep);
2219
2220 iter = getChildIterator(gIOPowerPlane);
2221 if ( iter )
2222 {
2223 while ( (next = iter->getNextObject()) )
2224 {
2225 if ( (connection = OSDynamicCast(IOPowerConnection, next)) )
2226 {
2227 // Ignore child that are in the process of joining.
2228 if (connection->getReadyFlag() == false)
2229 continue;
2230
2231 // OR in the child's input power requirements.
2232 // Is this connection attached to the child that called
2233 // requestPowerDomainState()?
2234
2235 if (connection == childConnection)
2236 {
2237 thisDesire = editedChildDesire;
2238 }
2239 else
2240 {
2241 thisDesire = 0;
2242 if (connection->getPreventIdleSleepFlag())
2243 thisDesire |= (kIOPMPowerOn | kIOPMPreventIdleSleep);
2244 if (connection->getPreventSystemSleepFlag())
2245 thisDesire |= (kIOPMPowerOn | kIOPMPreventSystemSleep);
2246 }
2247
2248 mergedChildDesire |= thisDesire;
2249 if (thisDesire && (kIOLogPMRootDomain & gIOKitDebug))
2250 {
2251 IOService * child =
2252 (IOService *) connection->getChildEntry(gIOPowerPlane);
2253 LOG("child %p, noIdle %d, noSleep %d - %s\n",
2254 child,
2255 ((thisDesire & kIOPMPreventIdleSleep) != 0),
2256 ((thisDesire & kIOPMPreventSystemSleep) != 0),
2257 child ? child->getName() : "?");
2258 }
2259 }
2260 }
2261 iter->release();
2262 }
2263
2264 DLOG("mergedChildDesire 0x%lx, extraSleepDelay %ld\n",
2265 mergedChildDesire, extraSleepDelay);
2266
2267 if ( !mergedChildDesire && !systemBooting )
2268 {
2269 if (!wrangler)
2270 {
2271 changePowerStateToPriv(ON_STATE);
2272 if (idleSeconds)
2273 {
2274 // stay awake for at least idleSeconds
2275 startIdleSleepTimer(idleSeconds);
2276 }
2277 }
2278 else if (!extraSleepDelay && !idleSleepTimerPending && !systemDarkWake)
2279 {
2280 sleepASAP = true;
2281 }
2282 }
2283
2284 // Drop our power clamp to SLEEP_STATE when all children became idle,
2285 // and system sleep and display sleep slider values are equal.
2286
2287 adjustPowerState(sleepASAP);
2288
2289 // If our power clamp has already dropped to SLEEP_STATE, and no child
2290 // is keeping us at ON_STATE, then the following will trigger idle sleep.
2291
2292 return super::requestPowerDomainState(
2293 editedChildDesire, childConnection, specification);
2294 }
2295
2296 //******************************************************************************
2297 // tellChangeDown
2298 //
2299 // Override the superclass implementation to send a different message type.
2300 //******************************************************************************
2301
2302 bool IOPMrootDomain::tellChangeDown( unsigned long stateNum )
2303 {
2304 DLOG("tellChangeDown %u->%u\n",
2305 (uint32_t) getPowerState(), (uint32_t) stateNum);
2306
2307 if (SLEEP_STATE == stateNum)
2308 {
2309 if (!ignoreTellChangeDown)
2310 tracePoint( kIOPMTracePointSleepApplications );
2311 else
2312 tracePoint( kIOPMTracePointSleepPriorityClients );
2313 }
2314
2315 if ((SLEEP_STATE == stateNum) && !ignoreTellChangeDown)
2316 {
2317 userActivityAtSleep = userActivityCount;
2318 hibernateAborted = false;
2319 DLOG("tellChangeDown::userActivityAtSleep %d\n", userActivityAtSleep);
2320
2321 // Direct callout into OSKext so it can disable kext unloads
2322 // during sleep/wake to prevent deadlocks.
2323 OSKextSystemSleepOrWake( kIOMessageSystemWillSleep );
2324
2325 IOService::updateConsoleUsers(NULL, kIOMessageSystemWillSleep);
2326
2327 // Notify platform that sleep has begun
2328 getPlatform()->callPlatformFunction(
2329 sleepMessagePEFunction, false,
2330 (void *)(uintptr_t) kIOMessageSystemWillSleep,
2331 NULL, NULL, NULL);
2332
2333 // Two change downs are sent by IOServicePM. Ignore the 2nd.
2334 // But tellClientsWithResponse() must be called for both.
2335 ignoreTellChangeDown = true;
2336 }
2337
2338 return super::tellClientsWithResponse( kIOMessageSystemWillSleep );
2339 }
2340
2341 //******************************************************************************
2342 // askChangeDown
2343 //
2344 // Override the superclass implementation to send a different message type.
2345 // This must be idle sleep since we don't ask during any other power change.
2346 //******************************************************************************
2347
2348 bool IOPMrootDomain::askChangeDown( unsigned long stateNum )
2349 {
2350 DLOG("askChangeDown %u->%u\n",
2351 (uint32_t) getPowerState(), (uint32_t) stateNum);
2352
2353 // Don't log for dark wake entry
2354 if (kSystemTransitionSleep == _systemTransitionType)
2355 tracePoint( kIOPMTracePointSleepApplications );
2356
2357 return super::tellClientsWithResponse( kIOMessageCanSystemSleep );
2358 }
2359
2360 //******************************************************************************
2361 // askChangeDownDone
2362 //
2363 // Called by PM after all apps have responded to kIOMessageCanSystemSleep.
2364 // pmconfigd may create a deny sleep assertion before ack'ing.
2365 //******************************************************************************
2366
2367 void IOPMrootDomain::askChangeDownDone(
2368 IOPMPowerChangeFlags * inOutChangeFlags, bool * cancel )
2369 {
2370 DLOG("askChangeDownDone(0x%x, %u) type %x, cap %x->%x\n",
2371 *inOutChangeFlags, *cancel,
2372 _systemTransitionType,
2373 _currentCapability, _pendingCapability);
2374
2375 if ((false == *cancel) && (kSystemTransitionSleep == _systemTransitionType))
2376 {
2377 // Dark->Sleep transition.
2378 // Check if there are any deny sleep assertions.
2379 // Full->Dark transition is never cancelled.
2380
2381 if (!checkSystemCanSleep(true))
2382 {
2383 // Cancel dark wake to sleep transition.
2384 // Must re-scan assertions upon entering dark wake.
2385
2386 *cancel = true;
2387 DLOG("cancel dark->sleep\n");
2388 }
2389 }
2390 }
2391
2392 //******************************************************************************
2393 // tellNoChangeDown
2394 //
2395 // Notify registered applications and kernel clients that we are not dropping
2396 // power.
2397 //
2398 // We override the superclass implementation so we can send a different message
2399 // type to the client or application being notified.
2400 //
2401 // This must be a vetoed idle sleep, since no other power change can be vetoed.
2402 //******************************************************************************
2403
2404 void IOPMrootDomain::tellNoChangeDown( unsigned long stateNum )
2405 {
2406 DLOG("tellNoChangeDown %u->%u\n",
2407 (uint32_t) getPowerState(), (uint32_t) stateNum);
2408
2409 if (idleSeconds && !wrangler)
2410 {
2411 // stay awake for at least idleSeconds
2412 startIdleSleepTimer(idleSeconds);
2413 }
2414 return tellClients( kIOMessageSystemWillNotSleep );
2415 }
2416
2417 //******************************************************************************
2418 // tellChangeUp
2419 //
2420 // Notify registered applications and kernel clients that we are raising power.
2421 //
2422 // We override the superclass implementation so we can send a different message
2423 // type to the client or application being notified.
2424 //******************************************************************************
2425
2426 void IOPMrootDomain::tellChangeUp( unsigned long stateNum )
2427 {
2428 OSData *publishPMStats = NULL;
2429
2430 DLOG("tellChangeUp %u->%u\n",
2431 (uint32_t) getPowerState(), (uint32_t) stateNum);
2432
2433 ignoreTellChangeDown = false;
2434
2435 if ( stateNum == ON_STATE )
2436 {
2437 // Direct callout into OSKext so it can disable kext unloads
2438 // during sleep/wake to prevent deadlocks.
2439 OSKextSystemSleepOrWake( kIOMessageSystemHasPoweredOn );
2440
2441 // Notify platform that sleep was cancelled or resumed.
2442 getPlatform()->callPlatformFunction(
2443 sleepMessagePEFunction, false,
2444 (void *)(uintptr_t) kIOMessageSystemHasPoweredOn,
2445 NULL, NULL, NULL);
2446
2447 if (getPowerState() == ON_STATE)
2448 {
2449 // this is a quick wake from aborted sleep
2450 if (idleSeconds && !wrangler)
2451 {
2452 // stay awake for at least idleSeconds
2453 startIdleSleepTimer(idleSeconds);
2454 }
2455 tellClients( kIOMessageSystemWillPowerOn );
2456 }
2457
2458 tracePoint( kIOPMTracePointWakeApplications );
2459 publishPMStats = OSData::withBytes(&pmStats, sizeof(pmStats));
2460 setProperty(kIOPMSleepStatisticsKey, publishPMStats);
2461 publishPMStats->release();
2462 bzero(&pmStats, sizeof(pmStats));
2463
2464 if (pmStatsAppResponses)
2465 {
2466 setProperty(kIOPMSleepStatisticsAppsKey, pmStatsAppResponses);
2467 pmStatsAppResponses->release();
2468 pmStatsAppResponses = OSArray::withCapacity(5);
2469 }
2470
2471 tellClients( kIOMessageSystemHasPoweredOn );
2472 }
2473 }
2474
2475 //******************************************************************************
2476 // sysPowerDownHandler
2477 //
2478 // Perform a vfs sync before system sleep.
2479 //******************************************************************************
2480
2481 IOReturn IOPMrootDomain::sysPowerDownHandler(
2482 void * target, void * refCon,
2483 UInt32 messageType, IOService * service,
2484 void * messageArgs, vm_size_t argSize )
2485 {
2486 IOReturn ret;
2487
2488 DLOG("sysPowerDownHandler message %s\n", getIOMessageString(messageType));
2489
2490 if (!gRootDomain)
2491 return kIOReturnUnsupported;
2492
2493 if (messageType == kIOMessageSystemCapabilityChange)
2494 {
2495 IOPMSystemCapabilityChangeParameters * params =
2496 (IOPMSystemCapabilityChangeParameters *) messageArgs;
2497
2498 // Interested applications have been notified of an impending power
2499 // change and have acked (when applicable).
2500 // This is our chance to save whatever state we can before powering
2501 // down.
2502 // We call sync_internal defined in xnu/bsd/vfs/vfs_syscalls.c,
2503 // via callout
2504
2505 DLOG("sysPowerDownHandler cap %x -> %x (flags %x)\n",
2506 params->fromCapabilities, params->toCapabilities,
2507 params->changeFlags);
2508
2509 if ((params->changeFlags & kIOPMSystemCapabilityWillChange) &&
2510 (params->fromCapabilities & kIOPMSystemCapabilityCPU) &&
2511 (params->toCapabilities & kIOPMSystemCapabilityCPU) == 0)
2512 {
2513 // We will ack within 20 seconds
2514 params->maxWaitForReply = 20 * 1000 * 1000;
2515 #if HIBERNATION
2516 gRootDomain->evaluateSystemSleepPolicyEarly();
2517
2518 // add in time we could spend freeing pages
2519 if (gRootDomain->hibernateMode && !gRootDomain->hibernateDisabled)
2520 {
2521 params->maxWaitForReply = kCapabilityClientMaxWait;
2522 }
2523 DLOG("sysPowerDownHandler timeout %d s\n", (int) (params->maxWaitForReply / 1000 / 1000));
2524 #endif
2525
2526 if ( !OSCompareAndSwap( 0, 1, &gSleepOrShutdownPending ) )
2527 {
2528 // Purposely delay the ack and hope that shutdown occurs quickly.
2529 // Another option is not to schedule the thread and wait for
2530 // ack timeout...
2531 AbsoluteTime deadline;
2532 clock_interval_to_deadline( 30, kSecondScale, &deadline );
2533 thread_call_enter1_delayed(
2534 gRootDomain->diskSyncCalloutEntry,
2535 (thread_call_param_t) params->notifyRef,
2536 deadline );
2537 }
2538 else
2539 thread_call_enter1(
2540 gRootDomain->diskSyncCalloutEntry,
2541 (thread_call_param_t) params->notifyRef);
2542 }
2543 #if HIBERNATION
2544 else
2545 if ((params->changeFlags & kIOPMSystemCapabilityDidChange) &&
2546 (params->toCapabilities & kIOPMSystemCapabilityCPU) &&
2547 (params->fromCapabilities & kIOPMSystemCapabilityCPU) == 0)
2548 {
2549 // We will ack within 110 seconds
2550 params->maxWaitForReply = 110 * 1000 * 1000;
2551
2552 thread_call_enter1(
2553 gRootDomain->diskSyncCalloutEntry,
2554 (thread_call_param_t) params->notifyRef);
2555 }
2556 #endif
2557 ret = kIOReturnSuccess;
2558 }
2559
2560 return ret;
2561 }
2562
2563 //******************************************************************************
2564 // handleQueueSleepWakeUUID
2565 //
2566 // Called from IOPMrootDomain when we're initiating a sleep,
2567 // or indirectly from PM configd when PM decides to clear the UUID.
2568 // PM clears the UUID several minutes after successful wake from sleep,
2569 // so that we might associate App spindumps with the immediately previous
2570 // sleep/wake.
2571 //
2572 // @param obj has a retain on it. We're responsible for releasing that retain.
2573 //******************************************************************************
2574
2575 void IOPMrootDomain::handleQueueSleepWakeUUID(OSObject *obj)
2576 {
2577 OSString *str = NULL;
2578
2579 if (kOSBooleanFalse == obj)
2580 {
2581 handlePublishSleepWakeUUID(NULL);
2582 }
2583 else if ((str = OSDynamicCast(OSString, obj)))
2584 {
2585 // This branch caches the UUID for an upcoming sleep/wake
2586 if (queuedSleepWakeUUIDString) {
2587 queuedSleepWakeUUIDString->release();
2588 queuedSleepWakeUUIDString = NULL;
2589 }
2590 queuedSleepWakeUUIDString = str;
2591 queuedSleepWakeUUIDString->retain();
2592
2593 DLOG("SleepWake UUID queued: %s\n", queuedSleepWakeUUIDString->getCStringNoCopy());
2594 }
2595
2596 if (obj) {
2597 obj->release();
2598 }
2599 return;
2600
2601 }
2602 //******************************************************************************
2603 // handlePublishSleepWakeUUID
2604 //
2605 // Called from IOPMrootDomain when we're initiating a sleep,
2606 // or indirectly from PM configd when PM decides to clear the UUID.
2607 // PM clears the UUID several minutes after successful wake from sleep,
2608 // so that we might associate App spindumps with the immediately previous
2609 // sleep/wake.
2610 //******************************************************************************
2611
2612 void IOPMrootDomain::handlePublishSleepWakeUUID( bool shouldPublish )
2613 {
2614 ASSERT_GATED();
2615
2616 /*
2617 * Clear the current UUID
2618 */
2619 if (gSleepWakeUUIDIsSet)
2620 {
2621 DLOG("SleepWake UUID cleared\n");
2622
2623 OSString *UUIDstring = NULL;
2624
2625 if (timeline &&
2626 (UUIDstring = OSDynamicCast(OSString, getProperty(kIOPMSleepWakeUUIDKey))))
2627 {
2628 PMEventDetails *details = PMEventDetails::eventDetails(kIOPMEventTypeUUIDClear,
2629 UUIDstring->getCStringNoCopy(), NULL, 0);
2630 if (details) {
2631 timeline->recordSystemPowerEvent( details );
2632 details->release();
2633 }
2634 timeline->setNumEventsLoggedThisPeriod(0);
2635 }
2636
2637 gSleepWakeUUIDIsSet = false;
2638
2639 removeProperty(kIOPMSleepWakeUUIDKey);
2640 messageClients(kIOPMMessageSleepWakeUUIDChange, kIOPMMessageSleepWakeUUIDCleared);
2641 }
2642
2643 /*
2644 * Optionally, publish a new UUID
2645 */
2646 if (queuedSleepWakeUUIDString && shouldPublish) {
2647
2648 OSString *publishThisUUID = NULL;
2649
2650 publishThisUUID = queuedSleepWakeUUIDString;
2651 publishThisUUID->retain();
2652
2653 if (timeline) {
2654 PMEventDetails *details;
2655 details = PMEventDetails::eventDetails(kIOPMEventTypeUUIDSet,
2656 publishThisUUID->getCStringNoCopy(), NULL, 0);
2657 if (details) {
2658 timeline->recordSystemPowerEvent( details );
2659 details->release();
2660 }
2661 }
2662
2663 if (publishThisUUID)
2664 {
2665 setProperty(kIOPMSleepWakeUUIDKey, publishThisUUID);
2666 publishThisUUID->release();
2667 }
2668
2669 gSleepWakeUUIDIsSet = true;
2670 messageClients(kIOPMMessageSleepWakeUUIDChange, kIOPMMessageSleepWakeUUIDSet);
2671
2672 queuedSleepWakeUUIDString->release();
2673 queuedSleepWakeUUIDString = NULL;
2674 }
2675 }
2676
2677 //******************************************************************************
2678 // changePowerStateTo & changePowerStateToPriv
2679 //
2680 // Override of these methods for logging purposes.
2681 //******************************************************************************
2682
2683 IOReturn IOPMrootDomain::changePowerStateTo( unsigned long ordinal )
2684 {
2685 return kIOReturnUnsupported; // ignored
2686 }
2687
2688 IOReturn IOPMrootDomain::changePowerStateToPriv( unsigned long ordinal )
2689 {
2690 DLOG("changePowerStateToPriv(%lu)\n", ordinal);
2691
2692 if ((ordinal != ON_STATE) && (ordinal != SLEEP_STATE))
2693 return kIOReturnUnsupported;
2694
2695 return super::changePowerStateToPriv(ordinal);
2696 }
2697
2698 //******************************************************************************
2699 // activity detect
2700 //
2701 //******************************************************************************
2702
2703 bool IOPMrootDomain::activitySinceSleep(void)
2704 {
2705 return (userActivityCount != userActivityAtSleep);
2706 }
2707
2708 bool IOPMrootDomain::abortHibernation(void)
2709 {
2710 bool ret = activitySinceSleep();
2711
2712 if (ret && !hibernateAborted)
2713 {
2714 DLOG("activitySinceSleep ABORT [%d, %d]\n", userActivityCount, userActivityAtSleep);
2715 hibernateAborted = true;
2716 }
2717 return (ret);
2718 }
2719
2720 extern "C" int
2721 hibernate_should_abort(void)
2722 {
2723 if (gRootDomain)
2724 return (gRootDomain->abortHibernation());
2725 else
2726 return (0);
2727 }
2728
2729 //******************************************************************************
2730 // sleepOnClamshellClosed
2731 //
2732 // contains the logic to determine if the system should sleep when the clamshell
2733 // is closed.
2734 //******************************************************************************
2735
2736 bool IOPMrootDomain::shouldSleepOnClamshellClosed( void )
2737 {
2738 if (!clamshellExists)
2739 return false;
2740
2741 DLOG("clamshell closed %d, disabled %d, desktopMode %d, ac %d\n",
2742 clamshellClosed, clamshellDisabled, desktopMode, acAdaptorConnected);
2743
2744 return ( !clamshellDisabled && !(desktopMode && acAdaptorConnected) );
2745 }
2746
2747 void IOPMrootDomain::sendClientClamshellNotification( void )
2748 {
2749 /* Only broadcast clamshell alert if clamshell exists. */
2750 if (!clamshellExists)
2751 return;
2752
2753 setProperty(kAppleClamshellStateKey,
2754 clamshellClosed ? kOSBooleanTrue : kOSBooleanFalse);
2755
2756 setProperty(kAppleClamshellCausesSleepKey,
2757 shouldSleepOnClamshellClosed() ? kOSBooleanTrue : kOSBooleanFalse);
2758
2759 /* Argument to message is a bitfiel of
2760 * ( kClamshellStateBit | kClamshellSleepBit )
2761 */
2762 messageClients(kIOPMMessageClamshellStateChange,
2763 (void *) ( (clamshellClosed ? kClamshellStateBit : 0)
2764 | ( shouldSleepOnClamshellClosed() ? kClamshellSleepBit : 0)) );
2765 }
2766
2767 //******************************************************************************
2768 // getSleepSupported
2769 //
2770 // Deprecated
2771 //******************************************************************************
2772
2773 IOOptionBits IOPMrootDomain::getSleepSupported( void )
2774 {
2775 return( platformSleepSupport );
2776 }
2777
2778 //******************************************************************************
2779 // setSleepSupported
2780 //
2781 // Deprecated
2782 //******************************************************************************
2783
2784 void IOPMrootDomain::setSleepSupported( IOOptionBits flags )
2785 {
2786 DLOG("setSleepSupported(%x)\n", (uint32_t) flags);
2787 OSBitOrAtomic(flags, &platformSleepSupport);
2788 }
2789
2790 //******************************************************************************
2791 // wakeFromDoze
2792 //
2793 // Deprecated.
2794 //******************************************************************************
2795
2796 void IOPMrootDomain::wakeFromDoze( void )
2797 {
2798 // Preserve symbol for familes (IOUSBFamily and IOGraphics)
2799 }
2800
2801 // MARK: -
2802 // MARK: Features
2803
2804 //******************************************************************************
2805 // publishFeature
2806 //
2807 // Adds a new feature to the supported features dictionary
2808 //******************************************************************************
2809
2810 void IOPMrootDomain::publishFeature( const char * feature )
2811 {
2812 publishFeature(feature, kRD_AllPowerSources, NULL);
2813 }
2814
2815 //******************************************************************************
2816 // publishFeature (with supported power source specified)
2817 //
2818 // Adds a new feature to the supported features dictionary
2819 //******************************************************************************
2820
2821 void IOPMrootDomain::publishFeature(
2822 const char *feature,
2823 uint32_t supportedWhere,
2824 uint32_t *uniqueFeatureID)
2825 {
2826 static uint16_t next_feature_id = 500;
2827
2828 OSNumber *new_feature_data = NULL;
2829 OSNumber *existing_feature = NULL;
2830 OSArray *existing_feature_arr = NULL;
2831 OSObject *osObj = NULL;
2832 uint32_t feature_value = 0;
2833
2834 supportedWhere &= kRD_AllPowerSources; // mask off any craziness!
2835
2836 if(!supportedWhere) {
2837 // Feature isn't supported anywhere!
2838 return;
2839 }
2840
2841 if(next_feature_id > 5000) {
2842 // Far, far too many features!
2843 return;
2844 }
2845
2846 if(featuresDictLock) IOLockLock(featuresDictLock);
2847
2848 OSDictionary *features =
2849 (OSDictionary *) getProperty(kRootDomainSupportedFeatures);
2850
2851 // Create new features dict if necessary
2852 if ( features && OSDynamicCast(OSDictionary, features)) {
2853 features = OSDictionary::withDictionary(features);
2854 } else {
2855 features = OSDictionary::withCapacity(1);
2856 }
2857
2858 // Create OSNumber to track new feature
2859
2860 next_feature_id += 1;
2861 if( uniqueFeatureID ) {
2862 // We don't really mind if the calling kext didn't give us a place
2863 // to stash their unique id. Many kexts don't plan to unload, and thus
2864 // have no need to remove themselves later.
2865 *uniqueFeatureID = next_feature_id;
2866 }
2867
2868 feature_value = (uint32_t)next_feature_id;
2869 feature_value <<= 16;
2870 feature_value += supportedWhere;
2871
2872 new_feature_data = OSNumber::withNumber(
2873 (unsigned long long)feature_value, 32);
2874
2875 // Does features object already exist?
2876 if( (osObj = features->getObject(feature)) )
2877 {
2878 if(( existing_feature = OSDynamicCast(OSNumber, osObj) ))
2879 {
2880 // We need to create an OSArray to hold the now 2 elements.
2881 existing_feature_arr = OSArray::withObjects(
2882 (const OSObject **)&existing_feature, 1, 2);
2883 } else if(( existing_feature_arr = OSDynamicCast(OSArray, osObj) ))
2884 {
2885 // Add object to existing array
2886 existing_feature_arr = OSArray::withArray(
2887 existing_feature_arr,
2888 existing_feature_arr->getCount() + 1);
2889 }
2890
2891 if (existing_feature_arr)
2892 {
2893 existing_feature_arr->setObject(new_feature_data);
2894 features->setObject(feature, existing_feature_arr);
2895 existing_feature_arr->release();
2896 existing_feature_arr = 0;
2897 }
2898 } else {
2899 // The easy case: no previously existing features listed. We simply
2900 // set the OSNumber at key 'feature' and we're on our way.
2901 features->setObject(feature, new_feature_data);
2902 }
2903
2904 new_feature_data->release();
2905
2906 setProperty(kRootDomainSupportedFeatures, features);
2907
2908 features->release();
2909
2910 if(featuresDictLock) IOLockUnlock(featuresDictLock);
2911
2912 // Notify EnergySaver and all those in user space so they might
2913 // re-populate their feature specific UI
2914 if(pmPowerStateQueue) {
2915 pmPowerStateQueue->submitPowerEvent( kPowerEventFeatureChanged );
2916 }
2917 }
2918
2919 //******************************************************************************
2920 // removePublishedFeature
2921 //
2922 // Removes previously published feature
2923 //******************************************************************************
2924
2925 IOReturn IOPMrootDomain::removePublishedFeature( uint32_t removeFeatureID )
2926 {
2927 IOReturn ret = kIOReturnError;
2928 uint32_t feature_value = 0;
2929 uint16_t feature_id = 0;
2930 bool madeAChange = false;
2931
2932 OSSymbol *dictKey = NULL;
2933 OSCollectionIterator *dictIterator = NULL;
2934 OSArray *arrayMember = NULL;
2935 OSNumber *numberMember = NULL;
2936 OSObject *osObj = NULL;
2937 OSNumber *osNum = NULL;
2938 OSArray *arrayMemberCopy;
2939
2940 if(featuresDictLock) IOLockLock(featuresDictLock);
2941
2942 OSDictionary *features =
2943 (OSDictionary *) getProperty(kRootDomainSupportedFeatures);
2944
2945 if ( features && OSDynamicCast(OSDictionary, features) )
2946 {
2947 // Any modifications to the dictionary are made to the copy to prevent
2948 // races & crashes with userland clients. Dictionary updated
2949 // automically later.
2950 features = OSDictionary::withDictionary(features);
2951 } else {
2952 features = NULL;
2953 ret = kIOReturnNotFound;
2954 goto exit;
2955 }
2956
2957 // We iterate 'features' dictionary looking for an entry tagged
2958 // with 'removeFeatureID'. If found, we remove it from our tracking
2959 // structures and notify the OS via a general interest message.
2960
2961 dictIterator = OSCollectionIterator::withCollection(features);
2962 if(!dictIterator) {
2963 goto exit;
2964 }
2965
2966 while( (dictKey = OSDynamicCast(OSSymbol, dictIterator->getNextObject())) )
2967 {
2968 osObj = features->getObject(dictKey);
2969
2970 // Each Feature is either tracked by an OSNumber
2971 if( osObj && (numberMember = OSDynamicCast(OSNumber, osObj)) )
2972 {
2973 feature_value = numberMember->unsigned32BitValue();
2974 feature_id = (uint16_t)(feature_value >> 16);
2975
2976 if( feature_id == (uint16_t)removeFeatureID )
2977 {
2978 // Remove this node
2979 features->removeObject(dictKey);
2980 madeAChange = true;
2981 break;
2982 }
2983
2984 // Or tracked by an OSArray of OSNumbers
2985 } else if( osObj && (arrayMember = OSDynamicCast(OSArray, osObj)) )
2986 {
2987 unsigned int arrayCount = arrayMember->getCount();
2988
2989 for(unsigned int i=0; i<arrayCount; i++)
2990 {
2991 osNum = OSDynamicCast(OSNumber, arrayMember->getObject(i));
2992 if(!osNum) {
2993 continue;
2994 }
2995
2996 feature_value = osNum->unsigned32BitValue();
2997 feature_id = (uint16_t)(feature_value >> 16);
2998
2999 if( feature_id == (uint16_t)removeFeatureID )
3000 {
3001 // Remove this node
3002 if( 1 == arrayCount ) {
3003 // If the array only contains one element, remove
3004 // the whole thing.
3005 features->removeObject(dictKey);
3006 } else {
3007 // Otherwise remove the element from a copy of the array.
3008 arrayMemberCopy = OSArray::withArray(arrayMember);
3009 if (arrayMemberCopy)
3010 {
3011 arrayMemberCopy->removeObject(i);
3012 features->setObject(dictKey, arrayMemberCopy);
3013 arrayMemberCopy->release();
3014 }
3015 }
3016
3017 madeAChange = true;
3018 break;
3019 }
3020 }
3021 }
3022 }
3023
3024 dictIterator->release();
3025
3026 if( madeAChange )
3027 {
3028 ret = kIOReturnSuccess;
3029
3030 setProperty(kRootDomainSupportedFeatures, features);
3031
3032 // Notify EnergySaver and all those in user space so they might
3033 // re-populate their feature specific UI
3034 if(pmPowerStateQueue) {
3035 pmPowerStateQueue->submitPowerEvent( kPowerEventFeatureChanged );
3036 }
3037 } else {
3038 ret = kIOReturnNotFound;
3039 }
3040
3041 exit:
3042 if(features) features->release();
3043 if(featuresDictLock) IOLockUnlock(featuresDictLock);
3044 return ret;
3045 }
3046
3047 //******************************************************************************
3048 // setPMSetting (private)
3049 //
3050 // Internal helper to relay PM settings changes from user space to individual
3051 // drivers. Should be called only by IOPMrootDomain::setProperties.
3052 //******************************************************************************
3053
3054 IOReturn IOPMrootDomain::setPMSetting(
3055 const OSSymbol *type,
3056 OSObject *object )
3057 {
3058 PMSettingCallEntry *entries = 0;
3059 OSArray *chosen = 0;
3060 const OSArray *array;
3061 PMSettingObject *pmso;
3062 thread_t thisThread;
3063 int i, j, count, capacity;
3064
3065 if (NULL == type)
3066 return kIOReturnBadArgument;
3067
3068 PMSETTING_LOCK();
3069
3070 // Update settings dict so changes are visible from copyPMSetting().
3071 fPMSettingsDict->setObject(type, object);
3072
3073 // Prep all PMSetting objects with the given 'type' for callout.
3074 array = (const OSArray *) settingsCallbacks->getObject(type);
3075 if (!array || ((capacity = array->getCount()) == 0))
3076 goto unlock_exit;
3077
3078 // Array to retain PMSetting objects targeted for callout.
3079 chosen = OSArray::withCapacity(capacity);
3080 if (!chosen)
3081 goto unlock_exit; // error
3082
3083 entries = IONew(PMSettingCallEntry, capacity);
3084 if (!entries)
3085 goto unlock_exit; // error
3086 memset(entries, 0, sizeof(PMSettingCallEntry) * capacity);
3087
3088 thisThread = current_thread();
3089
3090 for (i = 0, j = 0; i<capacity; i++)
3091 {
3092 pmso = (PMSettingObject *) array->getObject(i);
3093 if (pmso->disabled)
3094 continue;
3095 entries[j].thread = thisThread;
3096 queue_enter(&pmso->calloutQueue, &entries[j], PMSettingCallEntry *, link);
3097 chosen->setObject(pmso);
3098 j++;
3099 }
3100 count = j;
3101 if (!count)
3102 goto unlock_exit;
3103
3104 PMSETTING_UNLOCK();
3105
3106 // Call each pmso in the chosen array.
3107 for (i=0; i<count; i++)
3108 {
3109 pmso = (PMSettingObject *) chosen->getObject(i);
3110 pmso->dispatchPMSetting(type, object);
3111 }
3112
3113 PMSETTING_LOCK();
3114 for (i=0; i<count; i++)
3115 {
3116 pmso = (PMSettingObject *) chosen->getObject(i);
3117 queue_remove(&pmso->calloutQueue, &entries[i], PMSettingCallEntry *, link);
3118 if (pmso->waitThread)
3119 {
3120 PMSETTING_WAKEUP(pmso);
3121 }
3122 }
3123 unlock_exit:
3124 PMSETTING_UNLOCK();
3125
3126 if (chosen) chosen->release();
3127 if (entries) IODelete(entries, PMSettingCallEntry, capacity);
3128
3129 return kIOReturnSuccess;
3130 }
3131
3132 //******************************************************************************
3133 // copyPMSetting (public)
3134 //
3135 // Allows kexts to safely read setting values, without being subscribed to
3136 // notifications.
3137 //******************************************************************************
3138
3139 OSObject * IOPMrootDomain::copyPMSetting(
3140 OSSymbol *whichSetting)
3141 {
3142 OSObject *obj = NULL;
3143
3144 if(!whichSetting) return NULL;
3145
3146 PMSETTING_LOCK();
3147 obj = fPMSettingsDict->getObject(whichSetting);
3148 if(obj) {
3149 obj->retain();
3150 }
3151 PMSETTING_UNLOCK();
3152
3153 return obj;
3154 }
3155
3156 //******************************************************************************
3157 // registerPMSettingController (public)
3158 //
3159 // direct wrapper to registerPMSettingController with uint32_t power source arg
3160 //******************************************************************************
3161
3162 IOReturn IOPMrootDomain::registerPMSettingController(
3163 const OSSymbol * settings[],
3164 IOPMSettingControllerCallback func,
3165 OSObject *target,
3166 uintptr_t refcon,
3167 OSObject **handle)
3168 {
3169 return registerPMSettingController(
3170 settings,
3171 (kIOPMSupportedOnAC | kIOPMSupportedOnBatt | kIOPMSupportedOnUPS),
3172 func, target, refcon, handle);
3173 }
3174
3175 //******************************************************************************
3176 // registerPMSettingController (public)
3177 //
3178 // Kexts may register for notifications when a particular setting is changed.
3179 // A list of settings is available in IOPM.h.
3180 // Arguments:
3181 // * settings - An OSArray containing OSSymbols. Caller should populate this
3182 // array with a list of settings caller wants notifications from.
3183 // * func - A C function callback of the type IOPMSettingControllerCallback
3184 // * target - caller may provide an OSObject *, which PM will pass as an
3185 // target to calls to "func"
3186 // * refcon - caller may provide an void *, which PM will pass as an
3187 // argument to calls to "func"
3188 // * handle - This is a return argument. We will populate this pointer upon
3189 // call success. Hold onto this and pass this argument to
3190 // IOPMrootDomain::deRegisterPMSettingCallback when unloading your kext
3191 // Returns:
3192 // kIOReturnSuccess on success
3193 //******************************************************************************
3194
3195 IOReturn IOPMrootDomain::registerPMSettingController(
3196 const OSSymbol * settings[],
3197 uint32_t supportedPowerSources,
3198 IOPMSettingControllerCallback func,
3199 OSObject *target,
3200 uintptr_t refcon,
3201 OSObject **handle)
3202 {
3203 PMSettingObject *pmso = NULL;
3204 OSObject *pmsh = NULL;
3205 OSArray *list = NULL;
3206 int i;
3207
3208 if (NULL == settings ||
3209 NULL == func ||
3210 NULL == handle)
3211 {
3212 return kIOReturnBadArgument;
3213 }
3214
3215 pmso = PMSettingObject::pmSettingObject(
3216 (IOPMrootDomain *) this, func, target,
3217 refcon, supportedPowerSources, settings, &pmsh);
3218
3219 if (!pmso) {
3220 *handle = NULL;
3221 return kIOReturnInternalError;
3222 }
3223
3224 PMSETTING_LOCK();
3225 for (i=0; settings[i]; i++)
3226 {
3227 list = (OSArray *) settingsCallbacks->getObject(settings[i]);
3228 if (!list) {
3229 // New array of callbacks for this setting
3230 list = OSArray::withCapacity(1);
3231 settingsCallbacks->setObject(settings[i], list);
3232 list->release();
3233 }
3234
3235 // Add caller to the callback list
3236 list->setObject(pmso);
3237 }
3238 PMSETTING_UNLOCK();
3239
3240 // Return handle to the caller, the setting object is private.
3241 *handle = pmsh;
3242
3243 return kIOReturnSuccess;
3244 }
3245
3246 //******************************************************************************
3247 // deregisterPMSettingObject (private)
3248 //
3249 // Only called from PMSettingObject.
3250 //******************************************************************************
3251
3252 void IOPMrootDomain::deregisterPMSettingObject( PMSettingObject * pmso )
3253 {
3254 thread_t thisThread = current_thread();
3255 PMSettingCallEntry *callEntry;
3256 OSCollectionIterator *iter;
3257 OSSymbol *sym;
3258 OSArray *array;
3259 int index;
3260 bool wait;
3261
3262 PMSETTING_LOCK();
3263
3264 pmso->disabled = true;
3265
3266 // Wait for all callout threads to finish.
3267 do {
3268 wait = false;
3269 queue_iterate(&pmso->calloutQueue, callEntry, PMSettingCallEntry *, link)
3270 {
3271 if (callEntry->thread != thisThread)
3272 {
3273 wait = true;
3274 break;
3275 }
3276 }
3277 if (wait)
3278 {
3279 assert(0 == pmso->waitThread);
3280 pmso->waitThread = thisThread;
3281 PMSETTING_WAIT(pmso);
3282 pmso->waitThread = 0;
3283 }
3284 } while (wait);
3285
3286 // Search each PM settings array in the kernel.
3287 iter = OSCollectionIterator::withCollection(settingsCallbacks);
3288 if (iter)
3289 {
3290 while ((sym = OSDynamicCast(OSSymbol, iter->getNextObject())))
3291 {
3292 array = (OSArray *) settingsCallbacks->getObject(sym);
3293 index = array->getNextIndexOfObject(pmso, 0);
3294 if (-1 != index) {
3295 array->removeObject(index);
3296 }
3297 }
3298 iter->release();
3299 }
3300
3301 PMSETTING_UNLOCK();
3302
3303 pmso->release();
3304 }
3305
3306 //******************************************************************************
3307 // informCPUStateChange
3308 //
3309 // Call into PM CPU code so that CPU power savings may dynamically adjust for
3310 // running on battery, with the lid closed, etc.
3311 //
3312 // informCPUStateChange is a no-op on non x86 systems
3313 // only x86 has explicit support in the IntelCPUPowerManagement kext
3314 //******************************************************************************
3315
3316 void IOPMrootDomain::informCPUStateChange(
3317 uint32_t type,
3318 uint32_t value )
3319 {
3320 #if defined(__i386__) || defined(__x86_64__)
3321
3322 pmioctlVariableInfo_t varInfoStruct;
3323 int pmCPUret = 0;
3324 const char *varNameStr = NULL;
3325 int32_t *varIndex = NULL;
3326
3327 if (kInformAC == type) {
3328 varNameStr = kIOPMRootDomainBatPowerCString;
3329 varIndex = &idxPMCPULimitedPower;
3330 } else if (kInformLid == type) {
3331 varNameStr = kIOPMRootDomainLidCloseCString;
3332 varIndex = &idxPMCPUClamshell;
3333 } else {
3334 return;
3335 }
3336
3337 // Set the new value!
3338 // pmCPUControl will assign us a new ID if one doesn't exist yet
3339 bzero(&varInfoStruct, sizeof(pmioctlVariableInfo_t));
3340 varInfoStruct.varID = *varIndex;
3341 varInfoStruct.varType = vBool;
3342 varInfoStruct.varInitValue = value;
3343 varInfoStruct.varCurValue = value;
3344 strncpy( (char *)varInfoStruct.varName,
3345 (const char *)varNameStr,
3346 strlen(varNameStr) + 1 );
3347
3348 // Set!
3349 pmCPUret = pmCPUControl( PMIOCSETVARINFO, (void *)&varInfoStruct );
3350
3351 // pmCPU only assigns numerical id's when a new varName is specified
3352 if ((0 == pmCPUret)
3353 && (*varIndex == kCPUUnknownIndex))
3354 {
3355 // pmCPUControl has assigned us a new variable ID.
3356 // Let's re-read the structure we just SET to learn that ID.
3357 pmCPUret = pmCPUControl( PMIOCGETVARNAMEINFO, (void *)&varInfoStruct );
3358
3359 if (0 == pmCPUret)
3360 {
3361 // Store it in idxPMCPUClamshell or idxPMCPULimitedPower
3362 *varIndex = varInfoStruct.varID;
3363 }
3364 }
3365
3366 return;
3367
3368 #endif /* __i386__ || __x86_64__ */
3369 }
3370
3371 // MARK: -
3372 // MARK: Deep Sleep Policy
3373
3374 #if HIBERNATION
3375
3376 //******************************************************************************
3377 // evaluateSystemSleepPolicy
3378 //******************************************************************************
3379
3380 struct IOPMSystemSleepPolicyEntry
3381 {
3382 uint32_t factorMask;
3383 uint32_t factorBits;
3384 uint32_t sleepFlags;
3385 uint32_t wakeEvents;
3386 };
3387
3388 struct IOPMSystemSleepPolicyTable
3389 {
3390 uint8_t signature[4];
3391 uint16_t version;
3392 uint16_t entryCount;
3393 IOPMSystemSleepPolicyEntry entries[];
3394 };
3395
3396 enum {
3397 kIOPMSleepFactorSleepTimerWake = 0x00000001,
3398 kIOPMSleepFactorLidOpen = 0x00000002,
3399 kIOPMSleepFactorACPower = 0x00000004,
3400 kIOPMSleepFactorLowBattery = 0x00000008,
3401 kIOPMSleepFactorDeepSleepNoDelay = 0x00000010,
3402 kIOPMSleepFactorDeepSleepDemand = 0x00000020,
3403 kIOPMSleepFactorDeepSleepDisable = 0x00000040,
3404 kIOPMSleepFactorUSBExternalDevice = 0x00000080,
3405 kIOPMSleepFactorBluetoothHIDDevice = 0x00000100,
3406 kIOPMSleepFactorExternalMediaMounted = 0x00000200,
3407 kIOPMSleepFactorDriverAssertBit5 = 0x00000400, /* Reserved for ThunderBolt */
3408 kIOPMSleepFactorDriverAssertBit6 = 0x00000800,
3409 kIOPMSleepFactorDriverAssertBit7 = 0x00001000
3410 };
3411
3412 bool IOPMrootDomain::evaluateSystemSleepPolicy( IOPMSystemSleepParameters * p )
3413 {
3414 const IOPMSystemSleepPolicyTable * pt;
3415 OSObject * prop = 0;
3416 OSData * policyData;
3417 uint32_t currentFactors;
3418 uint32_t deepSleepDelay = 0;
3419 bool success = false;
3420
3421 if (getProperty(kIOPMDeepSleepEnabledKey) != kOSBooleanTrue)
3422 return false;
3423
3424 getSleepOption(kIOPMDeepSleepDelayKey, &deepSleepDelay);
3425
3426 prop = getServiceRoot()->copyProperty(kIOPlatformSystemSleepPolicyKey);
3427 if (!prop)
3428 return false;
3429
3430 policyData = OSDynamicCast(OSData, prop);
3431 if (!policyData ||
3432 (policyData->getLength() < sizeof(IOPMSystemSleepPolicyTable)))
3433 {
3434 goto done;
3435 }
3436
3437 pt = (const IOPMSystemSleepPolicyTable *) policyData->getBytesNoCopy();
3438 if ((pt->signature[0] != 'S') ||
3439 (pt->signature[1] != 'L') ||
3440 (pt->signature[2] != 'P') ||
3441 (pt->signature[3] != 'T') ||
3442 (pt->version != 1) ||
3443 (pt->entryCount == 0))
3444 {
3445 goto done;
3446 }
3447
3448 if ((policyData->getLength() - sizeof(IOPMSystemSleepPolicyTable)) !=
3449 (sizeof(IOPMSystemSleepPolicyEntry) * pt->entryCount))
3450 {
3451 goto done;
3452 }
3453
3454 currentFactors = 0;
3455 if (getPMAssertionLevel(kIOPMDriverAssertionUSBExternalDeviceBit) !=
3456 kIOPMDriverAssertionLevelOff)
3457 currentFactors |= kIOPMSleepFactorUSBExternalDevice;
3458 if (getPMAssertionLevel(kIOPMDriverAssertionBluetoothHIDDevicePairedBit) !=
3459 kIOPMDriverAssertionLevelOff)
3460 currentFactors |= kIOPMSleepFactorBluetoothHIDDevice;
3461 if (getPMAssertionLevel(kIOPMDriverAssertionExternalMediaMountedBit) !=
3462 kIOPMDriverAssertionLevelOff)
3463 currentFactors |= kIOPMSleepFactorExternalMediaMounted;
3464 if (getPMAssertionLevel(kIOPMDriverAssertionReservedBit5) != /* AssertionBit5 = Thunderbolt */
3465 kIOPMDriverAssertionLevelOff)
3466 currentFactors |= kIOPMSleepFactorDriverAssertBit5;
3467 if (getPMAssertionLevel(kIOPMDriverAssertionReservedBit7) !=
3468 kIOPMDriverAssertionLevelOff)
3469 currentFactors |= kIOPMSleepFactorDriverAssertBit7;
3470 if (0 == deepSleepDelay)
3471 currentFactors |= kIOPMSleepFactorDeepSleepNoDelay;
3472 if (!clamshellClosed)
3473 currentFactors |= kIOPMSleepFactorLidOpen;
3474 if (acAdaptorConnected)
3475 currentFactors |= kIOPMSleepFactorACPower;
3476 if (lowBatteryCondition)
3477 currentFactors |= kIOPMSleepFactorLowBattery;
3478 if (sleepTimerMaintenance)
3479 currentFactors |= kIOPMSleepFactorSleepTimerWake;
3480
3481 // pmset overrides
3482 if ((hibernateMode & kIOHibernateModeOn) == 0)
3483 currentFactors |= kIOPMSleepFactorDeepSleepDisable;
3484 else if ((hibernateMode & kIOHibernateModeSleep) == 0)
3485 currentFactors |= kIOPMSleepFactorDeepSleepDemand;
3486
3487 DLOG("Sleep policy %u entries, current factors 0x%x\n",
3488 pt->entryCount, currentFactors);
3489
3490 for (uint32_t i = 0; i < pt->entryCount; i++)
3491 {
3492 const IOPMSystemSleepPolicyEntry * policyEntry = &pt->entries[i];
3493
3494 DLOG("factor mask 0x%08x, bits 0x%08x, flags 0x%08x, wake 0x%08x\n",
3495 policyEntry->factorMask, policyEntry->factorBits,
3496 policyEntry->sleepFlags, policyEntry->wakeEvents);
3497
3498 if ((currentFactors ^ policyEntry->factorBits) & policyEntry->factorMask)
3499 continue; // mismatch, try next
3500
3501 if (p)
3502 {
3503 p->version = 1;
3504 p->sleepFlags = policyEntry->sleepFlags;
3505 p->sleepTimer = 0;
3506 p->wakeEvents = policyEntry->wakeEvents;
3507 if (p->sleepFlags & kIOPMSleepFlagSleepTimerEnable)
3508 {
3509 p->sleepTimer = deepSleepDelay;
3510 }
3511 }
3512
3513 DLOG("matched policy entry %u\n", i);
3514 success = true;
3515 break;
3516 }
3517
3518 done:
3519 if (prop)
3520 prop->release();
3521
3522 return success;
3523 }
3524
3525 void IOPMrootDomain::evaluateSystemSleepPolicyEarly( void )
3526 {
3527 IOPMSystemSleepParameters params;
3528
3529 // Evaluate sleep policy before driver sleep phase.
3530
3531 DLOG("%s\n", __FUNCTION__);
3532 removeProperty(kIOPMSystemSleepParametersKey);
3533
3534 hibernateDisabled = false;
3535 hibernateMode = 0;
3536 getSleepOption(kIOHibernateModeKey, &hibernateMode);
3537
3538 if (!hibernateNoDefeat &&
3539 evaluateSystemSleepPolicy(&params) &&
3540 ((params.sleepFlags & kIOPMSleepFlagHibernate) == 0))
3541 {
3542 hibernateDisabled = true;
3543 }
3544 }
3545
3546 void IOPMrootDomain::evaluateSystemSleepPolicyFinal( void )
3547 {
3548 IOPMSystemSleepParameters params;
3549 OSData * paramsData;
3550
3551 // Evaluate sleep policy after drivers but before platform sleep.
3552
3553 DLOG("%s\n", __FUNCTION__);
3554
3555 if (evaluateSystemSleepPolicy(&params))
3556 {
3557 if ((hibernateDisabled || hibernateAborted) &&
3558 (params.sleepFlags & kIOPMSleepFlagHibernate))
3559 {
3560 // Should hibernate but unable to or aborted.
3561 // Arm timer for a short sleep and retry or wake fully.
3562
3563 params.sleepFlags &= ~kIOPMSleepFlagHibernate;
3564 params.sleepFlags |= kIOPMSleepFlagSleepTimerEnable;
3565 params.sleepTimer = 1;
3566 hibernateNoDefeat = true;
3567 DLOG("wake in %u secs for hibernateDisabled %d, hibernateAborted %d\n",
3568 params.sleepTimer, hibernateDisabled, hibernateAborted);
3569 }
3570 else
3571 hibernateNoDefeat = false;
3572
3573 paramsData = OSData::withBytes(&params, sizeof(params));
3574 if (paramsData)
3575 {
3576 setProperty(kIOPMSystemSleepParametersKey, paramsData);
3577 paramsData->release();
3578 }
3579
3580 if (params.sleepFlags & kIOPMSleepFlagHibernate)
3581 {
3582 // Force hibernate
3583 gIOHibernateMode &= ~kIOHibernateModeSleep;
3584 }
3585 }
3586 }
3587
3588 bool IOPMrootDomain::getHibernateSettings(
3589 uint32_t * hibernateMode,
3590 uint32_t * hibernateFreeRatio,
3591 uint32_t * hibernateFreeTime )
3592 {
3593 bool ok = getSleepOption(kIOHibernateModeKey, hibernateMode);
3594 getSleepOption(kIOHibernateFreeRatioKey, hibernateFreeRatio);
3595 getSleepOption(kIOHibernateFreeTimeKey, hibernateFreeTime);
3596 if (hibernateDisabled)
3597 *hibernateMode = 0;
3598 DLOG("hibernateMode 0x%x\n", *hibernateMode);
3599 return ok;
3600 }
3601
3602 bool IOPMrootDomain::getSleepOption( const char * key, uint32_t * option )
3603 {
3604 OSObject * optionsProp;
3605 OSDictionary * optionsDict;
3606 OSObject * obj = 0;
3607 OSNumber * num;
3608 bool ok = false;
3609
3610 optionsProp = copyProperty(kRootDomainSleepOptionsKey);
3611 optionsDict = OSDynamicCast(OSDictionary, optionsProp);
3612
3613 if (optionsDict)
3614 {
3615 obj = optionsDict->getObject(key);
3616 if (obj) obj->retain();
3617 }
3618 if (!obj)
3619 {
3620 obj = copyProperty(key);
3621 }
3622 if (obj && (num = OSDynamicCast(OSNumber, obj)))
3623 {
3624 *option = num->unsigned32BitValue();
3625 ok = true;
3626 }
3627
3628 if (obj)
3629 obj->release();
3630 if (optionsProp)
3631 optionsProp->release();
3632
3633 return true;
3634 }
3635 #endif /* HIBERNATION */
3636
3637 // MARK: -
3638 // MARK: Shutdown and Restart
3639
3640 //******************************************************************************
3641 // handlePlatformHaltRestart
3642 //
3643 //******************************************************************************
3644
3645 struct HaltRestartApplierContext {
3646 IOPMrootDomain * RootDomain;
3647 unsigned long PowerState;
3648 IOPMPowerFlags PowerFlags;
3649 UInt32 MessageType;
3650 UInt32 Counter;
3651 };
3652
3653 static void
3654 platformHaltRestartApplier( OSObject * object, void * context )
3655 {
3656 IOPowerStateChangeNotification notify;
3657 HaltRestartApplierContext * ctx;
3658 AbsoluteTime startTime;
3659 UInt32 deltaTime;
3660
3661 ctx = (HaltRestartApplierContext *) context;
3662
3663 memset(&notify, 0, sizeof(notify));
3664 notify.powerRef = (void *)ctx->Counter;
3665 notify.returnValue = 0;
3666 notify.stateNumber = ctx->PowerState;
3667 notify.stateFlags = ctx->PowerFlags;
3668
3669 clock_get_uptime(&startTime);
3670 ctx->RootDomain->messageClient( ctx->MessageType, object, (void *)&notify );
3671 deltaTime = computeDeltaTimeMS(&startTime);
3672
3673 if ((deltaTime > kPMHaltTimeoutMS) ||
3674 (gIOKitDebug & kIOLogPMRootDomain))
3675 {
3676 _IOServiceInterestNotifier * notifier;
3677 notifier = OSDynamicCast(_IOServiceInterestNotifier, object);
3678
3679 // IOService children of IOPMrootDomain are not instrumented.
3680 // Only IORootParent currently falls under that group.
3681
3682 if (notifier)
3683 {
3684 LOG("%s handler %p took %u ms\n",
3685 (ctx->MessageType == kIOMessageSystemWillPowerOff) ? "PowerOff" :
3686 (ctx->MessageType == kIOMessageSystemPagingOff) ? "PagingOff" : "Restart",
3687 notifier->handler, (uint32_t) deltaTime );
3688 }
3689 }
3690
3691 ctx->Counter++;
3692 }
3693
3694 void IOPMrootDomain::handlePlatformHaltRestart( UInt32 pe_type )
3695 {
3696 HaltRestartApplierContext ctx;
3697 AbsoluteTime startTime;
3698 UInt32 deltaTime;
3699
3700 memset(&ctx, 0, sizeof(ctx));
3701 ctx.RootDomain = this;
3702
3703 clock_get_uptime(&startTime);
3704 switch (pe_type)
3705 {
3706 case kPEHaltCPU:
3707 case kPEUPSDelayHaltCPU:
3708 ctx.PowerState = OFF_STATE;
3709 ctx.MessageType = kIOMessageSystemWillPowerOff;
3710 break;
3711
3712 case kPERestartCPU:
3713 ctx.PowerState = RESTART_STATE;
3714 ctx.MessageType = kIOMessageSystemWillRestart;
3715 break;
3716
3717 case kPEPagingOff:
3718 ctx.PowerState = ON_STATE;
3719 ctx.MessageType = kIOMessageSystemPagingOff;
3720 break;
3721
3722 default:
3723 return;
3724 }
3725
3726 // Notify legacy clients
3727 applyToInterested(gIOPriorityPowerStateInterest, platformHaltRestartApplier, &ctx);
3728
3729 // For normal shutdown, turn off File Server Mode.
3730 if (kPEHaltCPU == pe_type)
3731 {
3732 const OSSymbol * setting = OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey);
3733 OSNumber * num = OSNumber::withNumber((unsigned long long) 0, 32);
3734 if (setting && num)
3735 {
3736 setPMSetting(setting, num);
3737 setting->release();
3738 num->release();
3739 }
3740 }
3741
3742 if (kPEPagingOff != pe_type)
3743 {
3744 // Notify in power tree order
3745 notifySystemShutdown(this, ctx.MessageType);
3746 }
3747
3748 deltaTime = computeDeltaTimeMS(&startTime);
3749 LOG("%s all drivers took %u ms\n",
3750 (ctx.MessageType == kIOMessageSystemWillPowerOff) ? "PowerOff" :
3751 (ctx.MessageType == kIOMessageSystemPagingOff) ? "PagingOff" : "Restart",
3752 (uint32_t) deltaTime );
3753 }
3754
3755 //******************************************************************************
3756 // shutdownSystem
3757 //
3758 //******************************************************************************
3759
3760 IOReturn IOPMrootDomain::shutdownSystem( void )
3761 {
3762 return kIOReturnUnsupported;
3763 }
3764
3765 //******************************************************************************
3766 // restartSystem
3767 //
3768 //******************************************************************************
3769
3770 IOReturn IOPMrootDomain::restartSystem( void )
3771 {
3772 return kIOReturnUnsupported;
3773 }
3774
3775 // MARK: -
3776 // MARK: System Capability
3777
3778 //******************************************************************************
3779 // tagPowerPlaneService
3780 //
3781 // Running on PM work loop thread.
3782 //******************************************************************************
3783
3784 void IOPMrootDomain::tagPowerPlaneService(
3785 IOService * service,
3786 IOPMActions * actions )
3787 {
3788 uint32_t flags = 0;
3789 bool isDisplayWrangler;
3790
3791 memset(actions, 0, sizeof(*actions));
3792 actions->target = this;
3793
3794 if (service == this)
3795 {
3796 actions->actionPowerChangeStart =
3797 OSMemberFunctionCast(
3798 IOPMActionPowerChangeStart, this,
3799 &IOPMrootDomain::handleOurPowerChangeStart);
3800
3801 actions->actionPowerChangeDone =
3802 OSMemberFunctionCast(
3803 IOPMActionPowerChangeDone, this,
3804 &IOPMrootDomain::handleOurPowerChangeDone);
3805
3806 actions->actionPowerChangeOverride =
3807 OSMemberFunctionCast(
3808 IOPMActionPowerChangeOverride, this,
3809 &IOPMrootDomain::overrideOurPowerChange);
3810 return;
3811 }
3812
3813 #if !NO_KERNEL_HID
3814 isDisplayWrangler = (0 != service->metaCast("IODisplayWrangler"));
3815 if (isDisplayWrangler)
3816 {
3817 wrangler = service;
3818 wranglerConnection = (IOService *) service->getParentEntry(gIOPowerPlane);
3819 }
3820 #else
3821 isDisplayWrangler = false;
3822 #endif
3823
3824 #if defined(__i386__) || defined(__x86_64__)
3825 if (isDisplayWrangler)
3826 flags |= kPMActionsFlagIsDisplayWrangler;
3827 if (service->getProperty("IOPMStrictTreeOrder"))
3828 flags |= kPMActionsFlagIsGraphicsDevice;
3829 if (service->getProperty("IOPMUnattendedWakePowerState"))
3830 flags |= kPMActionsFlagIsAudioDevice;
3831 #endif
3832
3833 // Find the power connection object that is a child of the PCI host
3834 // bridge, and has a graphics/audio device attached below. Mark the
3835 // power branch for delayed child notifications.
3836
3837 if (flags)
3838 {
3839 IORegistryEntry * child = service;
3840 IORegistryEntry * parent = child->getParentEntry(gIOPowerPlane);
3841
3842 while (child != this)
3843 {
3844 if ((parent == pciHostBridgeDriver) ||
3845 (parent == this))
3846 {
3847 if (OSDynamicCast(IOPowerConnection, child))
3848 {
3849 IOPowerConnection * conn = (IOPowerConnection *) child;
3850 conn->delayChildNotification = true;
3851 }
3852 break;
3853 }
3854 child = parent;
3855 parent = child->getParentEntry(gIOPowerPlane);
3856 }
3857 }
3858
3859 if (flags)
3860 {
3861 DLOG("%s tag flags %x\n", service->getName(), flags);
3862 actions->parameter |= flags;
3863 actions->actionPowerChangeOverride =
3864 OSMemberFunctionCast(
3865 IOPMActionPowerChangeOverride, this,
3866 &IOPMrootDomain::overridePowerChangeForUIService);
3867
3868 if (flags & kPMActionsFlagIsDisplayWrangler)
3869 {
3870 actions->actionActivityTickle =
3871 OSMemberFunctionCast(
3872 IOPMActionActivityTickle, this,
3873 &IOPMrootDomain::handleActivityTickleForDisplayWrangler);
3874 }
3875 return;
3876 }
3877
3878 // Locate the first PCI host bridge for PMTrace.
3879 if (!pciHostBridgeDevice && service->metaCast("IOPCIBridge"))
3880 {
3881 IOService * provider = service->getProvider();
3882 if (OSDynamicCast(IOPlatformDevice, provider) &&
3883 provider->inPlane(gIODTPlane))
3884 {
3885 pciHostBridgeDevice = provider;
3886 pciHostBridgeDriver = service;
3887 DLOG("PMTrace found PCI host bridge %s->%s\n",
3888 provider->getName(), service->getName());
3889 }
3890 }
3891
3892 // Tag top-level PCI devices. The order of PMinit() call does not
3893 // change across boots and is used as the PCI bit number.
3894 if (pciHostBridgeDevice && service->metaCast("IOPCIDevice"))
3895 {
3896 // Would prefer to check built-in property, but tagPowerPlaneService()
3897 // is called before pciDevice->registerService().
3898 IORegistryEntry * parent = service->getParentEntry(gIODTPlane);
3899 if ((parent == pciHostBridgeDevice) && service->getProperty("acpi-device"))
3900 {
3901 int bit = pmTracer->recordTopLevelPCIDevice( service );
3902 if (bit >= 0)
3903 {
3904 // Save the assigned bit for fast lookup.
3905 actions->parameter |= (bit & kPMActionsPCIBitNumberMask);
3906
3907 actions->actionPowerChangeStart =
3908 OSMemberFunctionCast(
3909 IOPMActionPowerChangeStart, this,
3910 &IOPMrootDomain::handlePowerChangeStartForPCIDevice);
3911
3912 actions->actionPowerChangeDone =
3913 OSMemberFunctionCast(
3914 IOPMActionPowerChangeDone, this,
3915 &IOPMrootDomain::handlePowerChangeDoneForPCIDevice);
3916 }
3917 }
3918 }
3919 }
3920
3921 //******************************************************************************
3922 // PM actions for root domain
3923 //******************************************************************************
3924
3925 void IOPMrootDomain::overrideOurPowerChange(
3926 IOService * service,
3927 IOPMActions * actions,
3928 unsigned long * inOutPowerState,
3929 uint32_t * inOutChangeFlags )
3930 {
3931 uint32_t powerState = (uint32_t) *inOutPowerState;
3932 uint32_t changeFlags = *inOutChangeFlags;
3933 uint32_t currentPowerState = (uint32_t) getPowerState();
3934
3935 if ((currentPowerState == powerState) ||
3936 (changeFlags & kIOPMParentInitiated))
3937 {
3938 // FIXME: cancel any parent change (unexpected)
3939 // Root parent is permanently pegged at max power,
3940 // kIOPMParentInitiated is unexpected.
3941 return;
3942 }
3943
3944 if (powerState < currentPowerState)
3945 {
3946 if ((changeFlags & kIOPMSkipAskPowerDown) == 0)
3947 {
3948 /* Convenient place to run any code at idle sleep time
3949 * IOPMrootDomain initiates an idle sleep here
3950 *
3951 * Set last sleep cause accordingly.
3952 */
3953 pmPowerStateQueue->submitPowerEvent(kPowerEventPublishSleepWakeUUID, (void *)true);
3954
3955 lastSleepReason = kIOPMSleepReasonIdle;
3956 setProperty(kRootDomainSleepReasonKey, kIOPMIdleSleepKey);
3957 }
3958 if (CAP_CURRENT(kIOPMSystemCapabilityGraphics))
3959 {
3960 // Root domain is dropping power state ON->SLEEP.
3961 // If system is in full wake, first drop to dark wake.
3962
3963 darkWakeToSleepASAP = true;
3964
3965 // Drop graphics capability.
3966 // No transition if system is already in dark wake.
3967
3968 _desiredCapability &= ~(
3969 kIOPMSystemCapabilityGraphics |
3970 kIOPMSystemCapabilityAudio );
3971
3972 *inOutPowerState = ON_STATE;
3973 *inOutChangeFlags |= kIOPMSynchronize;
3974
3975 // Revert device desire from SLEEP->ON.
3976 changePowerStateToPriv(ON_STATE);
3977 }
3978 }
3979 }
3980
3981 void IOPMrootDomain::handleOurPowerChangeStart(
3982 IOService * service,
3983 IOPMActions * actions,
3984 uint32_t powerState,
3985 uint32_t * inOutChangeFlags )
3986 {
3987 uint32_t changeFlags = *inOutChangeFlags;
3988 uint32_t currentPowerState = (uint32_t) getPowerState();
3989
3990 _systemTransitionType = kSystemTransitionNone;
3991 _systemMessageClientMask = 0;
3992 capabilityLoss = false;
3993
3994 // 1. Explicit capability change.
3995
3996 if (changeFlags & kIOPMSynchronize)
3997 {
3998 if (powerState == ON_STATE)
3999 {
4000 if (changeFlags & kIOPMSyncNoChildNotify)
4001 _systemTransitionType = kSystemTransitionNewCapClient;
4002 else
4003 _systemTransitionType = kSystemTransitionCapability;
4004 }
4005 }
4006
4007 // 2. Going to sleep (cancellation still possible).
4008
4009 else if (powerState < currentPowerState)
4010 _systemTransitionType = kSystemTransitionSleep;
4011
4012 // 3. Woke from (idle or demand) sleep.
4013
4014 else if (!systemBooting &&
4015 (changeFlags & kIOPMSelfInitiated) &&
4016 (powerState > currentPowerState))
4017 {
4018 _systemTransitionType = kSystemTransitionWake;
4019 _desiredCapability = kIOPMSystemCapabilityCPU |
4020 kIOPMSystemCapabilityNetwork;
4021
4022 // Check for early HID events (e.g. LID open)
4023 if (wranglerTickled)
4024 {
4025 _desiredCapability |= (
4026 kIOPMSystemCapabilityGraphics |
4027 kIOPMSystemCapabilityAudio );
4028 }
4029 }
4030
4031 // Update pending wake capability at the beginning of every
4032 // state transition (including synchronize). This will become
4033 // the current capability at the end of the transition.
4034
4035 if (kSystemTransitionSleep == _systemTransitionType)
4036 {
4037 _pendingCapability = 0;
4038 capabilityLoss = true;
4039 }
4040 else if (kSystemTransitionNewCapClient != _systemTransitionType)
4041 {
4042 _pendingCapability = _desiredCapability |
4043 kIOPMSystemCapabilityCPU |
4044 kIOPMSystemCapabilityNetwork;
4045
4046 if (_pendingCapability & kIOPMSystemCapabilityGraphics)
4047 _pendingCapability |= kIOPMSystemCapabilityAudio;
4048
4049 if ((kSystemTransitionCapability == _systemTransitionType) &&
4050 (_pendingCapability == _currentCapability))
4051 {
4052 // Cancel the PM state change.
4053 _systemTransitionType = kSystemTransitionNone;
4054 *inOutChangeFlags |= kIOPMNotDone;
4055 }
4056 if (__builtin_popcount(_pendingCapability) <
4057 __builtin_popcount(_currentCapability))
4058 capabilityLoss = true;
4059 if (CAP_LOSS(kIOPMSystemCapabilityGraphics))
4060 rejectWranglerTickle = true;
4061 }
4062
4063 // 1. Capability change.
4064
4065 if (kSystemTransitionCapability == _systemTransitionType)
4066 {
4067 // Dark to Full transition.
4068 if (CAP_GAIN(kIOPMSystemCapabilityGraphics))
4069 {
4070 tracePoint( kIOPMTracePointDarkWakeExit );
4071 wranglerSleepIgnored = false;
4072 sleepTimerMaintenance = false;
4073 hibernateNoDefeat = false;
4074 _systemMessageClientMask = kSystemMessageClientUser;
4075 if ((_highestCapability & kIOPMSystemCapabilityGraphics) == 0)
4076 _systemMessageClientMask |= kSystemMessageClientKernel;
4077
4078 tellClients(kIOMessageSystemWillPowerOn);
4079 }
4080
4081 // Full to Dark transition.
4082 if (CAP_LOSS(kIOPMSystemCapabilityGraphics))
4083 {
4084 tracePoint( kIOPMTracePointDarkWakeEntry );
4085 *inOutChangeFlags |= kIOPMSyncTellPowerDown;
4086 _systemMessageClientMask = kSystemMessageClientUser;
4087 }
4088 }
4089
4090 // 2. System sleep.
4091
4092 else if (kSystemTransitionSleep == _systemTransitionType)
4093 {
4094 // Beginning of a system sleep transition.
4095 // Cancellation is still possible.
4096 tracePoint( kIOPMTracePointSleepStarted, lastSleepReason );
4097
4098 _systemMessageClientMask = kSystemMessageClientAll;
4099 if ((_currentCapability & kIOPMSystemCapabilityGraphics) == 0)
4100 _systemMessageClientMask &= ~kSystemMessageClientApp;
4101 if ((_highestCapability & kIOPMSystemCapabilityGraphics) == 0)
4102 _systemMessageClientMask &= ~kSystemMessageClientKernel;
4103
4104 // Optimization to ignore wrangler power down thus skipping
4105 // the disk spindown and arming the idle timer for demand sleep.
4106
4107 if (changeFlags & kIOPMIgnoreChildren)
4108 {
4109 wranglerSleepIgnored = true;
4110 }
4111
4112 logWranglerTickle = false;
4113 }
4114
4115 // 3. System wake.
4116
4117 else if (kSystemTransitionWake == _systemTransitionType)
4118 {
4119 wranglerSleepIgnored = false;
4120
4121 if (_pendingCapability & kIOPMSystemCapabilityGraphics)
4122 {
4123 _systemMessageClientMask = kSystemMessageClientAll;
4124 }
4125 else
4126 {
4127 _systemMessageClientMask = kSystemMessageClientConfigd;
4128 }
4129
4130 tracePoint( kIOPMTracePointWakeWillPowerOnClients );
4131 tellClients(kIOMessageSystemWillPowerOn);
4132 }
4133
4134 if ((kSystemTransitionNone != _systemTransitionType) &&
4135 (kSystemTransitionNewCapClient != _systemTransitionType))
4136 {
4137 _systemStateGeneration++;
4138 systemDarkWake = false;
4139
4140 DLOG("=== START (%u->%u, 0x%x) type %u, gen %u, msg %x, "
4141 "dcp %x:%x:%x\n",
4142 currentPowerState, powerState, *inOutChangeFlags,
4143 _systemTransitionType, _systemStateGeneration,
4144 _systemMessageClientMask,
4145 _desiredCapability, _currentCapability, _pendingCapability);
4146 }
4147 }
4148
4149 void IOPMrootDomain::handleOurPowerChangeDone(
4150 IOService * service,
4151 IOPMActions * actions,
4152 uint32_t powerState,
4153 uint32_t changeFlags )
4154 {
4155 if (kSystemTransitionNewCapClient == _systemTransitionType)
4156 {
4157 _systemTransitionType = kSystemTransitionNone;
4158 return;
4159 }
4160
4161 if (_systemTransitionType != kSystemTransitionNone)
4162 {
4163 uint32_t currentPowerState = (uint32_t) getPowerState();
4164
4165 if (changeFlags & kIOPMNotDone)
4166 {
4167 // Power down was cancelled or vetoed.
4168 _pendingCapability = _currentCapability;
4169 lastSleepReason = 0;
4170
4171 if (((_currentCapability & kIOPMSystemCapabilityGraphics) == 0) &&
4172 (_currentCapability & kIOPMSystemCapabilityCPU))
4173 {
4174 pmPowerStateQueue->submitPowerEvent(
4175 kPowerEventPolicyStimulus,
4176 (void *) kStimulusDarkWakeReentry,
4177 _systemStateGeneration );
4178 }
4179
4180 // Revert device desire to max.
4181 changePowerStateToPriv(ON_STATE);
4182 }
4183 else
4184 {
4185 // Send message on dark wake to full wake promotion.
4186 // tellChangeUp() handles the normal SLEEP->ON case.
4187
4188 if (kSystemTransitionCapability == _systemTransitionType)
4189 {
4190 if (CAP_GAIN(kIOPMSystemCapabilityGraphics))
4191 {
4192 tellClients(kIOMessageSystemHasPoweredOn);
4193 #if DARK_TO_FULL_EVALUATE_CLAMSHELL
4194 // Re-evaluate clamshell state ourselves when graphics
4195 // will not get kIOMessageSystemHasPoweredOn.
4196
4197 if (clamshellClosed &&
4198 ((_systemMessageClientMask & kSystemMessageClientKernel) == 0))
4199 {
4200 receivePowerNotification( kLocalEvalClamshellCommand );
4201 }
4202 #endif
4203 }
4204 if (CAP_LOSS(kIOPMSystemCapabilityGraphics))
4205 wranglerTickled = false;
4206 }
4207
4208 // Reset state after exiting from dark wake.
4209
4210 if (CAP_GAIN(kIOPMSystemCapabilityGraphics) ||
4211 CAP_LOSS(kIOPMSystemCapabilityCPU))
4212 {
4213 darkWakeMaintenance = false;
4214 darkWakeToSleepASAP = false;
4215 pciCantSleepValid = false;
4216 rejectWranglerTickle = false;
4217 }
4218
4219 // Entered dark mode.
4220
4221 if (((_pendingCapability & kIOPMSystemCapabilityGraphics) == 0) &&
4222 (_pendingCapability & kIOPMSystemCapabilityCPU))
4223 {
4224 if (((gDarkWakeFlags & kDarkWakeFlagIgnoreDiskIOInDark) == 0) &&
4225 (kSystemTransitionWake == _systemTransitionType) &&
4226 (_debugWakeSeconds == 0))
4227 {
4228 OSObject * prop = copyProperty(kIOPMRootDomainWakeTypeKey);
4229 if (prop)
4230 {
4231 OSString * wakeType = OSDynamicCast(OSString, prop);
4232 if (wakeType &&
4233 wakeType->isEqualTo(kIOPMRootDomainWakeTypeNetwork))
4234 {
4235 // Woke from network and entered dark wake.
4236 if (darkWakeToSleepASAP)
4237 {
4238 DLOG("cleared darkWakeToSleepASAP\n");
4239 darkWakeToSleepASAP = false;
4240 }
4241 }
4242 prop->release();
4243 }
4244 }
4245
4246 // Queue an evaluation of whether to remain in dark wake,
4247 // and for how long. This serves the purpose of draining
4248 // any assertions from the queue.
4249
4250 pmPowerStateQueue->submitPowerEvent(
4251 kPowerEventPolicyStimulus,
4252 (void *) kStimulusDarkWakeEntry,
4253 _systemStateGeneration );
4254 }
4255 }
4256
4257 DLOG("=== FINISH (%u->%u, 0x%x) type %u, gen %u, msg %x, "
4258 "dcp %x:%x:%x, dbgtimer %u\n",
4259 currentPowerState, powerState, changeFlags,
4260 _systemTransitionType, _systemStateGeneration,
4261 _systemMessageClientMask,
4262 _desiredCapability, _currentCapability, _pendingCapability,
4263 _debugWakeSeconds);
4264
4265 // Update current system capability.
4266
4267 if (_currentCapability != _pendingCapability)
4268 _currentCapability = _pendingCapability;
4269
4270 // Update highest system capability.
4271
4272 if (!CAP_CURRENT(kIOPMSystemCapabilityCPU))
4273 _highestCapability = 0; // reset at sleep state
4274 else
4275 _highestCapability |= _currentCapability;
4276
4277 if (darkWakePostTickle &&
4278 (kSystemTransitionWake == _systemTransitionType) &&
4279 (gDarkWakeFlags & kDarkWakeFlagHIDTickleMask) ==
4280 kDarkWakeFlagHIDTickleLate)
4281 {
4282 darkWakePostTickle = false;
4283 reportUserInput();
4284 }
4285
4286 // Reset tracepoint at completion of capability change,
4287 // completion of wake transition, and aborted sleep transition.
4288
4289 if ((_systemTransitionType == kSystemTransitionCapability) ||
4290 (_systemTransitionType == kSystemTransitionWake) ||
4291 ((_systemTransitionType == kSystemTransitionSleep) &&
4292 (changeFlags & kIOPMNotDone)))
4293 {
4294 setProperty(kIOPMSystemCapabilitiesKey, _currentCapability, 64);
4295 tracePoint( kIOPMTracePointSystemUp, 0 );
4296 }
4297
4298 _systemTransitionType = kSystemTransitionNone;
4299 _systemMessageClientMask = 0;
4300
4301 logGraphicsClamp = false;
4302 }
4303 }
4304
4305 //******************************************************************************
4306 // PM actions for graphics and audio.
4307 //******************************************************************************
4308
4309 void IOPMrootDomain::overridePowerChangeForUIService(
4310 IOService * service,
4311 IOPMActions * actions,
4312 unsigned long * inOutPowerState,
4313 uint32_t * inOutChangeFlags )
4314 {
4315 uint32_t powerState = (uint32_t) *inOutPowerState;
4316 uint32_t changeFlags = (uint32_t) *inOutChangeFlags;
4317
4318 if (kSystemTransitionNone == _systemTransitionType)
4319 {
4320 // Not in midst of a system transition.
4321 // Do not modify power limit enable state.
4322 }
4323 else if ((actions->parameter & kPMActionsFlagLimitPower) == 0)
4324 {
4325 // Activate power limiter.
4326
4327 if ((actions->parameter & kPMActionsFlagIsDisplayWrangler) &&
4328 ((_pendingCapability & kIOPMSystemCapabilityGraphics) == 0))
4329 {
4330 actions->parameter |= kPMActionsFlagLimitPower;
4331 }
4332 else if ((actions->parameter & kPMActionsFlagIsAudioDevice) &&
4333 ((_pendingCapability & kIOPMSystemCapabilityAudio) == 0))
4334 {
4335 actions->parameter |= kPMActionsFlagLimitPower;
4336 }
4337 else if ((actions->parameter & kPMActionsFlagIsGraphicsDevice) &&
4338 (_systemTransitionType == kSystemTransitionSleep))
4339 {
4340 // For graphics devices, arm the limiter when entering
4341 // system sleep. Not when dropping to dark wake.
4342 actions->parameter |= kPMActionsFlagLimitPower;
4343 }
4344
4345 if (actions->parameter & kPMActionsFlagLimitPower)
4346 {
4347 DLOG("+ plimit %s %p\n",
4348 service->getName(), service);
4349 }
4350 }
4351 else
4352 {
4353 // Remove power limit.
4354
4355 if ((actions->parameter & (
4356 kPMActionsFlagIsDisplayWrangler |
4357 kPMActionsFlagIsGraphicsDevice )) &&
4358 (_pendingCapability & kIOPMSystemCapabilityGraphics))
4359 {
4360 actions->parameter &= ~kPMActionsFlagLimitPower;
4361 }
4362 else if ((actions->parameter & kPMActionsFlagIsAudioDevice) &&
4363 (_pendingCapability & kIOPMSystemCapabilityAudio))
4364 {
4365 actions->parameter &= ~kPMActionsFlagLimitPower;
4366 }
4367
4368 if ((actions->parameter & kPMActionsFlagLimitPower) == 0)
4369 {
4370 DLOG("- plimit %s %p\n",
4371 service->getName(), service);
4372 }
4373 }
4374
4375 if (gRAMDiskImageBoot &&
4376 (actions->parameter & kPMActionsFlagIsDisplayWrangler))
4377 {
4378 // Tag devices subject to power suppression.
4379 *inOutChangeFlags |= kIOPMPowerSuppressed;
4380 }
4381
4382 if (actions->parameter & kPMActionsFlagLimitPower)
4383 {
4384 uint32_t maxPowerState = (uint32_t)(-1);
4385
4386 if (changeFlags & (kIOPMDomainDidChange | kIOPMDomainWillChange))
4387 {
4388 // Enforce limit for system power/cap transitions.
4389
4390 maxPowerState = 0;
4391 if ((actions->parameter & kPMActionsFlagIsDisplayWrangler) &&
4392 (!gRAMDiskImageBoot || (service->getPowerState() > 0)))
4393 {
4394 // Forces a 3->1 transition sequence
4395 if (changeFlags & kIOPMDomainWillChange)
4396 maxPowerState = 3;
4397 else
4398 maxPowerState = 1;
4399 }
4400 }
4401 else
4402 {
4403 // Deny all self-initiated changes when power is limited.
4404 // Wrangler tickle should never defeat the limiter.
4405
4406 maxPowerState = service->getPowerState();
4407 }
4408
4409 if (powerState > maxPowerState)
4410 {
4411 DLOG("> plimit %s %p (%u->%u, 0x%x)\n",
4412 service->getName(), service, powerState, maxPowerState,
4413 changeFlags);
4414 *inOutPowerState = maxPowerState;
4415
4416 if (darkWakePostTickle &&
4417 (actions->parameter & kPMActionsFlagIsDisplayWrangler) &&
4418 (changeFlags & kIOPMDomainWillChange) &&
4419 ((gDarkWakeFlags & kDarkWakeFlagHIDTickleMask) ==
4420 kDarkWakeFlagHIDTickleEarly))
4421 {
4422 darkWakePostTickle = false;
4423 reportUserInput();
4424 }
4425 }
4426
4427 if (!graphicsSuppressed && (changeFlags & kIOPMDomainDidChange))
4428 {
4429 if (logGraphicsClamp)
4430 {
4431 AbsoluteTime now;
4432 uint64_t nsec;
4433
4434 clock_get_uptime(&now);
4435 SUB_ABSOLUTETIME(&now, &systemWakeTime);
4436 absolutetime_to_nanoseconds(now, &nsec);
4437 MSG("Graphics suppressed %u ms\n",
4438 ((int)((nsec) / 1000000ULL)));
4439 }
4440 graphicsSuppressed = true;
4441 }
4442 }
4443 }
4444
4445 void IOPMrootDomain::handleActivityTickleForDisplayWrangler(
4446 IOService * service,
4447 IOPMActions * actions )
4448 {
4449 // Warning: Not running in PM work loop context - don't modify state !!!
4450 // Trap tickle directed to IODisplayWrangler while running with graphics
4451 // capability suppressed.
4452
4453 assert(service == wrangler);
4454
4455 if (service == wrangler)
4456 {
4457 bool aborting = ((lastSleepReason == kIOPMSleepReasonIdle)
4458 || (lastSleepReason == kIOPMSleepReasonMaintenance));
4459 if (aborting) {
4460 userActivityCount++;
4461 DLOG("display wrangler tickled1 %d lastSleepReason %d\n", userActivityCount, lastSleepReason);
4462 }
4463 }
4464
4465 if (!wranglerTickled && !lowBatteryCondition &&
4466 ((_pendingCapability & kIOPMSystemCapabilityGraphics) == 0))
4467 {
4468 DLOG("display wrangler tickled\n");
4469 if (kIOLogPMRootDomain & gIOKitDebug)
4470 OSReportWithBacktrace("Dark wake display tickle");
4471 if (pmPowerStateQueue)
4472 {
4473 pmPowerStateQueue->submitPowerEvent(
4474 kPowerEventPolicyStimulus,
4475 (void *) kStimulusDarkWakeActivityTickle );
4476 }
4477 }
4478 }
4479
4480 //******************************************************************************
4481 // Approve usage of delayed child notification by PM.
4482 //******************************************************************************
4483
4484 bool IOPMrootDomain::shouldDelayChildNotification(
4485 IOService * service )
4486 {
4487 if (((gDarkWakeFlags & kDarkWakeFlagHIDTickleMask) != 0) &&
4488 !wranglerTickled &&
4489 (kSystemTransitionWake == _systemTransitionType))
4490 {
4491 DLOG("%s: delay child notify\n", service->getName());
4492 return true;
4493 }
4494 return false;
4495 }
4496
4497 //******************************************************************************
4498 // PM actions for PCI device.
4499 //******************************************************************************
4500
4501 void IOPMrootDomain::handlePowerChangeStartForPCIDevice(
4502 IOService * service,
4503 IOPMActions * actions,
4504 uint32_t powerState,
4505 uint32_t * inOutChangeFlags )
4506 {
4507 pmTracer->tracePCIPowerChange(
4508 PMTraceWorker::kPowerChangeStart,
4509 service, *inOutChangeFlags,
4510 (actions->parameter & kPMActionsPCIBitNumberMask));
4511 }
4512
4513 void IOPMrootDomain::handlePowerChangeDoneForPCIDevice(
4514 IOService * service,
4515 IOPMActions * actions,
4516 uint32_t powerState,
4517 uint32_t changeFlags )
4518 {
4519 pmTracer->tracePCIPowerChange(
4520 PMTraceWorker::kPowerChangeCompleted,
4521 service, changeFlags,
4522 (actions->parameter & kPMActionsPCIBitNumberMask));
4523 }
4524
4525 //******************************************************************************
4526 // registerInterest
4527 //
4528 // Override IOService::registerInterest() to intercept special clients.
4529 //******************************************************************************
4530
4531 IONotifier * IOPMrootDomain::registerInterest(
4532 const OSSymbol * typeOfInterest,
4533 IOServiceInterestHandler handler,
4534 void * target, void * ref )
4535 {
4536 IONotifier * notifier;
4537 bool isSystemCapabilityClient;
4538 bool isKernelCapabilityClient;
4539
4540 isSystemCapabilityClient =
4541 typeOfInterest &&
4542 typeOfInterest->isEqualTo(kIOPMSystemCapabilityInterest);
4543
4544 isKernelCapabilityClient =
4545 typeOfInterest &&
4546 typeOfInterest->isEqualTo(gIOPriorityPowerStateInterest);
4547
4548 if (isSystemCapabilityClient)
4549 typeOfInterest = gIOAppPowerStateInterest;
4550
4551 notifier = super::registerInterest(typeOfInterest, handler, target, ref);
4552 if (notifier && pmPowerStateQueue)
4553 {
4554 if (isSystemCapabilityClient)
4555 {
4556 notifier->retain();
4557 if (pmPowerStateQueue->submitPowerEvent(
4558 kPowerEventRegisterSystemCapabilityClient, notifier) == false)
4559 notifier->release();
4560 }
4561
4562 if (isKernelCapabilityClient)
4563 {
4564 notifier->retain();
4565 if (pmPowerStateQueue->submitPowerEvent(
4566 kPowerEventRegisterKernelCapabilityClient, notifier) == false)
4567 notifier->release();
4568 }
4569 }
4570
4571 return notifier;
4572 }
4573
4574 //******************************************************************************
4575 // systemMessageFilter
4576 //
4577 //******************************************************************************
4578
4579 bool IOPMrootDomain::systemMessageFilter(
4580 void * object, void * arg1, void * arg2, void * arg3 )
4581 {
4582 const IOPMInterestContext * context = (const IOPMInterestContext *) arg1;
4583 bool isCapMsg = (context->messageType == kIOMessageSystemCapabilityChange);
4584 bool isCapClient = false;
4585 bool allow = false;
4586
4587 do {
4588 if ((kSystemTransitionNewCapClient == _systemTransitionType) &&
4589 (!isCapMsg || !_joinedCapabilityClients ||
4590 !_joinedCapabilityClients->containsObject((OSObject *) object)))
4591 break;
4592
4593 // Capability change message for app and kernel clients.
4594
4595 if (isCapMsg)
4596 {
4597 if ((context->notifyType == kNotifyPriority) ||
4598 (context->notifyType == kNotifyCapabilityChangePriority))
4599 isCapClient = true;
4600
4601 if ((context->notifyType == kNotifyCapabilityChangeApps) &&
4602 (object == (void *) systemCapabilityNotifier))
4603 isCapClient = true;
4604 }
4605
4606 if (isCapClient)
4607 {
4608 IOPMSystemCapabilityChangeParameters * capArgs =
4609 (IOPMSystemCapabilityChangeParameters *) arg2;
4610
4611 if (kSystemTransitionNewCapClient == _systemTransitionType)
4612 {
4613 capArgs->fromCapabilities = 0;
4614 capArgs->toCapabilities = _currentCapability;
4615 capArgs->changeFlags = 0;
4616 }
4617 else
4618 {
4619 capArgs->fromCapabilities = _currentCapability;
4620 capArgs->toCapabilities = _pendingCapability;
4621
4622 if (context->isPreChange)
4623 capArgs->changeFlags = kIOPMSystemCapabilityWillChange;
4624 else
4625 capArgs->changeFlags = kIOPMSystemCapabilityDidChange;
4626 }
4627
4628 // Capability change messages only go to the PM configd plugin.
4629 // Wait for response post-change if capabilitiy is increasing.
4630 // Wait for response pre-change if capability is decreasing.
4631
4632 if ((context->notifyType == kNotifyCapabilityChangeApps) && arg3 &&
4633 ( (capabilityLoss && context->isPreChange) ||
4634 (!capabilityLoss && !context->isPreChange) ) )
4635 {
4636 // app has not replied yet, wait for it
4637 *((OSObject **) arg3) = kOSBooleanFalse;
4638 }
4639
4640 allow = true;
4641 break;
4642 }
4643
4644 // Capability client will always see kIOMessageCanSystemSleep,
4645 // even for demand sleep.
4646
4647 if ((kIOMessageCanSystemSleep == context->messageType) ||
4648 (kIOMessageSystemWillNotSleep == context->messageType))
4649 {
4650 if (object == (OSObject *) systemCapabilityNotifier)
4651 {
4652 allow = true;
4653 break;
4654 }
4655
4656 // Not idle sleep, don't ask apps.
4657 if (context->changeFlags & kIOPMSkipAskPowerDown)
4658 {
4659 break;
4660 }
4661 }
4662
4663 // Reject capability change messages for legacy clients.
4664 // Reject legacy system sleep messages for capability client.
4665
4666 if (isCapMsg || (object == (OSObject *) systemCapabilityNotifier))
4667 {
4668 break;
4669 }
4670
4671 // Filter system sleep messages.
4672
4673 if ((context->notifyType == kNotifyApps) &&
4674 (_systemMessageClientMask & kSystemMessageClientApp))
4675 {
4676 allow = true;
4677 }
4678 else if ((context->notifyType == kNotifyPriority) &&
4679 (_systemMessageClientMask & kSystemMessageClientKernel))
4680 {
4681 allow = true;
4682 }
4683 }
4684 while (false);
4685
4686 if (allow && isCapMsg && _joinedCapabilityClients)
4687 {
4688 _joinedCapabilityClients->removeObject((OSObject *) object);
4689 if (_joinedCapabilityClients->getCount() == 0)
4690 {
4691 DLOG("destroyed capability client set %p\n",
4692 _joinedCapabilityClients);
4693 _joinedCapabilityClients->release();
4694 _joinedCapabilityClients = 0;
4695 }
4696 }
4697
4698 return allow;
4699 }
4700
4701 //******************************************************************************
4702 // setMaintenanceWakeCalendar
4703 //
4704 //******************************************************************************
4705
4706 IOReturn IOPMrootDomain::setMaintenanceWakeCalendar(
4707 const IOPMCalendarStruct * calendar )
4708 {
4709 OSData * data;
4710 IOReturn ret;
4711
4712 if (!calendar)
4713 return kIOReturnBadArgument;
4714
4715 data = OSData::withBytesNoCopy((void *) calendar, sizeof(*calendar));
4716 if (!data)
4717 return kIOReturnNoMemory;
4718
4719 ret = setPMSetting(gIOPMSettingMaintenanceWakeCalendarKey, data);
4720
4721 data->release();
4722 return ret;
4723 }
4724
4725 // MARK: -
4726 // MARK: Display Wrangler
4727
4728 //******************************************************************************
4729 // displayWranglerNotification
4730 //
4731 // Handle the notification when the IODisplayWrangler changes power state.
4732 //******************************************************************************
4733
4734 IOReturn IOPMrootDomain::displayWranglerNotification(
4735 void * target, void * refCon,
4736 UInt32 messageType, IOService * service,
4737 void * messageArgument, vm_size_t argSize )
4738 {
4739 #if !NO_KERNEL_HID
4740 int displayPowerState;
4741 IOPowerStateChangeNotification * params =
4742 (IOPowerStateChangeNotification *) messageArgument;
4743
4744 if ((messageType != kIOMessageDeviceWillPowerOff) &&
4745 (messageType != kIOMessageDeviceHasPoweredOn))
4746 return kIOReturnUnsupported;
4747
4748 ASSERT_GATED();
4749 if (!gRootDomain)
4750 return kIOReturnUnsupported;
4751
4752 displayPowerState = params->stateNumber;
4753 DLOG("DisplayWrangler message 0x%x, power state %d\n",
4754 (uint32_t) messageType, displayPowerState);
4755
4756 switch (messageType) {
4757 case kIOMessageDeviceWillPowerOff:
4758
4759 // Display wrangler has dropped power due to display idle
4760 // or force system sleep.
4761 //
4762 // 4 Display ON
4763 // 3 Display Dim
4764 // 2 Display Sleep
4765 // 1 Not visible to user
4766 // 0 Not visible to user
4767
4768 if (displayPowerState > 2)
4769 break;
4770
4771 gRootDomain->evaluatePolicy( kStimulusDisplayWranglerSleep );
4772 break;
4773
4774 case kIOMessageDeviceHasPoweredOn:
4775
4776 // Display wrangler has powered on due to user activity
4777 // or wake from sleep.
4778
4779 if ( 4 != displayPowerState )
4780 break;
4781
4782 gRootDomain->evaluatePolicy( kStimulusDisplayWranglerWake );
4783 break;
4784 }
4785 #endif
4786 return kIOReturnUnsupported;
4787 }
4788
4789 //*********************************************************************************
4790 // displayWranglerMatchPublished
4791 //
4792 // Receives a notification when the IODisplayWrangler is published.
4793 // When it's published we install a power state change handler.
4794 //******************************************************************************
4795
4796 bool IOPMrootDomain::displayWranglerMatchPublished(
4797 void * target,
4798 void * refCon,
4799 IOService * newService,
4800 IONotifier * notifier __unused)
4801 {
4802 #if !NO_KERNEL_HID
4803 // found the display wrangler, now install a handler
4804 if( !newService->registerInterest( gIOGeneralInterest,
4805 &displayWranglerNotification, target, 0) )
4806 {
4807 return false;
4808 }
4809 #endif
4810 return true;
4811 }
4812
4813 //******************************************************************************
4814 // reportUserInput
4815 //
4816 //******************************************************************************
4817
4818 void IOPMrootDomain::reportUserInput( void )
4819 {
4820 #if !NO_KERNEL_HID
4821 OSIterator * iter;
4822
4823 if(!wrangler)
4824 {
4825 iter = getMatchingServices(serviceMatching("IODisplayWrangler"));
4826 if(iter)
4827 {
4828 wrangler = (IOService *) iter->getNextObject();
4829 iter->release();
4830 }
4831 }
4832
4833 if(wrangler)
4834 wrangler->activityTickle(0,0);
4835 #endif
4836 }
4837
4838 // MARK: -
4839 // MARK: Battery
4840
4841 //******************************************************************************
4842 // batteryPublished
4843 //
4844 // Notification on battery class IOPowerSource appearance
4845 //******************************************************************************
4846
4847 bool IOPMrootDomain::batteryPublished(
4848 void * target,
4849 void * root_domain,
4850 IOService * resourceService,
4851 IONotifier * notifier __unused )
4852 {
4853 // rdar://2936060&4435589
4854 // All laptops have dimmable LCD displays
4855 // All laptops have batteries
4856 // So if this machine has a battery, publish the fact that the backlight
4857 // supports dimming.
4858 ((IOPMrootDomain *)root_domain)->publishFeature("DisplayDims");
4859
4860 return (true);
4861 }
4862
4863 // MARK: -
4864 // MARK: System PM Policy
4865
4866 //******************************************************************************
4867 // checkSystemCanSleep
4868 //
4869 //******************************************************************************
4870
4871 bool IOPMrootDomain::checkSystemCanSleep( IOOptionBits options )
4872 {
4873 int err = 0;
4874
4875 // Conditions that prevent idle and demand system sleep.
4876
4877 do {
4878 if (userDisabledAllSleep)
4879 {
4880 err = 1; // 1. user-space sleep kill switch
4881 break;
4882 }
4883
4884 if (systemBooting || systemShutdown)
4885 {
4886 err = 2; // 2. restart or shutdown in progress
4887 break;
4888 }
4889
4890 if (options == 0)
4891 break;
4892
4893 // Conditions above pegs the system at full wake.
4894 // Conditions below prevent system sleep but does not prevent
4895 // dark wake, and must be called from gated context.
4896
4897 #if !CONFIG_SLEEP
4898 err = 3; // 3. config does not support sleep
4899 break;
4900 #endif
4901
4902 if (lowBatteryCondition)
4903 {
4904 break; // always sleep on low battery
4905 }
4906
4907 if (childPreventSystemSleep)
4908 {
4909 err = 4; // 4. child prevent system sleep clamp
4910 break;
4911 }
4912
4913 if (getPMAssertionLevel( kIOPMDriverAssertionCPUBit ) ==
4914 kIOPMDriverAssertionLevelOn)
4915 {
4916 err = 5; // 5. CPU assertion
4917 break;
4918 }
4919
4920 if (pciCantSleepValid)
4921 {
4922 if (pciCantSleepFlag)
4923 err = 6; // 6. PCI card does not support PM (cached)
4924 break;
4925 }
4926 else if (sleepSupportedPEFunction &&
4927 CAP_HIGHEST(kIOPMSystemCapabilityGraphics))
4928 {
4929 IOReturn ret;
4930 OSBitAndAtomic(~kPCICantSleep, &platformSleepSupport);
4931 ret = getPlatform()->callPlatformFunction(
4932 sleepSupportedPEFunction, false,
4933 NULL, NULL, NULL, NULL);
4934 pciCantSleepValid = true;
4935 pciCantSleepFlag = false;
4936 if ((platformSleepSupport & kPCICantSleep) ||
4937 ((ret != kIOReturnSuccess) && (ret != kIOReturnUnsupported)))
4938 {
4939 err = 6; // 6. PCI card does not support PM
4940 pciCantSleepFlag = true;
4941 break;
4942 }
4943 }
4944 }
4945 while (false);
4946
4947 if (err)
4948 {
4949 DLOG("System sleep prevented by %d\n", err);
4950 return false;
4951 }
4952 return true;
4953 }
4954
4955 //******************************************************************************
4956 // adjustPowerState
4957 //
4958 // Conditions that affect our wake/sleep decision has changed.
4959 // If conditions dictate that the system must remain awake, clamp power
4960 // state to max with changePowerStateToPriv(ON). Otherwise if sleepASAP
4961 // is TRUE, then remove the power clamp and allow the power state to drop
4962 // to SLEEP_STATE.
4963 //******************************************************************************
4964
4965 void IOPMrootDomain::adjustPowerState( bool sleepASAP )
4966 {
4967 DLOG("adjustPowerState ps %u, asap %d, slider %ld\n",
4968 (uint32_t) getPowerState(), sleepASAP, sleepSlider);
4969
4970 ASSERT_GATED();
4971
4972 if ((sleepSlider == 0) || !checkSystemCanSleep())
4973 {
4974 changePowerStateToPriv(ON_STATE);
4975 }
4976 else if ( sleepASAP )
4977 {
4978 changePowerStateToPriv(SLEEP_STATE);
4979 }
4980 }
4981
4982 //******************************************************************************
4983 // dispatchPowerEvent
4984 //
4985 // IOPMPowerStateQueue callback function. Running on PM work loop thread.
4986 //******************************************************************************
4987
4988 void IOPMrootDomain::dispatchPowerEvent(
4989 uint32_t event, void * arg0, uint64_t arg1 )
4990 {
4991 DLOG("power event %u args %p 0x%llx\n", event, arg0, arg1);
4992 ASSERT_GATED();
4993
4994 switch (event)
4995 {
4996 case kPowerEventFeatureChanged:
4997 messageClients(kIOPMMessageFeatureChange, this);
4998 break;
4999
5000 case kPowerEventReceivedPowerNotification:
5001 handlePowerNotification( (UInt32)(uintptr_t) arg0 );
5002 break;
5003
5004 case kPowerEventSystemBootCompleted:
5005 if (systemBooting)
5006 {
5007 systemBooting = false;
5008
5009 // If lid is closed, re-send lid closed notification
5010 // now that booting is complete.
5011 if ( clamshellClosed )
5012 {
5013 handlePowerNotification(kLocalEvalClamshellCommand);
5014 }
5015 evaluatePolicy( kStimulusAllowSystemSleepChanged );
5016 }
5017 break;
5018
5019 case kPowerEventSystemShutdown:
5020 if (kOSBooleanTrue == (OSBoolean *) arg0)
5021 {
5022 /* We set systemShutdown = true during shutdown
5023 to prevent sleep at unexpected times while loginwindow is trying
5024 to shutdown apps and while the OS is trying to transition to
5025 complete power of.
5026
5027 Set to true during shutdown, as soon as loginwindow shows
5028 the "shutdown countdown dialog", through individual app
5029 termination, and through black screen kernel shutdown.
5030 */
5031 systemShutdown = true;
5032 } else {
5033 /*
5034 A shutdown was initiated, but then the shutdown
5035 was cancelled, clearing systemShutdown to false here.
5036 */
5037 systemShutdown = false;
5038 }
5039 break;
5040
5041 case kPowerEventUserDisabledSleep:
5042 userDisabledAllSleep = (kOSBooleanTrue == (OSBoolean *) arg0);
5043 break;
5044
5045 case kPowerEventRegisterSystemCapabilityClient:
5046 if (systemCapabilityNotifier)
5047 {
5048 systemCapabilityNotifier->release();
5049 systemCapabilityNotifier = 0;
5050 }
5051 if (arg0)
5052 {
5053 systemCapabilityNotifier = (IONotifier *) arg0;
5054 systemCapabilityNotifier->retain();
5055 }
5056 /* intentional fall-through */
5057
5058 case kPowerEventRegisterKernelCapabilityClient:
5059 if (!_joinedCapabilityClients)
5060 _joinedCapabilityClients = OSSet::withCapacity(8);
5061 if (arg0)
5062 {
5063 IONotifier * notify = (IONotifier *) arg0;
5064 if (_joinedCapabilityClients)
5065 {
5066 _joinedCapabilityClients->setObject(notify);
5067 synchronizePowerTree( kIOPMSyncNoChildNotify );
5068 }
5069 notify->release();
5070 }
5071 break;
5072
5073 case kPowerEventPolicyStimulus:
5074 if (arg0)
5075 {
5076 int stimulus = (uintptr_t) arg0;
5077 evaluatePolicy( stimulus, (uint32_t) arg1 );
5078 }
5079 break;
5080
5081 case kPowerEventAssertionCreate:
5082 if (pmAssertions) {
5083 pmAssertions->handleCreateAssertion((OSData *)arg0);
5084 }
5085 break;
5086
5087
5088 case kPowerEventAssertionRelease:
5089 if (pmAssertions) {
5090 pmAssertions->handleReleaseAssertion(arg1);
5091 }
5092 break;
5093
5094 case kPowerEventAssertionSetLevel:
5095 if (pmAssertions) {
5096 pmAssertions->handleSetAssertionLevel(arg1, (IOPMDriverAssertionLevel)(uintptr_t)arg0);
5097 }
5098 break;
5099
5100 case kPowerEventQueueSleepWakeUUID:
5101 handleQueueSleepWakeUUID((OSObject *)arg0);
5102 break;
5103 case kPowerEventPublishSleepWakeUUID:
5104 handlePublishSleepWakeUUID((bool)arg0);
5105 break;
5106 }
5107 }
5108
5109 //******************************************************************************
5110 // systemPowerEventOccurred
5111 //
5112 // The power controller is notifying us of a hardware-related power management
5113 // event that we must handle.
5114 //
5115 // systemPowerEventOccurred covers the same functionality that
5116 // receivePowerNotification does; it simply provides a richer API for conveying
5117 // more information.
5118 //******************************************************************************
5119
5120 IOReturn IOPMrootDomain::systemPowerEventOccurred(
5121 const OSSymbol *event,
5122 uint32_t intValue)
5123 {
5124 IOReturn attempt = kIOReturnSuccess;
5125 OSNumber *newNumber = NULL;
5126
5127 if (!event)
5128 return kIOReturnBadArgument;
5129
5130 newNumber = OSNumber::withNumber(intValue, 8*sizeof(intValue));
5131 if (!newNumber)
5132 return kIOReturnInternalError;
5133
5134 attempt = systemPowerEventOccurred(event, (OSObject *)newNumber);
5135
5136 newNumber->release();
5137
5138 return attempt;
5139 }
5140
5141 IOReturn IOPMrootDomain::systemPowerEventOccurred(
5142 const OSSymbol *event,
5143 OSObject *value)
5144 {
5145 OSDictionary *thermalsDict = NULL;
5146 bool shouldUpdate = true;
5147
5148 if (!event || !value)
5149 return kIOReturnBadArgument;
5150
5151 // LOCK
5152 // We reuse featuresDict Lock because it already exists and guards
5153 // the very infrequently used publish/remove feature mechanism; so there's zero rsk
5154 // of stepping on that lock.
5155 if (featuresDictLock) IOLockLock(featuresDictLock);
5156
5157 thermalsDict = (OSDictionary *)getProperty(kIOPMRootDomainPowerStatusKey);
5158
5159 if (thermalsDict && OSDynamicCast(OSDictionary, thermalsDict)) {
5160 thermalsDict = OSDictionary::withDictionary(thermalsDict);
5161 } else {
5162 thermalsDict = OSDictionary::withCapacity(1);
5163 }
5164
5165 if (!thermalsDict) {
5166 shouldUpdate = false;
5167 goto exit;
5168 }
5169
5170 thermalsDict->setObject (event, value);
5171
5172 setProperty (kIOPMRootDomainPowerStatusKey, thermalsDict);
5173
5174 thermalsDict->release();
5175
5176 exit:
5177 // UNLOCK
5178 if (featuresDictLock) IOLockUnlock(featuresDictLock);
5179
5180 if (shouldUpdate)
5181 messageClients (kIOPMMessageSystemPowerEventOccurred, (void *)NULL);
5182
5183 return kIOReturnSuccess;
5184 }
5185
5186 //******************************************************************************
5187 // receivePowerNotification
5188 //
5189 // The power controller is notifying us of a hardware-related power management
5190 // event that we must handle. This may be a result of an 'environment' interrupt
5191 // from the power mgt micro.
5192 //******************************************************************************
5193
5194 IOReturn IOPMrootDomain::receivePowerNotification( UInt32 msg )
5195 {
5196 pmPowerStateQueue->submitPowerEvent(
5197 kPowerEventReceivedPowerNotification, (void *) msg );
5198 return kIOReturnSuccess;
5199 }
5200
5201 void IOPMrootDomain::handlePowerNotification( UInt32 msg )
5202 {
5203 bool eval_clamshell = false;
5204
5205 ASSERT_GATED();
5206
5207 /*
5208 * Local (IOPMrootDomain only) eval clamshell command
5209 */
5210 if (msg & kLocalEvalClamshellCommand)
5211 {
5212 eval_clamshell = true;
5213 }
5214
5215 /*
5216 * Overtemp
5217 */
5218 if (msg & kIOPMOverTemp)
5219 {
5220 MSG("PowerManagement emergency overtemp signal. Going to sleep!");
5221 privateSleepSystem (kIOPMSleepReasonThermalEmergency);
5222 }
5223
5224 /*
5225 * Sleep Now!
5226 */
5227 if (msg & kIOPMSleepNow)
5228 {
5229 privateSleepSystem (kIOPMSleepReasonSoftware);
5230 }
5231
5232 /*
5233 * Power Emergency
5234 */
5235 if (msg & kIOPMPowerEmergency)
5236 {
5237 lowBatteryCondition = true;
5238 privateSleepSystem (kIOPMSleepReasonLowPower);
5239 }
5240
5241 /*
5242 * Clamshell OPEN
5243 */
5244 if (msg & kIOPMClamshellOpened)
5245 {
5246 // Received clamshel open message from clamshell controlling driver
5247 // Update our internal state and tell general interest clients
5248 clamshellClosed = false;
5249 clamshellExists = true;
5250
5251 if (msg & kIOPMSetValue)
5252 {
5253 reportUserInput();
5254 }
5255
5256 // Tell PMCPU
5257 informCPUStateChange(kInformLid, 0);
5258
5259 // Tell general interest clients
5260 sendClientClamshellNotification();
5261
5262 bool aborting = ((lastSleepReason == kIOPMSleepReasonClamshell)
5263 || (lastSleepReason == kIOPMSleepReasonIdle)
5264 || (lastSleepReason == kIOPMSleepReasonMaintenance));
5265 if (aborting) userActivityCount++;
5266 DLOG("clamshell tickled %d lastSleepReason %d\n", userActivityCount, lastSleepReason);
5267 }
5268
5269 /*
5270 * Clamshell CLOSED
5271 * Send the clamshell interest notification since the lid is closing.
5272 */
5273 if (msg & kIOPMClamshellClosed)
5274 {
5275 // Received clamshel open message from clamshell controlling driver
5276 // Update our internal state and tell general interest clients
5277 clamshellClosed = true;
5278 clamshellExists = true;
5279
5280 // Tell PMCPU
5281 informCPUStateChange(kInformLid, 1);
5282
5283 // Tell general interest clients
5284 sendClientClamshellNotification();
5285
5286 // And set eval_clamshell = so we can attempt
5287 eval_clamshell = true;
5288 }
5289
5290 /*
5291 * Set Desktop mode (sent from graphics)
5292 *
5293 * -> reevaluate lid state
5294 */
5295 if (msg & kIOPMSetDesktopMode)
5296 {
5297 desktopMode = (0 != (msg & kIOPMSetValue));
5298 msg &= ~(kIOPMSetDesktopMode | kIOPMSetValue);
5299
5300 sendClientClamshellNotification();
5301
5302 // Re-evaluate the lid state
5303 if( clamshellClosed )
5304 {
5305 eval_clamshell = true;
5306 }
5307 }
5308
5309 /*
5310 * AC Adaptor connected
5311 *
5312 * -> reevaluate lid state
5313 */
5314 if (msg & kIOPMSetACAdaptorConnected)
5315 {
5316 acAdaptorConnected = (0 != (msg & kIOPMSetValue));
5317 msg &= ~(kIOPMSetACAdaptorConnected | kIOPMSetValue);
5318
5319 // Tell CPU PM
5320 informCPUStateChange(kInformAC, !acAdaptorConnected);
5321
5322 // Tell BSD if AC is connected
5323 // 0 == external power source; 1 == on battery
5324 post_sys_powersource(acAdaptorConnected ? 0:1);
5325
5326 sendClientClamshellNotification();
5327
5328 // Re-evaluate the lid state
5329 if( clamshellClosed )
5330 {
5331 eval_clamshell = true;
5332 }
5333 }
5334
5335 /*
5336 * Enable Clamshell (external display disappear)
5337 *
5338 * -> reevaluate lid state
5339 */
5340 if (msg & kIOPMEnableClamshell)
5341 {
5342 // Re-evaluate the lid state
5343 // System should sleep on external display disappearance
5344 // in lid closed operation.
5345 if( clamshellClosed && (true == clamshellDisabled) )
5346 {
5347 eval_clamshell = true;
5348 }
5349
5350 clamshellDisabled = false;
5351
5352 sendClientClamshellNotification();
5353 }
5354
5355 /*
5356 * Disable Clamshell (external display appeared)
5357 * We don't bother re-evaluating clamshell state. If the system is awake,
5358 * the lid is probably open.
5359 */
5360 if (msg & kIOPMDisableClamshell)
5361 {
5362 clamshellDisabled = true;
5363
5364 sendClientClamshellNotification();
5365 }
5366
5367 /*
5368 * Evaluate clamshell and SLEEP if appropiate
5369 */
5370 if ( eval_clamshell && shouldSleepOnClamshellClosed() )
5371 {
5372
5373
5374 // SLEEP!
5375 privateSleepSystem (kIOPMSleepReasonClamshell);
5376 }
5377 else if ( eval_clamshell )
5378 {
5379 evaluatePolicy(kStimulusDarkWakeEvaluate);
5380 }
5381
5382 /*
5383 * Power Button
5384 */
5385 if (msg & kIOPMPowerButton)
5386 {
5387 if (!wranglerAsleep)
5388 {
5389 OSString *pbs = OSString::withCString("DisablePowerButtonSleep");
5390 // Check that power button sleep is enabled
5391 if( pbs ) {
5392 if( kOSBooleanTrue != getProperty(pbs))
5393 privateSleepSystem (kIOPMSleepReasonPowerButton);
5394 }
5395 }
5396 else
5397 reportUserInput();
5398 }
5399 }
5400
5401 //******************************************************************************
5402 // evaluatePolicy
5403 //
5404 // Evaluate root-domain policy in response to external changes.
5405 //******************************************************************************
5406
5407 void IOPMrootDomain::evaluatePolicy( int stimulus, uint32_t arg )
5408 {
5409 union {
5410 struct {
5411 int idleSleepEnabled : 1;
5412 int idleSleepDisabled : 1;
5413 int displaySleep : 1;
5414 int sleepDelayChanged : 1;
5415 int evaluateDarkWake : 1;
5416 } bit;
5417 uint32_t u32;
5418 } flags;
5419
5420 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
5421
5422 ASSERT_GATED();
5423 flags.u32 = 0;
5424
5425 switch (stimulus)
5426 {
5427 case kStimulusDisplayWranglerSleep:
5428 if (!wranglerAsleep)
5429 {
5430 wranglerAsleep = true;
5431 clock_get_uptime(&wranglerSleepTime);
5432 flags.bit.displaySleep = true;
5433 }
5434 break;
5435
5436 case kStimulusDisplayWranglerWake:
5437 wranglerAsleep = false;
5438 flags.bit.idleSleepDisabled = true;
5439 break;
5440
5441 case kStimulusAggressivenessChanged:
5442 {
5443 unsigned long minutesToIdleSleep = 0;
5444 unsigned long minutesToDisplayDim = 0;
5445 unsigned long minutesDelta = 0;
5446
5447 // Fetch latest display and system sleep slider values.
5448 getAggressiveness(kPMMinutesToSleep, &minutesToIdleSleep);
5449 getAggressiveness(kPMMinutesToDim, &minutesToDisplayDim);
5450 DLOG("aggressiveness changed: system %u->%u, display %u\n",
5451 (uint32_t) sleepSlider,
5452 (uint32_t) minutesToIdleSleep,
5453 (uint32_t) minutesToDisplayDim);
5454
5455 DLOG("idle time -> %ld secs (ena %d)\n",
5456 idleSeconds, (minutesToIdleSleep != 0));
5457
5458 if (0x7fffffff == minutesToIdleSleep)
5459 minutesToIdleSleep = idleSeconds;
5460
5461 // How long to wait before sleeping the system once
5462 // the displays turns off is indicated by 'extraSleepDelay'.
5463
5464 if ( minutesToIdleSleep > minutesToDisplayDim )
5465 minutesDelta = minutesToIdleSleep - minutesToDisplayDim;
5466
5467 if ((sleepSlider == 0) && (minutesToIdleSleep != 0))
5468 flags.bit.idleSleepEnabled = true;
5469
5470 if ((sleepSlider != 0) && (minutesToIdleSleep == 0))
5471 flags.bit.idleSleepDisabled = true;
5472
5473 if ((minutesDelta != extraSleepDelay) &&
5474 !flags.bit.idleSleepEnabled && !flags.bit.idleSleepDisabled)
5475 flags.bit.sleepDelayChanged = true;
5476
5477 if (systemDarkWake && !darkWakeToSleepASAP &&
5478 (flags.bit.idleSleepEnabled || flags.bit.idleSleepDisabled))
5479 {
5480 // Reconsider decision to remain in dark wake
5481 flags.bit.evaluateDarkWake = true;
5482 }
5483
5484 sleepSlider = minutesToIdleSleep;
5485 extraSleepDelay = minutesDelta;
5486 } break;
5487
5488 case kStimulusDemandSystemSleep:
5489 changePowerStateWithOverrideTo( SLEEP_STATE );
5490 break;
5491
5492 case kStimulusAllowSystemSleepChanged:
5493 // FIXME: de-compose to change flags.
5494 adjustPowerState();
5495 break;
5496
5497 case kStimulusDarkWakeActivityTickle:
5498 if (false == wranglerTickled)
5499 {
5500 uint32_t options = 0;
5501 IOService * pciRoot = 0;
5502
5503 if (rejectWranglerTickle)
5504 {
5505 DLOG("rejected tickle, type %u capability %x:%x\n",
5506 _systemTransitionType,
5507 _currentCapability, _pendingCapability);
5508 break;
5509 }
5510
5511 _desiredCapability |=
5512 (kIOPMSystemCapabilityGraphics |
5513 kIOPMSystemCapabilityAudio);
5514
5515 if ((kSystemTransitionWake == _systemTransitionType) &&
5516 !(_pendingCapability & kIOPMSystemCapabilityGraphics) &&
5517 !graphicsSuppressed)
5518 {
5519 DLOG("Promoting to full wake\n");
5520
5521 // Elevate to full wake while waking up to dark wake.
5522 // PM will hold off notifying the graphics subsystem about
5523 // system wake as late as possible, so if a HID event does
5524 // arrive, we can turn on graphics on this wake cycle, and
5525 // not have to wait till the following cycle. That latency
5526 // can be huge on some systems. However, once any graphics
5527 // suppression has taken effect, it is too late. All other
5528 // graphics devices must be similarly suppressed. But the
5529 // delay till the following cycle should be very short.
5530
5531 _pendingCapability |=
5532 (kIOPMSystemCapabilityGraphics |
5533 kIOPMSystemCapabilityAudio);
5534
5535 // Immediately bring up audio and graphics.
5536 pciRoot = pciHostBridgeDriver;
5537
5538 // Notify clients about full wake.
5539 _systemMessageClientMask = kSystemMessageClientAll;
5540 tellClients(kIOMessageSystemWillPowerOn);
5541 }
5542
5543 // Unsafe to cancel once graphics was powered.
5544 // If system woke from dark wake, the return to sleep can
5545 // be cancelled. But "awake -> dark -> sleep" transition
5546 // cannot be cancelled.
5547
5548 if (!CAP_HIGHEST(kIOPMSystemCapabilityGraphics)) {
5549 options |= kIOPMSyncCancelPowerDown;
5550 }
5551
5552 synchronizePowerTree( options, pciRoot );
5553 wranglerTickled = true;
5554 // IOGraphics doesn't lit the display even though graphics
5555 // is enanbled in kIOMessageSystemCapabilityChange message(radar 9502104)
5556 // So, do an explicit activity tickle
5557 if(wrangler)
5558 wrangler->activityTickle(0,0);
5559
5560 if (logWranglerTickle)
5561 {
5562 AbsoluteTime now;
5563 uint64_t nsec;
5564
5565 clock_get_uptime(&now);
5566 SUB_ABSOLUTETIME(&now, &systemWakeTime);
5567 absolutetime_to_nanoseconds(now, &nsec);
5568 MSG("HID tickle %u ms\n",
5569 ((int)((nsec) / 1000000ULL)));
5570 logWranglerTickle = false;
5571 }
5572 }
5573 break;
5574
5575 case kStimulusDarkWakeEntry:
5576 case kStimulusDarkWakeReentry:
5577 // Any system transitions since the last dark wake transition
5578 // will invalid the stimulus.
5579
5580 if (arg == _systemStateGeneration)
5581 {
5582 DLOG("dark wake entry\n");
5583 systemDarkWake = true;
5584 wranglerAsleep = true;
5585 clock_get_uptime(&wranglerSleepTime);
5586
5587 // Always accelerate disk spindown while in dark wake,
5588 // even if system does not support/allow sleep.
5589
5590 cancelIdleSleepTimer();
5591 setQuickSpinDownTimeout();
5592 flags.bit.evaluateDarkWake = true;
5593 }
5594 break;
5595
5596 case kStimulusDarkWakeEvaluate:
5597 if (systemDarkWake)
5598 {
5599 flags.bit.evaluateDarkWake = true;
5600 }
5601 #if !DARK_TO_FULL_EVALUATE_CLAMSHELL
5602 else
5603 {
5604 // Not through kLocalEvalClamshellCommand to avoid loop.
5605 if (clamshellClosed && shouldSleepOnClamshellClosed() &&
5606 checkSystemCanSleep(true))
5607 {
5608 privateSleepSystem( kIOPMSleepReasonClamshell );
5609 }
5610 }
5611 #endif
5612 break;
5613
5614 } /* switch(stimulus) */
5615
5616 if (flags.bit.evaluateDarkWake && !wranglerTickled)
5617 {
5618 if (darkWakeToSleepASAP ||
5619 (clamshellClosed && !(desktopMode && acAdaptorConnected)))
5620 {
5621 // System currently in dark wake, and no children and
5622 // assertion prevent system sleep.
5623
5624 if (checkSystemCanSleep(true))
5625 {
5626 if (lowBatteryCondition)
5627 {
5628 lastSleepReason = kIOPMSleepReasonLowPower;
5629 setProperty(kRootDomainSleepReasonKey, kIOPMLowPowerSleepKey);
5630 }
5631 else if (darkWakeMaintenance)
5632 {
5633 lastSleepReason = kIOPMSleepReasonMaintenance;
5634 setProperty(kRootDomainSleepReasonKey, kIOPMMaintenanceSleepKey);
5635 }
5636 changePowerStateWithOverrideTo( SLEEP_STATE );
5637 }
5638 else
5639 {
5640 // Parked in dark wake, a tickle will return to full wake
5641 rejectWranglerTickle = false;
5642 }
5643 } else // non-maintenance (network) dark wake
5644 {
5645 if (checkSystemCanSleep(true))
5646 {
5647 // Release power clamp, and wait for children idle.
5648 adjustPowerState(true);
5649 }
5650 else
5651 {
5652 changePowerStateToPriv(ON_STATE);
5653 }
5654 rejectWranglerTickle = false;
5655 }
5656 }
5657
5658 if (systemDarkWake)
5659 {
5660 // The rest are irrelevant while system is in dark wake.
5661 flags.u32 = 0;
5662 }
5663
5664 if (flags.bit.displaySleep || flags.bit.sleepDelayChanged)
5665 {
5666 bool cancelQuickSpindown = false;
5667
5668 if (flags.bit.sleepDelayChanged)
5669 {
5670 DLOG("extra sleep timer changed\n");
5671 cancelIdleSleepTimer();
5672 cancelQuickSpindown = true;
5673 }
5674 else
5675 {
5676 DLOG("display sleep\n");
5677 }
5678
5679 if (wranglerAsleep && !wranglerSleepIgnored)
5680 {
5681 if ( extraSleepDelay )
5682 {
5683 // Start a timer here if the System Sleep timer is greater
5684 // than the Display Sleep timer.
5685
5686 startIdleSleepTimer(gRootDomain->extraSleepDelay * 60);
5687 }
5688 else if ( sleepSlider )
5689 {
5690 // Accelerate disk spindown if system sleep and display sleep
5691 // sliders are set to the same value (e.g. both set to 5 min),
5692 // and display is about to go dark. Check the system sleep is
5693 // not set to never sleep. Disk sleep setting is ignored.
5694
5695 setQuickSpinDownTimeout();
5696 cancelQuickSpindown = false;
5697 }
5698 }
5699
5700 if (cancelQuickSpindown)
5701 restoreUserSpinDownTimeout();
5702 }
5703
5704 if (flags.bit.idleSleepEnabled)
5705 {
5706 DLOG("idle sleep timer enabled\n");
5707 if (!wrangler)
5708 {
5709 changePowerStateToPriv(ON_STATE);
5710 if (idleSeconds)
5711 {
5712 startIdleSleepTimer( idleSeconds );
5713 }
5714 }
5715 else
5716 {
5717 // Start idle sleep timer if wrangler went to sleep
5718 // while system sleep was disabled. Disk spindown is
5719 // accelerated upon timer expiration.
5720
5721 if (wranglerAsleep)
5722 {
5723 AbsoluteTime now;
5724 uint64_t nanos;
5725 uint32_t minutesSinceDisplaySleep = 0;
5726 uint32_t sleepDelay;
5727
5728 clock_get_uptime(&now);
5729 if (CMP_ABSOLUTETIME(&now, &wranglerSleepTime) > 0)
5730 {
5731 SUB_ABSOLUTETIME(&now, &wranglerSleepTime);
5732 absolutetime_to_nanoseconds(now, &nanos);
5733 minutesSinceDisplaySleep = nanos / (60000000000ULL);
5734 }
5735
5736 if (extraSleepDelay > minutesSinceDisplaySleep)
5737 {
5738 sleepDelay = extraSleepDelay - minutesSinceDisplaySleep;
5739 }
5740 else
5741 {
5742 sleepDelay = 1; // 1 min
5743 }
5744
5745 startIdleSleepTimer(sleepDelay * 60);
5746 DLOG("display slept %u min, set idle timer to %u min\n",
5747 minutesSinceDisplaySleep, sleepDelay);
5748 }
5749 }
5750 }
5751
5752 if (flags.bit.idleSleepDisabled)
5753 {
5754 DLOG("idle sleep timer disabled\n");
5755 cancelIdleSleepTimer();
5756 restoreUserSpinDownTimeout();
5757 adjustPowerState();
5758 }
5759 }
5760
5761 // MARK: -
5762 // MARK: Statistics
5763
5764 //******************************************************************************
5765 // pmStats
5766 //
5767 //******************************************************************************
5768
5769 void IOPMrootDomain::pmStatsRecordEvent(
5770 int eventIndex,
5771 AbsoluteTime timestamp)
5772 {
5773 bool starting = eventIndex & kIOPMStatsEventStartFlag ? true:false;
5774 bool stopping = eventIndex & kIOPMStatsEventStopFlag ? true:false;
5775 uint64_t delta;
5776 uint64_t nsec;
5777
5778 eventIndex &= ~(kIOPMStatsEventStartFlag | kIOPMStatsEventStopFlag);
5779
5780 absolutetime_to_nanoseconds(timestamp, &nsec);
5781
5782 switch (eventIndex) {
5783 case kIOPMStatsHibernateImageWrite:
5784 if (starting)
5785 pmStats.hibWrite.start = nsec;
5786 else if (stopping)
5787 pmStats.hibWrite.stop = nsec;
5788
5789 if (stopping) {
5790 delta = pmStats.hibWrite.stop - pmStats.hibWrite.start;
5791 IOLog("PMStats: Hibernate write took %qd ms\n", delta/1000000ULL);
5792 }
5793 break;
5794 case kIOPMStatsHibernateImageRead:
5795 if (starting)
5796 pmStats.hibRead.start = nsec;
5797 else if (stopping)
5798 pmStats.hibRead.stop = nsec;
5799
5800 if (stopping) {
5801 delta = pmStats.hibRead.stop - pmStats.hibRead.start;
5802 IOLog("PMStats: Hibernate read took %qd ms\n", delta/1000000ULL);
5803 }
5804 break;
5805 }
5806 }
5807
5808 /*
5809 * Appends a record of the application response to
5810 * IOPMrootDomain::pmStatsAppResponses
5811 */
5812 void IOPMrootDomain::pmStatsRecordApplicationResponse(
5813 const OSSymbol *response,
5814 const char *name,
5815 int messageType,
5816 uint32_t delay_ms,
5817 int app_pid)
5818 {
5819 OSDictionary *responseDescription = NULL;
5820 OSNumber *delayNum = NULL;
5821 OSNumber *pidNum = NULL;
5822 OSNumber *msgNum = NULL;
5823 const OSSymbol *appname;
5824 const OSSymbol *entryName;
5825 OSObject *entryType;
5826 int i;
5827
5828 if (!pmStatsAppResponses || pmStatsAppResponses->getCount() > 50)
5829 return;
5830
5831 i = 0;
5832 while ((responseDescription = (OSDictionary *) pmStatsAppResponses->getObject(i++)))
5833 {
5834 entryType = responseDescription->getObject(_statsResponseTypeKey);
5835 entryName = (OSSymbol *) responseDescription->getObject(_statsNameKey);
5836 if (entryName && (entryType == response) && entryName->isEqualTo(name))
5837 {
5838 OSNumber * entryValue;
5839 entryValue = (OSNumber *) responseDescription->getObject(_statsTimeMSKey);
5840 if (entryValue && (entryValue->unsigned32BitValue() < delay_ms))
5841 entryValue->setValue(delay_ms);
5842 return;
5843 }
5844 }
5845
5846 responseDescription = OSDictionary::withCapacity(5);
5847 if (responseDescription)
5848 {
5849 if (response) {
5850 responseDescription->setObject(_statsResponseTypeKey, response);
5851 }
5852
5853 if (messageType != 0) {
5854 msgNum = OSNumber::withNumber(messageType, 32);
5855 if (msgNum) {
5856 responseDescription->setObject(_statsMessageTypeKey, msgNum);
5857 msgNum->release();
5858 }
5859 }
5860
5861 if (name && (strlen(name) > 0))
5862 {
5863 appname = OSSymbol::withCString(name);
5864 if (appname) {
5865 responseDescription->setObject(_statsNameKey, appname);
5866 appname->release();
5867 }
5868 }
5869
5870 if (app_pid != -1) {
5871 pidNum = OSNumber::withNumber(app_pid, 32);
5872 if (pidNum) {
5873 responseDescription->setObject(_statsPIDKey, pidNum);
5874 pidNum->release();
5875 }
5876 }
5877
5878 delayNum = OSNumber::withNumber(delay_ms, 32);
5879 if (delayNum) {
5880 responseDescription->setObject(_statsTimeMSKey, delayNum);
5881 delayNum->release();
5882 }
5883
5884 if (pmStatsAppResponses) {
5885 pmStatsAppResponses->setObject(responseDescription);
5886 }
5887
5888 responseDescription->release();
5889 }
5890 return;
5891 }
5892
5893 // MARK: -
5894 // MARK: PMTraceWorker
5895
5896 //******************************************************************************
5897 // TracePoint support
5898 //
5899 //******************************************************************************
5900
5901 #define kIOPMRegisterNVRAMTracePointHandlerKey \
5902 "IOPMRegisterNVRAMTracePointHandler"
5903
5904 IOReturn IOPMrootDomain::callPlatformFunction(
5905 const OSSymbol * functionName,
5906 bool waitForFunction,
5907 void * param1, void * param2,
5908 void * param3, void * param4 )
5909 {
5910 if (pmTracer && functionName &&
5911 functionName->isEqualTo(kIOPMRegisterNVRAMTracePointHandlerKey) &&
5912 !pmTracer->tracePointHandler && !pmTracer->tracePointTarget)
5913 {
5914 uint32_t tracePointPhases, tracePointPCI;
5915 uint64_t statusCode;
5916
5917 pmTracer->tracePointHandler = (IOPMTracePointHandler) param1;
5918 pmTracer->tracePointTarget = (void *) param2;
5919 tracePointPCI = (uint32_t)(uintptr_t) param3;
5920 tracePointPhases = (uint32_t)(uintptr_t) param4;
5921 statusCode = (((uint64_t)tracePointPCI) << 32) | tracePointPhases;
5922 if ((tracePointPhases >> 24) != kIOPMTracePointSystemUp)
5923 {
5924 MSG("Sleep failure code 0x%08x 0x%08x\n",
5925 tracePointPCI, tracePointPhases);
5926 }
5927 setProperty(kIOPMSleepWakeFailureCodeKey, statusCode, 64);
5928 pmTracer->tracePointHandler( pmTracer->tracePointTarget, 0, 0 );
5929
5930 return kIOReturnSuccess;
5931 }
5932
5933 return super::callPlatformFunction(
5934 functionName, waitForFunction, param1, param2, param3, param4);
5935 }
5936
5937 void IOPMrootDomain::tracePoint( uint8_t point )
5938 {
5939 if (!systemBooting)
5940 pmTracer->tracePoint(point);
5941 }
5942
5943 void IOPMrootDomain::tracePoint( uint8_t point, uint8_t data )
5944 {
5945 if (!systemBooting)
5946 pmTracer->tracePoint(point, data);
5947 }
5948
5949 void IOPMrootDomain::traceDetail( uint32_t detail )
5950 {
5951 if (!systemBooting)
5952 pmTracer->traceDetail( detail );
5953 }
5954
5955 //******************************************************************************
5956 // PMTraceWorker Class
5957 //
5958 //******************************************************************************
5959
5960 #undef super
5961 #define super OSObject
5962 OSDefineMetaClassAndStructors(PMTraceWorker, OSObject)
5963
5964 #define kPMBestGuessPCIDevicesCount 25
5965 #define kPMMaxRTCBitfieldSize 32
5966
5967 PMTraceWorker *PMTraceWorker::tracer(IOPMrootDomain *owner)
5968 {
5969 PMTraceWorker *me;
5970
5971 me = OSTypeAlloc( PMTraceWorker );
5972 if (!me || !me->init())
5973 {
5974 return NULL;
5975 }
5976
5977 DLOG("PMTraceWorker %p\n", me);
5978
5979 // Note that we cannot instantiate the PCI device -> bit mappings here, since
5980 // the IODeviceTree has not yet been created by IOPlatformExpert. We create
5981 // this dictionary lazily.
5982 me->owner = owner;
5983 me->pciDeviceBitMappings = NULL;
5984 me->pciMappingLock = IOLockAlloc();
5985 me->tracePhase = kIOPMTracePointSystemUp;
5986 me->loginWindowPhase = 0;
5987 me->traceData32 = 0;
5988 return me;
5989 }
5990
5991 void PMTraceWorker::RTC_TRACE(void)
5992 {
5993 if (tracePointHandler && tracePointTarget)
5994 {
5995 uint32_t wordA;
5996
5997 wordA = (tracePhase << 24) | (loginWindowPhase << 16) |
5998 (traceData8 << 8);
5999
6000 tracePointHandler( tracePointTarget, traceData32, wordA );
6001 _LOG("RTC_TRACE wrote 0x%08x 0x%08x\n", traceData32, wordA);
6002 }
6003 }
6004
6005 int PMTraceWorker::recordTopLevelPCIDevice(IOService * pciDevice)
6006 {
6007 const OSSymbol * deviceName;
6008 int index = -1;
6009
6010 IOLockLock(pciMappingLock);
6011
6012 if (!pciDeviceBitMappings)
6013 {
6014 pciDeviceBitMappings = OSArray::withCapacity(kPMBestGuessPCIDevicesCount);
6015 if (!pciDeviceBitMappings)
6016 goto exit;
6017 }
6018
6019 // Check for bitmask overflow.
6020 if (pciDeviceBitMappings->getCount() >= kPMMaxRTCBitfieldSize)
6021 goto exit;
6022
6023 if ((deviceName = pciDevice->copyName()) &&
6024 (pciDeviceBitMappings->getNextIndexOfObject(deviceName, 0) == (unsigned int)-1) &&
6025 pciDeviceBitMappings->setObject(deviceName))
6026 {
6027 index = pciDeviceBitMappings->getCount() - 1;
6028 _LOG("PMTrace PCI array: set object %s => %d\n",
6029 deviceName->getCStringNoCopy(), index);
6030 }
6031 if (deviceName)
6032 deviceName->release();
6033 if (!addedToRegistry && (index >= 0))
6034 addedToRegistry = owner->setProperty("PCITopLevel", this);
6035
6036 exit:
6037 IOLockUnlock(pciMappingLock);
6038 return index;
6039 }
6040
6041 bool PMTraceWorker::serialize(OSSerialize *s) const
6042 {
6043 bool ok = false;
6044 if (pciDeviceBitMappings)
6045 {
6046 IOLockLock(pciMappingLock);
6047 ok = pciDeviceBitMappings->serialize(s);
6048 IOLockUnlock(pciMappingLock);
6049 }
6050 return ok;
6051 }
6052
6053 void PMTraceWorker::tracePoint(uint8_t phase)
6054 {
6055 // clear trace detail when phase begins
6056 if (tracePhase != phase)
6057 traceData32 = 0;
6058
6059 tracePhase = phase;
6060
6061 DLOG("trace point 0x%02x\n", tracePhase);
6062 RTC_TRACE();
6063 }
6064
6065 void PMTraceWorker::tracePoint(uint8_t phase, uint8_t data8)
6066 {
6067 // clear trace detail when phase begins
6068 if (tracePhase != phase)
6069 traceData32 = 0;
6070
6071 tracePhase = phase;
6072 traceData8 = data8;
6073
6074 DLOG("trace point 0x%02x 0x%02x\n", tracePhase, traceData8);
6075 RTC_TRACE();
6076 }
6077
6078 void PMTraceWorker::traceDetail(uint32_t detail)
6079 {
6080 if (kIOPMTracePointSleepPriorityClients != tracePhase)
6081 return;
6082
6083 traceData32 = detail;
6084 DLOG("trace point 0x%02x detail 0x%08x\n", tracePhase, traceData32);
6085
6086 RTC_TRACE();
6087 }
6088
6089 void PMTraceWorker::traceLoginWindowPhase(uint8_t phase)
6090 {
6091 loginWindowPhase = phase;
6092
6093 DLOG("loginwindow tracepoint 0x%02x\n", loginWindowPhase);
6094 RTC_TRACE();
6095 }
6096
6097 void PMTraceWorker::tracePCIPowerChange(
6098 change_t type, IOService *service, uint32_t changeFlags, uint32_t bitNum)
6099 {
6100 uint32_t bitMask;
6101 uint32_t expectedFlag;
6102
6103 // Ignore PCI changes outside of system sleep/wake.
6104 if ((kIOPMTracePointSleepPowerPlaneDrivers != tracePhase) &&
6105 (kIOPMTracePointWakePowerPlaneDrivers != tracePhase))
6106 return;
6107
6108 // Only record the WillChange transition when going to sleep,
6109 // and the DidChange on the way up.
6110 changeFlags &= (kIOPMDomainWillChange | kIOPMDomainDidChange);
6111 expectedFlag = (kIOPMTracePointSleepPowerPlaneDrivers == tracePhase) ?
6112 kIOPMDomainWillChange : kIOPMDomainDidChange;
6113 if (changeFlags != expectedFlag)
6114 return;
6115
6116 // Mark this device off in our bitfield
6117 if (bitNum < kPMMaxRTCBitfieldSize)
6118 {
6119 bitMask = (1 << bitNum);
6120
6121 if (kPowerChangeStart == type)
6122 {
6123 traceData32 |= bitMask;
6124 _LOG("PMTrace: Device %s started - bit %2d mask 0x%08x => 0x%08x\n",
6125 service->getName(), bitNum, bitMask, traceData32);
6126 }
6127 else
6128 {
6129 traceData32 &= ~bitMask;
6130 _LOG("PMTrace: Device %s finished - bit %2d mask 0x%08x => 0x%08x\n",
6131 service->getName(), bitNum, bitMask, traceData32);
6132 }
6133
6134 RTC_TRACE();
6135 }
6136 }
6137
6138 // MARK: -
6139 // MARK: PMHaltWorker
6140
6141 //******************************************************************************
6142 // PMHaltWorker Class
6143 //
6144 //******************************************************************************
6145
6146 static unsigned int gPMHaltBusyCount;
6147 static unsigned int gPMHaltIdleCount;
6148 static int gPMHaltDepth;
6149 static unsigned long gPMHaltEvent;
6150 static IOLock * gPMHaltLock = 0;
6151 static OSArray * gPMHaltArray = 0;
6152 static const OSSymbol * gPMHaltClientAcknowledgeKey = 0;
6153
6154 PMHaltWorker * PMHaltWorker::worker( void )
6155 {
6156 PMHaltWorker * me;
6157 IOThread thread;
6158
6159 do {
6160 me = OSTypeAlloc( PMHaltWorker );
6161 if (!me || !me->init())
6162 break;
6163
6164 me->lock = IOLockAlloc();
6165 if (!me->lock)
6166 break;
6167
6168 DLOG("PMHaltWorker %p\n", me);
6169 me->retain(); // thread holds extra retain
6170 if (KERN_SUCCESS != kernel_thread_start(&PMHaltWorker::main, (void *) me, &thread))
6171 {
6172 me->release();
6173 break;
6174 }
6175 thread_deallocate(thread);
6176 return me;
6177
6178 } while (false);
6179
6180 if (me) me->release();
6181 return 0;
6182 }
6183
6184 void PMHaltWorker::free( void )
6185 {
6186 DLOG("PMHaltWorker free %p\n", this);
6187 if (lock)
6188 {
6189 IOLockFree(lock);
6190 lock = 0;
6191 }
6192 return OSObject::free();
6193 }
6194
6195 void PMHaltWorker::main( void * arg, wait_result_t waitResult )
6196 {
6197 PMHaltWorker * me = (PMHaltWorker *) arg;
6198
6199 IOLockLock( gPMHaltLock );
6200 gPMHaltBusyCount++;
6201 me->depth = gPMHaltDepth;
6202 IOLockUnlock( gPMHaltLock );
6203
6204 while (me->depth >= 0)
6205 {
6206 PMHaltWorker::work( me );
6207
6208 IOLockLock( gPMHaltLock );
6209 if (++gPMHaltIdleCount >= gPMHaltBusyCount)
6210 {
6211 // This is the last thread to finish work on this level,
6212 // inform everyone to start working on next lower level.
6213 gPMHaltDepth--;
6214 me->depth = gPMHaltDepth;
6215 gPMHaltIdleCount = 0;
6216 thread_wakeup((event_t) &gPMHaltIdleCount);
6217 }
6218 else
6219 {
6220 // One or more threads are still working on this level,
6221 // this thread must wait.
6222 me->depth = gPMHaltDepth - 1;
6223 do {
6224 IOLockSleep(gPMHaltLock, &gPMHaltIdleCount, THREAD_UNINT);
6225 } while (me->depth != gPMHaltDepth);
6226 }
6227 IOLockUnlock( gPMHaltLock );
6228 }
6229
6230 // No more work to do, terminate thread
6231 DLOG("All done for worker: %p (visits = %u)\n", me, me->visits);
6232 thread_wakeup( &gPMHaltDepth );
6233 me->release();
6234 }
6235
6236 void PMHaltWorker::work( PMHaltWorker * me )
6237 {
6238 IOService * service;
6239 OSSet * inner;
6240 AbsoluteTime startTime;
6241 UInt32 deltaTime;
6242 bool timeout;
6243
6244 while (true)
6245 {
6246 service = 0;
6247 timeout = false;
6248
6249 // Claim an unit of work from the shared pool
6250 IOLockLock( gPMHaltLock );
6251 inner = (OSSet *)gPMHaltArray->getObject(me->depth);
6252 if (inner)
6253 {
6254 service = (IOService *)inner->getAnyObject();
6255 if (service)
6256 {
6257 service->retain();
6258 inner->removeObject(service);
6259 }
6260 }
6261 IOLockUnlock( gPMHaltLock );
6262 if (!service)
6263 break; // no more work at this depth
6264
6265 clock_get_uptime(&startTime);
6266
6267 if (!service->isInactive() &&
6268 service->setProperty(gPMHaltClientAcknowledgeKey, me))
6269 {
6270 IOLockLock(me->lock);
6271 me->startTime = startTime;
6272 me->service = service;
6273 me->timeout = false;
6274 IOLockUnlock(me->lock);
6275
6276 service->systemWillShutdown( gPMHaltEvent );
6277
6278 // Wait for driver acknowledgement
6279 IOLockLock(me->lock);
6280 while (service->getProperty(gPMHaltClientAcknowledgeKey))
6281 {
6282 IOLockSleep(me->lock, me, THREAD_UNINT);
6283 }
6284 me->service = 0;
6285 timeout = me->timeout;
6286 IOLockUnlock(me->lock);
6287 }
6288
6289 deltaTime = computeDeltaTimeMS(&startTime);
6290 if ((deltaTime > kPMHaltTimeoutMS) || timeout ||
6291 (gIOKitDebug & kIOLogPMRootDomain))
6292 {
6293 LOG("%s driver %s (%p) took %u ms\n",
6294 (gPMHaltEvent == kIOMessageSystemWillPowerOff) ?
6295 "PowerOff" : "Restart",
6296 service->getName(), service,
6297 (uint32_t) deltaTime );
6298 }
6299
6300 service->release();
6301 me->visits++;
6302 }
6303 }
6304
6305 void PMHaltWorker::checkTimeout( PMHaltWorker * me, AbsoluteTime * now )
6306 {
6307 UInt64 nano;
6308 AbsoluteTime startTime;
6309 AbsoluteTime endTime;
6310
6311 endTime = *now;
6312
6313 IOLockLock(me->lock);
6314 if (me->service && !me->timeout)
6315 {
6316 startTime = me->startTime;
6317 nano = 0;
6318 if (CMP_ABSOLUTETIME(&endTime, &startTime) > 0)
6319 {
6320 SUB_ABSOLUTETIME(&endTime, &startTime);
6321 absolutetime_to_nanoseconds(endTime, &nano);
6322 }
6323 if (nano > 3000000000ULL)
6324 {
6325 me->timeout = true;
6326 MSG("%s still waiting on %s\n",
6327 (gPMHaltEvent == kIOMessageSystemWillPowerOff) ?
6328 "PowerOff" : "Restart",
6329 me->service->getName());
6330 }
6331 }
6332 IOLockUnlock(me->lock);
6333 }
6334
6335
6336 //******************************************************************************
6337 // acknowledgeSystemWillShutdown
6338 //
6339 // Acknowledgement from drivers that they have prepared for shutdown/restart.
6340 //******************************************************************************
6341
6342 void IOPMrootDomain::acknowledgeSystemWillShutdown( IOService * from )
6343 {
6344 PMHaltWorker * worker;
6345 OSObject * prop;
6346
6347 if (!from)
6348 return;
6349
6350 //DLOG("%s acknowledged\n", from->getName());
6351 prop = from->copyProperty( gPMHaltClientAcknowledgeKey );
6352 if (prop)
6353 {
6354 worker = (PMHaltWorker *) prop;
6355 IOLockLock(worker->lock);
6356 from->removeProperty( gPMHaltClientAcknowledgeKey );
6357 thread_wakeup((event_t) worker);
6358 IOLockUnlock(worker->lock);
6359 worker->release();
6360 }
6361 else
6362 {
6363 DLOG("%s acknowledged without worker property\n",
6364 from->getName());
6365 }
6366 }
6367
6368
6369 //******************************************************************************
6370 // notifySystemShutdown
6371 //
6372 // Notify all objects in PM tree that system will shutdown or restart
6373 //******************************************************************************
6374
6375 static void
6376 notifySystemShutdown( IOService * root, unsigned long event )
6377 {
6378 #define PLACEHOLDER ((OSSet *)gPMHaltArray)
6379 IORegistryIterator * iter;
6380 IORegistryEntry * entry;
6381 IOService * node;
6382 OSSet * inner;
6383 PMHaltWorker * workers[kPMHaltMaxWorkers];
6384 AbsoluteTime deadline;
6385 unsigned int totalNodes = 0;
6386 unsigned int depth;
6387 unsigned int rootDepth;
6388 unsigned int numWorkers;
6389 unsigned int count;
6390 int waitResult;
6391 void * baseFunc;
6392 bool ok;
6393
6394 DLOG("%s event = %lx\n", __FUNCTION__, event);
6395
6396 baseFunc = OSMemberFunctionCast(void *, root, &IOService::systemWillShutdown);
6397
6398 // Iterate the entire PM tree starting from root
6399
6400 rootDepth = root->getDepth( gIOPowerPlane );
6401 if (!rootDepth) goto done;
6402
6403 // debug - for repeated test runs
6404 while (PMHaltWorker::metaClass->getInstanceCount())
6405 IOSleep(1);
6406
6407 if (!gPMHaltArray)
6408 {
6409 gPMHaltArray = OSArray::withCapacity(40);
6410 if (!gPMHaltArray) goto done;
6411 }
6412 else // debug
6413 gPMHaltArray->flushCollection();
6414
6415 if (!gPMHaltLock)
6416 {
6417 gPMHaltLock = IOLockAlloc();
6418 if (!gPMHaltLock) goto done;
6419 }
6420
6421 if (!gPMHaltClientAcknowledgeKey)
6422 {
6423 gPMHaltClientAcknowledgeKey =
6424 OSSymbol::withCStringNoCopy("PMShutdown");
6425 if (!gPMHaltClientAcknowledgeKey) goto done;
6426 }
6427
6428 gPMHaltEvent = event;
6429
6430 // Depth-first walk of PM plane
6431
6432 iter = IORegistryIterator::iterateOver(
6433 root, gIOPowerPlane, kIORegistryIterateRecursively);
6434
6435 if (iter)
6436 {
6437 while ((entry = iter->getNextObject()))
6438 {
6439 node = OSDynamicCast(IOService, entry);
6440 if (!node)
6441 continue;
6442
6443 if (baseFunc ==
6444 OSMemberFunctionCast(void *, node, &IOService::systemWillShutdown))
6445 continue;
6446
6447 depth = node->getDepth( gIOPowerPlane );
6448 if (depth <= rootDepth)
6449 continue;
6450
6451 ok = false;
6452
6453 // adjust to zero based depth
6454 depth -= (rootDepth + 1);
6455
6456 // gPMHaltArray is an array of containers, each container
6457 // refers to nodes with the same depth.
6458
6459 count = gPMHaltArray->getCount();
6460 while (depth >= count)
6461 {
6462 // expand array and insert placeholders
6463 gPMHaltArray->setObject(PLACEHOLDER);
6464 count++;
6465 }
6466 count = gPMHaltArray->getCount();
6467 if (depth < count)
6468 {
6469 inner = (OSSet *)gPMHaltArray->getObject(depth);
6470 if (inner == PLACEHOLDER)
6471 {
6472 inner = OSSet::withCapacity(40);
6473 if (inner)
6474 {
6475 gPMHaltArray->replaceObject(depth, inner);
6476 inner->release();
6477 }
6478 }
6479
6480 // PM nodes that appear more than once in the tree will have
6481 // the same depth, OSSet will refuse to add the node twice.
6482 if (inner)
6483 ok = inner->setObject(node);
6484 }
6485 if (!ok)
6486 DLOG("Skipped PM node %s\n", node->getName());
6487 }
6488 iter->release();
6489 }
6490
6491 // debug only
6492 for (int i = 0; (inner = (OSSet *)gPMHaltArray->getObject(i)); i++)
6493 {
6494 count = 0;
6495 if (inner != PLACEHOLDER)
6496 count = inner->getCount();
6497 DLOG("Nodes at depth %u = %u\n", i, count);
6498 }
6499
6500 // strip placeholders (not all depths are populated)
6501 numWorkers = 0;
6502 for (int i = 0; (inner = (OSSet *)gPMHaltArray->getObject(i)); )
6503 {
6504 if (inner == PLACEHOLDER)
6505 {
6506 gPMHaltArray->removeObject(i);
6507 continue;
6508 }
6509 count = inner->getCount();
6510 if (count > numWorkers)
6511 numWorkers = count;
6512 totalNodes += count;
6513 i++;
6514 }
6515
6516 if (gPMHaltArray->getCount() == 0 || !numWorkers)
6517 goto done;
6518
6519 gPMHaltBusyCount = 0;
6520 gPMHaltIdleCount = 0;
6521 gPMHaltDepth = gPMHaltArray->getCount() - 1;
6522
6523 // Create multiple workers (and threads)
6524
6525 if (numWorkers > kPMHaltMaxWorkers)
6526 numWorkers = kPMHaltMaxWorkers;
6527
6528 DLOG("PM nodes = %u, maxDepth = %u, workers = %u\n",
6529 totalNodes, gPMHaltArray->getCount(), numWorkers);
6530
6531 for (unsigned int i = 0; i < numWorkers; i++)
6532 workers[i] = PMHaltWorker::worker();
6533
6534 // Wait for workers to exhaust all available work
6535
6536 IOLockLock(gPMHaltLock);
6537 while (gPMHaltDepth >= 0)
6538 {
6539 clock_interval_to_deadline(1000, kMillisecondScale, &deadline);
6540
6541 waitResult = IOLockSleepDeadline(
6542 gPMHaltLock, &gPMHaltDepth, deadline, THREAD_UNINT);
6543 if (THREAD_TIMED_OUT == waitResult)
6544 {
6545 AbsoluteTime now;
6546 clock_get_uptime(&now);
6547
6548 IOLockUnlock(gPMHaltLock);
6549 for (unsigned int i = 0 ; i < numWorkers; i++)
6550 {
6551 if (workers[i])
6552 PMHaltWorker::checkTimeout(workers[i], &now);
6553 }
6554 IOLockLock(gPMHaltLock);
6555 }
6556 }
6557 IOLockUnlock(gPMHaltLock);
6558
6559 // Release all workers
6560
6561 for (unsigned int i = 0; i < numWorkers; i++)
6562 {
6563 if (workers[i])
6564 workers[i]->release();
6565 // worker also retained by it's own thread
6566 }
6567
6568 done:
6569 DLOG("%s done\n", __FUNCTION__);
6570 return;
6571 }
6572
6573 //*********************************************************************************
6574 // Sleep/Wake logging
6575 //
6576 //*********************************************************************************
6577
6578 IOMemoryDescriptor *IOPMrootDomain::getPMTraceMemoryDescriptor(void)
6579 {
6580 if (timeline)
6581 return timeline->getPMTraceMemoryDescriptor();
6582 else
6583 return NULL;
6584 }
6585
6586 // Forwards external reports of detailed events to IOPMTimeline
6587 IOReturn IOPMrootDomain::recordPMEvent(PMEventDetails *details)
6588 {
6589 if (timeline && details) {
6590
6591 IOReturn rc;
6592
6593 // Record a detailed driver power change event, or...
6594 if(details->eventClassifier == kIOPMEventClassDriverEvent) {
6595 rc = timeline->recordDetailedPowerEvent( details );
6596 }
6597
6598 // Record a system power management event
6599 else if(details->eventClassifier == kIOPMEventClassSystemEvent) {
6600 rc = timeline->recordSystemPowerEvent( details );
6601 }
6602 else {
6603 return kIOReturnBadArgument;
6604 }
6605
6606 // If we get to record this message, then we've reached the
6607 // end of another successful Sleep --> Wake cycle
6608 // At this point, we pat ourselves in the back and allow
6609 // our Sleep --> Wake UUID to be published
6610 if(details->eventType == kIOPMEventTypeWakeDone) {
6611 timeline->setSleepCycleInProgressFlag(false);
6612 }
6613
6614 /*
6615 // Check if its time to clear the timeline buffer
6616 if(getProperty(kIOPMSleepWakeUUIDKey)
6617 && timeline->isSleepCycleInProgress() == false
6618 && timeline->getNumEventsLoggedThisPeriod() > 500) {
6619
6620 // Clear the old UUID
6621 if(pmPowerStateQueue) {
6622 pmPowerStateQueue->submitPowerEvent(kPowerEventPublishSleepWakeUUID, (void *)false );
6623 }
6624 }
6625 */
6626 return rc;
6627 }
6628 else
6629 return kIOReturnNotReady;
6630 }
6631
6632 IOReturn IOPMrootDomain::recordAndReleasePMEvent(PMEventDetails *details)
6633 {
6634 IOReturn ret = kIOReturnBadArgument;
6635
6636 if (details)
6637 {
6638 ret = recordPMEvent(details);
6639 details->release();
6640 }
6641
6642 return ret;
6643 }
6644
6645 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
6646
6647 IOPMDriverAssertionID IOPMrootDomain::createPMAssertion(
6648 IOPMDriverAssertionType whichAssertionBits,
6649 IOPMDriverAssertionLevel assertionLevel,
6650 IOService *ownerService,
6651 const char *ownerDescription)
6652 {
6653 IOReturn ret;
6654 IOPMDriverAssertionID newAssertion;
6655
6656 if (!pmAssertions)
6657 return 0;
6658
6659 ret = pmAssertions->createAssertion(whichAssertionBits, assertionLevel, ownerService, ownerDescription, &newAssertion);
6660
6661 if (kIOReturnSuccess == ret)
6662 return newAssertion;
6663 else
6664 return 0;
6665 }
6666
6667 IOReturn IOPMrootDomain::releasePMAssertion(IOPMDriverAssertionID releaseAssertion)
6668 {
6669 if (!pmAssertions)
6670 return kIOReturnInternalError;
6671
6672 return pmAssertions->releaseAssertion(releaseAssertion);
6673 }
6674
6675 IOReturn IOPMrootDomain::setPMAssertionLevel(
6676 IOPMDriverAssertionID assertionID,
6677 IOPMDriverAssertionLevel assertionLevel)
6678 {
6679 return pmAssertions->setAssertionLevel(assertionID, assertionLevel);
6680 }
6681
6682 IOPMDriverAssertionLevel IOPMrootDomain::getPMAssertionLevel(IOPMDriverAssertionType whichAssertion)
6683 {
6684 IOPMDriverAssertionType sysLevels;
6685
6686 if (!pmAssertions || whichAssertion == 0)
6687 return kIOPMDriverAssertionLevelOff;
6688
6689 sysLevels = pmAssertions->getActivatedAssertions();
6690
6691 // Check that every bit set in argument 'whichAssertion' is asserted
6692 // in the aggregate bits.
6693 if ((sysLevels & whichAssertion) == whichAssertion)
6694 return kIOPMDriverAssertionLevelOn;
6695 else
6696 return kIOPMDriverAssertionLevelOff;
6697 }
6698
6699 IOReturn IOPMrootDomain::setPMAssertionUserLevels(IOPMDriverAssertionType inLevels)
6700 {
6701 if (!pmAssertions)
6702 return kIOReturnNotFound;
6703
6704 return pmAssertions->setUserAssertionLevels(inLevels);
6705 }
6706
6707 bool IOPMrootDomain::serializeProperties( OSSerialize * s ) const
6708 {
6709 if (pmAssertions)
6710 {
6711 pmAssertions->publishProperties();
6712 }
6713 return( IOService::serializeProperties(s) );
6714 }
6715
6716 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
6717
6718 // MARK: -
6719 // MARK: PMSettingHandle
6720
6721 OSDefineMetaClassAndStructors( PMSettingHandle, OSObject )
6722
6723 void PMSettingHandle::free( void )
6724 {
6725 if (pmso)
6726 {
6727 pmso->clientHandleFreed();
6728 pmso->release();
6729 pmso = 0;
6730 }
6731
6732 OSObject::free();
6733 }
6734
6735 // MARK: -
6736 // MARK: PMSettingObject
6737
6738 #undef super
6739 #define super OSObject
6740 OSDefineMetaClassAndFinalStructors( PMSettingObject, OSObject )
6741
6742 /*
6743 * Static constructor/initializer for PMSettingObject
6744 */
6745 PMSettingObject *PMSettingObject::pmSettingObject(
6746 IOPMrootDomain *parent_arg,
6747 IOPMSettingControllerCallback handler_arg,
6748 OSObject *target_arg,
6749 uintptr_t refcon_arg,
6750 uint32_t supportedPowerSources,
6751 const OSSymbol * settings[],
6752 OSObject **handle_obj)
6753 {
6754 uint32_t settingCount = 0;
6755 PMSettingObject *pmso = 0;
6756 PMSettingHandle *pmsh = 0;
6757
6758 if ( !parent_arg || !handler_arg || !settings || !handle_obj )
6759 return NULL;
6760
6761 // count OSSymbol entries in NULL terminated settings array
6762 while (settings[settingCount]) {
6763 settingCount++;
6764 }
6765 if (0 == settingCount)
6766 return NULL;
6767
6768 pmso = new PMSettingObject;
6769 if (!pmso || !pmso->init())
6770 goto fail;
6771
6772 pmsh = new PMSettingHandle;
6773 if (!pmsh || !pmsh->init())
6774 goto fail;
6775
6776 queue_init(&pmso->calloutQueue);
6777 pmso->parent = parent_arg;
6778 pmso->func = handler_arg;
6779 pmso->target = target_arg;
6780 pmso->refcon = refcon_arg;
6781 pmso->settingCount = settingCount;
6782
6783 pmso->retain(); // handle holds a retain on pmso
6784 pmsh->pmso = pmso;
6785 pmso->pmsh = pmsh;
6786
6787 pmso->publishedFeatureID = (uint32_t *)IOMalloc(sizeof(uint32_t)*settingCount);
6788 if (pmso->publishedFeatureID) {
6789 for (unsigned int i=0; i<settingCount; i++) {
6790 // Since there is now at least one listener to this setting, publish
6791 // PM root domain support for it.
6792 parent_arg->publishFeature( settings[i]->getCStringNoCopy(),
6793 supportedPowerSources, &pmso->publishedFeatureID[i] );
6794 }
6795 }
6796
6797 *handle_obj = pmsh;
6798 return pmso;
6799
6800 fail:
6801 if (pmso) pmso->release();
6802 if (pmsh) pmsh->release();
6803 return NULL;
6804 }
6805
6806 void PMSettingObject::free( void )
6807 {
6808 if (publishedFeatureID) {
6809 for (uint32_t i=0; i<settingCount; i++) {
6810 if (publishedFeatureID[i]) {
6811 parent->removePublishedFeature( publishedFeatureID[i] );
6812 }
6813 }
6814
6815 IOFree(publishedFeatureID, sizeof(uint32_t) * settingCount);
6816 }
6817
6818 super::free();
6819 }
6820
6821 void PMSettingObject::dispatchPMSetting( const OSSymbol * type, OSObject * object )
6822 {
6823 (*func)(target, type, object, refcon);
6824 }
6825
6826 void PMSettingObject::clientHandleFreed( void )
6827 {
6828 parent->deregisterPMSettingObject(this);
6829 }
6830
6831 // MARK: -
6832 // MARK: IOPMTimeline
6833
6834 #undef super
6835 #define super OSObject
6836
6837 //*********************************************************************************
6838 //*********************************************************************************
6839 //*********************************************************************************
6840
6841 IOPMTimeline *IOPMTimeline::timeline(IOPMrootDomain *root_domain)
6842 {
6843 IOPMTimeline *myself;
6844
6845 if (!root_domain)
6846 return NULL;
6847
6848 myself = new IOPMTimeline;
6849
6850 if (myself) {
6851 myself->owner = root_domain;
6852 myself->init();
6853 }
6854
6855 return myself;
6856 }
6857
6858 bool IOPMTimeline::init(void)
6859 {
6860 if (!super::init()) {
6861 return false;
6862 }
6863
6864 logLock = IOLockAlloc();
6865
6866 // Fresh timeline, no events logged yet
6867 this->numEventsLoggedThisPeriod = 0;
6868 this->sleepCycleInProgress = false;
6869
6870 //this->setEventsRecordingLevel(1); // TODO
6871 this->setEventsTrackedCount(kIOPMDefaultSystemEventsTracked);
6872
6873 return true;
6874 }
6875
6876 void IOPMTimeline::free(void)
6877 {
6878 if (pmTraceMemoryDescriptor) {
6879 pmTraceMemoryDescriptor->release();
6880 pmTraceMemoryDescriptor = NULL;
6881 }
6882
6883 IOLockFree(logLock);
6884
6885 super::free();
6886 }
6887
6888 IOMemoryDescriptor *IOPMTimeline::getPMTraceMemoryDescriptor()
6889 {
6890 return pmTraceMemoryDescriptor;
6891 }
6892
6893 //*********************************************************************************
6894 //*********************************************************************************
6895 //*********************************************************************************
6896
6897 bool IOPMTimeline::setProperties(OSDictionary *d)
6898 {
6899 OSNumber *n = NULL;
6900 OSBoolean *b = NULL;
6901 bool changed = false;
6902
6903 /* Changes size of detailed events buffer */
6904 n = (OSNumber *)d->getObject(kIOPMTimelineSystemNumberTrackedKey);
6905 if (OSDynamicCast(OSNumber, n))
6906 {
6907 changed = true;
6908 this->setEventsTrackedCount(n->unsigned32BitValue());
6909 }
6910
6911
6912 /* enables or disables system events */
6913 b = (OSBoolean *)d->getObject(kIOPMTimelineEnabledKey);
6914 if (b)
6915 {
6916 changed = true;
6917 this->setEventsRecordingLevel((int)(kOSBooleanTrue == b));
6918 }
6919
6920 return changed;
6921 }
6922
6923 //*********************************************************************************
6924 //*********************************************************************************
6925 //*********************************************************************************
6926
6927 OSDictionary *IOPMTimeline::copyInfoDictionary(void)
6928 {
6929 OSDictionary *out = OSDictionary::withCapacity(3);
6930 OSNumber *n = NULL;
6931
6932 if (!out || !hdr)
6933 return NULL;
6934
6935 n = OSNumber::withNumber(hdr->sizeEntries, 32);
6936 out->setObject(kIOPMTimelineSystemNumberTrackedKey, n);
6937 n->release();
6938
6939 n = OSNumber::withNumber(hdr->sizeBytes, 32);
6940 out->setObject(kIOPMTimelineSystemBufferSizeKey, n);
6941 n->release();
6942
6943 // bool
6944 out->setObject(kIOPMTimelineEnabledKey, eventsRecordingLevel ? kOSBooleanTrue : kOSBooleanFalse);
6945
6946 return out;
6947 }
6948
6949 //*********************************************************************************
6950 //*********************************************************************************
6951 //*********************************************************************************
6952
6953 /* IOPMTimeline::recordSystemPowerEvent()
6954 *
6955 * Expected "type" arguments are listed in IOPMPrivate.h under enum "SystemEventTypes"
6956 * Type arguments include "system events", and "Intermediate events"
6957 *
6958 * - System Events have paired "start" and "stop" events.
6959 * - A start event shall be followed by a stop event.
6960 * - Any number of Intermediate Events may fall between the
6961 * start and stop events.
6962 * - Intermediate events are meaningless outside the bounds of a system event's
6963 * start & stoup routines.
6964 * - It's invalid to record a Start event without a following Stop event; e.g. two
6965 * Start events without an intervenining Stop event is invalid.
6966 *
6967 * Buffer invariants
6968 * - The first recorded system event shall be preceded by an entry with type == 0
6969 * - IOPMTimeline may choose not to record intermediate events while there's not
6970 * a system event in process.
6971 */
6972 IOReturn IOPMTimeline::recordSystemPowerEvent( PMEventDetails *details )
6973 {
6974 static bool wakeDonePending = true;
6975 IOPMSystemEventRecord *record_to = NULL;
6976 OSString *swUUIDKey = NULL;
6977 uint32_t useIndex = 0;
6978
6979 if (!details)
6980 return kIOReturnBadArgument;
6981
6982 if (!traceBuffer)
6983 return kIOReturnNotReady;
6984
6985 if (details->eventType == kIOPMEventTypeWakeDone)
6986 {
6987 if(!wakeDonePending)
6988 return kIOReturnBadArgument;
6989 }
6990
6991 IOLockLock(logLock);
6992
6993 if (details->eventType == kIOPMEventTypeWake) {
6994 wakeDonePending = true;
6995 } else if (details->eventType == kIOPMEventTypeWakeDone) {
6996 wakeDonePending = false;
6997 }
6998
6999 systemState = details->eventType;
7000
7001 useIndex = _atomicIndexIncrement(&hdr->index, hdr->sizeEntries);
7002
7003 // The entry immediately after the latest entry (and thus
7004 // immediately before the first entry) shall have a type 0.
7005 if (useIndex + 1 >= hdr->sizeEntries) {
7006 traceBuffer[useIndex + 1].eventType = 0;
7007 } else {
7008 traceBuffer[0].eventType = 0;
7009 }
7010
7011 record_to = &traceBuffer[useIndex];
7012 bzero(record_to, sizeof(IOPMSystemEventRecord));
7013
7014 /*****/
7015 record_to->eventType = details->eventType;
7016 record_to->eventReason = details->reason;
7017 record_to->eventResult = details->result;
7018 pmEventTimeStamp(&record_to->timestamp);
7019
7020 // If caller doesn't provide a UUID, we'll use the UUID that's posted
7021 // on IOPMrootDomain under key kIOPMSleepWakeUUIDKey
7022 if (!details->uuid) {
7023 swUUIDKey = OSDynamicCast(OSString, owner->copyProperty(kIOPMSleepWakeUUIDKey));
7024
7025 if (swUUIDKey)
7026 details->uuid = swUUIDKey->getCStringNoCopy();
7027 }
7028
7029 if (details->uuid)
7030 strncpy(record_to->uuid, details->uuid, kMaxPMStringLength);
7031
7032 if (swUUIDKey)
7033 swUUIDKey->release();
7034
7035 numEventsLoggedThisPeriod++;
7036 /*****/
7037
7038 IOLockUnlock(logLock);
7039
7040 return kIOReturnSuccess;
7041
7042 }
7043
7044 //*********************************************************************************
7045 //*********************************************************************************
7046 //*********************************************************************************
7047
7048 IOReturn IOPMTimeline::recordDetailedPowerEvent( PMEventDetails *details )
7049 {
7050 IOPMSystemEventRecord *record_to = NULL;
7051 uint32_t useIndex;
7052
7053 if (!details->eventType || !details->ownerName)
7054 return kIOReturnBadArgument;
7055
7056 IOLockLock(logLock);
7057
7058 useIndex = _atomicIndexIncrement(&hdr->index, hdr->sizeEntries);
7059
7060 record_to = (IOPMSystemEventRecord *)&traceBuffer[useIndex];
7061 bzero(record_to, sizeof(IOPMSystemEventRecord));
7062
7063 /*****/
7064 record_to->eventType = details->eventType;
7065 if (details->ownerName && (strlen(details->ownerName) > 1)) {
7066 strlcpy( record_to->ownerName,
7067 details->ownerName,
7068 sizeof(record_to->ownerName));
7069 }
7070
7071 record_to->ownerDisambiguateID = details->ownerUnique;
7072
7073 if (details->interestName && (strlen(details->interestName) > 1)) {
7074 strlcpy(record_to->interestName,
7075 details->interestName,
7076 sizeof(record_to->interestName));
7077 }
7078
7079 record_to->oldState = details->oldState;
7080 record_to->newState = details->newState;
7081 record_to->eventResult = details->result;
7082 record_to->elapsedTimeUS = details->elapsedTimeUS;
7083 pmEventTimeStamp(&record_to->timestamp);
7084
7085 numEventsLoggedThisPeriod++;
7086 /*****/
7087
7088 IOLockUnlock(logLock);
7089 return kIOReturnSuccess;
7090 }
7091
7092 uint32_t IOPMTimeline::getNumEventsLoggedThisPeriod() {
7093 return this->numEventsLoggedThisPeriod;
7094 }
7095
7096 void IOPMTimeline::setNumEventsLoggedThisPeriod(uint32_t newCount) {
7097 this->numEventsLoggedThisPeriod = newCount;
7098 }
7099
7100 bool IOPMTimeline::isSleepCycleInProgress() {
7101 return this->sleepCycleInProgress;
7102 }
7103
7104 void IOPMTimeline::setSleepCycleInProgressFlag(bool flag) {
7105 this->sleepCycleInProgress = flag;
7106 }
7107 //*********************************************************************************
7108 //*********************************************************************************
7109 //*********************************************************************************
7110
7111 void IOPMTimeline::setEventsTrackedCount(uint32_t newTracked)
7112 {
7113 size_t make_buf_size = 0;
7114
7115 make_buf_size = sizeof(IOPMTraceBufferHeader) + (newTracked * sizeof(IOPMSystemEventRecord));
7116
7117 IOLockLock(logLock);
7118
7119 if (pmTraceMemoryDescriptor) {
7120 pmTraceMemoryDescriptor->release();
7121 pmTraceMemoryDescriptor = NULL;
7122 }
7123
7124 hdr = NULL;
7125 traceBuffer = NULL;
7126
7127 if (0 == newTracked)
7128 {
7129 IOLog("IOPMrootDomain -> erased buffer.\n");
7130 goto exit;
7131 }
7132
7133 pmTraceMemoryDescriptor = IOBufferMemoryDescriptor::withOptions(
7134 kIOMemoryKernelUserShared | kIODirectionIn, make_buf_size);
7135
7136 if (!pmTraceMemoryDescriptor)
7137 {
7138 IOLog("IOPMRootDomain -> IOBufferMemoryDescriptor(%d) returns NULL\n", (int)make_buf_size);
7139 goto exit;
7140 }
7141
7142 pmTraceMemoryDescriptor->prepare(kIODirectionIn);
7143
7144 // Header occupies the first sizeof(IOPMTraceBufferHeader) bytes
7145 hdr = (IOPMTraceBufferHeader *)pmTraceMemoryDescriptor->getBytesNoCopy();
7146
7147 // Recorded events occupy the remaining bulk of the buffer
7148 traceBuffer = (IOPMSystemEventRecord *)((uint8_t *)hdr + sizeof(IOPMTraceBufferHeader));
7149
7150 bzero(hdr, make_buf_size);
7151
7152 hdr->sizeBytes = make_buf_size;
7153 hdr->sizeEntries = newTracked;
7154
7155 IOLog("IOPMRootDomain -> IOBufferMemoryDescriptor(%d) returns bufferMB with address 0x%08x\n", (int)make_buf_size, (unsigned int)(uintptr_t)traceBuffer);
7156
7157 exit:
7158 IOLockUnlock(logLock);
7159 }
7160
7161 //*********************************************************************************
7162 //*********************************************************************************
7163 //*********************************************************************************
7164
7165 void IOPMTimeline::setEventsRecordingLevel(uint32_t eventsTrackedBits)
7166 {
7167
7168 // TODO
7169
7170 return;
7171
7172 }
7173
7174 /* static helper to IOPMTimeline
7175 */
7176 uint32_t IOPMTimeline::_atomicIndexIncrement(uint32_t *index, uint32_t limit)
7177 {
7178 uint32_t was_index;
7179 uint32_t inc_index;
7180
7181 if(!index)
7182 return NULL;
7183
7184 do {
7185 was_index = *index;
7186 inc_index = (was_index+1)%limit;
7187 } while (!OSCompareAndSwap(was_index, inc_index, index));
7188
7189 return inc_index;
7190 }
7191
7192 // MARK: -
7193 // MARK: PMAssertionsTracker
7194
7195 //*********************************************************************************
7196 //*********************************************************************************
7197 //*********************************************************************************
7198 // class PMAssertionsTracker Implementation
7199
7200 #define kAssertUniqueIDStart 500
7201
7202 PMAssertionsTracker *PMAssertionsTracker::pmAssertionsTracker( IOPMrootDomain *rootDomain )
7203 {
7204 PMAssertionsTracker *myself;
7205
7206 myself = new PMAssertionsTracker;
7207
7208 if (myself) {
7209 myself->init();
7210 myself->owner = rootDomain;
7211 myself->issuingUniqueID = kAssertUniqueIDStart;
7212 myself->assertionsArray = OSArray::withCapacity(5);
7213 myself->assertionsKernel = 0;
7214 myself->assertionsUser = 0;
7215 myself->assertionsCombined = 0;
7216 myself->assertionsArrayLock = IOLockAlloc();
7217 myself->tabulateProducerCount = myself->tabulateConsumerCount = 0;
7218
7219 if (!myself->assertionsArray || !myself->assertionsArrayLock)
7220 myself = NULL;
7221 }
7222
7223 return myself;
7224 }
7225
7226 /* tabulate
7227 * - Update assertionsKernel to reflect the state of all
7228 * assertions in the kernel.
7229 * - Update assertionsCombined to reflect both kernel & user space.
7230 */
7231 void PMAssertionsTracker::tabulate(void)
7232 {
7233 int i;
7234 int count;
7235 PMAssertStruct *_a = NULL;
7236 OSData *_d = NULL;
7237
7238 IOPMDriverAssertionType oldKernel = assertionsKernel;
7239 IOPMDriverAssertionType oldCombined = assertionsCombined;
7240
7241 ASSERT_GATED();
7242
7243 assertionsKernel = 0;
7244 assertionsCombined = 0;
7245
7246 if (!assertionsArray)
7247 return;
7248
7249 if ((count = assertionsArray->getCount()))
7250 {
7251 for (i=0; i<count; i++)
7252 {
7253 _d = OSDynamicCast(OSData, assertionsArray->getObject(i));
7254 if (_d)
7255 {
7256 _a = (PMAssertStruct *)_d->getBytesNoCopy();
7257 if (_a && (kIOPMDriverAssertionLevelOn == _a->level))
7258 assertionsKernel |= _a->assertionBits;
7259 }
7260 }
7261 }
7262
7263 tabulateProducerCount++;
7264 assertionsCombined = assertionsKernel | assertionsUser;
7265
7266 if ((assertionsKernel != oldKernel) ||
7267 (assertionsCombined != oldCombined))
7268 {
7269 owner->messageClients(kIOPMMessageDriverAssertionsChanged);
7270
7271 if (((assertionsCombined & kIOPMDriverAssertionPreventDisplaySleepBit) != 0)
7272 && ((oldCombined & kIOPMDriverAssertionPreventDisplaySleepBit) == 0))
7273 {
7274 /* We react to a new PreventDisplaySleep assertion by waking the display
7275 * with an activityTickle
7276 */
7277 owner->evaluatePolicy(kStimulusDarkWakeActivityTickle);
7278 } else {
7279 owner->evaluatePolicy(kStimulusDarkWakeEvaluate);
7280 }
7281 }
7282 }
7283
7284 void PMAssertionsTracker::publishProperties( void )
7285 {
7286 OSArray *assertionsSummary = NULL;
7287
7288 if (tabulateConsumerCount != tabulateProducerCount)
7289 {
7290 IOLockLock(assertionsArrayLock);
7291
7292 tabulateConsumerCount = tabulateProducerCount;
7293
7294 /* Publish the IOPMrootDomain property "DriverPMAssertionsDetailed"
7295 */
7296 assertionsSummary = copyAssertionsArray();
7297 if (assertionsSummary)
7298 {
7299 owner->setProperty(kIOPMAssertionsDriverDetailedKey, assertionsSummary);
7300 assertionsSummary->release();
7301 }
7302 else
7303 {
7304 owner->removeProperty(kIOPMAssertionsDriverDetailedKey);
7305 }
7306
7307 /* Publish the IOPMrootDomain property "DriverPMAssertions"
7308 */
7309 owner->setProperty(kIOPMAssertionsDriverKey, assertionsKernel, 64);
7310
7311 IOLockUnlock(assertionsArrayLock);
7312 }
7313 }
7314
7315 PMAssertionsTracker::PMAssertStruct *PMAssertionsTracker::detailsForID(IOPMDriverAssertionID _id, int *index)
7316 {
7317 PMAssertStruct *_a = NULL;
7318 OSData *_d = NULL;
7319 int found = -1;
7320 int count = 0;
7321 int i = 0;
7322
7323 if (assertionsArray
7324 && (count = assertionsArray->getCount()))
7325 {
7326 for (i=0; i<count; i++)
7327 {
7328 _d = OSDynamicCast(OSData, assertionsArray->getObject(i));
7329 if (_d)
7330 {
7331 _a = (PMAssertStruct *)_d->getBytesNoCopy();
7332 if (_a && (_id == _a->id)) {
7333 found = i;
7334 break;
7335 }
7336 }
7337 }
7338 }
7339
7340 if (-1 == found) {
7341 return NULL;
7342 } else {
7343 if (index)
7344 *index = found;
7345 return _a;
7346 }
7347 }
7348
7349 /* PMAssertionsTracker::handleCreateAssertion
7350 * Perform assertion work on the PM workloop. Do not call directly.
7351 */
7352 IOReturn PMAssertionsTracker::handleCreateAssertion(OSData *newAssertion)
7353 {
7354 ASSERT_GATED();
7355
7356 if (newAssertion)
7357 {
7358 IOLockLock(assertionsArrayLock);
7359 assertionsArray->setObject(newAssertion);
7360 IOLockUnlock(assertionsArrayLock);
7361 newAssertion->release();
7362
7363 tabulate();
7364 }
7365 return kIOReturnSuccess;
7366 }
7367
7368 /* PMAssertionsTracker::createAssertion
7369 * createAssertion allocates memory for a new PM assertion, and affects system behavior, if
7370 * appropiate.
7371 */
7372 IOReturn PMAssertionsTracker::createAssertion(
7373 IOPMDriverAssertionType which,
7374 IOPMDriverAssertionLevel level,
7375 IOService *serviceID,
7376 const char *whoItIs,
7377 IOPMDriverAssertionID *outID)
7378 {
7379 OSData *dataStore = NULL;
7380 PMAssertStruct track;
7381
7382 // Warning: trillions and trillions of created assertions may overflow the unique ID.
7383 track.id = OSIncrementAtomic64((SInt64*) &issuingUniqueID);
7384 track.level = level;
7385 track.assertionBits = which;
7386 track.ownerString = whoItIs ? OSSymbol::withCString(whoItIs) : 0;
7387 track.ownerService = serviceID;
7388 track.modifiedTime = 0;
7389 pmEventTimeStamp(&track.createdTime);
7390
7391 dataStore = OSData::withBytes(&track, sizeof(PMAssertStruct));
7392 if (!dataStore)
7393 {
7394 if (track.ownerString)
7395 track.ownerString->release();
7396 return kIOReturnNoMemory;
7397 }
7398
7399 *outID = track.id;
7400
7401 if (owner && owner->pmPowerStateQueue) {
7402 owner->pmPowerStateQueue->submitPowerEvent(kPowerEventAssertionCreate, (void *)dataStore);
7403 }
7404
7405 return kIOReturnSuccess;
7406 }
7407
7408 /* PMAssertionsTracker::handleReleaseAssertion
7409 * Runs in PM workloop. Do not call directly.
7410 */
7411 IOReturn PMAssertionsTracker::handleReleaseAssertion(
7412 IOPMDriverAssertionID _id)
7413 {
7414 ASSERT_GATED();
7415
7416 int index;
7417 PMAssertStruct *assertStruct = detailsForID(_id, &index);
7418
7419 if (!assertStruct)
7420 return kIOReturnNotFound;
7421
7422 IOLockLock(assertionsArrayLock);
7423 if (assertStruct->ownerString)
7424 assertStruct->ownerString->release();
7425
7426 assertionsArray->removeObject(index);
7427 IOLockUnlock(assertionsArrayLock);
7428
7429 tabulate();
7430 return kIOReturnSuccess;
7431 }
7432
7433 /* PMAssertionsTracker::releaseAssertion
7434 * Releases an assertion and affects system behavior if appropiate.
7435 * Actual work happens on PM workloop.
7436 */
7437 IOReturn PMAssertionsTracker::releaseAssertion(
7438 IOPMDriverAssertionID _id)
7439 {
7440 if (owner && owner->pmPowerStateQueue) {
7441 owner->pmPowerStateQueue->submitPowerEvent(kPowerEventAssertionRelease, 0, _id);
7442 }
7443 return kIOReturnSuccess;
7444 }
7445
7446 /* PMAssertionsTracker::handleSetAssertionLevel
7447 * Runs in PM workloop. Do not call directly.
7448 */
7449 IOReturn PMAssertionsTracker::handleSetAssertionLevel(
7450 IOPMDriverAssertionID _id,
7451 IOPMDriverAssertionLevel _level)
7452 {
7453 PMAssertStruct *assertStruct = detailsForID(_id, NULL);
7454
7455 ASSERT_GATED();
7456
7457 if (!assertStruct) {
7458 return kIOReturnNotFound;
7459 }
7460
7461 IOLockLock(assertionsArrayLock);
7462 pmEventTimeStamp(&assertStruct->modifiedTime);
7463 assertStruct->level = _level;
7464 IOLockUnlock(assertionsArrayLock);
7465
7466 tabulate();
7467 return kIOReturnSuccess;
7468 }
7469
7470 /* PMAssertionsTracker::setAssertionLevel
7471 */
7472 IOReturn PMAssertionsTracker::setAssertionLevel(
7473 IOPMDriverAssertionID _id,
7474 IOPMDriverAssertionLevel _level)
7475 {
7476 if (owner && owner->pmPowerStateQueue) {
7477 owner->pmPowerStateQueue->submitPowerEvent(kPowerEventAssertionSetLevel,
7478 (void *)_level, _id);
7479 }
7480
7481 return kIOReturnSuccess;
7482 }
7483
7484 IOReturn PMAssertionsTracker::handleSetUserAssertionLevels(void * arg0)
7485 {
7486 IOPMDriverAssertionType new_user_levels = *(IOPMDriverAssertionType *) arg0;
7487
7488 ASSERT_GATED();
7489
7490 if (new_user_levels != assertionsUser)
7491 {
7492 assertionsUser = new_user_levels;
7493 DLOG("assertionsUser 0x%llx\n", assertionsUser);
7494 }
7495
7496 tabulate();
7497 return kIOReturnSuccess;
7498 }
7499
7500 IOReturn PMAssertionsTracker::setUserAssertionLevels(
7501 IOPMDriverAssertionType new_user_levels)
7502 {
7503 if (gIOPMWorkLoop) {
7504 gIOPMWorkLoop->runAction(
7505 OSMemberFunctionCast(
7506 IOWorkLoop::Action,
7507 this,
7508 &PMAssertionsTracker::handleSetUserAssertionLevels),
7509 this,
7510 (void *) &new_user_levels, 0, 0, 0);
7511 }
7512
7513 return kIOReturnSuccess;
7514 }
7515
7516
7517 OSArray *PMAssertionsTracker::copyAssertionsArray(void)
7518 {
7519 int count;
7520 int i;
7521 OSArray *outArray = NULL;
7522
7523 if (!assertionsArray ||
7524 (0 == (count = assertionsArray->getCount())) ||
7525 (NULL == (outArray = OSArray::withCapacity(count))))
7526 {
7527 goto exit;
7528 }
7529
7530 for (i=0; i<count; i++)
7531 {
7532 PMAssertStruct *_a = NULL;
7533 OSData *_d = NULL;
7534 OSDictionary *details = NULL;
7535
7536 _d = OSDynamicCast(OSData, assertionsArray->getObject(i));
7537 if (_d && (_a = (PMAssertStruct *)_d->getBytesNoCopy()))
7538 {
7539 OSNumber *_n = NULL;
7540
7541 details = OSDictionary::withCapacity(7);
7542 if (!details)
7543 continue;
7544
7545 outArray->setObject(details);
7546 details->release();
7547
7548 _n = OSNumber::withNumber(_a->id, 64);
7549 if (_n) {
7550 details->setObject(kIOPMDriverAssertionIDKey, _n);
7551 _n->release();
7552 }
7553 _n = OSNumber::withNumber(_a->createdTime, 64);
7554 if (_n) {
7555 details->setObject(kIOPMDriverAssertionCreatedTimeKey, _n);
7556 _n->release();
7557 }
7558 _n = OSNumber::withNumber(_a->modifiedTime, 64);
7559 if (_n) {
7560 details->setObject(kIOPMDriverAssertionModifiedTimeKey, _n);
7561 _n->release();
7562 }
7563 _n = OSNumber::withNumber((uintptr_t)_a->ownerService, 64);
7564 if (_n) {
7565 details->setObject(kIOPMDriverAssertionOwnerServiceKey, _n);
7566 _n->release();
7567 }
7568 _n = OSNumber::withNumber(_a->level, 64);
7569 if (_n) {
7570 details->setObject(kIOPMDriverAssertionLevelKey, _n);
7571 _n->release();
7572 }
7573 _n = OSNumber::withNumber(_a->assertionBits, 64);
7574 if (_n) {
7575 details->setObject(kIOPMDriverAssertionAssertedKey, _n);
7576 _n->release();
7577 }
7578
7579 if (_a->ownerString) {
7580 details->setObject(kIOPMDriverAssertionOwnerStringKey, _a->ownerString);
7581 }
7582 }
7583 }
7584
7585 exit:
7586 return outArray;
7587 }
7588
7589 IOPMDriverAssertionType PMAssertionsTracker::getActivatedAssertions(void)
7590 {
7591 return assertionsCombined;
7592 }
7593
7594 IOPMDriverAssertionLevel PMAssertionsTracker::getAssertionLevel(
7595 IOPMDriverAssertionType type)
7596 {
7597 if (type && ((type & assertionsKernel) == assertionsKernel))
7598 {
7599 return kIOPMDriverAssertionLevelOn;
7600 } else {
7601 return kIOPMDriverAssertionLevelOff;
7602 }
7603 }
7604
7605 //*********************************************************************************
7606 //*********************************************************************************
7607 //*********************************************************************************
7608
7609
7610 static void pmEventTimeStamp(uint64_t *recordTS)
7611 {
7612 clock_sec_t tsec;
7613 clock_usec_t tusec;
7614
7615 if (!recordTS)
7616 return;
7617
7618 // We assume tsec fits into 32 bits; 32 bits holds enough
7619 // seconds for 136 years since the epoch in 1970.
7620 clock_get_calendar_microtime(&tsec, &tusec);
7621
7622
7623 // Pack the sec & microsec calendar time into a uint64_t, for fun.
7624 *recordTS = 0;
7625 *recordTS |= (uint32_t)tusec;
7626 *recordTS |= ((uint64_t)tsec << 32);
7627
7628 return;
7629 }
7630
7631 // MARK: -
7632 // MARK: IORootParent
7633
7634 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
7635
7636 OSDefineMetaClassAndFinalStructors(IORootParent, IOService)
7637
7638 // The reason that root domain needs a root parent is to facilitate demand
7639 // sleep, since a power change from the root parent cannot be vetoed.
7640 //
7641 // The above statement is no longer true since root domain now performs
7642 // demand sleep using overrides. But root parent remains to avoid changing
7643 // the power tree stacking. Root parent is parked at the max power state.
7644
7645
7646 static IOPMPowerState patriarchPowerStates[2] =
7647 {
7648 {1,0,ON_POWER,0,0,0,0,0,0,0,0,0},
7649 {1,0,ON_POWER,0,0,0,0,0,0,0,0,0},
7650 };
7651
7652 void IORootParent::initialize( void )
7653 {
7654 }
7655
7656 bool IORootParent::start( IOService * nub )
7657 {
7658 IOService::start(nub);
7659 attachToParent( getRegistryRoot(), gIOPowerPlane );
7660 PMinit();
7661 registerPowerDriver(this, patriarchPowerStates, 2);
7662 makeUsable();
7663 return true;
7664 }
7665
7666 void IORootParent::shutDownSystem( void )
7667 {
7668 }
7669
7670 void IORootParent::restartSystem( void )
7671 {
7672 }
7673
7674 void IORootParent::sleepSystem( void )
7675 {
7676 }
7677
7678 void IORootParent::dozeSystem( void )
7679 {
7680 }
7681
7682 void IORootParent::sleepToDoze( void )
7683 {
7684 }
7685
7686 void IORootParent::wakeSystem( void )
7687 {
7688 }
7689
7690 OSObject * IORootParent::copyProperty( const char * aKey) const
7691 {
7692 return (IOService::copyProperty(aKey));
7693 }
7694