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