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