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