]> git.saurik.com Git - apple/xnu.git/blob - iokit/Kernel/IOServicePM.cpp
xnu-2050.18.24.tar.gz
[apple/xnu.git] / iokit / Kernel / IOServicePM.cpp
1 /*
2 * Copyright (c) 1998-2006 Apple Computer, 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
29 //#undef IOASSERT
30 //#define IOASSERT 1
31
32 #include <IOKit/assert.h>
33 #include <IOKit/IOKitDebug.h>
34 #include <IOKit/IOLib.h>
35 #include <IOKit/IOMessage.h>
36 #include <IOKit/IOPlatformExpert.h>
37 #include <IOKit/IOService.h>
38 #include <IOKit/IOEventSource.h>
39 #include <IOKit/IOWorkLoop.h>
40 #include <IOKit/IOCommand.h>
41
42 #include <IOKit/pwr_mgt/IOPMlog.h>
43 #include <IOKit/pwr_mgt/IOPMinformee.h>
44 #include <IOKit/pwr_mgt/IOPMinformeeList.h>
45 #include <IOKit/pwr_mgt/IOPowerConnection.h>
46 #include <IOKit/pwr_mgt/RootDomain.h>
47 #include <IOKit/pwr_mgt/IOPMPrivate.h>
48
49 #include <sys/proc.h>
50 #include <sys/proc_internal.h>
51 #include <libkern/OSDebug.h>
52
53 // Required for notification instrumentation
54 #include "IOServicePrivate.h"
55 #include "IOServicePMPrivate.h"
56 #include "IOKitKernelInternal.h"
57
58 static void settle_timer_expired(thread_call_param_t, thread_call_param_t);
59 static void idle_timer_expired(thread_call_param_t, thread_call_param_t);
60 static void tellKernelClientApplier(OSObject * object, void * arg);
61 static void tellAppClientApplier(OSObject * object, void * arg);
62
63 static uint64_t computeTimeDeltaNS( const AbsoluteTime * start )
64 {
65 AbsoluteTime now;
66 uint64_t nsec;
67
68 clock_get_uptime(&now);
69 SUB_ABSOLUTETIME(&now, start);
70 absolutetime_to_nanoseconds(now, &nsec);
71 return nsec;
72 }
73
74 #if PM_VARS_SUPPORT
75 OSDefineMetaClassAndStructors(IOPMprot, OSObject)
76 #endif
77
78 // Container class for recording system power events
79 OSDefineMetaClassAndStructors( PMEventDetails, OSObject );
80
81 //******************************************************************************
82 // Globals
83 //******************************************************************************
84
85 static bool gIOPMInitialized = false;
86 static uint32_t gIOPMBusyCount = 0;
87 static uint32_t gIOPMWorkCount = 0;
88 static IOWorkLoop * gIOPMWorkLoop = 0;
89 static IOPMRequestQueue * gIOPMRequestQueue = 0;
90 static IOPMRequestQueue * gIOPMReplyQueue = 0;
91 static IOPMWorkQueue * gIOPMWorkQueue = 0;
92 static IOPMCompletionQueue * gIOPMFreeQueue = 0;
93 static IOPMRequest * gIOPMRequest = 0;
94 static IOService * gIOPMRootNode = 0;
95 static IOPlatformExpert * gPlatform = 0;
96
97 static const OSSymbol * gIOPMPowerClientDevice = 0;
98 static const OSSymbol * gIOPMPowerClientDriver = 0;
99 static const OSSymbol * gIOPMPowerClientChildProxy = 0;
100 static const OSSymbol * gIOPMPowerClientChildren = 0;
101
102 static uint32_t getPMRequestType( void )
103 {
104 uint32_t type = kIOPMRequestTypeInvalid;
105 if (gIOPMRequest)
106 type = gIOPMRequest->getType();
107 return type;
108 }
109
110 //******************************************************************************
111 // Macros
112 //******************************************************************************
113
114 #define PM_ERROR(x...) do { kprintf(x); IOLog(x); } while (false)
115 #define PM_LOG(x...) do { kprintf(x); } while (false)
116
117 #define PM_LOG1(x...) do { \
118 if (kIOLogDebugPower & gIOKitDebug) \
119 kprintf(x); } while (false)
120
121 #define PM_LOG2(x...) do { \
122 if (kIOLogDebugPower & gIOKitDebug) \
123 kprintf(x); } while (false)
124
125 #if 0
126 #define PM_LOG3(x...) do { kprintf(x); } while (false)
127 #else
128 #define PM_LOG3(x...)
129 #endif
130
131 #define RD_LOG(x...) do { \
132 if ((kIOLogPMRootDomain & gIOKitDebug) && \
133 (getPMRootDomain() == this)) \
134 kprintf("PMRD: " x); } while (false)
135
136 #define PM_ASSERT_IN_GATE(x) \
137 do { \
138 assert(gIOPMWorkLoop->inGate()); \
139 } while(false)
140
141 #define PM_LOCK() IOLockLock(fPMLock)
142 #define PM_UNLOCK() IOLockUnlock(fPMLock)
143 #define PM_LOCK_SLEEP(event, dl) IOLockSleepDeadline(fPMLock, event, dl, THREAD_UNINT)
144 #define PM_LOCK_WAKEUP(event) IOLockWakeup(fPMLock, event, false)
145
146 #define ns_per_us 1000
147 #define k30Seconds (30*1000000)
148 #define kMinAckTimeoutTicks (10*1000000)
149 #define kIOPMTardyAckSPSKey "IOPMTardyAckSetPowerState"
150 #define kIOPMTardyAckPSCKey "IOPMTardyAckPowerStateChange"
151 #define kPwrMgtKey "IOPowerManagement"
152
153 #define OUR_PMLog(t, a, b) \
154 do { gPlatform->PMLog( fName, t, a, b); } while(0)
155
156 #define NS_TO_MS(nsec) ((int)((nsec) / 1000000ULL))
157 #define NS_TO_US(nsec) ((int)((nsec) / 1000ULL))
158
159 #if CONFIG_EMBEDDED
160 #define SUPPORT_IDLE_CANCEL 1
161 #endif
162
163 #define kIOPMPowerStateMax 0xFFFFFFFF
164
165 #define IS_PM_ROOT (this == gIOPMRootNode)
166 #define IS_ROOT_DOMAIN (getPMRootDomain() == this)
167 #define IS_POWER_DROP (fHeadNotePowerState < fCurrentPowerState)
168 #define IS_POWER_RISE (fHeadNotePowerState > fCurrentPowerState)
169
170 // log setPowerStates longer than (ns):
171 #define LOG_SETPOWER_TIMES (50ULL * 1000ULL * 1000ULL)
172 // log app responses longer than (ns):
173 #define LOG_APP_RESPONSE_TIMES (100ULL * 1000ULL * 1000ULL)
174 // use message tracer to log messages longer than (ns):
175 #define LOG_APP_RESPONSE_MSG_TRACER (3 * 1000ULL * 1000ULL * 1000ULL)
176
177 enum {
178 kReserveDomainPower = 1
179 };
180
181 #define MS_PUSH(n) \
182 do { assert(kIOPM_BadMachineState == fSavedMachineState); \
183 assert(kIOPM_BadMachineState != n); \
184 fSavedMachineState = n; } while (false)
185
186 #define MS_POP() \
187 do { assert(kIOPM_BadMachineState != fSavedMachineState); \
188 fMachineState = fSavedMachineState; \
189 fSavedMachineState = kIOPM_BadMachineState; } while (false)
190
191 #define PM_ACTION_0(a) \
192 do { if (fPMActions.a) { \
193 (fPMActions.a)(fPMActions.target, this, &fPMActions); } \
194 } while (false)
195
196 #define PM_ACTION_2(a, x, y) \
197 do { if (fPMActions.a) { \
198 (fPMActions.a)(fPMActions.target, this, &fPMActions, x, y); } \
199 } while (false)
200
201 static OSNumber * copyClientIDForNotification(
202 OSObject *object,
203 IOPMInterestContext *context);
204
205 static void logClientIDForNotification(
206 OSObject *object,
207 IOPMInterestContext *context,
208 const char *logString);
209
210
211 //*********************************************************************************
212 // PM machine states
213 //
214 // Check kgmacros after modifying machine states.
215 //*********************************************************************************
216
217 enum {
218 kIOPM_Finished = 0,
219
220 kIOPM_OurChangeTellClientsPowerDown = 1,
221 kIOPM_OurChangeTellPriorityClientsPowerDown = 2,
222 kIOPM_OurChangeNotifyInterestedDriversWillChange = 3,
223 kIOPM_OurChangeSetPowerState = 4,
224 kIOPM_OurChangeWaitForPowerSettle = 5,
225 kIOPM_OurChangeNotifyInterestedDriversDidChange = 6,
226 kIOPM_OurChangeTellCapabilityDidChange = 7,
227 kIOPM_OurChangeFinish = 8,
228
229 kIOPM_ParentChangeTellPriorityClientsPowerDown = 10,
230 kIOPM_ParentChangeNotifyInterestedDriversWillChange = 11,
231 kIOPM_ParentChangeSetPowerState = 12,
232 kIOPM_ParentChangeWaitForPowerSettle = 13,
233 kIOPM_ParentChangeNotifyInterestedDriversDidChange = 14,
234 kIOPM_ParentChangeTellCapabilityDidChange = 15,
235 kIOPM_ParentChangeAcknowledgePowerChange = 16,
236
237 kIOPM_NotifyChildrenStart = 17,
238 kIOPM_NotifyChildrenOrdered = 18,
239 kIOPM_NotifyChildrenDelayed = 19,
240 kIOPM_SyncTellClientsPowerDown = 20,
241 kIOPM_SyncTellPriorityClientsPowerDown = 21,
242 kIOPM_SyncNotifyWillChange = 22,
243 kIOPM_SyncNotifyDidChange = 23,
244 kIOPM_SyncTellCapabilityDidChange = 24,
245 kIOPM_SyncFinish = 25,
246 kIOPM_TellCapabilityChangeDone = 26,
247 kIOPM_DriverThreadCallDone = 27,
248
249 kIOPM_BadMachineState = 0xFFFFFFFF
250 };
251
252
253 /*
254 Power Management defines a few roles that drivers can play in their own,
255 and other drivers', power management. We briefly define those here.
256
257 Many drivers implement their policy maker and power controller within the same
258 IOService object, but that is not required.
259
260 == Policy Maker ==
261 * Virtual IOService PM methods a "policy maker" may implement
262 * maxCapabilityForDomainState()
263 * initialPowerStateForDomainState()
264 * powerStateForDomainState()
265
266 * Virtual IOService PM methods a "policy maker" may CALL
267 * PMinit()
268
269 == Power Controller ==
270 * Virtual IOService PM methods a "power controller" may implement
271 * setPowerState()
272
273 * Virtual IOService PM methods a "power controller" may CALL
274 * joinPMtree()
275 * registerPowerDriver()
276
277 =======================
278 There are two different kinds of power state changes.
279 * One is initiated by a subclassed device object which has either decided
280 to change power state, or its controlling driver has suggested it, or
281 some other driver wants to use the idle device and has asked it to become
282 usable.
283 * The second kind of power state change is initiated by the power domain
284 parent.
285 The two are handled through different code paths.
286
287 We maintain a queue of "change notifications," or change notes.
288 * Usually the queue is empty.
289 * When it isn't, usually there is one change note in it
290 * It's possible to have more than one power state change pending at one
291 time, so a queue is implemented.
292 Example:
293 * The subclass device decides it's idle and initiates a change to a lower
294 power state. This causes interested parties to be notified, but they
295 don't all acknowledge right away. This causes the change note to sit
296 in the queue until all the acks are received. During this time, the
297 device decides it isn't idle anymore and wants to raise power back up
298 again. This change can't be started, however, because the previous one
299 isn't complete yet, so the second one waits in the queue. During this
300 time, the parent decides to lower or raise the power state of the entire
301 power domain and notifies the device, and that notification goes into
302 the queue, too, and can't be actioned until the others are.
303
304 == SelfInitiated ==
305 This is how a power change initiated by the subclass device is handled:
306 -> First, all interested parties are notified of the change via their
307 powerStateWillChangeTo method. If they all don't acknowledge via return
308 code, then we have to wait. If they do, or when they finally all
309 acknowledge via our acknowledgePowerChange method, then we can continue.
310 -> We call the controlling driver, instructing it to change to the new state
311 -> Then we wait for power to settle. If there is no settling-time, or after
312 it has passed,
313 -> we notify interested parties again, this time via their
314 powerStateDidChangeTo methods.
315 -> When they have all acked, we're done.
316 If we lowered power and don't need the power domain to be in its current power
317 state, we suggest to the parent that it lower the power domain state.
318
319 == PowerDomainDownInitiated ==
320 How a change to a lower power domain state initiated by the parent is handled:
321 -> First, we figure out what power state we will be in when the new domain
322 state is reached.
323 -> Then all interested parties are notified that we are moving to that new
324 state.
325 -> When they have acknowledged, we call the controlling driver to assume
326 that state and we wait for power to settle.
327 -> Then we acknowledge our preparedness to our parent. When all its
328 interested parties have acknowledged,
329 -> it lowers power and then notifies its interested parties again.
330 -> When we get this call, we notify our interested parties that the power
331 state has changed, and when they have all acknowledged, we're done.
332
333 == PowerDomainUpInitiated ==
334 How a change to a higher power domain state initiated by the parent is handled:
335 -> We figure out what power state we will be in when the new domain state is
336 reached.
337 -> If it is different from our current state we acknowledge the parent.
338 -> When all the parent's interested parties have acknowledged, it raises
339 power in the domain and waits for power to settle.
340 -> Then it notifies everyone that the new state has been reached.
341 -> When we get this call, we call the controlling driver, instructing it to
342 assume the new state, and wait for power to settle.
343 -> Then we notify our interested parties. When they all acknowledge we are
344 done.
345
346 In either of the two power domain state cases above, it is possible that we
347 will not be changing state even though the domain is.
348 Examples:
349 * A change to a lower domain state may not affect us because we are already
350 in a low enough state,
351 * We will not take advantage of a change to a higher domain state, because
352 we have no need of the higher power. In such cases, there is nothing to
353 do but acknowledge the parent. So when the parent calls our
354 powerDomainWillChange method, and we decide that we will not be changing
355 state, we merely acknowledge the parent, via return code, and wait.
356 When the parent subsequently calls powerStateDidChange, we acknowledge again
357 via return code, and the change is complete.
358
359 == 4 Paths Through State Machine ==
360 Power state changes are processed in a state machine, and since there are four
361 varieties of power state changes, there are four major paths through the state
362 machine.
363
364 == 5. No Need To change ==
365 The fourth is nearly trivial. In this path, the parent is changing the domain
366 state, but we are not changing the device state. The change starts when the
367 parent calls powerDomainWillChange. All we do is acknowledge the parent. When
368 the parent calls powerStateDidChange, we acknowledge the parent again, and
369 we're done.
370
371 == 1. OurChange Down == XXX gvdl
372 The first is fairly simple. It starts:
373 * when a power domain child calls requestPowerDomainState and we decide to
374 change power states to accomodate the child,
375 * or if our power-controlling driver calls changePowerStateTo,
376 * or if some other driver which is using our device calls makeUsable,
377 * or if a subclassed object calls changePowerStateToPriv.
378 These are all power changes initiated by us, not forced upon us by the parent.
379
380 -> We start by notifying interested parties.
381 -> If they all acknowledge via return code, we can go on to state
382 "msSetPowerState".
383 -> Otherwise, we start the ack timer and wait for the stragglers to
384 acknowlege by calling acknowledgePowerChange.
385 -> We move on to state "msSetPowerState" when all the
386 stragglers have acknowledged, or when the ack timer expires on
387 all those which didn't acknowledge.
388 In "msSetPowerState" we call the power-controlling driver to change the
389 power state of the hardware.
390 -> If it returns saying it has done so, we go on to state
391 "msWaitForPowerSettle".
392 -> Otherwise, we have to wait for it, so we set the ack timer and wait.
393 -> When it calls acknowledgeSetPowerState, or when the ack timer
394 expires, we go on.
395 In "msWaitForPowerSettle", we look in the power state array to see if
396 there is any settle time required when changing from our current state to the
397 new state.
398 -> If not, we go right away to "msNotifyInterestedDriversDidChange".
399 -> Otherwise, we set the settle timer and wait. When it expires, we move on.
400 In "msNotifyInterestedDriversDidChange" state, we notify all our
401 interested parties via their powerStateDidChange methods that we have finished
402 changing power state.
403 -> If they all acknowledge via return code, we move on to "msFinish".
404 -> Otherwise we set the ack timer and wait. When they have all
405 acknowledged, or when the ack timer has expired for those that didn't,
406 we move on to "msFinish".
407 In "msFinish" we remove the used change note from the head of the queue
408 and start the next one if one exists.
409
410 == 2. Parent Change Down ==
411 Start at Stage 2 of OurChange Down XXX gvdl
412
413 == 3. Change Up ==
414 Start at Stage 4 of OurChange Down XXX gvdl
415
416 Note all parent requested changes need to acknowledge the power has changed to the parent when done.
417 */
418
419 //*********************************************************************************
420 // [public] PMinit
421 //
422 // Initialize power management.
423 //*********************************************************************************
424
425 void IOService::PMinit ( void )
426 {
427 if ( !initialized )
428 {
429 if ( !gIOPMInitialized )
430 {
431 gPlatform = getPlatform();
432 gIOPMWorkLoop = IOWorkLoop::workLoop();
433 if (gIOPMWorkLoop)
434 {
435 gIOPMRequestQueue = IOPMRequestQueue::create(
436 this, OSMemberFunctionCast(IOPMRequestQueue::Action,
437 this, &IOService::servicePMRequestQueue));
438
439 gIOPMReplyQueue = IOPMRequestQueue::create(
440 this, OSMemberFunctionCast(IOPMRequestQueue::Action,
441 this, &IOService::servicePMReplyQueue));
442
443 gIOPMWorkQueue = IOPMWorkQueue::create(
444 this,
445 OSMemberFunctionCast(IOPMWorkQueue::Action, this,
446 &IOService::servicePMRequest),
447 OSMemberFunctionCast(IOPMWorkQueue::Action, this,
448 &IOService::retirePMRequest));
449
450 gIOPMFreeQueue = IOPMCompletionQueue::create(
451 this, OSMemberFunctionCast(IOPMCompletionQueue::Action,
452 this, &IOService::servicePMFreeQueue));
453
454 if (gIOPMWorkLoop->addEventSource(gIOPMRequestQueue) !=
455 kIOReturnSuccess)
456 {
457 gIOPMRequestQueue->release();
458 gIOPMRequestQueue = 0;
459 }
460
461 if (gIOPMWorkLoop->addEventSource(gIOPMReplyQueue) !=
462 kIOReturnSuccess)
463 {
464 gIOPMReplyQueue->release();
465 gIOPMReplyQueue = 0;
466 }
467
468 if (gIOPMWorkLoop->addEventSource(gIOPMWorkQueue) !=
469 kIOReturnSuccess)
470 {
471 gIOPMWorkQueue->release();
472 gIOPMWorkQueue = 0;
473 }
474
475 if (gIOPMWorkLoop->addEventSource(gIOPMFreeQueue) !=
476 kIOReturnSuccess)
477 {
478 gIOPMFreeQueue->release();
479 gIOPMFreeQueue = 0;
480 }
481
482 gIOPMPowerClientDevice =
483 OSSymbol::withCStringNoCopy( "DevicePowerState" );
484
485 gIOPMPowerClientDriver =
486 OSSymbol::withCStringNoCopy( "DriverPowerState" );
487
488 gIOPMPowerClientChildProxy =
489 OSSymbol::withCStringNoCopy( "ChildProxyPowerState" );
490
491 gIOPMPowerClientChildren =
492 OSSymbol::withCStringNoCopy( "ChildrenPowerState" );
493 }
494
495 if (gIOPMRequestQueue && gIOPMReplyQueue && gIOPMFreeQueue)
496 gIOPMInitialized = true;
497 }
498 if (!gIOPMInitialized)
499 return;
500
501 pwrMgt = new IOServicePM;
502 pwrMgt->init();
503 setProperty(kPwrMgtKey, pwrMgt);
504
505 queue_init(&pwrMgt->WorkChain);
506 queue_init(&pwrMgt->RequestHead);
507 queue_init(&pwrMgt->PMDriverCallQueue);
508
509 fOwner = this;
510 fPMLock = IOLockAlloc();
511 fInterestedDrivers = new IOPMinformeeList;
512 fInterestedDrivers->initialize();
513 fDesiredPowerState = 0;
514 fDeviceDesire = 0;
515 fInitialPowerChange = true;
516 fInitialSetPowerState = true;
517 fPreviousRequestPowerFlags = 0;
518 fDeviceOverrideEnabled = false;
519 fMachineState = kIOPM_Finished;
520 fSavedMachineState = kIOPM_BadMachineState;
521 fIdleTimerMinPowerState = 0;
522 fActivityLock = IOLockAlloc();
523 fStrictTreeOrder = false;
524 fActivityTicklePowerState = -1;
525 fControllingDriver = NULL;
526 fPowerStates = NULL;
527 fNumberOfPowerStates = 0;
528 fCurrentPowerState = 0;
529 fParentsCurrentPowerFlags = 0;
530 fMaxPowerState = 0;
531 fName = getName();
532 fParentsKnowState = false;
533 fSerialNumber = 0;
534 fResponseArray = NULL;
535 fNotifyClientArray = NULL;
536 fCurrentPowerConsumption = kIOPMUnknown;
537 fOverrideMaxPowerState = kIOPMPowerStateMax;
538
539 if (!gIOPMRootNode && (getParentEntry(gIOPowerPlane) == getRegistryRoot()))
540 {
541 gIOPMRootNode = this;
542 fParentsKnowState = true;
543 }
544
545 fAckTimer = thread_call_allocate(
546 &IOService::ack_timer_expired, (thread_call_param_t)this);
547 fSettleTimer = thread_call_allocate(
548 &settle_timer_expired, (thread_call_param_t)this);
549 fIdleTimer = thread_call_allocate(
550 &idle_timer_expired, (thread_call_param_t)this);
551 fDriverCallEntry = thread_call_allocate(
552 (thread_call_func_t) &IOService::pmDriverCallout, this);
553 assert(fDriverCallEntry);
554
555 // Check for powerChangeDone override.
556 if (OSMemberFunctionCast(void (*)(void),
557 getResourceService(), &IOService::powerChangeDone) !=
558 OSMemberFunctionCast(void (*)(void),
559 this, &IOService::powerChangeDone))
560 {
561 fPCDFunctionOverride = true;
562 }
563
564 #if PM_VARS_SUPPORT
565 IOPMprot * prot = new IOPMprot;
566 if (prot)
567 {
568 prot->init();
569 prot->ourName = fName;
570 prot->thePlatform = gPlatform;
571 fPMVars = prot;
572 pm_vars = prot;
573 }
574 #else
575 pm_vars = (void *) (uintptr_t) true;
576 #endif
577
578 initialized = true;
579 }
580 }
581
582 //*********************************************************************************
583 // [private] PMfree
584 //
585 // Free the data created by PMinit. Only called from IOService::free().
586 //*********************************************************************************
587
588 void IOService::PMfree ( void )
589 {
590 initialized = false;
591 pm_vars = 0;
592
593 if ( pwrMgt )
594 {
595 assert(fMachineState == kIOPM_Finished);
596 assert(fInsertInterestSet == NULL);
597 assert(fRemoveInterestSet == NULL);
598 assert(fNotifyChildArray == NULL);
599 assert(queue_empty(&pwrMgt->RequestHead));
600 assert(queue_empty(&fPMDriverCallQueue));
601
602 if ( fSettleTimer ) {
603 thread_call_cancel(fSettleTimer);
604 thread_call_free(fSettleTimer);
605 fSettleTimer = NULL;
606 }
607 if ( fAckTimer ) {
608 thread_call_cancel(fAckTimer);
609 thread_call_free(fAckTimer);
610 fAckTimer = NULL;
611 }
612 if ( fIdleTimer ) {
613 thread_call_cancel(fIdleTimer);
614 thread_call_free(fIdleTimer);
615 fIdleTimer = NULL;
616 }
617 if ( fDriverCallEntry ) {
618 thread_call_free(fDriverCallEntry);
619 fDriverCallEntry = NULL;
620 }
621 if ( fPMLock ) {
622 IOLockFree(fPMLock);
623 fPMLock = NULL;
624 }
625 if ( fActivityLock ) {
626 IOLockFree(fActivityLock);
627 fActivityLock = NULL;
628 }
629 if ( fInterestedDrivers ) {
630 fInterestedDrivers->release();
631 fInterestedDrivers = NULL;
632 }
633 if (fDriverCallParamSlots && fDriverCallParamPtr) {
634 IODelete(fDriverCallParamPtr, DriverCallParam, fDriverCallParamSlots);
635 fDriverCallParamPtr = 0;
636 fDriverCallParamSlots = 0;
637 }
638 if ( fResponseArray ) {
639 fResponseArray->release();
640 fResponseArray = NULL;
641 }
642 if ( fNotifyClientArray ) {
643 fNotifyClientArray->release();
644 fNotifyClientArray = NULL;
645 }
646 if (fPowerStates && fNumberOfPowerStates) {
647 IODelete(fPowerStates, IOPMPSEntry, fNumberOfPowerStates);
648 fNumberOfPowerStates = 0;
649 fPowerStates = NULL;
650 }
651 if (fPowerClients) {
652 fPowerClients->release();
653 fPowerClients = 0;
654 }
655
656 #if PM_VARS_SUPPORT
657 if (fPMVars)
658 {
659 fPMVars->release();
660 fPMVars = 0;
661 }
662 #endif
663
664 pwrMgt->release();
665 pwrMgt = 0;
666 }
667 }
668
669 //*********************************************************************************
670 // [public] joinPMtree
671 //
672 // A policy-maker calls its nub here when initializing, to be attached into
673 // the power management hierarchy. The default function is to call the
674 // platform expert, which knows how to do it. This method is overridden
675 // by a nub subclass which may either know how to do it, or may need to
676 // take other action.
677 //
678 // This may be the only "power management" method used in a nub,
679 // meaning it may not be initialized for power management.
680 //*********************************************************************************
681
682 void IOService::joinPMtree ( IOService * driver )
683 {
684 IOPlatformExpert * platform;
685
686 platform = getPlatform();
687 assert(platform != 0);
688 platform->PMRegisterDevice(this, driver);
689 }
690
691 #ifndef __LP64__
692 //*********************************************************************************
693 // [deprecated] youAreRoot
694 //
695 // Power Managment is informing us that we are the root power domain.
696 //*********************************************************************************
697
698 IOReturn IOService::youAreRoot ( void )
699 {
700 return IOPMNoErr;
701 }
702 #endif /* !__LP64__ */
703
704 //*********************************************************************************
705 // [public] PMstop
706 //
707 // Immediately stop driver callouts. Schedule an async stop request to detach
708 // from power plane.
709 //*********************************************************************************
710
711 void IOService::PMstop ( void )
712 {
713 IOPMRequest * request;
714
715 if (!initialized)
716 return;
717
718 PM_LOCK();
719
720 if (fLockedFlags.PMStop)
721 {
722 PM_LOG2("%s: PMstop() already stopped\n", fName);
723 PM_UNLOCK();
724 return;
725 }
726
727 // Inhibit future driver calls.
728 fLockedFlags.PMStop = true;
729
730 // Wait for all prior driver calls to finish.
731 waitForPMDriverCall();
732
733 PM_UNLOCK();
734
735 // The rest of the work is performed async.
736 request = acquirePMRequest( this, kIOPMRequestTypePMStop );
737 if (request)
738 {
739 PM_LOG2("%s: %p PMstop\n", getName(), this);
740 submitPMRequest( request );
741 }
742 }
743
744 //*********************************************************************************
745 // [private] handlePMstop
746 //
747 // Disconnect the node from all parents and children in the power plane.
748 //*********************************************************************************
749
750 void IOService::handlePMstop ( IOPMRequest * request )
751 {
752 OSIterator * iter;
753 OSObject * next;
754 IOPowerConnection * connection;
755 IOService * theChild;
756 IOService * theParent;
757
758 PM_ASSERT_IN_GATE();
759 PM_LOG2("%s: %p %s start\n", getName(), this, __FUNCTION__);
760
761 // remove driver from prevent system sleep lists
762 getPMRootDomain()->updatePreventIdleSleepList(this, false);
763 getPMRootDomain()->updatePreventSystemSleepList(this, false);
764
765 // remove the property
766 removeProperty(kPwrMgtKey);
767
768 // detach parents
769 iter = getParentIterator(gIOPowerPlane);
770 if ( iter )
771 {
772 while ( (next = iter->getNextObject()) )
773 {
774 if ( (connection = OSDynamicCast(IOPowerConnection, next)) )
775 {
776 theParent = (IOService *)connection->copyParentEntry(gIOPowerPlane);
777 if ( theParent )
778 {
779 theParent->removePowerChild(connection);
780 theParent->release();
781 }
782 }
783 }
784 iter->release();
785 }
786
787 // detach IOConnections
788 detachAbove( gIOPowerPlane );
789
790 // no more power state changes
791 fParentsKnowState = false;
792
793 // detach children
794 iter = getChildIterator(gIOPowerPlane);
795 if ( iter )
796 {
797 while ( (next = iter->getNextObject()) )
798 {
799 if ( (connection = OSDynamicCast(IOPowerConnection, next)) )
800 {
801 theChild = ((IOService *)(connection->copyChildEntry(gIOPowerPlane)));
802 if ( theChild )
803 {
804 // detach nub from child
805 connection->detachFromChild(theChild, gIOPowerPlane);
806 theChild->release();
807 }
808 // detach us from nub
809 detachFromChild(connection, gIOPowerPlane);
810 }
811 }
812 iter->release();
813 }
814
815 // Remove all interested drivers from the list, including the power
816 // controlling driver.
817 //
818 // Usually, the controlling driver and the policy-maker functionality
819 // are implemented by the same object, and without the deregistration,
820 // the object will be holding an extra retain on itself, and cannot
821 // be freed.
822
823 if ( fInterestedDrivers )
824 {
825 IOPMinformeeList * list = fInterestedDrivers;
826 IOPMinformee * item;
827
828 PM_LOCK();
829 while ((item = list->firstInList()))
830 {
831 list->removeFromList(item->whatObject);
832 }
833 PM_UNLOCK();
834 }
835
836 // Tell idleTimerExpired() to ignore idle timer.
837 fIdleTimerPeriod = 0;
838 if (fIdleTimer && thread_call_cancel(fIdleTimer))
839 release();
840
841 PM_LOG2("%s: %p %s done\n", getName(), this, __FUNCTION__);
842 }
843
844 //*********************************************************************************
845 // [public] addPowerChild
846 //
847 // Power Management is informing us who our children are.
848 //*********************************************************************************
849
850 IOReturn IOService::addPowerChild ( IOService * child )
851 {
852 IOPowerConnection * connection = 0;
853 IOPMRequest * requests[3] = {0, 0, 0};
854 OSIterator * iter;
855 bool ok = true;
856
857 if (!child)
858 return kIOReturnBadArgument;
859
860 if (!initialized || !child->initialized)
861 return IOPMNotYetInitialized;
862
863 OUR_PMLog( kPMLogAddChild, (uintptr_t) child, 0 );
864
865 do {
866 // Is this child already one of our children?
867
868 iter = child->getParentIterator( gIOPowerPlane );
869 if ( iter )
870 {
871 IORegistryEntry * entry;
872 OSObject * next;
873
874 while ((next = iter->getNextObject()))
875 {
876 if ((entry = OSDynamicCast(IORegistryEntry, next)) &&
877 isChild(entry, gIOPowerPlane))
878 {
879 ok = false;
880 break;
881 }
882 }
883 iter->release();
884 }
885 if (!ok)
886 {
887 PM_LOG("%s: %s (%p) is already a child\n",
888 getName(), child->getName(), child);
889 break;
890 }
891
892 // Add the child to the power plane immediately, but the
893 // joining connection is marked as not ready.
894 // We want the child to appear in the power plane before
895 // returning to the caller, but don't want the caller to
896 // block on the PM work loop.
897
898 connection = new IOPowerConnection;
899 if (!connection)
900 break;
901
902 // Create a chain of PM requests to perform the bottom-half
903 // work from the PM work loop.
904
905 requests[0] = acquirePMRequest(
906 /* target */ this,
907 /* type */ kIOPMRequestTypeAddPowerChild1 );
908
909 requests[1] = acquirePMRequest(
910 /* target */ child,
911 /* type */ kIOPMRequestTypeAddPowerChild2 );
912
913 requests[2] = acquirePMRequest(
914 /* target */ this,
915 /* type */ kIOPMRequestTypeAddPowerChild3 );
916
917 if (!requests[0] || !requests[1] || !requests[2])
918 break;
919
920 requests[0]->attachNextRequest( requests[1] );
921 requests[1]->attachNextRequest( requests[2] );
922
923 connection->init();
924 connection->start(this);
925 connection->setAwaitingAck(false);
926 connection->setReadyFlag(false);
927
928 attachToChild( connection, gIOPowerPlane );
929 connection->attachToChild( child, gIOPowerPlane );
930
931 // connection needs to be released
932 requests[0]->fArg0 = connection;
933 requests[1]->fArg0 = connection;
934 requests[2]->fArg0 = connection;
935
936 submitPMRequest( requests, 3 );
937 return kIOReturnSuccess;
938 }
939 while (false);
940
941 if (connection) connection->release();
942 if (requests[0]) releasePMRequest(requests[0]);
943 if (requests[1]) releasePMRequest(requests[1]);
944 if (requests[2]) releasePMRequest(requests[2]);
945
946 // Silent failure, to prevent platform drivers from adding the child
947 // to the root domain.
948
949 return kIOReturnSuccess;
950 }
951
952 //*********************************************************************************
953 // [private] addPowerChild1
954 //
955 // Step 1/3 of adding a power child. Called on the power parent.
956 //*********************************************************************************
957
958 void IOService::addPowerChild1 ( IOPMRequest * request )
959 {
960 unsigned long tempDesire = 0;
961
962 // Make us temporary usable before adding the child.
963
964 PM_ASSERT_IN_GATE();
965 OUR_PMLog( kPMLogMakeUsable, kPMLogMakeUsable, 0 );
966
967 if (fControllingDriver && inPlane(gIOPowerPlane) && fParentsKnowState)
968 {
969 tempDesire = fNumberOfPowerStates - 1;
970 }
971
972 if (tempDesire && (IS_PM_ROOT || (fMaxPowerState >= tempDesire)))
973 {
974 adjustPowerState(tempDesire);
975 }
976 }
977
978 //*********************************************************************************
979 // [private] addPowerChild2
980 //
981 // Step 2/3 of adding a power child. Called on the joining child.
982 // Execution blocked behind addPowerChild1.
983 //*********************************************************************************
984
985 void IOService::addPowerChild2 ( IOPMRequest * request )
986 {
987 IOPowerConnection * connection = (IOPowerConnection *) request->fArg0;
988 IOService * parent;
989 IOPMPowerFlags powerFlags;
990 bool knowsState;
991 unsigned long powerState;
992 unsigned long tempDesire;
993
994 PM_ASSERT_IN_GATE();
995 parent = (IOService *) connection->getParentEntry(gIOPowerPlane);
996
997 if (!parent || !inPlane(gIOPowerPlane))
998 {
999 PM_LOG("%s: addPowerChild2 not in power plane\n", getName());
1000 return;
1001 }
1002
1003 // Parent will be waiting for us to complete this stage.
1004 // It is safe to directly access parent's vars.
1005
1006 knowsState = (parent->fPowerStates) && (parent->fParentsKnowState);
1007 powerState = parent->fCurrentPowerState;
1008
1009 if (knowsState)
1010 powerFlags = parent->fPowerStates[powerState].outputPowerFlags;
1011 else
1012 powerFlags = 0;
1013
1014 // Set our power parent.
1015
1016 OUR_PMLog(kPMLogSetParent, knowsState, powerFlags);
1017
1018 setParentInfo( powerFlags, connection, knowsState );
1019
1020 connection->setReadyFlag(true);
1021
1022 if ( fControllingDriver && fParentsKnowState )
1023 {
1024 fMaxPowerState = fControllingDriver->maxCapabilityForDomainState(fParentsCurrentPowerFlags);
1025 // initially change into the state we are already in
1026 tempDesire = fControllingDriver->initialPowerStateForDomainState(fParentsCurrentPowerFlags);
1027 fPreviousRequestPowerFlags = (IOPMPowerFlags)(-1);
1028 adjustPowerState(tempDesire);
1029 }
1030
1031 getPMRootDomain()->tagPowerPlaneService(this, &fPMActions);
1032 }
1033
1034 //*********************************************************************************
1035 // [private] addPowerChild3
1036 //
1037 // Step 3/3 of adding a power child. Called on the parent.
1038 // Execution blocked behind addPowerChild2.
1039 //*********************************************************************************
1040
1041 void IOService::addPowerChild3 ( IOPMRequest * request )
1042 {
1043 IOPowerConnection * connection = (IOPowerConnection *) request->fArg0;
1044 IOService * child;
1045 IOPMrootDomain * rootDomain = getPMRootDomain();
1046
1047 PM_ASSERT_IN_GATE();
1048 child = (IOService *) connection->getChildEntry(gIOPowerPlane);
1049
1050 if (child && inPlane(gIOPowerPlane))
1051 {
1052 if ((this != rootDomain) && child->getProperty("IOPMStrictTreeOrder"))
1053 {
1054 PM_LOG1("%s: strict PM order enforced\n", getName());
1055 fStrictTreeOrder = true;
1056 }
1057
1058 if (rootDomain)
1059 rootDomain->joinAggressiveness( child );
1060 }
1061 else
1062 {
1063 PM_LOG("%s: addPowerChild3 not in power plane\n", getName());
1064 }
1065
1066 connection->release();
1067 }
1068
1069 #ifndef __LP64__
1070 //*********************************************************************************
1071 // [deprecated] setPowerParent
1072 //
1073 // Power Management is informing us who our parent is.
1074 // If we have a controlling driver, find out, given our newly-informed
1075 // power domain state, what state it would be in, and then tell it
1076 // to assume that state.
1077 //*********************************************************************************
1078
1079 IOReturn IOService::setPowerParent (
1080 IOPowerConnection * theParent, bool stateKnown, IOPMPowerFlags powerFlags )
1081 {
1082 return kIOReturnUnsupported;
1083 }
1084 #endif /* !__LP64__ */
1085
1086 //*********************************************************************************
1087 // [public] removePowerChild
1088 //
1089 // Called on a parent whose child is being removed by PMstop().
1090 //*********************************************************************************
1091
1092 IOReturn IOService::removePowerChild ( IOPowerConnection * theNub )
1093 {
1094 IORegistryEntry * theChild;
1095
1096 PM_ASSERT_IN_GATE();
1097 OUR_PMLog( kPMLogRemoveChild, 0, 0 );
1098
1099 theNub->retain();
1100
1101 // detach nub from child
1102 theChild = theNub->copyChildEntry(gIOPowerPlane);
1103 if ( theChild )
1104 {
1105 theNub->detachFromChild(theChild, gIOPowerPlane);
1106 theChild->release();
1107 }
1108 // detach from the nub
1109 detachFromChild(theNub, gIOPowerPlane);
1110
1111 // Are we awaiting an ack from this child?
1112 if ( theNub->getAwaitingAck() )
1113 {
1114 // yes, pretend we got one
1115 theNub->setAwaitingAck(false);
1116 if (fHeadNotePendingAcks != 0 )
1117 {
1118 // that's one fewer ack to worry about
1119 fHeadNotePendingAcks--;
1120
1121 // is that the last?
1122 if ( fHeadNotePendingAcks == 0 )
1123 {
1124 stop_ack_timer();
1125
1126 // Request unblocked, work queue
1127 // should re-scan all busy requests.
1128 gIOPMWorkQueue->incrementProducerCount();
1129 }
1130 }
1131 }
1132
1133 theNub->release();
1134
1135 // A child has gone away, re-scan children desires and clamp bits.
1136 // The fPendingAdjustPowerRequest helps to reduce redundant parent work.
1137
1138 if (!fAdjustPowerScheduled)
1139 {
1140 IOPMRequest * request;
1141 request = acquirePMRequest( this, kIOPMRequestTypeAdjustPowerState );
1142 if (request)
1143 {
1144 submitPMRequest( request );
1145 fAdjustPowerScheduled = true;
1146 }
1147 }
1148
1149 return IOPMNoErr;
1150 }
1151
1152 //*********************************************************************************
1153 // [public] registerPowerDriver
1154 //
1155 // A driver has called us volunteering to control power to our device.
1156 //*********************************************************************************
1157
1158 IOReturn IOService::registerPowerDriver (
1159 IOService * powerDriver,
1160 IOPMPowerState * powerStates,
1161 unsigned long numberOfStates )
1162 {
1163 IOPMRequest * request;
1164 IOPMPSEntry * powerStatesCopy = 0;
1165
1166 if (!initialized)
1167 return IOPMNotYetInitialized;
1168
1169 // Validate arguments.
1170 if (!powerStates || (numberOfStates < 2))
1171 {
1172 OUR_PMLog(kPMLogControllingDriverErr5, numberOfStates, 0);
1173 return kIOReturnBadArgument;
1174 }
1175
1176 if (!powerDriver || !powerDriver->initialized)
1177 {
1178 OUR_PMLog(kPMLogControllingDriverErr4, 0, 0);
1179 return kIOReturnBadArgument;
1180 }
1181
1182 if (powerStates[0].version != kIOPMPowerStateVersion1)
1183 {
1184 OUR_PMLog(kPMLogControllingDriverErr1, powerStates[0].version, 0);
1185 return kIOReturnBadArgument;
1186 }
1187
1188 do {
1189 // Make a copy of the supplied power state array.
1190 powerStatesCopy = IONew(IOPMPSEntry, numberOfStates);
1191 if (!powerStatesCopy)
1192 break;
1193
1194 for (uint32_t i = 0; i < numberOfStates; i++)
1195 {
1196 powerStatesCopy[i].capabilityFlags = powerStates[i].capabilityFlags;
1197 powerStatesCopy[i].outputPowerFlags = powerStates[i].outputPowerCharacter;
1198 powerStatesCopy[i].inputPowerFlags = powerStates[i].inputPowerRequirement;
1199 powerStatesCopy[i].staticPower = powerStates[i].staticPower;
1200 powerStatesCopy[i].settleUpTime = powerStates[i].settleUpTime;
1201 powerStatesCopy[i].settleDownTime = powerStates[i].settleDownTime;
1202 }
1203
1204 request = acquirePMRequest( this, kIOPMRequestTypeRegisterPowerDriver );
1205 if (!request)
1206 break;
1207
1208 powerDriver->retain();
1209 request->fArg0 = (void *) powerDriver;
1210 request->fArg1 = (void *) powerStatesCopy;
1211 request->fArg2 = (void *) numberOfStates;
1212
1213 submitPMRequest( request );
1214 return kIOReturnSuccess;
1215 }
1216 while (false);
1217
1218 if (powerStatesCopy)
1219 IODelete(powerStatesCopy, IOPMPSEntry, numberOfStates);
1220 return kIOReturnNoMemory;
1221 }
1222
1223 //*********************************************************************************
1224 // [private] handleRegisterPowerDriver
1225 //*********************************************************************************
1226
1227 void IOService::handleRegisterPowerDriver ( IOPMRequest * request )
1228 {
1229 IOService * powerDriver = (IOService *) request->fArg0;
1230 IOPMPSEntry * powerStates = (IOPMPSEntry *) request->fArg1;
1231 unsigned long numberOfStates = (unsigned long) request->fArg2;
1232 unsigned long i;
1233 IOService * root;
1234 OSIterator * iter;
1235
1236 PM_ASSERT_IN_GATE();
1237 assert(powerStates);
1238 assert(powerDriver);
1239 assert(numberOfStates > 1);
1240
1241 if ( !fNumberOfPowerStates )
1242 {
1243 OUR_PMLog(kPMLogControllingDriver,
1244 (unsigned long) numberOfStates,
1245 (unsigned long) kIOPMPowerStateVersion1);
1246
1247 fPowerStates = powerStates;
1248 fNumberOfPowerStates = numberOfStates;
1249 fControllingDriver = powerDriver;
1250 fCurrentCapabilityFlags = fPowerStates[0].capabilityFlags;
1251
1252 // make a mask of all the character bits we know about
1253 fOutputPowerCharacterFlags = 0;
1254 for ( i = 0; i < numberOfStates; i++ ) {
1255 fOutputPowerCharacterFlags |= fPowerStates[i].outputPowerFlags;
1256 }
1257
1258 // Register powerDriver as interested, unless already done.
1259 // We don't want to register the default implementation since
1260 // it does nothing. One ramification of not always registering
1261 // is the one fewer retain count held.
1262
1263 root = getPlatform()->getProvider();
1264 assert(root);
1265 if (!root ||
1266 ((OSMemberFunctionCast(void (*)(void),
1267 root, &IOService::powerStateDidChangeTo)) !=
1268 ((OSMemberFunctionCast(void (*)(void),
1269 this, &IOService::powerStateDidChangeTo)))) ||
1270 ((OSMemberFunctionCast(void (*)(void),
1271 root, &IOService::powerStateWillChangeTo)) !=
1272 ((OSMemberFunctionCast(void (*)(void),
1273 this, &IOService::powerStateWillChangeTo)))))
1274 {
1275 if (fInterestedDrivers->findItem(powerDriver) == NULL)
1276 {
1277 PM_LOCK();
1278 fInterestedDrivers->appendNewInformee(powerDriver);
1279 PM_UNLOCK();
1280 }
1281 }
1282
1283 // Examine all existing power clients and perform limit check.
1284
1285 if (fPowerClients)
1286 {
1287 iter = OSCollectionIterator::withCollection(fPowerClients);
1288 if (iter)
1289 {
1290 const OSSymbol * client;
1291 while ((client = (const OSSymbol *) iter->getNextObject()))
1292 {
1293 uint32_t powerState = getPowerStateForClient(client);
1294 if (powerState >= numberOfStates)
1295 {
1296 updatePowerClient(client, numberOfStates - 1);
1297 }
1298 }
1299 iter->release();
1300 }
1301 }
1302
1303 if ( inPlane(gIOPowerPlane) && fParentsKnowState )
1304 {
1305 unsigned long tempDesire;
1306 fMaxPowerState = fControllingDriver->maxCapabilityForDomainState(fParentsCurrentPowerFlags);
1307 // initially change into the state we are already in
1308 tempDesire = fControllingDriver->initialPowerStateForDomainState(fParentsCurrentPowerFlags);
1309 adjustPowerState(tempDesire);
1310 }
1311 }
1312 else
1313 {
1314 OUR_PMLog(kPMLogControllingDriverErr2, numberOfStates, 0);
1315 IODelete(powerStates, IOPMPSEntry, numberOfStates);
1316 }
1317
1318 powerDriver->release();
1319 }
1320
1321 //*********************************************************************************
1322 // [public] registerInterestedDriver
1323 //
1324 // Add the caller to our list of interested drivers and return our current
1325 // power state. If we don't have a power-controlling driver yet, we will
1326 // call this interested driver again later when we do get a driver and find
1327 // out what the current power state of the device is.
1328 //*********************************************************************************
1329
1330 IOPMPowerFlags IOService::registerInterestedDriver ( IOService * driver )
1331 {
1332 IOPMRequest * request;
1333 bool signal;
1334
1335 if (!driver || !initialized || !fInterestedDrivers)
1336 return 0;
1337
1338 PM_LOCK();
1339 signal = (!fInsertInterestSet && !fRemoveInterestSet);
1340 if (fInsertInterestSet == NULL)
1341 fInsertInterestSet = OSSet::withCapacity(4);
1342 if (fInsertInterestSet)
1343 {
1344 fInsertInterestSet->setObject(driver);
1345 if (fRemoveInterestSet)
1346 fRemoveInterestSet->removeObject(driver);
1347 }
1348 PM_UNLOCK();
1349
1350 if (signal)
1351 {
1352 request = acquirePMRequest( this, kIOPMRequestTypeInterestChanged );
1353 if (request)
1354 submitPMRequest( request );
1355 }
1356
1357 // This return value cannot be trusted, but return a value
1358 // for those clients that care.
1359
1360 OUR_PMLog(kPMLogInterestedDriver, kIOPMDeviceUsable, 2);
1361 return kIOPMDeviceUsable;
1362 }
1363
1364 //*********************************************************************************
1365 // [public] deRegisterInterestedDriver
1366 //*********************************************************************************
1367
1368 IOReturn IOService::deRegisterInterestedDriver ( IOService * driver )
1369 {
1370 IOPMinformeeList * list;
1371 IOPMinformee * item;
1372 IOPMRequest * request;
1373 bool signal;
1374
1375 if (!driver)
1376 return kIOReturnBadArgument;
1377 if (!initialized || !fInterestedDrivers)
1378 return IOPMNotPowerManaged;
1379
1380 PM_LOCK();
1381 signal = (!fRemoveInterestSet && !fInsertInterestSet);
1382 if (fRemoveInterestSet == NULL)
1383 fRemoveInterestSet = OSSet::withCapacity(4);
1384 if (fRemoveInterestSet)
1385 {
1386 fRemoveInterestSet->setObject(driver);
1387 if (fInsertInterestSet)
1388 fInsertInterestSet->removeObject(driver);
1389
1390 list = fInterestedDrivers;
1391 item = list->findItem(driver);
1392 if (item && item->active)
1393 {
1394 item->active = false;
1395 waitForPMDriverCall( driver );
1396 }
1397 }
1398 PM_UNLOCK();
1399
1400 if (signal)
1401 {
1402 request = acquirePMRequest( this, kIOPMRequestTypeInterestChanged );
1403 if (request)
1404 submitPMRequest( request );
1405 }
1406
1407 return IOPMNoErr;
1408 }
1409
1410 //*********************************************************************************
1411 // [private] handleInterestChanged
1412 //
1413 // Handle interest added or removed.
1414 //*********************************************************************************
1415
1416 void IOService::handleInterestChanged( IOPMRequest * request )
1417 {
1418 IOService * driver;
1419 IOPMinformee * informee;
1420 IOPMinformeeList * list = fInterestedDrivers;
1421
1422 PM_LOCK();
1423
1424 if (fInsertInterestSet)
1425 {
1426 while ((driver = (IOService *) fInsertInterestSet->getAnyObject()))
1427 {
1428 if (list->findItem(driver) == NULL)
1429 {
1430 informee = list->appendNewInformee(driver);
1431 }
1432 fInsertInterestSet->removeObject(driver);
1433 }
1434 fInsertInterestSet->release();
1435 fInsertInterestSet = 0;
1436 }
1437
1438 if (fRemoveInterestSet)
1439 {
1440 while ((driver = (IOService *) fRemoveInterestSet->getAnyObject()))
1441 {
1442 informee = list->findItem(driver);
1443 if (informee)
1444 {
1445 // Clean-up async interest acknowledgement
1446 if (fHeadNotePendingAcks && informee->timer)
1447 {
1448 informee->timer = 0;
1449 fHeadNotePendingAcks--;
1450 }
1451 list->removeFromList(driver);
1452 }
1453 fRemoveInterestSet->removeObject(driver);
1454 }
1455 fRemoveInterestSet->release();
1456 fRemoveInterestSet = 0;
1457 }
1458
1459 PM_UNLOCK();
1460 }
1461
1462 //*********************************************************************************
1463 // [public] acknowledgePowerChange
1464 //
1465 // After we notified one of the interested drivers or a power-domain child
1466 // of an impending change in power, it has called to say it is now
1467 // prepared for the change. If this object is the last to
1468 // acknowledge this change, we take whatever action we have been waiting
1469 // for.
1470 // That may include acknowledging to our parent. In this case, we do it
1471 // last of all to insure that this doesn't cause the parent to call us some-
1472 // where else and alter data we are relying on here (like the very existance
1473 // of a "current change note".)
1474 //*********************************************************************************
1475
1476 IOReturn IOService::acknowledgePowerChange ( IOService * whichObject )
1477 {
1478 IOPMRequest * request;
1479
1480 if (!initialized)
1481 return IOPMNotYetInitialized;
1482 if (!whichObject)
1483 return kIOReturnBadArgument;
1484
1485 request = acquirePMRequest( this, kIOPMRequestTypeAckPowerChange );
1486 if (!request)
1487 return kIOReturnNoMemory;
1488
1489 whichObject->retain();
1490 request->fArg0 = whichObject;
1491
1492 submitPMRequest( request );
1493 return IOPMNoErr;
1494 }
1495
1496 //*********************************************************************************
1497 // [private] handleAcknowledgePowerChange
1498 //*********************************************************************************
1499
1500 bool IOService::handleAcknowledgePowerChange ( IOPMRequest * request )
1501 {
1502 IOPMinformee * informee;
1503 unsigned long childPower = kIOPMUnknown;
1504 IOService * theChild;
1505 IOService * whichObject;
1506 bool all_acked = false;
1507
1508 PM_ASSERT_IN_GATE();
1509 whichObject = (IOService *) request->fArg0;
1510 assert(whichObject);
1511
1512 // one of our interested drivers?
1513 informee = fInterestedDrivers->findItem( whichObject );
1514 if ( informee == NULL )
1515 {
1516 if ( !isChild(whichObject, gIOPowerPlane) )
1517 {
1518 OUR_PMLog(kPMLogAcknowledgeErr1, 0, 0);
1519 goto no_err;
1520 } else {
1521 OUR_PMLog(kPMLogChildAcknowledge, fHeadNotePendingAcks, 0);
1522 }
1523 } else {
1524 OUR_PMLog(kPMLogDriverAcknowledge, fHeadNotePendingAcks, 0);
1525 }
1526
1527 if ( fHeadNotePendingAcks != 0 )
1528 {
1529 assert(fPowerStates != NULL);
1530
1531 // yes, make sure we're expecting acks
1532 if ( informee != NULL )
1533 {
1534 // it's an interested driver
1535 // make sure we're expecting this ack
1536 if ( informee->timer != 0 )
1537 {
1538 #if LOG_SETPOWER_TIMES
1539 if (informee->timer > 0)
1540 {
1541 uint64_t nsec = computeTimeDeltaNS(&informee->startTime);
1542 if (nsec > LOG_SETPOWER_TIMES)
1543 PM_LOG("%s::powerState%sChangeTo(%p, %s, %lu -> %lu) async took %d ms\n",
1544 informee->whatObject->getName(),
1545 (fDriverCallReason == kDriverCallInformPreChange) ? "Will" : "Did",
1546 informee->whatObject,
1547 fName, fCurrentPowerState, fHeadNotePowerState, NS_TO_US(nsec));
1548
1549 uint16_t logType = (fDriverCallReason == kDriverCallInformPreChange)
1550 ? kIOPMEventTypePSWillChangeTo
1551 : kIOPMEventTypePSDidChangeTo;
1552
1553 PMEventDetails *details = PMEventDetails::eventDetails(
1554 logType,
1555 fName,
1556 (uintptr_t)this,
1557 informee->whatObject->getName(),
1558 0, 0, 0,
1559 NS_TO_MS(nsec));
1560
1561 getPMRootDomain()->recordAndReleasePMEventGated( details );
1562 }
1563 #endif
1564 // mark it acked
1565 informee->timer = 0;
1566 // that's one fewer to worry about
1567 fHeadNotePendingAcks--;
1568 } else {
1569 // this driver has already acked
1570 OUR_PMLog(kPMLogAcknowledgeErr2, 0, 0);
1571 }
1572 } else {
1573 // it's a child
1574 // make sure we're expecting this ack
1575 if ( ((IOPowerConnection *)whichObject)->getAwaitingAck() )
1576 {
1577 // that's one fewer to worry about
1578 fHeadNotePendingAcks--;
1579 ((IOPowerConnection *)whichObject)->setAwaitingAck(false);
1580 theChild = (IOService *)whichObject->copyChildEntry(gIOPowerPlane);
1581 if ( theChild )
1582 {
1583 childPower = theChild->currentPowerConsumption();
1584 theChild->release();
1585 }
1586 if ( childPower == kIOPMUnknown )
1587 {
1588 fHeadNotePowerArrayEntry->staticPower = kIOPMUnknown;
1589 } else {
1590 if (fHeadNotePowerArrayEntry->staticPower != kIOPMUnknown)
1591 {
1592 fHeadNotePowerArrayEntry->staticPower += childPower;
1593 }
1594 }
1595 }
1596 }
1597
1598 if ( fHeadNotePendingAcks == 0 ) {
1599 // yes, stop the timer
1600 stop_ack_timer();
1601 // and now we can continue
1602 all_acked = true;
1603 }
1604 } else {
1605 OUR_PMLog(kPMLogAcknowledgeErr3, 0, 0); // not expecting anybody to ack
1606 }
1607
1608 no_err:
1609 if (whichObject)
1610 whichObject->release();
1611
1612 return all_acked;
1613 }
1614
1615 //*********************************************************************************
1616 // [public] acknowledgeSetPowerState
1617 //
1618 // After we instructed our controlling driver to change power states,
1619 // it has called to say it has finished doing so.
1620 // We continue to process the power state change.
1621 //*********************************************************************************
1622
1623 IOReturn IOService::acknowledgeSetPowerState ( void )
1624 {
1625 IOPMRequest * request;
1626
1627 if (!initialized)
1628 return IOPMNotYetInitialized;
1629
1630 request = acquirePMRequest( this, kIOPMRequestTypeAckSetPowerState );
1631 if (!request)
1632 return kIOReturnNoMemory;
1633
1634 submitPMRequest( request );
1635 return kIOReturnSuccess;
1636 }
1637
1638 //*********************************************************************************
1639 // [private] adjustPowerState
1640 //*********************************************************************************
1641
1642 void IOService::adjustPowerState ( uint32_t clamp )
1643 {
1644 PM_ASSERT_IN_GATE();
1645 computeDesiredState(clamp);
1646 if (fControllingDriver && fParentsKnowState && inPlane(gIOPowerPlane))
1647 {
1648 IOPMPowerChangeFlags changeFlags = kIOPMSelfInitiated;
1649
1650 // Indicate that children desires were ignored, and do not ask
1651 // apps for permission to drop power. This is used by root domain
1652 // for demand sleep.
1653
1654 if (getPMRequestType() == kIOPMRequestTypeRequestPowerStateOverride)
1655 changeFlags |= (kIOPMIgnoreChildren | kIOPMSkipAskPowerDown);
1656
1657 startPowerChange(
1658 /* flags */ changeFlags,
1659 /* power state */ fDesiredPowerState,
1660 /* domain flags */ 0,
1661 /* connection */ 0,
1662 /* parent flags */ 0);
1663 }
1664 }
1665
1666 //*********************************************************************************
1667 // [public] synchronizePowerTree
1668 //*********************************************************************************
1669
1670 IOReturn IOService::synchronizePowerTree (
1671 IOOptionBits options,
1672 IOService * notifyRoot )
1673 {
1674 IOPMRequest * request_c = 0;
1675 IOPMRequest * request_s;
1676
1677 if (this != getPMRootDomain())
1678 return kIOReturnBadArgument;
1679 if (!initialized)
1680 return kIOPMNotYetInitialized;
1681
1682 if (notifyRoot)
1683 {
1684 IOPMRequest * nr;
1685
1686 // Cancels don't need to be synchronized.
1687 nr = acquirePMRequest(notifyRoot, kIOPMRequestTypeChildNotifyDelayCancel);
1688 if (nr) submitPMRequest(nr);
1689 nr = acquirePMRequest(getPMRootDomain(), kIOPMRequestTypeChildNotifyDelayCancel);
1690 if (nr) submitPMRequest(nr);
1691 }
1692
1693 request_s = acquirePMRequest( this, kIOPMRequestTypeSynchronizePowerTree );
1694 if (!request_s)
1695 goto error_no_memory;
1696
1697 if (options & kIOPMSyncCancelPowerDown)
1698 request_c = acquirePMRequest( this, kIOPMRequestTypeIdleCancel );
1699 if (request_c)
1700 {
1701 request_c->attachNextRequest( request_s );
1702 submitPMRequest(request_c);
1703 }
1704
1705 request_s->fArg0 = (void *)(uintptr_t) options;
1706 submitPMRequest(request_s);
1707
1708 return kIOReturnSuccess;
1709
1710 error_no_memory:
1711 if (request_c) releasePMRequest(request_c);
1712 if (request_s) releasePMRequest(request_s);
1713 return kIOReturnNoMemory;
1714 }
1715
1716 //*********************************************************************************
1717 // [private] handleSynchronizePowerTree
1718 //*********************************************************************************
1719
1720 void IOService::handleSynchronizePowerTree ( IOPMRequest * request )
1721 {
1722 PM_ASSERT_IN_GATE();
1723 if (fControllingDriver && fParentsKnowState && inPlane(gIOPowerPlane) &&
1724 (fCurrentPowerState == fNumberOfPowerStates - 1))
1725 {
1726 IOOptionBits options = (uintptr_t) request->fArg0;
1727
1728 startPowerChange(
1729 /* flags */ kIOPMSelfInitiated | kIOPMSynchronize |
1730 (options & kIOPMSyncNoChildNotify),
1731 /* power state */ fCurrentPowerState,
1732 /* domain flags */ 0,
1733 /* connection */ 0,
1734 /* parent flags */ 0);
1735 }
1736 }
1737
1738 #ifndef __LP64__
1739 //*********************************************************************************
1740 // [deprecated] powerDomainWillChangeTo
1741 //
1742 // Called by the power-hierarchy parent notifying of a new power state
1743 // in the power domain.
1744 // We enqueue a parent power-change to our queue of power changes.
1745 // This may or may not cause us to change power, depending on what
1746 // kind of change is occuring in the domain.
1747 //*********************************************************************************
1748
1749 IOReturn IOService::powerDomainWillChangeTo (
1750 IOPMPowerFlags newPowerFlags,
1751 IOPowerConnection * whichParent )
1752 {
1753 assert(false);
1754 return kIOReturnUnsupported;
1755 }
1756 #endif /* !__LP64__ */
1757
1758 //*********************************************************************************
1759 // [private] handlePowerDomainWillChangeTo
1760 //*********************************************************************************
1761
1762 void IOService::handlePowerDomainWillChangeTo ( IOPMRequest * request )
1763 {
1764 IOPMPowerFlags parentPowerFlags = (IOPMPowerFlags) request->fArg0;
1765 IOPowerConnection * whichParent = (IOPowerConnection *) request->fArg1;
1766 IOPMPowerChangeFlags parentChangeFlags = (IOPMPowerChangeFlags)(uintptr_t) request->fArg2;
1767 IOPMPowerChangeFlags myChangeFlags;
1768 OSIterator * iter;
1769 OSObject * next;
1770 IOPowerConnection * connection;
1771 IOPMPowerStateIndex newPowerState;
1772 IOPMPowerFlags combinedPowerFlags;
1773 bool savedParentsKnowState;
1774 IOReturn result = IOPMAckImplied;
1775
1776 PM_ASSERT_IN_GATE();
1777 OUR_PMLog(kPMLogWillChange, parentPowerFlags, 0);
1778
1779 if (!inPlane(gIOPowerPlane) || !whichParent || !whichParent->getAwaitingAck())
1780 {
1781 PM_LOG("%s::%s not in power tree\n", getName(), __FUNCTION__);
1782 goto exit_no_ack;
1783 }
1784
1785 savedParentsKnowState = fParentsKnowState;
1786
1787 // Combine parents' output power flags.
1788
1789 combinedPowerFlags = 0;
1790
1791 iter = getParentIterator(gIOPowerPlane);
1792 if ( iter )
1793 {
1794 while ( (next = iter->getNextObject()) )
1795 {
1796 if ( (connection = OSDynamicCast(IOPowerConnection, next)) )
1797 {
1798 if ( connection == whichParent )
1799 combinedPowerFlags |= parentPowerFlags;
1800 else
1801 combinedPowerFlags |= connection->parentCurrentPowerFlags();
1802 }
1803 }
1804 iter->release();
1805 }
1806
1807 // If our initial change has yet to occur, then defer the power change
1808 // until after the power domain has completed its power transition.
1809
1810 if ( fControllingDriver && !fInitialPowerChange )
1811 {
1812 newPowerState = fControllingDriver->maxCapabilityForDomainState(
1813 combinedPowerFlags);
1814
1815 // Absorb parent's kIOPMSynchronize flag.
1816 myChangeFlags = kIOPMParentInitiated | kIOPMDomainWillChange |
1817 (parentChangeFlags & kIOPMSynchronize);
1818
1819 result = startPowerChange(
1820 /* flags */ myChangeFlags,
1821 /* power state */ newPowerState,
1822 /* domain flags */ combinedPowerFlags,
1823 /* connection */ whichParent,
1824 /* parent flags */ parentPowerFlags);
1825 }
1826
1827 // If parent is dropping power, immediately update the parent's
1828 // capability flags. Any future merging of parent(s) combined
1829 // power flags should account for this power drop.
1830
1831 if (parentChangeFlags & kIOPMDomainPowerDrop)
1832 {
1833 setParentInfo(parentPowerFlags, whichParent, true);
1834 }
1835
1836 // Parent is expecting an ACK from us. If we did not embark on a state
1837 // transition, i.e. startPowerChange() returned IOPMAckImplied. We are
1838 // still required to issue an ACK to our parent.
1839
1840 if (IOPMAckImplied == result)
1841 {
1842 IOService * parent;
1843 parent = (IOService *) whichParent->copyParentEntry(gIOPowerPlane);
1844 assert(parent);
1845 if ( parent )
1846 {
1847 parent->acknowledgePowerChange( whichParent );
1848 parent->release();
1849 }
1850 }
1851
1852 exit_no_ack:
1853 // Drop the retain from notifyChild().
1854 if (whichParent) whichParent->release();
1855 }
1856
1857 #ifndef __LP64__
1858 //*********************************************************************************
1859 // [deprecated] powerDomainDidChangeTo
1860 //
1861 // Called by the power-hierarchy parent after the power state of the power domain
1862 // has settled at a new level.
1863 // We enqueue a parent power-change to our queue of power changes.
1864 // This may or may not cause us to change power, depending on what
1865 // kind of change is occuring in the domain.
1866 //*********************************************************************************
1867
1868 IOReturn IOService::powerDomainDidChangeTo (
1869 IOPMPowerFlags newPowerFlags,
1870 IOPowerConnection * whichParent )
1871 {
1872 assert(false);
1873 return kIOReturnUnsupported;
1874 }
1875 #endif /* !__LP64__ */
1876
1877 //*********************************************************************************
1878 // [private] handlePowerDomainDidChangeTo
1879 //*********************************************************************************
1880
1881 void IOService::handlePowerDomainDidChangeTo ( IOPMRequest * request )
1882 {
1883 IOPMPowerFlags parentPowerFlags = (IOPMPowerFlags) request->fArg0;
1884 IOPowerConnection * whichParent = (IOPowerConnection *) request->fArg1;
1885 IOPMPowerChangeFlags parentChangeFlags = (IOPMPowerChangeFlags)(uintptr_t) request->fArg2;
1886 IOPMPowerChangeFlags myChangeFlags;
1887 IOPMPowerStateIndex newPowerState;
1888 IOPMPowerStateIndex initialDesire;
1889 bool savedParentsKnowState;
1890 IOReturn result = IOPMAckImplied;
1891
1892 PM_ASSERT_IN_GATE();
1893 OUR_PMLog(kPMLogDidChange, parentPowerFlags, 0);
1894
1895 if (!inPlane(gIOPowerPlane) || !whichParent || !whichParent->getAwaitingAck())
1896 {
1897 PM_LOG("%s::%s not in power tree\n", getName(), __FUNCTION__);
1898 goto exit_no_ack;
1899 }
1900
1901 savedParentsKnowState = fParentsKnowState;
1902
1903 setParentInfo(parentPowerFlags, whichParent, true);
1904
1905 if ( fControllingDriver )
1906 {
1907 newPowerState = fControllingDriver->maxCapabilityForDomainState(
1908 fParentsCurrentPowerFlags);
1909
1910 if (fInitialPowerChange)
1911 {
1912 initialDesire = fControllingDriver->initialPowerStateForDomainState(
1913 fParentsCurrentPowerFlags);
1914 computeDesiredState(initialDesire);
1915 }
1916
1917 // Absorb parent's kIOPMSynchronize flag.
1918 myChangeFlags = kIOPMParentInitiated | kIOPMDomainDidChange |
1919 (parentChangeFlags & kIOPMSynchronize);
1920
1921 result = startPowerChange(
1922 /* flags */ myChangeFlags,
1923 /* power state */ newPowerState,
1924 /* domain flags */ fParentsCurrentPowerFlags,
1925 /* connection */ whichParent,
1926 /* parent flags */ 0);
1927 }
1928
1929 // Parent is expecting an ACK from us. If we did not embark on a state
1930 // transition, i.e. startPowerChange() returned IOPMAckImplied. We are
1931 // still required to issue an ACK to our parent.
1932
1933 if (IOPMAckImplied == result)
1934 {
1935 IOService * parent;
1936 parent = (IOService *) whichParent->copyParentEntry(gIOPowerPlane);
1937 assert(parent);
1938 if ( parent )
1939 {
1940 parent->acknowledgePowerChange( whichParent );
1941 parent->release();
1942 }
1943 }
1944
1945 // If the parent registers its power driver late, then this is the
1946 // first opportunity to tell our parent about our desire.
1947
1948 if (!savedParentsKnowState && fParentsKnowState)
1949 {
1950 PM_LOG1("%s::powerDomainDidChangeTo parentsKnowState = true\n",
1951 getName());
1952 requestDomainPower( fDesiredPowerState );
1953 }
1954
1955 exit_no_ack:
1956 // Drop the retain from notifyChild().
1957 if (whichParent) whichParent->release();
1958 }
1959
1960 //*********************************************************************************
1961 // [private] setParentInfo
1962 //
1963 // Set our connection data for one specific parent, and then combine all the parent
1964 // data together.
1965 //*********************************************************************************
1966
1967 void IOService::setParentInfo (
1968 IOPMPowerFlags newPowerFlags,
1969 IOPowerConnection * whichParent,
1970 bool knowsState )
1971 {
1972 OSIterator * iter;
1973 OSObject * next;
1974 IOPowerConnection * conn;
1975
1976 PM_ASSERT_IN_GATE();
1977
1978 // set our connection data
1979 whichParent->setParentCurrentPowerFlags(newPowerFlags);
1980 whichParent->setParentKnowsState(knowsState);
1981
1982 // recompute our parent info
1983 fParentsCurrentPowerFlags = 0;
1984 fParentsKnowState = true;
1985
1986 iter = getParentIterator(gIOPowerPlane);
1987 if ( iter )
1988 {
1989 while ( (next = iter->getNextObject()) )
1990 {
1991 if ( (conn = OSDynamicCast(IOPowerConnection, next)) )
1992 {
1993 fParentsKnowState &= conn->parentKnowsState();
1994 fParentsCurrentPowerFlags |= conn->parentCurrentPowerFlags();
1995 }
1996 }
1997 iter->release();
1998 }
1999 }
2000
2001 //******************************************************************************
2002 // [private] trackSystemSleepPreventers
2003 //******************************************************************************
2004
2005 void IOService::trackSystemSleepPreventers(
2006 IOPMPowerStateIndex oldPowerState,
2007 IOPMPowerStateIndex newPowerState,
2008 IOPMPowerChangeFlags changeFlags __unused )
2009 {
2010 IOPMPowerFlags oldCapability, newCapability;
2011
2012 oldCapability = fPowerStates[oldPowerState].capabilityFlags &
2013 (kIOPMPreventIdleSleep | kIOPMPreventSystemSleep);
2014 newCapability = fPowerStates[newPowerState].capabilityFlags &
2015 (kIOPMPreventIdleSleep | kIOPMPreventSystemSleep);
2016
2017 if (fHeadNoteChangeFlags & kIOPMInitialPowerChange)
2018 oldCapability = 0;
2019 if (oldCapability == newCapability)
2020 return;
2021
2022 if ((oldCapability ^ newCapability) & kIOPMPreventIdleSleep)
2023 {
2024 #if SUPPORT_IDLE_CANCEL
2025 if ((oldCapability & kIOPMPreventIdleSleep) == 0)
2026 {
2027 IOPMRequest * cancelRequest;
2028
2029 cancelRequest = acquirePMRequest( this, kIOPMRequestTypeIdleCancel );
2030 if (cancelRequest)
2031 {
2032 getPMRootDomain()->submitPMRequest( cancelRequest );
2033 }
2034 }
2035 #endif
2036
2037 getPMRootDomain()->updatePreventIdleSleepList(this,
2038 ((oldCapability & kIOPMPreventIdleSleep) == 0));
2039 }
2040
2041 if ((oldCapability ^ newCapability) & kIOPMPreventSystemSleep)
2042 {
2043
2044 getPMRootDomain()->updatePreventSystemSleepList(this,
2045 ((oldCapability & kIOPMPreventSystemSleep) == 0));
2046 }
2047 }
2048
2049 //*********************************************************************************
2050 // [public] requestPowerDomainState
2051 //
2052 // Called on a power parent when a child's power requirement changes.
2053 //*********************************************************************************
2054
2055 IOReturn IOService::requestPowerDomainState(
2056 IOPMPowerFlags childRequestPowerFlags,
2057 IOPowerConnection * childConnection,
2058 unsigned long specification )
2059 {
2060 IOPMPowerStateIndex ps;
2061 IOPMPowerFlags outputPowerFlags;
2062 IOService * child;
2063 IOPMRequest * subRequest;
2064 bool adjustPower = false;
2065
2066 if (!initialized)
2067 return IOPMNotYetInitialized;
2068
2069 if (gIOPMWorkLoop->onThread() == false)
2070 {
2071 PM_LOG("%s::requestPowerDomainState\n", getName());
2072 return kIOReturnSuccess;
2073 }
2074
2075 OUR_PMLog(kPMLogRequestDomain, childRequestPowerFlags, specification);
2076
2077 if (!isChild(childConnection, gIOPowerPlane))
2078 return kIOReturnNotAttached;
2079
2080 if (!fControllingDriver || !fNumberOfPowerStates)
2081 return kIOReturnNotReady;
2082
2083 child = (IOService *) childConnection->getChildEntry(gIOPowerPlane);
2084 assert(child);
2085
2086 // Merge in the power flags contributed by this power parent
2087 // at its current or impending power state.
2088
2089 outputPowerFlags = fPowerStates[fCurrentPowerState].outputPowerFlags;
2090 if (fMachineState != kIOPM_Finished)
2091 {
2092 if (IS_POWER_DROP && !IS_ROOT_DOMAIN)
2093 {
2094 // Use the lower power state when dropping power.
2095 // Must be careful since a power drop can be canceled
2096 // from the following states:
2097 // - kIOPM_OurChangeTellClientsPowerDown
2098 // - kIOPM_OurChangeTellPriorityClientsPowerDown
2099 //
2100 // The child must not wait for this parent to raise power
2101 // if the power drop was cancelled. The solution is to cancel
2102 // the power drop if possible, then schedule an adjustment to
2103 // re-evaluate the parent's power state.
2104 //
2105 // Root domain is excluded to avoid idle sleep issues. And permit
2106 // root domain children to pop up when system is going to sleep.
2107
2108 if ((fMachineState == kIOPM_OurChangeTellClientsPowerDown) ||
2109 (fMachineState == kIOPM_OurChangeTellPriorityClientsPowerDown))
2110 {
2111 fDoNotPowerDown = true; // cancel power drop
2112 adjustPower = true; // schedule an adjustment
2113 PM_LOG1("%s: power drop cancelled in state %u by %s\n",
2114 getName(), fMachineState, child->getName());
2115 }
2116 else
2117 {
2118 // Beyond cancellation point, report the impending state.
2119 outputPowerFlags =
2120 fPowerStates[fHeadNotePowerState].outputPowerFlags;
2121 }
2122 }
2123 else if (IS_POWER_RISE)
2124 {
2125 // When raising power, must report the output power flags from
2126 // child's perspective. A child power request may arrive while
2127 // parent is transitioning upwards. If a request arrives after
2128 // setParentInfo() has already recorded the output power flags
2129 // for the next power state, then using the power supplied by
2130 // fCurrentPowerState is incorrect, and might cause the child
2131 // to wait when it should not.
2132
2133 outputPowerFlags = childConnection->parentCurrentPowerFlags();
2134 }
2135 }
2136 child->fHeadNoteDomainTargetFlags |= outputPowerFlags;
2137
2138 // Map child's requested power flags to one of our power state.
2139
2140 for (ps = 0; ps < fNumberOfPowerStates; ps++)
2141 {
2142 if ((fPowerStates[ps].outputPowerFlags & childRequestPowerFlags) ==
2143 (fOutputPowerCharacterFlags & childRequestPowerFlags))
2144 break;
2145 }
2146 if (ps >= fNumberOfPowerStates)
2147 {
2148 ps = 0; // should never happen
2149 }
2150
2151 // Conditions that warrants a power adjustment on this parent.
2152 // Adjust power will also propagate any changes to the child's
2153 // prevent idle/sleep flags towards the root domain.
2154
2155 if (!childConnection->childHasRequestedPower() ||
2156 (ps != childConnection->getDesiredDomainState()))
2157 adjustPower = true;
2158
2159 #if ENABLE_DEBUG_LOGS
2160 if (adjustPower)
2161 {
2162 PM_LOG("requestPowerDomainState[%s]: %s, init %d, %u->%u\n",
2163 getName(), child->getName(),
2164 !childConnection->childHasRequestedPower(),
2165 (uint32_t) childConnection->getDesiredDomainState(),
2166 (uint32_t) ps);
2167 }
2168 #endif
2169
2170 // Record the child's desires on the connection.
2171 childConnection->setChildHasRequestedPower();
2172 childConnection->setDesiredDomainState( ps );
2173
2174 // Schedule a request to re-evaluate all children desires and
2175 // adjust power state. Submit a request if one wasn't pending,
2176 // or if the current request is part of a call tree.
2177
2178 if (adjustPower && !fDeviceOverrideEnabled &&
2179 (!fAdjustPowerScheduled || gIOPMRequest->getRootRequest()))
2180 {
2181 subRequest = acquirePMRequest(
2182 this, kIOPMRequestTypeAdjustPowerState, gIOPMRequest );
2183 if (subRequest)
2184 {
2185 submitPMRequest( subRequest );
2186 fAdjustPowerScheduled = true;
2187 }
2188 }
2189
2190 return kIOReturnSuccess;
2191 }
2192
2193 //*********************************************************************************
2194 // [public] temporaryPowerClampOn
2195 //
2196 // A power domain wants to clamp its power on till it has children which
2197 // will thendetermine the power domain state.
2198 //
2199 // We enter the highest state until addPowerChild is called.
2200 //*********************************************************************************
2201
2202 IOReturn IOService::temporaryPowerClampOn ( void )
2203 {
2204 return requestPowerState( gIOPMPowerClientChildProxy, kIOPMPowerStateMax );
2205 }
2206
2207 //*********************************************************************************
2208 // [public] makeUsable
2209 //
2210 // Some client of our device is asking that we become usable. Although
2211 // this has not come from a subclassed device object, treat it exactly
2212 // as if it had. In this way, subsequent requests for lower power from
2213 // a subclassed device object will pre-empt this request.
2214 //
2215 // We treat this as a subclass object request to switch to the
2216 // highest power state.
2217 //*********************************************************************************
2218
2219 IOReturn IOService::makeUsable ( void )
2220 {
2221 OUR_PMLog(kPMLogMakeUsable, 0, 0);
2222 return requestPowerState( gIOPMPowerClientDevice, kIOPMPowerStateMax );
2223 }
2224
2225 //*********************************************************************************
2226 // [public] currentCapability
2227 //*********************************************************************************
2228
2229 IOPMPowerFlags IOService::currentCapability ( void )
2230 {
2231 if (!initialized)
2232 return IOPMNotPowerManaged;
2233
2234 return fCurrentCapabilityFlags;
2235 }
2236
2237 //*********************************************************************************
2238 // [public] changePowerStateTo
2239 //
2240 // Called by our power-controlling driver to change power state. The new desired
2241 // power state is computed and compared against the current power state. If those
2242 // power states differ, then a power state change is initiated.
2243 //*********************************************************************************
2244
2245 IOReturn IOService::changePowerStateTo ( unsigned long ordinal )
2246 {
2247 OUR_PMLog(kPMLogChangeStateTo, ordinal, 0);
2248 return requestPowerState( gIOPMPowerClientDriver, ordinal );
2249 }
2250
2251 //*********************************************************************************
2252 // [protected] changePowerStateToPriv
2253 //
2254 // Called by our driver subclass to change power state. The new desired power
2255 // state is computed and compared against the current power state. If those
2256 // power states differ, then a power state change is initiated.
2257 //*********************************************************************************
2258
2259 IOReturn IOService::changePowerStateToPriv ( unsigned long ordinal )
2260 {
2261 OUR_PMLog(kPMLogChangeStateToPriv, ordinal, 0);
2262 return requestPowerState( gIOPMPowerClientDevice, ordinal );
2263 }
2264
2265 //*********************************************************************************
2266 // [protected] changePowerStateWithOverrideTo
2267 //
2268 // Called by our driver subclass to change power state. The new desired power
2269 // state is computed and compared against the current power state. If those
2270 // power states differ, then a power state change is initiated.
2271 // Override enforced - Children and Driver desires are ignored.
2272 //*********************************************************************************
2273
2274 IOReturn IOService::changePowerStateWithOverrideTo ( unsigned long ordinal )
2275 {
2276 IOPMRequest * request;
2277
2278 if (!initialized)
2279 return kIOPMNotYetInitialized;
2280
2281 OUR_PMLog(kPMLogChangeStateToPriv, ordinal, 0);
2282
2283 request = acquirePMRequest( this, kIOPMRequestTypeRequestPowerStateOverride );
2284 if (!request)
2285 return kIOReturnNoMemory;
2286
2287 gIOPMPowerClientDevice->retain();
2288 request->fArg0 = (void *) ordinal;
2289 request->fArg1 = (void *) gIOPMPowerClientDevice;
2290 request->fArg2 = 0;
2291 #if NOT_READY
2292 if (action)
2293 request->installCompletionAction( action, target, param );
2294 #endif
2295
2296 // Prevent needless downwards power transitions by clamping power
2297 // until the scheduled request is executed.
2298
2299 if (gIOPMWorkLoop->inGate() && (ordinal < fNumberOfPowerStates))
2300 {
2301 fTempClampPowerState = max(fTempClampPowerState, ordinal);
2302 fTempClampCount++;
2303 fOverrideMaxPowerState = ordinal;
2304 request->fArg2 = (void *) (uintptr_t) true;
2305 }
2306
2307 submitPMRequest( request );
2308 return IOPMNoErr;
2309 }
2310
2311 //*********************************************************************************
2312 // [private] requestPowerState
2313 //*********************************************************************************
2314
2315 IOReturn IOService::requestPowerState (
2316 const OSSymbol * client,
2317 uint32_t state )
2318 {
2319 IOPMRequest * request;
2320
2321 if (!client)
2322 return kIOReturnBadArgument;
2323 if (!initialized)
2324 return kIOPMNotYetInitialized;
2325
2326 request = acquirePMRequest( this, kIOPMRequestTypeRequestPowerState );
2327 if (!request)
2328 return kIOReturnNoMemory;
2329
2330 client->retain();
2331 request->fArg0 = (void *) state;
2332 request->fArg1 = (void *) client;
2333 request->fArg2 = 0;
2334 #if NOT_READY
2335 if (action)
2336 request->installCompletionAction( action, target, param );
2337 #endif
2338
2339 // Prevent needless downwards power transitions by clamping power
2340 // until the scheduled request is executed.
2341
2342 if (gIOPMWorkLoop->inGate() && (state < fNumberOfPowerStates))
2343 {
2344 fTempClampPowerState = max(fTempClampPowerState, state);
2345 fTempClampCount++;
2346 request->fArg2 = (void *) (uintptr_t) true;
2347 }
2348
2349 submitPMRequest( request );
2350 return IOPMNoErr;
2351 }
2352
2353 //*********************************************************************************
2354 // [private] handleRequestPowerState
2355 //*********************************************************************************
2356
2357 void IOService::handleRequestPowerState ( IOPMRequest * request )
2358 {
2359 const OSSymbol * client = (const OSSymbol *) request->fArg1;
2360 uint32_t state = (uint32_t)(uintptr_t) request->fArg0;
2361
2362 PM_ASSERT_IN_GATE();
2363 if (request->fArg2)
2364 {
2365 assert(fTempClampCount != 0);
2366 if (fTempClampCount) fTempClampCount--;
2367 if (!fTempClampCount) fTempClampPowerState = 0;
2368 }
2369
2370 if (fNumberOfPowerStates && (state >= fNumberOfPowerStates))
2371 state = fNumberOfPowerStates - 1;
2372
2373 // The power suppression due to changePowerStateWithOverrideTo() expires
2374 // upon the next "device" power request - changePowerStateToPriv().
2375
2376 if ((getPMRequestType() != kIOPMRequestTypeRequestPowerStateOverride) &&
2377 (client == gIOPMPowerClientDevice))
2378 fOverrideMaxPowerState = kIOPMPowerStateMax;
2379
2380 if ((state == 0) &&
2381 (client != gIOPMPowerClientDevice) &&
2382 (client != gIOPMPowerClientDriver) &&
2383 (client != gIOPMPowerClientChildProxy))
2384 removePowerClient(client);
2385 else
2386 updatePowerClient(client, state);
2387
2388 adjustPowerState();
2389 client->release();
2390 }
2391
2392 //*********************************************************************************
2393 // [private] Helper functions to update/remove power clients.
2394 //*********************************************************************************
2395
2396 void IOService::updatePowerClient( const OSSymbol * client, uint32_t powerState )
2397 {
2398 if (!fPowerClients)
2399 fPowerClients = OSDictionary::withCapacity(4);
2400 if (fPowerClients && client)
2401 {
2402 OSNumber * num = (OSNumber *) fPowerClients->getObject(client);
2403 if (num)
2404 num->setValue(powerState);
2405 else
2406 {
2407 num = OSNumber::withNumber(powerState, 32);
2408 if (num)
2409 {
2410 fPowerClients->setObject(client, num);
2411 num->release();
2412 }
2413 }
2414 }
2415 }
2416
2417 void IOService::removePowerClient( const OSSymbol * client )
2418 {
2419 if (fPowerClients && client)
2420 fPowerClients->removeObject(client);
2421 }
2422
2423 uint32_t IOService::getPowerStateForClient( const OSSymbol * client )
2424 {
2425 uint32_t powerState = 0;
2426
2427 if (fPowerClients && client)
2428 {
2429 OSNumber * num = (OSNumber *) fPowerClients->getObject(client);
2430 if (num) powerState = num->unsigned32BitValue();
2431 }
2432 return powerState;
2433 }
2434
2435 //*********************************************************************************
2436 // [protected] powerOverrideOnPriv
2437 //*********************************************************************************
2438
2439 IOReturn IOService::powerOverrideOnPriv ( void )
2440 {
2441 IOPMRequest * request;
2442
2443 if (!initialized)
2444 return IOPMNotYetInitialized;
2445
2446 if (gIOPMWorkLoop->inGate())
2447 {
2448 fDeviceOverrideEnabled = true;
2449 return IOPMNoErr;
2450 }
2451
2452 request = acquirePMRequest( this, kIOPMRequestTypePowerOverrideOnPriv );
2453 if (!request)
2454 return kIOReturnNoMemory;
2455
2456 submitPMRequest( request );
2457 return IOPMNoErr;
2458 }
2459
2460 //*********************************************************************************
2461 // [protected] powerOverrideOffPriv
2462 //*********************************************************************************
2463
2464 IOReturn IOService::powerOverrideOffPriv ( void )
2465 {
2466 IOPMRequest * request;
2467
2468 if (!initialized)
2469 return IOPMNotYetInitialized;
2470
2471 if (gIOPMWorkLoop->inGate())
2472 {
2473 fDeviceOverrideEnabled = false;
2474 return IOPMNoErr;
2475 }
2476
2477 request = acquirePMRequest( this, kIOPMRequestTypePowerOverrideOffPriv );
2478 if (!request)
2479 return kIOReturnNoMemory;
2480
2481 submitPMRequest( request );
2482 return IOPMNoErr;
2483 }
2484
2485 //*********************************************************************************
2486 // [private] handlePowerOverrideChanged
2487 //*********************************************************************************
2488
2489 void IOService::handlePowerOverrideChanged ( IOPMRequest * request )
2490 {
2491 PM_ASSERT_IN_GATE();
2492 if (request->getType() == kIOPMRequestTypePowerOverrideOnPriv)
2493 {
2494 OUR_PMLog(kPMLogOverrideOn, 0, 0);
2495 fDeviceOverrideEnabled = true;
2496 }
2497 else
2498 {
2499 OUR_PMLog(kPMLogOverrideOff, 0, 0);
2500 fDeviceOverrideEnabled = false;
2501 }
2502
2503 adjustPowerState();
2504 }
2505
2506 //*********************************************************************************
2507 // [private] computeDesiredState
2508 //*********************************************************************************
2509
2510 void IOService::computeDesiredState ( unsigned long localClamp )
2511 {
2512 OSIterator * iter;
2513 OSObject * next;
2514 IOPowerConnection * connection;
2515 uint32_t desiredState = 0;
2516 uint32_t newPowerState = 0;
2517 bool hasChildren = false;
2518
2519 // Desired power state is always 0 without a controlling driver.
2520
2521 if (!fNumberOfPowerStates)
2522 {
2523 fDesiredPowerState = 0;
2524 //PM_LOG("%s::%s no controlling driver\n", getName(), __FUNCTION__);
2525 return;
2526 }
2527
2528 // Examine the children's desired power state.
2529
2530 iter = getChildIterator(gIOPowerPlane);
2531 if (iter)
2532 {
2533 while ((next = iter->getNextObject()))
2534 {
2535 if ((connection = OSDynamicCast(IOPowerConnection, next)))
2536 {
2537 if (connection->getReadyFlag() == false)
2538 {
2539 PM_LOG3("[%s] %s: connection not ready\n",
2540 getName(), __FUNCTION__);
2541 continue;
2542 }
2543 if (connection->childHasRequestedPower())
2544 hasChildren = true;
2545 if (connection->getDesiredDomainState() > desiredState)
2546 desiredState = connection->getDesiredDomainState();
2547 }
2548 }
2549 iter->release();
2550 }
2551 if (hasChildren)
2552 updatePowerClient(gIOPMPowerClientChildren, desiredState);
2553 else
2554 removePowerClient(gIOPMPowerClientChildren);
2555
2556 // Iterate through all power clients to determine the min power state.
2557
2558 iter = OSCollectionIterator::withCollection(fPowerClients);
2559 if (iter)
2560 {
2561 const OSSymbol * client;
2562 while ((client = (const OSSymbol *) iter->getNextObject()))
2563 {
2564 // Ignore child and driver when override is in effect.
2565 if ((fDeviceOverrideEnabled ||
2566 (getPMRequestType() == kIOPMRequestTypeRequestPowerStateOverride)) &&
2567 ((client == gIOPMPowerClientChildren) ||
2568 (client == gIOPMPowerClientDriver)))
2569 continue;
2570
2571 // Ignore child proxy when children are present.
2572 if (hasChildren && (client == gIOPMPowerClientChildProxy))
2573 continue;
2574
2575 desiredState = getPowerStateForClient(client);
2576 assert(desiredState < fNumberOfPowerStates);
2577 PM_LOG1(" %u %s\n",
2578 desiredState, client->getCStringNoCopy());
2579
2580 newPowerState = max(newPowerState, desiredState);
2581
2582 if (client == gIOPMPowerClientDevice)
2583 fDeviceDesire = desiredState;
2584 }
2585 iter->release();
2586 }
2587
2588 // Factor in the temporary power desires.
2589
2590 newPowerState = max(newPowerState, localClamp);
2591 newPowerState = max(newPowerState, fTempClampPowerState);
2592
2593 // Limit check against max power override.
2594
2595 newPowerState = min(newPowerState, fOverrideMaxPowerState);
2596
2597 // Limit check against number of power states.
2598
2599 if (newPowerState >= fNumberOfPowerStates)
2600 newPowerState = fNumberOfPowerStates - 1;
2601
2602 fDesiredPowerState = newPowerState;
2603
2604 PM_LOG1(" temp %u, clamp %u, current %u, new %u\n",
2605 (uint32_t) localClamp, (uint32_t) fTempClampPowerState,
2606 (uint32_t) fCurrentPowerState, newPowerState);
2607
2608 // Restart idle timer if stopped and device desire has increased.
2609
2610 if (fDeviceDesire && fIdleTimerStopped)
2611 {
2612 fIdleTimerStopped = false;
2613 fActivityTickleCount = 0;
2614 clock_get_uptime(&fIdleTimerStartTime);
2615 start_PM_idle_timer();
2616 }
2617
2618 // Invalidate cached tickle power state when desires change, and not
2619 // due to a tickle request. This invalidation must occur before the
2620 // power state change to minimize races. We want to err on the side
2621 // of servicing more activity tickles rather than dropping one when
2622 // the device is in a low power state.
2623
2624 if ((getPMRequestType() != kIOPMRequestTypeActivityTickle) &&
2625 (fActivityTicklePowerState != -1))
2626 {
2627 IOLockLock(fActivityLock);
2628 fActivityTicklePowerState = -1;
2629 IOLockUnlock(fActivityLock);
2630 }
2631 }
2632
2633 //*********************************************************************************
2634 // [public] currentPowerConsumption
2635 //
2636 //*********************************************************************************
2637
2638 unsigned long IOService::currentPowerConsumption ( void )
2639 {
2640 if (!initialized)
2641 return kIOPMUnknown;
2642
2643 return fCurrentPowerConsumption;
2644 }
2645
2646 //*********************************************************************************
2647 // [deprecated] getPMworkloop
2648 //*********************************************************************************
2649
2650 IOWorkLoop * IOService::getPMworkloop ( void )
2651 {
2652 return gIOPMWorkLoop;
2653 }
2654
2655 #if NOT_YET
2656
2657 //*********************************************************************************
2658 // Power Parent/Children Applier
2659 //*********************************************************************************
2660
2661 static void
2662 applyToPowerChildren(
2663 IOService * service,
2664 IOServiceApplierFunction applier,
2665 void * context,
2666 IOOptionBits options )
2667 {
2668 PM_ASSERT_IN_GATE();
2669
2670 IORegistryEntry * entry;
2671 IORegistryIterator * iter;
2672 IOPowerConnection * connection;
2673 IOService * child;
2674
2675 iter = IORegistryIterator::iterateOver(service, gIOPowerPlane, options);
2676 if (iter)
2677 {
2678 while ((entry = iter->getNextObject()))
2679 {
2680 // Get child of IOPowerConnection objects
2681 if ((connection = OSDynamicCast(IOPowerConnection, entry)))
2682 {
2683 child = (IOService *) connection->copyChildEntry(gIOPowerPlane);
2684 if (child)
2685 {
2686 (*applier)(child, context);
2687 child->release();
2688 }
2689 }
2690 }
2691 iter->release();
2692 }
2693 }
2694
2695 static void
2696 applyToPowerParent(
2697 IOService * service,
2698 IOServiceApplierFunction applier,
2699 void * context,
2700 IOOptionBits options )
2701 {
2702 PM_ASSERT_IN_GATE();
2703
2704 IORegistryEntry * entry;
2705 IORegistryIterator * iter;
2706 IOPowerConnection * connection;
2707 IOService * parent;
2708
2709 iter = IORegistryIterator::iterateOver(service, gIOPowerPlane,
2710 options | kIORegistryIterateParents);
2711 if (iter)
2712 {
2713 while ((entry = iter->getNextObject()))
2714 {
2715 // Get child of IOPowerConnection objects
2716 if ((connection = OSDynamicCast(IOPowerConnection, entry)))
2717 {
2718 parent = (IOService *) connection->copyParentEntry(gIOPowerPlane);
2719 if (parent)
2720 {
2721 (*applier)(parent, context);
2722 parent->release();
2723 }
2724 }
2725 }
2726 iter->release();
2727 }
2728 }
2729
2730 #endif /* NOT_YET */
2731
2732 // MARK: -
2733 // MARK: Activity Tickle & Idle Timer
2734
2735 //*********************************************************************************
2736 // [public] activityTickle
2737 //
2738 // The tickle with parameter kIOPMSuperclassPolicy1 causes the activity
2739 // flag to be set, and the device state checked. If the device has been
2740 // powered down, it is powered up again.
2741 // The tickle with parameter kIOPMSubclassPolicy is ignored here and
2742 // should be intercepted by a subclass.
2743 //*********************************************************************************
2744
2745 bool IOService::activityTickle ( unsigned long type, unsigned long stateNumber )
2746 {
2747 IOPMRequest * request;
2748 bool noPowerChange = true;
2749
2750 if ( initialized && stateNumber && (type == kIOPMSuperclassPolicy1) )
2751 {
2752 IOLockLock(fActivityLock);
2753
2754 // Record device activity for the idle timer handler.
2755
2756 fDeviceWasActive = true;
2757 fActivityTickleCount++;
2758 clock_get_uptime(&fDeviceActiveTimestamp);
2759
2760 PM_ACTION_0(actionActivityTickle);
2761
2762 // Record the last tickle power state.
2763 // This helps to filter out redundant tickles as
2764 // this function may be called from the data path.
2765
2766 if (fActivityTicklePowerState < (long)stateNumber)
2767 {
2768 fActivityTicklePowerState = stateNumber;
2769 noPowerChange = false;
2770
2771 request = acquirePMRequest( this, kIOPMRequestTypeActivityTickle );
2772 if (request)
2773 {
2774 request->fArg0 = (void *) stateNumber; // power state
2775 request->fArg1 = (void *) (uintptr_t) true; // power rise
2776 submitPMRequest(request);
2777 }
2778 }
2779
2780 IOLockUnlock(fActivityLock);
2781 }
2782
2783 // Returns false if the activityTickle might cause a transition to a
2784 // higher powered state, true otherwise.
2785
2786 return noPowerChange;
2787 }
2788
2789 //*********************************************************************************
2790 // [private] handleActivityTickle
2791 //*********************************************************************************
2792
2793 void IOService::handleActivityTickle ( IOPMRequest * request )
2794 {
2795 uint32_t ticklePowerState = (uint32_t)(uintptr_t) request->fArg0;
2796 bool adjustPower = false;
2797
2798 PM_ASSERT_IN_GATE();
2799 if (request->fArg1)
2800 {
2801 // Power rise from activity tickle.
2802 if ((ticklePowerState > fDeviceDesire) &&
2803 (ticklePowerState < fNumberOfPowerStates))
2804 {
2805 fIdleTimerMinPowerState = ticklePowerState;
2806 adjustPower = true;
2807 }
2808 }
2809 else if (fDeviceDesire > fIdleTimerMinPowerState)
2810 {
2811 // Power drop due to idle timer expiration.
2812 // Do not allow idle timer to reduce power below tickle power.
2813 ticklePowerState = fDeviceDesire - 1;
2814 adjustPower = true;
2815 }
2816
2817 if (adjustPower)
2818 {
2819 updatePowerClient(gIOPMPowerClientDevice, ticklePowerState);
2820 adjustPowerState();
2821 }
2822 }
2823
2824 //******************************************************************************
2825 // [public] setIdleTimerPeriod
2826 //
2827 // A subclass policy-maker is using our standard idleness detection service.
2828 // Start the idle timer. Period is in seconds.
2829 //******************************************************************************
2830
2831 IOReturn IOService::setIdleTimerPeriod ( unsigned long period )
2832 {
2833 if (!initialized)
2834 return IOPMNotYetInitialized;
2835
2836 OUR_PMLog(kPMLogSetIdleTimerPeriod, period, fIdleTimerPeriod);
2837
2838 IOPMRequest * request =
2839 acquirePMRequest( this, kIOPMRequestTypeSetIdleTimerPeriod );
2840 if (!request)
2841 return kIOReturnNoMemory;
2842
2843 request->fArg0 = (void *) period;
2844 submitPMRequest( request );
2845
2846 return kIOReturnSuccess;
2847 }
2848
2849 IOReturn IOService::setIgnoreIdleTimer( bool ignore )
2850 {
2851 if (!initialized)
2852 return IOPMNotYetInitialized;
2853
2854 OUR_PMLog(kIOPMRequestTypeIgnoreIdleTimer, ignore, 0);
2855
2856 IOPMRequest * request =
2857 acquirePMRequest( this, kIOPMRequestTypeIgnoreIdleTimer );
2858 if (!request)
2859 return kIOReturnNoMemory;
2860
2861 request->fArg0 = (void *) ignore;
2862 submitPMRequest( request );
2863
2864 return kIOReturnSuccess;
2865 }
2866
2867 //******************************************************************************
2868 // [public] nextIdleTimeout
2869 //
2870 // Returns how many "seconds from now" the device should idle into its
2871 // next lowest power state.
2872 //******************************************************************************
2873
2874 SInt32 IOService::nextIdleTimeout(
2875 AbsoluteTime currentTime,
2876 AbsoluteTime lastActivity,
2877 unsigned int powerState)
2878 {
2879 AbsoluteTime delta;
2880 UInt64 delta_ns;
2881 SInt32 delta_secs;
2882 SInt32 delay_secs;
2883
2884 // Calculate time difference using funky macro from clock.h.
2885 delta = currentTime;
2886 SUB_ABSOLUTETIME(&delta, &lastActivity);
2887
2888 // Figure it in seconds.
2889 absolutetime_to_nanoseconds(delta, &delta_ns);
2890 delta_secs = (SInt32)(delta_ns / NSEC_PER_SEC);
2891
2892 // Be paranoid about delta somehow exceeding timer period.
2893 if (delta_secs < (int) fIdleTimerPeriod)
2894 delay_secs = (int) fIdleTimerPeriod - delta_secs;
2895 else
2896 delay_secs = (int) fIdleTimerPeriod;
2897
2898 return (SInt32)delay_secs;
2899 }
2900
2901 //*********************************************************************************
2902 // [public] start_PM_idle_timer
2903 //*********************************************************************************
2904
2905 void IOService::start_PM_idle_timer ( void )
2906 {
2907 static const int maxTimeout = 100000;
2908 static const int minTimeout = 1;
2909 AbsoluteTime uptime, deadline;
2910 SInt32 idle_in = 0;
2911 boolean_t pending;
2912
2913 if (!initialized || !fIdleTimerPeriod)
2914 return;
2915
2916 IOLockLock(fActivityLock);
2917
2918 clock_get_uptime(&uptime);
2919
2920 // Subclasses may modify idle sleep algorithm
2921 idle_in = nextIdleTimeout(uptime, fDeviceActiveTimestamp, fCurrentPowerState);
2922
2923 // Check for out-of range responses
2924 if (idle_in > maxTimeout)
2925 {
2926 // use standard implementation
2927 idle_in = IOService::nextIdleTimeout(uptime,
2928 fDeviceActiveTimestamp,
2929 fCurrentPowerState);
2930 } else if (idle_in < minTimeout) {
2931 idle_in = fIdleTimerPeriod;
2932 }
2933
2934 IOLockUnlock(fActivityLock);
2935
2936 retain();
2937 clock_interval_to_absolutetime_interval(idle_in, kSecondScale, &deadline);
2938 ADD_ABSOLUTETIME(&deadline, &uptime);
2939 pending = thread_call_enter_delayed(fIdleTimer, deadline);
2940 if (pending) release();
2941 }
2942
2943 //*********************************************************************************
2944 // idle_timer_expired
2945 //*********************************************************************************
2946
2947 static void
2948 idle_timer_expired (
2949 thread_call_param_t arg0, thread_call_param_t arg1 )
2950 {
2951 IOService * me = (IOService *) arg0;
2952
2953 if (gIOPMWorkLoop)
2954 gIOPMWorkLoop->runAction(
2955 OSMemberFunctionCast(IOWorkLoop::Action, me,
2956 &IOService::idleTimerExpired),
2957 me);
2958
2959 me->release();
2960 }
2961
2962 //*********************************************************************************
2963 // [private] idleTimerExpired
2964 //
2965 // The idle timer has expired. If there has been activity since the last
2966 // expiration, just restart the timer and return. If there has not been
2967 // activity, switch to the next lower power state and restart the timer.
2968 //*********************************************************************************
2969
2970 void IOService::idleTimerExpired( void )
2971 {
2972 IOPMRequest * request;
2973 bool restartTimer = true;
2974
2975 if ( !initialized || !fIdleTimerPeriod || fLockedFlags.PMStop )
2976 return;
2977
2978 IOLockLock(fActivityLock);
2979
2980 // Check for device activity (tickles) over last timer period.
2981
2982 if (fDeviceWasActive)
2983 {
2984 // Device was active - do not drop power, restart timer.
2985 fDeviceWasActive = false;
2986 }
2987 else if (!fIdleTimerIgnored)
2988 {
2989 // No device activity - drop power state by one level.
2990 // Decrement the cached tickle power state when possible.
2991 // This value may be (-1) before activityTickle() is called,
2992 // but the power drop request must be issued regardless.
2993
2994 if (fActivityTicklePowerState > 0)
2995 {
2996 fActivityTicklePowerState--;
2997 }
2998
2999 request = acquirePMRequest( this, kIOPMRequestTypeActivityTickle );
3000 if (request)
3001 {
3002 request->fArg0 = (void *) 0; // power state (irrelevant)
3003 request->fArg1 = (void *) (uintptr_t) false; // power drop
3004 submitPMRequest( request );
3005
3006 // Do not restart timer until after the tickle request has been
3007 // processed.
3008
3009 restartTimer = false;
3010 }
3011 }
3012
3013 IOLockUnlock(fActivityLock);
3014
3015 if (restartTimer)
3016 start_PM_idle_timer();
3017 }
3018
3019 #ifndef __LP64__
3020 //*********************************************************************************
3021 // [deprecated] PM_idle_timer_expiration
3022 //*********************************************************************************
3023
3024 void IOService::PM_idle_timer_expiration ( void )
3025 {
3026 }
3027
3028 //*********************************************************************************
3029 // [deprecated] command_received
3030 //*********************************************************************************
3031
3032 void IOService::command_received ( void *statePtr , void *, void * , void * )
3033 {
3034 }
3035 #endif /* !__LP64__ */
3036
3037 //*********************************************************************************
3038 // [public] setAggressiveness
3039 //
3040 // Pass on the input parameters to all power domain children. All those which are
3041 // power domains will pass it on to their children, etc.
3042 //*********************************************************************************
3043
3044 IOReturn IOService::setAggressiveness ( unsigned long type, unsigned long newLevel )
3045 {
3046 return kIOReturnSuccess;
3047 }
3048
3049 //*********************************************************************************
3050 // [public] getAggressiveness
3051 //
3052 // Called by the user client.
3053 //*********************************************************************************
3054
3055 IOReturn IOService::getAggressiveness ( unsigned long type, unsigned long * currentLevel )
3056 {
3057 IOPMrootDomain * rootDomain = getPMRootDomain();
3058
3059 if (!rootDomain)
3060 return kIOReturnNotReady;
3061
3062 return rootDomain->getAggressiveness( type, currentLevel );
3063 }
3064
3065 //*********************************************************************************
3066 // [public] getPowerState
3067 //
3068 //*********************************************************************************
3069
3070 UInt32 IOService::getPowerState ( void )
3071 {
3072 if (!initialized)
3073 return 0;
3074
3075 return fCurrentPowerState;
3076 }
3077
3078 #ifndef __LP64__
3079 //*********************************************************************************
3080 // [deprecated] systemWake
3081 //
3082 // Pass this to all power domain children. All those which are
3083 // power domains will pass it on to their children, etc.
3084 //*********************************************************************************
3085
3086 IOReturn IOService::systemWake ( void )
3087 {
3088 OSIterator * iter;
3089 OSObject * next;
3090 IOPowerConnection * connection;
3091 IOService * theChild;
3092
3093 iter = getChildIterator(gIOPowerPlane);
3094 if ( iter )
3095 {
3096 while ( (next = iter->getNextObject()) )
3097 {
3098 if ( (connection = OSDynamicCast(IOPowerConnection, next)) )
3099 {
3100 if (connection->getReadyFlag() == false)
3101 {
3102 PM_LOG3("[%s] %s: connection not ready\n",
3103 getName(), __FUNCTION__);
3104 continue;
3105 }
3106
3107 theChild = (IOService *)connection->copyChildEntry(gIOPowerPlane);
3108 if ( theChild )
3109 {
3110 theChild->systemWake();
3111 theChild->release();
3112 }
3113 }
3114 }
3115 iter->release();
3116 }
3117
3118 if ( fControllingDriver != NULL )
3119 {
3120 if ( fControllingDriver->didYouWakeSystem() )
3121 {
3122 makeUsable();
3123 }
3124 }
3125
3126 return IOPMNoErr;
3127 }
3128
3129 //*********************************************************************************
3130 // [deprecated] temperatureCriticalForZone
3131 //*********************************************************************************
3132
3133 IOReturn IOService::temperatureCriticalForZone ( IOService * whichZone )
3134 {
3135 IOService * theParent;
3136 IOService * theNub;
3137
3138 OUR_PMLog(kPMLogCriticalTemp, 0, 0);
3139
3140 if ( inPlane(gIOPowerPlane) && !IS_PM_ROOT )
3141 {
3142 theNub = (IOService *)copyParentEntry(gIOPowerPlane);
3143 if ( theNub )
3144 {
3145 theParent = (IOService *)theNub->copyParentEntry(gIOPowerPlane);
3146 theNub->release();
3147 if ( theParent )
3148 {
3149 theParent->temperatureCriticalForZone(whichZone);
3150 theParent->release();
3151 }
3152 }
3153 }
3154 return IOPMNoErr;
3155 }
3156 #endif /* !__LP64__ */
3157
3158 // MARK: -
3159 // MARK: Power Change (Common)
3160
3161 //*********************************************************************************
3162 // [private] startPowerChange
3163 //
3164 // All power state changes starts here.
3165 //*********************************************************************************
3166
3167 IOReturn IOService::startPowerChange(
3168 IOPMPowerChangeFlags changeFlags,
3169 IOPMPowerStateIndex powerState,
3170 IOPMPowerFlags domainFlags,
3171 IOPowerConnection * parentConnection,
3172 IOPMPowerFlags parentFlags )
3173 {
3174 PM_ASSERT_IN_GATE();
3175 assert( fMachineState == kIOPM_Finished );
3176 assert( powerState < fNumberOfPowerStates );
3177
3178 if (powerState >= fNumberOfPowerStates)
3179 return IOPMAckImplied;
3180
3181 fIsPreChange = true;
3182 PM_ACTION_2(actionPowerChangeOverride, &powerState, &changeFlags);
3183
3184 // Forks to either Driver or Parent initiated power change paths.
3185
3186 fHeadNoteChangeFlags = changeFlags;
3187 fHeadNotePowerState = powerState;
3188 fHeadNotePowerArrayEntry = &fPowerStates[ powerState ];
3189 fHeadNoteParentConnection = NULL;
3190
3191 if (changeFlags & kIOPMSelfInitiated)
3192 {
3193 if (changeFlags & kIOPMSynchronize)
3194 OurSyncStart();
3195 else
3196 OurChangeStart();
3197 return 0;
3198 }
3199 else
3200 {
3201 assert(changeFlags & kIOPMParentInitiated);
3202 fHeadNoteDomainFlags = domainFlags;
3203 fHeadNoteParentFlags = parentFlags;
3204 fHeadNoteParentConnection = parentConnection;
3205 return ParentChangeStart();
3206 }
3207 }
3208
3209 //*********************************************************************************
3210 // [private] notifyInterestedDrivers
3211 //*********************************************************************************
3212
3213 bool IOService::notifyInterestedDrivers ( void )
3214 {
3215 IOPMinformee * informee;
3216 IOPMinformeeList * list = fInterestedDrivers;
3217 DriverCallParam * param;
3218 IOItemCount count;
3219
3220 PM_ASSERT_IN_GATE();
3221 assert( fDriverCallParamCount == 0 );
3222 assert( fHeadNotePendingAcks == 0 );
3223
3224 fHeadNotePendingAcks = 0;
3225
3226 count = list->numberOfItems();
3227 if (!count)
3228 goto done; // no interested drivers
3229
3230 // Allocate an array of interested drivers and their return values
3231 // for the callout thread. Everything else is still "owned" by the
3232 // PM work loop, which can run to process acknowledgePowerChange()
3233 // responses.
3234
3235 param = (DriverCallParam *) fDriverCallParamPtr;
3236 if (count > fDriverCallParamSlots)
3237 {
3238 if (fDriverCallParamSlots)
3239 {
3240 assert(fDriverCallParamPtr);
3241 IODelete(fDriverCallParamPtr, DriverCallParam, fDriverCallParamSlots);
3242 fDriverCallParamPtr = 0;
3243 fDriverCallParamSlots = 0;
3244 }
3245
3246 param = IONew(DriverCallParam, count);
3247 if (!param)
3248 goto done; // no memory
3249
3250 fDriverCallParamPtr = (void *) param;
3251 fDriverCallParamSlots = count;
3252 }
3253
3254 informee = list->firstInList();
3255 assert(informee);
3256 for (IOItemCount i = 0; i < count; i++)
3257 {
3258 informee->timer = -1;
3259 param[i].Target = informee;
3260 informee->retain();
3261 informee = list->nextInList( informee );
3262 }
3263
3264 fDriverCallParamCount = count;
3265 fHeadNotePendingAcks = count;
3266
3267 // Block state machine and wait for callout completion.
3268 assert(!fDriverCallBusy);
3269 fDriverCallBusy = true;
3270 thread_call_enter( fDriverCallEntry );
3271 return true;
3272
3273 done:
3274 // Return false if there are no interested drivers or could not schedule
3275 // callout thread due to error.
3276 return false;
3277 }
3278
3279 //*********************************************************************************
3280 // [private] notifyInterestedDriversDone
3281 //*********************************************************************************
3282
3283 void IOService::notifyInterestedDriversDone ( void )
3284 {
3285 IOPMinformee * informee;
3286 IOItemCount count;
3287 DriverCallParam * param;
3288 IOReturn result;
3289
3290 PM_ASSERT_IN_GATE();
3291 assert( fDriverCallBusy == false );
3292 assert( fMachineState == kIOPM_DriverThreadCallDone );
3293
3294 param = (DriverCallParam *) fDriverCallParamPtr;
3295 count = fDriverCallParamCount;
3296
3297 if (param && count)
3298 {
3299 for (IOItemCount i = 0; i < count; i++, param++)
3300 {
3301 informee = (IOPMinformee *) param->Target;
3302 result = param->Result;
3303
3304 if ((result == IOPMAckImplied) || (result < 0))
3305 {
3306 // Interested driver return IOPMAckImplied.
3307 // If informee timer is zero, it must have de-registered
3308 // interest during the thread callout. That also drops
3309 // the pending ack count.
3310
3311 if (fHeadNotePendingAcks && informee->timer)
3312 fHeadNotePendingAcks--;
3313
3314 informee->timer = 0;
3315 }
3316 else if (informee->timer)
3317 {
3318 assert(informee->timer == -1);
3319
3320 // Driver has not acked, and has returned a positive result.
3321 // Enforce a minimum permissible timeout value.
3322 // Make the min value large enough so timeout is less likely
3323 // to occur if a driver misinterpreted that the return value
3324 // should be in microsecond units. And make it large enough
3325 // to be noticeable if a driver neglects to ack.
3326
3327 if (result < kMinAckTimeoutTicks)
3328 result = kMinAckTimeoutTicks;
3329
3330 informee->timer = (result / (ACK_TIMER_PERIOD / ns_per_us)) + 1;
3331 }
3332 // else, child has already acked or driver has removed interest,
3333 // and head_note_pendingAcks decremented.
3334 // informee may have been removed from the interested drivers list,
3335 // thus the informee must be retained across the callout.
3336
3337 informee->release();
3338 }
3339
3340 fDriverCallParamCount = 0;
3341
3342 if ( fHeadNotePendingAcks )
3343 {
3344 OUR_PMLog(kPMLogStartAckTimer, 0, 0);
3345 start_ack_timer();
3346 }
3347 }
3348
3349 MS_POP(); // pushed by notifyAll()
3350
3351 // If interest acks are outstanding, wait for fHeadNotePendingAcks to become
3352 // zero before notifying children. This enforces the children after interest
3353 // ordering even for async interest clients.
3354
3355 if (!fHeadNotePendingAcks)
3356 {
3357 notifyChildren();
3358 }
3359 else
3360 {
3361 MS_PUSH(fMachineState);
3362 fMachineState = kIOPM_NotifyChildrenStart;
3363 PM_LOG2("%s: %u outstanding async interest\n",
3364 getName(), fHeadNotePendingAcks);
3365 }
3366 }
3367
3368 //*********************************************************************************
3369 // [private] notifyChildren
3370 //*********************************************************************************
3371
3372 void IOService::notifyChildren ( void )
3373 {
3374 OSIterator * iter;
3375 OSObject * next;
3376 IOPowerConnection * connection;
3377 OSArray * children = 0;
3378 IOPMrootDomain * rootDomain;
3379 bool delayNotify = false;
3380
3381 if ((fHeadNotePowerState != fCurrentPowerState) &&
3382 (IS_POWER_DROP == fIsPreChange) &&
3383 ((rootDomain = getPMRootDomain()) == this))
3384 {
3385 rootDomain->tracePoint( IS_POWER_DROP ?
3386 kIOPMTracePointSleepPowerPlaneDrivers :
3387 kIOPMTracePointWakePowerPlaneDrivers );
3388 }
3389
3390 if (fStrictTreeOrder)
3391 children = OSArray::withCapacity(8);
3392
3393 // Sum child power consumption in notifyChild()
3394 fHeadNotePowerArrayEntry->staticPower = 0;
3395
3396 iter = getChildIterator(gIOPowerPlane);
3397 if ( iter )
3398 {
3399 while ((next = iter->getNextObject()))
3400 {
3401 if ((connection = OSDynamicCast(IOPowerConnection, next)))
3402 {
3403 if (connection->getReadyFlag() == false)
3404 {
3405 PM_LOG3("[%s] %s: connection not ready\n",
3406 getName(), __FUNCTION__);
3407 continue;
3408 }
3409
3410 // Mechanism to postpone the did-change notification to
3411 // certain power children to order those children last.
3412 // Cannot be used together with strict tree ordering.
3413
3414 if (!fIsPreChange &&
3415 (connection->delayChildNotification) &&
3416 getPMRootDomain()->shouldDelayChildNotification(this))
3417 {
3418 if (!children)
3419 {
3420 children = OSArray::withCapacity(8);
3421 if (children)
3422 delayNotify = true;
3423 }
3424 if (delayNotify)
3425 {
3426 children->setObject( connection );
3427 continue;
3428 }
3429 }
3430
3431 if (!delayNotify && children)
3432 children->setObject( connection );
3433 else
3434 notifyChild( connection );
3435 }
3436 }
3437 iter->release();
3438 }
3439
3440 if (children && (children->getCount() == 0))
3441 {
3442 children->release();
3443 children = 0;
3444 }
3445 if (children)
3446 {
3447 assert(fNotifyChildArray == 0);
3448 fNotifyChildArray = children;
3449 MS_PUSH(fMachineState);
3450
3451 if (delayNotify)
3452 {
3453 // Wait for exiting child notifications to complete,
3454 // before notifying the children in the array.
3455 fMachineState = kIOPM_NotifyChildrenDelayed;
3456 PM_LOG2("%s: %d children in delayed array\n",
3457 getName(), children->getCount());
3458 }
3459 else
3460 {
3461 // Notify children in the array one at a time.
3462 fMachineState = kIOPM_NotifyChildrenOrdered;
3463 }
3464 }
3465 }
3466
3467 //*********************************************************************************
3468 // [private] notifyChildrenOrdered
3469 //*********************************************************************************
3470
3471 void IOService::notifyChildrenOrdered ( void )
3472 {
3473 PM_ASSERT_IN_GATE();
3474 assert(fNotifyChildArray);
3475 assert(fMachineState == kIOPM_NotifyChildrenOrdered);
3476
3477 // Notify one child, wait for it to ack, then repeat for next child.
3478 // This is a workaround for some drivers with multiple instances at
3479 // the same branch in the power tree, but the driver is slow to power
3480 // up unless the tree ordering is observed. Problem observed only on
3481 // system wake, not on system sleep.
3482 //
3483 // We have the ability to power off in reverse child index order.
3484 // That works nicely on some machines, but not on all HW configs.
3485
3486 if (fNotifyChildArray->getCount())
3487 {
3488 IOPowerConnection * connection;
3489 connection = (IOPowerConnection *) fNotifyChildArray->getObject(0);
3490 notifyChild( connection );
3491 fNotifyChildArray->removeObject(0);
3492 }
3493 else
3494 {
3495 fNotifyChildArray->release();
3496 fNotifyChildArray = 0;
3497
3498 MS_POP(); // pushed by notifyChildren()
3499 }
3500 }
3501
3502 //*********************************************************************************
3503 // [private] notifyChildrenDelayed
3504 //*********************************************************************************
3505
3506 void IOService::notifyChildrenDelayed ( void )
3507 {
3508 IOPowerConnection * connection;
3509
3510 PM_ASSERT_IN_GATE();
3511 assert(fNotifyChildArray);
3512 assert(fMachineState == kIOPM_NotifyChildrenDelayed);
3513
3514 // Wait after all non-delayed children and interested drivers have ack'ed,
3515 // then notify all delayed children. When explicitly cancelled, interest
3516 // acks (and ack timer) may still be outstanding.
3517
3518 for (int i = 0; ; i++)
3519 {
3520 connection = (IOPowerConnection *) fNotifyChildArray->getObject(i);
3521 if (!connection)
3522 break;
3523
3524 notifyChild( connection );
3525 }
3526
3527 PM_LOG2("%s: notified delayed children\n", getName());
3528 fNotifyChildArray->release();
3529 fNotifyChildArray = 0;
3530
3531 MS_POP(); // pushed by notifyChildren()
3532 }
3533
3534 //*********************************************************************************
3535 // [private] notifyAll
3536 //*********************************************************************************
3537
3538 IOReturn IOService::notifyAll ( uint32_t nextMS )
3539 {
3540 // Save the next machine_state to be restored by notifyInterestedDriversDone()
3541
3542 PM_ASSERT_IN_GATE();
3543 MS_PUSH(nextMS);
3544 fMachineState = kIOPM_DriverThreadCallDone;
3545 fDriverCallReason = fIsPreChange ?
3546 kDriverCallInformPreChange : kDriverCallInformPostChange;
3547
3548 if (!notifyInterestedDrivers())
3549 notifyInterestedDriversDone();
3550
3551 return IOPMWillAckLater;
3552 }
3553
3554 //*********************************************************************************
3555 // [private, static] pmDriverCallout
3556 //
3557 // Thread call context
3558 //*********************************************************************************
3559
3560 IOReturn IOService::actionDriverCalloutDone (
3561 OSObject * target,
3562 void * arg0, void * arg1,
3563 void * arg2, void * arg3 )
3564 {
3565 IOServicePM * pwrMgt = (IOServicePM *) arg0;
3566
3567 assert( fDriverCallBusy );
3568 fDriverCallBusy = false;
3569
3570 assert(gIOPMWorkQueue);
3571 gIOPMWorkQueue->signalWorkAvailable();
3572
3573 return kIOReturnSuccess;
3574 }
3575
3576 void IOService::pmDriverCallout ( IOService * from )
3577 {
3578 assert(from);
3579 switch (from->fDriverCallReason)
3580 {
3581 case kDriverCallSetPowerState:
3582 from->driverSetPowerState();
3583 break;
3584
3585 case kDriverCallInformPreChange:
3586 case kDriverCallInformPostChange:
3587 from->driverInformPowerChange();
3588 break;
3589
3590 default:
3591 panic("IOService::pmDriverCallout bad machine state %x",
3592 from->fDriverCallReason);
3593 }
3594
3595 gIOPMWorkLoop->runAction(actionDriverCalloutDone,
3596 /* target */ from,
3597 /* arg0 */ (void *) from->pwrMgt );
3598 }
3599
3600 //*********************************************************************************
3601 // [private] driverSetPowerState
3602 //
3603 // Thread call context
3604 //*********************************************************************************
3605
3606 void IOService::driverSetPowerState ( void )
3607 {
3608 IOPMPowerStateIndex powerState;
3609 DriverCallParam * param;
3610 IOPMDriverCallEntry callEntry;
3611 AbsoluteTime end;
3612 IOReturn result;
3613 uint32_t oldPowerState = getPowerState();
3614
3615 assert( fDriverCallBusy );
3616 assert( fDriverCallParamPtr );
3617 assert( fDriverCallParamCount == 1 );
3618
3619 param = (DriverCallParam *) fDriverCallParamPtr;
3620 powerState = fHeadNotePowerState;
3621
3622 if (assertPMDriverCall(&callEntry))
3623 {
3624 OUR_PMLog( kPMLogProgramHardware, (uintptr_t) this, powerState);
3625 clock_get_uptime(&fDriverCallStartTime);
3626 result = fControllingDriver->setPowerState( powerState, this );
3627 clock_get_uptime(&end);
3628 OUR_PMLog((UInt32) -kPMLogProgramHardware, (uintptr_t) this, (UInt32) result);
3629
3630 deassertPMDriverCall(&callEntry);
3631
3632 if (result < 0)
3633 {
3634 PM_LOG("%s::setPowerState(%p, %lu -> %lu) returned 0x%x\n",
3635 fName, this, fCurrentPowerState, powerState, result);
3636 }
3637
3638 #if LOG_SETPOWER_TIMES
3639 if ((result == IOPMAckImplied) || (result < 0))
3640 {
3641 uint64_t nsec;
3642
3643 SUB_ABSOLUTETIME(&end, &fDriverCallStartTime);
3644 absolutetime_to_nanoseconds(end, &nsec);
3645 if (nsec > LOG_SETPOWER_TIMES)
3646 PM_LOG("%s::setPowerState(%p, %lu -> %lu) took %d ms\n",
3647 fName, this, fCurrentPowerState, powerState, NS_TO_MS(nsec));
3648
3649 PMEventDetails *details = PMEventDetails::eventDetails(
3650 kIOPMEventTypeSetPowerStateImmediate, // type
3651 fName, // who
3652 (uintptr_t)this, // owner unique
3653 NULL, // interest name
3654 (uint8_t)oldPowerState, // old
3655 (uint8_t)powerState, // new
3656 0, // result
3657 NS_TO_US(nsec)); // usec completion time
3658
3659 getPMRootDomain()->recordAndReleasePMEventGated( details );
3660 }
3661 #endif
3662 }
3663 else
3664 result = kIOPMAckImplied;
3665
3666 param->Result = result;
3667 }
3668
3669 //*********************************************************************************
3670 // [private] driverInformPowerChange
3671 //
3672 // Thread call context
3673 //*********************************************************************************
3674
3675 void IOService::driverInformPowerChange ( void )
3676 {
3677 IOPMinformee * informee;
3678 IOService * driver;
3679 DriverCallParam * param;
3680 IOPMDriverCallEntry callEntry;
3681 IOPMPowerFlags powerFlags;
3682 IOPMPowerStateIndex powerState;
3683 AbsoluteTime end;
3684 IOReturn result;
3685 IOItemCount count;
3686
3687 assert( fDriverCallBusy );
3688 assert( fDriverCallParamPtr );
3689 assert( fDriverCallParamCount );
3690
3691 param = (DriverCallParam *) fDriverCallParamPtr;
3692 count = fDriverCallParamCount;
3693
3694 powerFlags = fHeadNotePowerArrayEntry->capabilityFlags;
3695 powerState = fHeadNotePowerState;
3696
3697 for (IOItemCount i = 0; i < count; i++)
3698 {
3699 informee = (IOPMinformee *) param->Target;
3700 driver = informee->whatObject;
3701
3702 if (assertPMDriverCall(&callEntry, 0, informee))
3703 {
3704 if (fDriverCallReason == kDriverCallInformPreChange)
3705 {
3706 OUR_PMLog(kPMLogInformDriverPreChange, (uintptr_t) this, powerState);
3707 clock_get_uptime(&informee->startTime);
3708 result = driver->powerStateWillChangeTo(powerFlags, powerState, this);
3709 clock_get_uptime(&end);
3710 OUR_PMLog((UInt32)-kPMLogInformDriverPreChange, (uintptr_t) this, result);
3711 }
3712 else
3713 {
3714 OUR_PMLog(kPMLogInformDriverPostChange, (uintptr_t) this, powerState);
3715 clock_get_uptime(&informee->startTime);
3716 result = driver->powerStateDidChangeTo(powerFlags, powerState, this);
3717 clock_get_uptime(&end);
3718 OUR_PMLog((UInt32)-kPMLogInformDriverPostChange, (uintptr_t) this, result);
3719 }
3720
3721 deassertPMDriverCall(&callEntry);
3722
3723 #if LOG_SETPOWER_TIMES
3724 if ((result == IOPMAckImplied) || (result < 0))
3725 {
3726 uint64_t nsec;
3727
3728 SUB_ABSOLUTETIME(&end, &informee->startTime);
3729 absolutetime_to_nanoseconds(end, &nsec);
3730 if (nsec > LOG_SETPOWER_TIMES)
3731 PM_LOG("%s::powerState%sChangeTo(%p, %s, %lu -> %lu) took %d ms\n",
3732 driver->getName(),
3733 (fDriverCallReason == kDriverCallInformPreChange) ? "Will" : "Did",
3734 driver, fName, fCurrentPowerState, powerState, NS_TO_MS(nsec));
3735
3736 uint16_t logType = (fDriverCallReason == kDriverCallInformPreChange)
3737 ? kIOPMEventTypePSWillChangeTo
3738 : kIOPMEventTypePSDidChangeTo;
3739
3740 PMEventDetails *details = PMEventDetails::eventDetails(
3741 logType, // type
3742 fName, // who
3743 (uintptr_t)this, // owner unique
3744 driver->getName(), // interest name
3745 (uint8_t)fCurrentPowerState, // old
3746 (uint8_t)fHeadNotePowerState, // new
3747 0, // result
3748 NS_TO_US(nsec)); // usec completion time
3749
3750 getPMRootDomain()->recordAndReleasePMEventGated( details );
3751 }
3752 #endif
3753 }
3754 else
3755 result = kIOPMAckImplied;
3756
3757 param->Result = result;
3758 param++;
3759 }
3760 }
3761
3762 //*********************************************************************************
3763 // [private] notifyChild
3764 //
3765 // Notify a power domain child of an upcoming power change.
3766 // If the object acknowledges the current change, we return TRUE.
3767 //*********************************************************************************
3768
3769 bool IOService::notifyChild ( IOPowerConnection * theNub )
3770 {
3771 IOReturn ret = IOPMAckImplied;
3772 unsigned long childPower;
3773 IOService * theChild;
3774 IOPMRequest * childRequest;
3775 IOPMPowerChangeFlags requestArg2;
3776 int requestType;
3777
3778 PM_ASSERT_IN_GATE();
3779 theChild = (IOService *)(theNub->copyChildEntry(gIOPowerPlane));
3780 if (!theChild)
3781 {
3782 return true;
3783 }
3784
3785 // Unless the child handles the notification immediately and returns
3786 // kIOPMAckImplied, we'll be awaiting their acknowledgement later.
3787 fHeadNotePendingAcks++;
3788 theNub->setAwaitingAck(true);
3789
3790 requestArg2 = fHeadNoteChangeFlags;
3791 if (fHeadNotePowerState < fCurrentPowerState)
3792 requestArg2 |= kIOPMDomainPowerDrop;
3793
3794 requestType = fIsPreChange ?
3795 kIOPMRequestTypePowerDomainWillChange :
3796 kIOPMRequestTypePowerDomainDidChange;
3797
3798 childRequest = acquirePMRequest( theChild, requestType );
3799 if (childRequest)
3800 {
3801 theNub->retain();
3802 childRequest->fArg0 = (void *) fHeadNotePowerArrayEntry->outputPowerFlags;
3803 childRequest->fArg1 = (void *) theNub;
3804 childRequest->fArg2 = (void *) requestArg2;
3805 theChild->submitPMRequest( childRequest );
3806 ret = IOPMWillAckLater;
3807 }
3808 else
3809 {
3810 ret = IOPMAckImplied;
3811 fHeadNotePendingAcks--;
3812 theNub->setAwaitingAck(false);
3813 childPower = theChild->currentPowerConsumption();
3814 if ( childPower == kIOPMUnknown )
3815 {
3816 fHeadNotePowerArrayEntry->staticPower = kIOPMUnknown;
3817 } else {
3818 if (fHeadNotePowerArrayEntry->staticPower != kIOPMUnknown )
3819 fHeadNotePowerArrayEntry->staticPower += childPower;
3820 }
3821 }
3822
3823 theChild->release();
3824 return (IOPMAckImplied == ret);
3825 }
3826
3827 //*********************************************************************************
3828 // [private] notifyControllingDriver
3829 //*********************************************************************************
3830
3831 bool IOService::notifyControllingDriver ( void )
3832 {
3833 DriverCallParam * param;
3834
3835 PM_ASSERT_IN_GATE();
3836 assert( fDriverCallParamCount == 0 );
3837 assert( fControllingDriver );
3838
3839 if (fInitialSetPowerState)
3840 {
3841 fInitialSetPowerState = false;
3842 fHeadNoteChangeFlags |= kIOPMInitialPowerChange;
3843
3844 // Driver specified flag to skip the inital setPowerState()
3845 if (fHeadNotePowerArrayEntry->capabilityFlags & kIOPMInitialDeviceState)
3846 {
3847 return false;
3848 }
3849 }
3850
3851 param = (DriverCallParam *) fDriverCallParamPtr;
3852 if (!param)
3853 {
3854 param = IONew(DriverCallParam, 1);
3855 if (!param)
3856 return false; // no memory
3857
3858 fDriverCallParamPtr = (void *) param;
3859 fDriverCallParamSlots = 1;
3860 }
3861
3862 param->Target = fControllingDriver;
3863 fDriverCallParamCount = 1;
3864 fDriverTimer = -1;
3865
3866 // Block state machine and wait for callout completion.
3867 assert(!fDriverCallBusy);
3868 fDriverCallBusy = true;
3869 thread_call_enter( fDriverCallEntry );
3870
3871 return true;
3872 }
3873
3874 //*********************************************************************************
3875 // [private] notifyControllingDriverDone
3876 //*********************************************************************************
3877
3878 void IOService::notifyControllingDriverDone( void )
3879 {
3880 DriverCallParam * param;
3881 IOReturn result;
3882
3883 PM_ASSERT_IN_GATE();
3884 param = (DriverCallParam *) fDriverCallParamPtr;
3885
3886 assert( fDriverCallBusy == false );
3887 assert( fMachineState == kIOPM_DriverThreadCallDone );
3888
3889 if (param && fDriverCallParamCount)
3890 {
3891 assert(fDriverCallParamCount == 1);
3892
3893 // the return value from setPowerState()
3894 result = param->Result;
3895
3896 if ((result == IOPMAckImplied) || (result < 0))
3897 {
3898 fDriverTimer = 0;
3899 }
3900 else if (fDriverTimer)
3901 {
3902 assert(fDriverTimer == -1);
3903
3904 // Driver has not acked, and has returned a positive result.
3905 // Enforce a minimum permissible timeout value.
3906 // Make the min value large enough so timeout is less likely
3907 // to occur if a driver misinterpreted that the return value
3908 // should be in microsecond units. And make it large enough
3909 // to be noticeable if a driver neglects to ack.
3910
3911 if (result < kMinAckTimeoutTicks)
3912 result = kMinAckTimeoutTicks;
3913
3914 fDriverTimer = (result / (ACK_TIMER_PERIOD / ns_per_us)) + 1;
3915 }
3916 // else, child has already acked and driver_timer reset to 0.
3917
3918 fDriverCallParamCount = 0;
3919
3920 if ( fDriverTimer )
3921 {
3922 OUR_PMLog(kPMLogStartAckTimer, 0, 0);
3923 start_ack_timer();
3924 }
3925 }
3926
3927 MS_POP(); // pushed by OurChangeSetPowerState()
3928 fIsPreChange = false;
3929 }
3930
3931 //*********************************************************************************
3932 // [private] all_done
3933 //
3934 // A power change is done.
3935 //*********************************************************************************
3936
3937 void IOService::all_done ( void )
3938 {
3939 IOPMPowerStateIndex prevPowerState;
3940 const IOPMPSEntry * powerStatePtr;
3941 IOPMDriverCallEntry callEntry;
3942 uint32_t prevMachineState = fMachineState;
3943 bool callAction = false;
3944
3945 fMachineState = kIOPM_Finished;
3946
3947 if ((fHeadNoteChangeFlags & kIOPMSynchronize) &&
3948 ((prevMachineState == kIOPM_Finished) ||
3949 (prevMachineState == kIOPM_SyncFinish)))
3950 {
3951 // Sync operation and no power change occurred.
3952 // Do not inform driver and clients about this request completion,
3953 // except for the originator (root domain).
3954
3955 PM_ACTION_2(actionPowerChangeDone,
3956 fHeadNotePowerState, fHeadNoteChangeFlags);
3957
3958 if (getPMRequestType() == kIOPMRequestTypeSynchronizePowerTree)
3959 {
3960 powerChangeDone(fCurrentPowerState);
3961 }
3962
3963 return;
3964 }
3965
3966 // our power change
3967 if ( fHeadNoteChangeFlags & kIOPMSelfInitiated )
3968 {
3969 // could our driver switch to the new state?
3970 if ( !( fHeadNoteChangeFlags & kIOPMNotDone) )
3971 {
3972 trackSystemSleepPreventers(
3973 fCurrentPowerState, fHeadNotePowerState, fHeadNoteChangeFlags);
3974
3975 // we changed, tell our parent
3976 requestDomainPower(fHeadNotePowerState);
3977
3978 // yes, did power raise?
3979 if ( fCurrentPowerState < fHeadNotePowerState )
3980 {
3981 // yes, inform clients and apps
3982 tellChangeUp (fHeadNotePowerState);
3983 }
3984 prevPowerState = fCurrentPowerState;
3985 // either way
3986 fCurrentPowerState = fHeadNotePowerState;
3987 #if PM_VARS_SUPPORT
3988 fPMVars->myCurrentState = fCurrentPowerState;
3989 #endif
3990 OUR_PMLog(kPMLogChangeDone, fCurrentPowerState, 0);
3991 PM_ACTION_2(actionPowerChangeDone,
3992 fHeadNotePowerState, fHeadNoteChangeFlags);
3993 callAction = true;
3994
3995 powerStatePtr = &fPowerStates[fCurrentPowerState];
3996 fCurrentCapabilityFlags = powerStatePtr->capabilityFlags;
3997 if (fCurrentCapabilityFlags & kIOPMStaticPowerValid)
3998 fCurrentPowerConsumption = powerStatePtr->staticPower;
3999
4000 // inform subclass policy-maker
4001 if (fPCDFunctionOverride && fParentsKnowState &&
4002 assertPMDriverCall(&callEntry, kIOPMADC_NoInactiveCheck))
4003 {
4004 powerChangeDone(prevPowerState);
4005 deassertPMDriverCall(&callEntry);
4006 }
4007 }
4008 else if (getPMRequestType() == kIOPMRequestTypeRequestPowerStateOverride)
4009 {
4010 // changePowerStateWithOverrideTo() was cancelled
4011 fOverrideMaxPowerState = kIOPMPowerStateMax;
4012 }
4013 }
4014
4015 // parent's power change
4016 if ( fHeadNoteChangeFlags & kIOPMParentInitiated)
4017 {
4018 if (((fHeadNoteChangeFlags & kIOPMDomainWillChange) &&
4019 (fCurrentPowerState >= fHeadNotePowerState)) ||
4020 ((fHeadNoteChangeFlags & kIOPMDomainDidChange) &&
4021 (fCurrentPowerState < fHeadNotePowerState)))
4022 {
4023 trackSystemSleepPreventers(
4024 fCurrentPowerState, fHeadNotePowerState, fHeadNoteChangeFlags);
4025
4026 // did power raise?
4027 if ( fCurrentPowerState < fHeadNotePowerState )
4028 {
4029 // yes, inform clients and apps
4030 tellChangeUp (fHeadNotePowerState);
4031 }
4032 // either way
4033 prevPowerState = fCurrentPowerState;
4034 fCurrentPowerState = fHeadNotePowerState;
4035 #if PM_VARS_SUPPORT
4036 fPMVars->myCurrentState = fCurrentPowerState;
4037 #endif
4038 fMaxPowerState = fControllingDriver->maxCapabilityForDomainState(fHeadNoteDomainFlags);
4039
4040 OUR_PMLog(kPMLogChangeDone, fCurrentPowerState, 0);
4041 PM_ACTION_2(actionPowerChangeDone,
4042 fHeadNotePowerState, fHeadNoteChangeFlags);
4043 callAction = true;
4044
4045 powerStatePtr = &fPowerStates[fCurrentPowerState];
4046 fCurrentCapabilityFlags = powerStatePtr->capabilityFlags;
4047 if (fCurrentCapabilityFlags & kIOPMStaticPowerValid)
4048 fCurrentPowerConsumption = powerStatePtr->staticPower;
4049
4050 // inform subclass policy-maker
4051 if (fPCDFunctionOverride && fParentsKnowState &&
4052 assertPMDriverCall(&callEntry, kIOPMADC_NoInactiveCheck))
4053 {
4054 powerChangeDone(prevPowerState);
4055 deassertPMDriverCall(&callEntry);
4056 }
4057 }
4058 }
4059
4060 // When power rises enough to satisfy the tickle's desire for more power,
4061 // the condition preventing idle-timer from dropping power is removed.
4062
4063 if (fCurrentPowerState >= fIdleTimerMinPowerState)
4064 {
4065 fIdleTimerMinPowerState = 0;
4066 }
4067
4068 if (!callAction)
4069 {
4070 PM_ACTION_2(actionPowerChangeDone,
4071 fHeadNotePowerState, fHeadNoteChangeFlags);
4072 }
4073 }
4074
4075 // MARK: -
4076 // MARK: Power Change Initiated by Driver
4077
4078 //*********************************************************************************
4079 // [private] OurChangeStart
4080 //
4081 // Begin the processing of a power change initiated by us.
4082 //*********************************************************************************
4083
4084 void IOService::OurChangeStart ( void )
4085 {
4086 PM_ASSERT_IN_GATE();
4087 OUR_PMLog( kPMLogStartDeviceChange, fHeadNotePowerState, fCurrentPowerState );
4088
4089 // fMaxPowerState is our maximum possible power state based on the current
4090 // power state of our parents. If we are trying to raise power beyond the
4091 // maximum, send an async request for more power to all parents.
4092
4093 if (!IS_PM_ROOT && (fMaxPowerState < fHeadNotePowerState))
4094 {
4095 fHeadNoteChangeFlags |= kIOPMNotDone;
4096 requestDomainPower(fHeadNotePowerState);
4097 OurChangeFinish();
4098 return;
4099 }
4100
4101 // Redundant power changes skips to the end of the state machine.
4102
4103 if (!fInitialPowerChange && (fHeadNotePowerState == fCurrentPowerState))
4104 {
4105 OurChangeFinish();
4106 return;
4107 }
4108 fInitialPowerChange = false;
4109
4110 // Change started, but may not complete...
4111 // Can be canceled (power drop) or deferred (power rise).
4112
4113 PM_ACTION_2(actionPowerChangeStart, fHeadNotePowerState, &fHeadNoteChangeFlags);
4114
4115 // Two separate paths, depending if power is being raised or lowered.
4116 // Lowering power is subject to approval by clients of this service.
4117
4118 if (IS_POWER_DROP)
4119 {
4120 fDoNotPowerDown = false;
4121
4122 // Ask for persmission to drop power state
4123 fMachineState = kIOPM_OurChangeTellClientsPowerDown;
4124 fOutOfBandParameter = kNotifyApps;
4125 askChangeDown(fHeadNotePowerState);
4126 }
4127 else
4128 {
4129 // This service is raising power and parents are able to support the
4130 // new power state. However a parent may have already committed to
4131 // drop power, which might force this object to temporarily drop power.
4132 // This results in "oscillations" before the state machines converge
4133 // to a steady state.
4134 //
4135 // To prevent this, a child must make a power reservation against all
4136 // parents before raising power. If the reservation fails, indicating
4137 // that the child will be unable to sustain the higher power state,
4138 // then the child will signal the parent to adjust power, and the child
4139 // will defer its power change.
4140
4141 IOReturn ret;
4142
4143 // Reserve parent power necessary to achieve fHeadNotePowerState.
4144 ret = requestDomainPower( fHeadNotePowerState, kReserveDomainPower );
4145 if (ret != kIOReturnSuccess)
4146 {
4147 // Reservation failed, defer power rise.
4148 fHeadNoteChangeFlags |= kIOPMNotDone;
4149 OurChangeFinish();
4150 return;
4151 }
4152
4153 OurChangeTellCapabilityWillChange();
4154 }
4155 }
4156
4157 //*********************************************************************************
4158
4159 struct IOPMRequestDomainPowerContext {
4160 IOService * child; // the requesting child
4161 IOPMPowerFlags requestPowerFlags; // power flags requested by child
4162 };
4163
4164 static void
4165 requestDomainPowerApplier(
4166 IORegistryEntry * entry,
4167 void * inContext )
4168 {
4169 IOPowerConnection * connection;
4170 IOService * parent;
4171 IOPMRequestDomainPowerContext * context;
4172
4173 if ((connection = OSDynamicCast(IOPowerConnection, entry)) == 0)
4174 return;
4175 parent = (IOService *) connection->copyParentEntry(gIOPowerPlane);
4176 if (!parent)
4177 return;
4178
4179 assert(inContext);
4180 context = (IOPMRequestDomainPowerContext *) inContext;
4181
4182 if (connection->parentKnowsState() && connection->getReadyFlag())
4183 {
4184 parent->requestPowerDomainState(
4185 context->requestPowerFlags,
4186 connection,
4187 IOPMLowestState);
4188 }
4189
4190 parent->release();
4191 }
4192
4193 //*********************************************************************************
4194 // [private] requestDomainPower
4195 //*********************************************************************************
4196
4197 IOReturn IOService::requestDomainPower(
4198 IOPMPowerStateIndex ourPowerState,
4199 IOOptionBits options )
4200 {
4201 IOPMPowerFlags requestPowerFlags;
4202 IOPMPowerStateIndex maxPowerState;
4203 IOPMRequestDomainPowerContext context;
4204
4205 PM_ASSERT_IN_GATE();
4206 assert(ourPowerState < fNumberOfPowerStates);
4207 if (ourPowerState >= fNumberOfPowerStates)
4208 return kIOReturnBadArgument;
4209 if (IS_PM_ROOT)
4210 return kIOReturnSuccess;
4211
4212 // Fetch the input power flags for the requested power state.
4213 // Parent request is stated in terms of required power flags.
4214
4215 requestPowerFlags = fPowerStates[ourPowerState].inputPowerFlags;
4216
4217 // Disregard the "previous request" for power reservation.
4218
4219 if (((options & kReserveDomainPower) == 0) &&
4220 (fPreviousRequestPowerFlags == requestPowerFlags))
4221 {
4222 // skip if domain already knows our requirements
4223 goto done;
4224 }
4225 fPreviousRequestPowerFlags = requestPowerFlags;
4226
4227 context.child = this;
4228 context.requestPowerFlags = requestPowerFlags;
4229 fHeadNoteDomainTargetFlags = 0;
4230 applyToParents(requestDomainPowerApplier, &context, gIOPowerPlane);
4231
4232 if (options & kReserveDomainPower)
4233 {
4234 maxPowerState = fControllingDriver->maxCapabilityForDomainState(
4235 fHeadNoteDomainTargetFlags );
4236
4237 if (maxPowerState < fHeadNotePowerState)
4238 {
4239 PM_LOG1("%s: power desired %u:0x%x got %u:0x%x\n",
4240 getName(),
4241 (uint32_t) ourPowerState, (uint32_t) requestPowerFlags,
4242 (uint32_t) maxPowerState, (uint32_t) fHeadNoteDomainTargetFlags);
4243 return kIOReturnNoPower;
4244 }
4245 }
4246
4247 done:
4248 return kIOReturnSuccess;
4249 }
4250
4251 //*********************************************************************************
4252 // [private] OurSyncStart
4253 //*********************************************************************************
4254
4255 void IOService::OurSyncStart ( void )
4256 {
4257 PM_ASSERT_IN_GATE();
4258
4259 if (fInitialPowerChange)
4260 return;
4261
4262 PM_ACTION_2(actionPowerChangeStart, fHeadNotePowerState, &fHeadNoteChangeFlags);
4263
4264 if (fHeadNoteChangeFlags & kIOPMNotDone)
4265 {
4266 OurChangeFinish();
4267 return;
4268 }
4269
4270 if (fHeadNoteChangeFlags & kIOPMSyncTellPowerDown)
4271 {
4272 fDoNotPowerDown = false;
4273
4274 // Ask for permission to drop power state
4275 fMachineState = kIOPM_SyncTellClientsPowerDown;
4276 fOutOfBandParameter = kNotifyApps;
4277 askChangeDown(fHeadNotePowerState);
4278 }
4279 else
4280 {
4281 // Only inform capability app and clients.
4282 tellSystemCapabilityChange( kIOPM_SyncNotifyWillChange );
4283 }
4284 }
4285
4286 //*********************************************************************************
4287 // [private] OurChangeTellClientsPowerDown
4288 //
4289 // All applications and kernel clients have acknowledged our permission to drop
4290 // power. Here we notify them that we will lower the power and wait for acks.
4291 //*********************************************************************************
4292
4293 void IOService::OurChangeTellClientsPowerDown ( void )
4294 {
4295 fMachineState = kIOPM_OurChangeTellPriorityClientsPowerDown;
4296 tellChangeDown1(fHeadNotePowerState);
4297 }
4298
4299 //*********************************************************************************
4300 // [private] OurChangeTellPriorityClientsPowerDown
4301 //
4302 // All applications and kernel clients have acknowledged our intention to drop
4303 // power. Here we notify "priority" clients that we are lowering power.
4304 //*********************************************************************************
4305
4306 void IOService::OurChangeTellPriorityClientsPowerDown ( void )
4307 {
4308 fMachineState = kIOPM_OurChangeNotifyInterestedDriversWillChange;
4309 tellChangeDown2(fHeadNotePowerState);
4310 }
4311
4312 //*********************************************************************************
4313 // [private] OurChangeTellCapabilityWillChange
4314 //
4315 // Extra stage for root domain to notify apps and drivers about the
4316 // system capability change when raising power state.
4317 //*********************************************************************************
4318
4319 void IOService::OurChangeTellCapabilityWillChange ( void )
4320 {
4321 if (!IS_ROOT_DOMAIN)
4322 return OurChangeNotifyInterestedDriversWillChange();
4323
4324 tellSystemCapabilityChange( kIOPM_OurChangeNotifyInterestedDriversWillChange );
4325 }
4326
4327 //*********************************************************************************
4328 // [private] OurChangeNotifyInterestedDriversWillChange
4329 //
4330 // All applications and kernel clients have acknowledged our power state change.
4331 // Here we notify interested drivers pre-change.
4332 //*********************************************************************************
4333
4334 void IOService::OurChangeNotifyInterestedDriversWillChange ( void )
4335 {
4336 IOPMrootDomain * rootDomain;
4337 if ((rootDomain = getPMRootDomain()) == this)
4338 {
4339 if (IS_POWER_DROP)
4340 {
4341 rootDomain->tracePoint( kIOPMTracePointSleepWillChangeInterests );
4342
4343 PMEventDetails *details = PMEventDetails::eventDetails(
4344 kIOPMEventTypeAppNotificationsFinished,
4345 NULL,
4346 100,
4347 kIOReturnSuccess);
4348 rootDomain->recordAndReleasePMEventGated( details );
4349 }
4350 else
4351 rootDomain->tracePoint( kIOPMTracePointWakeWillChangeInterests );
4352 }
4353
4354 notifyAll( kIOPM_OurChangeSetPowerState );
4355 }
4356
4357 //*********************************************************************************
4358 // [private] OurChangeSetPowerState
4359 //
4360 // Instruct our controlling driver to program the hardware for the power state
4361 // change. Wait for async completions.
4362 //*********************************************************************************
4363
4364 void IOService::OurChangeSetPowerState ( void )
4365 {
4366 MS_PUSH( kIOPM_OurChangeWaitForPowerSettle );
4367 fMachineState = kIOPM_DriverThreadCallDone;
4368 fDriverCallReason = kDriverCallSetPowerState;
4369
4370 if (notifyControllingDriver() == false)
4371 notifyControllingDriverDone();
4372 }
4373
4374 //*********************************************************************************
4375 // [private] OurChangeWaitForPowerSettle
4376 //
4377 // Our controlling driver has completed the power state change we initiated.
4378 // Wait for the driver specified settle time to expire.
4379 //*********************************************************************************
4380
4381 void IOService::OurChangeWaitForPowerSettle ( void )
4382 {
4383 fMachineState = kIOPM_OurChangeNotifyInterestedDriversDidChange;
4384 startSettleTimer();
4385 }
4386
4387 //*********************************************************************************
4388 // [private] OurChangeNotifyInterestedDriversDidChange
4389 //
4390 // Power has settled on a power change we initiated. Here we notify
4391 // all our interested drivers post-change.
4392 //*********************************************************************************
4393
4394 void IOService::OurChangeNotifyInterestedDriversDidChange ( void )
4395 {
4396 IOPMrootDomain * rootDomain;
4397 if ((rootDomain = getPMRootDomain()) == this)
4398 {
4399 rootDomain->tracePoint( IS_POWER_DROP ?
4400 kIOPMTracePointSleepDidChangeInterests :
4401 kIOPMTracePointWakeDidChangeInterests );
4402 }
4403
4404 notifyAll( kIOPM_OurChangeTellCapabilityDidChange );
4405 }
4406
4407 //*********************************************************************************
4408 // [private] OurChangeTellCapabilityDidChange
4409 //
4410 // For root domain to notify capability power-change.
4411 //*********************************************************************************
4412
4413 void IOService::OurChangeTellCapabilityDidChange ( void )
4414 {
4415 if (!IS_ROOT_DOMAIN)
4416 return OurChangeFinish();
4417
4418 getPMRootDomain()->tracePoint( IS_POWER_DROP ?
4419 kIOPMTracePointSleepCapabilityClients :
4420 kIOPMTracePointWakeCapabilityClients );
4421
4422 tellSystemCapabilityChange( kIOPM_OurChangeFinish );
4423 }
4424
4425 //*********************************************************************************
4426 // [private] OurChangeFinish
4427 //
4428 // Done with this self-induced power state change.
4429 //*********************************************************************************
4430
4431 void IOService::OurChangeFinish ( void )
4432 {
4433 all_done();
4434 }
4435
4436 // MARK: -
4437 // MARK: Power Change Initiated by Parent
4438
4439 //*********************************************************************************
4440 // [private] ParentChangeStart
4441 //
4442 // Here we begin the processing of a power change initiated by our parent.
4443 //*********************************************************************************
4444
4445 IOReturn IOService::ParentChangeStart ( void )
4446 {
4447 PM_ASSERT_IN_GATE();
4448 OUR_PMLog( kPMLogStartParentChange, fHeadNotePowerState, fCurrentPowerState );
4449
4450 // Power domain is lowering power
4451 if ( fHeadNotePowerState < fCurrentPowerState )
4452 {
4453 // TODO: redundant? See handlePowerDomainWillChangeTo()
4454 setParentInfo( fHeadNoteParentFlags, fHeadNoteParentConnection, true );
4455
4456 PM_ACTION_2(actionPowerChangeStart, fHeadNotePowerState, &fHeadNoteChangeFlags);
4457
4458 // Tell apps and kernel clients
4459 fInitialPowerChange = false;
4460 fMachineState = kIOPM_ParentChangeTellPriorityClientsPowerDown;
4461 tellChangeDown1(fHeadNotePowerState);
4462 return IOPMWillAckLater;
4463 }
4464
4465 // Power domain is raising power
4466 if ( fHeadNotePowerState > fCurrentPowerState )
4467 {
4468 if ( fDesiredPowerState > fCurrentPowerState )
4469 {
4470 if ( fDesiredPowerState < fHeadNotePowerState )
4471 {
4472 // We power up, but not all the way
4473 fHeadNotePowerState = fDesiredPowerState;
4474 fHeadNotePowerArrayEntry = &fPowerStates[fDesiredPowerState];
4475 OUR_PMLog(kPMLogAmendParentChange, fHeadNotePowerState, 0);
4476 }
4477 } else {
4478 // We don't need to change
4479 fHeadNotePowerState = fCurrentPowerState;
4480 fHeadNotePowerArrayEntry = &fPowerStates[fCurrentPowerState];
4481 OUR_PMLog(kPMLogAmendParentChange, fHeadNotePowerState, 0);
4482 }
4483 }
4484
4485 if ( fHeadNoteChangeFlags & kIOPMDomainDidChange )
4486 {
4487 if ( fHeadNotePowerState > fCurrentPowerState )
4488 {
4489 PM_ACTION_2(actionPowerChangeStart,
4490 fHeadNotePowerState, &fHeadNoteChangeFlags);
4491
4492 // Parent did change up - start our change up
4493 fInitialPowerChange = false;
4494 ParentChangeTellCapabilityWillChange();
4495 return IOPMWillAckLater;
4496 }
4497 else if (fHeadNoteChangeFlags & kIOPMSynchronize)
4498 {
4499 // We do not need to change power state, but notify
4500 // children to propagate tree synchronization.
4501 fMachineState = kIOPM_SyncNotifyDidChange;
4502 fDriverCallReason = kDriverCallInformPreChange;
4503 notifyChildren();
4504 return IOPMWillAckLater;
4505 }
4506 }
4507
4508 all_done();
4509 return IOPMAckImplied;
4510 }
4511
4512 //*********************************************************************************
4513 // [private] ParentChangeTellPriorityClientsPowerDown
4514 //
4515 // All applications and kernel clients have acknowledged our intention to drop
4516 // power. Here we notify "priority" clients that we are lowering power.
4517 //*********************************************************************************
4518
4519 void IOService::ParentChangeTellPriorityClientsPowerDown ( void )
4520 {
4521 fMachineState = kIOPM_ParentChangeNotifyInterestedDriversWillChange;
4522 tellChangeDown2(fHeadNotePowerState);
4523 }
4524
4525 //*********************************************************************************
4526 // [private] ParentChangeTellCapabilityWillChange
4527 //
4528 // All (legacy) applications and kernel clients have acknowledged, extra stage for
4529 // root domain to notify apps and drivers about the system capability change.
4530 //*********************************************************************************
4531
4532 void IOService::ParentChangeTellCapabilityWillChange ( void )
4533 {
4534 if (!IS_ROOT_DOMAIN)
4535 return ParentChangeNotifyInterestedDriversWillChange();
4536
4537 tellSystemCapabilityChange( kIOPM_ParentChangeNotifyInterestedDriversWillChange );
4538 }
4539
4540 //*********************************************************************************
4541 // [private] ParentChangeNotifyInterestedDriversWillChange
4542 //
4543 // All applications and kernel clients have acknowledged our power state change.
4544 // Here we notify interested drivers pre-change.
4545 //*********************************************************************************
4546
4547 void IOService::ParentChangeNotifyInterestedDriversWillChange ( void )
4548 {
4549 notifyAll( kIOPM_ParentChangeSetPowerState );
4550 }
4551
4552 //*********************************************************************************
4553 // [private] ParentChangeSetPowerState
4554 //
4555 // Instruct our controlling driver to program the hardware for the power state
4556 // change. Wait for async completions.
4557 //*********************************************************************************
4558
4559 void IOService::ParentChangeSetPowerState ( void )
4560 {
4561 MS_PUSH( kIOPM_ParentChangeWaitForPowerSettle );
4562 fMachineState = kIOPM_DriverThreadCallDone;
4563 fDriverCallReason = kDriverCallSetPowerState;
4564
4565 if (notifyControllingDriver() == false)
4566 notifyControllingDriverDone();
4567 }
4568
4569 //*********************************************************************************
4570 // [private] ParentChangeWaitForPowerSettle
4571 //
4572 // Our controlling driver has completed the power state change initiated by our
4573 // parent. Wait for the driver specified settle time to expire.
4574 //*********************************************************************************
4575
4576 void IOService::ParentChangeWaitForPowerSettle ( void )
4577 {
4578 fMachineState = kIOPM_ParentChangeNotifyInterestedDriversDidChange;
4579 startSettleTimer();
4580 }
4581
4582 //*********************************************************************************
4583 // [private] ParentChangeNotifyInterestedDriversDidChange
4584 //
4585 // Power has settled on a power change initiated by our parent. Here we notify
4586 // all our interested drivers post-change.
4587 //*********************************************************************************
4588
4589 void IOService::ParentChangeNotifyInterestedDriversDidChange ( void )
4590 {
4591 notifyAll( kIOPM_ParentChangeTellCapabilityDidChange );
4592 }
4593
4594 //*********************************************************************************
4595 // [private] ParentChangeTellCapabilityDidChange
4596 //
4597 // For root domain to notify capability power-change.
4598 //*********************************************************************************
4599
4600 void IOService::ParentChangeTellCapabilityDidChange ( void )
4601 {
4602 if (!IS_ROOT_DOMAIN)
4603 return ParentChangeAcknowledgePowerChange();
4604
4605 tellSystemCapabilityChange( kIOPM_ParentChangeAcknowledgePowerChange );
4606 }
4607
4608 //*********************************************************************************
4609 // [private] ParentAcknowledgePowerChange
4610 //
4611 // Acknowledge our power parent that our power change is done.
4612 //*********************************************************************************
4613
4614 void IOService::ParentChangeAcknowledgePowerChange ( void )
4615 {
4616 IORegistryEntry * nub;
4617 IOService * parent;
4618
4619 nub = fHeadNoteParentConnection;
4620 nub->retain();
4621 all_done();
4622 parent = (IOService *)nub->copyParentEntry(gIOPowerPlane);
4623 if ( parent )
4624 {
4625 parent->acknowledgePowerChange((IOService *)nub);
4626 parent->release();
4627 }
4628 nub->release();
4629 }
4630
4631 // MARK: -
4632 // MARK: Ack and Settle timers
4633
4634 //*********************************************************************************
4635 // [private] settleTimerExpired
4636 //
4637 // Power has settled after our last change. Notify interested parties that
4638 // there is a new power state.
4639 //*********************************************************************************
4640
4641 void IOService::settleTimerExpired( void )
4642 {
4643 fSettleTimeUS = 0;
4644 gIOPMWorkQueue->signalWorkAvailable();
4645 }
4646
4647 //*********************************************************************************
4648 // settle_timer_expired
4649 //
4650 // Holds a retain while the settle timer callout is in flight.
4651 //*********************************************************************************
4652
4653 static void
4654 settle_timer_expired( thread_call_param_t arg0, thread_call_param_t arg1 )
4655 {
4656 IOService * me = (IOService *) arg0;
4657
4658 if (gIOPMWorkLoop && gIOPMWorkQueue)
4659 {
4660 gIOPMWorkLoop->runAction(
4661 OSMemberFunctionCast(IOWorkLoop::Action, me, &IOService::settleTimerExpired),
4662 me);
4663 }
4664 me->release();
4665 }
4666
4667 //*********************************************************************************
4668 // [private] startSettleTimer
4669 //
4670 // Calculate a power-settling delay in microseconds and start a timer.
4671 //*********************************************************************************
4672
4673 void IOService::startSettleTimer( void )
4674 {
4675 AbsoluteTime deadline;
4676 IOPMPowerStateIndex i;
4677 uint32_t settleTime = 0;
4678 boolean_t pending;
4679
4680 PM_ASSERT_IN_GATE();
4681
4682 i = fCurrentPowerState;
4683
4684 // lowering power
4685 if ( fHeadNotePowerState < fCurrentPowerState )
4686 {
4687 while ( i > fHeadNotePowerState )
4688 {
4689 settleTime += (uint32_t) fPowerStates[i].settleDownTime;
4690 i--;
4691 }
4692 }
4693
4694 // raising power
4695 if ( fHeadNotePowerState > fCurrentPowerState )
4696 {
4697 while ( i < fHeadNotePowerState )
4698 {
4699 settleTime += (uint32_t) fPowerStates[i+1].settleUpTime;
4700 i++;
4701 }
4702 }
4703
4704 if (settleTime)
4705 {
4706 retain();
4707 clock_interval_to_deadline(settleTime, kMicrosecondScale, &deadline);
4708 pending = thread_call_enter_delayed(fSettleTimer, deadline);
4709 if (pending) release();
4710 }
4711 }
4712
4713 //*********************************************************************************
4714 // [private] ackTimerTick
4715 //
4716 // The acknowledgement timeout periodic timer has ticked.
4717 // If we are awaiting acks for a power change notification,
4718 // we decrement the timer word of each interested driver which hasn't acked.
4719 // If a timer word becomes zero, we pretend the driver aknowledged.
4720 // If we are waiting for the controlling driver to change the power
4721 // state of the hardware, we decrement its timer word, and if it becomes
4722 // zero, we pretend the driver acknowledged.
4723 //
4724 // Returns true if the timer tick made it possible to advance to the next
4725 // machine state, false otherwise.
4726 //*********************************************************************************
4727
4728 #ifndef __LP64__
4729 void IOService::ack_timer_ticked ( void )
4730 {
4731 assert(false);
4732 }
4733 #endif /* !__LP64__ */
4734
4735 bool IOService::ackTimerTick( void )
4736 {
4737 IOPMinformee * nextObject;
4738 bool done = false;
4739
4740 PM_ASSERT_IN_GATE();
4741 switch (fMachineState) {
4742 case kIOPM_OurChangeWaitForPowerSettle:
4743 case kIOPM_ParentChangeWaitForPowerSettle:
4744 // are we waiting for controlling driver to acknowledge?
4745 if ( fDriverTimer > 0 )
4746 {
4747 // yes, decrement timer tick
4748 fDriverTimer--;
4749 if ( fDriverTimer == 0 )
4750 {
4751 // controlling driver is tardy
4752 uint64_t nsec = computeTimeDeltaNS(&fDriverCallStartTime);
4753 OUR_PMLog(kPMLogCtrlDriverTardy, 0, 0);
4754 setProperty(kIOPMTardyAckSPSKey, kOSBooleanTrue);
4755 PM_ERROR("%s::setPowerState(%p, %lu -> %lu) timed out after %d ms\n",
4756 fName, this, fCurrentPowerState, fHeadNotePowerState, NS_TO_MS(nsec));
4757
4758 #if LOG_SETPOWER_TIMES
4759 PMEventDetails *details = PMEventDetails::eventDetails(
4760 kIOPMEventTypeSetPowerStateDelayed, // type
4761 fName, // who
4762 (uintptr_t)this, // owner unique
4763 NULL, // interest name
4764 (uint8_t)getPowerState(), // old
4765 0, // new
4766 kIOReturnTimeout, // result
4767 NS_TO_US(nsec)); // usec completion time
4768
4769 getPMRootDomain()->recordAndReleasePMEventGated( details );
4770 #endif
4771
4772 if (gIOKitDebug & kIOLogDebugPower)
4773 {
4774 panic("%s::setPowerState(%p, %lu -> %lu) timed out after %d ms",
4775 fName, this, fCurrentPowerState, fHeadNotePowerState, NS_TO_MS(nsec));
4776 }
4777 else
4778 {
4779 // Unblock state machine and pretend driver has acked.
4780 done = true;
4781 }
4782 } else {
4783 // still waiting, set timer again
4784 start_ack_timer();
4785 }
4786 }
4787 break;
4788
4789 case kIOPM_NotifyChildrenStart:
4790 // are we waiting for interested parties to acknowledge?
4791 if ( fHeadNotePendingAcks != 0 )
4792 {
4793 // yes, go through the list of interested drivers
4794 nextObject = fInterestedDrivers->firstInList();
4795 // and check each one
4796 while ( nextObject != NULL )
4797 {
4798 if ( nextObject->timer > 0 )
4799 {
4800 nextObject->timer--;
4801 // this one should have acked by now
4802 if ( nextObject->timer == 0 )
4803 {
4804 uint64_t nsec = computeTimeDeltaNS(&nextObject->startTime);
4805 OUR_PMLog(kPMLogIntDriverTardy, 0, 0);
4806 nextObject->whatObject->setProperty(kIOPMTardyAckPSCKey, kOSBooleanTrue);
4807 PM_ERROR("%s::powerState%sChangeTo(%p, %s, %lu -> %lu) timed out after %d ms\n",
4808 nextObject->whatObject->getName(),
4809 (fDriverCallReason == kDriverCallInformPreChange) ? "Will" : "Did",
4810 nextObject->whatObject, fName, fCurrentPowerState, fHeadNotePowerState,
4811 NS_TO_MS(nsec));
4812
4813 #if LOG_SETPOWER_TIMES
4814 uint16_t logType = (fDriverCallReason == kDriverCallInformPreChange)
4815 ? kIOPMEventTypePSWillChangeTo
4816 : kIOPMEventTypePSDidChangeTo;
4817
4818 PMEventDetails *details = PMEventDetails::eventDetails(
4819 logType, // type
4820 fName, // who
4821 (uintptr_t)this, // owner unique
4822 nextObject->whatObject->getName(), // interest name
4823 (uint8_t)fCurrentPowerState, // old
4824 (uint8_t)fHeadNotePowerState, // new
4825 kIOReturnTimeout, // result
4826 NS_TO_US(nsec)); // usec completion time
4827
4828 getPMRootDomain()->recordAndReleasePMEventGated( details );
4829 #endif
4830
4831 // Pretend driver has acked.
4832 fHeadNotePendingAcks--;
4833 }
4834 }
4835 nextObject = fInterestedDrivers->nextInList(nextObject);
4836 }
4837
4838 // is that the last?
4839 if ( fHeadNotePendingAcks == 0 )
4840 {
4841 // yes, we can continue
4842 done = true;
4843 } else {
4844 // no, set timer again
4845 start_ack_timer();
4846 }
4847 }
4848 break;
4849
4850 // TODO: aggreggate this
4851 case kIOPM_OurChangeTellClientsPowerDown:
4852 case kIOPM_OurChangeTellPriorityClientsPowerDown:
4853 case kIOPM_OurChangeNotifyInterestedDriversWillChange:
4854 case kIOPM_ParentChangeTellPriorityClientsPowerDown:
4855 case kIOPM_ParentChangeNotifyInterestedDriversWillChange:
4856 case kIOPM_SyncTellClientsPowerDown:
4857 case kIOPM_SyncTellPriorityClientsPowerDown:
4858 case kIOPM_SyncNotifyWillChange:
4859 case kIOPM_TellCapabilityChangeDone:
4860 // apps didn't respond in time
4861 cleanClientResponses(true);
4862 OUR_PMLog(kPMLogClientTardy, 0, 1);
4863 // tardy equates to approval
4864 done = true;
4865 break;
4866
4867 default:
4868 PM_LOG1("%s: unexpected ack timer tick (state = %d)\n",
4869 getName(), fMachineState);
4870 break;
4871 }
4872 return done;
4873 }
4874
4875 //*********************************************************************************
4876 // [private] start_ack_timer
4877 //*********************************************************************************
4878
4879 void IOService::start_ack_timer ( void )
4880 {
4881 start_ack_timer( ACK_TIMER_PERIOD, kNanosecondScale );
4882 }
4883
4884 void IOService::start_ack_timer ( UInt32 interval, UInt32 scale )
4885 {
4886 AbsoluteTime deadline;
4887 boolean_t pending;
4888
4889 clock_interval_to_deadline(interval, scale, &deadline);
4890
4891 retain();
4892 pending = thread_call_enter_delayed(fAckTimer, deadline);
4893 if (pending) release();
4894 }
4895
4896 //*********************************************************************************
4897 // [private] stop_ack_timer
4898 //*********************************************************************************
4899
4900 void IOService::stop_ack_timer ( void )
4901 {
4902 boolean_t pending;
4903
4904 pending = thread_call_cancel(fAckTimer);
4905 if (pending) release();
4906 }
4907
4908 //*********************************************************************************
4909 // [static] actionAckTimerExpired
4910 //
4911 // Inside PM work loop's gate.
4912 //*********************************************************************************
4913
4914 IOReturn
4915 IOService::actionAckTimerExpired (
4916 OSObject * target,
4917 void * arg0, void * arg1,
4918 void * arg2, void * arg3 )
4919 {
4920 IOService * me = (IOService *) target;
4921 bool done;
4922
4923 // done will be true if the timer tick unblocks the machine state,
4924 // otherwise no need to signal the work loop.
4925
4926 done = me->ackTimerTick();
4927 if (done && gIOPMWorkQueue)
4928 gIOPMWorkQueue->signalWorkAvailable();
4929
4930 return kIOReturnSuccess;
4931 }
4932
4933 //*********************************************************************************
4934 // ack_timer_expired
4935 //
4936 // Thread call function. Holds a retain while the callout is in flight.
4937 //*********************************************************************************
4938
4939 void
4940 IOService::ack_timer_expired ( thread_call_param_t arg0, thread_call_param_t arg1 )
4941 {
4942 IOService * me = (IOService *) arg0;
4943
4944 if (gIOPMWorkLoop)
4945 {
4946 gIOPMWorkLoop->runAction(&actionAckTimerExpired, me);
4947 }
4948 me->release();
4949 }
4950
4951 // MARK: -
4952 // MARK: Client Messaging
4953
4954 //*********************************************************************************
4955 // [private] tellSystemCapabilityChange
4956 //*********************************************************************************
4957
4958 void IOService::tellSystemCapabilityChange( uint32_t nextMS )
4959 {
4960 MS_PUSH( nextMS );
4961 fMachineState = kIOPM_TellCapabilityChangeDone;
4962 fOutOfBandMessage = kIOMessageSystemCapabilityChange;
4963
4964 if (fIsPreChange)
4965 {
4966 // Notify app first on pre-change.
4967 fOutOfBandParameter = kNotifyCapabilityChangeApps;
4968 }
4969 else
4970 {
4971 // Notify kernel clients first on post-change.
4972 fOutOfBandParameter = kNotifyCapabilityChangePriority;
4973 }
4974
4975 tellClientsWithResponse( fOutOfBandMessage );
4976 }
4977
4978 //*********************************************************************************
4979 // [public] askChangeDown
4980 //
4981 // Ask registered applications and kernel clients if we can change to a lower
4982 // power state.
4983 //
4984 // Subclass can override this to send a different message type. Parameter is
4985 // the destination state number.
4986 //
4987 // Return true if we don't have to wait for acknowledgements
4988 //*********************************************************************************
4989
4990 bool IOService::askChangeDown ( unsigned long stateNum )
4991 {
4992 return tellClientsWithResponse( kIOMessageCanDevicePowerOff );
4993 }
4994
4995 //*********************************************************************************
4996 // [private] tellChangeDown1
4997 //
4998 // Notify registered applications and kernel clients that we are definitely
4999 // dropping power.
5000 //
5001 // Return true if we don't have to wait for acknowledgements
5002 //*********************************************************************************
5003
5004 bool IOService::tellChangeDown1 ( unsigned long stateNum )
5005 {
5006 fOutOfBandParameter = kNotifyApps;
5007 return tellChangeDown(stateNum);
5008 }
5009
5010 //*********************************************************************************
5011 // [private] tellChangeDown2
5012 //
5013 // Notify priority clients that we are definitely dropping power.
5014 //
5015 // Return true if we don't have to wait for acknowledgements
5016 //*********************************************************************************
5017
5018 bool IOService::tellChangeDown2 ( unsigned long stateNum )
5019 {
5020 fOutOfBandParameter = kNotifyPriority;
5021 return tellChangeDown(stateNum);
5022 }
5023
5024 //*********************************************************************************
5025 // [public] tellChangeDown
5026 //
5027 // Notify registered applications and kernel clients that we are definitely
5028 // dropping power.
5029 //
5030 // Subclass can override this to send a different message type. Parameter is
5031 // the destination state number.
5032 //
5033 // Return true if we don't have to wait for acknowledgements
5034 //*********************************************************************************
5035
5036 bool IOService::tellChangeDown ( unsigned long stateNum )
5037 {
5038 return tellClientsWithResponse( kIOMessageDeviceWillPowerOff );
5039 }
5040
5041 //*********************************************************************************
5042 // cleanClientResponses
5043 //
5044 //*********************************************************************************
5045
5046 static void logAppTimeouts ( OSObject * object, void * arg )
5047 {
5048 IOPMInterestContext * context = (IOPMInterestContext *) arg;
5049 OSObject * flag;
5050 unsigned int clientIndex;
5051
5052 if (OSDynamicCast(_IOServiceInterestNotifier, object))
5053 {
5054 // Discover the 'counter' value or index assigned to this client
5055 // when it was notified, by searching for the array index of the
5056 // client in an array holding the cached interested clients.
5057
5058 clientIndex = context->notifyClients->getNextIndexOfObject(object, 0);
5059
5060 if ((clientIndex != (unsigned int) -1) &&
5061 (flag = context->responseArray->getObject(clientIndex)) &&
5062 (flag != kOSBooleanTrue))
5063 {
5064 OSString *logClientID = NULL;
5065 OSNumber *clientID = copyClientIDForNotification(object, context);
5066
5067 if (clientID) {
5068 logClientID = IOCopyLogNameForPID(clientID->unsigned32BitValue());
5069 clientID->release();
5070 }
5071
5072 PM_ERROR(context->errorLog, logClientID ? logClientID->getCStringNoCopy() : "");
5073
5074 // TODO: record message type if possible
5075 IOService::getPMRootDomain()->pmStatsRecordApplicationResponse(
5076 gIOPMStatsApplicationResponseTimedOut,
5077 logClientID ? logClientID->getCStringNoCopy() : "",
5078 0, (30*1000), -1);
5079
5080 if (logClientID)
5081 logClientID->release();
5082 }
5083 }
5084 }
5085
5086 void IOService::cleanClientResponses ( bool logErrors )
5087 {
5088 if (logErrors && fResponseArray)
5089 {
5090 switch ( fOutOfBandParameter ) {
5091 case kNotifyApps:
5092 case kNotifyCapabilityChangeApps:
5093 if (fNotifyClientArray)
5094 {
5095 IOPMInterestContext context;
5096
5097 context.responseArray = fResponseArray;
5098 context.notifyClients = fNotifyClientArray;
5099 context.serialNumber = fSerialNumber;
5100 context.messageType = kIOMessageCopyClientID;
5101 context.notifyType = kNotifyApps;
5102 context.isPreChange = fIsPreChange;
5103 context.enableTracing = false;
5104 context.us = this;
5105 context.maxTimeRequested = 0;
5106 context.stateNumber = fHeadNotePowerState;
5107 context.stateFlags = fHeadNotePowerArrayEntry->capabilityFlags;
5108 context.changeFlags = fHeadNoteChangeFlags;
5109 context.errorLog = "PM notification timeout (%s)\n";
5110
5111 applyToInterested(gIOAppPowerStateInterest, logAppTimeouts, (void *) &context);
5112 }
5113 break;
5114
5115 default:
5116 // kNotifyPriority, kNotifyCapabilityChangePriority
5117 // TODO: identify the priority client that has not acked
5118 PM_ERROR("PM priority notification timeout\n");
5119 if (gIOKitDebug & kIOLogDebugPower)
5120 {
5121 panic("PM priority notification timeout");
5122 }
5123 break;
5124 }
5125 }
5126
5127 if (fResponseArray)
5128 {
5129 fResponseArray->release();
5130 fResponseArray = NULL;
5131 }
5132 if (fNotifyClientArray)
5133 {
5134 fNotifyClientArray->release();
5135 fNotifyClientArray = NULL;
5136 }
5137 }
5138
5139 //*********************************************************************************
5140 // [protected] tellClientsWithResponse
5141 //
5142 // Notify registered applications and kernel clients that we are definitely
5143 // dropping power.
5144 //
5145 // Return true if we don't have to wait for acknowledgements
5146 //*********************************************************************************
5147
5148 bool IOService::tellClientsWithResponse ( int messageType )
5149 {
5150 IOPMInterestContext context;
5151 bool isRootDomain = IS_ROOT_DOMAIN;
5152
5153 PM_ASSERT_IN_GATE();
5154 assert( fResponseArray == NULL );
5155 assert( fNotifyClientArray == NULL );
5156
5157 RD_LOG("tellClientsWithResponse( %s, %d )\n",
5158 getIOMessageString(messageType), fOutOfBandParameter);
5159
5160 fResponseArray = OSArray::withCapacity( 1 );
5161 if (!fResponseArray)
5162 goto exit;
5163
5164 fResponseArray->setCapacityIncrement(8);
5165 if (++fSerialNumber == 0)
5166 fSerialNumber++;
5167
5168 context.responseArray = fResponseArray;
5169 context.notifyClients = 0;
5170 context.serialNumber = fSerialNumber;
5171 context.messageType = messageType;
5172 context.notifyType = fOutOfBandParameter;
5173 context.isPreChange = fIsPreChange;
5174 context.enableTracing = false;
5175 context.us = this;
5176 context.maxTimeRequested = 0;
5177 context.stateNumber = fHeadNotePowerState;
5178 context.stateFlags = fHeadNotePowerArrayEntry->capabilityFlags;
5179 context.changeFlags = fHeadNoteChangeFlags;
5180 context.messageFilter = (isRootDomain) ?
5181 OSMemberFunctionCast(
5182 IOPMMessageFilter,
5183 this,
5184 &IOPMrootDomain::systemMessageFilter) : 0;
5185
5186 switch ( fOutOfBandParameter ) {
5187 case kNotifyApps:
5188 applyToInterested( gIOAppPowerStateInterest,
5189 pmTellAppWithResponse, (void *) &context );
5190
5191 if (isRootDomain &&
5192 (fMachineState != kIOPM_OurChangeTellClientsPowerDown) &&
5193 (fMachineState != kIOPM_SyncTellClientsPowerDown))
5194 {
5195 // Notify capability app for tellChangeDown1()
5196 // but not for askChangeDown().
5197 context.notifyType = kNotifyCapabilityChangeApps;
5198 context.messageType = kIOMessageSystemCapabilityChange;
5199 applyToInterested( gIOAppPowerStateInterest,
5200 pmTellCapabilityAppWithResponse, (void *) &context );
5201 context.notifyType = fOutOfBandParameter;
5202 context.messageType = messageType;
5203 }
5204 context.maxTimeRequested = k30Seconds;
5205
5206 applyToInterested( gIOGeneralInterest,
5207 pmTellClientWithResponse, (void *) &context );
5208
5209 fNotifyClientArray = context.notifyClients;
5210 break;
5211
5212 case kNotifyPriority:
5213 context.enableTracing = isRootDomain;
5214 applyToInterested( gIOPriorityPowerStateInterest,
5215 pmTellClientWithResponse, (void *) &context );
5216
5217 if (isRootDomain)
5218 {
5219 // Notify capability clients for tellChangeDown2().
5220 context.notifyType = kNotifyCapabilityChangePriority;
5221 context.messageType = kIOMessageSystemCapabilityChange;
5222 applyToInterested( gIOPriorityPowerStateInterest,
5223 pmTellCapabilityClientWithResponse, (void *) &context );
5224 }
5225 break;
5226
5227 case kNotifyCapabilityChangeApps:
5228 applyToInterested( gIOAppPowerStateInterest,
5229 pmTellCapabilityAppWithResponse, (void *) &context );
5230 fNotifyClientArray = context.notifyClients;
5231 context.maxTimeRequested = k30Seconds;
5232 break;
5233
5234 case kNotifyCapabilityChangePriority:
5235 applyToInterested( gIOPriorityPowerStateInterest,
5236 pmTellCapabilityClientWithResponse, (void *) &context );
5237 break;
5238 }
5239
5240 // do we have to wait for somebody?
5241 if ( !checkForDone() )
5242 {
5243 OUR_PMLog(kPMLogStartAckTimer, context.maxTimeRequested, 0);
5244 if (context.enableTracing)
5245 getPMRootDomain()->traceDetail( context.maxTimeRequested / 1000 );
5246 start_ack_timer( context.maxTimeRequested / 1000, kMillisecondScale );
5247 return false;
5248 }
5249
5250 exit:
5251 // everybody responded
5252 if (fResponseArray)
5253 {
5254 fResponseArray->release();
5255 fResponseArray = NULL;
5256 }
5257 if (fNotifyClientArray)
5258 {
5259 fNotifyClientArray->release();
5260 fNotifyClientArray = NULL;
5261 }
5262
5263 return true;
5264 }
5265
5266 //*********************************************************************************
5267 // [static private] pmTellAppWithResponse
5268 //
5269 // We send a message to an application, and we expect a response, so we compute a
5270 // cookie we can identify the response with.
5271 //*********************************************************************************
5272
5273 void IOService::pmTellAppWithResponse ( OSObject * object, void * arg )
5274 {
5275 IOPMInterestContext * context = (IOPMInterestContext *) arg;
5276 IOServicePM * pwrMgt = context->us->pwrMgt;
5277 uint32_t msgIndex, msgRef, msgType;
5278 OSNumber *clientID = NULL;
5279 proc_t proc = NULL;
5280 boolean_t proc_suspended = FALSE;
5281 #if LOG_APP_RESPONSE_TIMES
5282 AbsoluteTime now;
5283 #endif
5284
5285 if (!OSDynamicCast(_IOServiceInterestNotifier, object))
5286 return;
5287
5288 if (context->us == getPMRootDomain())
5289 {
5290 if ((clientID = copyClientIDForNotification(object, context)))
5291 {
5292 uint32_t clientPID = clientID->unsigned32BitValue();
5293 clientID->release();
5294 proc = proc_find(clientPID);
5295
5296 if (proc)
5297 {
5298 proc_suspended = get_task_pidsuspended((task_t) proc->task);
5299 proc_rele(proc);
5300
5301 if (proc_suspended)
5302 {
5303 logClientIDForNotification(object, context, "PMTellAppWithResponse - Suspended");
5304 return;
5305 }
5306 }
5307 }
5308 }
5309
5310 if (context->messageFilter &&
5311 !context->messageFilter(context->us, object, context, 0, 0))
5312 {
5313 if (kIOLogDebugPower & gIOKitDebug)
5314 {
5315 logClientIDForNotification(object, context, "DROP App");
5316 }
5317 return;
5318 }
5319
5320 // Create client array (for tracking purposes) only if the service
5321 // has app clients. Usually only root domain does.
5322 if (0 == context->notifyClients)
5323 context->notifyClients = OSArray::withCapacity( 32 );
5324
5325 msgType = context->messageType;
5326 msgIndex = context->responseArray->getCount();
5327 msgRef = ((context->serialNumber & 0xFFFF) << 16) + (msgIndex & 0xFFFF);
5328
5329 OUR_PMLog(kPMLogAppNotify, msgType, msgRef);
5330 if (kIOLogDebugPower & gIOKitDebug)
5331 {
5332 logClientIDForNotification(object, context, "MESG App");
5333 }
5334
5335 #if LOG_APP_RESPONSE_TIMES
5336 OSNumber * num;
5337 clock_get_uptime(&now);
5338 num = OSNumber::withNumber(AbsoluteTime_to_scalar(&now), sizeof(uint64_t) * 8);
5339 if (num)
5340 {
5341 context->responseArray->setObject(msgIndex, num);
5342 num->release();
5343 }
5344 else
5345 #endif
5346 context->responseArray->setObject(msgIndex, kOSBooleanFalse);
5347
5348 if (context->notifyClients)
5349 context->notifyClients->setObject(msgIndex, object);
5350
5351 context->us->messageClient(msgType, object, (void *) msgRef);
5352 }
5353
5354 //*********************************************************************************
5355 // [static private] pmTellClientWithResponse
5356 //
5357 // We send a message to an in-kernel client, and we expect a response,
5358 // so we compute a cookie we can identify the response with.
5359 //*********************************************************************************
5360
5361 void IOService::pmTellClientWithResponse ( OSObject * object, void * arg )
5362 {
5363 IOPowerStateChangeNotification notify;
5364 IOPMInterestContext * context = (IOPMInterestContext *) arg;
5365 OSObject * replied = kOSBooleanTrue;
5366 _IOServiceInterestNotifier * notifier;
5367 uint32_t msgIndex, msgRef, msgType;
5368 IOReturn retCode;
5369
5370 if (context->messageFilter &&
5371 !context->messageFilter(context->us, object, context, 0, 0))
5372 {
5373 if ((kIOLogDebugPower & gIOKitDebug) &&
5374 (OSDynamicCast(_IOServiceInterestNotifier, object)))
5375 {
5376 _IOServiceInterestNotifier *n = (_IOServiceInterestNotifier *) object;
5377 PM_LOG("%s DROP Client %s, notifier %p, handler %p\n",
5378 context->us->getName(),
5379 getIOMessageString(context->messageType),
5380 object, n->handler);
5381 }
5382 return;
5383 }
5384
5385 notifier = OSDynamicCast(_IOServiceInterestNotifier, object);
5386 msgType = context->messageType;
5387 msgIndex = context->responseArray->getCount();
5388 msgRef = ((context->serialNumber & 0xFFFF) << 16) + (msgIndex & 0xFFFF);
5389
5390 IOServicePM * pwrMgt = context->us->pwrMgt;
5391 if (gIOKitDebug & kIOLogPower) {
5392 OUR_PMLog(kPMLogClientNotify, msgRef, msgType);
5393 if (OSDynamicCast(IOService, object)) {
5394 const char *who = ((IOService *) object)->getName();
5395 gPlatform->PMLog(who, kPMLogClientNotify, (uintptr_t) object, 0);
5396 }
5397 else if (notifier) {
5398 OUR_PMLog(kPMLogClientNotify, (uintptr_t) notifier->handler, 0);
5399 }
5400 }
5401 if ((kIOLogDebugPower & gIOKitDebug) && notifier)
5402 {
5403 PM_LOG("%s MESG Client %s, notifier %p, handler %p\n",
5404 context->us->getName(),
5405 getIOMessageString(msgType),
5406 object, notifier->handler);
5407 }
5408
5409 notify.powerRef = (void *)(uintptr_t) msgRef;
5410 notify.returnValue = 0;
5411 notify.stateNumber = context->stateNumber;
5412 notify.stateFlags = context->stateFlags;
5413
5414 if (context->enableTracing && (notifier != 0))
5415 {
5416 uint32_t detail = ((msgIndex & 0xff) << 24) |
5417 ((msgType & 0xfff) << 12) |
5418 (((uintptr_t) notifier->handler) & 0xfff);
5419 getPMRootDomain()->traceDetail( detail );
5420 }
5421
5422 retCode = context->us->messageClient(msgType, object, (void *) &notify, sizeof(notify));
5423
5424 if (kIOReturnSuccess == retCode)
5425 {
5426 if (0 == notify.returnValue) {
5427 OUR_PMLog(kPMLogClientAcknowledge, msgRef, (uintptr_t) object);
5428 } else {
5429 replied = kOSBooleanFalse;
5430 if ( notify.returnValue > context->maxTimeRequested )
5431 {
5432 if (notify.returnValue > kPriorityClientMaxWait)
5433 {
5434 context->maxTimeRequested = kPriorityClientMaxWait;
5435 PM_ERROR("%s: client %p returned %llu for %s\n",
5436 context->us->getName(),
5437 notifier ? (void *) notifier->handler : object,
5438 (uint64_t) notify.returnValue,
5439 getIOMessageString(msgType));
5440 }
5441 else
5442 context->maxTimeRequested = notify.returnValue;
5443 }
5444 }
5445 } else {
5446 // not a client of ours
5447 // so we won't be waiting for response
5448 OUR_PMLog(kPMLogClientAcknowledge, msgRef, 0);
5449 }
5450
5451 context->responseArray->setObject(msgIndex, replied);
5452 }
5453
5454 //*********************************************************************************
5455 // [static private] pmTellCapabilityAppWithResponse
5456 //*********************************************************************************
5457
5458 void IOService::pmTellCapabilityAppWithResponse ( OSObject * object, void * arg )
5459 {
5460 IOPMSystemCapabilityChangeParameters msgArg;
5461 IOPMInterestContext * context = (IOPMInterestContext *) arg;
5462 OSObject * replied = kOSBooleanTrue;
5463 IOServicePM * pwrMgt = context->us->pwrMgt;
5464 uint32_t msgIndex, msgRef, msgType;
5465 #if LOG_APP_RESPONSE_TIMES
5466 AbsoluteTime now;
5467 #endif
5468
5469 if (!OSDynamicCast(_IOServiceInterestNotifier, object))
5470 return;
5471
5472 memset(&msgArg, 0, sizeof(msgArg));
5473 if (context->messageFilter &&
5474 !context->messageFilter(context->us, object, context, &msgArg, &replied))
5475 {
5476 return;
5477 }
5478
5479 // Create client array (for tracking purposes) only if the service
5480 // has app clients. Usually only root domain does.
5481 if (0 == context->notifyClients)
5482 context->notifyClients = OSArray::withCapacity( 32 );
5483
5484 msgType = context->messageType;
5485 msgIndex = context->responseArray->getCount();
5486 msgRef = ((context->serialNumber & 0xFFFF) << 16) + (msgIndex & 0xFFFF);
5487
5488 OUR_PMLog(kPMLogAppNotify, msgType, msgRef);
5489 if (kIOLogDebugPower & gIOKitDebug)
5490 {
5491 // Log client pid/name and client array index.
5492 OSNumber * clientID = NULL;
5493 OSString * clientIDString = NULL;;
5494 context->us->messageClient(kIOMessageCopyClientID, object, &clientID);
5495 if (clientID) {
5496 clientIDString = IOCopyLogNameForPID(clientID->unsigned32BitValue());
5497 }
5498
5499 PM_LOG("%s MESG App(%u) %s, wait %u, %s\n",
5500 context->us->getName(),
5501 msgIndex, getIOMessageString(msgType),
5502 (replied != kOSBooleanTrue),
5503 clientIDString ? clientIDString->getCStringNoCopy() : "");
5504 if (clientID) clientID->release();
5505 if (clientIDString) clientIDString->release();
5506 }
5507
5508 msgArg.notifyRef = msgRef;
5509 msgArg.maxWaitForReply = 0;
5510
5511 if (replied == kOSBooleanTrue)
5512 {
5513 msgArg.notifyRef = 0;
5514 context->responseArray->setObject(msgIndex, kOSBooleanTrue);
5515 if (context->notifyClients)
5516 context->notifyClients->setObject(msgIndex, kOSBooleanTrue);
5517 }
5518 else
5519 {
5520 #if LOG_APP_RESPONSE_TIMES
5521 OSNumber * num;
5522 clock_get_uptime(&now);
5523 num = OSNumber::withNumber(AbsoluteTime_to_scalar(&now), sizeof(uint64_t) * 8);
5524 if (num)
5525 {
5526 context->responseArray->setObject(msgIndex, num);
5527 num->release();
5528 }
5529 else
5530 #endif
5531 context->responseArray->setObject(msgIndex, kOSBooleanFalse);
5532
5533 if (context->notifyClients)
5534 context->notifyClients->setObject(msgIndex, object);
5535 }
5536
5537 context->us->messageClient(msgType, object, (void *) &msgArg, sizeof(msgArg));
5538 }
5539
5540 //*********************************************************************************
5541 // [static private] pmTellCapabilityClientWithResponse
5542 //*********************************************************************************
5543
5544 void IOService::pmTellCapabilityClientWithResponse(
5545 OSObject * object, void * arg )
5546 {
5547 IOPMSystemCapabilityChangeParameters msgArg;
5548 IOPMInterestContext * context = (IOPMInterestContext *) arg;
5549 OSObject * replied = kOSBooleanTrue;
5550 _IOServiceInterestNotifier * notifier;
5551 uint32_t msgIndex, msgRef, msgType;
5552 IOReturn retCode;
5553
5554 memset(&msgArg, 0, sizeof(msgArg));
5555 if (context->messageFilter &&
5556 !context->messageFilter(context->us, object, context, &msgArg, 0))
5557 {
5558 if ((kIOLogDebugPower & gIOKitDebug) &&
5559 (OSDynamicCast(_IOServiceInterestNotifier, object)))
5560 {
5561 _IOServiceInterestNotifier *n = (_IOServiceInterestNotifier *) object;
5562 PM_LOG("%s DROP Client %s, notifier %p, handler %p\n",
5563 context->us->getName(),
5564 getIOMessageString(context->messageType),
5565 object, n->handler);
5566 }
5567 return;
5568 }
5569
5570 notifier = OSDynamicCast(_IOServiceInterestNotifier, object);
5571 msgType = context->messageType;
5572 msgIndex = context->responseArray->getCount();
5573 msgRef = ((context->serialNumber & 0xFFFF) << 16) + (msgIndex & 0xFFFF);
5574
5575 IOServicePM * pwrMgt = context->us->pwrMgt;
5576 if (gIOKitDebug & kIOLogPower) {
5577 OUR_PMLog(kPMLogClientNotify, msgRef, msgType);
5578 if (OSDynamicCast(IOService, object)) {
5579 const char *who = ((IOService *) object)->getName();
5580 gPlatform->PMLog(who, kPMLogClientNotify, (uintptr_t) object, 0);
5581 }
5582 else if (notifier) {
5583 OUR_PMLog(kPMLogClientNotify, (uintptr_t) notifier->handler, 0);
5584 }
5585 }
5586 if ((kIOLogDebugPower & gIOKitDebug) && notifier)
5587 {
5588 PM_LOG("%s MESG Client %s, notifier %p, handler %p\n",
5589 context->us->getName(),
5590 getIOMessageString(msgType),
5591 object, notifier->handler);
5592 }
5593
5594 msgArg.notifyRef = msgRef;
5595 msgArg.maxWaitForReply = 0;
5596
5597 if (context->enableTracing && (notifier != 0))
5598 {
5599 uint32_t detail = ((msgIndex & 0xff) << 24) |
5600 ((msgType & 0xfff) << 12) |
5601 (((uintptr_t) notifier->handler) & 0xfff);
5602 getPMRootDomain()->traceDetail( detail );
5603 }
5604
5605 retCode = context->us->messageClient(
5606 msgType, object, (void *) &msgArg, sizeof(msgArg));
5607
5608 if ( kIOReturnSuccess == retCode )
5609 {
5610 if ( 0 == msgArg.maxWaitForReply )
5611 {
5612 // client doesn't want time to respond
5613 OUR_PMLog(kPMLogClientAcknowledge, msgRef, (uintptr_t) object);
5614 }
5615 else
5616 {
5617 replied = kOSBooleanFalse;
5618 if ( msgArg.maxWaitForReply > context->maxTimeRequested )
5619 {
5620 if (msgArg.maxWaitForReply > kCapabilityClientMaxWait)
5621 {
5622 context->maxTimeRequested = kCapabilityClientMaxWait;
5623 PM_ERROR("%s: client %p returned %u for %s\n",
5624 context->us->getName(),
5625 notifier ? (void *) notifier->handler : object,
5626 msgArg.maxWaitForReply,
5627 getIOMessageString(msgType));
5628 }
5629 else
5630 context->maxTimeRequested = msgArg.maxWaitForReply;
5631 }
5632 }
5633 }
5634 else
5635 {
5636 // not a client of ours
5637 // so we won't be waiting for response
5638 OUR_PMLog(kPMLogClientAcknowledge, msgRef, 0);
5639 }
5640
5641 context->responseArray->setObject(msgIndex, replied);
5642 }
5643
5644 //*********************************************************************************
5645 // [public] tellNoChangeDown
5646 //
5647 // Notify registered applications and kernel clients that we are not
5648 // dropping power.
5649 //
5650 // Subclass can override this to send a different message type. Parameter is
5651 // the aborted destination state number.
5652 //*********************************************************************************
5653
5654 void IOService::tellNoChangeDown ( unsigned long )
5655 {
5656 return tellClients( kIOMessageDeviceWillNotPowerOff );
5657 }
5658
5659 //*********************************************************************************
5660 // [public] tellChangeUp
5661 //
5662 // Notify registered applications and kernel clients that we are raising power.
5663 //
5664 // Subclass can override this to send a different message type. Parameter is
5665 // the aborted destination state number.
5666 //*********************************************************************************
5667
5668 void IOService::tellChangeUp ( unsigned long )
5669 {
5670 return tellClients( kIOMessageDeviceHasPoweredOn );
5671 }
5672
5673 //*********************************************************************************
5674 // [protected] tellClients
5675 //
5676 // Notify registered applications and kernel clients of something.
5677 //*********************************************************************************
5678
5679 void IOService::tellClients ( int messageType )
5680 {
5681 IOPMInterestContext context;
5682
5683 RD_LOG("tellClients( %s )\n", getIOMessageString(messageType));
5684
5685 memset(&context, 0, sizeof(context));
5686 context.messageType = messageType;
5687 context.isPreChange = fIsPreChange;
5688 context.us = this;
5689 context.stateNumber = fHeadNotePowerState;
5690 context.stateFlags = fHeadNotePowerArrayEntry->capabilityFlags;
5691 context.changeFlags = fHeadNoteChangeFlags;
5692 context.messageFilter = (IS_ROOT_DOMAIN) ?
5693 OSMemberFunctionCast(
5694 IOPMMessageFilter,
5695 this,
5696 &IOPMrootDomain::systemMessageFilter) : 0;
5697
5698 context.notifyType = kNotifyPriority;
5699 applyToInterested( gIOPriorityPowerStateInterest,
5700 tellKernelClientApplier, (void *) &context );
5701
5702 context.notifyType = kNotifyApps;
5703 applyToInterested( gIOAppPowerStateInterest,
5704 tellAppClientApplier, (void *) &context );
5705
5706 applyToInterested( gIOGeneralInterest,
5707 tellKernelClientApplier, (void *) &context );
5708 }
5709
5710 //*********************************************************************************
5711 // [private] tellKernelClientApplier
5712 //
5713 // Message a kernel client.
5714 //*********************************************************************************
5715
5716 static void tellKernelClientApplier ( OSObject * object, void * arg )
5717 {
5718 IOPowerStateChangeNotification notify;
5719 IOPMInterestContext * context = (IOPMInterestContext *) arg;
5720
5721 if (context->messageFilter &&
5722 !context->messageFilter(context->us, object, context, 0, 0))
5723 {
5724 if ((kIOLogDebugPower & gIOKitDebug) &&
5725 (OSDynamicCast(_IOServiceInterestNotifier, object)))
5726 {
5727 _IOServiceInterestNotifier *n = (_IOServiceInterestNotifier *) object;
5728 PM_LOG("%s DROP Client %s, notifier %p, handler %p\n",
5729 context->us->getName(),
5730 IOService::getIOMessageString(context->messageType),
5731 object, n->handler);
5732 }
5733 return;
5734 }
5735
5736 notify.powerRef = (void *) 0;
5737 notify.returnValue = 0;
5738 notify.stateNumber = context->stateNumber;
5739 notify.stateFlags = context->stateFlags;
5740
5741 context->us->messageClient(context->messageType, object, &notify, sizeof(notify));
5742
5743 if ((kIOLogDebugPower & gIOKitDebug) &&
5744 (OSDynamicCast(_IOServiceInterestNotifier, object)))
5745 {
5746 _IOServiceInterestNotifier *n = (_IOServiceInterestNotifier *) object;
5747 PM_LOG("%s MESG Client %s, notifier %p, handler %p\n",
5748 context->us->getName(),
5749 IOService::getIOMessageString(context->messageType),
5750 object, n->handler);
5751 }
5752 }
5753
5754 static OSNumber * copyClientIDForNotification(
5755 OSObject *object,
5756 IOPMInterestContext *context)
5757 {
5758 OSNumber *clientID = NULL;
5759 context->us->messageClient(kIOMessageCopyClientID, object, &clientID);
5760 return clientID;
5761 }
5762
5763 static void logClientIDForNotification(
5764 OSObject *object,
5765 IOPMInterestContext *context,
5766 const char *logString)
5767 {
5768 OSString *logClientID = NULL;
5769 OSNumber *clientID = copyClientIDForNotification(object, context);
5770
5771 if (logString)
5772 {
5773 if (clientID)
5774 logClientID = IOCopyLogNameForPID(clientID->unsigned32BitValue());
5775
5776 PM_LOG("%s %s %s, %s\n",
5777 context->us->getName(), logString,
5778 IOService::getIOMessageString(context->messageType),
5779 logClientID ? logClientID->getCStringNoCopy() : "");
5780
5781 if (logClientID)
5782 logClientID->release();
5783 }
5784
5785 if (clientID)
5786 clientID->release();
5787
5788 return;
5789 }
5790
5791
5792 static void tellAppClientApplier ( OSObject * object, void * arg )
5793 {
5794 IOPMInterestContext * context = (IOPMInterestContext *) arg;
5795 OSNumber * clientID = NULL;
5796 proc_t proc = NULL;
5797 boolean_t proc_suspended = FALSE;
5798
5799 if (context->us == IOService::getPMRootDomain())
5800 {
5801 if ((clientID = copyClientIDForNotification(object, context)))
5802 {
5803 uint32_t clientPID = clientID->unsigned32BitValue();
5804 clientID->release();
5805 proc = proc_find(clientPID);
5806
5807 if (proc)
5808 {
5809 proc_suspended = get_task_pidsuspended((task_t) proc->task);
5810 proc_rele(proc);
5811
5812 if (proc_suspended)
5813 {
5814 logClientIDForNotification(object, context, "tellAppClientApplier - Suspended");
5815 return;
5816 }
5817 }
5818 }
5819 }
5820
5821 if (context->messageFilter &&
5822 !context->messageFilter(context->us, object, context, 0, 0))
5823 {
5824 if (kIOLogDebugPower & gIOKitDebug)
5825 {
5826 logClientIDForNotification(object, context, "DROP App");
5827 }
5828 return;
5829 }
5830
5831 if (kIOLogDebugPower & gIOKitDebug)
5832 {
5833 logClientIDForNotification(object, context, "MESG App");
5834 }
5835
5836 context->us->messageClient(context->messageType, object, 0);
5837 }
5838
5839 //*********************************************************************************
5840 // [private] checkForDone
5841 //*********************************************************************************
5842
5843 bool IOService::checkForDone ( void )
5844 {
5845 int i = 0;
5846 OSObject * theFlag;
5847
5848 if (fResponseArray == NULL) {
5849 return true;
5850 }
5851
5852 for (i = 0; ; i++) {
5853 theFlag = fResponseArray->getObject(i);
5854
5855 if (NULL == theFlag) {
5856 break;
5857 }
5858
5859 if (kOSBooleanTrue != theFlag) {
5860 return false;
5861 }
5862 }
5863 return true;
5864 }
5865
5866 //*********************************************************************************
5867 // [public] responseValid
5868 //*********************************************************************************
5869
5870 bool IOService::responseValid ( uint32_t refcon, int pid )
5871 {
5872 UInt16 serialComponent;
5873 UInt16 ordinalComponent;
5874 OSObject * theFlag;
5875
5876 serialComponent = (refcon >> 16) & 0xFFFF;
5877 ordinalComponent = (refcon & 0xFFFF);
5878
5879 if ( serialComponent != fSerialNumber )
5880 {
5881 return false;
5882 }
5883
5884 if ( fResponseArray == NULL )
5885 {
5886 return false;
5887 }
5888
5889 theFlag = fResponseArray->getObject(ordinalComponent);
5890
5891 if ( theFlag == 0 )
5892 {
5893 return false;
5894 }
5895
5896 OSNumber * num;
5897 if ((num = OSDynamicCast(OSNumber, theFlag)))
5898 {
5899 #if LOG_APP_RESPONSE_TIMES
5900 AbsoluteTime now;
5901 AbsoluteTime start;
5902 uint64_t nsec;
5903 OSString *name = IOCopyLogNameForPID(pid);
5904
5905 clock_get_uptime(&now);
5906 AbsoluteTime_to_scalar(&start) = num->unsigned64BitValue();
5907 SUB_ABSOLUTETIME(&now, &start);
5908 absolutetime_to_nanoseconds(now, &nsec);
5909
5910 PMEventDetails *details = PMEventDetails::eventDetails(
5911 kIOPMEventTypeAppResponse, // type
5912 name ? name->getCStringNoCopy() : "", // who
5913 (uintptr_t)pid, // owner unique
5914 NULL, // interest name
5915 0, // old
5916 0, // new
5917 0, // result
5918 NS_TO_US(nsec)); // usec completion time
5919
5920 getPMRootDomain()->recordAndReleasePMEventGated( details );
5921
5922 if (kIOLogDebugPower & gIOKitDebug)
5923 {
5924 PM_LOG("Ack(%u) %u ms\n",
5925 (uint32_t) ordinalComponent,
5926 NS_TO_MS(nsec));
5927 }
5928
5929 // > 100 ms
5930 if (nsec > LOG_APP_RESPONSE_TIMES)
5931 {
5932 PM_LOG("PM response took %d ms (%s)\n", NS_TO_MS(nsec),
5933 name ? name->getCStringNoCopy() : "");
5934
5935 if (nsec > LOG_APP_RESPONSE_MSG_TRACER)
5936 {
5937 // TODO: populate the messageType argument
5938 getPMRootDomain()->pmStatsRecordApplicationResponse(
5939 gIOPMStatsApplicationResponseSlow,
5940 name ? name->getCStringNoCopy() : "", 0,
5941 NS_TO_MS(nsec), pid);
5942 }
5943 }
5944
5945 if (name)
5946 name->release();
5947 #endif
5948 theFlag = kOSBooleanFalse;
5949 }
5950
5951 if ( kOSBooleanFalse == theFlag )
5952 {
5953 fResponseArray->replaceObject(ordinalComponent, kOSBooleanTrue);
5954 }
5955
5956 return true;
5957 }
5958
5959 //*********************************************************************************
5960 // [public] allowPowerChange
5961 //
5962 // Our power state is about to lower, and we have notified applications
5963 // and kernel clients, and one of them has acknowledged. If this is the last to do
5964 // so, and all acknowledgements are positive, we continue with the power change.
5965 //*********************************************************************************
5966
5967 IOReturn IOService::allowPowerChange ( unsigned long refcon )
5968 {
5969 IOPMRequest * request;
5970
5971 if ( !initialized )
5972 {
5973 // we're unloading
5974 return kIOReturnSuccess;
5975 }
5976
5977 request = acquirePMRequest( this, kIOPMRequestTypeAllowPowerChange );
5978 if (!request)
5979 return kIOReturnNoMemory;
5980
5981 request->fArg0 = (void *) refcon;
5982 request->fArg1 = (void *) proc_selfpid();
5983 request->fArg2 = (void *) 0;
5984 submitPMRequest( request );
5985
5986 return kIOReturnSuccess;
5987 }
5988
5989 #ifndef __LP64__
5990 IOReturn IOService::serializedAllowPowerChange2 ( unsigned long refcon )
5991 {
5992 // [deprecated] public
5993 return kIOReturnUnsupported;
5994 }
5995 #endif /* !__LP64__ */
5996
5997 //*********************************************************************************
5998 // [public] cancelPowerChange
5999 //
6000 // Our power state is about to lower, and we have notified applications
6001 // and kernel clients, and one of them has vetoed the change. If this is the last
6002 // client to respond, we abandon the power change.
6003 //*********************************************************************************
6004
6005 IOReturn IOService::cancelPowerChange ( unsigned long refcon )
6006 {
6007 IOPMRequest * request;
6008 OSString * name;
6009
6010 if ( !initialized )
6011 {
6012 // we're unloading
6013 return kIOReturnSuccess;
6014 }
6015
6016 name = IOCopyLogNameForPID(proc_selfpid());
6017 PM_ERROR("PM notification cancel (%s)\n", name ? name->getCStringNoCopy() : "");
6018
6019 request = acquirePMRequest( this, kIOPMRequestTypeCancelPowerChange );
6020 if (!request)
6021 {
6022 if (name)
6023 name->release();
6024 return kIOReturnNoMemory;
6025 }
6026
6027 request->fArg0 = (void *) refcon;
6028 request->fArg1 = (void *) proc_selfpid();
6029 request->fArg2 = (void *) name;
6030 submitPMRequest( request );
6031
6032 return kIOReturnSuccess;
6033 }
6034
6035 #ifndef __LP64__
6036 IOReturn IOService::serializedCancelPowerChange2 ( unsigned long refcon )
6037 {
6038 // [deprecated] public
6039 return kIOReturnUnsupported;
6040 }
6041
6042 //*********************************************************************************
6043 // PM_Clamp_Timer_Expired
6044 //
6045 // called when clamp timer expires...set power state to 0.
6046 //*********************************************************************************
6047
6048 void IOService::PM_Clamp_Timer_Expired ( void )
6049 {
6050 }
6051
6052 //*********************************************************************************
6053 // clampPowerOn
6054 //
6055 // Set to highest available power state for a minimum of duration milliseconds
6056 //*********************************************************************************
6057
6058 void IOService::clampPowerOn ( unsigned long duration )
6059 {
6060 }
6061 #endif /* !__LP64__ */
6062
6063 // MARK: -
6064 // MARK: Driver Overrides
6065
6066 //*********************************************************************************
6067 // [public] setPowerState
6068 //
6069 // Does nothing here. This should be implemented in a subclass driver.
6070 //*********************************************************************************
6071
6072 IOReturn IOService::setPowerState (
6073 unsigned long powerStateOrdinal, IOService * whatDevice )
6074 {
6075 return IOPMNoErr;
6076 }
6077
6078 //*********************************************************************************
6079 // [public] maxCapabilityForDomainState
6080 //
6081 // Finds the highest power state in the array whose input power
6082 // requirement is equal to the input parameter. Where a more intelligent
6083 // decision is possible, override this in the subclassed driver.
6084 //*********************************************************************************
6085
6086 unsigned long IOService::maxCapabilityForDomainState ( IOPMPowerFlags domainState )
6087 {
6088 int i;
6089
6090 if (fNumberOfPowerStates == 0 )
6091 {
6092 return 0;
6093 }
6094 for ( i = fNumberOfPowerStates - 1; i >= 0; i-- )
6095 {
6096 if ( (domainState & fPowerStates[i].inputPowerFlags) ==
6097 fPowerStates[i].inputPowerFlags )
6098 {
6099 return i;
6100 }
6101 }
6102 return 0;
6103 }
6104
6105 //*********************************************************************************
6106 // [public] initialPowerStateForDomainState
6107 //
6108 // Finds the highest power state in the array whose input power
6109 // requirement is equal to the input parameter. Where a more intelligent
6110 // decision is possible, override this in the subclassed driver.
6111 //*********************************************************************************
6112
6113 unsigned long IOService::initialPowerStateForDomainState ( IOPMPowerFlags domainState )
6114 {
6115 int i;
6116
6117 if (fNumberOfPowerStates == 0 )
6118 {
6119 return 0;
6120 }
6121 for ( i = fNumberOfPowerStates - 1; i >= 0; i-- )
6122 {
6123 if ( (domainState & fPowerStates[i].inputPowerFlags) ==
6124 fPowerStates[i].inputPowerFlags )
6125 {
6126 return i;
6127 }
6128 }
6129 return 0;
6130 }
6131
6132 //*********************************************************************************
6133 // [public] powerStateForDomainState
6134 //
6135 // Finds the highest power state in the array whose input power
6136 // requirement is equal to the input parameter. Where a more intelligent
6137 // decision is possible, override this in the subclassed driver.
6138 //*********************************************************************************
6139
6140 unsigned long IOService::powerStateForDomainState ( IOPMPowerFlags domainState )
6141 {
6142 int i;
6143
6144 if (fNumberOfPowerStates == 0 )
6145 {
6146 return 0;
6147 }
6148 for ( i = fNumberOfPowerStates - 1; i >= 0; i-- )
6149 {
6150 if ( (domainState & fPowerStates[i].inputPowerFlags) ==
6151 fPowerStates[i].inputPowerFlags )
6152 {
6153 return i;
6154 }
6155 }
6156 return 0;
6157 }
6158
6159 #ifndef __LP64__
6160 //*********************************************************************************
6161 // [deprecated] didYouWakeSystem
6162 //
6163 // Does nothing here. This should be implemented in a subclass driver.
6164 //*********************************************************************************
6165
6166 bool IOService::didYouWakeSystem ( void )
6167 {
6168 return false;
6169 }
6170 #endif /* !__LP64__ */
6171
6172 //*********************************************************************************
6173 // [public] powerStateWillChangeTo
6174 //
6175 // Does nothing here. This should be implemented in a subclass driver.
6176 //*********************************************************************************
6177
6178 IOReturn IOService::powerStateWillChangeTo ( IOPMPowerFlags, unsigned long, IOService * )
6179 {
6180 return kIOPMAckImplied;
6181 }
6182
6183 //*********************************************************************************
6184 // [public] powerStateDidChangeTo
6185 //
6186 // Does nothing here. This should be implemented in a subclass driver.
6187 //*********************************************************************************
6188
6189 IOReturn IOService::powerStateDidChangeTo ( IOPMPowerFlags, unsigned long, IOService * )
6190 {
6191 return kIOPMAckImplied;
6192 }
6193
6194 //*********************************************************************************
6195 // [protected] powerChangeDone
6196 //
6197 // Called from PM work loop thread.
6198 // Does nothing here. This should be implemented in a subclass policy-maker.
6199 //*********************************************************************************
6200
6201 void IOService::powerChangeDone ( unsigned long )
6202 {
6203 }
6204
6205 #ifndef __LP64__
6206 //*********************************************************************************
6207 // [deprecated] newTemperature
6208 //
6209 // Does nothing here. This should be implemented in a subclass driver.
6210 //*********************************************************************************
6211
6212 IOReturn IOService::newTemperature ( long currentTemp, IOService * whichZone )
6213 {
6214 return IOPMNoErr;
6215 }
6216 #endif /* !__LP64__ */
6217
6218 //*********************************************************************************
6219 // [public] systemWillShutdown
6220 //
6221 // System shutdown and restart notification.
6222 //*********************************************************************************
6223
6224 void IOService::systemWillShutdown( IOOptionBits specifier )
6225 {
6226 IOPMrootDomain * rootDomain = IOService::getPMRootDomain();
6227 if (rootDomain)
6228 rootDomain->acknowledgeSystemWillShutdown( this );
6229 }
6230
6231 // MARK: -
6232 // MARK: PM State Machine
6233
6234 //*********************************************************************************
6235 // [private static] acquirePMRequest
6236 //*********************************************************************************
6237
6238 IOPMRequest *
6239 IOService::acquirePMRequest( IOService * target, IOOptionBits requestType,
6240 IOPMRequest * active )
6241 {
6242 IOPMRequest * request;
6243
6244 assert(target);
6245
6246 request = IOPMRequest::create();
6247 if (request)
6248 {
6249 request->init( target, requestType );
6250 if (active)
6251 {
6252 IOPMRequest * root = active->getRootRequest();
6253 if (root) request->attachRootRequest(root);
6254 }
6255 }
6256 else
6257 {
6258 PM_ERROR("%s: No memory for PM request type 0x%x\n",
6259 target->getName(), (uint32_t) requestType);
6260 }
6261 return request;
6262 }
6263
6264 //*********************************************************************************
6265 // [private static] releasePMRequest
6266 //*********************************************************************************
6267
6268 void IOService::releasePMRequest( IOPMRequest * request )
6269 {
6270 if (request)
6271 {
6272 request->reset();
6273 request->release();
6274 }
6275 }
6276
6277 //*********************************************************************************
6278 // [private] submitPMRequest
6279 //*********************************************************************************
6280
6281 void IOService::submitPMRequest( IOPMRequest * request )
6282 {
6283 assert( request );
6284 assert( gIOPMReplyQueue );
6285 assert( gIOPMRequestQueue );
6286
6287 PM_LOG1("[+ %02lx] %p [%p %s] %p %p %p\n",
6288 (long)request->getType(), request,
6289 request->getTarget(), request->getTarget()->getName(),
6290 request->fArg0, request->fArg1, request->fArg2);
6291
6292 if (request->isReplyType())
6293 gIOPMReplyQueue->queuePMRequest( request );
6294 else
6295 gIOPMRequestQueue->queuePMRequest( request );
6296 }
6297
6298 void IOService::submitPMRequest( IOPMRequest ** requests, IOItemCount count )
6299 {
6300 assert( requests );
6301 assert( count > 0 );
6302 assert( gIOPMRequestQueue );
6303
6304 for (IOItemCount i = 0; i < count; i++)
6305 {
6306 IOPMRequest * req = requests[i];
6307 PM_LOG1("[+ %02lx] %p [%p %s] %p %p %p\n",
6308 (long)req->getType(), req,
6309 req->getTarget(), req->getTarget()->getName(),
6310 req->fArg0, req->fArg1, req->fArg2);
6311 }
6312
6313 gIOPMRequestQueue->queuePMRequestChain( requests, count );
6314 }
6315
6316 //*********************************************************************************
6317 // [private] servicePMRequestQueue
6318 //
6319 // Called from IOPMRequestQueue::checkForWork().
6320 //*********************************************************************************
6321
6322 bool IOService::servicePMRequestQueue(
6323 IOPMRequest * request,
6324 IOPMRequestQueue * queue )
6325 {
6326 bool more;
6327
6328 if (initialized)
6329 {
6330 // Work queue will immediately execute the queue'd request if possible.
6331 // If execution blocks, the work queue will wait for a producer signal.
6332 // Only need to signal more when completing attached requests.
6333
6334 more = gIOPMWorkQueue->queuePMRequest(request, pwrMgt);
6335 return more;
6336 }
6337
6338 // Calling PM without PMinit() is not allowed, fail the request.
6339
6340 PM_LOG("%s: PM not initialized\n", getName());
6341 fAdjustPowerScheduled = false;
6342 more = gIOPMFreeQueue->queuePMRequest(request);
6343 if (more) gIOPMWorkQueue->incrementProducerCount();
6344 return more;
6345 }
6346
6347 //*********************************************************************************
6348 // [private] servicePMFreeQueue
6349 //
6350 // Called from IOPMCompletionQueue::checkForWork().
6351 //*********************************************************************************
6352
6353 bool IOService::servicePMFreeQueue(
6354 IOPMRequest * request,
6355 IOPMCompletionQueue * queue )
6356 {
6357 bool more = request->getNextRequest();
6358 IOPMRequest * root = request->getRootRequest();
6359
6360 if (root && (root != request))
6361 more = true;
6362 if (more)
6363 gIOPMWorkQueue->incrementProducerCount();
6364
6365 releasePMRequest( request );
6366 return more;
6367 }
6368
6369 //*********************************************************************************
6370 // [private] retirePMRequest
6371 //
6372 // Called by IOPMWorkQueue to retire a completed request.
6373 //*********************************************************************************
6374
6375 bool IOService::retirePMRequest( IOPMRequest * request, IOPMWorkQueue * queue )
6376 {
6377 assert(request && queue);
6378
6379 PM_LOG1("[- %02x] %p [%p %s] state %d, busy %d\n",
6380 request->getType(), request, this, getName(),
6381 fMachineState, gIOPMBusyCount);
6382
6383 // Catch requests created by idleTimerExpired().
6384
6385 if ((request->getType() == kIOPMRequestTypeActivityTickle) &&
6386 (request->fArg1 == (void *) (uintptr_t) false))
6387 {
6388 // Idle timer power drop request completed.
6389 // Restart the idle timer if deviceDesire can go lower, otherwise set
6390 // a flag so we know to restart idle timer when deviceDesire goes up.
6391
6392 if (fDeviceDesire > 0)
6393 {
6394 fActivityTickleCount = 0;
6395 clock_get_uptime(&fIdleTimerStartTime);
6396 start_PM_idle_timer();
6397 }
6398 else
6399 fIdleTimerStopped = true;
6400 }
6401
6402 // If the request is linked, then Work queue has already incremented its
6403 // producer count.
6404
6405 return (gIOPMFreeQueue->queuePMRequest( request ));
6406 }
6407
6408 //*********************************************************************************
6409 // [private] isPMBlocked
6410 //
6411 // Check if machine state transition is blocked.
6412 //*********************************************************************************
6413
6414 bool IOService::isPMBlocked ( IOPMRequest * request, int count )
6415 {
6416 int reason = 0;
6417
6418 do {
6419 if (kIOPM_Finished == fMachineState)
6420 break;
6421
6422 if (kIOPM_DriverThreadCallDone == fMachineState)
6423 {
6424 // 5 = kDriverCallInformPreChange
6425 // 6 = kDriverCallInformPostChange
6426 // 7 = kDriverCallSetPowerState
6427 if (fDriverCallBusy)
6428 reason = 5 + fDriverCallReason;
6429 break;
6430 }
6431
6432 // Waiting on driver's setPowerState() timeout.
6433 if (fDriverTimer)
6434 {
6435 reason = 1; break;
6436 }
6437
6438 // Child or interested driver acks pending.
6439 if (fHeadNotePendingAcks)
6440 {
6441 reason = 2; break;
6442 }
6443
6444 // Waiting on apps or priority power interest clients.
6445 if (fResponseArray)
6446 {
6447 reason = 3; break;
6448 }
6449
6450 // Waiting on settle timer expiration.
6451 if (fSettleTimeUS)
6452 {
6453 reason = 4; break;
6454 }
6455 } while (false);
6456
6457 fWaitReason = reason;
6458
6459 if (reason)
6460 {
6461 if (count)
6462 {
6463 PM_LOG1("[B %02x] %p [%p %s] state %d, reason %d\n",
6464 request->getType(), request, this, getName(),
6465 fMachineState, reason);
6466 }
6467
6468 return true;
6469 }
6470
6471 return false;
6472 }
6473
6474 //*********************************************************************************
6475 // [private] servicePMRequest
6476 //
6477 // Service a request from our work queue.
6478 //*********************************************************************************
6479
6480 bool IOService::servicePMRequest( IOPMRequest * request, IOPMWorkQueue * queue )
6481 {
6482 bool done = false;
6483 int loop = 0;
6484
6485 assert(request && queue);
6486
6487 while (isPMBlocked(request, loop++) == false)
6488 {
6489 PM_LOG1("[W %02x] %p [%p %s] state %d\n",
6490 request->getType(), request, this, getName(), fMachineState);
6491
6492 gIOPMRequest = request;
6493 gIOPMWorkCount++;
6494
6495 // Every PM machine states must be handled in one of the cases below.
6496
6497 switch ( fMachineState )
6498 {
6499 case kIOPM_Finished:
6500 executePMRequest( request );
6501 break;
6502
6503 case kIOPM_OurChangeTellClientsPowerDown:
6504 // Root domain might self cancel due to assertions.
6505 if (IS_ROOT_DOMAIN)
6506 {
6507 bool cancel = (bool) fDoNotPowerDown;
6508 getPMRootDomain()->askChangeDownDone(
6509 &fHeadNoteChangeFlags, &cancel);
6510 fDoNotPowerDown = cancel;
6511 }
6512
6513 // askChangeDown() done, was it vetoed?
6514 if (!fDoNotPowerDown)
6515 {
6516 if (IS_ROOT_DOMAIN) {
6517 PMEventDetails *details = PMEventDetails::eventDetails(
6518 kIOPMEventTypeAppNotificationsFinished,
6519 NULL,
6520 0,
6521 0);
6522
6523 getPMRootDomain()->recordAndReleasePMEventGated( details );
6524 }
6525
6526 // no, we can continue
6527 OurChangeTellClientsPowerDown();
6528 }
6529 else
6530 {
6531 if (IS_ROOT_DOMAIN) {
6532 PMEventDetails *details = PMEventDetails::eventDetails(
6533 kIOPMEventTypeSleepDone,
6534 NULL,
6535 1, /* reason: 1 == Ask clients succeeded */
6536 kIOReturnAborted); /* result */
6537
6538 getPMRootDomain()->recordAndReleasePMEventGated( details );
6539 }
6540
6541 OUR_PMLog(kPMLogIdleCancel, (uintptr_t) this, fMachineState);
6542 PM_ERROR("%s: idle cancel\n", fName);
6543 // yes, rescind the warning
6544 tellNoChangeDown(fHeadNotePowerState);
6545 // mark the change note un-actioned
6546 fHeadNoteChangeFlags |= kIOPMNotDone;
6547 // and we're done
6548 OurChangeFinish();
6549 }
6550 break;
6551
6552 case kIOPM_OurChangeTellPriorityClientsPowerDown:
6553 // tellChangeDown(kNotifyApps) done, was it cancelled?
6554 if (fDoNotPowerDown)
6555 {
6556 if (IS_ROOT_DOMAIN) {
6557 PMEventDetails *details = PMEventDetails::eventDetails(
6558 kIOPMEventTypeSleepDone,
6559 NULL,
6560 2, /* reason: 2 == Client cancelled wake */
6561 kIOReturnAborted); /* result */
6562
6563 getPMRootDomain()->recordAndReleasePMEventGated( details );
6564 }
6565 OUR_PMLog(kPMLogIdleCancel, (uintptr_t) this, fMachineState);
6566 PM_ERROR("%s: idle revert\n", fName);
6567 // no, tell clients we're back in the old state
6568 tellChangeUp(fCurrentPowerState);
6569 // mark the change note un-actioned
6570 fHeadNoteChangeFlags |= kIOPMNotDone;
6571 // and we're done
6572 OurChangeFinish();
6573 }
6574 else
6575 {
6576 if (IS_ROOT_DOMAIN) {
6577 PMEventDetails *details = PMEventDetails::eventDetails(
6578 kIOPMEventTypeAppNotificationsFinished,
6579 NULL,
6580 2, /* reason: 2 == TellPriorityClientsDone */
6581 kIOReturnSuccess); /* result */
6582
6583 getPMRootDomain()->recordAndReleasePMEventGated( details );
6584 }
6585 // yes, we can continue
6586 OurChangeTellPriorityClientsPowerDown();
6587 }
6588 break;
6589
6590 case kIOPM_OurChangeNotifyInterestedDriversWillChange:
6591 OurChangeNotifyInterestedDriversWillChange();
6592 break;
6593
6594 case kIOPM_OurChangeSetPowerState:
6595 OurChangeSetPowerState();
6596 break;
6597
6598 case kIOPM_OurChangeWaitForPowerSettle:
6599 OurChangeWaitForPowerSettle();
6600 break;
6601
6602 case kIOPM_OurChangeNotifyInterestedDriversDidChange:
6603 OurChangeNotifyInterestedDriversDidChange();
6604 break;
6605
6606 case kIOPM_OurChangeTellCapabilityDidChange:
6607 OurChangeTellCapabilityDidChange();
6608 break;
6609
6610 case kIOPM_OurChangeFinish:
6611 OurChangeFinish();
6612 break;
6613
6614 case kIOPM_ParentChangeTellPriorityClientsPowerDown:
6615 ParentChangeTellPriorityClientsPowerDown();
6616 break;
6617
6618 case kIOPM_ParentChangeNotifyInterestedDriversWillChange:
6619 ParentChangeNotifyInterestedDriversWillChange();
6620 break;
6621
6622 case kIOPM_ParentChangeSetPowerState:
6623 ParentChangeSetPowerState();
6624 break;
6625
6626 case kIOPM_ParentChangeWaitForPowerSettle:
6627 ParentChangeWaitForPowerSettle();
6628 break;
6629
6630 case kIOPM_ParentChangeNotifyInterestedDriversDidChange:
6631 ParentChangeNotifyInterestedDriversDidChange();
6632 break;
6633
6634 case kIOPM_ParentChangeTellCapabilityDidChange:
6635 ParentChangeTellCapabilityDidChange();
6636 break;
6637
6638 case kIOPM_ParentChangeAcknowledgePowerChange:
6639 ParentChangeAcknowledgePowerChange();
6640 break;
6641
6642 case kIOPM_DriverThreadCallDone:
6643 if (fDriverCallReason == kDriverCallSetPowerState)
6644 notifyControllingDriverDone();
6645 else
6646 notifyInterestedDriversDone();
6647 break;
6648
6649 case kIOPM_NotifyChildrenOrdered:
6650 notifyChildrenOrdered();
6651 break;
6652
6653 case kIOPM_NotifyChildrenDelayed:
6654 notifyChildrenDelayed();
6655 break;
6656
6657 case kIOPM_NotifyChildrenStart:
6658 PM_LOG2("%s: kIOPM_NotifyChildrenStart done\n", getName());
6659 MS_POP(); // from notifyInterestedDriversDone()
6660 notifyChildren();
6661 break;
6662
6663 case kIOPM_SyncTellClientsPowerDown:
6664 // Root domain might self cancel due to assertions.
6665 if (IS_ROOT_DOMAIN)
6666 {
6667 bool cancel = (bool) fDoNotPowerDown;
6668 getPMRootDomain()->askChangeDownDone(
6669 &fHeadNoteChangeFlags, &cancel);
6670 fDoNotPowerDown = cancel;
6671 }
6672 if (!fDoNotPowerDown)
6673 {
6674 fMachineState = kIOPM_SyncTellPriorityClientsPowerDown;
6675 fOutOfBandParameter = kNotifyApps;
6676 tellChangeDown(fHeadNotePowerState);
6677 }
6678 else
6679 {
6680 OUR_PMLog(kPMLogIdleCancel, (uintptr_t) this, fMachineState);
6681 PM_ERROR("%s: idle cancel\n", fName);
6682 tellNoChangeDown(fHeadNotePowerState);
6683 fHeadNoteChangeFlags |= kIOPMNotDone;
6684 OurChangeFinish();
6685 }
6686 break;
6687
6688 case kIOPM_SyncTellPriorityClientsPowerDown:
6689 if (!fDoNotPowerDown)
6690 {
6691 fMachineState = kIOPM_SyncNotifyWillChange;
6692 fOutOfBandParameter = kNotifyPriority;
6693 tellChangeDown(fHeadNotePowerState);
6694 }
6695 else
6696 {
6697 OUR_PMLog(kPMLogIdleCancel, (uintptr_t) this, fMachineState);
6698 PM_ERROR("%s: idle revert\n", fName);
6699 tellChangeUp(fCurrentPowerState);
6700 fHeadNoteChangeFlags |= kIOPMNotDone;
6701 OurChangeFinish();
6702 }
6703 break;
6704
6705 case kIOPM_SyncNotifyWillChange:
6706 if (kIOPMSyncNoChildNotify & fHeadNoteChangeFlags)
6707 {
6708 fMachineState = kIOPM_SyncFinish;
6709 continue;
6710 }
6711 fMachineState = kIOPM_SyncNotifyDidChange;
6712 fDriverCallReason = kDriverCallInformPreChange;
6713 notifyChildren();
6714 break;
6715
6716 case kIOPM_SyncNotifyDidChange:
6717 fIsPreChange = false;
6718
6719 if (fHeadNoteChangeFlags & kIOPMParentInitiated)
6720 fMachineState = kIOPM_SyncFinish;
6721 else
6722 fMachineState = kIOPM_SyncTellCapabilityDidChange;
6723
6724 fDriverCallReason = kDriverCallInformPostChange;
6725 notifyChildren();
6726 break;
6727
6728 case kIOPM_SyncTellCapabilityDidChange:
6729 tellSystemCapabilityChange( kIOPM_SyncFinish );
6730 break;
6731
6732 case kIOPM_SyncFinish:
6733 if (fHeadNoteChangeFlags & kIOPMParentInitiated)
6734 ParentChangeAcknowledgePowerChange();
6735 else
6736 OurChangeFinish();
6737 break;
6738
6739 case kIOPM_TellCapabilityChangeDone:
6740 if (fIsPreChange)
6741 {
6742 if (fOutOfBandParameter == kNotifyCapabilityChangePriority)
6743 {
6744 MS_POP(); // tellSystemCapabilityChange()
6745 continue;
6746 }
6747 fOutOfBandParameter = kNotifyCapabilityChangePriority;
6748 }
6749 else
6750 {
6751 if (fOutOfBandParameter == kNotifyCapabilityChangeApps)
6752 {
6753 MS_POP(); // tellSystemCapabilityChange()
6754 continue;
6755 }
6756 fOutOfBandParameter = kNotifyCapabilityChangeApps;
6757 }
6758 tellClientsWithResponse( fOutOfBandMessage );
6759 break;
6760
6761 default:
6762 panic("servicePMWorkQueue: unknown machine state %x",
6763 fMachineState);
6764 }
6765
6766 gIOPMRequest = 0;
6767
6768 if (fMachineState == kIOPM_Finished)
6769 {
6770 done = true;
6771 break;
6772 }
6773 }
6774
6775 return done;
6776 }
6777
6778 //*********************************************************************************
6779 // [private] executePMRequest
6780 //*********************************************************************************
6781
6782 void IOService::executePMRequest( IOPMRequest * request )
6783 {
6784 assert( kIOPM_Finished == fMachineState );
6785
6786 switch (request->getType())
6787 {
6788 case kIOPMRequestTypePMStop:
6789 handlePMstop( request );
6790 break;
6791
6792 case kIOPMRequestTypeAddPowerChild1:
6793 addPowerChild1( request );
6794 break;
6795
6796 case kIOPMRequestTypeAddPowerChild2:
6797 addPowerChild2( request );
6798 break;
6799
6800 case kIOPMRequestTypeAddPowerChild3:
6801 addPowerChild3( request );
6802 break;
6803
6804 case kIOPMRequestTypeRegisterPowerDriver:
6805 handleRegisterPowerDriver( request );
6806 break;
6807
6808 case kIOPMRequestTypeAdjustPowerState:
6809 fAdjustPowerScheduled = false;
6810 adjustPowerState();
6811 break;
6812
6813 case kIOPMRequestTypePowerDomainWillChange:
6814 handlePowerDomainWillChangeTo( request );
6815 break;
6816
6817 case kIOPMRequestTypePowerDomainDidChange:
6818
6819 handlePowerDomainDidChangeTo( request );
6820 break;
6821
6822 case kIOPMRequestTypeRequestPowerState:
6823 case kIOPMRequestTypeRequestPowerStateOverride:
6824 handleRequestPowerState( request );
6825 break;
6826
6827 case kIOPMRequestTypePowerOverrideOnPriv:
6828 case kIOPMRequestTypePowerOverrideOffPriv:
6829 handlePowerOverrideChanged( request );
6830 break;
6831
6832 case kIOPMRequestTypeActivityTickle:
6833 handleActivityTickle( request );
6834 break;
6835
6836 case kIOPMRequestTypeSynchronizePowerTree:
6837 handleSynchronizePowerTree( request );
6838 break;
6839
6840 case kIOPMRequestTypeSetIdleTimerPeriod:
6841 {
6842 fIdleTimerPeriod = (uintptr_t) request->fArg0;
6843
6844 if ((false == fLockedFlags.PMStop) && (fIdleTimerPeriod > 0))
6845 {
6846 fActivityTickleCount = 0;
6847 clock_get_uptime(&fIdleTimerStartTime);
6848 start_PM_idle_timer();
6849 }
6850 }
6851 break;
6852
6853 case kIOPMRequestTypeIgnoreIdleTimer:
6854 fIdleTimerIgnored = request->fArg0 ? 1 : 0;
6855 break;
6856
6857 default:
6858 panic("executePMRequest: unknown request type %x", request->getType());
6859 }
6860 }
6861
6862 //*********************************************************************************
6863 // [private] servicePMReplyQueue
6864 //*********************************************************************************
6865
6866 bool IOService::servicePMReplyQueue( IOPMRequest * request, IOPMRequestQueue * queue )
6867 {
6868 bool more = false;
6869
6870 assert( request && queue );
6871 assert( request->isReplyType() );
6872
6873 PM_LOG1("[A %02x] %p [%p %s] state %d\n",
6874 request->getType(), request, this, getName(), fMachineState);
6875
6876 switch ( request->getType() )
6877 {
6878 case kIOPMRequestTypeAllowPowerChange:
6879 case kIOPMRequestTypeCancelPowerChange:
6880 // Check if we are expecting this response.
6881 if (responseValid((uint32_t)(uintptr_t) request->fArg0,
6882 (int)(uintptr_t) request->fArg1))
6883 {
6884 if (kIOPMRequestTypeCancelPowerChange == request->getType())
6885 {
6886 // Clients are not allowed to cancel when kIOPMSkipAskPowerDown
6887 // flag is set. Only root domain will set this flag.
6888
6889 if ((fHeadNoteChangeFlags & kIOPMSkipAskPowerDown) == 0)
6890 {
6891 fDoNotPowerDown = true;
6892
6893 OSString * name = (OSString *) request->fArg2;
6894 getPMRootDomain()->pmStatsRecordApplicationResponse(
6895 gIOPMStatsApplicationResponseCancel,
6896 name ? name->getCStringNoCopy() : "", 0,
6897 0, (int)(uintptr_t) request->fArg1);
6898 }
6899 }
6900
6901 if (checkForDone())
6902 {
6903 stop_ack_timer();
6904 cleanClientResponses(false);
6905 more = true;
6906 }
6907 }
6908 // OSString containing app name in Arg2 must be released.
6909 if (request->getType() == kIOPMRequestTypeCancelPowerChange)
6910 {
6911 OSObject * obj = (OSObject *) request->fArg2;
6912 if (obj) obj->release();
6913 }
6914 break;
6915
6916 case kIOPMRequestTypeAckPowerChange:
6917 more = handleAcknowledgePowerChange( request );
6918 break;
6919
6920 case kIOPMRequestTypeAckSetPowerState:
6921 if (fDriverTimer == -1)
6922 {
6923 // driver acked while setPowerState() call is in-flight.
6924 // take this ack, return value from setPowerState() is irrelevant.
6925 OUR_PMLog(kPMLogDriverAcknowledgeSet,
6926 (uintptr_t) this, fDriverTimer);
6927 fDriverTimer = 0;
6928 }
6929 else if (fDriverTimer > 0)
6930 {
6931 // expected ack, stop the timer
6932 stop_ack_timer();
6933
6934 #if LOG_SETPOWER_TIMES
6935 uint64_t nsec = computeTimeDeltaNS(&fDriverCallStartTime);
6936 if (nsec > LOG_SETPOWER_TIMES)
6937 PM_LOG("%s::setPowerState(%p, %lu -> %lu) async took %d ms\n",
6938 fName, this, fCurrentPowerState, fHeadNotePowerState, NS_TO_MS(nsec));
6939
6940 PMEventDetails *details = PMEventDetails::eventDetails(
6941 kIOPMEventTypeSetPowerStateDelayed, // type
6942 fName, // who
6943 (uintptr_t)this, // owner unique
6944 NULL, // interest name
6945 (uint8_t)getPowerState(), // old
6946 (uint8_t)fHeadNotePowerState, // new
6947 0, // result
6948 NS_TO_US(nsec)); // usec completion time
6949
6950 getPMRootDomain()->recordAndReleasePMEventGated( details );
6951 #endif
6952 OUR_PMLog(kPMLogDriverAcknowledgeSet, (uintptr_t) this, fDriverTimer);
6953 fDriverTimer = 0;
6954 more = true;
6955 }
6956 else
6957 {
6958 // unexpected ack
6959 OUR_PMLog(kPMLogAcknowledgeErr4, (uintptr_t) this, 0);
6960 }
6961 break;
6962
6963 case kIOPMRequestTypeInterestChanged:
6964 handleInterestChanged( request );
6965 more = true;
6966 break;
6967
6968 case kIOPMRequestTypeIdleCancel:
6969 if ((fMachineState == kIOPM_OurChangeTellClientsPowerDown)
6970 || (fMachineState == kIOPM_OurChangeTellPriorityClientsPowerDown)
6971 || (fMachineState == kIOPM_SyncTellClientsPowerDown)
6972 || (fMachineState == kIOPM_SyncTellPriorityClientsPowerDown))
6973 {
6974 OUR_PMLog(kPMLogIdleCancel, (uintptr_t) this, fMachineState);
6975 PM_LOG2("%s: cancel from machine state %d\n",
6976 getName(), fMachineState);
6977 fDoNotPowerDown = true;
6978 // Stop waiting for app replys.
6979 if ((fMachineState == kIOPM_OurChangeTellPriorityClientsPowerDown) ||
6980 (fMachineState == kIOPM_SyncTellPriorityClientsPowerDown))
6981 cleanClientResponses(false);
6982 more = true;
6983 }
6984 break;
6985
6986 case kIOPMRequestTypeChildNotifyDelayCancel:
6987 if (fMachineState == kIOPM_NotifyChildrenDelayed)
6988 {
6989 PM_LOG2("%s: delay notify cancelled\n", getName());
6990 notifyChildrenDelayed();
6991 }
6992 break;
6993
6994 default:
6995 panic("servicePMReplyQueue: unknown reply type %x",
6996 request->getType());
6997 }
6998
6999 more |= gIOPMFreeQueue->queuePMRequest(request);
7000 if (more)
7001 gIOPMWorkQueue->incrementProducerCount();
7002
7003 return more;
7004 }
7005
7006 //*********************************************************************************
7007 // [private] assertPMDriverCall / deassertPMDriverCall
7008 //*********************************************************************************
7009
7010 bool IOService::assertPMDriverCall(
7011 IOPMDriverCallEntry * entry,
7012 IOOptionBits options,
7013 IOPMinformee * inform )
7014 {
7015 IOService * target = 0;
7016 bool ok = false;
7017
7018 if (!initialized)
7019 return false;
7020
7021 PM_LOCK();
7022
7023 if (fLockedFlags.PMStop)
7024 {
7025 goto fail;
7026 }
7027
7028 if (((options & kIOPMADC_NoInactiveCheck) == 0) && isInactive())
7029 {
7030 goto fail;
7031 }
7032
7033 if (inform)
7034 {
7035 if (!inform->active)
7036 {
7037 goto fail;
7038 }
7039 target = inform->whatObject;
7040 if (target->isInactive())
7041 {
7042 goto fail;
7043 }
7044 }
7045
7046 entry->thread = current_thread();
7047 entry->target = target;
7048 queue_enter(&fPMDriverCallQueue, entry, IOPMDriverCallEntry *, link);
7049 ok = true;
7050
7051 fail:
7052 PM_UNLOCK();
7053
7054 return ok;
7055 }
7056
7057 void IOService::deassertPMDriverCall( IOPMDriverCallEntry * entry )
7058 {
7059 bool wakeup = false;
7060
7061 PM_LOCK();
7062
7063 assert( !queue_empty(&fPMDriverCallQueue) );
7064 queue_remove(&fPMDriverCallQueue, entry, IOPMDriverCallEntry *, link);
7065 if (fLockedFlags.PMDriverCallWait)
7066 {
7067 wakeup = true;
7068 }
7069
7070 PM_UNLOCK();
7071
7072 if (wakeup)
7073 PM_LOCK_WAKEUP(&fPMDriverCallQueue);
7074 }
7075
7076 void IOService::waitForPMDriverCall( IOService * target )
7077 {
7078 const IOPMDriverCallEntry * entry;
7079 thread_t thread = current_thread();
7080 AbsoluteTime deadline;
7081 int waitResult;
7082 bool log = true;
7083 bool wait;
7084
7085 do {
7086 wait = false;
7087 queue_iterate(&fPMDriverCallQueue, entry, const IOPMDriverCallEntry *, link)
7088 {
7089 // Target of interested driver call
7090 if (target && (target != entry->target))
7091 continue;
7092
7093 if (entry->thread == thread)
7094 {
7095 if (log)
7096 {
7097 PM_LOG("%s: %s(%s) on PM thread\n",
7098 fName, __FUNCTION__, target ? target->getName() : "");
7099 OSReportWithBacktrace("%s: %s(%s) on PM thread\n",
7100 fName, __FUNCTION__, target ? target->getName() : "");
7101 log = false;
7102 }
7103 continue;
7104 }
7105
7106 wait = true;
7107 break;
7108 }
7109
7110 if (wait)
7111 {
7112 fLockedFlags.PMDriverCallWait = true;
7113 clock_interval_to_deadline(15, kSecondScale, &deadline);
7114 waitResult = PM_LOCK_SLEEP(&fPMDriverCallQueue, deadline);
7115 fLockedFlags.PMDriverCallWait = false;
7116 if (THREAD_TIMED_OUT == waitResult)
7117 {
7118 PM_ERROR("%s: waitForPMDriverCall timeout\n", fName);
7119 wait = false;
7120 }
7121 }
7122 } while (wait);
7123 }
7124
7125 //*********************************************************************************
7126 // [private] Debug helpers
7127 //*********************************************************************************
7128
7129 const char * IOService::getIOMessageString( uint32_t msg )
7130 {
7131 #define MSG_ENTRY(x) {x, #x}
7132
7133 static const IONamedValue msgNames[] = {
7134 MSG_ENTRY( kIOMessageCanDevicePowerOff ),
7135 MSG_ENTRY( kIOMessageDeviceWillPowerOff ),
7136 MSG_ENTRY( kIOMessageDeviceWillNotPowerOff ),
7137 MSG_ENTRY( kIOMessageDeviceHasPoweredOn ),
7138 MSG_ENTRY( kIOMessageCanSystemPowerOff ),
7139 MSG_ENTRY( kIOMessageSystemWillPowerOff ),
7140 MSG_ENTRY( kIOMessageSystemWillNotPowerOff ),
7141 MSG_ENTRY( kIOMessageCanSystemSleep ),
7142 MSG_ENTRY( kIOMessageSystemWillSleep ),
7143 MSG_ENTRY( kIOMessageSystemWillNotSleep ),
7144 MSG_ENTRY( kIOMessageSystemHasPoweredOn ),
7145 MSG_ENTRY( kIOMessageSystemWillRestart ),
7146 MSG_ENTRY( kIOMessageSystemWillPowerOn ),
7147 MSG_ENTRY( kIOMessageSystemCapabilityChange )
7148 };
7149
7150 return IOFindNameForValue(msg, msgNames);
7151 }
7152
7153 // MARK: -
7154 // MARK: IOPMRequest
7155
7156 //*********************************************************************************
7157 // IOPMRequest Class
7158 //
7159 // Requests from PM clients, and also used for inter-object messaging within PM.
7160 //*********************************************************************************
7161
7162 OSDefineMetaClassAndStructors( IOPMRequest, IOCommand );
7163
7164 IOPMRequest * IOPMRequest::create( void )
7165 {
7166 IOPMRequest * me = OSTypeAlloc(IOPMRequest);
7167 if (me && !me->init(0, kIOPMRequestTypeInvalid))
7168 {
7169 me->release();
7170 me = 0;
7171 }
7172 return me;
7173 }
7174
7175 bool IOPMRequest::init( IOService * target, IOOptionBits type )
7176 {
7177 if (!IOCommand::init())
7178 return false;
7179
7180 fType = type;
7181 fTarget = target;
7182 fCompletionStatus = kIOReturnSuccess;
7183
7184 if (fTarget)
7185 fTarget->retain();
7186
7187 return true;
7188 }
7189
7190 void IOPMRequest::reset( void )
7191 {
7192 assert( fWorkWaitCount == 0 );
7193 assert( fFreeWaitCount == 0 );
7194
7195 detachNextRequest();
7196 detachRootRequest();
7197
7198 fType = kIOPMRequestTypeInvalid;
7199
7200 if (fCompletionAction)
7201 {
7202 fCompletionAction(fCompletionTarget, fCompletionParam, fCompletionStatus);
7203 }
7204
7205 if (fTarget)
7206 {
7207 fTarget->release();
7208 fTarget = 0;
7209 }
7210 }
7211
7212 bool IOPMRequest::attachNextRequest( IOPMRequest * next )
7213 {
7214 bool ok = false;
7215
7216 if (!fRequestNext)
7217 {
7218 // Postpone the execution of the next request after
7219 // this request.
7220 fRequestNext = next;
7221 fRequestNext->fWorkWaitCount++;
7222 #if LOG_REQUEST_ATTACH
7223 kprintf("Attached next: %p [0x%x] -> %p [0x%x, %u] %s\n",
7224 this, (uint32_t) fType, fRequestNext,
7225 (uint32_t) fRequestNext->fType,
7226 (uint32_t) fRequestNext->fWorkWaitCount,
7227 fTarget->getName());
7228 #endif
7229 ok = true;
7230 }
7231 return ok;
7232 }
7233
7234 bool IOPMRequest::detachNextRequest( void )
7235 {
7236 bool ok = false;
7237
7238 if (fRequestNext)
7239 {
7240 assert(fRequestNext->fWorkWaitCount);
7241 if (fRequestNext->fWorkWaitCount)
7242 fRequestNext->fWorkWaitCount--;
7243 #if LOG_REQUEST_ATTACH
7244 kprintf("Detached next: %p [0x%x] -> %p [0x%x, %u] %s\n",
7245 this, (uint32_t) fType, fRequestNext,
7246 (uint32_t) fRequestNext->fType,
7247 (uint32_t) fRequestNext->fWorkWaitCount,
7248 fTarget->getName());
7249 #endif
7250 fRequestNext = 0;
7251 ok = true;
7252 }
7253 return ok;
7254 }
7255
7256 bool IOPMRequest::attachRootRequest( IOPMRequest * root )
7257 {
7258 bool ok = false;
7259
7260 if (!fRequestRoot)
7261 {
7262 // Delay the completion of the root request after
7263 // this request.
7264 fRequestRoot = root;
7265 fRequestRoot->fFreeWaitCount++;
7266 #if LOG_REQUEST_ATTACH
7267 kprintf("Attached root: %p [0x%x] -> %p [0x%x, %u] %s\n",
7268 this, (uint32_t) fType, fRequestRoot,
7269 (uint32_t) fRequestRoot->fType,
7270 (uint32_t) fRequestRoot->fFreeWaitCount,
7271 fTarget->getName());
7272 #endif
7273 ok = true;
7274 }
7275 return ok;
7276 }
7277
7278 bool IOPMRequest::detachRootRequest( void )
7279 {
7280 bool ok = false;
7281
7282 if (fRequestRoot)
7283 {
7284 assert(fRequestRoot->fFreeWaitCount);
7285 if (fRequestRoot->fFreeWaitCount)
7286 fRequestRoot->fFreeWaitCount--;
7287 #if LOG_REQUEST_ATTACH
7288 kprintf("Detached root: %p [0x%x] -> %p [0x%x, %u] %s\n",
7289 this, (uint32_t) fType, fRequestRoot,
7290 (uint32_t) fRequestRoot->fType,
7291 (uint32_t) fRequestRoot->fFreeWaitCount,
7292 fTarget->getName());
7293 #endif
7294 fRequestRoot = 0;
7295 ok = true;
7296 }
7297 return ok;
7298 }
7299
7300 // MARK: -
7301 // MARK: IOPMRequestQueue
7302
7303 //*********************************************************************************
7304 // IOPMRequestQueue Class
7305 //
7306 // Global queues. Queues are created once and never released.
7307 //*********************************************************************************
7308
7309 OSDefineMetaClassAndStructors( IOPMRequestQueue, IOEventSource );
7310
7311 IOPMRequestQueue * IOPMRequestQueue::create( IOService * inOwner, Action inAction )
7312 {
7313 IOPMRequestQueue * me = OSTypeAlloc(IOPMRequestQueue);
7314 if (me && !me->init(inOwner, inAction))
7315 {
7316 me->release();
7317 me = 0;
7318 }
7319 return me;
7320 }
7321
7322 bool IOPMRequestQueue::init( IOService * inOwner, Action inAction )
7323 {
7324 if (!inAction || !IOEventSource::init(inOwner, (IOEventSourceAction)inAction))
7325 return false;
7326
7327 queue_init(&fQueue);
7328 fLock = IOLockAlloc();
7329 return (fLock != 0);
7330 }
7331
7332 void IOPMRequestQueue::free( void )
7333 {
7334 if (fLock)
7335 {
7336 IOLockFree(fLock);
7337 fLock = 0;
7338 }
7339 return IOEventSource::free();
7340 }
7341
7342 void IOPMRequestQueue::queuePMRequest( IOPMRequest * request )
7343 {
7344 assert(request);
7345 IOLockLock(fLock);
7346 queue_enter(&fQueue, request, IOPMRequest *, fCommandChain);
7347 IOLockUnlock(fLock);
7348 if (workLoop) signalWorkAvailable();
7349 }
7350
7351 void
7352 IOPMRequestQueue::queuePMRequestChain( IOPMRequest ** requests, IOItemCount count )
7353 {
7354 IOPMRequest * next;
7355
7356 assert(requests && count);
7357 IOLockLock(fLock);
7358 while (count--)
7359 {
7360 next = *requests;
7361 requests++;
7362 queue_enter(&fQueue, next, IOPMRequest *, fCommandChain);
7363 }
7364 IOLockUnlock(fLock);
7365 if (workLoop) signalWorkAvailable();
7366 }
7367
7368 bool IOPMRequestQueue::checkForWork( void )
7369 {
7370 Action dqAction = (Action) action;
7371 IOPMRequest * request;
7372 IOService * target;
7373 bool more = false;
7374
7375 IOLockLock( fLock );
7376
7377 while (!queue_empty(&fQueue))
7378 {
7379 queue_remove_first( &fQueue, request, IOPMRequest *, fCommandChain );
7380 IOLockUnlock( fLock );
7381 target = request->getTarget();
7382 assert(target);
7383 more |= (*dqAction)( target, request, this );
7384 IOLockLock( fLock );
7385 }
7386
7387 IOLockUnlock( fLock );
7388 return more;
7389 }
7390
7391 // MARK: -
7392 // MARK: IOPMWorkQueue
7393
7394 //*********************************************************************************
7395 // IOPMWorkQueue Class
7396 //
7397 // Queue of IOServicePM objects with busy IOPMRequest(s).
7398 //*********************************************************************************
7399
7400 OSDefineMetaClassAndStructors( IOPMWorkQueue, IOEventSource );
7401
7402 IOPMWorkQueue *
7403 IOPMWorkQueue::create( IOService * inOwner, Action work, Action retire )
7404 {
7405 IOPMWorkQueue * me = OSTypeAlloc(IOPMWorkQueue);
7406 if (me && !me->init(inOwner, work, retire))
7407 {
7408 me->release();
7409 me = 0;
7410 }
7411 return me;
7412 }
7413
7414 bool IOPMWorkQueue::init( IOService * inOwner, Action work, Action retire )
7415 {
7416 if (!work || !retire ||
7417 !IOEventSource::init(inOwner, (IOEventSourceAction)0))
7418 return false;
7419
7420 queue_init(&fWorkQueue);
7421
7422 fWorkAction = work;
7423 fRetireAction = retire;
7424 fConsumerCount = fProducerCount = 0;
7425
7426 return true;
7427 }
7428
7429 bool IOPMWorkQueue::queuePMRequest( IOPMRequest * request, IOServicePM * pwrMgt )
7430 {
7431 bool more = false;
7432 bool empty;
7433
7434 assert( request );
7435 assert( pwrMgt );
7436 assert( onThread() );
7437 assert( queue_next(&request->fCommandChain) ==
7438 queue_prev(&request->fCommandChain) );
7439
7440 gIOPMBusyCount++;
7441
7442 // Add new request to the tail of the per-service request queue.
7443 // Then immediately check the request queue to minimize latency
7444 // if the queue was empty.
7445
7446 empty = queue_empty(&pwrMgt->RequestHead);
7447 queue_enter(&pwrMgt->RequestHead, request, IOPMRequest *, fCommandChain);
7448 if (empty)
7449 {
7450 more = checkRequestQueue(&pwrMgt->RequestHead, &empty);
7451 if (!empty)
7452 {
7453 // New Request is blocked, add IOServicePM to work queue.
7454 assert( queue_next(&pwrMgt->WorkChain) ==
7455 queue_prev(&pwrMgt->WorkChain) );
7456
7457 queue_enter(&fWorkQueue, pwrMgt, IOServicePM *, WorkChain);
7458 fQueueLength++;
7459 PM_LOG3("IOPMWorkQueue: [%u] added %s@%p to queue\n",
7460 fQueueLength, pwrMgt->Name, pwrMgt);
7461 }
7462 }
7463
7464 return more;
7465 }
7466
7467 bool IOPMWorkQueue::checkRequestQueue( queue_head_t * queue, bool * empty )
7468 {
7469 IOPMRequest * request;
7470 IOService * target;
7471 bool more = false;
7472 bool done = false;
7473
7474 assert(!queue_empty(queue));
7475 do {
7476 request = (IOPMRequest *) queue_first(queue);
7477 if (request->isWorkBlocked())
7478 break; // cannot start, blocked on attached request
7479
7480 target = request->getTarget();
7481 done = (*fWorkAction)( target, request, this );
7482 if (!done)
7483 break; // work started, blocked on PM state machine
7484
7485 assert(gIOPMBusyCount > 0);
7486 if (gIOPMBusyCount)
7487 gIOPMBusyCount--;
7488
7489 queue_remove_first(queue, request, IOPMRequest *, fCommandChain);
7490 more |= (*fRetireAction)( target, request, this );
7491 done = queue_empty(queue);
7492 } while (!done);
7493
7494 *empty = done;
7495
7496 if (more)
7497 {
7498 // Retired request blocks another request, since the
7499 // blocked request may reside in the work queue, we
7500 // must bump the producer count to avoid work stall.
7501 fProducerCount++;
7502 }
7503
7504 return more;
7505 }
7506
7507 bool IOPMWorkQueue::checkForWork( void )
7508 {
7509 IOServicePM * entry;
7510 IOServicePM * next;
7511 bool more = false;
7512 bool empty;
7513
7514 #if WORK_QUEUE_STATS
7515 fStatCheckForWork++;
7516 #endif
7517
7518 // Each producer signal triggers a full iteration over
7519 // all IOServicePM entries in the work queue.
7520
7521 while (fConsumerCount != fProducerCount)
7522 {
7523 PM_LOG3("IOPMWorkQueue: checkForWork %u %u\n",
7524 fProducerCount, fConsumerCount);
7525
7526 fConsumerCount = fProducerCount;
7527
7528 #if WORK_QUEUE_STATS
7529 if (queue_empty(&fWorkQueue))
7530 {
7531 fStatQueueEmpty++;
7532 break;
7533 }
7534 fStatScanEntries++;
7535 uint32_t cachedWorkCount = gIOPMWorkCount;
7536 #endif
7537
7538 entry = (IOServicePM *) queue_first(&fWorkQueue);
7539 while (!queue_end(&fWorkQueue, (queue_entry_t) entry))
7540 {
7541 more |= checkRequestQueue(&entry->RequestHead, &empty);
7542
7543 // Get next entry, points to head if current entry is last.
7544 next = (IOServicePM *) queue_next(&entry->WorkChain);
7545
7546 // if request queue is empty, remove IOServicePM from queue.
7547 if (empty)
7548 {
7549 assert(fQueueLength);
7550 if (fQueueLength) fQueueLength--;
7551 PM_LOG3("IOPMWorkQueue: [%u] removed %s@%p from queue\n",
7552 fQueueLength, entry->Name, entry);
7553 queue_remove(&fWorkQueue, entry, IOServicePM *, WorkChain);
7554 }
7555 entry = next;
7556 }
7557
7558 #if WORK_QUEUE_STATS
7559 if (cachedWorkCount == gIOPMWorkCount)
7560 fStatNoWorkDone++;
7561 #endif
7562 }
7563
7564 return more;
7565 }
7566
7567 void IOPMWorkQueue::signalWorkAvailable( void )
7568 {
7569 fProducerCount++;
7570 IOEventSource::signalWorkAvailable();
7571 }
7572
7573 void IOPMWorkQueue::incrementProducerCount( void )
7574 {
7575 fProducerCount++;
7576 }
7577
7578 // MARK: -
7579 // MARK: IOPMCompletionQueue
7580
7581 //*********************************************************************************
7582 // IOPMCompletionQueue Class
7583 //*********************************************************************************
7584
7585 OSDefineMetaClassAndStructors( IOPMCompletionQueue, IOEventSource );
7586
7587 IOPMCompletionQueue *
7588 IOPMCompletionQueue::create( IOService * inOwner, Action inAction )
7589 {
7590 IOPMCompletionQueue * me = OSTypeAlloc(IOPMCompletionQueue);
7591 if (me && !me->init(inOwner, inAction))
7592 {
7593 me->release();
7594 me = 0;
7595 }
7596 return me;
7597 }
7598
7599 bool IOPMCompletionQueue::init( IOService * inOwner, Action inAction )
7600 {
7601 if (!inAction || !IOEventSource::init(inOwner, (IOEventSourceAction)inAction))
7602 return false;
7603
7604 queue_init(&fQueue);
7605 return true;
7606 }
7607
7608 bool IOPMCompletionQueue::queuePMRequest( IOPMRequest * request )
7609 {
7610 bool more;
7611
7612 assert(request);
7613 // unblock dependent request
7614 more = request->detachNextRequest();
7615 queue_enter(&fQueue, request, IOPMRequest *, fCommandChain);
7616 return more;
7617 }
7618
7619 bool IOPMCompletionQueue::checkForWork( void )
7620 {
7621 Action dqAction = (Action) action;
7622 IOPMRequest * request;
7623 IOPMRequest * next;
7624 IOService * target;
7625 bool more = false;
7626
7627 request = (IOPMRequest *) queue_first(&fQueue);
7628 while (!queue_end(&fQueue, (queue_entry_t) request))
7629 {
7630 next = (IOPMRequest *) queue_next(&request->fCommandChain);
7631 if (!request->isFreeBlocked())
7632 {
7633 queue_remove(&fQueue, request, IOPMRequest *, fCommandChain);
7634 target = request->getTarget();
7635 assert(target);
7636 more |= (*dqAction)( target, request, this );
7637 }
7638 request = next;
7639 }
7640
7641 return more;
7642 }
7643
7644 // MARK: -
7645 // MARK: IOServicePM
7646
7647 OSDefineMetaClassAndStructors(IOServicePM, OSObject)
7648
7649 //*********************************************************************************
7650 // serialize
7651 //
7652 // Serialize IOServicePM for debugging.
7653 //*********************************************************************************
7654
7655 static void
7656 setPMProperty( OSDictionary * dict, const char * key, uint64_t value )
7657 {
7658 OSNumber * num = OSNumber::withNumber(value, sizeof(value) * 8);
7659 if (num)
7660 {
7661 dict->setObject(key, num);
7662 num->release();
7663 }
7664 }
7665
7666 IOReturn IOServicePM::gatedSerialize( OSSerialize * s )
7667 {
7668 OSDictionary * dict;
7669 bool ok = false;
7670 int dictSize = 5;
7671
7672 if (IdleTimerPeriod)
7673 dictSize += 4;
7674
7675 #if WORK_QUEUE_STATS
7676 if (gIOPMRootNode == ControllingDriver)
7677 dictSize += 4;
7678 #endif
7679
7680 if (PowerClients)
7681 dict = OSDictionary::withDictionary(
7682 PowerClients, PowerClients->getCount() + dictSize);
7683 else
7684 dict = OSDictionary::withCapacity(dictSize);
7685
7686 if (dict)
7687 {
7688 setPMProperty(dict, "CurrentPowerState", CurrentPowerState);
7689 if (NumberOfPowerStates)
7690 setPMProperty(dict, "MaxPowerState", NumberOfPowerStates-1);
7691 if (DesiredPowerState != CurrentPowerState)
7692 setPMProperty(dict, "DesiredPowerState", DesiredPowerState);
7693 if (kIOPM_Finished != MachineState)
7694 setPMProperty(dict, "MachineState", MachineState);
7695 if (DeviceOverrideEnabled)
7696 dict->setObject("PowerOverrideOn", kOSBooleanTrue);
7697
7698 if (IdleTimerPeriod)
7699 {
7700 AbsoluteTime now;
7701 AbsoluteTime delta;
7702 uint64_t nsecs;
7703
7704 clock_get_uptime(&now);
7705
7706 // The idle timer period in milliseconds.
7707 setPMProperty(dict, "IdleTimerPeriod", IdleTimerPeriod * 1000ULL);
7708
7709 // The number of activity tickles recorded since device idle
7710 setPMProperty(dict, "ActivityTickles", ActivityTickleCount);
7711
7712 if (AbsoluteTime_to_scalar(&DeviceActiveTimestamp))
7713 {
7714 // The number of milliseconds since the last activity tickle.
7715 delta = now;
7716 SUB_ABSOLUTETIME(&delta, &DeviceActiveTimestamp);
7717 absolutetime_to_nanoseconds(delta, &nsecs);
7718 setPMProperty(dict, "TimeSinceLastTickle", NS_TO_MS(nsecs));
7719 }
7720
7721 if (AbsoluteTime_to_scalar(&IdleTimerStartTime))
7722 {
7723 // The number of milliseconds since the last device idle.
7724 delta = now;
7725 SUB_ABSOLUTETIME(&delta, &IdleTimerStartTime);
7726 absolutetime_to_nanoseconds(delta, &nsecs);
7727 setPMProperty(dict, "TimeSinceDeviceIdle", NS_TO_MS(nsecs));
7728 }
7729 }
7730
7731 #if WORK_QUEUE_STATS
7732 if (gIOPMRootNode == Owner)
7733 {
7734 setPMProperty(dict, "WQ-CheckForWork",
7735 gIOPMWorkQueue->fStatCheckForWork);
7736 setPMProperty(dict, "WQ-ScanEntries",
7737 gIOPMWorkQueue->fStatScanEntries);
7738 setPMProperty(dict, "WQ-QueueEmpty",
7739 gIOPMWorkQueue->fStatQueueEmpty);
7740 setPMProperty(dict, "WQ-NoWorkDone",
7741 gIOPMWorkQueue->fStatNoWorkDone);
7742 }
7743 #endif
7744
7745 ok = dict->serialize(s);
7746 dict->release();
7747 }
7748
7749 return (ok ? kIOReturnSuccess : kIOReturnNoMemory);
7750 }
7751
7752 bool IOServicePM::serialize( OSSerialize * s ) const
7753 {
7754 IOReturn ret = kIOReturnNotReady;
7755
7756 if (gIOPMWorkLoop)
7757 {
7758 ret = gIOPMWorkLoop->runAction(
7759 OSMemberFunctionCast(IOWorkLoop::Action, this, &IOServicePM::gatedSerialize),
7760 (OSObject *) this, (void *) s);
7761 }
7762
7763 return (kIOReturnSuccess == ret);
7764 }
7765
7766 PMEventDetails* PMEventDetails::eventDetails(uint32_t type,
7767 const char *ownerName,
7768 uintptr_t ownerUnique,
7769 const char *interestName,
7770 uint8_t oldState,
7771 uint8_t newState,
7772 uint32_t result,
7773 uint32_t elapsedTimeUS) {
7774
7775 PMEventDetails *myself;
7776 myself = new PMEventDetails;
7777
7778 if(myself) {
7779 myself->eventType = type;
7780 myself->ownerName = ownerName;
7781 myself->ownerUnique = ownerUnique;
7782 myself->interestName = interestName;
7783 myself->oldState = oldState;
7784 myself->newState = newState;
7785 myself->result = result;
7786 myself->elapsedTimeUS = elapsedTimeUS;
7787
7788 myself->eventClassifier = kIOPMEventClassDriverEvent;
7789 }
7790
7791 return myself;
7792 }
7793
7794
7795 PMEventDetails* PMEventDetails::eventDetails(uint32_t type,
7796 const char *uuid,
7797 uint32_t reason,
7798 uint32_t result) {
7799
7800 PMEventDetails *myself;
7801 myself = new PMEventDetails;
7802
7803 if(myself) {
7804 myself->eventType = type;
7805 myself->uuid = uuid;
7806 myself->reason = reason;
7807 myself->result = result;
7808
7809 myself->eventClassifier = kIOPMEventClassSystemEvent;
7810 }
7811
7812 return myself;
7813 }
7814