]> git.saurik.com Git - apple/xnu.git/blame - iokit/Kernel/IOServicePM.cpp
xnu-792.12.6.tar.gz
[apple/xnu.git] / iokit / Kernel / IOServicePM.cpp
CommitLineData
1c79356b
A
1/*
2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
3 *
8ad349bb 4 * @APPLE_LICENSE_OSREFERENCE_HEADER_START@
1c79356b 5 *
8ad349bb
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
10 * License may not be used to create, or enable the creation or
11 * redistribution of, unlawful or unlicensed copies of an Apple operating
12 * system, or to circumvent, violate, or enable the circumvention or
13 * violation of, any terms of an Apple operating system software license
14 * agreement.
15 *
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
18 * file.
19 *
20 * The Original Code and all software distributed under the License are
21 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
22 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
23 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
25 * Please see the License for the specific language governing rights and
26 * limitations under the License.
27 *
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
1c79356b 29 */
91447636
A
30
31#include <IOKit/assert.h>
32
1c79356b 33#include <IOKit/IOCommandGate.h>
91447636
A
34#include <IOKit/IOKitDebug.h>
35#include <IOKit/IOLib.h>
36#include <IOKit/IOMessage.h>
37#include <IOKit/IOPlatformExpert.h>
38#include <IOKit/IOService.h>
1c79356b
A
39#include <IOKit/IOTimerEventSource.h>
40#include <IOKit/IOWorkLoop.h>
1c79356b 41
91447636
A
42#include <IOKit/pwr_mgt/IOPMchangeNoteList.h>
43#include <IOKit/pwr_mgt/IOPMinformee.h>
44#include <IOKit/pwr_mgt/IOPMinformeeList.h>
45#include <IOKit/pwr_mgt/IOPMlog.h>
46#include <IOKit/pwr_mgt/IOPowerConnection.h>
47#include <IOKit/pwr_mgt/RootDomain.h>
9bccf70c 48
91447636
A
49// Required for notification instrumentation
50#include "IOServicePrivate.h"
9bccf70c 51
91447636 52#define super IORegistryEntry
9bccf70c 53
91447636
A
54#define OUR_PMLog(t, a, b) \
55 do { pm_vars->thePlatform->PMLog(pm_vars->ourName, t, a, b); } while(0)
9bccf70c 56
1c79356b
A
57static void ack_timer_expired(thread_call_param_t);
58static void settle_timer_expired(thread_call_param_t);
1c79356b 59static void PM_idle_timer_expired(OSObject *, IOTimerEventSource *);
1c79356b
A
60void tellAppWithResponse ( OSObject * object, void * context);
61void tellClientWithResponse ( OSObject * object, void * context);
62void tellClient ( OSObject * object, void * context);
63IOReturn serializedAllowPowerChange ( OSObject *, void *, void *, void *, void *);
64IOReturn serializedCancelPowerChange ( OSObject *, void *, void *, void *, void *);
65
66extern const IORegistryPlane * gIOPowerPlane;
67
68
69// and there's 1000 nanoseconds in a microsecond:
70#define ns_per_us 1000
71
72
73// The current change note is processed by a state machine.
74// Inputs are acks from interested parties, ack from the controlling driver,
75// ack timeouts, settle timeout, and powerStateDidChange from the parent.
76// These are the states:
55e303ae
A
77enum {
78 kIOPM_OurChangeTellClientsPowerDown = 1,
79 kIOPM_OurChangeTellPriorityClientsPowerDown,
80 kIOPM_OurChangeNotifyInterestedDriversWillChange,
81 kIOPM_OurChangeSetPowerState,
82 kIOPM_OurChangeWaitForPowerSettle,
83 kIOPM_OurChangeNotifyInterestedDriversDidChange,
84 kIOPM_OurChangeFinish,
85 kIOPM_ParentDownTellPriorityClientsPowerDown_Immediate,
86 kIOPM_ParentDownNotifyInterestedDriversWillChange_Delayed,
87 kIOPM_ParentDownWaitForPowerSettleAndNotifyDidChange_Immediate,
88 kIOPM_ParentDownNotifyDidChangeAndAcknowledgeChange_Delayed,
89 kIOPM_ParentDownSetPowerState_Delayed,
90 kIOPM_ParentDownWaitForPowerSettle_Delayed,
91 kIOPM_ParentDownAcknowledgeChange_Delayed,
92 kIOPM_ParentUpSetPowerState_Delayed,
93 kIOPM_ParentUpSetPowerState_Immediate,
94 kIOPM_ParentUpWaitForSettleTime_Delayed,
95 kIOPM_ParentUpNotifyInterestedDriversDidChange_Delayed,
96 kIOPM_ParentUpAcknowledgePowerChange_Delayed,
97 kIOPM_Finished
98};
1c79356b 99
55e303ae 100// values of outofbandparameter
1c79356b 101enum {
0b4e3aa0
A
102 kNotifyApps,
103 kNotifyPriority
104};
105
55e303ae
A
106
107// used for applyToInterested
108struct context {
1c79356b
A
109 OSArray * responseFlags;
110 UInt16 serialNumber;
111 UInt16 counter;
112 UInt32 maxTimeRequested;
113 int msgType;
114 IOService * us;
115 IOLock * flags_lock;
0b4e3aa0
A
116 unsigned long stateNumber;
117 IOPMPowerFlags stateFlags;
1c79356b
A
118};
119
55e303ae 120// five minutes in microseconds
1c79356b 121#define FIVE_MINUTES 5*60*1000000
0b4e3aa0 122#define k30seconds 30*1000000
1c79356b
A
123
124/*
125 There are two different kinds of power state changes. One is initiated by a subclassed device object which has either
126 decided to change power state, or its controlling driver has suggested it, or some other driver wants to use the
127 idle device and has asked it to become usable. The second kind of power state change is initiated by the power
128 domain parent. The two are handled slightly differently.
129
130There is a queue of so-called change notifications, or change notes for short. Usually the queue is empty, and when
131 it isn't, usually there is one change note in it, but since it's possible to have more than one power state change pending
132 at one time, a queue is implemented. Example: the subclass device decides it's idle and initiates a change to a lower
133 power state. This causes interested parties to be notified, but they don't all acknowledge right away. This causes the
134 change note to sit in the queue until all the acks are received. During this time, the device decides it isn't idle anymore and
135 wants to raise power back up again. This change can't be started, however, because the previous one isn't complete yet,
136 so the second one waits in the queue. During this time, the parent decides to lower or raise the power state of the entire
137 power domain and notifies the device, and that notification goes into the queue, too, and can't be actioned until the
138 others are.
139
140 This is how a power change initiated by the subclass device is handled:
141 First, all interested parties are notified of the change via their powerStateWillChangeTo method. If they all don't
142 acknowledge via return code, then we have to wait. If they do, or when they finally all acknowledge via our
143 acknowledgePowerChange method, then we can continue. We call the controlling driver, instructing it to change to
144 the new state. Then we wait for power to settle. If there is no settling-time, or after it has passed, we notify
145 interested parties again, this time via their powerStateDidChangeTo methods. When they have all acked, we're done.
146 If we lowered power and don't need the power domain to be in its current power state, we suggest to the parent that
147 it lower the power domain state.
148
149 This is how a change to a lower power domain state initiated by the parent is handled:
150 First, we figure out what power state we will be in when the new domain state is reached. Then all interested parties are
151 notified that we are moving to that new state. When they have acknowledged, we call the controlling driver to assume
152 that state and we wait for power to settle. Then we acknowledge our preparedness to our parent. When all its interested
153 parties have acknowledged, it lowers power and then notifies its interested parties again. When we get this call, we notify
154 our interested parties that the power state has changed, and when they have all acknowledged, we're done.
155
156 This is how a change to a higher power domain state initiated by the parent is handled:
157 We figure out what power state we will be in when the new domain state is reached. If it is different from our current
158 state we acknowledge the parent. When all the parent's interested parties have acknowledged, it raises power in the
159domain and waits for power to settle. Then it notifies everyone that the new state has been reached. When we get this call,
160 we call the controlling driver, instructing it to assume the new state, and wait for power to settle. Then we notify our interested
161 parties. When they all acknowledge we are done.
162
163 In either of the two cases above, it is possible that we will not be changing state even though the domain is. Examples:
164 A change to a lower domain state may not affect us because we are already in a low enough state, and
165 We will not take advantage of a change to a higher domain state, because we have no need of the higher power.
166 In such a case, there is nothing to do but acknowledge the parent. So when the parent calls our powerDomainWillChange
167 method, and we decide that we will not be changing state, we merely acknowledge the parent, via return code, and wait.
168 When the parent subsequently calls powerStateDidChange, we acknowledge again via return code, and the change is complete.
169
170 Power state changes are processed in a state machine, and since there are four varieties of power state changes, there are
171 four major paths through the state machine:
172
173 The fourth is nearly trivial. In this path, the parent is changing the domain state, but we are not changing the device state.
174 The change starts when the parent calls powerDomainWillChange. All we do is acknowledge the parent.
175When the parent calls powerStateDidChange, we acknowledge the parent again, and we're done.
176
177 The first is fairly simple. It starts when a power domain child calls requestPowerDomainState and we decide to change power states
178 to accomodate the child, or if our power-controlling driver calls changePowerStateTo, or if some other driver which is using our
179 device calls makeUsable, or if a subclassed object calls changePowerStateToPriv. These are all power changes initiated by us, not
180 forced upon us by the parent. We start by notifying interested parties. If they all acknowledge via return code, we can go
55e303ae
A
181 on to state "OurChangeSetPowerState". Otherwise, we start the ack timer and wait for the stragglers to acknowlege by calling
182 acknowledgePowerChange. We move on to state "OurChangeSetPowerState" when all the stragglers have acknowledged,
183 or when the ack timer expires on all those which didn't acknowledge. In "OurChangeSetPowerState" we call the power-controlling
184 driver to change the power state of the hardware. If it returns saying it has done so, we go on to state "OurChangeWaitForPowerSettle".
1c79356b 185 Otherwise, we have to wait for it, so we set the ack timer and wait. When it calls acknowledgeSetPowerState, or when the
55e303ae
A
186 ack timer expires, we go on. In "OurChangeWaitForPowerSettle", we look in the power state array to see if there is any settle time required
187 when changing from our current state to the new state. If not, we go right away to "OurChangeNotifyInterestedDriversDidChange". Otherwise, we
188 set the settle timer and wait. When it expires, we move on. In "OurChangeNotifyInterestedDriversDidChange" state, we notify all our interested parties
1c79356b 189 via their powerStateDidChange methods that we have finished changing power state. If they all acknowledge via return
55e303ae
A
190 code, we move on to "OurChangeFinish". Otherwise we set the ack timer and wait. When they have all acknowledged, or
191 when the ack timer has expired for those that didn't, we move on to "OurChangeFinish", where we remove the used
1c79356b
A
192 change note from the head of the queue and start the next one if one exists.
193
194 Parent-initiated changes are more complex in the state machine. First, power going up and power going down are handled
195 differently, so they have different paths throught the state machine. Second, we can acknowledge the parent's notification
196 in two different ways, so each of the parent paths is really two.
197
198 When the parent calls our powerDomainWillChange method, notifying us that it will lower power in the domain, we decide
55e303ae
A
199 what state that will put our device in. Then we embark on the state machine path "IOPMParentDownSetPowerState_Immediate"
200 and "kIOPM_ParentDownWaitForPowerSettleAndNotifyDidChange_Immediate", in which we notify interested parties of the upcoming change, instruct our driver to make
1c79356b
A
201 the change, check for settle time, and notify interested parties of the completed change. If we get to the end of this path without
202 stalling due to an interested party which didn't acknowledge via return code, due to the controlling driver not able to change
203 state right away, or due to a non-zero settling time, then we return IOPMAckImplied to the parent, and we're done with the change.
55e303ae
A
204 If we do stall in any of those states, we return IOPMWillAckLater to the parent and enter the parallel path "kIOPM_ParentDownSetPowerState_Delayed"
205 "kIOPM_ParentDownWaitForPowerSettle_Delayed", and "kIOPM_ParentDownNotifyDidChangeAndAcknowledgeChange_Delayed", where we continue with the same processing, except that at the end we
1c79356b
A
206 acknowledge the parent explicitly via acknowledgePowerChange, and we're done with the change.
207Then when the parent calls us at powerStateDidChange we acknowledging via return code, because we have already made
208 the power change. In any case, when we are done we remove the used change note from the head of the queue and start on the next one.
209
210 The case of the parent raising power in the domain is handled similarly in that there are parallel paths, one for no-stall
211 that ends in implicit acknowleging the parent, and one that has stalled at least once that ends in explicit acknowledging
212 the parent. This case is different, though in that our device changes state in the second half, after the parent calls
213 powerStateDidChange rather than before, as in the power-lowering case.
214
215 When the parent calls our powerDomainWillChange method, notifying us that it will raise power in the domain, we acknowledge
216 via return code, because there's really nothing we can do until the power is actually raised in the domain.
217 When the parent calls us at powerStateDidChange, we start by notifying our interested parties. If they all acknowledge via return code,
55e303ae
A
218 we go on to" kIOPM_ParentUpSetPowerState_Immediate" to instruct the driver to raise its power level. After that, we check for any
219 necessary settling time in "IOPMParentUpWaitForSettleTime_Immediate", and we notify all interested parties that power has changed
220 in "IOPMParentUpNotifyInterestedDriversDidChange_Immediate". If none of these operations stall, we acknowledge the parent via return code, release
221 the change note, and start the next, if there is one. If one of them does stall, we enter the parallel path "kIOPM_ParentUpSetPowerState_Delayed",
222 "kIOPM_ParentUpWaitForSettleTime_Delayed", "kIOPM_ParentUpNotifyInterestedDriversDidChange_Delayed", and "kIOPM_ParentUpAcknowledgePowerChange_Delayed", which ends with
1c79356b
A
223 our explicit acknowledgement to the parent.
224
225*/
226
227
228const char priv_key[ ] = "Power Management private data";
229const char prot_key[ ] = "Power Management protected data";
230
231
232void IOService::PMinit ( void )
233{
234 if ( ! initialized ) {
235
55e303ae
A
236 // make space for our variables
237 pm_vars = new IOPMprot;
1c79356b
A
238 priv = new IOPMpriv;
239 pm_vars->init();
240 priv->init();
241
55e303ae
A
242
243 // add pm_vars & priv to the properties
244 setProperty(prot_key, (OSObject *) pm_vars);
1c79356b
A
245 setProperty(priv_key, (OSObject *) priv);
246
55e303ae 247 // then initialize them
1c79356b 248 priv->owner = this;
55e303ae 249 pm_vars->theNumberOfPowerStates = 0;
1c79356b
A
250 priv->we_are_root = false;
251 pm_vars->theControllingDriver = NULL;
252 priv->our_lock = IOLockAlloc();
253 priv->flags_lock = IOLockAlloc();
0b4e3aa0
A
254 priv->queue_lock = IOLockAlloc();
255 pm_vars->childLock = IOLockAlloc();
256 pm_vars->parentLock = IOLockAlloc();
1c79356b
A
257 priv->interestedDrivers = new IOPMinformeeList;
258 priv->interestedDrivers->initialize();
259 priv->changeList = new IOPMchangeNoteList;
260 priv->changeList->initialize();
261 pm_vars->aggressiveness = 0;
55e303ae
A
262 for (unsigned int i = 0; i <= kMaxType; i++)
263 {
264 pm_vars->current_aggressiveness_values[i] = 0;
265 pm_vars->current_aggressiveness_valid[i] = false;
1c79356b
A
266 }
267 pm_vars->myCurrentState = 0;
268 priv->imminentState = 0;
1c79356b
A
269 priv->ourDesiredPowerState = 0;
270 pm_vars->parentsCurrentPowerFlags = 0;
271 pm_vars->maxCapability = 0;
272 priv->driverDesire = 0;
273 priv->deviceDesire = 0;
274 priv->initial_change = true;
275 priv->need_to_become_usable = false;
276 priv->previousRequest = 0;
277 priv->device_overrides = false;
55e303ae 278 priv->machine_state = kIOPM_Finished;
1c79356b
A
279 priv->timerEventSrc = NULL;
280 priv->clampTimerEventSrc = NULL;
281 pm_vars->PMworkloop = NULL;
282 priv->activityLock = NULL;
283 pm_vars->ourName = getName();
284 pm_vars->thePlatform = getPlatform();
285 pm_vars->parentsKnowState = false;
286 assert( pm_vars->thePlatform != 0 );
287 priv->clampOn = false;
288 pm_vars->serialNumber = 0;
289 pm_vars->responseFlags = NULL;
290 pm_vars->doNotPowerDown = true;
291 pm_vars->PMcommandGate = NULL;
292 priv->ackTimer = thread_call_allocate((thread_call_func_t)ack_timer_expired, (thread_call_param_t)this);
293 priv->settleTimer = thread_call_allocate((thread_call_func_t)settle_timer_expired, (thread_call_param_t)this);
294 initialized = true;
295 }
296}
297
298
0b4e3aa0
A
299//*********************************************************************************
300// PMfree
301//
302// Free up the data created in PMinit, if it exists.
303//*********************************************************************************
304void IOService::PMfree ( void )
305{
306 if ( priv ) {
307 if ( priv->clampTimerEventSrc != NULL ) {
308 getPMworkloop()->removeEventSource(priv->clampTimerEventSrc);
309 priv->clampTimerEventSrc->release();
310 priv->clampTimerEventSrc = NULL;
311 }
312 if ( priv->timerEventSrc != NULL ) {
313 pm_vars->PMworkloop->removeEventSource(priv->timerEventSrc);
314 priv->timerEventSrc->release();
315 priv->timerEventSrc = NULL;
316 }
317 if ( priv->settleTimer ) {
318 thread_call_cancel(priv->settleTimer);
319 thread_call_free(priv->settleTimer);
320 priv->settleTimer = NULL;
321 }
322 if ( priv->ackTimer ) {
323 thread_call_cancel(priv->ackTimer);
324 thread_call_free(priv->ackTimer);
325 priv->ackTimer = NULL;
326 }
327 if ( priv->our_lock ) {
328 IOLockFree(priv->our_lock);
329 priv->our_lock = NULL;
330 }
331 if ( priv->flags_lock ) {
332 IOLockFree(priv->flags_lock);
333 priv->flags_lock = NULL;
334 }
335 if ( priv->activityLock ) {
336 IOLockFree(priv->activityLock);
337 priv->activityLock = NULL;
338 }
339 priv->interestedDrivers->release();
340 priv->changeList->release();
55e303ae
A
341 // remove instance variables
342 priv->release();
0b4e3aa0
A
343 }
344
345 if ( pm_vars ) {
0b4e3aa0 346 if ( pm_vars->PMcommandGate ) {
91447636
A
347 if(pm_vars->PMworkloop)
348 pm_vars->PMworkloop->removeEventSource(pm_vars->PMcommandGate);
0b4e3aa0
A
349 pm_vars->PMcommandGate->release();
350 pm_vars->PMcommandGate = NULL;
351 }
352 if ( pm_vars->PMworkloop ) {
353 // The work loop object returned from getPMworkLoop() is
354 // never retained, therefore it should not be released.
355 // pm_vars->PMworkloop->release();
356 pm_vars->PMworkloop = NULL;
357 }
358 if ( pm_vars->responseFlags ) {
359 pm_vars->responseFlags->release();
360 pm_vars->responseFlags = NULL;
361 }
55e303ae
A
362 // remove instance variables
363 pm_vars->release();
0b4e3aa0
A
364 }
365}
366
367
1c79356b
A
368//*********************************************************************************
369// PMstop
370//
0b4e3aa0 371// Disconnect the node from its parents and children in the Power Plane.
1c79356b
A
372//*********************************************************************************
373void IOService::PMstop ( void )
374{
375 OSIterator * iter;
376 OSObject * next;
377 IOPowerConnection * connection;
0b4e3aa0
A
378 IOService * theChild;
379 IOService * theParent;
1c79356b 380
55e303ae
A
381 // remove the properties
382 removeProperty(prot_key);
1c79356b
A
383 removeProperty(priv_key);
384
55e303ae
A
385 // detach parents
386 iter = getParentIterator(gIOPowerPlane);
1c79356b 387
55e303ae
A
388 if ( iter )
389 {
390 while ( (next = iter->getNextObject()) )
391 {
392 if ( (connection = OSDynamicCast(IOPowerConnection,next)) )
393 {
0b4e3aa0 394 theParent = (IOService *)connection->copyParentEntry(gIOPowerPlane);
55e303ae
A
395 if ( theParent )
396 {
0b4e3aa0
A
397 theParent->removePowerChild(connection);
398 theParent->release();
399 }
1c79356b
A
400 }
401 }
402 iter->release();
403 }
55e303ae
A
404
405 // detach IOConnections
406 detachAbove( gIOPowerPlane );
1c79356b 407
91447636
A
408 if ( pm_vars )
409 {
410 // no more power state changes
411 pm_vars->parentsKnowState = false;
412 }
413
55e303ae
A
414 // detach children
415 iter = getChildIterator(gIOPowerPlane);
1c79356b 416
55e303ae
A
417 if ( iter )
418 {
419 while ( (next = iter->getNextObject()) )
420 {
421 if ( (connection = OSDynamicCast(IOPowerConnection,next)) )
422 {
0b4e3aa0 423 theChild = ((IOService *)(connection->copyChildEntry(gIOPowerPlane)));
55e303ae
A
424 if ( theChild )
425 {
426 // detach nub from child
427 connection->detachFromChild(theChild,gIOPowerPlane);
0b4e3aa0
A
428 theChild->release();
429 }
55e303ae
A
430 // detach us from nub
431 detachFromChild(connection,gIOPowerPlane);
1c79356b
A
432 }
433 }
434 iter->release();
435 }
1c79356b 436
0b4e3aa0
A
437 // Remove all interested drivers from the list, including the power
438 // controlling driver.
439 //
440 // Usually, the controlling driver and the policy-maker functionality
441 // are implemented by the same object, and without the deregistration,
442 // the object will be holding an extra retain on itself, and cannot
443 // be freed.
444
445 if ( priv && priv->interestedDrivers )
446 {
447 IOPMinformee * informee;
1c79356b 448
0b4e3aa0
A
449 while (( informee = priv->interestedDrivers->firstInList() ))
450 deRegisterInterestedDriver( informee->whatObject );
451 }
1c79356b
A
452}
453
454
455//*********************************************************************************
456// joinPMtree
457//
458// A policy-maker calls its nub here when initializing, to be attached into
459// the power management hierarchy. The default function is to call the
460// platform expert, which knows how to do it. This method is overridden
461// by a nub subclass which may either know how to do it, or may need
462// to take other action.
463//
464// This may be the only "power management" method used in a nub,
465// meaning it may not be initialized for power management.
466//*********************************************************************************
467void IOService::joinPMtree ( IOService * driver )
468{
469 IOPlatformExpert * thePlatform;
470
471 thePlatform = getPlatform();
472 assert(thePlatform != 0 );
473 thePlatform->PMRegisterDevice(this,driver);
474}
475
476
477//*********************************************************************************
478// youAreRoot
479//
480// Power Managment is informing us that we are the root power domain.
481// The only difference between us and any other power domain is that
482// we have no parent and therefore never call it.
483//*********************************************************************************
484IOReturn IOService::youAreRoot ( void )
485{
486 priv-> we_are_root = true;
487 pm_vars->parentsKnowState = true;
488 attachToParent( getRegistryRoot(),gIOPowerPlane );
489
490 return IOPMNoErr;
491}
492
493
494//*********************************************************************************
495// setPowerParent
496//
497// Power Management is informing us who our parent is.
498// If we have a controlling driver, find out, given our newly-informed
499// power domain state, what state it would be in, and then tell it
500// to assume that state.
501//*********************************************************************************
502IOReturn IOService::setPowerParent ( IOPowerConnection * theParent, bool stateKnown, IOPMPowerFlags currentState )
503{
504 OSIterator * iter;
505 OSObject * next;
506 IOPowerConnection * connection;
507 unsigned long tempDesire;
508
509 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogSetParent,stateKnown,currentState);
510
0b4e3aa0
A
511 IOLockLock(pm_vars->parentLock);
512
55e303ae
A
513 if ( stateKnown && ((pm_vars->PMworkloop == NULL) || (pm_vars->PMcommandGate == NULL)) )
514 {
515 // we have a path to the root
516 // find out the workloop
517 getPMworkloop();
518 if ( pm_vars->PMworkloop != NULL )
519 {
520 if ( pm_vars->PMcommandGate == NULL )
521 {
522 // and make our command gate
1c79356b 523 pm_vars->PMcommandGate = IOCommandGate::commandGate((OSObject *)this);
55e303ae
A
524 if ( pm_vars->PMcommandGate != NULL )
525 {
1c79356b
A
526 pm_vars->PMworkloop->addEventSource(pm_vars->PMcommandGate);
527 }
528 }
529 }
530 }
531
0b4e3aa0
A
532 IOLockUnlock(pm_vars->parentLock);
533
55e303ae
A
534 // set our connection data
535 theParent->setParentCurrentPowerFlags(currentState);
1c79356b
A
536 theParent->setParentKnowsState(stateKnown);
537
55e303ae
A
538 // combine parent knowledge
539 pm_vars->parentsKnowState = true;
1c79356b
A
540 pm_vars->parentsCurrentPowerFlags = 0;
541
542 iter = getParentIterator(gIOPowerPlane);
543
55e303ae
A
544 if ( iter )
545 {
546 while ( (next = iter->getNextObject()) )
547 {
548 if ( (connection = OSDynamicCast(IOPowerConnection,next)) )
549 {
1c79356b
A
550 pm_vars->parentsKnowState &= connection->parentKnowsState();
551 pm_vars->parentsCurrentPowerFlags |= connection->parentCurrentPowerFlags();
552 }
553 }
554 iter->release();
555 }
556
557 if ( (pm_vars->theControllingDriver != NULL) &&
55e303ae
A
558 (pm_vars->parentsKnowState) )
559 {
1c79356b 560 pm_vars->maxCapability = pm_vars->theControllingDriver->maxCapabilityForDomainState(pm_vars->parentsCurrentPowerFlags);
55e303ae
A
561 // initially change into the state we are already in
562 tempDesire = priv->deviceDesire;
1c79356b 563 priv->deviceDesire = pm_vars->theControllingDriver->initialPowerStateForDomainState(pm_vars->parentsCurrentPowerFlags);
0b4e3aa0
A
564 computeDesiredState();
565 priv->previousRequest = 0xffffffff;
1c79356b 566 changeState();
55e303ae
A
567 // put this back like before
568 priv->deviceDesire = tempDesire;
1c79356b 569 }
0b4e3aa0 570
1c79356b
A
571 return IOPMNoErr;
572}
573
574
575//*********************************************************************************
576// addPowerChild
577//
578// Power Management is informing us who our children are.
579//*********************************************************************************
580IOReturn IOService::addPowerChild ( IOService * theChild )
581{
55e303ae
A
582 IOPowerConnection *connection;
583 unsigned int i;
1c79356b 584
55e303ae
A
585 if ( ! initialized )
586 {
587 // we're not a power-managed IOService
588 return IOPMNotYetInitialized;
1c79356b
A
589 }
590
591 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogAddChild,0,0);
592
55e303ae
A
593 // Put ourselves into a usable power state.
594 // We must be in an "on" power state, as our children must be able to access
595 // our hardware after joining the power plane.
8ad349bb 596 makeUsable();
55e303ae
A
597
598 // make a nub
599 connection = new IOPowerConnection;
1c79356b
A
600
601 connection->init();
602 connection->start(this);
0b4e3aa0 603 connection->setAwaitingAck(false);
55e303ae
A
604
605 // connect it up
606 attachToChild( connection,gIOPowerPlane );
1c79356b
A
607 connection->attachToChild( theChild,gIOPowerPlane );
608 connection->release();
609
55e303ae
A
610 // tell it the current state of the power domain
611 if ( (pm_vars->theControllingDriver == NULL) ||
612 ! (inPlane(gIOPowerPlane)) ||
613 ! (pm_vars->parentsKnowState) )
614 {
1c79356b 615 theChild->setPowerParent(connection,false,0);
55e303ae
A
616 if ( inPlane(gIOPowerPlane) )
617 {
1c79356b 618 for (i = 0; i <= kMaxType; i++) {
55e303ae
A
619 if ( pm_vars->current_aggressiveness_valid[i] )
620 {
1c79356b
A
621 theChild->setAggressiveness (i, pm_vars->current_aggressiveness_values[i]);
622 }
623 }
624 }
55e303ae 625 } else {
1c79356b 626 theChild->setPowerParent(connection,true,pm_vars->thePowerStates[pm_vars->myCurrentState].outputPowerCharacter);
55e303ae
A
627 for (i = 0; i <= kMaxType; i++)
628 {
629 if ( pm_vars->current_aggressiveness_valid[i] )
630 {
1c79356b
A
631 theChild->setAggressiveness (i, pm_vars->current_aggressiveness_values[i]);
632 }
633 }
55e303ae
A
634 // catch it up if change is in progress
635 add_child_to_active_change(connection);
1c79356b
A
636 }
637
638 return IOPMNoErr;
639}
640
641
8ad349bb 642//*********************************************************************************
1c79356b
A
643// removePowerChild
644//
8ad349bb 645//*********************************************************************************
0b4e3aa0
A
646IOReturn IOService::removePowerChild ( IOPowerConnection * theNub )
647{
55e303ae 648 IORegistryEntry *theChild;
8ad349bb 649 OSIterator *iter;
0b4e3aa0 650
1c79356b
A
651 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogRemoveChild,0,0);
652
0b4e3aa0
A
653 theNub->retain();
654
55e303ae
A
655 // detach nub from child
656 theChild = theNub->copyChildEntry(gIOPowerPlane);
657 if ( theChild )
658 {
0b4e3aa0
A
659 theNub->detachFromChild(theChild, gIOPowerPlane);
660 theChild->release();
661 }
55e303ae
A
662 // detach from the nub
663 detachFromChild(theNub,gIOPowerPlane);
0b4e3aa0 664
55e303ae
A
665 // are we awaiting an ack from this child?
666 if ( theNub->getAwaitingAck() )
667 {
668 // yes, pretend we got one
669 theNub->setAwaitingAck(false);
670 if ( acquire_lock() )
671 {
672 if (priv->head_note_pendingAcks != 0 )
673 {
674 // that's one fewer ack to worry about
675 priv->head_note_pendingAcks -= 1;
676 // is that the last?
677 if ( priv->head_note_pendingAcks == 0 )
678 {
679 // yes, stop the timer
680 stop_ack_timer();
0b4e3aa0 681 IOUnlock(priv->our_lock);
55e303ae
A
682 // and now we can continue our power change
683 all_acked();
684 } else {
0b4e3aa0
A
685 IOUnlock(priv->our_lock);
686 }
55e303ae 687 } else {
0b4e3aa0
A
688 IOUnlock(priv->our_lock);
689 }
690 }
691 }
90556fb8 692
0b4e3aa0 693 theNub->release();
1c79356b 694
55e303ae
A
695 // if not fully initialized
696 if ( (pm_vars->theControllingDriver == NULL) ||
697 !(inPlane(gIOPowerPlane)) ||
698 !(pm_vars->parentsKnowState) )
699 {
700 // we can do no more
701 return IOPMNoErr;
1c79356b
A
702 }
703
8ad349bb
A
704 // Perhaps the departing child was holding up idle or system sleep - we need to re-evaluate our
705 // childrens' requests. Clear and re-calculate our kIOPMChildClamp and kIOPMChildClamp2 bits.
90556fb8 706 rebuildChildClampBits();
55e303ae 707
8ad349bb
A
708 if(!priv->clampOn)
709 {
710 // count children
711 iter = getChildIterator(gIOPowerPlane);
712 if ( !iter || !iter->getNextObject() )
713 {
714 // paired to match the makeUsable() call in addPowerChild()
715 changePowerStateToPriv(0);
716 }
717 if(iter) iter->release();
718 }
719
720 // this may be different now
55e303ae 721 computeDesiredState();
8ad349bb 722 // change state if we can now tolerate lower power
55e303ae 723 changeState();
1c79356b
A
724
725 return IOPMNoErr;
726}
727
728
729//*********************************************************************************
730// registerPowerDriver
731//
732// A driver has called us volunteering to control power to our device.
733// If the power state array it provides is richer than the one we already
734// know about (supplied by an earlier volunteer), then accept the offer.
735// Notify all interested parties of our power state, which we now know.
736//*********************************************************************************
737
738IOReturn IOService::registerPowerDriver ( IOService * controllingDriver, IOPMPowerState* powerStates, unsigned long numberOfStates )
739{
55e303ae
A
740 unsigned long i;
741 unsigned long tempDesire;
742
743 if ( (numberOfStates > pm_vars->theNumberOfPowerStates)
744 && (numberOfStates > 1) )
745 {
746 if ( priv->changeList->currentChange() == -1 )
747 {
748 if ( controllingDriver != NULL )
749 {
750 if ( numberOfStates <= IOPMMaxPowerStates )
751 {
752 switch ( powerStates[0].version )
753 {
1c79356b
A
754 case 1:
755 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogControllingDriver,
55e303ae
A
756 (unsigned long)numberOfStates, (unsigned long)powerStates[0].version);
757 for ( i = 0; i < numberOfStates; i++ )
758 {
1c79356b
A
759 pm_vars->thePowerStates[i] = powerStates[i];
760 }
761 break;
762 case 2:
763 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogControllingDriver,
55e303ae
A
764 (unsigned long) numberOfStates,(unsigned long) powerStates[0].version);
765 for ( i = 0; i < numberOfStates; i++ )
766 {
1c79356b
A
767 pm_vars->thePowerStates[i].version = powerStates[i].version;
768 pm_vars->thePowerStates[i].capabilityFlags = powerStates[i].capabilityFlags;
769 pm_vars->thePowerStates[i].outputPowerCharacter = powerStates[i].outputPowerCharacter;
770 pm_vars->thePowerStates[i].inputPowerRequirement = powerStates[i].inputPowerRequirement;
771 pm_vars->thePowerStates[i].staticPower = powerStates[i].staticPower;
772 pm_vars->thePowerStates[i].unbudgetedPower = powerStates[i].unbudgetedPower;
773 pm_vars->thePowerStates[i].powerToAttain = powerStates[i].powerToAttain;
774 pm_vars->thePowerStates[i].timeToAttain = powerStates[i].timeToAttain;
775 pm_vars->thePowerStates[i].settleUpTime = powerStates[i].settleUpTime;
776 pm_vars->thePowerStates[i].timeToLower = powerStates[i].timeToLower;
777 pm_vars->thePowerStates[i].settleDownTime = powerStates[i].settleDownTime;
778 pm_vars->thePowerStates[i].powerDomainBudget = powerStates[i].powerDomainBudget;
779 }
780 break;
781 default:
782 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogControllingDriverErr1,
783 (unsigned long)powerStates[0].version,0);
784 return IOPMNoErr;
785 }
786
55e303ae
A
787 // make a mask of all the character bits we know about
788 pm_vars->myCharacterFlags = 0;
1c79356b
A
789 for ( i = 0; i < numberOfStates; i++ ) {
790 pm_vars->myCharacterFlags |= pm_vars->thePowerStates[i].outputPowerCharacter;
791 }
792
793 pm_vars->theNumberOfPowerStates = numberOfStates;
794 pm_vars->theControllingDriver = controllingDriver;
55e303ae
A
795 if ( priv->interestedDrivers->findItem(controllingDriver) == NULL )
796 {
797 // register it as interested, unless already done
798 registerInterestedDriver (controllingDriver );
1c79356b
A
799 }
800 if ( priv->need_to_become_usable ) {
801 priv->need_to_become_usable = false;
802 priv->deviceDesire = pm_vars->theNumberOfPowerStates - 1;
803 }
804
805 if ( inPlane(gIOPowerPlane) &&
806 (pm_vars->parentsKnowState) ) {
807 pm_vars->maxCapability = pm_vars->theControllingDriver->maxCapabilityForDomainState(pm_vars->parentsCurrentPowerFlags);
55e303ae
A
808 // initially change into the state we are already in
809 tempDesire = priv->deviceDesire;
1c79356b 810 priv->deviceDesire = pm_vars->theControllingDriver->initialPowerStateForDomainState(pm_vars->parentsCurrentPowerFlags);
0b4e3aa0 811 computeDesiredState();
1c79356b 812 changeState();
55e303ae
A
813 // put this back like before
814 priv->deviceDesire = tempDesire;
1c79356b 815 }
55e303ae 816 } else {
1c79356b
A
817 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogControllingDriverErr2,(unsigned long)numberOfStates,0);
818 }
55e303ae 819 } else {
1c79356b
A
820 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogControllingDriverErr4,0,0);
821 }
822 }
823 }
824 else {
825 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogControllingDriverErr5,(unsigned long)numberOfStates,0);
826 }
827 return IOPMNoErr;
828}
829
830//*********************************************************************************
831// registerInterestedDriver
832//
833// Add the caller to our list of interested drivers and return our current
834// power state. If we don't have a power-controlling driver yet, we will
835// call this interested driver again later when we do get a driver and find
836// out what the current power state of the device is.
837//*********************************************************************************
838
839IOPMPowerFlags IOService::registerInterestedDriver ( IOService * theDriver )
840{
55e303ae
A
841 IOPMinformee *newInformee;
842 IOPMPowerFlags futureCapability;
1c79356b
A
843
844 if (theDriver == NULL ) {
845 return 0;
846 }
847
55e303ae
A
848 // make new driver node
849 newInformee = new IOPMinformee;
1c79356b 850 newInformee->initialize(theDriver);
55e303ae
A
851 // add it to list of drivers
852 priv->interestedDrivers->addToList(newInformee);
1c79356b
A
853
854 if ( (pm_vars->theControllingDriver == NULL) ||
55e303ae
A
855 !(inPlane(gIOPowerPlane)) ||
856 !(pm_vars->parentsKnowState) )
857 {
858 // can't tell it a state yet
1c79356b 859 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogInterestedDriver,IOPMNotPowerManaged,0);
55e303ae 860 return IOPMNotPowerManaged;
1c79356b
A
861 }
862
55e303ae
A
863 // can we notify new driver of a change in progress?
864 switch (priv->machine_state) {
865 case kIOPM_OurChangeSetPowerState:
866 case kIOPM_OurChangeFinish:
867 case kIOPM_ParentDownSetPowerState_Delayed:
868 case kIOPM_ParentDownAcknowledgeChange_Delayed:
869 case kIOPM_ParentUpSetPowerState_Delayed:
870 case kIOPM_ParentUpAcknowledgePowerChange_Delayed:
871 // yes, remember what we tell it
872 futureCapability = priv->head_note_capabilityFlags;
1c79356b 873 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogInterestedDriver,(unsigned long)futureCapability,1);
55e303ae
A
874 // notify it
875 add_driver_to_active_change(newInformee);
876 // and return the same thing
877 return futureCapability;
1c79356b
A
878 }
879
880 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogInterestedDriver,
55e303ae
A
881 (unsigned long) pm_vars->thePowerStates[pm_vars->myCurrentState].capabilityFlags,2);
882
883 // no, return current capability
884 return pm_vars->thePowerStates[pm_vars->myCurrentState].capabilityFlags;
1c79356b
A
885}
886
887
888//*********************************************************************************
889// deRegisterInterestedDriver
890//
891//*********************************************************************************
892IOReturn IOService::deRegisterInterestedDriver ( IOService * theDriver )
893{
894 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogRemoveDriver,0,0);
895
55e303ae
A
896 // remove the departing driver
897 priv->interestedDrivers->removeFromList(theDriver);
1c79356b
A
898
899 return IOPMNoErr;
900}
901
902
903//*********************************************************************************
904// acknowledgePowerChange
905//
906// After we notified one of the interested drivers or a power-domain child
907// of an impending change in power, it has called to say it is now
908// prepared for the change. If this object is the last to
909// acknowledge this change, we take whatever action we have been waiting
910// for.
911// That may include acknowledging to our parent. In this case, we do it
912// last of all to insure that this doesn't cause the parent to call us some-
913// where else and alter data we are relying on here (like the very existance
914// of a "current change note".)
915//*********************************************************************************
916
917IOReturn IOService::acknowledgePowerChange ( IOService * whichObject )
918{
55e303ae
A
919 IOPMinformee *ackingObject;
920 unsigned long childPower = kIOPMUnknown;
921 IOService *theChild;
1c79356b 922
55e303ae
A
923 // one of our interested drivers?
924 ackingObject = priv->interestedDrivers->findItem(whichObject);
925 if ( ackingObject == NULL )
926 {
927 if ( ! isChild(whichObject,gIOPowerPlane) )
928 {
929 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogAcknowledgeErr1,0,0);
930 //kprintf("errant driver: %s\n",whichObject->getName());
931 // no, just return
932 return IOPMNoErr;
933 } else {
934 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogChildAcknowledge,priv->head_note_pendingAcks,0);
935 }
936 } else {
937 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogDriverAcknowledge,priv->head_note_pendingAcks,0);
938 }
939
940 if (! acquire_lock() )
941 {
942 return IOPMNoErr;
943 }
944
945 if (priv->head_note_pendingAcks != 0 )
946 {
947 // yes, make sure we're expecting acks
948 if ( ackingObject != NULL )
949 {
950 // it's an interested driver
951 // make sure we're expecting this ack
952 if ( ackingObject->timer != 0 )
953 {
954 // mark it acked
955 ackingObject->timer = 0;
956 // that's one fewer to worry about
957 priv->head_note_pendingAcks -= 1;
958 // is that the last?
959 if ( priv->head_note_pendingAcks == 0 )
960 {
961 // yes, stop the timer
962 stop_ack_timer();
963 IOUnlock(priv->our_lock);
964 // and now we can continue
965 all_acked();
966 return IOPMNoErr;
967 }
968 } else {
969 // this driver has already acked
970 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogAcknowledgeErr2,0,0);
971 //kprintf("errant driver: %s\n",whichObject->getName());
972 }
973 } else {
974 // it's a child
975 // make sure we're expecting this ack
976 if ( ((IOPowerConnection *)whichObject)->getAwaitingAck() )
977 {
978 // that's one fewer to worry about
979 priv->head_note_pendingAcks -= 1;
0b4e3aa0
A
980 ((IOPowerConnection *)whichObject)->setAwaitingAck(false);
981 theChild = (IOService *)whichObject->copyChildEntry(gIOPowerPlane);
55e303ae
A
982 if ( theChild )
983 {
0b4e3aa0
A
984 childPower = theChild->currentPowerConsumption();
985 theChild->release();
986 }
55e303ae
A
987 if ( childPower == kIOPMUnknown )
988 {
0b4e3aa0 989 pm_vars->thePowerStates[priv->head_note_state].staticPower = kIOPMUnknown;
55e303ae
A
990 } else {
991 if ( pm_vars->thePowerStates[priv->head_note_state].staticPower != kIOPMUnknown )
992 {
0b4e3aa0
A
993 pm_vars->thePowerStates[priv->head_note_state].staticPower += childPower;
994 }
995 }
55e303ae
A
996 // is that the last?
997 if ( priv->head_note_pendingAcks == 0 ) {
998 // yes, stop the timer
999 stop_ack_timer();
0b4e3aa0 1000 IOUnlock(priv->our_lock);
55e303ae
A
1001 // and now we can continue
1002 all_acked();
0b4e3aa0
A
1003 return IOPMNoErr;
1004 }
1005 }
55e303ae
A
1006 }
1007 } else {
1008 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogAcknowledgeErr3,0,0); // not expecting anybody to ack
1009 //kprintf("errant driver: %s\n",whichObject->getName());
1c79356b 1010 }
55e303ae
A
1011 IOUnlock(priv->our_lock);
1012 return IOPMNoErr;
1c79356b
A
1013}
1014
1015//*********************************************************************************
1016// acknowledgeSetPowerState
1017//
1018// After we instructed our controlling driver to change power states,
1019// it has called to say it has finished doing so.
1020// We continue to process the power state change.
1021//*********************************************************************************
1022
1023IOReturn IOService::acknowledgeSetPowerState ( void )
1024{
91447636 1025 if (!acquire_lock())
1c79356b 1026 return IOPMNoErr;
9bccf70c 1027
91447636
A
1028 IOReturn timer = priv->driver_timer;
1029 if ( timer == -1 ) {
55e303ae 1030 // driver is acking instead of using return code
91447636 1031 OUR_PMLog(kPMLogDriverAcknowledgeSet, (UInt32) this, timer);
55e303ae 1032 priv->driver_timer = 0;
91447636
A
1033 }
1034 else if ( timer > 0 ) { // are we expecting this?
1035 // yes, stop the timer
1036 stop_ack_timer();
1037 priv->driver_timer = 0;
1038 OUR_PMLog(kPMLogDriverAcknowledgeSet, (UInt32) this, timer);
1039 IOUnlock(priv->our_lock);
1040 driver_acked();
1041 return IOPMNoErr;
55e303ae 1042 } else {
91447636
A
1043 // not expecting this
1044 OUR_PMLog(kPMLogAcknowledgeErr4, (UInt32) this, 0);
1c79356b 1045 }
91447636 1046
1c79356b
A
1047 IOUnlock(priv->our_lock);
1048 return IOPMNoErr;
1049}
1050
1051
1052//*********************************************************************************
1053// driver_acked
1054//
1055// Either the controlling driver has called acknowledgeSetPowerState
1056// or the acknowledgement timer has expired while waiting for that.
1057// We carry on processing the current change note.
1058//*********************************************************************************
1059
1060void IOService::driver_acked ( void )
1061{
1062 switch (priv->machine_state) {
55e303ae
A
1063 case kIOPM_OurChangeWaitForPowerSettle:
1064 OurChangeWaitForPowerSettle();
1c79356b 1065 break;
55e303ae
A
1066 case kIOPM_ParentDownWaitForPowerSettle_Delayed:
1067 ParentDownWaitForPowerSettle_Delayed();
1c79356b 1068 break;
55e303ae
A
1069 case kIOPM_ParentUpWaitForSettleTime_Delayed:
1070 ParentUpWaitForSettleTime_Delayed();
1c79356b
A
1071 break;
1072 }
1073}
1074
1075
1076//*********************************************************************************
1077// powerDomainWillChangeTo
1078//
1079// Called by the power-hierarchy parent notifying of a new power state
1080// in the power domain.
1081// We enqueue a parent power-change to our queue of power changes.
1082// This may or may not cause us to change power, depending on what
1083// kind of change is occuring in the domain.
1084//*********************************************************************************
1085
1086IOReturn IOService::powerDomainWillChangeTo ( IOPMPowerFlags newPowerStateFlags, IOPowerConnection * whichParent )
1087{
55e303ae
A
1088 OSIterator *iter;
1089 OSObject *next;
1090 IOPowerConnection *connection;
1091 unsigned long newStateNumber;
1092 IOPMPowerFlags combinedPowerFlags;
1c79356b
A
1093
1094 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogWillChange,(unsigned long)newPowerStateFlags,0);
1095
55e303ae
A
1096 if ( ! inPlane(gIOPowerPlane) )
1097 {
1098 // somebody goofed
1099 return IOPMAckImplied;
1c79356b
A
1100 }
1101
0b4e3aa0
A
1102 IOLockLock(pm_vars->parentLock);
1103
55e303ae
A
1104 if ( (pm_vars->PMworkloop == NULL) || (pm_vars->PMcommandGate == NULL) )
1105 {
1106 // we have a path to the root
1107 getPMworkloop();
1108 // so find out the workloop
1109 if ( pm_vars->PMworkloop != NULL )
1110 {
1111 // and make our command gate
1112 if ( pm_vars->PMcommandGate == NULL )
1113 {
1c79356b 1114 pm_vars->PMcommandGate = IOCommandGate::commandGate((OSObject *)this);
55e303ae
A
1115 if ( pm_vars->PMcommandGate != NULL )
1116 {
1c79356b
A
1117 pm_vars->PMworkloop->addEventSource(pm_vars->PMcommandGate);
1118 }
1119 }
1120 }
1121 }
1122
0b4e3aa0
A
1123 IOLockUnlock(pm_vars->parentLock);
1124
55e303ae
A
1125 // combine parents' power states
1126 // to determine our maximum state within the new power domain
1127 combinedPowerFlags = 0;
1c79356b
A
1128
1129 iter = getParentIterator(gIOPowerPlane);
1130
55e303ae
A
1131 if ( iter )
1132 {
1133 while ( (next = iter->getNextObject()) )
1134 {
1135 if ( (connection = OSDynamicCast(IOPowerConnection,next)) )
1136 {
1c79356b
A
1137 if ( connection == whichParent ){
1138 combinedPowerFlags |= newPowerStateFlags;
55e303ae 1139 } else {
1c79356b
A
1140 combinedPowerFlags |= connection->parentCurrentPowerFlags();
1141 }
1142 }
1143 }
1144 iter->release();
1145 }
0b4e3aa0 1146
55e303ae
A
1147 if ( pm_vars->theControllingDriver == NULL )
1148 {
1149 // we can't take any more action
1c79356b
A
1150 return IOPMAckImplied;
1151 }
1152 newStateNumber = pm_vars->theControllingDriver->maxCapabilityForDomainState(combinedPowerFlags);
55e303ae 1153 // make the change
0b4e3aa0 1154 return enqueuePowerChange(IOPMParentInitiated | IOPMDomainWillChange,
55e303ae 1155 newStateNumber,combinedPowerFlags,whichParent,newPowerStateFlags);
1c79356b
A
1156}
1157
1158
1159//*********************************************************************************
1160// powerDomainDidChangeTo
1161//
1162// Called by the power-hierarchy parent after the power state of the power domain
1163// has settled at a new level.
1164// We enqueue a parent power-change to our queue of power changes.
1165// This may or may not cause us to change power, depending on what
1166// kind of change is occuring in the domain.
1167//*********************************************************************************
1168
1169IOReturn IOService::powerDomainDidChangeTo ( IOPMPowerFlags newPowerStateFlags, IOPowerConnection * whichParent )
1170{
0b4e3aa0 1171 unsigned long newStateNumber;
1c79356b
A
1172
1173 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogDidChange,newPowerStateFlags,0);
1174
0b4e3aa0
A
1175 setParentInfo(newPowerStateFlags,whichParent);
1176
1177 if ( pm_vars->theControllingDriver == NULL ) {
1178 return IOPMAckImplied;
1179 }
1180
1181 newStateNumber = pm_vars->theControllingDriver->maxCapabilityForDomainState(pm_vars->parentsCurrentPowerFlags);
55e303ae 1182 // tell interested parties about it
0b4e3aa0 1183 return enqueuePowerChange(IOPMParentInitiated | IOPMDomainDidChange,
55e303ae 1184 newStateNumber,pm_vars->parentsCurrentPowerFlags,whichParent,0);
0b4e3aa0
A
1185}
1186
1187
1188//*********************************************************************************
1189// setParentInfo
1190//
1191// Set our connection data for one specific parent, and then combine all the parent
1192// data together.
1193//*********************************************************************************
1194
1195void IOService::setParentInfo ( IOPMPowerFlags newPowerStateFlags, IOPowerConnection * whichParent )
1196{
55e303ae
A
1197 OSIterator *iter;
1198 OSObject *next;
1199 IOPowerConnection *connection;
0b4e3aa0 1200
55e303ae
A
1201 // set our connection data
1202 whichParent->setParentCurrentPowerFlags(newPowerStateFlags);
1c79356b
A
1203 whichParent->setParentKnowsState(true);
1204
0b4e3aa0
A
1205 IOLockLock(pm_vars->parentLock);
1206
55e303ae
A
1207 // recompute our parent info
1208 pm_vars->parentsCurrentPowerFlags = 0;
1c79356b
A
1209 pm_vars->parentsKnowState = true;
1210
1211 iter = getParentIterator(gIOPowerPlane);
1212
55e303ae
A
1213 if ( iter )
1214 {
1215 while ( (next = iter->getNextObject()) )
1216 {
1217 if ( (connection = OSDynamicCast(IOPowerConnection,next)) )
1218 {
1c79356b
A
1219 pm_vars->parentsKnowState &= connection->parentKnowsState();
1220 pm_vars->parentsCurrentPowerFlags |= connection->parentCurrentPowerFlags();
1221 }
1222 }
1223 iter->release();
1224 }
0b4e3aa0 1225 IOLockUnlock(pm_vars->parentLock);
1c79356b
A
1226}
1227
90556fb8
A
1228//*********************************************************************************
1229// rebuildChildClampBits
1230//
1231// The ChildClamp bits (kIOPMChildClamp & kIOPMChildClamp2) in our capabilityFlags
1232// indicate that one of our children (or grandchildren or great-grandchildren or ...)
1233// doesn't support idle or system sleep in its current state. Since we don't track the
1234// origin of each bit, every time any child changes state we have to clear these bits
1235// and rebuild them.
1236//*********************************************************************************
1237
1238void IOService::rebuildChildClampBits(void)
1239{
55e303ae
A
1240 unsigned long i;
1241 OSIterator *iter;
1242 OSObject *next;
1243 IOPowerConnection *connection;
90556fb8
A
1244
1245
1246 // A child's desires has changed. We need to rebuild the child-clamp bits in our
1247 // power state array. Start by clearing the bits in each power state.
1248
55e303ae
A
1249 for ( i = 0; i < pm_vars->theNumberOfPowerStates; i++ )
1250 {
90556fb8
A
1251 pm_vars->thePowerStates[i].capabilityFlags &= ~(kIOPMChildClamp | kIOPMChildClamp2);
1252 }
1253
1254 // Now loop through the children. When we encounter the calling child, save
1255 // the computed state as this child's desire. And while we're at it, set the ChildClamp bits
1256 // in any of our states that some child has requested with clamp on.
1257
1258 iter = getChildIterator(gIOPowerPlane);
1259
1260 if ( iter )
1261 {
1262 while ( (next = iter->getNextObject()) )
1263 {
1264 if ( (connection = OSDynamicCast(IOPowerConnection,next)) )
1265 {
1266 if ( connection->getPreventIdleSleepFlag() )
1267 pm_vars->thePowerStates[connection->getDesiredDomainState()].capabilityFlags |= kIOPMChildClamp;
1268 if ( connection->getPreventSystemSleepFlag() )
1269 pm_vars->thePowerStates[connection->getDesiredDomainState()].capabilityFlags |= kIOPMChildClamp2;
1270 }
1271 }
1272 iter->release();
1273 }
1274
1275}
1276
1c79356b
A
1277
1278//*********************************************************************************
1279// requestPowerDomainState
1280//
0b4e3aa0
A
1281// The kIOPMPreventIdleSleep and/or kIOPMPreventIdleSleep bits may be be set in the parameter.
1282// It is not considered part of the state specification.
1c79356b
A
1283//*********************************************************************************
1284IOReturn IOService::requestPowerDomainState ( IOPMPowerFlags desiredState, IOPowerConnection * whichChild, unsigned long specification )
1285{
55e303ae
A
1286 unsigned long i;
1287 unsigned long computedState;
1288 unsigned long theDesiredState = desiredState & ~(kIOPMPreventIdleSleep | kIOPMPreventSystemSleep);
1289 OSIterator *iter;
1290 OSObject *next;
1291 IOPowerConnection *connection;
1c79356b
A
1292
1293 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogRequestDomain,
1294 (unsigned long)desiredState,(unsigned long)specification);
1295
55e303ae
A
1296 if ( pm_vars->theControllingDriver == NULL)
1297 {
1c79356b
A
1298 return IOPMNotYetInitialized;
1299 }
1300
1301 switch (specification) {
1302 case IOPMLowestState:
1303 i = 0;
55e303ae
A
1304 while ( i < pm_vars->theNumberOfPowerStates )
1305 {
1306 if ( ( pm_vars->thePowerStates[i].outputPowerCharacter & theDesiredState) == (theDesiredState & pm_vars->myCharacterFlags) )
1307 {
1c79356b
A
1308 break;
1309 }
1310 i++;
1311 }
55e303ae
A
1312 if ( i >= pm_vars->theNumberOfPowerStates )
1313 {
1c79356b 1314 return IOPMNoSuchState;
55e303ae 1315 }
1c79356b
A
1316 break;
1317
1318 case IOPMNextLowerState:
1319 i = pm_vars->myCurrentState - 1;
91447636 1320 while ( (int) i >= 0 )
55e303ae
A
1321 {
1322 if ( ( pm_vars->thePowerStates[i].outputPowerCharacter & theDesiredState) == (theDesiredState & pm_vars->myCharacterFlags) )
1323 {
1c79356b
A
1324 break;
1325 }
1326 i--;
1327 }
91447636 1328 if ( (int) i < 0 )
55e303ae 1329 {
1c79356b
A
1330 return IOPMNoSuchState;
1331 }
1332 break;
1333
1334 case IOPMHighestState:
1335 i = pm_vars->theNumberOfPowerStates;
91447636 1336 while ( (int) i >= 0 )
55e303ae 1337 {
1c79356b 1338 i--;
55e303ae
A
1339 if ( ( pm_vars->thePowerStates[i].outputPowerCharacter & theDesiredState) == (theDesiredState & pm_vars->myCharacterFlags) )
1340 {
1c79356b
A
1341 break;
1342 }
1343 }
91447636 1344 if ( (int) i < 0 )
55e303ae 1345 {
1c79356b
A
1346 return IOPMNoSuchState;
1347 }
1348 break;
1349
1350 case IOPMNextHigherState:
1351 i = pm_vars->myCurrentState + 1;
55e303ae
A
1352 while ( i < pm_vars->theNumberOfPowerStates )
1353 {
1354 if ( ( pm_vars->thePowerStates[i].outputPowerCharacter & theDesiredState) == (theDesiredState & pm_vars->myCharacterFlags) )
1355 {
1c79356b
A
1356 break;
1357 }
55e303ae 1358 i++;
1c79356b 1359 }
55e303ae
A
1360 if ( i == pm_vars->theNumberOfPowerStates )
1361 {
1c79356b
A
1362 return IOPMNoSuchState;
1363 }
1364 break;
1365
1366 default:
1367 return IOPMBadSpecification;
1368 }
1369
0b4e3aa0
A
1370 computedState = i;
1371
1372 IOLockLock(pm_vars->childLock);
1373
90556fb8
A
1374 // Now loop through the children. When we encounter the calling child, save
1375 // the computed state as this child's desire.
1c79356b
A
1376 iter = getChildIterator(gIOPowerPlane);
1377
55e303ae
A
1378 if ( iter )
1379 {
1380 while ( (next = iter->getNextObject()) )
1381 {
1382 if ( (connection = OSDynamicCast(IOPowerConnection,next)) )
1383 {
1384 if ( connection == whichChild )
1385 {
0b4e3aa0
A
1386 connection->setDesiredDomainState(computedState);
1387 connection->setPreventIdleSleepFlag(desiredState & kIOPMPreventIdleSleep);
1388 connection->setPreventSystemSleepFlag(desiredState & kIOPMPreventSystemSleep);
1389 connection->setChildHasRequestedPower();
1390 }
1c79356b
A
1391 }
1392 }
1393 iter->release();
1394 }
90556fb8
A
1395
1396 // Since a child's power requirements may have changed, clear and rebuild
1397 // kIOPMChildClamp and kIOPMChildClamp2 (idle and system sleep clamps)
1398 rebuildChildClampBits();
0b4e3aa0
A
1399
1400 IOLockUnlock(pm_vars->childLock);
1401
55e303ae
A
1402 // this may be different now
1403 computeDesiredState();
1c79356b 1404
55e303ae
A
1405 if ( inPlane(gIOPowerPlane) &&
1406 (pm_vars->parentsKnowState) ) {
1407 // change state if all children can now tolerate lower power
1408 changeState();
1409 }
1c79356b 1410
55e303ae
A
1411 // are we clamped on, waiting for this child?
1412 if ( priv->clampOn ) {
1413 // yes, remove the clamp
1414 priv->clampOn = false;
1415 changePowerStateToPriv(0);
1416 }
1c79356b
A
1417
1418 return IOPMNoErr;
1419}
1420
1421
1422//*********************************************************************************
1423// temporaryPowerClampOn
1424//
1425// A power domain wants to clamp its power on till it has children which
1426// will thendetermine the power domain state.
1427//
1428// We enter the highest state until addPowerChild is called.
1429//*********************************************************************************
1430
1431IOReturn IOService::temporaryPowerClampOn ( void )
1432{
1433 priv->clampOn = true;
1434 makeUsable();
1435 return IOPMNoErr;
1436}
1437
1438
1439//*********************************************************************************
1440// makeUsable
1441//
1442// Some client of our device is asking that we become usable. Although
1443// this has not come from a subclassed device object, treat it exactly
1444// as if it had. In this way, subsequent requests for lower power from
1445// a subclassed device object will pre-empt this request.
1446//
1447// We treat this as a subclass object request to switch to the
1448// highest power state.
1449//*********************************************************************************
1450
1451IOReturn IOService::makeUsable ( void )
1452{
1453 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogMakeUsable,0,0);
1454
55e303ae
A
1455 if ( pm_vars->theControllingDriver == NULL )
1456 {
1c79356b
A
1457 priv->need_to_become_usable = true;
1458 return IOPMNoErr;
1459 }
1460 priv->deviceDesire = pm_vars->theNumberOfPowerStates - 1;
0b4e3aa0 1461 computeDesiredState();
55e303ae
A
1462 if ( inPlane(gIOPowerPlane) && (pm_vars->parentsKnowState) )
1463 {
1c79356b
A
1464 return changeState();
1465 }
1466 return IOPMNoErr;
1467}
1468
1469
1470//*********************************************************************************
1471// currentCapability
1472//
1473//*********************************************************************************
1474
1475IOPMPowerFlags IOService::currentCapability ( void )
1476{
55e303ae
A
1477 if ( pm_vars->theControllingDriver == NULL )
1478 {
1c79356b 1479 return 0;
55e303ae 1480 } else {
1c79356b
A
1481 return pm_vars->thePowerStates[pm_vars->myCurrentState].capabilityFlags;
1482 }
1483}
1484
1485
1486//*********************************************************************************
1487// changePowerStateTo
1488//
1489// For some reason, our power-controlling driver has decided it needs to change
1490// power state. We enqueue the power change so that appropriate parties
1491// will be notified, and then we will instruct the driver to make the change.
1492//*********************************************************************************
1493
1494IOReturn IOService::changePowerStateTo ( unsigned long ordinal )
1495{
1496 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogChangeStateTo,ordinal,0);
1497
55e303ae
A
1498 if ( ordinal >= pm_vars->theNumberOfPowerStates )
1499 {
1c79356b
A
1500 return IOPMParameterError;
1501 }
1502 priv->driverDesire = ordinal;
0b4e3aa0 1503 computeDesiredState();
55e303ae
A
1504 if ( inPlane(gIOPowerPlane) && (pm_vars->parentsKnowState) )
1505 {
1c79356b
A
1506 return changeState();
1507 }
1508
1509 return IOPMNoErr;
1510}
1511
1512//*********************************************************************************
1513// changePowerStateToPriv
1514//
1515// For some reason, a subclassed device object has decided it needs to change
1516// power state. We enqueue the power change so that appropriate parties
1517// will be notified, and then we will instruct the driver to make the change.
1518//*********************************************************************************
1519
1520IOReturn IOService::changePowerStateToPriv ( unsigned long ordinal )
1521{
1522 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogChangeStateToPriv,ordinal,0);
1523
55e303ae
A
1524 if ( pm_vars->theControllingDriver == NULL)
1525 {
1c79356b
A
1526 return IOPMNotYetInitialized;
1527 }
55e303ae
A
1528 if ( ordinal >= pm_vars->theNumberOfPowerStates )
1529 {
1c79356b
A
1530 return IOPMParameterError;
1531 }
1532 priv->deviceDesire = ordinal;
0b4e3aa0 1533 computeDesiredState();
55e303ae
A
1534 if ( inPlane(gIOPowerPlane) && (pm_vars->parentsKnowState) )
1535 {
1c79356b
A
1536 return changeState();
1537 }
1538
1539 return IOPMNoErr;
1540}
1541
1542
1543//*********************************************************************************
0b4e3aa0 1544// computeDesiredState
1c79356b 1545//
1c79356b
A
1546//*********************************************************************************
1547
0b4e3aa0 1548void IOService::computeDesiredState ( void )
1c79356b 1549{
55e303ae
A
1550 OSIterator *iter;
1551 OSObject *next;
1552 IOPowerConnection *connection;
1553 unsigned long newDesiredState = 0;
1c79356b
A
1554
1555 // Compute the maximum of our children's desires, our controlling driver's desire, and the subclass device's desire.
55e303ae
A
1556 if ( ! priv->device_overrides )
1557 {
1c79356b
A
1558 iter = getChildIterator(gIOPowerPlane);
1559
55e303ae
A
1560 if ( iter )
1561 {
1562 while ( (next = iter->getNextObject()) )
1563 {
1564 if ( (connection = OSDynamicCast(IOPowerConnection,next)) )
1565 {
1566 if ( connection->getDesiredDomainState() > newDesiredState )
1567 {
1c79356b
A
1568 newDesiredState = connection->getDesiredDomainState();
1569 }
1570 }
1571 }
1572 iter->release();
1573 }
1574
55e303ae
A
1575 if ( priv->driverDesire > newDesiredState )
1576 {
1c79356b
A
1577 newDesiredState = priv->driverDesire;
1578 }
1579 }
1580
55e303ae
A
1581 if ( priv->deviceDesire > newDesiredState )
1582 {
1c79356b
A
1583 newDesiredState = priv->deviceDesire;
1584 }
1585
1586 priv->ourDesiredPowerState = newDesiredState;
0b4e3aa0
A
1587}
1588
1c79356b 1589
0b4e3aa0
A
1590//*********************************************************************************
1591// changeState
1592//
1593// A subclass object, our controlling driver, or a power domain child
1594// has asked for a different power state. Here we compute what new
1595// state we should enter and enqueue the change (or start it).
1596//*********************************************************************************
1597
1598IOReturn IOService::changeState ( void )
1599{
55e303ae
A
1600 // if not fully initialized
1601 if ( (pm_vars->theControllingDriver == NULL) ||
1602 !(inPlane(gIOPowerPlane)) ||
1603 !(pm_vars->parentsKnowState) )
1604 {
1605 // we can do no more
1606 return IOPMNoErr;
1c79356b
A
1607 }
1608
0b4e3aa0 1609 return enqueuePowerChange(IOPMWeInitiated,priv->ourDesiredPowerState,0,0,0);
1c79356b
A
1610}
1611
1612
1613//*********************************************************************************
1614// currentPowerConsumption
1615//
1616//*********************************************************************************
1617
1618unsigned long IOService::currentPowerConsumption ( void )
1619{
55e303ae
A
1620 if ( pm_vars->theControllingDriver == NULL )
1621 {
0b4e3aa0 1622 return kIOPMUnknown;
1c79356b 1623 }
55e303ae
A
1624 if ( pm_vars->thePowerStates[pm_vars->myCurrentState].capabilityFlags & kIOPMStaticPowerValid )
1625 {
1c79356b
A
1626 return pm_vars->thePowerStates[pm_vars->myCurrentState].staticPower;
1627 }
0b4e3aa0 1628 return kIOPMUnknown;
1c79356b
A
1629}
1630
1631//*********************************************************************************
1632// activityTickle
1633//
1634// The activity tickle with parameter kIOPMSubclassPolicyis not handled
1635// here and should have been intercepted by the subclass.
1636// The tickle with parameter kIOPMSuperclassPolicy1 causes the activity
1637// flag to be set, and the device state checked. If the device has been
1638// powered down, it is powered up again.
1639//*********************************************************************************
1640
55e303ae 1641bool IOService::activityTickle ( unsigned long type, unsigned long stateNumber )
1c79356b 1642{
55e303ae
A
1643 IOPMrootDomain *pmRootDomain;
1644 AbsoluteTime uptime;
e7c99d92 1645
55e303ae
A
1646 if ( type == kIOPMSuperclassPolicy1 )
1647 {
1648 if ( pm_vars->theControllingDriver == NULL )
1649 {
1c79356b
A
1650 return true;
1651 }
55e303ae
A
1652
1653 if( priv->activityLock == NULL )
1654 {
1655 priv->activityLock = IOLockAlloc();
1656 }
1657
1c79356b
A
1658 IOTakeLock(priv->activityLock);
1659 priv->device_active = true;
e7c99d92
A
1660
1661 clock_get_uptime(&uptime);
1662 priv->device_active_timestamp = uptime;
1663
55e303ae
A
1664 if ( pm_vars->myCurrentState >= stateNumber)
1665 {
1c79356b
A
1666 IOUnlock(priv->activityLock);
1667 return true;
1668 }
9bccf70c 1669 IOUnlock(priv->activityLock);
91447636 1670
55e303ae
A
1671 // Transfer execution to the PM workloop
1672 if( (pmRootDomain = getPMRootDomain()) )
1673 pmRootDomain->unIdleDevice(this, stateNumber);
1674
1c79356b
A
1675 return false;
1676 }
1677 return true;
1678}
1679
1680//*********************************************************************************
1681// getPMworkloop
1682//
1683// A child is calling to get a pointer to the Power Management workloop.
1684// We got it or get it from one of our parents.
1685//*********************************************************************************
1686
1687IOWorkLoop * IOService::getPMworkloop ( void )
1688{
55e303ae
A
1689 IOService *nub;
1690 IOService *parent;
1c79356b 1691
55e303ae
A
1692 if ( ! inPlane(gIOPowerPlane) )
1693 {
1c79356b
A
1694 return NULL;
1695 }
55e303ae
A
1696 // we have no workloop yet
1697 if ( pm_vars->PMworkloop == NULL )
1698 {
0b4e3aa0 1699 nub = (IOService *)copyParentEntry(gIOPowerPlane);
55e303ae
A
1700 if ( nub )
1701 {
0b4e3aa0
A
1702 parent = (IOService *)nub->copyParentEntry(gIOPowerPlane);
1703 nub->release();
55e303ae
A
1704 // ask one of our parents for the workloop
1705 if ( parent )
1706 {
0b4e3aa0
A
1707 pm_vars->PMworkloop = parent->getPMworkloop();
1708 parent->release();
1709 }
1c79356b
A
1710 }
1711 }
1712 return pm_vars->PMworkloop;
1713}
1714
1715
1716//*********************************************************************************
1717// setIdleTimerPeriod
1718//
1719// A subclass policy-maker is going to use our standard idleness
1720// detection service. Make a command queue and an idle timer and
1721// connect them to the power management workloop. Finally,
1722// start the timer.
1723//*********************************************************************************
1724
1725IOReturn IOService::setIdleTimerPeriod ( unsigned long period )
1726{
1727 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMsetIdleTimerPeriod,period, 0);
1728
1729 priv->idle_timer_period = period;
1730
55e303ae
A
1731 if ( period > 0 )
1732 {
1733 if ( getPMworkloop() == NULL )
1734 {
1c79356b
A
1735 return kIOReturnError;
1736 }
55e303ae
A
1737
1738 // make the timer event
1739 if ( priv->timerEventSrc == NULL )
1740 {
1c79356b
A
1741 priv->timerEventSrc = IOTimerEventSource::timerEventSource(this,
1742 PM_idle_timer_expired);
55e303ae
A
1743 if ((!priv->timerEventSrc) ||
1744 (pm_vars->PMworkloop->addEventSource(priv->timerEventSrc) != kIOReturnSuccess) )
1745 {
1c79356b
A
1746 return kIOReturnError;
1747 }
1748 }
1749
55e303ae
A
1750 if ( priv->activityLock == NULL )
1751 {
1c79356b
A
1752 priv->activityLock = IOLockAlloc();
1753 }
1754
1755 start_PM_idle_timer();
1756 }
1757 return IOPMNoErr;
1758}
1759
91447636
A
1760//******************************************************************************
1761// nextIdleTimeout
1762//
1763// Returns how many "seconds from now" the device should idle into its
1764// next lowest power state.
1765//******************************************************************************
1766SInt32 IOService::nextIdleTimeout(
1767 AbsoluteTime currentTime,
1768 AbsoluteTime lastActivity,
1769 unsigned int powerState)
1770{
1771 AbsoluteTime delta;
1772 UInt64 delta_ns;
1773 SInt32 delta_secs;
1774 SInt32 delay_secs;
1c79356b 1775
91447636
A
1776 // Calculate time difference using funky macro from clock.h.
1777 delta = currentTime;
1778 SUB_ABSOLUTETIME(&delta, &lastActivity);
1779
1780 // Figure it in seconds.
1781 absolutetime_to_nanoseconds(delta, &delta_ns);
1782 delta_secs = (SInt32)(delta_ns / NSEC_PER_SEC);
1783
1784 // Be paranoid about delta somehow exceeding timer period.
1785 if (delta_secs < (int) priv->idle_timer_period )
1786 delay_secs = (int) priv->idle_timer_period - delta_secs;
1787 else
1788 delay_secs = (int) priv->idle_timer_period;
1789
1790 return (SInt32)delay_secs;
1791}
1792
1793//******************************************************************************
1c79356b
A
1794// start_PM_idle_timer
1795//
1796// The parameter is a pointer to us. Use it to call our timeout method.
91447636 1797//******************************************************************************
1c79356b
A
1798void IOService::start_PM_idle_timer ( void )
1799{
91447636
A
1800 static const int maxTimeout = 100000;
1801 static const int minTimeout = 1;
55e303ae 1802 AbsoluteTime uptime;
91447636 1803 SInt32 idle_in = 0;
e7c99d92
A
1804
1805 IOLockLock(priv->activityLock);
1806
1807 clock_get_uptime(&uptime);
91447636
A
1808
1809 // Subclasses may modify idle sleep algorithm
1810 idle_in = nextIdleTimeout(uptime,
1811 priv->device_active_timestamp,
1812 pm_vars->myCurrentState);
e7c99d92 1813
91447636
A
1814 // Check for out-of range responses
1815 if(idle_in > maxTimeout)
55e303ae 1816 {
91447636
A
1817 // use standard implementation
1818 idle_in = IOService::nextIdleTimeout(uptime,
1819 priv->device_active_timestamp,
1820 pm_vars->myCurrentState);
1821 } else if(idle_in < minTimeout) {
1822 // fire immediately
1823 idle_in = 0;
e7c99d92
A
1824 }
1825
91447636 1826 priv->timerEventSrc->setTimeout(idle_in, NSEC_PER_SEC);
e7c99d92
A
1827
1828 IOLockUnlock(priv->activityLock);
1829 return;
1c79356b
A
1830}
1831
1832
1833//*********************************************************************************
1834// PM_idle_timer_expired
1835//
1836// The parameter is a pointer to us. Use it to call our timeout method.
1837//*********************************************************************************
1838
1839void PM_idle_timer_expired(OSObject * ourSelves, IOTimerEventSource *)
1840{
1841 ((IOService *)ourSelves)->PM_idle_timer_expiration();
1842}
1843
1844
1845//*********************************************************************************
1846// PM_idle_timer_expiration
1847//
1848// The idle timer has expired. If there has been activity since the last
1849// expiration, just restart the timer and return. If there has not been
1850// activity, switch to the next lower power state and restart the timer.
1851//*********************************************************************************
1852
1853void IOService::PM_idle_timer_expiration ( void )
1854{
55e303ae
A
1855 if ( ! initialized )
1856 {
1857 // we're unloading
1858 return;
1c79356b
A
1859 }
1860
55e303ae
A
1861 if ( priv->idle_timer_period > 0 )
1862 {
1c79356b 1863 IOTakeLock(priv->activityLock);
55e303ae
A
1864 if ( priv->device_active )
1865 {
1c79356b
A
1866 priv->device_active = false;
1867 IOUnlock(priv->activityLock);
1868 start_PM_idle_timer();
1869 return;
1870 }
55e303ae
A
1871 if ( pm_vars->myCurrentState > 0 )
1872 {
1c79356b 1873 IOUnlock(priv->activityLock);
8ad349bb
A
1874 changePowerStateToPriv(pm_vars->myCurrentState - 1);
1875 start_PM_idle_timer();
1c79356b
A
1876 return;
1877 }
1878 IOUnlock(priv->activityLock);
1879 start_PM_idle_timer();
1880 }
1881}
1882
1883
1c79356b 1884// **********************************************************************************
55e303ae 1885// command_received
1c79356b 1886//
55e303ae
A
1887// We are un-idling a device due to its activity tickle. This routine runs on the
1888// PM workloop, and is initiated by IOService::activityTickle.
1889// We process all activityTickle state requests on the list.
1c79356b 1890// **********************************************************************************
55e303ae 1891void IOService::command_received ( void *statePtr , void *, void * , void * )
1c79356b 1892{
55e303ae 1893 unsigned long stateNumber;
1c79356b 1894
55e303ae 1895 stateNumber = (unsigned long)statePtr;
1c79356b 1896
55e303ae
A
1897 // If not initialized, we're unloading
1898 if ( ! initialized ) return;
1c79356b 1899
55e303ae
A
1900 if ( (pm_vars->myCurrentState < stateNumber) &&
1901 (priv->imminentState < stateNumber) )
1902 {
1903 changePowerStateToPriv(stateNumber);
91447636
A
1904
1905 // After we raise our state, re-schedule the idle timer.
1906 if(priv->timerEventSrc)
1907 start_PM_idle_timer();
1c79356b
A
1908 }
1909}
1910
1911
1912//*********************************************************************************
1913// setAggressiveness
1914//
1915// Pass on the input parameters to all power domain children. All those which are
1916// power domains will pass it on to their children, etc.
1917//*********************************************************************************
1918
1919IOReturn IOService::setAggressiveness ( unsigned long type, unsigned long newLevel )
1920{
55e303ae
A
1921 OSIterator *iter;
1922 OSObject *next;
1923 IOPowerConnection *connection;
1924 IOService *child;
1c79356b
A
1925
1926 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogSetAggressiveness,type, newLevel);
1927
55e303ae
A
1928 if ( type <= kMaxType )
1929 {
1c79356b
A
1930 pm_vars->current_aggressiveness_values[type] = newLevel;
1931 pm_vars->current_aggressiveness_valid[type] = true;
1932 }
1933
1934 iter = getChildIterator(gIOPowerPlane);
1935
55e303ae
A
1936 if ( iter )
1937 {
1938 while ( (next = iter->getNextObject()) )
1939 {
1940 if ( (connection = OSDynamicCast(IOPowerConnection,next)) )
1941 {
0b4e3aa0 1942 child = ((IOService *)(connection->copyChildEntry(gIOPowerPlane)));
55e303ae
A
1943 if ( child )
1944 {
0b4e3aa0
A
1945 child->setAggressiveness(type, newLevel);
1946 child->release();
1947 }
1c79356b
A
1948 }
1949 }
1950 iter->release();
1951 }
1952
1953 return IOPMNoErr;
1954}
1955
1956//*********************************************************************************
1957// getAggressiveness
1958//
1959// Called by the user client.
1960//*********************************************************************************
1961
1962IOReturn IOService::getAggressiveness ( unsigned long type, unsigned long * currentLevel )
1963{
91447636
A
1964 if ( type > kMaxType )
1965 return kIOReturnBadArgument;
55e303ae
A
1966
1967 if ( !pm_vars->current_aggressiveness_valid[type] )
1968 return kIOReturnInvalid;
1969
1970 *currentLevel = pm_vars->current_aggressiveness_values[type];
1971
1c79356b
A
1972 return kIOReturnSuccess;
1973}
1974
1975//*********************************************************************************
1976// systemWake
1977//
1978// Pass this to all power domain children. All those which are
1979// power domains will pass it on to their children, etc.
1980//*********************************************************************************
1981
1982IOReturn IOService::systemWake ( void )
1983{
55e303ae
A
1984 OSIterator *iter;
1985 OSObject *next;
1986 IOPowerConnection *connection;
1987 IOService *theChild;
1c79356b
A
1988
1989 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogSystemWake,0, 0);
1990
1991 iter = getChildIterator(gIOPowerPlane);
1992
55e303ae
A
1993 if ( iter )
1994 {
1995 while ( (next = iter->getNextObject()) )
1996 {
1997 if ( (connection = OSDynamicCast(IOPowerConnection,next)) )
1998 {
0b4e3aa0 1999 theChild = (IOService *)connection->copyChildEntry(gIOPowerPlane);
55e303ae
A
2000 if ( theChild )
2001 {
0b4e3aa0 2002 theChild->systemWake();
55e303ae 2003 theChild->release();
0b4e3aa0 2004 }
1c79356b
A
2005 }
2006 }
2007 iter->release();
2008 }
2009
55e303ae
A
2010 if ( pm_vars->theControllingDriver != NULL )
2011 {
2012 if ( pm_vars->theControllingDriver->didYouWakeSystem() )
2013 {
1c79356b
A
2014 makeUsable();
2015 }
2016 }
2017
2018 return IOPMNoErr;
2019}
2020
2021
2022//*********************************************************************************
2023// temperatureCriticalForZone
2024//
2025//*********************************************************************************
2026
2027IOReturn IOService::temperatureCriticalForZone ( IOService * whichZone )
2028{
55e303ae
A
2029 IOService *theParent;
2030 IOService *theNub;
0b4e3aa0 2031
1c79356b
A
2032 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogCriticalTemp,0,0);
2033
55e303ae
A
2034 if ( inPlane(gIOPowerPlane) && !(priv->we_are_root) )
2035 {
0b4e3aa0 2036 theNub = (IOService *)copyParentEntry(gIOPowerPlane);
55e303ae
A
2037 if ( theNub )
2038 {
0b4e3aa0
A
2039 theParent = (IOService *)theNub->copyParentEntry(gIOPowerPlane);
2040 theNub->release();
55e303ae
A
2041 if ( theParent )
2042 {
0b4e3aa0
A
2043 theParent->temperatureCriticalForZone(whichZone);
2044 theParent->release();
2045 }
2046 }
1c79356b
A
2047 }
2048 return IOPMNoErr;
2049}
2050
2051
2052//*********************************************************************************
2053// powerOverrideOnPriv
2054//
2055//*********************************************************************************
2056
2057
2058IOReturn IOService::powerOverrideOnPriv ( void )
2059{
2060 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogOverrideOn,0,0);
2061
55e303ae
A
2062 // turn on the override
2063 priv->device_overrides = true;
0b4e3aa0 2064 computeDesiredState();
55e303ae
A
2065
2066 // change state if that changed something
2067 return changeState();
1c79356b
A
2068}
2069
2070
2071//*********************************************************************************
2072// powerOverrideOffPriv
2073//
2074//*********************************************************************************
2075IOReturn IOService::powerOverrideOffPriv ( void )
2076{
2077 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogOverrideOff,0,0);
2078
55e303ae
A
2079 // turn off the override
2080 priv->device_overrides = false;
0b4e3aa0
A
2081 computeDesiredState();
2082 if( priv->clampOn)
55e303ae 2083 {
0b4e3aa0 2084 return makeUsable();
55e303ae
A
2085 } else {
2086 // change state if that changed something
2087 return changeState();
2088 }
1c79356b
A
2089}
2090
2091
2092//*********************************************************************************
2093// enqueuePowerChange
2094//
2095// Allocate a new state change notification, initialize it with fields from the
2096// caller, and add it to the tail of the list of pending power changes.
2097//
2098// If it is early enough in the list, and almost all the time it is the only one in
2099// the list, start the power change.
2100//
2101// In rare instances, this change will preempt the previous change in the list.
2102// If the previous change is un-actioned in any way (because we are still
2103// processing an even earlier power change), and if both the previous change
2104// in the list and this change are initiated by us (not the parent), then we
2105// needn't perform the previous change, so we collapse the list a little.
2106//*********************************************************************************
2107
8ad349bb 2108IOReturn IOService::enqueuePowerChange ( unsigned long flags, unsigned long whatStateOrdinal, unsigned long domainState, IOPowerConnection * whichParent, unsigned long singleParentState )
1c79356b 2109{
55e303ae
A
2110 long newNote;
2111 long previousNote;
1c79356b 2112
55e303ae 2113 // Create and initialize the new change note
1c79356b 2114
0b4e3aa0 2115 IOLockLock(priv->queue_lock);
1c79356b
A
2116 newNote = priv->changeList->createChangeNote();
2117 if ( newNote == -1 ) {
55e303ae 2118 // uh-oh, our list is full
0b4e3aa0 2119 IOLockUnlock(priv->queue_lock);
1c79356b 2120 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogEnqueueErr,0,0);
55e303ae 2121 return IOPMAckImplied;
1c79356b
A
2122 }
2123
2124 priv->changeList->changeNote[newNote].newStateNumber = whatStateOrdinal;
55e303ae
A
2125 priv->changeList->changeNote[newNote].outputPowerCharacter = pm_vars->thePowerStates[whatStateOrdinal].outputPowerCharacter;
2126 priv->changeList->changeNote[newNote].inputPowerRequirement = pm_vars->thePowerStates[whatStateOrdinal].inputPowerRequirement;
2127 priv->changeList->changeNote[newNote].capabilityFlags = pm_vars->thePowerStates[whatStateOrdinal].capabilityFlags;
1c79356b 2128 priv->changeList->changeNote[newNote].flags = flags;
55e303ae
A
2129 priv->changeList->changeNote[newNote].parent = NULL;
2130 if (flags & IOPMParentInitiated )
2131 {
2132 priv->changeList->changeNote[newNote].domainState = domainState;
2133 priv->changeList->changeNote[newNote].parent = whichParent;
0b4e3aa0 2134 whichParent->retain();
55e303ae 2135 priv->changeList->changeNote[newNote].singleParentState = singleParentState;
1c79356b
A
2136 }
2137
2138 previousNote = priv->changeList->previousChangeNote(newNote);
2139
55e303ae
A
2140 if ( previousNote == -1 )
2141 {
1c79356b
A
2142
2143 // Queue is empty, we can start this change.
2144
55e303ae
A
2145 if (flags & IOPMWeInitiated )
2146 {
0b4e3aa0 2147 IOLockUnlock(priv->queue_lock);
1c79356b
A
2148 start_our_change(newNote);
2149 return 0;
55e303ae 2150 } else {
0b4e3aa0 2151 IOLockUnlock(priv->queue_lock);
1c79356b
A
2152 return start_parent_change(newNote);
2153 }
2154 }
2155
2156 // The queue is not empty. Try to collapse this new change and the previous one in queue into one change.
2157 // This is possible only if both changes are initiated by us, and neither has been started yet.
2158 // Do this more than once if possible.
2159
2160 // (A change is started iff it is at the head of the queue)
2161
2162 while ( (previousNote != priv->head_note) && (previousNote != -1) &&
55e303ae
A
2163 (priv->changeList->changeNote[newNote].flags & priv->changeList->changeNote[previousNote].flags & IOPMWeInitiated) )
2164 {
1c79356b
A
2165 priv->changeList->changeNote[previousNote].outputPowerCharacter = priv->changeList->changeNote[newNote].outputPowerCharacter;
2166 priv->changeList->changeNote[previousNote].inputPowerRequirement = priv->changeList->changeNote[newNote].inputPowerRequirement;
2167 priv->changeList->changeNote[previousNote].capabilityFlags =priv-> changeList->changeNote[newNote].capabilityFlags;
0b4e3aa0
A
2168 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogCollapseQueue,priv->changeList->changeNote[newNote].newStateNumber,
2169 priv->changeList->changeNote[previousNote].newStateNumber);
1c79356b
A
2170 priv->changeList->changeNote[previousNote].newStateNumber = priv->changeList->changeNote[newNote].newStateNumber;
2171 priv->changeList->releaseTailChangeNote();
2172 newNote = previousNote;
2173 previousNote = priv->changeList->previousChangeNote(newNote);
1c79356b 2174 }
0b4e3aa0 2175 IOLockUnlock(priv->queue_lock);
55e303ae
A
2176 // in any case, we can't start yet
2177 return IOPMWillAckLater;
1c79356b
A
2178}
2179
1c79356b
A
2180//*********************************************************************************
2181// notifyAll
2182//
2183// Notify all interested parties either that a change is impending or that the
2184// previously-notified change is done and power has settled.
2185// The parameter identifies whether this is the
2186// pre-change notification or the post-change notification.
2187//
2188//*********************************************************************************
2189
2190IOReturn IOService::notifyAll ( bool is_prechange )
2191{
2192 IOPMinformee * nextObject;
2193 OSIterator * iter;
2194 OSObject * next;
2195 IOPowerConnection * connection;
2196
8ad349bb
A
2197 // To prevent acknowledgePowerChange from finishing the change note and removing it from the queue if
2198 // some driver calls it, we inflate the number of pending acks so it cannot become zero. We'll fix it later.
1c79356b 2199
8ad349bb
A
2200 priv->head_note_pendingAcks =1;
2201
2202 // OK, we will go through the lists of interested drivers and power domain children
2203 // and notify each one of this change.
55e303ae
A
2204
2205 nextObject = priv->interestedDrivers->firstInList();
1c79356b
A
2206 while ( nextObject != NULL ) {
2207 priv->head_note_pendingAcks +=1;
8ad349bb 2208 if (! inform(nextObject, is_prechange) )
55e303ae 2209 {
1c79356b
A
2210 }
2211 nextObject = priv->interestedDrivers->nextInList(nextObject);
2212 }
2213
8ad349bb
A
2214 if (! acquire_lock() ) {
2215 return IOPMNoErr;
2216 }
55e303ae
A
2217 // did they all ack?
2218 if ( priv->head_note_pendingAcks > 1 ) {
2219 // no
2220 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogStartAckTimer,0,0);
1c79356b
A
2221 start_ack_timer();
2222 }
55e303ae
A
2223 // either way
2224 IOUnlock(priv->our_lock);
1c79356b 2225
55e303ae
A
2226 // notify children
2227 iter = getChildIterator(gIOPowerPlane);
2228 // summing their power consumption
2229 pm_vars->thePowerStates[priv->head_note_state].staticPower = 0;
1c79356b 2230
8ad349bb 2231 if ( iter )
55e303ae
A
2232 {
2233 while ( (next = iter->getNextObject()) )
2234 {
2235 if ( (connection = OSDynamicCast(IOPowerConnection,next)) )
2236 {
1c79356b
A
2237 priv->head_note_pendingAcks +=1;
2238 notifyChild(connection, is_prechange);
2239 }
2240 }
2241 iter->release();
2242 }
2243
2244 if (! acquire_lock() ) {
2245 return IOPMNoErr;
2246 }
55e303ae
A
2247 // now make this real
2248 priv->head_note_pendingAcks -= 1;
2249 // is it all acked?
2250 if (priv->head_note_pendingAcks == 0 ) {
2251 // yes, all acked
2252 IOUnlock(priv->our_lock);
2253 // return ack to parent
2254 return IOPMAckImplied;
1c79356b 2255 }
55e303ae
A
2256
2257 // not all acked
2258 IOUnlock(priv->our_lock);
1c79356b
A
2259 return IOPMWillAckLater;
2260}
2261
2262
2263//*********************************************************************************
2264// notifyChild
2265//
2266// Notify a power domain child of an upcoming power change.
2267//
2268// If the object acknowledges the current change, we return TRUE.
2269//*********************************************************************************
2270
2271bool IOService::notifyChild ( IOPowerConnection * theNub, bool is_prechange )
2272{
55e303ae
A
2273 IOReturn k = IOPMAckImplied;
2274 unsigned long childPower;
3a60a9f5 2275 IOService *theChild;
55e303ae 2276
3a60a9f5
A
2277 theChild = (IOService *)(theNub->copyChildEntry(gIOPowerPlane));
2278 if(!theChild)
55e303ae 2279 {
3a60a9f5
A
2280 // The child has been detached since we grabbed the child iterator.
2281 // Decrement pending_acks, already incremented in notifyAll,
2282 // to account for this unexpected departure.
8ad349bb 2283 priv->head_note_pendingAcks--;
0b4e3aa0 2284 return true;
55e303ae
A
2285 }
2286
3a60a9f5
A
2287 // Unless the child handles the notification immediately and returns
2288 // kIOPMAckImplied, we'll be awaiting their acknowledgement later.
2289 theNub->setAwaitingAck(true);
2290
55e303ae
A
2291 if ( is_prechange )
2292 {
2293 k = theChild->powerDomainWillChangeTo(priv->head_note_outputFlags,theNub);
2294 } else {
2295 k = theChild->powerDomainDidChangeTo(priv->head_note_outputFlags,theNub);
2296 }
2297
2298 // did the return code ack?
2299 if ( k == IOPMAckImplied )
2300 {
2301 // yes
8ad349bb 2302 priv->head_note_pendingAcks--;
0b4e3aa0
A
2303 theNub->setAwaitingAck(false);
2304 childPower = theChild->currentPowerConsumption();
55e303ae
A
2305 if ( childPower == kIOPMUnknown )
2306 {
0b4e3aa0 2307 pm_vars->thePowerStates[priv->head_note_state].staticPower = kIOPMUnknown;
55e303ae
A
2308 } else {
2309 if ( pm_vars->thePowerStates[priv->head_note_state].staticPower != kIOPMUnknown )
2310 {
0b4e3aa0
A
2311 pm_vars->thePowerStates[priv->head_note_state].staticPower += childPower;
2312 }
2313 }
2314 theChild->release();
55e303ae
A
2315 return true;
2316 }
2317 theChild->release();
2318 return false;
1c79356b
A
2319}
2320
2321
2322//*********************************************************************************
2323// inform
2324//
2325// Notify an interested driver of an upcoming power change.
2326//
2327// If the object acknowledges the current change, we return TRUE.
2328//*********************************************************************************
2329
2330bool IOService::inform ( IOPMinformee * nextObject, bool is_prechange )
2331{
55e303ae 2332 IOReturn k = IOPMAckImplied;
1c79356b 2333
55e303ae
A
2334 // initialize this
2335 nextObject->timer = -1;
2336
2337 if ( is_prechange )
2338 {
2339 pm_vars->thePlatform->PMLog (pm_vars->ourName,PMlogInformDriverPreChange,
1c79356b 2340 (unsigned long)priv->head_note_capabilityFlags,(unsigned long)priv->head_note_state);
55e303ae
A
2341 k = nextObject->whatObject->powerStateWillChangeTo( priv->head_note_capabilityFlags,priv->head_note_state,this);
2342 } else {
2343 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogInformDriverPostChange,
2344 (unsigned long)priv->head_note_capabilityFlags,(unsigned long)priv->head_note_state);
2345 k = nextObject->whatObject->powerStateDidChangeTo(priv->head_note_capabilityFlags,priv->head_note_state,this);
2346 }
2347
2348 // did it ack behind our back?
2349 if ( nextObject->timer == 0 )
2350 {
2351 // yes
2352 return true;
2353 }
2354
8ad349bb
A
2355 // no, did the return code ack?
2356 if ( k ==IOPMAckImplied )
55e303ae
A
2357 {
2358 // yes
2359 nextObject->timer = 0;
8ad349bb
A
2360 priv->head_note_pendingAcks -= 1;
2361 return true;
2362 }
2363 if ( k<0 )
2364 {
2365 // somebody goofed
2366 nextObject->timer = 0;
2367 priv-> head_note_pendingAcks -= 1;
55e303ae
A
2368 return true;
2369 }
2370
2371 // no, it's a timer
2372 nextObject->timer = (k / (ACK_TIMER_PERIOD / ns_per_us)) + 1;
2373
2374 return false;
1c79356b
A
2375}
2376
2377
2378//*********************************************************************************
55e303ae 2379// OurChangeTellClientsPowerDown
1c79356b
A
2380//
2381// All registered applications and kernel clients have positively acknowledged our
2382// intention of lowering power. Here we notify them all that we will definitely
2383// lower the power. If we don't have to wait for any of them to acknowledge, we
2384// carry on by notifying interested drivers. Otherwise, we do wait.
2385//*********************************************************************************
2386
55e303ae 2387void IOService::OurChangeTellClientsPowerDown ( void )
0b4e3aa0 2388{
55e303ae
A
2389 // next state
2390 priv->machine_state = kIOPM_OurChangeTellPriorityClientsPowerDown;
2391
2392 // are we waiting for responses?
2393 if ( tellChangeDown1(priv->head_note_state) )
2394 {
2395 // no, notify priority clients
2396 OurChangeTellPriorityClientsPowerDown();
0b4e3aa0 2397 }
55e303ae
A
2398 // If we are waiting for responses, execution will resume via
2399 // allowCancelCommon() or ack timeout
0b4e3aa0
A
2400}
2401
2402
2403//*********************************************************************************
55e303ae 2404// OurChangeTellPriorityClientsPowerDown
0b4e3aa0
A
2405//
2406// All registered applications and kernel clients have positively acknowledged our
2407// intention of lowering power. Here we notify "priority" clients that we are
2408// lowering power. If we don't have to wait for any of them to acknowledge, we
2409// carry on by notifying interested drivers. Otherwise, we do wait.
2410//*********************************************************************************
2411
55e303ae 2412void IOService::OurChangeTellPriorityClientsPowerDown ( void )
1c79356b 2413{
55e303ae
A
2414 // next state
2415 priv->machine_state = kIOPM_OurChangeNotifyInterestedDriversWillChange;
2416 // are we waiting for responses?
2417 if ( tellChangeDown2(priv->head_note_state) )
2418 {
2419 // no, notify interested drivers
2420 return OurChangeNotifyInterestedDriversWillChange();
1c79356b 2421 }
55e303ae
A
2422 // If we are waiting for responses, execution will resume via
2423 // allowCancelCommon() or ack timeout
1c79356b
A
2424}
2425
2426
2427//*********************************************************************************
55e303ae 2428// OurChangeNotifyInterestedDriversWillChange
1c79356b
A
2429//
2430// All registered applications and kernel clients have acknowledged our notification
2431// that we are lowering power. Here we notify interested drivers. If we don't have
2432// to wait for any of them to acknowledge, we instruct our power driver to make the change.
2433// Otherwise, we do wait.
2434//*********************************************************************************
2435
55e303ae 2436void IOService::OurChangeNotifyInterestedDriversWillChange ( void )
1c79356b 2437{
55e303ae
A
2438 // no, in case they don't all ack
2439 priv->machine_state = kIOPM_OurChangeSetPowerState;
2440 if ( notifyAll(true) == IOPMAckImplied )
2441 {
2442 // not waiting for responses
2443 OurChangeSetPowerState();
1c79356b 2444 }
55e303ae
A
2445 // If we are waiting for responses, execution will resume via
2446 // all_acked() or ack timeout
1c79356b
A
2447}
2448
2449
2450//*********************************************************************************
55e303ae 2451// OurChangeSetPowerState
1c79356b
A
2452//
2453// All interested drivers have acknowledged our pre-change notification of a power
2454// change we initiated. Here we instruct our controlling driver to make
2455// the change to the hardware. If it does so, we continue processing
2456// (waiting for settle and notifying interested parties post-change.)
2457// If it doesn't, we have to wait for it to acknowledge and then continue.
2458//*********************************************************************************
2459
55e303ae 2460void IOService::OurChangeSetPowerState ( void )
1c79356b 2461{
55e303ae
A
2462 priv->machine_state = kIOPM_OurChangeWaitForPowerSettle;
2463
2464 if ( instruct_driver(priv->head_note_state) == IOPMAckImplied )
2465 {
2466 // it's done, carry on
2467 OurChangeWaitForPowerSettle();
2468 } else {
2469 // it's not, wait for it
1c79356b
A
2470 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogStartAckTimer,0,0);
2471 start_ack_timer();
55e303ae 2472 // execution will resume via ack_timer_ticked()
1c79356b
A
2473 }
2474}
2475
2476
2477//*********************************************************************************
55e303ae 2478// OurChangeWaitForPowerSettle
1c79356b
A
2479//
2480// Our controlling driver has changed power state on the hardware
2481// during a power change we initiated. Here we see if we need to wait
2482// for power to settle before continuing. If not, we continue processing
2483// (notifying interested parties post-change). If so, we wait and
2484// continue later.
2485//*********************************************************************************
2486
55e303ae 2487void IOService::OurChangeWaitForPowerSettle ( void )
1c79356b 2488{
55e303ae
A
2489 priv->settle_time = compute_settle_time();
2490 if ( priv->settle_time == 0 )
2491 {
2492 OurChangeNotifyInterestedDriversDidChange();
2493 } else {
2494 priv->machine_state = kIOPM_OurChangeNotifyInterestedDriversDidChange;
1c79356b
A
2495 startSettleTimer(priv->settle_time);
2496 }
2497}
2498
2499
2500//*********************************************************************************
55e303ae 2501// OurChangeNotifyInterestedDriversDidChange
1c79356b
A
2502//
2503// Power has settled on a power change we initiated. Here we notify
2504// all our interested parties post-change. If they all acknowledge, we're
2505// done with this change note, and we can start on the next one.
2506// Otherwise we have to wait for acknowledgements and finish up later.
2507//*********************************************************************************
2508
55e303ae 2509void IOService::OurChangeNotifyInterestedDriversDidChange ( void )
1c79356b 2510{
55e303ae
A
2511 // in case they don't all ack
2512 priv->machine_state = kIOPM_OurChangeFinish;
2513 if ( notifyAll(false) == IOPMAckImplied )
2514 {
2515 // not waiting for responses
2516 OurChangeFinish();
1c79356b 2517 }
55e303ae
A
2518 // If we are waiting for responses, execution will resume via
2519 // all_acked() or ack timeout
1c79356b
A
2520}
2521
2522
2523//*********************************************************************************
55e303ae 2524// OurChangeFinish
1c79356b
A
2525//
2526// Power has settled on a power change we initiated, and
2527// all our interested parties have acknowledged. We're
2528// done with this change note, and we can start on the next one.
2529//*********************************************************************************
2530
55e303ae 2531void IOService::OurChangeFinish ( void )
1c79356b
A
2532{
2533 all_done();
2534}
2535
2536
2537//*********************************************************************************
55e303ae 2538// ParentDownTellPriorityClientsPowerDown_Immediate
1c79356b
A
2539//
2540// All applications and kernel clients have been notified of a power lowering
2541// initiated by the parent and we didn't have to wait for any responses. Here
0b4e3aa0
A
2542// we notify any priority clients. If they all ack, we continue with the power change.
2543// If at least one doesn't, we have to wait for it to acknowledge and then continue.
2544//*********************************************************************************
2545
55e303ae 2546IOReturn IOService::ParentDownTellPriorityClientsPowerDown_Immediate ( void )
0b4e3aa0 2547{
55e303ae
A
2548 // in case they don't all ack
2549 priv->machine_state = kIOPM_ParentDownNotifyInterestedDriversWillChange_Delayed;
2550 // are we waiting for responses?
2551 if ( tellChangeDown2(priv->head_note_state) )
2552 {
2553 // no, notify interested drivers
2554 return ParentDownNotifyInterestedDriversWillChange_Immediate();
0b4e3aa0 2555 }
55e303ae
A
2556 // If we are waiting for responses, execution will resume via
2557 // allowCancelCommon() or ack timeout
2558 return IOPMWillAckLater;
0b4e3aa0
A
2559}
2560
2561
2562//*********************************************************************************
55e303ae 2563// ParentDownTellPriorityClientsPowerDown_Immediate2
0b4e3aa0
A
2564//
2565// All priority kernel clients have been notified of a power lowering
2566// initiated by the parent and we didn't have to wait for any responses. Here
1c79356b
A
2567// we notify any interested drivers and power domain children. If they all ack,
2568// we continue with the power change.
2569// If at least one doesn't, we have to wait for it to acknowledge and then continue.
2570//*********************************************************************************
2571
55e303ae 2572IOReturn IOService::ParentDownNotifyInterestedDriversWillChange_Immediate ( void )
1c79356b 2573{
55e303ae
A
2574 // in case they don't all ack
2575 priv->machine_state = kIOPM_ParentDownSetPowerState_Delayed;
2576 if ( notifyAll(true) == IOPMAckImplied )
2577 {
2578 // they did
2579 return ParentDownSetPowerState_Immediate();
1c79356b 2580 }
55e303ae
A
2581 // If we are waiting for responses, execution will resume via
2582 // all_acked() or ack timeout
2583 return IOPMWillAckLater;
1c79356b
A
2584}
2585
2586
0b4e3aa0 2587//*********************************************************************************
55e303ae 2588// ParentDownTellPriorityClientsPowerDown_Immediate4
0b4e3aa0
A
2589//
2590// All applications and kernel clients have been notified of a power lowering
2591// initiated by the parent and we had to wait for responses. Here
2592// we notify any priority clients. If they all ack, we continue with the power change.
2593// If at least one doesn't, we have to wait for it to acknowledge and then continue.
2594//*********************************************************************************
2595
55e303ae 2596void IOService::ParentDownTellPriorityClientsPowerDown_Delayed ( void )
0b4e3aa0 2597{
55e303ae
A
2598 // in case they don't all ack
2599 priv->machine_state = kIOPM_ParentDownNotifyInterestedDriversWillChange_Delayed;
2600
2601 // are we waiting for responses?
2602 if ( tellChangeDown2(priv->head_note_state) )
2603 {
2604 // no, notify interested drivers
2605 ParentDownNotifyInterestedDriversWillChange_Delayed();
0b4e3aa0 2606 }
55e303ae
A
2607 // If we are waiting for responses, execution will resume via
2608 // allowCancelCommon() or ack timeout
0b4e3aa0
A
2609}
2610
2611
1c79356b 2612//*********************************************************************************
55e303ae 2613// ParentDownTellPriorityClientsPowerDown_Immediate5
1c79356b
A
2614//
2615// All applications and kernel clients have been notified of a power lowering
2616// initiated by the parent and we had to wait for their responses. Here we notify
2617// any interested drivers and power domain children. If they all ack, we continue
2618// with the power change.
2619// If at least one doesn't, we have to wait for it to acknowledge and then continue.
2620//*********************************************************************************
2621
55e303ae 2622void IOService::ParentDownNotifyInterestedDriversWillChange_Delayed ( void )
1c79356b 2623{
55e303ae
A
2624 // in case they don't all ack
2625 priv->machine_state = kIOPM_ParentDownSetPowerState_Delayed;
2626 if ( notifyAll(true) == IOPMAckImplied )
2627 {
2628 // they did
2629 ParentDownSetPowerState_Delayed();
1c79356b 2630 }
55e303ae
A
2631 // If we are waiting for responses, execution will resume via
2632 // all_acked() or ack timeout
1c79356b
A
2633}
2634
2635
2636//*********************************************************************************
55e303ae 2637// ParentDownSetPowerState_Immediate
1c79356b
A
2638//
2639// All parties have acknowledged our pre-change notification of a power
2640// lowering initiated by the parent. Here we instruct our controlling driver
2641// to put the hardware in the state it needs to be in when the domain is
2642// lowered. If it does so, we continue processing
2643// (waiting for settle and acknowledging the parent.)
2644// If it doesn't, we have to wait for it to acknowledge and then continue.
2645//*********************************************************************************
2646
55e303ae 2647IOReturn IOService::ParentDownSetPowerState_Immediate ( void )
1c79356b 2648{
55e303ae
A
2649 priv->machine_state = kIOPM_ParentDownWaitForPowerSettle_Delayed;
2650
2651 if ( instruct_driver(priv->head_note_state) == IOPMAckImplied )
2652 {
2653 // it's done, carry on
2654 return ParentDownWaitForPowerSettleAndNotifyDidChange_Immediate();
1c79356b 2655 }
55e303ae 2656 // it's not, wait for it
1c79356b
A
2657 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogStartAckTimer,0,0);
2658 start_ack_timer();
2659 return IOPMWillAckLater;
2660}
2661
2662
2663//*********************************************************************************
55e303ae 2664// ParentDownSetPowerState_Delayed
1c79356b
A
2665//
2666// We had to wait for it, but all parties have acknowledged our pre-change
2667// notification of a power lowering initiated by the parent.
2668// Here we instruct our controlling driver
2669// to put the hardware in the state it needs to be in when the domain is
2670// lowered. If it does so, we continue processing
2671// (waiting for settle and acknowledging the parent.)
2672// If it doesn't, we have to wait for it to acknowledge and then continue.
2673//*********************************************************************************
2674
55e303ae 2675void IOService::ParentDownSetPowerState_Delayed ( void )
1c79356b 2676{
55e303ae
A
2677 priv-> machine_state = kIOPM_ParentDownWaitForPowerSettle_Delayed;
2678
2679 if ( instruct_driver(priv->head_note_state) == IOPMAckImplied )
2680 {
2681 // it's done, carry on
2682 ParentDownWaitForPowerSettle_Delayed();
2683 } else {
2684 // it's not, wait for it
1c79356b
A
2685 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogStartAckTimer,0,0);
2686 start_ack_timer();
2687 }
2688}
2689
2690
2691//*********************************************************************************
55e303ae 2692// ParentDownWaitForPowerSettleAndNotifyDidChange_Immediate
1c79356b
A
2693//
2694// Our controlling driver has changed power state on the hardware
2695// during a power change initiated by our parent. Here we see if we need
2696// to wait for power to settle before continuing. If not, we continue
2697// processing (acknowledging our preparedness to the parent).
2698// If so, we wait and continue later.
2699//*********************************************************************************
2700
55e303ae 2701IOReturn IOService::ParentDownWaitForPowerSettleAndNotifyDidChange_Immediate ( void )
1c79356b 2702{
0b4e3aa0
A
2703 IOService * nub;
2704
1c79356b 2705 priv->settle_time = compute_settle_time();
55e303ae
A
2706 if ( priv->settle_time == 0 )
2707 {
2708 // store current state in case they don't all ack
2709 priv->machine_state = kIOPM_ParentDownAcknowledgeChange_Delayed;
2710 if ( notifyAll(false) == IOPMAckImplied )
2711 {
2712 // not waiting for responses
0b4e3aa0 2713 nub = priv->head_note_parent;
55e303ae 2714 nub->retain();
1c79356b 2715 all_done();
0b4e3aa0 2716 nub->release();
1c79356b
A
2717 return IOPMAckImplied;
2718 }
55e303ae
A
2719 // If we are waiting for responses, execution will resume via
2720 // all_acked() or ack timeout
2721 return IOPMWillAckLater;
2722 } else {
2723 // let settle time elapse, then notify interest drivers of our power state change in ParentDownNotifyDidChangeAndAcknowledgeChange_Delayed
2724 priv->machine_state = kIOPM_ParentDownNotifyDidChangeAndAcknowledgeChange_Delayed;
2725 startSettleTimer(priv->settle_time);
2726 return IOPMWillAckLater;
1c79356b
A
2727 }
2728}
2729
2730
2731//*********************************************************************************
55e303ae 2732// ParentDownWaitForPowerSettle_Delayed
1c79356b
A
2733//
2734// Our controlling driver has changed power state on the hardware
2735// during a power change initiated by our parent. We have had to wait
2736// for acknowledgement from interested parties, or we have had to wait
2737// for the controlling driver to change the state. Here we see if we need
2738// to wait for power to settle before continuing. If not, we continue
2739// processing (acknowledging our preparedness to the parent).
2740// If so, we wait and continue later.
2741//*********************************************************************************
2742
55e303ae 2743void IOService::ParentDownWaitForPowerSettle_Delayed ( void )
1c79356b
A
2744{
2745 priv->settle_time = compute_settle_time();
55e303ae
A
2746 if ( priv->settle_time == 0 )
2747 {
2748 ParentDownNotifyDidChangeAndAcknowledgeChange_Delayed();
2749 } else {
2750 priv->machine_state = kIOPM_ParentDownNotifyDidChangeAndAcknowledgeChange_Delayed;
1c79356b
A
2751 startSettleTimer(priv->settle_time);
2752 }
2753}
2754
2755
2756//*********************************************************************************
55e303ae 2757// ParentDownNotifyDidChangeAndAcknowledgeChange_Delayed
1c79356b
A
2758//
2759// Power has settled on a power change initiated by our parent. Here we
2760// notify interested parties.
2761//*********************************************************************************
2762
55e303ae 2763void IOService::ParentDownNotifyDidChangeAndAcknowledgeChange_Delayed ( void )
1c79356b 2764{
55e303ae
A
2765 IORegistryEntry *nub;
2766 IOService *parent;
1c79356b 2767
55e303ae
A
2768 // in case they don't all ack
2769 priv->machine_state = kIOPM_ParentDownAcknowledgeChange_Delayed;
1c79356b 2770 if ( notifyAll(false) == IOPMAckImplied ) {
0b4e3aa0 2771 nub = priv->head_note_parent;
55e303ae 2772 nub->retain();
1c79356b 2773 all_done();
0b4e3aa0
A
2774 parent = (IOService *)nub->copyParentEntry(gIOPowerPlane);
2775 if ( parent ) {
2776 parent->acknowledgePowerChange((IOService *)nub);
2777 parent->release();
2778 }
2779 nub->release();
1c79356b 2780 }
55e303ae
A
2781 // If we are waiting for responses, execution will resume via
2782 // all_acked() or ack timeout in ParentDownAcknowledgeChange_Delayed.
2783 // Notice the duplication of code just above and in ParentDownAcknowledgeChange_Delayed.
1c79356b
A
2784}
2785
2786
2787//*********************************************************************************
55e303ae 2788// ParentDownAcknowledgeChange_Delayed
1c79356b
A
2789//
2790// We had to wait for it, but all parties have acknowledged our post-change
2791// notification of a power lowering initiated by the parent.
2792// Here we acknowledge the parent.
2793// We are done with this change note, and we can start on the next one.
2794//*********************************************************************************
2795
55e303ae 2796void IOService::ParentDownAcknowledgeChange_Delayed ( void )
1c79356b 2797{
55e303ae
A
2798 IORegistryEntry *nub;
2799 IOService *parent;
1c79356b 2800
0b4e3aa0 2801 nub = priv->head_note_parent;
55e303ae 2802 nub->retain();
1c79356b 2803 all_done();
0b4e3aa0 2804 parent = (IOService *)nub->copyParentEntry(gIOPowerPlane);
55e303ae
A
2805 if ( parent )
2806 {
0b4e3aa0
A
2807 parent->acknowledgePowerChange((IOService *)nub);
2808 parent->release();
2809 }
2810 nub->release();
1c79356b
A
2811}
2812
2813
2814//*********************************************************************************
55e303ae 2815// ParentUpSetPowerState_Delayed
1c79356b
A
2816//
2817// Our parent has informed us via powerStateDidChange that it has
2818// raised the power in our power domain, and we have had to wait
2819// for some interested party to acknowledge our notification.
2820// Here we instruct our controlling
2821// driver to program the hardware to take advantage of the higher domain
2822// power. If it does so, we continue processing
2823// (waiting for settle and notifying interested parties post-change.)
2824// If it doesn't, we have to wait for it to acknowledge and then continue.
2825//*********************************************************************************
2826
55e303ae 2827void IOService::ParentUpSetPowerState_Delayed ( void )
1c79356b 2828{
55e303ae
A
2829 priv->machine_state = kIOPM_ParentUpWaitForSettleTime_Delayed;
2830
2831 if ( instruct_driver(priv->head_note_state) == IOPMAckImplied )
2832 {
2833 // it did it, carry on
2834 ParentUpWaitForSettleTime_Delayed();
2835 } else {
2836 // it didn't, wait for it
1c79356b
A
2837 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogStartAckTimer,0,0);
2838 start_ack_timer();
2839 }
2840}
2841
2842
2843//*********************************************************************************
55e303ae 2844// ParentUpSetPowerState_Immediate
1c79356b
A
2845//
2846// Our parent has informed us via powerStateDidChange that it has
2847// raised the power in our power domain. Here we instruct our controlling
2848// driver to program the hardware to take advantage of the higher domain
2849// power. If it does so, we continue processing
2850// (waiting for settle and notifying interested parties post-change.)
2851// If it doesn't, we have to wait for it to acknowledge and then continue.
2852//*********************************************************************************
2853
55e303ae 2854IOReturn IOService::ParentUpSetPowerState_Immediate ( void )
1c79356b 2855{
55e303ae
A
2856 priv->machine_state = kIOPM_ParentUpWaitForSettleTime_Delayed;
2857
2858 if ( instruct_driver(priv->head_note_state) == IOPMAckImplied )
2859 {
2860 // it did it, carry on
2861 return ParentUpWaitForSettleTime_Immediate();
1c79356b
A
2862 }
2863 else {
55e303ae 2864 // it didn't, wait for it
1c79356b
A
2865 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogStartAckTimer,0,0);
2866 start_ack_timer();
2867 return IOPMWillAckLater;
2868 }
2869}
2870
2871
2872//*********************************************************************************
55e303ae 2873// ParentUpWaitForSettleTime_Immediate
1c79356b
A
2874//
2875// Our controlling driver has changed power state on the hardware
2876// during a power raise initiated by the parent. Here we see if we need to wait
2877// for power to settle before continuing. If not, we continue processing
2878// (notifying interested parties post-change). If so, we wait and
2879// continue later.
2880//*********************************************************************************
2881
55e303ae 2882IOReturn IOService::ParentUpWaitForSettleTime_Immediate ( void )
1c79356b
A
2883{
2884 priv->settle_time = compute_settle_time();
55e303ae
A
2885 if ( priv->settle_time == 0 )
2886 {
2887 return ParentUpNotifyInterestedDriversDidChange_Immediate();
2888 } else {
2889 priv->machine_state = kIOPM_ParentUpNotifyInterestedDriversDidChange_Delayed;
2890 startSettleTimer(priv->settle_time);
2891 return IOPMWillAckLater;
2892 }
1c79356b
A
2893}
2894
2895
2896//*********************************************************************************
55e303ae 2897// ParentUpWaitForSettleTime_Delayed
1c79356b
A
2898//
2899// Our controlling driver has changed power state on the hardware
2900// during a power raise initiated by the parent, but we had to wait for it.
2901// Here we see if we need to wait for power to settle before continuing.
2902// If not, we continue processing (notifying interested parties post-change).
2903// If so, we wait and continue later.
2904//*********************************************************************************
2905
55e303ae 2906void IOService::ParentUpWaitForSettleTime_Delayed ( void )
1c79356b
A
2907{
2908 priv->settle_time = compute_settle_time();
55e303ae
A
2909 if ( priv->settle_time == 0 )
2910 {
2911 ParentUpNotifyInterestedDriversDidChange_Delayed();
2912 } else {
2913 priv->machine_state = kIOPM_ParentUpNotifyInterestedDriversDidChange_Delayed;
2914 startSettleTimer(priv->settle_time);
2915 }
1c79356b
A
2916}
2917
2918
2919//*********************************************************************************
55e303ae 2920// ParentUpNotifyInterestedDriversDidChange_Immediate
1c79356b
A
2921//
2922// No power settling was required on a power raise initiated by the parent.
2923// Here we notify all our interested parties post-change. If they all acknowledge,
2924// we're done with this change note, and we can start on the next one.
2925// Otherwise we have to wait for acknowledgements and finish up later.
2926//*********************************************************************************
2927
55e303ae 2928IOReturn IOService::ParentUpNotifyInterestedDriversDidChange_Immediate ( void )
1c79356b 2929{
0b4e3aa0
A
2930 IOService * nub;
2931
55e303ae
A
2932 // in case they don't all ack
2933 priv->machine_state = kIOPM_ParentUpAcknowledgePowerChange_Delayed;
2934 if ( notifyAll(false) == IOPMAckImplied )
2935 {
0b4e3aa0 2936 nub = priv->head_note_parent;
55e303ae 2937 nub->retain();
1c79356b 2938 all_done();
0b4e3aa0 2939 nub->release();
1c79356b
A
2940 return IOPMAckImplied;
2941 }
55e303ae
A
2942 // If we are waiting for responses, execution will resume via
2943 // all_acked() or ack timeout in ParentUpAcknowledgePowerChange_Delayed.
2944 return IOPMWillAckLater;
1c79356b
A
2945}
2946
2947
2948//*********************************************************************************
55e303ae 2949// ParentUpNotifyInterestedDriversDidChange_Delayed
1c79356b
A
2950//
2951// Power has settled on a power raise initiated by the parent.
2952// Here we notify all our interested parties post-change. If they all acknowledge,
2953// we're done with this change note, and we can start on the next one.
2954// Otherwise we have to wait for acknowledgements and finish up later.
2955//*********************************************************************************
2956
55e303ae 2957void IOService::ParentUpNotifyInterestedDriversDidChange_Delayed ( void )
1c79356b 2958{
55e303ae
A
2959 // in case they don't all ack
2960 priv->machine_state = kIOPM_ParentUpAcknowledgePowerChange_Delayed;
2961 if ( notifyAll(false) == IOPMAckImplied )
2962 {
2963 ParentUpAcknowledgePowerChange_Delayed();
1c79356b 2964 }
55e303ae
A
2965 // If we are waiting for responses, execution will resume via
2966 // all_acked() or ack timeout in ParentUpAcknowledgePowerChange_Delayed.
1c79356b
A
2967}
2968
2969
2970//*********************************************************************************
55e303ae 2971// ParentUpAcknowledgePowerChange_Delayed
1c79356b
A
2972//
2973// All parties have acknowledged our post-change notification of a power
2974// raising initiated by the parent. Here we acknowledge the parent.
2975// We are done with this change note, and we can start on the next one.
2976//*********************************************************************************
2977
55e303ae 2978void IOService::ParentUpAcknowledgePowerChange_Delayed ( void )
1c79356b 2979{
55e303ae
A
2980 IORegistryEntry *nub;
2981 IOService *parent;
1c79356b 2982
0b4e3aa0 2983 nub = priv->head_note_parent;
55e303ae 2984 nub->retain();
1c79356b 2985 all_done();
0b4e3aa0 2986 parent = (IOService *)nub->copyParentEntry(gIOPowerPlane);
55e303ae
A
2987 if ( parent )
2988 {
0b4e3aa0
A
2989 parent->acknowledgePowerChange((IOService *)nub);
2990 parent->release();
2991 }
2992 nub->release();
1c79356b
A
2993}
2994
2995
2996//*********************************************************************************
2997// all_done
2998//
2999// A power change is complete, and the used post-change note is at
3000// the head of the queue. Remove it and set myCurrentState to the result
3001// of the change. Start up the next change in queue.
3002//*********************************************************************************
3003
3004void IOService::all_done ( void )
0b4e3aa0 3005{
55e303ae
A
3006 unsigned long previous_state;
3007 IORegistryEntry *nub;
3008 IOService *parent;
0b4e3aa0 3009
55e303ae 3010 priv->machine_state = kIOPM_Finished;
1c79356b 3011
55e303ae
A
3012 // our power change
3013 if ( priv->head_note_flags & IOPMWeInitiated )
3014 {
3015 // could our driver switch to the new state?
3016 if ( !( priv->head_note_flags & IOPMNotDone) )
3017 {
3018 // yes, did power raise?
3019 if ( pm_vars->myCurrentState < priv->head_note_state )
3020 {
3021 // yes, inform clients and apps
3022 tellChangeUp (priv->head_note_state);
3023 } else {
3024 // no, if this lowers our
3025 if ( ! priv->we_are_root )
3026 {
3027 // power requirements, tell the parent
3028 ask_parent(priv->head_note_state);
1c79356b
A
3029 }
3030 }
0b4e3aa0 3031 previous_state = pm_vars->myCurrentState;
55e303ae
A
3032 // either way
3033 pm_vars->myCurrentState = priv->head_note_state;
0b4e3aa0 3034 priv->imminentState = pm_vars->myCurrentState;
1c79356b 3035 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogChangeDone,(unsigned long)pm_vars->myCurrentState,0);
55e303ae
A
3036 // inform subclass policy-maker
3037 powerChangeDone(previous_state);
1c79356b 3038 }
1c79356b 3039 }
55e303ae
A
3040
3041 // parent's power change
3042 if ( priv->head_note_flags & IOPMParentInitiated)
3043 {
1c79356b 3044 if ( ((priv->head_note_flags & IOPMDomainWillChange) && (pm_vars->myCurrentState >= priv->head_note_state)) ||
55e303ae
A
3045 ((priv->head_note_flags & IOPMDomainDidChange) && (pm_vars->myCurrentState < priv->head_note_state)) )
3046 {
3047 // did power raise?
3048 if ( pm_vars->myCurrentState < priv->head_note_state )
3049 {
3050 // yes, inform clients and apps
3051 tellChangeUp (priv->head_note_state);
1c79356b 3052 }
55e303ae
A
3053 // either way
3054 previous_state = pm_vars->myCurrentState;
0b4e3aa0
A
3055 pm_vars->myCurrentState = priv->head_note_state;
3056 priv->imminentState = pm_vars->myCurrentState;
1c79356b
A
3057 pm_vars->maxCapability = pm_vars->theControllingDriver->maxCapabilityForDomainState(priv->head_note_domainState);
3058
3059 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogChangeDone,(unsigned long)pm_vars->myCurrentState,0);
55e303ae
A
3060 // inform subclass policy-maker
3061 powerChangeDone(previous_state);
1c79356b
A
3062 }
3063 }
3064
0b4e3aa0 3065 IOLockLock(priv->queue_lock);
55e303ae
A
3066 // we're done with this
3067 priv->changeList->releaseHeadChangeNote();
1c79356b 3068
55e303ae
A
3069 // start next one in queue
3070 priv->head_note = priv->changeList->currentChange();
3071 if ( priv->head_note != -1 )
3072 {
1c79356b 3073
0b4e3aa0 3074 IOLockUnlock(priv->queue_lock);
55e303ae
A
3075 if (priv->changeList->changeNote[priv->head_note].flags & IOPMWeInitiated )
3076 {
1c79356b 3077 start_our_change(priv->head_note);
55e303ae 3078 } else {
0b4e3aa0 3079 nub = priv->changeList->changeNote[priv->head_note].parent;
55e303ae
A
3080 if ( start_parent_change(priv->head_note) == IOPMAckImplied )
3081 {
0b4e3aa0 3082 parent = (IOService *)nub->copyParentEntry(gIOPowerPlane);
55e303ae
A
3083 if ( parent )
3084 {
0b4e3aa0
A
3085 parent->acknowledgePowerChange((IOService *)nub);
3086 parent->release();
3087 }
1c79356b
A
3088 }
3089 }
55e303ae
A
3090 } else {
3091 IOLockUnlock(priv->queue_lock);
1c79356b
A
3092 }
3093}
3094
3095
3096
3097//*********************************************************************************
3098// all_acked
3099//
3100// A driver or child has acknowledged our notification of an upcoming power
3101// change, and this acknowledgement is the last one pending
3102// before we change power or after changing power.
3103//
3104//*********************************************************************************
3105
3106void IOService::all_acked ( void )
3107{
3108 switch (priv->machine_state) {
55e303ae
A
3109 case kIOPM_OurChangeSetPowerState:
3110 OurChangeSetPowerState();
1c79356b 3111 break;
55e303ae
A
3112 case kIOPM_OurChangeFinish:
3113 OurChangeFinish();
1c79356b 3114 break;
55e303ae
A
3115 case kIOPM_ParentDownSetPowerState_Delayed:
3116 ParentDownSetPowerState_Delayed();
1c79356b 3117 break;
55e303ae
A
3118 case kIOPM_ParentDownAcknowledgeChange_Delayed:
3119 ParentDownAcknowledgeChange_Delayed();
1c79356b 3120 break;
55e303ae
A
3121 case kIOPM_ParentUpSetPowerState_Delayed:
3122 ParentUpSetPowerState_Delayed();
1c79356b 3123 break;
55e303ae
A
3124 case kIOPM_ParentUpAcknowledgePowerChange_Delayed:
3125 ParentUpAcknowledgePowerChange_Delayed();
1c79356b
A
3126 break;
3127 }
3128}
3129
1c79356b
A
3130//*********************************************************************************
3131// settleTimerExpired
3132//
3133// Power has settled after our last change. Notify interested parties that
3134// there is a new power state.
3135//*********************************************************************************
3136
3137void IOService::settleTimerExpired ( void )
3138{
55e303ae
A
3139 if ( ! initialized )
3140 {
3141 // we're unloading
3142 return;
1c79356b
A
3143 }
3144
3145 switch (priv->machine_state) {
55e303ae
A
3146 case kIOPM_OurChangeNotifyInterestedDriversDidChange:
3147 OurChangeNotifyInterestedDriversDidChange();
1c79356b 3148 break;
55e303ae
A
3149 case kIOPM_ParentDownNotifyDidChangeAndAcknowledgeChange_Delayed:
3150 ParentDownNotifyDidChangeAndAcknowledgeChange_Delayed();
1c79356b 3151 break;
55e303ae
A
3152 case kIOPM_ParentUpNotifyInterestedDriversDidChange_Delayed:
3153 ParentUpNotifyInterestedDriversDidChange_Delayed();
1c79356b
A
3154 break;
3155 }
3156}
3157
3158
3159//*********************************************************************************
3160// compute_settle_time
3161//
3162// Compute the power-settling delay in microseconds for the
3163// change from myCurrentState to head_note_state.
3164//*********************************************************************************
3165
3166unsigned long IOService::compute_settle_time ( void )
3167{
55e303ae
A
3168 unsigned long totalTime;
3169 unsigned long i;
1c79356b 3170
55e303ae
A
3171 // compute total time to attain the new state
3172 totalTime = 0;
1c79356b 3173 i = pm_vars->myCurrentState;
55e303ae
A
3174
3175 // we're lowering power
3176 if ( priv->head_note_state < pm_vars->myCurrentState )
3177 {
3178 while ( i > priv->head_note_state )
3179 {
1c79356b
A
3180 totalTime += pm_vars->thePowerStates[i].settleDownTime;
3181 i--;
3182 }
3183 }
3184
55e303ae
A
3185 // we're raising power
3186 if ( priv->head_note_state > pm_vars->myCurrentState )
3187 {
3188 while ( i < priv->head_note_state )
3189 {
1c79356b
A
3190 totalTime += pm_vars->thePowerStates[i+1].settleUpTime;
3191 i++;
3192 }
3193 }
3194
3195 return totalTime;
3196}
3197
3198
3199//*********************************************************************************
3200// startSettleTimer
3201//
3202// Enter with a power-settling delay in microseconds and start a nano-second
3203// timer for that delay.
3204//*********************************************************************************
3205
3206IOReturn IOService::startSettleTimer ( unsigned long delay )
3207{
3208 AbsoluteTime deadline;
3209
3210 clock_interval_to_deadline(delay, kMicrosecondScale, &deadline);
3211
3212 thread_call_enter_delayed(priv->settleTimer, deadline);
3213
3214 return IOPMNoErr;
3215}
3216
3217//*********************************************************************************
3218// ack_timer_ticked
3219//
3220// The acknowledgement timeout periodic timer has ticked.
3221// If we are awaiting acks for a power change notification,
3222// we decrement the timer word of each interested driver which hasn't acked.
3223// If a timer word becomes zero, we pretend the driver aknowledged.
3224// If we are waiting for the controlling driver to change the power
3225// state of the hardware, we decrement its timer word, and if it becomes
3226// zero, we pretend the driver acknowledged.
3227//*********************************************************************************
3228
3229void IOService::ack_timer_ticked ( void )
3230{
3231 IOPMinformee * nextObject;
3232
55e303ae
A
3233 if ( ! initialized )
3234 {
3235 // we're unloading
3236 return;
1c79356b
A
3237 }
3238
55e303ae
A
3239 if (! acquire_lock() )
3240 {
1c79356b
A
3241 return;
3242 }
3243
3244 switch (priv->machine_state) {
55e303ae
A
3245 case kIOPM_OurChangeWaitForPowerSettle:
3246 case kIOPM_ParentDownWaitForPowerSettle_Delayed:
3247 case kIOPM_ParentUpWaitForSettleTime_Delayed:
3248 // are we waiting for our driver to make its change?
3249 if ( priv->driver_timer != 0 ) {
3250 // yes, tick once
3251 priv->driver_timer -= 1;
3252 // it's tardy, we'll go on without it
3253 if ( priv->driver_timer == 0 )
3254 {
1c79356b
A
3255 IOUnlock(priv->our_lock);
3256 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogCtrlDriverTardy,0,0);
3257 driver_acked();
55e303ae
A
3258 } else {
3259 // still waiting, set timer again
1c79356b
A
3260 start_ack_timer();
3261 IOUnlock(priv->our_lock);
3262 }
3263 }
3264 else {
3265 IOUnlock(priv->our_lock);
3266 }
3267 break;
3268
55e303ae
A
3269 case kIOPM_OurChangeSetPowerState:
3270 case kIOPM_OurChangeFinish:
3271 case kIOPM_ParentDownSetPowerState_Delayed:
3272 case kIOPM_ParentDownAcknowledgeChange_Delayed:
3273 case kIOPM_ParentUpSetPowerState_Delayed:
3274 case kIOPM_ParentUpAcknowledgePowerChange_Delayed:
3275 // are we waiting for interested parties to acknowledge?
3276 if (priv->head_note_pendingAcks != 0 )
3277 {
3278 // yes, go through the list of interested drivers
3279 nextObject = priv->interestedDrivers->firstInList();
3280 // and check each one
3281 while ( nextObject != NULL )
3282 {
3283 if ( nextObject->timer > 0 )
3284 {
1c79356b 3285 nextObject->timer -= 1;
55e303ae
A
3286 // this one should have acked by now
3287 if ( nextObject->timer == 0 )
3288 {
1c79356b 3289 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogIntDriverTardy,0,0);
55e303ae 3290 //kprintf("interested driver tardy: %s\n",nextObject->whatObject->getName());
1c79356b
A
3291 priv->head_note_pendingAcks -= 1;
3292 }
3293 }
3294 nextObject = priv->interestedDrivers->nextInList(nextObject);
3295 }
55e303ae
A
3296
3297 // is that the last?
3298 if ( priv->head_note_pendingAcks == 0 )
3299 {
1c79356b 3300 IOUnlock(priv->our_lock);
55e303ae
A
3301 // yes, we can continue
3302 all_acked();
3303 } else {
3304 // no, set timer again
1c79356b
A
3305 start_ack_timer();
3306 IOUnlock(priv->our_lock);
3307 }
55e303ae 3308 } else {
1c79356b
A
3309 IOUnlock(priv->our_lock);
3310 }
3311 break;
3312
55e303ae
A
3313 // apps didn't respond to parent-down notification
3314 case kIOPM_ParentDownTellPriorityClientsPowerDown_Immediate:
0b4e3aa0
A
3315 IOUnlock(priv->our_lock);
3316 IOLockLock(priv->flags_lock);
55e303ae
A
3317 if (pm_vars->responseFlags)
3318 {
3319 // get rid of this stuff
3320 pm_vars->responseFlags->release();
0b4e3aa0
A
3321 pm_vars->responseFlags = NULL;
3322 }
3323 IOLockUnlock(priv->flags_lock);
3324 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogClientTardy,0,5);
55e303ae
A
3325 // carry on with the change
3326 ParentDownTellPriorityClientsPowerDown_Delayed();
0b4e3aa0
A
3327 break;
3328
55e303ae 3329 case kIOPM_ParentDownNotifyInterestedDriversWillChange_Delayed:
1c79356b
A
3330 IOUnlock(priv->our_lock);
3331 IOLockLock(priv->flags_lock);
55e303ae
A
3332 if (pm_vars->responseFlags)
3333 {
3334 // get rid of this stuff
3335 pm_vars->responseFlags->release();
1c79356b
A
3336 pm_vars->responseFlags = NULL;
3337 }
3338 IOLockUnlock(priv->flags_lock);
3339 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogClientTardy,0,1);
55e303ae
A
3340 // carry on with the change
3341 ParentDownNotifyInterestedDriversWillChange_Delayed();
1c79356b
A
3342 break;
3343
55e303ae
A
3344 case kIOPM_OurChangeTellClientsPowerDown:
3345 // apps didn't respond to our power-down request
1c79356b
A
3346 IOUnlock(priv->our_lock);
3347 IOLockLock(priv->flags_lock);
55e303ae
A
3348 if (pm_vars->responseFlags)
3349 {
3350 // get rid of this stuff
3351 pm_vars->responseFlags->release();
1c79356b
A
3352 pm_vars->responseFlags = NULL;
3353 }
3354 IOLockUnlock(priv->flags_lock);
3355 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogClientTardy,0,2);
55e303ae
A
3356 // rescind the request
3357 tellNoChangeDown(priv->head_note_state);
3358 // mark the change note un-actioned
3359 priv->head_note_flags |= IOPMNotDone;
3360 // and we're done
3361 all_done();
1c79356b
A
3362 break;
3363
55e303ae
A
3364 case kIOPM_OurChangeTellPriorityClientsPowerDown:
3365 // clients didn't respond to our power-down note
0b4e3aa0
A
3366 IOUnlock(priv->our_lock);
3367 IOLockLock(priv->flags_lock);
55e303ae
A
3368 if (pm_vars->responseFlags)
3369 {
3370 // get rid of this stuff
3371 pm_vars->responseFlags->release();
0b4e3aa0
A
3372 pm_vars->responseFlags = NULL;
3373 }
3374 IOLockUnlock(priv->flags_lock);
3375 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogClientTardy,0,4);
55e303ae
A
3376 // carry on with the change
3377 OurChangeTellPriorityClientsPowerDown();
0b4e3aa0
A
3378 break;
3379
55e303ae
A
3380 case kIOPM_OurChangeNotifyInterestedDriversWillChange:
3381 // apps didn't respond to our power-down notification
1c79356b
A
3382 IOUnlock(priv->our_lock);
3383 IOLockLock(priv->flags_lock);
55e303ae
A
3384 if (pm_vars->responseFlags)
3385 {
3386 // get rid of this stuff
3387 pm_vars->responseFlags->release();
1c79356b
A
3388 pm_vars->responseFlags = NULL;
3389 }
3390 IOLockUnlock(priv->flags_lock);
3391 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogClientTardy,0,3);
55e303ae
A
3392 // carry on with the change
3393 OurChangeNotifyInterestedDriversWillChange();
1c79356b
A
3394 break;
3395
3396 default:
55e303ae
A
3397 // not waiting for acks
3398 IOUnlock(priv->our_lock);
1c79356b
A
3399 break;
3400 }
3401}
3402
3403
3404//*********************************************************************************
3405// start_ack_timer
3406//
3407//*********************************************************************************
3408
3409void IOService::start_ack_timer ( void )
3410{
55e303ae 3411 AbsoluteTime deadline;
1c79356b
A
3412
3413 clock_interval_to_deadline(ACK_TIMER_PERIOD, kNanosecondScale, &deadline);
3414
3415 thread_call_enter_delayed(priv->ackTimer, deadline);
3416}
3417
3418
3419//*********************************************************************************
3420// stop_ack_timer
3421//
3422//*********************************************************************************
3423
3424void IOService::stop_ack_timer ( void )
3425{
3426 thread_call_cancel(priv->ackTimer);
3427}
3428
3429
3430//*********************************************************************************
3431// c-language timer expiration functions
3432//
3433//*********************************************************************************
3434
3435static void ack_timer_expired ( thread_call_param_t us)
3436{
3437 ((IOService *)us)->ack_timer_ticked();
3438}
3439
3440
3441static void settle_timer_expired ( thread_call_param_t us)
3442{
3443 ((IOService *)us)->settleTimerExpired();
3444}
3445
3446
3447//*********************************************************************************
3448// add_child_to_active_change
3449//
3450// A child has just registered with us. If there is
3451// currently a change in progress, get the new party involved: if we
3452// have notified all parties and are waiting for acks, notify the new
3453// party.
3454//*********************************************************************************
3455
3456IOReturn IOService::add_child_to_active_change ( IOPowerConnection * newObject )
3457{
55e303ae
A
3458 if (! acquire_lock() )
3459 {
1c79356b
A
3460 return IOPMNoErr;
3461 }
3462
55e303ae
A
3463 switch (priv->machine_state)
3464 {
3465 case kIOPM_OurChangeSetPowerState:
3466 case kIOPM_ParentDownSetPowerState_Delayed:
3467 case kIOPM_ParentUpSetPowerState_Delayed:
3468 // one for this child and one to prevent
3469 priv->head_note_pendingAcks += 2;
3470 // incoming acks from changing our state
3471 IOUnlock(priv->our_lock);
1c79356b 3472 notifyChild(newObject, true);
55e303ae
A
3473 if (! acquire_lock() )
3474 {
3475 // put it back
3476 --priv->head_note_pendingAcks;
1c79356b
A
3477 return IOPMNoErr;
3478 }
55e303ae
A
3479 // are we still waiting for acks?
3480 if ( --priv->head_note_pendingAcks == 0 )
3481 {
3482 // no, stop the timer
3483 stop_ack_timer();
1c79356b 3484 IOUnlock(priv->our_lock);
55e303ae
A
3485
3486 // and now we can continue
3487 all_acked();
1c79356b
A
3488 return IOPMNoErr;
3489 }
3490 break;
55e303ae
A
3491 case kIOPM_OurChangeFinish:
3492 case kIOPM_ParentDownAcknowledgeChange_Delayed:
3493 case kIOPM_ParentUpAcknowledgePowerChange_Delayed:
3494 // one for this child and one to prevent
3495 priv->head_note_pendingAcks += 2;
3496 // incoming acks from changing our state
3497 IOUnlock(priv->our_lock);
1c79356b 3498 notifyChild(newObject, false);
55e303ae
A
3499 if (! acquire_lock() )
3500 {
3501 // put it back
3502 --priv->head_note_pendingAcks;
1c79356b
A
3503 return IOPMNoErr;
3504 }
55e303ae
A
3505 // are we still waiting for acks?
3506 if ( --priv->head_note_pendingAcks == 0 )
3507 {
3508 // no, stop the timer
3509 stop_ack_timer();
1c79356b 3510 IOUnlock(priv->our_lock);
55e303ae
A
3511
3512 // and now we can continue
3513 all_acked();
1c79356b
A
3514 return IOPMNoErr;
3515 }
3516 break;
3517 }
3518 IOUnlock(priv->our_lock);
3519 return IOPMNoErr;
3520}
3521
3522
3523//*********************************************************************************
3524// add_driver_to_active_change
3525//
3526// An interested driver has just registered with us. If there is
3527// currently a change in progress, get the new party involved: if we
3528// have notified all parties and are waiting for acks, notify the new
3529// party.
3530//*********************************************************************************
3531
3532IOReturn IOService::add_driver_to_active_change ( IOPMinformee * newObject )
3533{
55e303ae
A
3534 if (! acquire_lock() )
3535 {
1c79356b
A
3536 return IOPMNoErr;
3537 }
3538
3539 switch (priv->machine_state) {
55e303ae
A
3540 case kIOPM_OurChangeSetPowerState:
3541 case kIOPM_ParentDownSetPowerState_Delayed:
3542 case kIOPM_ParentUpSetPowerState_Delayed:
3543 // one for this driver and one to prevent
3544 priv->head_note_pendingAcks += 2;
3545 // incoming acks from changing our state
3546 IOUnlock(priv->our_lock);
3547 // inform the driver
3548 inform(newObject, true);
3549 if (! acquire_lock() )
3550 {
3551 // put it back
3552 --priv->head_note_pendingAcks;
1c79356b
A
3553 return IOPMNoErr;
3554 }
55e303ae
A
3555 // are we still waiting for acks?
3556 if ( --priv->head_note_pendingAcks == 0 )
3557 {
3558 // no, stop the timer
3559 stop_ack_timer();
1c79356b 3560 IOUnlock(priv->our_lock);
55e303ae
A
3561
3562 // and now we can continue
3563 all_acked();
1c79356b
A
3564 return IOPMNoErr;
3565 }
3566 break;
55e303ae
A
3567 case kIOPM_OurChangeFinish:
3568 case kIOPM_ParentDownAcknowledgeChange_Delayed:
3569 case kIOPM_ParentUpAcknowledgePowerChange_Delayed:
3570 // one for this driver and one to prevent
3571 priv->head_note_pendingAcks += 2;
3572 // incoming acks from changing our state
3573 IOUnlock(priv->our_lock);
3574 // inform the driver
3575 inform(newObject, false);
1c79356b 3576 if (! acquire_lock() ) {
55e303ae
A
3577 // put it back
3578 --priv->head_note_pendingAcks;
1c79356b
A
3579 return IOPMNoErr;
3580 }
55e303ae
A
3581 // are we still waiting for acks?
3582 if ( --priv->head_note_pendingAcks == 0 ) {
3583 // no, stop the timer
3584 stop_ack_timer();
1c79356b 3585 IOUnlock(priv->our_lock);
55e303ae
A
3586
3587 // and now we can continue
3588 all_acked();
1c79356b
A
3589 return IOPMNoErr;
3590 }
3591 break;
3592 }
3593 IOUnlock(priv->our_lock);
3594 return IOPMNoErr;
3595}
3596
3597
3598//*********************************************************************************
3599// start_parent_change
3600//
3601// Here we begin the processing of a change note initiated by our parent
3602// which is at the head of the queue.
3603//
3604// It is possible for the change to be processed to completion and removed from the queue.
3605// There are several possible interruptions to the processing, though, and they are:
3606// we may have to wait for interested parties to acknowledge our pre-change notification,
3607// we may have to wait for our controlling driver to change the hardware power state,
3608// there may be a settling time after changing the hardware power state,
3609// we may have to wait for interested parties to acknowledge our post-change notification,
3610// we may have to wait for the acknowledgement timer expiration to substitute for the
3611// acknowledgement from a failing driver.
3612//*********************************************************************************
3613
3614IOReturn IOService::start_parent_change ( unsigned long queue_head )
3615{
3616 priv->head_note = queue_head;
3617 priv->head_note_flags = priv-> changeList->changeNote[priv->head_note].flags;
3618 priv->head_note_state = priv->changeList->changeNote[priv->head_note].newStateNumber;
0b4e3aa0 3619 priv->imminentState = priv->head_note_state;
1c79356b
A
3620 priv->head_note_outputFlags = priv->changeList->changeNote[priv->head_note].outputPowerCharacter;
3621 priv->head_note_domainState = priv->changeList->changeNote[priv->head_note].domainState;
3622 priv->head_note_parent = priv->changeList->changeNote[priv->head_note].parent;
3623 priv->head_note_capabilityFlags = priv->changeList->changeNote[priv->head_note].capabilityFlags;
3624
3625 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogStartParentChange,
3626 (unsigned long)priv->head_note_state,(unsigned long)pm_vars->myCurrentState);
3627
55e303ae
A
3628 // if we need something and haven't told the parent, do so
3629 ask_parent( priv->ourDesiredPowerState);
1c79356b 3630
55e303ae
A
3631 // power domain is lowering
3632 if ( priv->head_note_state < pm_vars->myCurrentState )
3633 {
0b4e3aa0 3634 setParentInfo(priv->changeList->changeNote[priv->head_note].singleParentState,priv->head_note_parent);
55e303ae
A
3635 priv->initial_change = false;
3636 // tell apps and kernel clients
3637 priv->machine_state = kIOPM_ParentDownTellPriorityClientsPowerDown_Immediate;
3638
3639 // are we waiting for responses?
3640 if ( tellChangeDown1(priv->head_note_state) )
3641 {
3642 // no, notify priority clients
3643 return ParentDownTellPriorityClientsPowerDown_Immediate();
1c79356b 3644 }
55e303ae
A
3645 // yes
3646 return IOPMWillAckLater;
1c79356b
A
3647 }
3648
55e303ae
A
3649 // parent is raising power, we may or may not
3650 if ( priv->head_note_state > pm_vars->myCurrentState )
3651 {
3652 if ( priv->ourDesiredPowerState > pm_vars->myCurrentState )
3653 {
3654 if ( priv->ourDesiredPowerState < priv->head_note_state )
3655 {
3656 // we do, but not all the way
3657 priv->head_note_state = priv->ourDesiredPowerState;
3658 priv->imminentState = priv->head_note_state;
3659 priv->head_note_outputFlags = pm_vars->thePowerStates[priv->head_note_state].outputPowerCharacter;
3660 priv->head_note_capabilityFlags = pm_vars->thePowerStates[priv->head_note_state].capabilityFlags;
3661 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogAmendParentChange,(unsigned long)priv->head_note_state,0);
3662 }
3663 } else {
3664 // we don't
3665 priv->head_note_state = pm_vars->myCurrentState;
0b4e3aa0 3666 priv->imminentState = priv->head_note_state;
1c79356b
A
3667 priv->head_note_outputFlags = pm_vars->thePowerStates[priv->head_note_state].outputPowerCharacter;
3668 priv->head_note_capabilityFlags = pm_vars->thePowerStates[priv->head_note_state].capabilityFlags;
3669 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogAmendParentChange,(unsigned long)priv->head_note_state,0);
3670 }
3671 }
3672
3673 if ( (priv->head_note_state > pm_vars->myCurrentState) &&
55e303ae
A
3674 (priv->head_note_flags & IOPMDomainDidChange) )
3675 {
3676 // changing up
1c79356b 3677 priv->initial_change = false;
55e303ae
A
3678 priv->machine_state = kIOPM_ParentUpSetPowerState_Delayed;
3679 if ( notifyAll(true) == IOPMAckImplied ) {
3680 return ParentUpSetPowerState_Immediate();
3681 }
3682 // they didn't all ack
3683 return IOPMWillAckLater;
1c79356b
A
3684 }
3685
3686 all_done();
55e303ae
A
3687 // a null change or power will go up
3688 return IOPMAckImplied;
1c79356b
A
3689}
3690
3691
3692//*********************************************************************************
3693// start_our_change
3694//
3695// Here we begin the processing of a change note initiated by us
3696// which is at the head of the queue.
3697//
3698// It is possible for the change to be processed to completion and removed from the queue.
3699// There are several possible interruptions to the processing, though, and they are:
3700// we may have to wait for interested parties to acknowledge our pre-change notification,
3701// changes initiated by the parent will wait in the middle for powerStateDidChange,
3702// we may have to wait for our controlling driver to change the hardware power state,
3703// there may be a settling time after changing the hardware power state,
3704// we may have to wait for interested parties to acknowledge our post-change notification,
3705// we may have to wait for the acknowledgement timer expiration to substitute for the
3706// acknowledgement from a failing driver.
3707//*********************************************************************************
3708
3709void IOService::start_our_change ( unsigned long queue_head )
3710{
3711 priv->head_note = queue_head;
3712 priv->head_note_flags = priv->changeList->changeNote[priv->head_note].flags;
3713 priv->head_note_state = priv->changeList->changeNote[priv->head_note].newStateNumber;
0b4e3aa0 3714 priv->imminentState = priv->head_note_state;
1c79356b
A
3715 priv->head_note_outputFlags = priv->changeList->changeNote[priv->head_note].outputPowerCharacter;
3716 priv->head_note_capabilityFlags = priv->changeList->changeNote[priv->head_note].capabilityFlags;
3717
3718 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogStartDeviceChange,
3719 (unsigned long)priv->head_note_state,(unsigned long)pm_vars->myCurrentState);
3720
55e303ae
A
3721 // can our driver switch to the new state?
3722 if ( priv->head_note_capabilityFlags & IOPMNotAttainable )
3723 {
3724 // no, ask the parent to do it then
3725 if ( ! priv->we_are_root )
3726 {
1c79356b
A
3727 ask_parent(priv->head_note_state);
3728 }
55e303ae
A
3729 // mark the change note un-actioned
3730 priv-> head_note_flags |= IOPMNotDone;
3731 // and we're done
3732 all_done();
1c79356b
A
3733 return;
3734 }
55e303ae
A
3735
3736 // is there enough power in the domain?
3737 if ( (pm_vars->maxCapability < priv->head_note_state) && (! priv->we_are_root) )
3738 {
3739 // no, ask the parent to raise it
3740 if ( ! priv->we_are_root )
3741 {
1c79356b
A
3742 ask_parent(priv->head_note_state);
3743 }
55e303ae
A
3744 // no, mark the change note un-actioned
3745 priv->head_note_flags |= IOPMNotDone;
3746 // and we're done
3747 // till the parent raises power
3748 all_done();
3749 return;
1c79356b
A
3750 }
3751
55e303ae
A
3752 if ( ! priv->initial_change )
3753 {
3754 if ( priv->head_note_state == pm_vars->myCurrentState )
3755 {
3756 // we initiated a null change; forget it
3757 all_done();
1c79356b
A
3758 return;
3759 }
3760 }
3761 priv->initial_change = false;
3762
55e303ae
A
3763 // dropping power?
3764 if ( priv->head_note_state < pm_vars->myCurrentState )
3765 {
3766 // yes, in case we have to wait for acks
3767 priv->machine_state = kIOPM_OurChangeTellClientsPowerDown;
1c79356b 3768 pm_vars->doNotPowerDown = false;
55e303ae
A
3769
3770 // ask apps and kernel clients if we can drop power
3771 pm_vars->outofbandparameter = kNotifyApps;
3772 if ( askChangeDown(priv->head_note_state) )
3773 {
3774 // don't have to wait, did any clients veto?
3775 if ( pm_vars->doNotPowerDown )
3776 {
3777 // yes, rescind the warning
3778 tellNoChangeDown(priv->head_note_state);
3779 // mark the change note un-actioned
3780 priv-> head_note_flags |= IOPMNotDone;
3781 // and we're done
3782 all_done();
3783 } else {
3784 // no, tell'em we're dropping power
3785 OurChangeTellClientsPowerDown();
1c79356b
A
3786 }
3787 }
55e303ae
A
3788 } else {
3789 // we are raising power
3790 if ( ! priv->we_are_root )
3791 {
3792 // if this changes our power requirement, tell the parent
3793 ask_parent(priv->head_note_state);
1c79356b 3794 }
55e303ae
A
3795 // in case they don't all ack
3796 priv->machine_state = kIOPM_OurChangeSetPowerState;
3797
3798 // notify interested drivers and children
3799 if ( notifyAll(true) == IOPMAckImplied )
3800 {
3801 OurChangeSetPowerState();
1c79356b
A
3802 }
3803 }
3804}
3805
3806
3807//*********************************************************************************
3808// ask_parent
3809//
3810// Call the power domain parent to ask for a higher power state in the domain
3811// or to suggest a lower power state.
3812//*********************************************************************************
3813
3814IOReturn IOService::ask_parent ( unsigned long requestedState )
3815{
55e303ae
A
3816 OSIterator *iter;
3817 OSObject *next;
3818 IOPowerConnection *connection;
3819 IOService *parent;
3820 unsigned long ourRequest = pm_vars->thePowerStates[requestedState].inputPowerRequirement;
1c79356b 3821
55e303ae
A
3822 if ( pm_vars->thePowerStates[requestedState].capabilityFlags & (kIOPMChildClamp | kIOPMPreventIdleSleep) )
3823 {
0b4e3aa0
A
3824 ourRequest |= kIOPMPreventIdleSleep;
3825 }
55e303ae
A
3826 if ( pm_vars->thePowerStates[requestedState].capabilityFlags & (kIOPMChildClamp2 | kIOPMPreventSystemSleep) )
3827 {
0b4e3aa0
A
3828 ourRequest |= kIOPMPreventSystemSleep;
3829 }
3830
90556fb8
A
3831 // is this a new desire?
3832 if ( priv->previousRequest == ourRequest )
3833 {
3834 // no, the parent knows already, just return
3835 return IOPMNoErr;
1c79356b
A
3836 }
3837
55e303ae
A
3838 if ( priv->we_are_root )
3839 {
1c79356b
A
3840 return IOPMNoErr;
3841 }
0b4e3aa0 3842 priv->previousRequest = ourRequest;
1c79356b
A
3843
3844 iter = getParentIterator(gIOPowerPlane);
3845
55e303ae
A
3846 if ( iter )
3847 {
3848 while ( (next = iter->getNextObject()) )
3849 {
3850 if ( (connection = OSDynamicCast(IOPowerConnection,next)) )
3851 {
0b4e3aa0
A
3852 parent = (IOService *)connection->copyParentEntry(gIOPowerPlane);
3853 if ( parent ) {
55e303ae
A
3854 if ( parent->requestPowerDomainState(ourRequest,connection,IOPMLowestState)!= IOPMNoErr )
3855 {
0b4e3aa0
A
3856 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogRequestDenied,
3857 (unsigned long)priv->previousRequest,0);
3858 }
3859 parent->release();
1c79356b
A
3860 }
3861 }
3862 }
3863 iter->release();
3864 }
3865
3866 return IOPMNoErr;
3867}
3868
3869
3870//*********************************************************************************
3871// instruct_driver
3872//
3873// Call the controlling driver and have it change the power state of the
3874// hardware. If it returns IOPMAckImplied, the change is complete, and
3875// we return IOPMAckImplied. Otherwise, it will ack when the change
3876// is done; we return IOPMWillAckLater.
3877//*********************************************************************************
1c79356b
A
3878IOReturn IOService::instruct_driver ( unsigned long newState )
3879{
91447636 3880 IOReturn delay;
1c79356b 3881
55e303ae
A
3882 // can our driver switch to the desired state?
3883 if ( pm_vars->thePowerStates[newState].capabilityFlags & IOPMNotAttainable )
3884 {
3885 // no, so don't try
3886 return IOPMAckImplied;
1c79356b 3887 }
55e303ae 3888
1c79356b 3889 priv->driver_timer = -1;
0b4e3aa0 3890
55e303ae 3891 // yes, instruct it
91447636
A
3892 OUR_PMLog( kPMLogProgramHardware, (UInt32) this, newState);
3893 delay = pm_vars->theControllingDriver->setPowerState( newState,this );
3894 OUR_PMLog((UInt32) -kPMLogProgramHardware, (UInt32) this, (UInt32) delay);
9bccf70c 3895
55e303ae 3896 // it finished
91447636 3897 if ( delay == IOPMAckImplied )
55e303ae 3898 {
1c79356b
A
3899 priv->driver_timer = 0;
3900 return IOPMAckImplied;
3901 }
3902
55e303ae
A
3903 // it acked behind our back
3904 if ( priv->driver_timer == 0 )
3905 {
1c79356b
A
3906 return IOPMAckImplied;
3907 }
3908
55e303ae 3909 // somebody goofed
91447636 3910 if ( delay < 0 )
55e303ae 3911 {
1c79356b
A
3912 return IOPMAckImplied;
3913 }
55e303ae
A
3914
3915 // it didn't finish
91447636 3916 priv->driver_timer = (delay / ( ACK_TIMER_PERIOD / ns_per_us )) + 1;
1c79356b
A
3917 return IOPMWillAckLater;
3918}
3919
3920
3921//*********************************************************************************
3922// acquire_lock
3923//
3924// We are acquiring the lock we use to protect our queue head from
3925// simutaneous access by a thread which calls acknowledgePowerStateChange
3926// or acknowledgeSetPowerState and the ack timer expiration thread.
3927// Return TRUE if we acquire the lock, and the queue head didn't change
3928// while we were acquiring the lock (and maybe blocked).
3929// If there is no queue head, or it changes while we are blocked,
3930// return FALSE with the lock unlocked.
3931//*********************************************************************************
3932
3933bool IOService::acquire_lock ( void )
3934{
3935 long current_change_note;
3936
3937 current_change_note = priv->head_note;
3938 if ( current_change_note == -1 ) {
3939 return FALSE;
3940 }
3941
3942 IOTakeLock(priv->our_lock);
55e303ae
A
3943 if ( current_change_note == priv->head_note )
3944 {
1c79356b 3945 return TRUE;
55e303ae
A
3946 } else {
3947 // we blocked and something changed radically
3948 // so there's nothing to do any more
3949 IOUnlock(priv->our_lock);
1c79356b
A
3950 return FALSE;
3951 }
3952}
3953
3954
3955//*********************************************************************************
3956// askChangeDown
3957//
3958// Ask registered applications and kernel clients if we can change to a lower
3959// power state.
3960//
3961// Subclass can override this to send a different message type. Parameter is
3962// the destination state number.
3963//
3964// Return true if we don't have to wait for acknowledgements
3965//*********************************************************************************
3966
0b4e3aa0 3967bool IOService::askChangeDown ( unsigned long stateNum )
1c79356b
A
3968{
3969 return tellClientsWithResponse(kIOMessageCanDevicePowerOff);
3970}
3971
3972
0b4e3aa0
A
3973//*********************************************************************************
3974// tellChangeDown1
3975//
3976// Notify registered applications and kernel clients that we are definitely
3977// dropping power.
3978//
3979// Return true if we don't have to wait for acknowledgements
3980//*********************************************************************************
3981
3982bool IOService::tellChangeDown1 ( unsigned long stateNum )
3983{
3984 pm_vars->outofbandparameter = kNotifyApps;
3985 return tellChangeDown(stateNum);
3986}
3987
3988
3989//*********************************************************************************
3990// tellChangeDown2
3991//
3992// Notify priority clients that we are definitely dropping power.
3993//
3994// Return true if we don't have to wait for acknowledgements
3995//*********************************************************************************
3996
3997bool IOService::tellChangeDown2 ( unsigned long stateNum )
3998{
3999 pm_vars->outofbandparameter = kNotifyPriority;
4000 return tellChangeDown(stateNum);
4001}
4002
4003
1c79356b
A
4004//*********************************************************************************
4005// tellChangeDown
4006//
4007// Notify registered applications and kernel clients that we are definitely
4008// dropping power.
4009//
4010// Subclass can override this to send a different message type. Parameter is
4011// the destination state number.
4012//
4013// Return true if we don't have to wait for acknowledgements
4014//*********************************************************************************
4015
0b4e3aa0 4016bool IOService::tellChangeDown ( unsigned long stateNum )
1c79356b
A
4017{
4018 return tellClientsWithResponse(kIOMessageDeviceWillPowerOff);
4019}
4020
4021
4022//*********************************************************************************
4023// tellClientsWithResponse
4024//
4025// Notify registered applications and kernel clients that we are definitely
4026// dropping power.
4027//
4028// Return true if we don't have to wait for acknowledgements
4029//*********************************************************************************
4030
4031bool IOService::tellClientsWithResponse ( int messageType )
4032{
55e303ae
A
4033 struct context theContext;
4034 AbsoluteTime deadline;
4035 OSBoolean *aBool;
1c79356b
A
4036
4037 pm_vars->responseFlags = OSArray::withCapacity( 1 );
4038 pm_vars->serialNumber += 1;
4039
4040 theContext.responseFlags = pm_vars->responseFlags;
4041 theContext.serialNumber = pm_vars->serialNumber;
4042 theContext.flags_lock = priv->flags_lock;
4043 theContext.counter = 1;
4044 theContext.msgType = messageType;
4045 theContext.us = this;
4046 theContext.maxTimeRequested = 0;
0b4e3aa0
A
4047 theContext.stateNumber = priv->head_note_state;
4048 theContext.stateFlags = priv->head_note_capabilityFlags;
4049
1c79356b 4050 IOLockLock(priv->flags_lock);
55e303ae
A
4051
4052 // position zero is false to
4053 // prevent allowCancelCommon from succeeding
4054 aBool = OSBoolean::withBoolean(false);
4055 theContext.responseFlags->setObject(0,aBool);
1c79356b
A
4056 aBool->release();
4057 IOLockUnlock(priv->flags_lock);
4058
0b4e3aa0
A
4059 switch ( pm_vars->outofbandparameter ) {
4060 case kNotifyApps:
4061 applyToInterested(gIOAppPowerStateInterest,tellAppWithResponse,(void *)&theContext);
4062 applyToInterested(gIOGeneralInterest,tellClientWithResponse,(void *)&theContext);
4063 break;
4064 case kNotifyPriority:
4065 applyToInterested(gIOPriorityPowerStateInterest,tellClientWithResponse,(void *)&theContext);
4066 break;
4067 }
1c79356b 4068
55e303ae
A
4069 if (! acquire_lock() )
4070 {
1c79356b
A
4071 return true;
4072 }
4073 IOLockLock(priv->flags_lock);
55e303ae
A
4074 // now fix position zero
4075 aBool = OSBoolean::withBoolean(true);
1c79356b
A
4076 theContext.responseFlags->replaceObject(0,aBool);
4077 aBool->release();
4078 IOLockUnlock(priv->flags_lock);
4079
55e303ae
A
4080 // do we have to wait for somebody?
4081 if ( ! checkForDone() )
4082 {
4083 // yes, start the ackTimer
1c79356b
A
4084 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogStartAckTimer,theContext.maxTimeRequested,0);
4085 clock_interval_to_deadline(theContext.maxTimeRequested / 1000, kMillisecondScale, &deadline);
4086
4087 thread_call_enter_delayed(priv->ackTimer, deadline);
4088
55e303ae 4089 IOUnlock(priv->our_lock);
1c79356b
A
4090 return false;
4091 }
4092
4093 IOUnlock(priv->our_lock);
4094 IOLockLock(priv->flags_lock);
55e303ae
A
4095
4096 // everybody responded
4097 pm_vars->responseFlags->release();
1c79356b
A
4098 pm_vars->responseFlags = NULL;
4099 IOLockUnlock(priv->flags_lock);
4100
4101 return true;
4102}
4103
4104
4105//*********************************************************************************
4106// tellAppWithResponse
4107//
4108// We send a message to an application, and we expect a response, so we compute a
4109// cookie we can identify the response with.
4110//*********************************************************************************
4111void tellAppWithResponse ( OSObject * object, void * context)
4112{
55e303ae 4113 struct context *theContext = (struct context *)context;
55e303ae 4114 OSBoolean *aBool;
91447636
A
4115 IOPMprot *pm_vars = theContext->us->pm_vars;
4116
55e303ae
A
4117 if( OSDynamicCast( IOService, object) )
4118 {
91447636 4119 // Automatically 'ack' in kernel clients
1c79356b
A
4120 IOLockLock(theContext->flags_lock);
4121 aBool = OSBoolean::withBoolean(true);
4122 theContext->responseFlags->setObject(theContext->counter,aBool);
4123 aBool->release();
4124 IOLockUnlock(theContext->flags_lock);
91447636
A
4125
4126 const char *who = ((IOService *) object)->getName();
4127 pm_vars->thePlatform->PMLog(who,
4128 kPMLogClientAcknowledge, theContext->msgType, * (UInt32 *) object);
55e303ae 4129 } else {
91447636
A
4130 UInt32 refcon = ((theContext->serialNumber & 0xFFFF)<<16)
4131 + (theContext->counter & 0xFFFF);
1c79356b
A
4132 IOLockLock(theContext->flags_lock);
4133 aBool = OSBoolean::withBoolean(false);
4134 theContext->responseFlags->setObject(theContext->counter,aBool);
4135 aBool->release();
4136 IOLockUnlock(theContext->flags_lock);
91447636
A
4137
4138 OUR_PMLog(kPMLogAppNotify, theContext->msgType, refcon);
1c79356b 4139 theContext->us->messageClient(theContext->msgType,object,(void *)refcon);
55e303ae
A
4140 if ( theContext->maxTimeRequested < k30seconds )
4141 {
0b4e3aa0 4142 theContext->maxTimeRequested = k30seconds;
1c79356b
A
4143 }
4144 }
4145 theContext->counter += 1;
4146}
4147
1c79356b
A
4148//*********************************************************************************
4149// tellClientWithResponse
4150//
4151// We send a message to an in-kernel client, and we expect a response, so we compute a
4152// cookie we can identify the response with.
4153// If it doesn't understand the notification (it is not power-management savvy)
4154// we won't wait for it to prepare for sleep. If it tells us via a return code
4155// in the passed struct that it is currently ready, we won't wait for it to prepare.
4156// If it tells us via the return code in the struct that it does need time, we will chill.
4157//*********************************************************************************
4158void tellClientWithResponse ( OSObject * object, void * context)
4159{
55e303ae
A
4160 struct context *theContext = (struct context *)context;
4161 IOPowerStateChangeNotification notify;
4162 UInt32 refcon;
4163 IOReturn retCode;
4164 OSBoolean *aBool;
4165 OSObject *theFlag;
1c79356b
A
4166
4167 refcon = ((theContext->serialNumber & 0xFFFF)<<16) + (theContext->counter & 0xFFFF);
4168 IOLockLock(theContext->flags_lock);
4169 aBool = OSBoolean::withBoolean(false);
4170 theContext->responseFlags->setObject(theContext->counter,aBool);
4171 aBool->release();
4172 IOLockUnlock(theContext->flags_lock);
0b4e3aa0 4173
91447636
A
4174 IOPMprot *pm_vars = theContext->us->pm_vars;
4175 if (gIOKitDebug & kIOLogPower) {
4176 OUR_PMLog(kPMLogClientNotify, refcon, (UInt32) theContext->msgType);
4177 if (OSDynamicCast(IOService, object)) {
4178 const char *who = ((IOService *) object)->getName();
4179 pm_vars->thePlatform->PMLog(who,
4180 kPMLogClientNotify, * (UInt32 *) object, (UInt32) object);
4181 } else if (OSDynamicCast(_IOServiceInterestNotifier, object)) {
4182 _IOServiceInterestNotifier *n = (_IOServiceInterestNotifier *) object;
4183 OUR_PMLog(kPMLogClientNotify, (UInt32) n->handler, 0);
4184 }
4185 }
4186
0b4e3aa0
A
4187 notify.powerRef = (void *)refcon;
4188 notify.returnValue = 0;
4189 notify.stateNumber = theContext->stateNumber;
4190 notify.stateFlags = theContext->stateFlags;
4191 retCode = theContext->us->messageClient(theContext->msgType,object,(void *)&notify);
55e303ae
A
4192 if ( retCode == kIOReturnSuccess )
4193 {
4194 if ( notify.returnValue == 0 )
4195 {
4196 // client doesn't want time to respond
1c79356b
A
4197 IOLockLock(theContext->flags_lock);
4198 aBool = OSBoolean::withBoolean(true);
55e303ae
A
4199 // so set its flag true
4200 theContext->responseFlags->replaceObject(theContext->counter,aBool);
1c79356b
A
4201 aBool->release();
4202 IOLockUnlock(theContext->flags_lock);
91447636 4203 OUR_PMLog(kPMLogClientAcknowledge, refcon, (UInt32) object);
55e303ae 4204 } else {
1c79356b 4205 IOLockLock(theContext->flags_lock);
55e303ae
A
4206
4207 // it does want time, and it hasn't responded yet
4208 theFlag = theContext->responseFlags->getObject(theContext->counter);
4209 if ( theFlag != 0 )
4210 {
4211 if ( ((OSBoolean *)theFlag)->isFalse() )
4212 {
4213 // so note its time requirement
4214 if ( theContext->maxTimeRequested < notify.returnValue )
4215 {
0b4e3aa0 4216 theContext->maxTimeRequested = notify.returnValue;
1c79356b
A
4217 }
4218 }
4219 }
4220 IOLockUnlock(theContext->flags_lock);
4221 }
55e303ae 4222 } else {
91447636 4223 OUR_PMLog(kPMLogClientAcknowledge, refcon, 0);
55e303ae 4224 // not a client of ours
1c79356b 4225 IOLockLock(theContext->flags_lock);
55e303ae
A
4226 // so we won't be waiting for response
4227 aBool = OSBoolean::withBoolean(true);
1c79356b
A
4228 theContext->responseFlags->replaceObject(theContext->counter,aBool);
4229 aBool->release();
4230 IOLockUnlock(theContext->flags_lock);
4231 }
4232 theContext->counter += 1;
4233}
4234
4235
4236//*********************************************************************************
4237// tellNoChangeDown
4238//
4239// Notify registered applications and kernel clients that we are not
4240// dropping power.
4241//
4242// Subclass can override this to send a different message type. Parameter is
4243// the aborted destination state number.
4244//*********************************************************************************
4245
4246void IOService::tellNoChangeDown ( unsigned long )
4247{
4248 return tellClients(kIOMessageDeviceWillNotPowerOff);
4249}
4250
4251
4252//*********************************************************************************
4253// tellChangeUp
4254//
4255// Notify registered applications and kernel clients that we are raising power.
4256//
4257// Subclass can override this to send a different message type. Parameter is
4258// the aborted destination state number.
4259//*********************************************************************************
4260
4261void IOService::tellChangeUp ( unsigned long )
4262{
4263 return tellClients(kIOMessageDeviceHasPoweredOn);
4264}
4265
4266
4267//*********************************************************************************
4268// tellClients
4269//
4270// Notify registered applications and kernel clients of something.
4271//*********************************************************************************
4272
4273void IOService::tellClients ( int messageType )
4274{
4275 struct context theContext;
4276
4277 theContext.msgType = messageType;
4278 theContext.us = this;
0b4e3aa0
A
4279 theContext.stateNumber = priv->head_note_state;
4280 theContext.stateFlags = priv->head_note_capabilityFlags;
1c79356b
A
4281
4282 applyToInterested(gIOAppPowerStateInterest,tellClient,(void *)&theContext);
4283 applyToInterested(gIOGeneralInterest,tellClient,(void *)&theContext);
4284}
4285
4286
4287//*********************************************************************************
4288// tellClient
4289//
4290// Notify a registered application or kernel client of something.
4291//*********************************************************************************
4292void tellClient ( OSObject * object, void * context)
4293{
55e303ae
A
4294 struct context *theContext = (struct context *)context;
4295 IOPowerStateChangeNotification notify;
1c79356b 4296
0b4e3aa0
A
4297 notify.powerRef = (void *) 0;
4298 notify.returnValue = 0;
4299 notify.stateNumber = theContext->stateNumber;
4300 notify.stateFlags = theContext->stateFlags;
4301
4302 theContext->us->messageClient(theContext->msgType,object, &notify);
1c79356b
A
4303}
4304
4305
4306// **********************************************************************************
4307// checkForDone
4308//
4309// **********************************************************************************
4310bool IOService::checkForDone ( void )
4311{
55e303ae
A
4312 int i = 0;
4313 OSObject *theFlag;
1c79356b
A
4314
4315 IOLockLock(priv->flags_lock);
55e303ae
A
4316 if ( pm_vars->responseFlags == NULL )
4317 {
1c79356b
A
4318 IOLockUnlock(priv->flags_lock);
4319 return true;
4320 }
55e303ae
A
4321
4322 for ( i = 0; ; i++ )
4323 {
1c79356b 4324 theFlag = pm_vars->responseFlags->getObject(i);
55e303ae
A
4325 if ( theFlag == NULL )
4326 {
1c79356b
A
4327 break;
4328 }
55e303ae
A
4329 if ( ((OSBoolean *)theFlag)->isFalse() )
4330 {
1c79356b
A
4331 IOLockUnlock(priv->flags_lock);
4332 return false;
4333 }
4334 }
4335 IOLockUnlock(priv->flags_lock);
4336 return true;
4337}
4338
4339
4340// **********************************************************************************
4341// responseValid
4342//
4343// **********************************************************************************
4344bool IOService::responseValid ( unsigned long x )
4345{
4346 UInt16 serialComponent;
4347 UInt16 ordinalComponent;
4348 OSObject * theFlag;
4349 unsigned long refcon = (unsigned long)x;
4350 OSBoolean * aBool;
4351
4352 serialComponent = (refcon>>16) & 0xFFFF;
4353 ordinalComponent = refcon & 0xFFFF;
4354
55e303ae
A
4355 if ( serialComponent != pm_vars->serialNumber )
4356 {
1c79356b
A
4357 return false;
4358 }
4359
4360 IOLockLock(priv->flags_lock);
55e303ae
A
4361 if ( pm_vars->responseFlags == NULL )
4362 {
1c79356b
A
4363 IOLockUnlock(priv->flags_lock);
4364 return false;
4365 }
4366
4367 theFlag = pm_vars->responseFlags->getObject(ordinalComponent);
4368
55e303ae
A
4369 if ( theFlag == 0 )
4370 {
1c79356b
A
4371 IOLockUnlock(priv->flags_lock);
4372 return false;
4373 }
4374
55e303ae
A
4375 if ( ((OSBoolean *)theFlag)->isFalse() )
4376 {
1c79356b
A
4377 aBool = OSBoolean::withBoolean(true);
4378 pm_vars->responseFlags->replaceObject(ordinalComponent,aBool);
4379 aBool->release();
4380 }
4381
4382 IOLockUnlock(priv->flags_lock);
4383 return true;
4384}
4385
4386
4387// **********************************************************************************
4388// allowPowerChange
4389//
4390// Our power state is about to lower, and we have notified applications
4391// and kernel clients, and one of them has acknowledged. If this is the last to do
4392// so, and all acknowledgements are positive, we continue with the power change.
4393//
4394// We serialize this processing with timer expiration with a command gate on the
4395// power management workloop, which the timer expiration is command gated to as well.
4396// **********************************************************************************
4397IOReturn IOService::allowPowerChange ( unsigned long refcon )
4398{
55e303ae
A
4399 if ( ! initialized )
4400 {
4401 // we're unloading
4402 return kIOReturnSuccess;
1c79356b
A
4403 }
4404
4405 return pm_vars->PMcommandGate->runAction(serializedAllowPowerChange,(void *)refcon);
4406}
4407
4408
4409IOReturn serializedAllowPowerChange ( OSObject *owner, void * refcon, void *, void *, void *)
4410{
4411 return ((IOService *)owner)->serializedAllowPowerChange2((unsigned long)refcon);
4412}
4413
4414IOReturn IOService::serializedAllowPowerChange2 ( unsigned long refcon )
4415{
55e303ae
A
4416 // response valid?
4417 if ( ! responseValid(refcon) )
4418 {
1c79356b 4419 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogAcknowledgeErr5,refcon,0);
55e303ae
A
4420 // no, just return
4421 return kIOReturnSuccess;
1c79356b
A
4422 }
4423 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogClientAcknowledge,refcon,0);
4424
4425 return allowCancelCommon();
4426}
4427
4428
4429// **********************************************************************************
4430// cancelPowerChange
4431//
4432// Our power state is about to lower, and we have notified applications
4433// and kernel clients, and one of them has vetoed the change. If this is the last
4434// client to respond, we abandon the power change.
4435//
4436// We serialize this processing with timer expiration with a command gate on the
4437// power management workloop, which the timer expiration is command gated to as well.
4438// **********************************************************************************
4439IOReturn IOService::cancelPowerChange ( unsigned long refcon )
4440{
55e303ae
A
4441 if ( ! initialized )
4442 {
4443 // we're unloading
4444 return kIOReturnSuccess;
1c79356b
A
4445 }
4446
4447 return pm_vars->PMcommandGate->runAction(serializedCancelPowerChange,(void *)refcon);
4448}
4449
4450
4451IOReturn serializedCancelPowerChange ( OSObject *owner, void * refcon, void *, void *, void *)
4452{
4453 return ((IOService *)owner)->serializedCancelPowerChange2((unsigned long)refcon);
4454}
4455
4456IOReturn IOService::serializedCancelPowerChange2 ( unsigned long refcon )
4457{
55e303ae
A
4458 // response valid?
4459 if ( ! responseValid(refcon) )
4460 {
1c79356b 4461 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogAcknowledgeErr5,refcon,0);
55e303ae
A
4462 // no, just return
4463 return kIOReturnSuccess;
1c79356b
A
4464 }
4465 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogClientCancel,refcon,0);
4466
4467 pm_vars->doNotPowerDown = true;
4468
4469 return allowCancelCommon();
4470}
4471
4472
4473// **********************************************************************************
4474// allowCancelCommon
4475//
4476// **********************************************************************************
4477IOReturn IOService::allowCancelCommon ( void )
4478{
55e303ae
A
4479 if (! acquire_lock() )
4480 {
1c79356b
A
4481 return kIOReturnSuccess;
4482 }
4483
55e303ae
A
4484 // is this the last response?
4485 if ( checkForDone() )
4486 {
4487 // yes, stop the timer
4488 stop_ack_timer();
1c79356b
A
4489 IOUnlock(priv->our_lock);
4490 IOLockLock(priv->flags_lock);
55e303ae
A
4491 if ( pm_vars->responseFlags )
4492 {
1c79356b
A
4493 pm_vars->responseFlags->release();
4494 pm_vars->responseFlags = NULL;
4495 }
4496 IOLockUnlock(priv->flags_lock);
4497 switch (priv->machine_state) {
55e303ae
A
4498 case kIOPM_OurChangeTellClientsPowerDown:
4499 // our change, was it vetoed?
4500 if ( ! pm_vars->doNotPowerDown )
4501 {
4502 // no, we can continue
4503 OurChangeTellClientsPowerDown();
4504 } else {
4505 // yes, rescind the warning
4506 tellNoChangeDown(priv->head_note_state);
4507 // mark the change note un-actioned
4508 priv->head_note_flags |= IOPMNotDone;
4509
4510 // and we're done
4511 all_done();
1c79356b
A
4512 }
4513 break;
55e303ae
A
4514 case kIOPM_OurChangeTellPriorityClientsPowerDown:
4515 OurChangeTellPriorityClientsPowerDown();
0b4e3aa0 4516 break;
55e303ae
A
4517 case kIOPM_OurChangeNotifyInterestedDriversWillChange:
4518 // our change, continue
4519 OurChangeNotifyInterestedDriversWillChange();
1c79356b 4520 break;
55e303ae
A
4521 case kIOPM_ParentDownTellPriorityClientsPowerDown_Immediate:
4522 // parent change, continue
4523 ParentDownTellPriorityClientsPowerDown_Delayed();
0b4e3aa0 4524 break;
55e303ae
A
4525 case kIOPM_ParentDownNotifyInterestedDriversWillChange_Delayed:
4526 // parent change, continue
4527 ParentDownNotifyInterestedDriversWillChange_Delayed();
1c79356b
A
4528 break;
4529 }
55e303ae
A
4530 } else {
4531 // not done yet
4532 IOUnlock(priv->our_lock);
1c79356b
A
4533 }
4534
1c79356b
A
4535 return kIOReturnSuccess;
4536}
4537
4538
91447636 4539#if 0
1c79356b 4540//*********************************************************************************
91447636 4541// c_PM_clamp_Timer_Expired (C Func)
1c79356b 4542//
91447636 4543// Called when our clamp timer expires...we will call the object method.
1c79356b
A
4544//*********************************************************************************
4545
91447636 4546static void c_PM_Clamp_Timer_Expired (OSObject * client, IOTimerEventSource *)
1c79356b 4547{
91447636
A
4548 if (client)
4549 ((IOService *)client)->PM_Clamp_Timer_Expired ();
1c79356b 4550}
91447636
A
4551#endif
4552
1c79356b
A
4553
4554//*********************************************************************************
4555// PM_Clamp_Timer_Expired
4556//
4557// called when clamp timer expires...set power state to 0.
4558//*********************************************************************************
4559
4560void IOService::PM_Clamp_Timer_Expired (void)
4561{
91447636 4562#if 0
55e303ae
A
4563 if ( ! initialized )
4564 {
4565 // we're unloading
4566 return;
1c79356b
A
4567 }
4568
4569 changePowerStateToPriv (0);
91447636 4570#endif
1c79356b
A
4571}
4572
91447636
A
4573//******************************************************************************
4574// clampPowerOn
1c79356b 4575//
91447636
A
4576// Set to highest available power state for a minimum of duration milliseconds
4577//******************************************************************************
4578
4579#define kFiveMinutesInNanoSeconds (300 * NSEC_PER_SEC)
1c79356b 4580
91447636 4581void IOService::clampPowerOn (unsigned long duration)
1c79356b 4582{
91447636
A
4583#if 0
4584 changePowerStateToPriv (pm_vars->theNumberOfPowerStates-1);
4585
4586 if ( priv->clampTimerEventSrc == NULL ) {
4587 priv->clampTimerEventSrc = IOTimerEventSource::timerEventSource(this,
4588 c_PM_Clamp_Timer_Expired);
4589
4590 IOWorkLoop * workLoop = getPMworkloop ();
4591
4592 if ( !priv->clampTimerEventSrc || !workLoop ||
4593 ( workLoop->addEventSource( priv->clampTimerEventSrc) != kIOReturnSuccess) ) {
4594
4595 }
4596 }
1c79356b 4597
91447636
A
4598 priv->clampTimerEventSrc->setTimeout(300*USEC_PER_SEC, USEC_PER_SEC);
4599#endif
4600}
1c79356b
A
4601
4602//*********************************************************************************
4603// setPowerState
4604//
4605// Does nothing here. This should be implemented in a subclass driver.
4606//*********************************************************************************
4607
4608IOReturn IOService::setPowerState ( unsigned long powerStateOrdinal, IOService* whatDevice )
4609{
4610 return IOPMNoErr;
4611}
4612
4613
4614//*********************************************************************************
4615// maxCapabilityForDomainState
4616//
4617// Finds the highest power state in the array whose input power
4618// requirement is equal to the input parameter. Where a more intelligent
4619// decision is possible, override this in the subclassed driver.
4620//*********************************************************************************
4621
4622unsigned long IOService::maxCapabilityForDomainState ( IOPMPowerFlags domainState )
4623{
4624 int i;
4625
55e303ae
A
4626 if (pm_vars->theNumberOfPowerStates == 0 )
4627 {
1c79356b
A
4628 return 0;
4629 }
55e303ae
A
4630 for ( i = (pm_vars->theNumberOfPowerStates)-1; i >= 0; i-- )
4631 {
4632 if ( (domainState & pm_vars->thePowerStates[i].inputPowerRequirement) == pm_vars->thePowerStates[i].inputPowerRequirement )
4633 {
1c79356b
A
4634 return i;
4635 }
4636 }
4637 return 0;
4638}
4639
4640
4641//*********************************************************************************
4642// initialPowerStateForDomainState
4643//
4644// Finds the highest power state in the array whose input power
4645// requirement is equal to the input parameter. Where a more intelligent
4646// decision is possible, override this in the subclassed driver.
4647//*********************************************************************************
4648
4649unsigned long IOService::initialPowerStateForDomainState ( IOPMPowerFlags domainState )
4650{
55e303ae 4651 int i;
1c79356b 4652
55e303ae
A
4653 if (pm_vars->theNumberOfPowerStates == 0 )
4654 {
4655 return 0;
4656 }
4657 for ( i = (pm_vars->theNumberOfPowerStates)-1; i >= 0; i-- )
4658 {
4659 if ( (domainState & pm_vars->thePowerStates[i].inputPowerRequirement) == pm_vars->thePowerStates[i].inputPowerRequirement )
4660 {
4661 return i;
4662 }
4663 }
4664 return 0;
1c79356b
A
4665}
4666
4667
4668//*********************************************************************************
4669// powerStateForDomainState
4670//
4671// Finds the highest power state in the array whose input power
4672// requirement is equal to the input parameter. Where a more intelligent
4673// decision is possible, override this in the subclassed driver.
4674//*********************************************************************************
4675
4676unsigned long IOService::powerStateForDomainState ( IOPMPowerFlags domainState )
4677{
55e303ae 4678 int i;
1c79356b 4679
55e303ae
A
4680 if (pm_vars->theNumberOfPowerStates == 0 )
4681 {
4682 return 0;
4683 }
4684 for ( i = (pm_vars->theNumberOfPowerStates)-1; i >= 0; i-- )
4685 {
4686 if ( (domainState & pm_vars->thePowerStates[i].inputPowerRequirement) == pm_vars->thePowerStates[i].inputPowerRequirement )
4687 {
4688 return i;
4689 }
4690 }
4691 return 0;
1c79356b
A
4692}
4693
4694
4695//*********************************************************************************
4696// didYouWakeSystem
4697//
4698// Does nothing here. This should be implemented in a subclass driver.
4699//*********************************************************************************
4700
4701bool IOService::didYouWakeSystem ( void )
4702{
4703 return false;
4704}
4705
4706
4707//*********************************************************************************
4708// powerStateWillChangeTo
4709//
4710// Does nothing here. This should be implemented in a subclass driver.
4711//*********************************************************************************
4712
4713IOReturn IOService::powerStateWillChangeTo ( IOPMPowerFlags, unsigned long, IOService*)
4714{
4715 return 0;
4716}
4717
4718
4719//*********************************************************************************
4720// powerStateDidChangeTo
4721//
4722// Does nothing here. This should be implemented in a subclass driver.
4723//*********************************************************************************
4724
4725IOReturn IOService::powerStateDidChangeTo ( IOPMPowerFlags, unsigned long, IOService*)
4726{
4727 return 0;
4728}
4729
4730
4731//*********************************************************************************
4732// powerChangeDone
4733//
4734// Does nothing here. This should be implemented in a subclass policy-maker.
4735//*********************************************************************************
4736
4737void IOService::powerChangeDone ( unsigned long )
4738{
4739}
4740
4741
4742//*********************************************************************************
4743// newTemperature
4744//
4745// Does nothing here. This should be implemented in a subclass driver.
4746//*********************************************************************************
4747
4748IOReturn IOService::newTemperature ( long currentTemp, IOService * whichZone )
4749
4750{
4751 return IOPMNoErr;
4752}
4753
4754
4755#undef super
4756#define super OSObject
4757
4758OSDefineMetaClassAndStructors(IOPMprot, OSObject)
4759//*********************************************************************************
4760// serialize
4761//
4762// Serialize protected instance variables for debug output.
4763//*********************************************************************************
4764bool IOPMprot::serialize(OSSerialize *s) const
4765{
4766 OSString * theOSString;
4767 char * buffer;
4768 char * ptr;
91447636 4769 int buf_size;
1c79356b
A
4770 int i;
4771 bool rtn_code;
4772
91447636
A
4773 // estimate how many bytes we need to present all power states
4774 buf_size = 150 // beginning and end of string
4775 + (275 * (int)theNumberOfPowerStates) // size per state
4776 + 100; // extra room just for kicks
4777
4778 buffer = ptr = IONew(char, buf_size);
1c79356b
A
4779 if(!buffer)
4780 return false;
4781
4782 ptr += sprintf(ptr,"{ theNumberOfPowerStates = %d, ",(unsigned int)theNumberOfPowerStates);
4783
4784 if ( theNumberOfPowerStates != 0 ) {
4785 ptr += sprintf(ptr,"version %d, ",(unsigned int)thePowerStates[0].version);
4786 }
4787
4788 if ( theNumberOfPowerStates != 0 ) {
4789 for ( i = 0; i < (int)theNumberOfPowerStates; i++ ) {
91447636 4790 ptr += sprintf(ptr, "power state %d = { ",i);
1c79356b
A
4791 ptr += sprintf(ptr,"capabilityFlags %08x, ",(unsigned int)thePowerStates[i].capabilityFlags);
4792 ptr += sprintf(ptr,"outputPowerCharacter %08x, ",(unsigned int)thePowerStates[i].outputPowerCharacter);
4793 ptr += sprintf(ptr,"inputPowerRequirement %08x, ",(unsigned int)thePowerStates[i].inputPowerRequirement);
4794 ptr += sprintf(ptr,"staticPower %d, ",(unsigned int)thePowerStates[i].staticPower);
4795 ptr += sprintf(ptr,"unbudgetedPower %d, ",(unsigned int)thePowerStates[i].unbudgetedPower);
4796 ptr += sprintf(ptr,"powerToAttain %d, ",(unsigned int)thePowerStates[i].powerToAttain);
4797 ptr += sprintf(ptr,"timeToAttain %d, ",(unsigned int)thePowerStates[i].timeToAttain);
4798 ptr += sprintf(ptr,"settleUpTime %d, ",(unsigned int)thePowerStates[i].settleUpTime);
4799 ptr += sprintf(ptr,"timeToLower %d, ",(unsigned int)thePowerStates[i].timeToLower);
4800 ptr += sprintf(ptr,"settleDownTime %d, ",(unsigned int)thePowerStates[i].settleDownTime);
4801 ptr += sprintf(ptr,"powerDomainBudget %d }, ",(unsigned int)thePowerStates[i].powerDomainBudget);
4802 }
4803 }
4804
4805 ptr += sprintf(ptr,"aggressiveness = %d, ",(unsigned int)aggressiveness);
4806 ptr += sprintf(ptr,"myCurrentState = %d, ",(unsigned int)myCurrentState);
4807 ptr += sprintf(ptr,"parentsCurrentPowerFlags = %08x, ",(unsigned int)parentsCurrentPowerFlags);
4808 ptr += sprintf(ptr,"maxCapability = %d }",(unsigned int)maxCapability);
4809
4810 theOSString = OSString::withCString(buffer);
4811 rtn_code = theOSString->serialize(s);
4812 theOSString->release();
91447636 4813 IODelete(buffer, char, buf_size);
1c79356b
A
4814
4815 return rtn_code;
4816}
4817
4818
4819#undef super
4820#define super OSObject
4821
4822OSDefineMetaClassAndStructors(IOPMpriv, OSObject)
4823//*********************************************************************************
4824// serialize
4825//
4826// Serialize private instance variables for debug output.
4827//*********************************************************************************
4828bool IOPMpriv::serialize(OSSerialize *s) const
4829{
4830 OSString * theOSString;
4831 bool rtn_code;
4832 char * buffer;
4833 char * ptr;
4834 IOPMinformee * nextObject;
4835
4836 buffer = ptr = IONew(char, 2000);
4837 if(!buffer)
4838 return false;
4839
4840 ptr += sprintf(ptr,"{ this object = %08x",(unsigned int)owner);
4841 if ( we_are_root ) {
4842 ptr += sprintf(ptr," (root)");
4843 }
4844 ptr += sprintf(ptr,", ");
4845
4846 nextObject = interestedDrivers->firstInList(); // display interested drivers
4847 while ( nextObject != NULL ) {
4848 ptr += sprintf(ptr,"interested driver = %08x, ",(unsigned int)nextObject->whatObject);
4849 nextObject = interestedDrivers->nextInList(nextObject);
4850 }
4851
55e303ae 4852 if ( machine_state != kIOPM_Finished ) {
1c79356b
A
4853 ptr += sprintf(ptr,"machine_state = %d, ",(unsigned int)machine_state);
4854 ptr += sprintf(ptr,"driver_timer = %d, ",(unsigned int)driver_timer);
4855 ptr += sprintf(ptr,"settle_time = %d, ",(unsigned int)settle_time);
4856 ptr += sprintf(ptr,"head_note_flags = %08x, ",(unsigned int)head_note_flags);
4857 ptr += sprintf(ptr,"head_note_state = %d, ",(unsigned int)head_note_state);
4858 ptr += sprintf(ptr,"head_note_outputFlags = %08x, ",(unsigned int)head_note_outputFlags);
4859 ptr += sprintf(ptr,"head_note_domainState = %08x, ",(unsigned int)head_note_domainState);
4860 ptr += sprintf(ptr,"head_note_capabilityFlags = %08x, ",(unsigned int)head_note_capabilityFlags);
4861 ptr += sprintf(ptr,"head_note_pendingAcks = %d, ",(unsigned int)head_note_pendingAcks);
4862 }
4863
4864 if ( device_overrides ) {
4865 ptr += sprintf(ptr,"device overrides, ");
4866 }
4867 ptr += sprintf(ptr,"driverDesire = %d, ",(unsigned int)driverDesire);
4868 ptr += sprintf(ptr,"deviceDesire = %d, ",(unsigned int)deviceDesire);
4869 ptr += sprintf(ptr,"ourDesiredPowerState = %d, ",(unsigned int)ourDesiredPowerState);
4870 ptr += sprintf(ptr,"previousRequest = %d }",(unsigned int)previousRequest);
4871
4872 theOSString = OSString::withCString(buffer);
4873 rtn_code = theOSString->serialize(s);
4874 theOSString->release();
4875 IODelete(buffer, char, 2000);
4876
4877 return rtn_code;
4878}
4879