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