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