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