2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_OSREFERENCE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the
10 * License may not be used to create, or enable the creation or
11 * redistribution of, unlawful or unlicensed copies of an Apple operating
12 * system, or to circumvent, violate, or enable the circumvention or
13 * violation of, any terms of an Apple operating system software license
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
20 * The Original Code and all software distributed under the License are
21 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
22 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
23 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
25 * Please see the License for the specific language governing rights and
26 * limitations under the License.
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
31 #include <IOKit/assert.h>
33 #include <IOKit/IOCommandGate.h>
34 #include <IOKit/IOKitDebug.h>
35 #include <IOKit/IOLib.h>
36 #include <IOKit/IOMessage.h>
37 #include <IOKit/IOPlatformExpert.h>
38 #include <IOKit/IOService.h>
39 #include <IOKit/IOTimerEventSource.h>
40 #include <IOKit/IOWorkLoop.h>
42 #include <IOKit/pwr_mgt/IOPMchangeNoteList.h>
43 #include <IOKit/pwr_mgt/IOPMinformee.h>
44 #include <IOKit/pwr_mgt/IOPMinformeeList.h>
45 #include <IOKit/pwr_mgt/IOPMlog.h>
46 #include <IOKit/pwr_mgt/IOPowerConnection.h>
47 #include <IOKit/pwr_mgt/RootDomain.h>
49 // Required for notification instrumentation
50 #include "IOServicePrivate.h"
52 #define super IORegistryEntry
54 #define OUR_PMLog(t, a, b) \
55 do { pm_vars->thePlatform->PMLog(pm_vars->ourName, t, a, b); } while(0)
57 static void ack_timer_expired(thread_call_param_t
);
58 static void settle_timer_expired(thread_call_param_t
);
59 static void PM_idle_timer_expired(OSObject
*, IOTimerEventSource
*);
60 void tellAppWithResponse ( OSObject
* object
, void * context
);
61 void tellClientWithResponse ( OSObject
* object
, void * context
);
62 void tellClient ( OSObject
* object
, void * context
);
63 IOReturn
serializedAllowPowerChange ( OSObject
*, void *, void *, void *, void *);
64 IOReturn
serializedCancelPowerChange ( OSObject
*, void *, void *, void *, void *);
66 extern const IORegistryPlane
* gIOPowerPlane
;
69 // and there's 1000 nanoseconds in a microsecond:
70 #define ns_per_us 1000
73 // The current change note is processed by a state machine.
74 // Inputs are acks from interested parties, ack from the controlling driver,
75 // ack timeouts, settle timeout, and powerStateDidChange from the parent.
76 // These are the states:
78 kIOPM_OurChangeTellClientsPowerDown
= 1,
79 kIOPM_OurChangeTellPriorityClientsPowerDown
,
80 kIOPM_OurChangeNotifyInterestedDriversWillChange
,
81 kIOPM_OurChangeSetPowerState
,
82 kIOPM_OurChangeWaitForPowerSettle
,
83 kIOPM_OurChangeNotifyInterestedDriversDidChange
,
84 kIOPM_OurChangeFinish
,
85 kIOPM_ParentDownTellPriorityClientsPowerDown_Immediate
,
86 kIOPM_ParentDownNotifyInterestedDriversWillChange_Delayed
,
87 kIOPM_ParentDownWaitForPowerSettleAndNotifyDidChange_Immediate
,
88 kIOPM_ParentDownNotifyDidChangeAndAcknowledgeChange_Delayed
,
89 kIOPM_ParentDownSetPowerState_Delayed
,
90 kIOPM_ParentDownWaitForPowerSettle_Delayed
,
91 kIOPM_ParentDownAcknowledgeChange_Delayed
,
92 kIOPM_ParentUpSetPowerState_Delayed
,
93 kIOPM_ParentUpSetPowerState_Immediate
,
94 kIOPM_ParentUpWaitForSettleTime_Delayed
,
95 kIOPM_ParentUpNotifyInterestedDriversDidChange_Delayed
,
96 kIOPM_ParentUpAcknowledgePowerChange_Delayed
,
100 // values of outofbandparameter
107 // used for applyToInterested
109 OSArray
* responseFlags
;
112 UInt32 maxTimeRequested
;
116 unsigned long stateNumber
;
117 IOPMPowerFlags stateFlags
;
120 // five minutes in microseconds
121 #define FIVE_MINUTES 5*60*1000000
122 #define k30seconds 30*1000000
125 There are two different kinds of power state changes. One is initiated by a subclassed device object which has either
126 decided to change power state, or its controlling driver has suggested it, or some other driver wants to use the
127 idle device and has asked it to become usable. The second kind of power state change is initiated by the power
128 domain parent. The two are handled slightly differently.
130 There is a queue of so-called change notifications, or change notes for short. Usually the queue is empty, and when
131 it isn't, usually there is one change note in it, but since it's possible to have more than one power state change pending
132 at one time, a queue is implemented. Example: the subclass device decides it's idle and initiates a change to a lower
133 power state. This causes interested parties to be notified, but they don't all acknowledge right away. This causes the
134 change note to sit in the queue until all the acks are received. During this time, the device decides it isn't idle anymore and
135 wants to raise power back up again. This change can't be started, however, because the previous one isn't complete yet,
136 so the second one waits in the queue. During this time, the parent decides to lower or raise the power state of the entire
137 power domain and notifies the device, and that notification goes into the queue, too, and can't be actioned until the
140 This is how a power change initiated by the subclass device is handled:
141 First, all interested parties are notified of the change via their powerStateWillChangeTo method. If they all don't
142 acknowledge via return code, then we have to wait. If they do, or when they finally all acknowledge via our
143 acknowledgePowerChange method, then we can continue. We call the controlling driver, instructing it to change to
144 the new state. Then we wait for power to settle. If there is no settling-time, or after it has passed, we notify
145 interested parties again, this time via their powerStateDidChangeTo methods. When they have all acked, we're done.
146 If we lowered power and don't need the power domain to be in its current power state, we suggest to the parent that
147 it lower the power domain state.
149 This is how a change to a lower power domain state initiated by the parent is handled:
150 First, we figure out what power state we will be in when the new domain state is reached. Then all interested parties are
151 notified that we are moving to that new state. When they have acknowledged, we call the controlling driver to assume
152 that state and we wait for power to settle. Then we acknowledge our preparedness to our parent. When all its interested
153 parties have acknowledged, it lowers power and then notifies its interested parties again. When we get this call, we notify
154 our interested parties that the power state has changed, and when they have all acknowledged, we're done.
156 This is how a change to a higher power domain state initiated by the parent is handled:
157 We figure out what power state we will be in when the new domain state is reached. If it is different from our current
158 state we acknowledge the parent. When all the parent's interested parties have acknowledged, it raises power in the
159 domain and waits for power to settle. Then it notifies everyone that the new state has been reached. When we get this call,
160 we call the controlling driver, instructing it to assume the new state, and wait for power to settle. Then we notify our interested
161 parties. When they all acknowledge we are done.
163 In either of the two cases above, it is possible that we will not be changing state even though the domain is. Examples:
164 A change to a lower domain state may not affect us because we are already in a low enough state, and
165 We will not take advantage of a change to a higher domain state, because we have no need of the higher power.
166 In such a case, there is nothing to do but acknowledge the parent. So when the parent calls our powerDomainWillChange
167 method, and we decide that we will not be changing state, we merely acknowledge the parent, via return code, and wait.
168 When the parent subsequently calls powerStateDidChange, we acknowledge again via return code, and the change is complete.
170 Power state changes are processed in a state machine, and since there are four varieties of power state changes, there are
171 four major paths through the state machine:
173 The fourth is nearly trivial. In this path, the parent is changing the domain state, but we are not changing the device state.
174 The change starts when the parent calls powerDomainWillChange. All we do is acknowledge the parent.
175 When the parent calls powerStateDidChange, we acknowledge the parent again, and we're done.
177 The first is fairly simple. It starts when a power domain child calls requestPowerDomainState and we decide to change power states
178 to accomodate the child, or if our power-controlling driver calls changePowerStateTo, or if some other driver which is using our
179 device calls makeUsable, or if a subclassed object calls changePowerStateToPriv. These are all power changes initiated by us, not
180 forced upon us by the parent. We start by notifying interested parties. If they all acknowledge via return code, we can go
181 on to state "OurChangeSetPowerState". Otherwise, we start the ack timer and wait for the stragglers to acknowlege by calling
182 acknowledgePowerChange. We move on to state "OurChangeSetPowerState" when all the stragglers have acknowledged,
183 or when the ack timer expires on all those which didn't acknowledge. In "OurChangeSetPowerState" we call the power-controlling
184 driver to change the power state of the hardware. If it returns saying it has done so, we go on to state "OurChangeWaitForPowerSettle".
185 Otherwise, we have to wait for it, so we set the ack timer and wait. When it calls acknowledgeSetPowerState, or when the
186 ack timer expires, we go on. In "OurChangeWaitForPowerSettle", we look in the power state array to see if there is any settle time required
187 when changing from our current state to the new state. If not, we go right away to "OurChangeNotifyInterestedDriversDidChange". Otherwise, we
188 set the settle timer and wait. When it expires, we move on. In "OurChangeNotifyInterestedDriversDidChange" state, we notify all our interested parties
189 via their powerStateDidChange methods that we have finished changing power state. If they all acknowledge via return
190 code, we move on to "OurChangeFinish". Otherwise we set the ack timer and wait. When they have all acknowledged, or
191 when the ack timer has expired for those that didn't, we move on to "OurChangeFinish", where we remove the used
192 change note from the head of the queue and start the next one if one exists.
194 Parent-initiated changes are more complex in the state machine. First, power going up and power going down are handled
195 differently, so they have different paths throught the state machine. Second, we can acknowledge the parent's notification
196 in two different ways, so each of the parent paths is really two.
198 When the parent calls our powerDomainWillChange method, notifying us that it will lower power in the domain, we decide
199 what state that will put our device in. Then we embark on the state machine path "IOPMParentDownSetPowerState_Immediate"
200 and "kIOPM_ParentDownWaitForPowerSettleAndNotifyDidChange_Immediate", in which we notify interested parties of the upcoming change, instruct our driver to make
201 the change, check for settle time, and notify interested parties of the completed change. If we get to the end of this path without
202 stalling due to an interested party which didn't acknowledge via return code, due to the controlling driver not able to change
203 state right away, or due to a non-zero settling time, then we return IOPMAckImplied to the parent, and we're done with the change.
204 If we do stall in any of those states, we return IOPMWillAckLater to the parent and enter the parallel path "kIOPM_ParentDownSetPowerState_Delayed"
205 "kIOPM_ParentDownWaitForPowerSettle_Delayed", and "kIOPM_ParentDownNotifyDidChangeAndAcknowledgeChange_Delayed", where we continue with the same processing, except that at the end we
206 acknowledge the parent explicitly via acknowledgePowerChange, and we're done with the change.
207 Then when the parent calls us at powerStateDidChange we acknowledging via return code, because we have already made
208 the power change. In any case, when we are done we remove the used change note from the head of the queue and start on the next one.
210 The case of the parent raising power in the domain is handled similarly in that there are parallel paths, one for no-stall
211 that ends in implicit acknowleging the parent, and one that has stalled at least once that ends in explicit acknowledging
212 the parent. This case is different, though in that our device changes state in the second half, after the parent calls
213 powerStateDidChange rather than before, as in the power-lowering case.
215 When the parent calls our powerDomainWillChange method, notifying us that it will raise power in the domain, we acknowledge
216 via return code, because there's really nothing we can do until the power is actually raised in the domain.
217 When the parent calls us at powerStateDidChange, we start by notifying our interested parties. If they all acknowledge via return code,
218 we go on to" kIOPM_ParentUpSetPowerState_Immediate" to instruct the driver to raise its power level. After that, we check for any
219 necessary settling time in "IOPMParentUpWaitForSettleTime_Immediate", and we notify all interested parties that power has changed
220 in "IOPMParentUpNotifyInterestedDriversDidChange_Immediate". If none of these operations stall, we acknowledge the parent via return code, release
221 the change note, and start the next, if there is one. If one of them does stall, we enter the parallel path "kIOPM_ParentUpSetPowerState_Delayed",
222 "kIOPM_ParentUpWaitForSettleTime_Delayed", "kIOPM_ParentUpNotifyInterestedDriversDidChange_Delayed", and "kIOPM_ParentUpAcknowledgePowerChange_Delayed", which ends with
223 our explicit acknowledgement to the parent.
228 const char priv_key
[ ] = "Power Management private data";
229 const char prot_key
[ ] = "Power Management protected data";
232 void IOService::PMinit ( void )
234 if ( ! initialized
) {
236 // make space for our variables
237 pm_vars
= new IOPMprot
;
243 // add pm_vars & priv to the properties
244 setProperty(prot_key
, (OSObject
*) pm_vars
);
245 setProperty(priv_key
, (OSObject
*) priv
);
247 // then initialize them
249 pm_vars
->theNumberOfPowerStates
= 0;
250 priv
->we_are_root
= false;
251 pm_vars
->theControllingDriver
= NULL
;
252 priv
->our_lock
= IOLockAlloc();
253 priv
->flags_lock
= IOLockAlloc();
254 priv
->queue_lock
= IOLockAlloc();
255 pm_vars
->childLock
= IOLockAlloc();
256 pm_vars
->parentLock
= IOLockAlloc();
257 priv
->interestedDrivers
= new IOPMinformeeList
;
258 priv
->interestedDrivers
->initialize();
259 priv
->changeList
= new IOPMchangeNoteList
;
260 priv
->changeList
->initialize();
261 pm_vars
->aggressiveness
= 0;
262 for (unsigned int i
= 0; i
<= kMaxType
; i
++)
264 pm_vars
->current_aggressiveness_values
[i
] = 0;
265 pm_vars
->current_aggressiveness_valid
[i
] = false;
267 pm_vars
->myCurrentState
= 0;
268 priv
->imminentState
= 0;
269 priv
->ourDesiredPowerState
= 0;
270 pm_vars
->parentsCurrentPowerFlags
= 0;
271 pm_vars
->maxCapability
= 0;
272 priv
->driverDesire
= 0;
273 priv
->deviceDesire
= 0;
274 priv
->initial_change
= true;
275 priv
->need_to_become_usable
= false;
276 priv
->previousRequest
= 0;
277 priv
->device_overrides
= false;
278 priv
->machine_state
= kIOPM_Finished
;
279 priv
->timerEventSrc
= NULL
;
280 priv
->clampTimerEventSrc
= NULL
;
281 pm_vars
->PMworkloop
= NULL
;
282 priv
->activityLock
= NULL
;
283 pm_vars
->ourName
= getName();
284 pm_vars
->thePlatform
= getPlatform();
285 pm_vars
->parentsKnowState
= false;
286 assert( pm_vars
->thePlatform
!= 0 );
287 priv
->clampOn
= false;
288 pm_vars
->serialNumber
= 0;
289 pm_vars
->responseFlags
= NULL
;
290 pm_vars
->doNotPowerDown
= true;
291 pm_vars
->PMcommandGate
= NULL
;
292 priv
->ackTimer
= thread_call_allocate((thread_call_func_t
)ack_timer_expired
, (thread_call_param_t
)this);
293 priv
->settleTimer
= thread_call_allocate((thread_call_func_t
)settle_timer_expired
, (thread_call_param_t
)this);
299 //*********************************************************************************
302 // Free up the data created in PMinit, if it exists.
303 //*********************************************************************************
304 void IOService::PMfree ( void )
307 if ( priv
->clampTimerEventSrc
!= NULL
) {
308 getPMworkloop()->removeEventSource(priv
->clampTimerEventSrc
);
309 priv
->clampTimerEventSrc
->release();
310 priv
->clampTimerEventSrc
= NULL
;
312 if ( priv
->timerEventSrc
!= NULL
) {
313 pm_vars
->PMworkloop
->removeEventSource(priv
->timerEventSrc
);
314 priv
->timerEventSrc
->release();
315 priv
->timerEventSrc
= NULL
;
317 if ( priv
->settleTimer
) {
318 thread_call_cancel(priv
->settleTimer
);
319 thread_call_free(priv
->settleTimer
);
320 priv
->settleTimer
= NULL
;
322 if ( priv
->ackTimer
) {
323 thread_call_cancel(priv
->ackTimer
);
324 thread_call_free(priv
->ackTimer
);
325 priv
->ackTimer
= NULL
;
327 if ( priv
->our_lock
) {
328 IOLockFree(priv
->our_lock
);
329 priv
->our_lock
= NULL
;
331 if ( priv
->flags_lock
) {
332 IOLockFree(priv
->flags_lock
);
333 priv
->flags_lock
= NULL
;
335 if ( priv
->activityLock
) {
336 IOLockFree(priv
->activityLock
);
337 priv
->activityLock
= NULL
;
339 priv
->interestedDrivers
->release();
340 priv
->changeList
->release();
341 // remove instance variables
346 if ( pm_vars
->PMcommandGate
) {
347 if(pm_vars
->PMworkloop
)
348 pm_vars
->PMworkloop
->removeEventSource(pm_vars
->PMcommandGate
);
349 pm_vars
->PMcommandGate
->release();
350 pm_vars
->PMcommandGate
= NULL
;
352 if ( pm_vars
->PMworkloop
) {
353 // The work loop object returned from getPMworkLoop() is
354 // never retained, therefore it should not be released.
355 // pm_vars->PMworkloop->release();
356 pm_vars
->PMworkloop
= NULL
;
358 if ( pm_vars
->responseFlags
) {
359 pm_vars
->responseFlags
->release();
360 pm_vars
->responseFlags
= NULL
;
362 // remove instance variables
368 //*********************************************************************************
371 // Disconnect the node from its parents and children in the Power Plane.
372 //*********************************************************************************
373 void IOService::PMstop ( void )
377 IOPowerConnection
* connection
;
378 IOService
* theChild
;
379 IOService
* theParent
;
381 // remove the properties
382 removeProperty(prot_key
);
383 removeProperty(priv_key
);
386 iter
= getParentIterator(gIOPowerPlane
);
390 while ( (next
= iter
->getNextObject()) )
392 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) )
394 theParent
= (IOService
*)connection
->copyParentEntry(gIOPowerPlane
);
397 theParent
->removePowerChild(connection
);
398 theParent
->release();
405 // detach IOConnections
406 detachAbove( gIOPowerPlane
);
410 // no more power state changes
411 pm_vars
->parentsKnowState
= false;
415 iter
= getChildIterator(gIOPowerPlane
);
419 while ( (next
= iter
->getNextObject()) )
421 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) )
423 theChild
= ((IOService
*)(connection
->copyChildEntry(gIOPowerPlane
)));
426 // detach nub from child
427 connection
->detachFromChild(theChild
,gIOPowerPlane
);
430 // detach us from nub
431 detachFromChild(connection
,gIOPowerPlane
);
437 // Remove all interested drivers from the list, including the power
438 // controlling driver.
440 // Usually, the controlling driver and the policy-maker functionality
441 // are implemented by the same object, and without the deregistration,
442 // the object will be holding an extra retain on itself, and cannot
445 if ( priv
&& priv
->interestedDrivers
)
447 IOPMinformee
* informee
;
449 while (( informee
= priv
->interestedDrivers
->firstInList() ))
450 deRegisterInterestedDriver( informee
->whatObject
);
455 //*********************************************************************************
458 // A policy-maker calls its nub here when initializing, to be attached into
459 // the power management hierarchy. The default function is to call the
460 // platform expert, which knows how to do it. This method is overridden
461 // by a nub subclass which may either know how to do it, or may need
462 // to take other action.
464 // This may be the only "power management" method used in a nub,
465 // meaning it may not be initialized for power management.
466 //*********************************************************************************
467 void IOService::joinPMtree ( IOService
* driver
)
469 IOPlatformExpert
* thePlatform
;
471 thePlatform
= getPlatform();
472 assert(thePlatform
!= 0 );
473 thePlatform
->PMRegisterDevice(this,driver
);
477 //*********************************************************************************
480 // Power Managment is informing us that we are the root power domain.
481 // The only difference between us and any other power domain is that
482 // we have no parent and therefore never call it.
483 //*********************************************************************************
484 IOReturn
IOService::youAreRoot ( void )
486 priv
-> we_are_root
= true;
487 pm_vars
->parentsKnowState
= true;
488 attachToParent( getRegistryRoot(),gIOPowerPlane
);
494 //*********************************************************************************
497 // Power Management is informing us who our parent is.
498 // If we have a controlling driver, find out, given our newly-informed
499 // power domain state, what state it would be in, and then tell it
500 // to assume that state.
501 //*********************************************************************************
502 IOReturn
IOService::setPowerParent ( IOPowerConnection
* theParent
, bool stateKnown
, IOPMPowerFlags currentState
)
506 IOPowerConnection
* connection
;
507 unsigned long tempDesire
;
509 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogSetParent
,stateKnown
,currentState
);
511 IOLockLock(pm_vars
->parentLock
);
513 if ( stateKnown
&& ((pm_vars
->PMworkloop
== NULL
) || (pm_vars
->PMcommandGate
== NULL
)) )
515 // we have a path to the root
516 // find out the workloop
518 if ( pm_vars
->PMworkloop
!= NULL
)
520 if ( pm_vars
->PMcommandGate
== NULL
)
522 // and make our command gate
523 pm_vars
->PMcommandGate
= IOCommandGate::commandGate((OSObject
*)this);
524 if ( pm_vars
->PMcommandGate
!= NULL
)
526 pm_vars
->PMworkloop
->addEventSource(pm_vars
->PMcommandGate
);
532 IOLockUnlock(pm_vars
->parentLock
);
534 // set our connection data
535 theParent
->setParentCurrentPowerFlags(currentState
);
536 theParent
->setParentKnowsState(stateKnown
);
538 // combine parent knowledge
539 pm_vars
->parentsKnowState
= true;
540 pm_vars
->parentsCurrentPowerFlags
= 0;
542 iter
= getParentIterator(gIOPowerPlane
);
546 while ( (next
= iter
->getNextObject()) )
548 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) )
550 pm_vars
->parentsKnowState
&= connection
->parentKnowsState();
551 pm_vars
->parentsCurrentPowerFlags
|= connection
->parentCurrentPowerFlags();
557 if ( (pm_vars
->theControllingDriver
!= NULL
) &&
558 (pm_vars
->parentsKnowState
) )
560 pm_vars
->maxCapability
= pm_vars
->theControllingDriver
->maxCapabilityForDomainState(pm_vars
->parentsCurrentPowerFlags
);
561 // initially change into the state we are already in
562 tempDesire
= priv
->deviceDesire
;
563 priv
->deviceDesire
= pm_vars
->theControllingDriver
->initialPowerStateForDomainState(pm_vars
->parentsCurrentPowerFlags
);
564 computeDesiredState();
565 priv
->previousRequest
= 0xffffffff;
567 // put this back like before
568 priv
->deviceDesire
= tempDesire
;
575 //*********************************************************************************
578 // Power Management is informing us who our children are.
579 //*********************************************************************************
580 IOReturn
IOService::addPowerChild ( IOService
* theChild
)
582 IOPowerConnection
*connection
;
587 // we're not a power-managed IOService
588 return IOPMNotYetInitialized
;
591 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogAddChild
,0,0);
593 // Put ourselves into a usable power state.
594 // We must be in an "on" power state, as our children must be able to access
595 // our hardware after joining the power plane.
599 connection
= new IOPowerConnection
;
602 connection
->start(this);
603 connection
->setAwaitingAck(false);
606 attachToChild( connection
,gIOPowerPlane
);
607 connection
->attachToChild( theChild
,gIOPowerPlane
);
608 connection
->release();
610 // tell it the current state of the power domain
611 if ( (pm_vars
->theControllingDriver
== NULL
) ||
612 ! (inPlane(gIOPowerPlane
)) ||
613 ! (pm_vars
->parentsKnowState
) )
615 theChild
->setPowerParent(connection
,false,0);
616 if ( inPlane(gIOPowerPlane
) )
618 for (i
= 0; i
<= kMaxType
; i
++) {
619 if ( pm_vars
->current_aggressiveness_valid
[i
] )
621 theChild
->setAggressiveness (i
, pm_vars
->current_aggressiveness_values
[i
]);
626 theChild
->setPowerParent(connection
,true,pm_vars
->thePowerStates
[pm_vars
->myCurrentState
].outputPowerCharacter
);
627 for (i
= 0; i
<= kMaxType
; i
++)
629 if ( pm_vars
->current_aggressiveness_valid
[i
] )
631 theChild
->setAggressiveness (i
, pm_vars
->current_aggressiveness_values
[i
]);
634 // catch it up if change is in progress
635 add_child_to_active_change(connection
);
642 //*********************************************************************************
645 //*********************************************************************************
646 IOReturn
IOService::removePowerChild ( IOPowerConnection
* theNub
)
648 IORegistryEntry
*theChild
;
651 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogRemoveChild
,0,0);
655 // detach nub from child
656 theChild
= theNub
->copyChildEntry(gIOPowerPlane
);
659 theNub
->detachFromChild(theChild
, gIOPowerPlane
);
662 // detach from the nub
663 detachFromChild(theNub
,gIOPowerPlane
);
665 // are we awaiting an ack from this child?
666 if ( theNub
->getAwaitingAck() )
668 // yes, pretend we got one
669 theNub
->setAwaitingAck(false);
670 if ( acquire_lock() )
672 if (priv
->head_note_pendingAcks
!= 0 )
674 // that's one fewer ack to worry about
675 priv
->head_note_pendingAcks
-= 1;
677 if ( priv
->head_note_pendingAcks
== 0 )
679 // yes, stop the timer
681 IOUnlock(priv
->our_lock
);
682 // and now we can continue our power change
685 IOUnlock(priv
->our_lock
);
688 IOUnlock(priv
->our_lock
);
695 // if not fully initialized
696 if ( (pm_vars
->theControllingDriver
== NULL
) ||
697 !(inPlane(gIOPowerPlane
)) ||
698 !(pm_vars
->parentsKnowState
) )
704 // Perhaps the departing child was holding up idle or system sleep - we need to re-evaluate our
705 // childrens' requests. Clear and re-calculate our kIOPMChildClamp and kIOPMChildClamp2 bits.
706 rebuildChildClampBits();
711 iter
= getChildIterator(gIOPowerPlane
);
712 if ( !iter
|| !iter
->getNextObject() )
714 // paired to match the makeUsable() call in addPowerChild()
715 changePowerStateToPriv(0);
717 if(iter
) iter
->release();
720 // this may be different now
721 computeDesiredState();
722 // change state if we can now tolerate lower power
729 //*********************************************************************************
730 // registerPowerDriver
732 // A driver has called us volunteering to control power to our device.
733 // If the power state array it provides is richer than the one we already
734 // know about (supplied by an earlier volunteer), then accept the offer.
735 // Notify all interested parties of our power state, which we now know.
736 //*********************************************************************************
738 IOReturn
IOService::registerPowerDriver ( IOService
* controllingDriver
, IOPMPowerState
* powerStates
, unsigned long numberOfStates
)
741 unsigned long tempDesire
;
743 if ( (numberOfStates
> pm_vars
->theNumberOfPowerStates
)
744 && (numberOfStates
> 1) )
746 if ( priv
->changeList
->currentChange() == -1 )
748 if ( controllingDriver
!= NULL
)
750 if ( numberOfStates
<= IOPMMaxPowerStates
)
752 switch ( powerStates
[0].version
)
755 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogControllingDriver
,
756 (unsigned long)numberOfStates
, (unsigned long)powerStates
[0].version
);
757 for ( i
= 0; i
< numberOfStates
; i
++ )
759 pm_vars
->thePowerStates
[i
] = powerStates
[i
];
763 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogControllingDriver
,
764 (unsigned long) numberOfStates
,(unsigned long) powerStates
[0].version
);
765 for ( i
= 0; i
< numberOfStates
; i
++ )
767 pm_vars
->thePowerStates
[i
].version
= powerStates
[i
].version
;
768 pm_vars
->thePowerStates
[i
].capabilityFlags
= powerStates
[i
].capabilityFlags
;
769 pm_vars
->thePowerStates
[i
].outputPowerCharacter
= powerStates
[i
].outputPowerCharacter
;
770 pm_vars
->thePowerStates
[i
].inputPowerRequirement
= powerStates
[i
].inputPowerRequirement
;
771 pm_vars
->thePowerStates
[i
].staticPower
= powerStates
[i
].staticPower
;
772 pm_vars
->thePowerStates
[i
].unbudgetedPower
= powerStates
[i
].unbudgetedPower
;
773 pm_vars
->thePowerStates
[i
].powerToAttain
= powerStates
[i
].powerToAttain
;
774 pm_vars
->thePowerStates
[i
].timeToAttain
= powerStates
[i
].timeToAttain
;
775 pm_vars
->thePowerStates
[i
].settleUpTime
= powerStates
[i
].settleUpTime
;
776 pm_vars
->thePowerStates
[i
].timeToLower
= powerStates
[i
].timeToLower
;
777 pm_vars
->thePowerStates
[i
].settleDownTime
= powerStates
[i
].settleDownTime
;
778 pm_vars
->thePowerStates
[i
].powerDomainBudget
= powerStates
[i
].powerDomainBudget
;
782 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogControllingDriverErr1
,
783 (unsigned long)powerStates
[0].version
,0);
787 // make a mask of all the character bits we know about
788 pm_vars
->myCharacterFlags
= 0;
789 for ( i
= 0; i
< numberOfStates
; i
++ ) {
790 pm_vars
->myCharacterFlags
|= pm_vars
->thePowerStates
[i
].outputPowerCharacter
;
793 pm_vars
->theNumberOfPowerStates
= numberOfStates
;
794 pm_vars
->theControllingDriver
= controllingDriver
;
795 if ( priv
->interestedDrivers
->findItem(controllingDriver
) == NULL
)
797 // register it as interested, unless already done
798 registerInterestedDriver (controllingDriver
);
800 if ( priv
->need_to_become_usable
) {
801 priv
->need_to_become_usable
= false;
802 priv
->deviceDesire
= pm_vars
->theNumberOfPowerStates
- 1;
805 if ( inPlane(gIOPowerPlane
) &&
806 (pm_vars
->parentsKnowState
) ) {
807 pm_vars
->maxCapability
= pm_vars
->theControllingDriver
->maxCapabilityForDomainState(pm_vars
->parentsCurrentPowerFlags
);
808 // initially change into the state we are already in
809 tempDesire
= priv
->deviceDesire
;
810 priv
->deviceDesire
= pm_vars
->theControllingDriver
->initialPowerStateForDomainState(pm_vars
->parentsCurrentPowerFlags
);
811 computeDesiredState();
813 // put this back like before
814 priv
->deviceDesire
= tempDesire
;
817 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogControllingDriverErr2
,(unsigned long)numberOfStates
,0);
820 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogControllingDriverErr4
,0,0);
825 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogControllingDriverErr5
,(unsigned long)numberOfStates
,0);
830 //*********************************************************************************
831 // registerInterestedDriver
833 // Add the caller to our list of interested drivers and return our current
834 // power state. If we don't have a power-controlling driver yet, we will
835 // call this interested driver again later when we do get a driver and find
836 // out what the current power state of the device is.
837 //*********************************************************************************
839 IOPMPowerFlags
IOService::registerInterestedDriver ( IOService
* theDriver
)
841 IOPMinformee
*newInformee
;
842 IOPMPowerFlags futureCapability
;
844 if (theDriver
== NULL
) {
848 // make new driver node
849 newInformee
= new IOPMinformee
;
850 newInformee
->initialize(theDriver
);
851 // add it to list of drivers
852 priv
->interestedDrivers
->addToList(newInformee
);
854 if ( (pm_vars
->theControllingDriver
== NULL
) ||
855 !(inPlane(gIOPowerPlane
)) ||
856 !(pm_vars
->parentsKnowState
) )
858 // can't tell it a state yet
859 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogInterestedDriver
,IOPMNotPowerManaged
,0);
860 return IOPMNotPowerManaged
;
863 // can we notify new driver of a change in progress?
864 switch (priv
->machine_state
) {
865 case kIOPM_OurChangeSetPowerState
:
866 case kIOPM_OurChangeFinish
:
867 case kIOPM_ParentDownSetPowerState_Delayed
:
868 case kIOPM_ParentDownAcknowledgeChange_Delayed
:
869 case kIOPM_ParentUpSetPowerState_Delayed
:
870 case kIOPM_ParentUpAcknowledgePowerChange_Delayed
:
871 // yes, remember what we tell it
872 futureCapability
= priv
->head_note_capabilityFlags
;
873 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogInterestedDriver
,(unsigned long)futureCapability
,1);
875 add_driver_to_active_change(newInformee
);
876 // and return the same thing
877 return futureCapability
;
880 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogInterestedDriver
,
881 (unsigned long) pm_vars
->thePowerStates
[pm_vars
->myCurrentState
].capabilityFlags
,2);
883 // no, return current capability
884 return pm_vars
->thePowerStates
[pm_vars
->myCurrentState
].capabilityFlags
;
888 //*********************************************************************************
889 // deRegisterInterestedDriver
891 //*********************************************************************************
892 IOReturn
IOService::deRegisterInterestedDriver ( IOService
* theDriver
)
894 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogRemoveDriver
,0,0);
896 // remove the departing driver
897 priv
->interestedDrivers
->removeFromList(theDriver
);
903 //*********************************************************************************
904 // acknowledgePowerChange
906 // After we notified one of the interested drivers or a power-domain child
907 // of an impending change in power, it has called to say it is now
908 // prepared for the change. If this object is the last to
909 // acknowledge this change, we take whatever action we have been waiting
911 // That may include acknowledging to our parent. In this case, we do it
912 // last of all to insure that this doesn't cause the parent to call us some-
913 // where else and alter data we are relying on here (like the very existance
914 // of a "current change note".)
915 //*********************************************************************************
917 IOReturn
IOService::acknowledgePowerChange ( IOService
* whichObject
)
919 IOPMinformee
*ackingObject
;
920 unsigned long childPower
= kIOPMUnknown
;
923 // one of our interested drivers?
924 ackingObject
= priv
->interestedDrivers
->findItem(whichObject
);
925 if ( ackingObject
== NULL
)
927 if ( ! isChild(whichObject
,gIOPowerPlane
) )
929 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogAcknowledgeErr1
,0,0);
930 //kprintf("errant driver: %s\n",whichObject->getName());
934 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogChildAcknowledge
,priv
->head_note_pendingAcks
,0);
937 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogDriverAcknowledge
,priv
->head_note_pendingAcks
,0);
940 if (! acquire_lock() )
945 if (priv
->head_note_pendingAcks
!= 0 )
947 // yes, make sure we're expecting acks
948 if ( ackingObject
!= NULL
)
950 // it's an interested driver
951 // make sure we're expecting this ack
952 if ( ackingObject
->timer
!= 0 )
955 ackingObject
->timer
= 0;
956 // that's one fewer to worry about
957 priv
->head_note_pendingAcks
-= 1;
959 if ( priv
->head_note_pendingAcks
== 0 )
961 // yes, stop the timer
963 IOUnlock(priv
->our_lock
);
964 // and now we can continue
969 // this driver has already acked
970 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogAcknowledgeErr2
,0,0);
971 //kprintf("errant driver: %s\n",whichObject->getName());
975 // make sure we're expecting this ack
976 if ( ((IOPowerConnection
*)whichObject
)->getAwaitingAck() )
978 // that's one fewer to worry about
979 priv
->head_note_pendingAcks
-= 1;
980 ((IOPowerConnection
*)whichObject
)->setAwaitingAck(false);
981 theChild
= (IOService
*)whichObject
->copyChildEntry(gIOPowerPlane
);
984 childPower
= theChild
->currentPowerConsumption();
987 if ( childPower
== kIOPMUnknown
)
989 pm_vars
->thePowerStates
[priv
->head_note_state
].staticPower
= kIOPMUnknown
;
991 if ( pm_vars
->thePowerStates
[priv
->head_note_state
].staticPower
!= kIOPMUnknown
)
993 pm_vars
->thePowerStates
[priv
->head_note_state
].staticPower
+= childPower
;
997 if ( priv
->head_note_pendingAcks
== 0 ) {
998 // yes, stop the timer
1000 IOUnlock(priv
->our_lock
);
1001 // and now we can continue
1008 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogAcknowledgeErr3
,0,0); // not expecting anybody to ack
1009 //kprintf("errant driver: %s\n",whichObject->getName());
1011 IOUnlock(priv
->our_lock
);
1015 //*********************************************************************************
1016 // acknowledgeSetPowerState
1018 // After we instructed our controlling driver to change power states,
1019 // it has called to say it has finished doing so.
1020 // We continue to process the power state change.
1021 //*********************************************************************************
1023 IOReturn
IOService::acknowledgeSetPowerState ( void )
1025 if (!acquire_lock())
1028 IOReturn timer
= priv
->driver_timer
;
1029 if ( timer
== -1 ) {
1030 // driver is acking instead of using return code
1031 OUR_PMLog(kPMLogDriverAcknowledgeSet
, (UInt32
) this, timer
);
1032 priv
->driver_timer
= 0;
1034 else if ( timer
> 0 ) { // are we expecting this?
1035 // yes, stop the timer
1037 priv
->driver_timer
= 0;
1038 OUR_PMLog(kPMLogDriverAcknowledgeSet
, (UInt32
) this, timer
);
1039 IOUnlock(priv
->our_lock
);
1043 // not expecting this
1044 OUR_PMLog(kPMLogAcknowledgeErr4
, (UInt32
) this, 0);
1047 IOUnlock(priv
->our_lock
);
1052 //*********************************************************************************
1055 // Either the controlling driver has called acknowledgeSetPowerState
1056 // or the acknowledgement timer has expired while waiting for that.
1057 // We carry on processing the current change note.
1058 //*********************************************************************************
1060 void IOService::driver_acked ( void )
1062 switch (priv
->machine_state
) {
1063 case kIOPM_OurChangeWaitForPowerSettle
:
1064 OurChangeWaitForPowerSettle();
1066 case kIOPM_ParentDownWaitForPowerSettle_Delayed
:
1067 ParentDownWaitForPowerSettle_Delayed();
1069 case kIOPM_ParentUpWaitForSettleTime_Delayed
:
1070 ParentUpWaitForSettleTime_Delayed();
1076 //*********************************************************************************
1077 // powerDomainWillChangeTo
1079 // Called by the power-hierarchy parent notifying of a new power state
1080 // in the power domain.
1081 // We enqueue a parent power-change to our queue of power changes.
1082 // This may or may not cause us to change power, depending on what
1083 // kind of change is occuring in the domain.
1084 //*********************************************************************************
1086 IOReturn
IOService::powerDomainWillChangeTo ( IOPMPowerFlags newPowerStateFlags
, IOPowerConnection
* whichParent
)
1090 IOPowerConnection
*connection
;
1091 unsigned long newStateNumber
;
1092 IOPMPowerFlags combinedPowerFlags
;
1094 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogWillChange
,(unsigned long)newPowerStateFlags
,0);
1096 if ( ! inPlane(gIOPowerPlane
) )
1099 return IOPMAckImplied
;
1102 IOLockLock(pm_vars
->parentLock
);
1104 if ( (pm_vars
->PMworkloop
== NULL
) || (pm_vars
->PMcommandGate
== NULL
) )
1106 // we have a path to the root
1108 // so find out the workloop
1109 if ( pm_vars
->PMworkloop
!= NULL
)
1111 // and make our command gate
1112 if ( pm_vars
->PMcommandGate
== NULL
)
1114 pm_vars
->PMcommandGate
= IOCommandGate::commandGate((OSObject
*)this);
1115 if ( pm_vars
->PMcommandGate
!= NULL
)
1117 pm_vars
->PMworkloop
->addEventSource(pm_vars
->PMcommandGate
);
1123 IOLockUnlock(pm_vars
->parentLock
);
1125 // combine parents' power states
1126 // to determine our maximum state within the new power domain
1127 combinedPowerFlags
= 0;
1129 iter
= getParentIterator(gIOPowerPlane
);
1133 while ( (next
= iter
->getNextObject()) )
1135 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) )
1137 if ( connection
== whichParent
){
1138 combinedPowerFlags
|= newPowerStateFlags
;
1140 combinedPowerFlags
|= connection
->parentCurrentPowerFlags();
1147 if ( pm_vars
->theControllingDriver
== NULL
)
1149 // we can't take any more action
1150 return IOPMAckImplied
;
1152 newStateNumber
= pm_vars
->theControllingDriver
->maxCapabilityForDomainState(combinedPowerFlags
);
1154 return enqueuePowerChange(IOPMParentInitiated
| IOPMDomainWillChange
,
1155 newStateNumber
,combinedPowerFlags
,whichParent
,newPowerStateFlags
);
1159 //*********************************************************************************
1160 // powerDomainDidChangeTo
1162 // Called by the power-hierarchy parent after the power state of the power domain
1163 // has settled at a new level.
1164 // We enqueue a parent power-change to our queue of power changes.
1165 // This may or may not cause us to change power, depending on what
1166 // kind of change is occuring in the domain.
1167 //*********************************************************************************
1169 IOReturn
IOService::powerDomainDidChangeTo ( IOPMPowerFlags newPowerStateFlags
, IOPowerConnection
* whichParent
)
1171 unsigned long newStateNumber
;
1173 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogDidChange
,newPowerStateFlags
,0);
1175 setParentInfo(newPowerStateFlags
,whichParent
);
1177 if ( pm_vars
->theControllingDriver
== NULL
) {
1178 return IOPMAckImplied
;
1181 newStateNumber
= pm_vars
->theControllingDriver
->maxCapabilityForDomainState(pm_vars
->parentsCurrentPowerFlags
);
1182 // tell interested parties about it
1183 return enqueuePowerChange(IOPMParentInitiated
| IOPMDomainDidChange
,
1184 newStateNumber
,pm_vars
->parentsCurrentPowerFlags
,whichParent
,0);
1188 //*********************************************************************************
1191 // Set our connection data for one specific parent, and then combine all the parent
1193 //*********************************************************************************
1195 void IOService::setParentInfo ( IOPMPowerFlags newPowerStateFlags
, IOPowerConnection
* whichParent
)
1199 IOPowerConnection
*connection
;
1201 // set our connection data
1202 whichParent
->setParentCurrentPowerFlags(newPowerStateFlags
);
1203 whichParent
->setParentKnowsState(true);
1205 IOLockLock(pm_vars
->parentLock
);
1207 // recompute our parent info
1208 pm_vars
->parentsCurrentPowerFlags
= 0;
1209 pm_vars
->parentsKnowState
= true;
1211 iter
= getParentIterator(gIOPowerPlane
);
1215 while ( (next
= iter
->getNextObject()) )
1217 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) )
1219 pm_vars
->parentsKnowState
&= connection
->parentKnowsState();
1220 pm_vars
->parentsCurrentPowerFlags
|= connection
->parentCurrentPowerFlags();
1225 IOLockUnlock(pm_vars
->parentLock
);
1228 //*********************************************************************************
1229 // rebuildChildClampBits
1231 // The ChildClamp bits (kIOPMChildClamp & kIOPMChildClamp2) in our capabilityFlags
1232 // indicate that one of our children (or grandchildren or great-grandchildren or ...)
1233 // doesn't support idle or system sleep in its current state. Since we don't track the
1234 // origin of each bit, every time any child changes state we have to clear these bits
1235 // and rebuild them.
1236 //*********************************************************************************
1238 void IOService::rebuildChildClampBits(void)
1243 IOPowerConnection
*connection
;
1246 // A child's desires has changed. We need to rebuild the child-clamp bits in our
1247 // power state array. Start by clearing the bits in each power state.
1249 for ( i
= 0; i
< pm_vars
->theNumberOfPowerStates
; i
++ )
1251 pm_vars
->thePowerStates
[i
].capabilityFlags
&= ~(kIOPMChildClamp
| kIOPMChildClamp2
);
1254 // Now loop through the children. When we encounter the calling child, save
1255 // the computed state as this child's desire. And while we're at it, set the ChildClamp bits
1256 // in any of our states that some child has requested with clamp on.
1258 iter
= getChildIterator(gIOPowerPlane
);
1262 while ( (next
= iter
->getNextObject()) )
1264 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) )
1266 if ( connection
->getPreventIdleSleepFlag() )
1267 pm_vars
->thePowerStates
[connection
->getDesiredDomainState()].capabilityFlags
|= kIOPMChildClamp
;
1268 if ( connection
->getPreventSystemSleepFlag() )
1269 pm_vars
->thePowerStates
[connection
->getDesiredDomainState()].capabilityFlags
|= kIOPMChildClamp2
;
1278 //*********************************************************************************
1279 // requestPowerDomainState
1281 // The kIOPMPreventIdleSleep and/or kIOPMPreventIdleSleep bits may be be set in the parameter.
1282 // It is not considered part of the state specification.
1283 //*********************************************************************************
1284 IOReturn
IOService::requestPowerDomainState ( IOPMPowerFlags desiredState
, IOPowerConnection
* whichChild
, unsigned long specification
)
1287 unsigned long computedState
;
1288 unsigned long theDesiredState
= desiredState
& ~(kIOPMPreventIdleSleep
| kIOPMPreventSystemSleep
);
1291 IOPowerConnection
*connection
;
1293 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogRequestDomain
,
1294 (unsigned long)desiredState
,(unsigned long)specification
);
1296 if ( pm_vars
->theControllingDriver
== NULL
)
1298 return IOPMNotYetInitialized
;
1301 switch (specification
) {
1302 case IOPMLowestState
:
1304 while ( i
< pm_vars
->theNumberOfPowerStates
)
1306 if ( ( pm_vars
->thePowerStates
[i
].outputPowerCharacter
& theDesiredState
) == (theDesiredState
& pm_vars
->myCharacterFlags
) )
1312 if ( i
>= pm_vars
->theNumberOfPowerStates
)
1314 return IOPMNoSuchState
;
1318 case IOPMNextLowerState
:
1319 i
= pm_vars
->myCurrentState
- 1;
1320 while ( (int) i
>= 0 )
1322 if ( ( pm_vars
->thePowerStates
[i
].outputPowerCharacter
& theDesiredState
) == (theDesiredState
& pm_vars
->myCharacterFlags
) )
1330 return IOPMNoSuchState
;
1334 case IOPMHighestState
:
1335 i
= pm_vars
->theNumberOfPowerStates
;
1336 while ( (int) i
>= 0 )
1339 if ( ( pm_vars
->thePowerStates
[i
].outputPowerCharacter
& theDesiredState
) == (theDesiredState
& pm_vars
->myCharacterFlags
) )
1346 return IOPMNoSuchState
;
1350 case IOPMNextHigherState
:
1351 i
= pm_vars
->myCurrentState
+ 1;
1352 while ( i
< pm_vars
->theNumberOfPowerStates
)
1354 if ( ( pm_vars
->thePowerStates
[i
].outputPowerCharacter
& theDesiredState
) == (theDesiredState
& pm_vars
->myCharacterFlags
) )
1360 if ( i
== pm_vars
->theNumberOfPowerStates
)
1362 return IOPMNoSuchState
;
1367 return IOPMBadSpecification
;
1372 IOLockLock(pm_vars
->childLock
);
1374 // Now loop through the children. When we encounter the calling child, save
1375 // the computed state as this child's desire.
1376 iter
= getChildIterator(gIOPowerPlane
);
1380 while ( (next
= iter
->getNextObject()) )
1382 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) )
1384 if ( connection
== whichChild
)
1386 connection
->setDesiredDomainState(computedState
);
1387 connection
->setPreventIdleSleepFlag(desiredState
& kIOPMPreventIdleSleep
);
1388 connection
->setPreventSystemSleepFlag(desiredState
& kIOPMPreventSystemSleep
);
1389 connection
->setChildHasRequestedPower();
1396 // Since a child's power requirements may have changed, clear and rebuild
1397 // kIOPMChildClamp and kIOPMChildClamp2 (idle and system sleep clamps)
1398 rebuildChildClampBits();
1400 IOLockUnlock(pm_vars
->childLock
);
1402 // this may be different now
1403 computeDesiredState();
1405 if ( inPlane(gIOPowerPlane
) &&
1406 (pm_vars
->parentsKnowState
) ) {
1407 // change state if all children can now tolerate lower power
1411 // are we clamped on, waiting for this child?
1412 if ( priv
->clampOn
) {
1413 // yes, remove the clamp
1414 priv
->clampOn
= false;
1415 changePowerStateToPriv(0);
1422 //*********************************************************************************
1423 // temporaryPowerClampOn
1425 // A power domain wants to clamp its power on till it has children which
1426 // will thendetermine the power domain state.
1428 // We enter the highest state until addPowerChild is called.
1429 //*********************************************************************************
1431 IOReturn
IOService::temporaryPowerClampOn ( void )
1433 priv
->clampOn
= true;
1439 //*********************************************************************************
1442 // Some client of our device is asking that we become usable. Although
1443 // this has not come from a subclassed device object, treat it exactly
1444 // as if it had. In this way, subsequent requests for lower power from
1445 // a subclassed device object will pre-empt this request.
1447 // We treat this as a subclass object request to switch to the
1448 // highest power state.
1449 //*********************************************************************************
1451 IOReturn
IOService::makeUsable ( void )
1453 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogMakeUsable
,0,0);
1455 if ( pm_vars
->theControllingDriver
== NULL
)
1457 priv
->need_to_become_usable
= true;
1460 priv
->deviceDesire
= pm_vars
->theNumberOfPowerStates
- 1;
1461 computeDesiredState();
1462 if ( inPlane(gIOPowerPlane
) && (pm_vars
->parentsKnowState
) )
1464 return changeState();
1470 //*********************************************************************************
1471 // currentCapability
1473 //*********************************************************************************
1475 IOPMPowerFlags
IOService::currentCapability ( void )
1477 if ( pm_vars
->theControllingDriver
== NULL
)
1481 return pm_vars
->thePowerStates
[pm_vars
->myCurrentState
].capabilityFlags
;
1486 //*********************************************************************************
1487 // changePowerStateTo
1489 // For some reason, our power-controlling driver has decided it needs to change
1490 // power state. We enqueue the power change so that appropriate parties
1491 // will be notified, and then we will instruct the driver to make the change.
1492 //*********************************************************************************
1494 IOReturn
IOService::changePowerStateTo ( unsigned long ordinal
)
1496 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogChangeStateTo
,ordinal
,0);
1498 if ( ordinal
>= pm_vars
->theNumberOfPowerStates
)
1500 return IOPMParameterError
;
1502 priv
->driverDesire
= ordinal
;
1503 computeDesiredState();
1504 if ( inPlane(gIOPowerPlane
) && (pm_vars
->parentsKnowState
) )
1506 return changeState();
1512 //*********************************************************************************
1513 // changePowerStateToPriv
1515 // For some reason, a subclassed device object has decided it needs to change
1516 // power state. We enqueue the power change so that appropriate parties
1517 // will be notified, and then we will instruct the driver to make the change.
1518 //*********************************************************************************
1520 IOReturn
IOService::changePowerStateToPriv ( unsigned long ordinal
)
1522 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogChangeStateToPriv
,ordinal
,0);
1524 if ( pm_vars
->theControllingDriver
== NULL
)
1526 return IOPMNotYetInitialized
;
1528 if ( ordinal
>= pm_vars
->theNumberOfPowerStates
)
1530 return IOPMParameterError
;
1532 priv
->deviceDesire
= ordinal
;
1533 computeDesiredState();
1534 if ( inPlane(gIOPowerPlane
) && (pm_vars
->parentsKnowState
) )
1536 return changeState();
1543 //*********************************************************************************
1544 // computeDesiredState
1546 //*********************************************************************************
1548 void IOService::computeDesiredState ( void )
1552 IOPowerConnection
*connection
;
1553 unsigned long newDesiredState
= 0;
1555 // Compute the maximum of our children's desires, our controlling driver's desire, and the subclass device's desire.
1556 if ( ! priv
->device_overrides
)
1558 iter
= getChildIterator(gIOPowerPlane
);
1562 while ( (next
= iter
->getNextObject()) )
1564 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) )
1566 if ( connection
->getDesiredDomainState() > newDesiredState
)
1568 newDesiredState
= connection
->getDesiredDomainState();
1575 if ( priv
->driverDesire
> newDesiredState
)
1577 newDesiredState
= priv
->driverDesire
;
1581 if ( priv
->deviceDesire
> newDesiredState
)
1583 newDesiredState
= priv
->deviceDesire
;
1586 priv
->ourDesiredPowerState
= newDesiredState
;
1590 //*********************************************************************************
1593 // A subclass object, our controlling driver, or a power domain child
1594 // has asked for a different power state. Here we compute what new
1595 // state we should enter and enqueue the change (or start it).
1596 //*********************************************************************************
1598 IOReturn
IOService::changeState ( void )
1600 // if not fully initialized
1601 if ( (pm_vars
->theControllingDriver
== NULL
) ||
1602 !(inPlane(gIOPowerPlane
)) ||
1603 !(pm_vars
->parentsKnowState
) )
1605 // we can do no more
1609 return enqueuePowerChange(IOPMWeInitiated
,priv
->ourDesiredPowerState
,0,0,0);
1613 //*********************************************************************************
1614 // currentPowerConsumption
1616 //*********************************************************************************
1618 unsigned long IOService::currentPowerConsumption ( void )
1620 if ( pm_vars
->theControllingDriver
== NULL
)
1622 return kIOPMUnknown
;
1624 if ( pm_vars
->thePowerStates
[pm_vars
->myCurrentState
].capabilityFlags
& kIOPMStaticPowerValid
)
1626 return pm_vars
->thePowerStates
[pm_vars
->myCurrentState
].staticPower
;
1628 return kIOPMUnknown
;
1631 //*********************************************************************************
1634 // The activity tickle with parameter kIOPMSubclassPolicyis not handled
1635 // here and should have been intercepted by the subclass.
1636 // The tickle with parameter kIOPMSuperclassPolicy1 causes the activity
1637 // flag to be set, and the device state checked. If the device has been
1638 // powered down, it is powered up again.
1639 //*********************************************************************************
1641 bool IOService::activityTickle ( unsigned long type
, unsigned long stateNumber
)
1643 IOPMrootDomain
*pmRootDomain
;
1644 AbsoluteTime uptime
;
1646 if ( type
== kIOPMSuperclassPolicy1
)
1648 if ( pm_vars
->theControllingDriver
== NULL
)
1653 if( priv
->activityLock
== NULL
)
1655 priv
->activityLock
= IOLockAlloc();
1658 IOTakeLock(priv
->activityLock
);
1659 priv
->device_active
= true;
1661 clock_get_uptime(&uptime
);
1662 priv
->device_active_timestamp
= uptime
;
1664 if ( pm_vars
->myCurrentState
>= stateNumber
)
1666 IOUnlock(priv
->activityLock
);
1669 IOUnlock(priv
->activityLock
);
1671 // Transfer execution to the PM workloop
1672 if( (pmRootDomain
= getPMRootDomain()) )
1673 pmRootDomain
->unIdleDevice(this, stateNumber
);
1680 //*********************************************************************************
1683 // A child is calling to get a pointer to the Power Management workloop.
1684 // We got it or get it from one of our parents.
1685 //*********************************************************************************
1687 IOWorkLoop
* IOService::getPMworkloop ( void )
1692 if ( ! inPlane(gIOPowerPlane
) )
1696 // we have no workloop yet
1697 if ( pm_vars
->PMworkloop
== NULL
)
1699 nub
= (IOService
*)copyParentEntry(gIOPowerPlane
);
1702 parent
= (IOService
*)nub
->copyParentEntry(gIOPowerPlane
);
1704 // ask one of our parents for the workloop
1707 pm_vars
->PMworkloop
= parent
->getPMworkloop();
1712 return pm_vars
->PMworkloop
;
1716 //*********************************************************************************
1717 // setIdleTimerPeriod
1719 // A subclass policy-maker is going to use our standard idleness
1720 // detection service. Make a command queue and an idle timer and
1721 // connect them to the power management workloop. Finally,
1723 //*********************************************************************************
1725 IOReturn
IOService::setIdleTimerPeriod ( unsigned long period
)
1727 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMsetIdleTimerPeriod
,period
, 0);
1729 priv
->idle_timer_period
= period
;
1733 if ( getPMworkloop() == NULL
)
1735 return kIOReturnError
;
1738 // make the timer event
1739 if ( priv
->timerEventSrc
== NULL
)
1741 priv
->timerEventSrc
= IOTimerEventSource::timerEventSource(this,
1742 PM_idle_timer_expired
);
1743 if ((!priv
->timerEventSrc
) ||
1744 (pm_vars
->PMworkloop
->addEventSource(priv
->timerEventSrc
) != kIOReturnSuccess
) )
1746 return kIOReturnError
;
1750 if ( priv
->activityLock
== NULL
)
1752 priv
->activityLock
= IOLockAlloc();
1755 start_PM_idle_timer();
1760 //******************************************************************************
1763 // Returns how many "seconds from now" the device should idle into its
1764 // next lowest power state.
1765 //******************************************************************************
1766 SInt32
IOService::nextIdleTimeout(
1767 AbsoluteTime currentTime
,
1768 AbsoluteTime lastActivity
,
1769 unsigned int powerState
)
1776 // Calculate time difference using funky macro from clock.h.
1777 delta
= currentTime
;
1778 SUB_ABSOLUTETIME(&delta
, &lastActivity
);
1780 // Figure it in seconds.
1781 absolutetime_to_nanoseconds(delta
, &delta_ns
);
1782 delta_secs
= (SInt32
)(delta_ns
/ NSEC_PER_SEC
);
1784 // Be paranoid about delta somehow exceeding timer period.
1785 if (delta_secs
< (int) priv
->idle_timer_period
)
1786 delay_secs
= (int) priv
->idle_timer_period
- delta_secs
;
1788 delay_secs
= (int) priv
->idle_timer_period
;
1790 return (SInt32
)delay_secs
;
1793 //******************************************************************************
1794 // start_PM_idle_timer
1796 // The parameter is a pointer to us. Use it to call our timeout method.
1797 //******************************************************************************
1798 void IOService::start_PM_idle_timer ( void )
1800 static const int maxTimeout
= 100000;
1801 static const int minTimeout
= 1;
1802 AbsoluteTime uptime
;
1805 IOLockLock(priv
->activityLock
);
1807 clock_get_uptime(&uptime
);
1809 // Subclasses may modify idle sleep algorithm
1810 idle_in
= nextIdleTimeout(uptime
,
1811 priv
->device_active_timestamp
,
1812 pm_vars
->myCurrentState
);
1814 // Check for out-of range responses
1815 if(idle_in
> maxTimeout
)
1817 // use standard implementation
1818 idle_in
= IOService::nextIdleTimeout(uptime
,
1819 priv
->device_active_timestamp
,
1820 pm_vars
->myCurrentState
);
1821 } else if(idle_in
< minTimeout
) {
1826 priv
->timerEventSrc
->setTimeout(idle_in
, NSEC_PER_SEC
);
1828 IOLockUnlock(priv
->activityLock
);
1833 //*********************************************************************************
1834 // PM_idle_timer_expired
1836 // The parameter is a pointer to us. Use it to call our timeout method.
1837 //*********************************************************************************
1839 void PM_idle_timer_expired(OSObject
* ourSelves
, IOTimerEventSource
*)
1841 ((IOService
*)ourSelves
)->PM_idle_timer_expiration();
1845 //*********************************************************************************
1846 // PM_idle_timer_expiration
1848 // The idle timer has expired. If there has been activity since the last
1849 // expiration, just restart the timer and return. If there has not been
1850 // activity, switch to the next lower power state and restart the timer.
1851 //*********************************************************************************
1853 void IOService::PM_idle_timer_expiration ( void )
1855 if ( ! initialized
)
1861 if ( priv
->idle_timer_period
> 0 )
1863 IOTakeLock(priv
->activityLock
);
1864 if ( priv
->device_active
)
1866 priv
->device_active
= false;
1867 IOUnlock(priv
->activityLock
);
1868 start_PM_idle_timer();
1871 if ( pm_vars
->myCurrentState
> 0 )
1873 IOUnlock(priv
->activityLock
);
1874 changePowerStateToPriv(pm_vars
->myCurrentState
- 1);
1875 start_PM_idle_timer();
1878 IOUnlock(priv
->activityLock
);
1879 start_PM_idle_timer();
1884 // **********************************************************************************
1887 // We are un-idling a device due to its activity tickle. This routine runs on the
1888 // PM workloop, and is initiated by IOService::activityTickle.
1889 // We process all activityTickle state requests on the list.
1890 // **********************************************************************************
1891 void IOService::command_received ( void *statePtr
, void *, void * , void * )
1893 unsigned long stateNumber
;
1895 stateNumber
= (unsigned long)statePtr
;
1897 // If not initialized, we're unloading
1898 if ( ! initialized
) return;
1900 if ( (pm_vars
->myCurrentState
< stateNumber
) &&
1901 (priv
->imminentState
< stateNumber
) )
1903 changePowerStateToPriv(stateNumber
);
1905 // After we raise our state, re-schedule the idle timer.
1906 if(priv
->timerEventSrc
)
1907 start_PM_idle_timer();
1912 //*********************************************************************************
1913 // setAggressiveness
1915 // Pass on the input parameters to all power domain children. All those which are
1916 // power domains will pass it on to their children, etc.
1917 //*********************************************************************************
1919 IOReturn
IOService::setAggressiveness ( unsigned long type
, unsigned long newLevel
)
1923 IOPowerConnection
*connection
;
1926 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogSetAggressiveness
,type
, newLevel
);
1928 if ( type
<= kMaxType
)
1930 pm_vars
->current_aggressiveness_values
[type
] = newLevel
;
1931 pm_vars
->current_aggressiveness_valid
[type
] = true;
1934 iter
= getChildIterator(gIOPowerPlane
);
1938 while ( (next
= iter
->getNextObject()) )
1940 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) )
1942 child
= ((IOService
*)(connection
->copyChildEntry(gIOPowerPlane
)));
1945 child
->setAggressiveness(type
, newLevel
);
1956 //*********************************************************************************
1957 // getAggressiveness
1959 // Called by the user client.
1960 //*********************************************************************************
1962 IOReturn
IOService::getAggressiveness ( unsigned long type
, unsigned long * currentLevel
)
1964 if ( type
> kMaxType
)
1965 return kIOReturnBadArgument
;
1967 if ( !pm_vars
->current_aggressiveness_valid
[type
] )
1968 return kIOReturnInvalid
;
1970 *currentLevel
= pm_vars
->current_aggressiveness_values
[type
];
1972 return kIOReturnSuccess
;
1975 //*********************************************************************************
1978 // Pass this to all power domain children. All those which are
1979 // power domains will pass it on to their children, etc.
1980 //*********************************************************************************
1982 IOReturn
IOService::systemWake ( void )
1986 IOPowerConnection
*connection
;
1987 IOService
*theChild
;
1989 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogSystemWake
,0, 0);
1991 iter
= getChildIterator(gIOPowerPlane
);
1995 while ( (next
= iter
->getNextObject()) )
1997 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) )
1999 theChild
= (IOService
*)connection
->copyChildEntry(gIOPowerPlane
);
2002 theChild
->systemWake();
2003 theChild
->release();
2010 if ( pm_vars
->theControllingDriver
!= NULL
)
2012 if ( pm_vars
->theControllingDriver
->didYouWakeSystem() )
2022 //*********************************************************************************
2023 // temperatureCriticalForZone
2025 //*********************************************************************************
2027 IOReturn
IOService::temperatureCriticalForZone ( IOService
* whichZone
)
2029 IOService
*theParent
;
2032 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogCriticalTemp
,0,0);
2034 if ( inPlane(gIOPowerPlane
) && !(priv
->we_are_root
) )
2036 theNub
= (IOService
*)copyParentEntry(gIOPowerPlane
);
2039 theParent
= (IOService
*)theNub
->copyParentEntry(gIOPowerPlane
);
2043 theParent
->temperatureCriticalForZone(whichZone
);
2044 theParent
->release();
2052 //*********************************************************************************
2053 // powerOverrideOnPriv
2055 //*********************************************************************************
2058 IOReturn
IOService::powerOverrideOnPriv ( void )
2060 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogOverrideOn
,0,0);
2062 // turn on the override
2063 priv
->device_overrides
= true;
2064 computeDesiredState();
2066 // change state if that changed something
2067 return changeState();
2071 //*********************************************************************************
2072 // powerOverrideOffPriv
2074 //*********************************************************************************
2075 IOReturn
IOService::powerOverrideOffPriv ( void )
2077 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogOverrideOff
,0,0);
2079 // turn off the override
2080 priv
->device_overrides
= false;
2081 computeDesiredState();
2084 return makeUsable();
2086 // change state if that changed something
2087 return changeState();
2092 //*********************************************************************************
2093 // enqueuePowerChange
2095 // Allocate a new state change notification, initialize it with fields from the
2096 // caller, and add it to the tail of the list of pending power changes.
2098 // If it is early enough in the list, and almost all the time it is the only one in
2099 // the list, start the power change.
2101 // In rare instances, this change will preempt the previous change in the list.
2102 // If the previous change is un-actioned in any way (because we are still
2103 // processing an even earlier power change), and if both the previous change
2104 // in the list and this change are initiated by us (not the parent), then we
2105 // needn't perform the previous change, so we collapse the list a little.
2106 //*********************************************************************************
2108 IOReturn
IOService::enqueuePowerChange ( unsigned long flags
, unsigned long whatStateOrdinal
, unsigned long domainState
, IOPowerConnection
* whichParent
, unsigned long singleParentState
)
2113 // Create and initialize the new change note
2115 IOLockLock(priv
->queue_lock
);
2116 newNote
= priv
->changeList
->createChangeNote();
2117 if ( newNote
== -1 ) {
2118 // uh-oh, our list is full
2119 IOLockUnlock(priv
->queue_lock
);
2120 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogEnqueueErr
,0,0);
2121 return IOPMAckImplied
;
2124 priv
->changeList
->changeNote
[newNote
].newStateNumber
= whatStateOrdinal
;
2125 priv
->changeList
->changeNote
[newNote
].outputPowerCharacter
= pm_vars
->thePowerStates
[whatStateOrdinal
].outputPowerCharacter
;
2126 priv
->changeList
->changeNote
[newNote
].inputPowerRequirement
= pm_vars
->thePowerStates
[whatStateOrdinal
].inputPowerRequirement
;
2127 priv
->changeList
->changeNote
[newNote
].capabilityFlags
= pm_vars
->thePowerStates
[whatStateOrdinal
].capabilityFlags
;
2128 priv
->changeList
->changeNote
[newNote
].flags
= flags
;
2129 priv
->changeList
->changeNote
[newNote
].parent
= NULL
;
2130 if (flags
& IOPMParentInitiated
)
2132 priv
->changeList
->changeNote
[newNote
].domainState
= domainState
;
2133 priv
->changeList
->changeNote
[newNote
].parent
= whichParent
;
2134 whichParent
->retain();
2135 priv
->changeList
->changeNote
[newNote
].singleParentState
= singleParentState
;
2138 previousNote
= priv
->changeList
->previousChangeNote(newNote
);
2140 if ( previousNote
== -1 )
2143 // Queue is empty, we can start this change.
2145 if (flags
& IOPMWeInitiated
)
2147 IOLockUnlock(priv
->queue_lock
);
2148 start_our_change(newNote
);
2151 IOLockUnlock(priv
->queue_lock
);
2152 return start_parent_change(newNote
);
2156 // The queue is not empty. Try to collapse this new change and the previous one in queue into one change.
2157 // This is possible only if both changes are initiated by us, and neither has been started yet.
2158 // Do this more than once if possible.
2160 // (A change is started iff it is at the head of the queue)
2162 while ( (previousNote
!= priv
->head_note
) && (previousNote
!= -1) &&
2163 (priv
->changeList
->changeNote
[newNote
].flags
& priv
->changeList
->changeNote
[previousNote
].flags
& IOPMWeInitiated
) )
2165 priv
->changeList
->changeNote
[previousNote
].outputPowerCharacter
= priv
->changeList
->changeNote
[newNote
].outputPowerCharacter
;
2166 priv
->changeList
->changeNote
[previousNote
].inputPowerRequirement
= priv
->changeList
->changeNote
[newNote
].inputPowerRequirement
;
2167 priv
->changeList
->changeNote
[previousNote
].capabilityFlags
=priv
-> changeList
->changeNote
[newNote
].capabilityFlags
;
2168 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogCollapseQueue
,priv
->changeList
->changeNote
[newNote
].newStateNumber
,
2169 priv
->changeList
->changeNote
[previousNote
].newStateNumber
);
2170 priv
->changeList
->changeNote
[previousNote
].newStateNumber
= priv
->changeList
->changeNote
[newNote
].newStateNumber
;
2171 priv
->changeList
->releaseTailChangeNote();
2172 newNote
= previousNote
;
2173 previousNote
= priv
->changeList
->previousChangeNote(newNote
);
2175 IOLockUnlock(priv
->queue_lock
);
2176 // in any case, we can't start yet
2177 return IOPMWillAckLater
;
2180 //*********************************************************************************
2183 // Notify all interested parties either that a change is impending or that the
2184 // previously-notified change is done and power has settled.
2185 // The parameter identifies whether this is the
2186 // pre-change notification or the post-change notification.
2188 //*********************************************************************************
2190 IOReturn
IOService::notifyAll ( bool is_prechange
)
2192 IOPMinformee
* nextObject
;
2195 IOPowerConnection
* connection
;
2197 // To prevent acknowledgePowerChange from finishing the change note and removing it from the queue if
2198 // some driver calls it, we inflate the number of pending acks so it cannot become zero. We'll fix it later.
2200 priv
->head_note_pendingAcks
=1;
2202 // OK, we will go through the lists of interested drivers and power domain children
2203 // and notify each one of this change.
2205 nextObject
= priv
->interestedDrivers
->firstInList();
2206 while ( nextObject
!= NULL
) {
2207 priv
->head_note_pendingAcks
+=1;
2208 if (! inform(nextObject
, is_prechange
) )
2211 nextObject
= priv
->interestedDrivers
->nextInList(nextObject
);
2214 if (! acquire_lock() ) {
2217 // did they all ack?
2218 if ( priv
->head_note_pendingAcks
> 1 ) {
2220 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogStartAckTimer
,0,0);
2224 IOUnlock(priv
->our_lock
);
2227 iter
= getChildIterator(gIOPowerPlane
);
2228 // summing their power consumption
2229 pm_vars
->thePowerStates
[priv
->head_note_state
].staticPower
= 0;
2233 while ( (next
= iter
->getNextObject()) )
2235 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) )
2237 priv
->head_note_pendingAcks
+=1;
2238 notifyChild(connection
, is_prechange
);
2244 if (! acquire_lock() ) {
2247 // now make this real
2248 priv
->head_note_pendingAcks
-= 1;
2250 if (priv
->head_note_pendingAcks
== 0 ) {
2252 IOUnlock(priv
->our_lock
);
2253 // return ack to parent
2254 return IOPMAckImplied
;
2258 IOUnlock(priv
->our_lock
);
2259 return IOPMWillAckLater
;
2263 //*********************************************************************************
2266 // Notify a power domain child of an upcoming power change.
2268 // If the object acknowledges the current change, we return TRUE.
2269 //*********************************************************************************
2271 bool IOService::notifyChild ( IOPowerConnection
* theNub
, bool is_prechange
)
2273 IOReturn k
= IOPMAckImplied
;
2274 unsigned long childPower
;
2275 IOService
*theChild
;
2277 theChild
= (IOService
*)(theNub
->copyChildEntry(gIOPowerPlane
));
2280 // The child has been detached since we grabbed the child iterator.
2281 // Decrement pending_acks, already incremented in notifyAll,
2282 // to account for this unexpected departure.
2283 priv
->head_note_pendingAcks
--;
2287 // Unless the child handles the notification immediately and returns
2288 // kIOPMAckImplied, we'll be awaiting their acknowledgement later.
2289 theNub
->setAwaitingAck(true);
2293 k
= theChild
->powerDomainWillChangeTo(priv
->head_note_outputFlags
,theNub
);
2295 k
= theChild
->powerDomainDidChangeTo(priv
->head_note_outputFlags
,theNub
);
2298 // did the return code ack?
2299 if ( k
== IOPMAckImplied
)
2302 priv
->head_note_pendingAcks
--;
2303 theNub
->setAwaitingAck(false);
2304 childPower
= theChild
->currentPowerConsumption();
2305 if ( childPower
== kIOPMUnknown
)
2307 pm_vars
->thePowerStates
[priv
->head_note_state
].staticPower
= kIOPMUnknown
;
2309 if ( pm_vars
->thePowerStates
[priv
->head_note_state
].staticPower
!= kIOPMUnknown
)
2311 pm_vars
->thePowerStates
[priv
->head_note_state
].staticPower
+= childPower
;
2314 theChild
->release();
2317 theChild
->release();
2322 //*********************************************************************************
2325 // Notify an interested driver of an upcoming power change.
2327 // If the object acknowledges the current change, we return TRUE.
2328 //*********************************************************************************
2330 bool IOService::inform ( IOPMinformee
* nextObject
, bool is_prechange
)
2332 IOReturn k
= IOPMAckImplied
;
2335 nextObject
->timer
= -1;
2339 pm_vars
->thePlatform
->PMLog (pm_vars
->ourName
,PMlogInformDriverPreChange
,
2340 (unsigned long)priv
->head_note_capabilityFlags
,(unsigned long)priv
->head_note_state
);
2341 k
= nextObject
->whatObject
->powerStateWillChangeTo( priv
->head_note_capabilityFlags
,priv
->head_note_state
,this);
2343 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogInformDriverPostChange
,
2344 (unsigned long)priv
->head_note_capabilityFlags
,(unsigned long)priv
->head_note_state
);
2345 k
= nextObject
->whatObject
->powerStateDidChangeTo(priv
->head_note_capabilityFlags
,priv
->head_note_state
,this);
2348 // did it ack behind our back?
2349 if ( nextObject
->timer
== 0 )
2355 // no, did the return code ack?
2356 if ( k
==IOPMAckImplied
)
2359 nextObject
->timer
= 0;
2360 priv
->head_note_pendingAcks
-= 1;
2366 nextObject
->timer
= 0;
2367 priv
-> head_note_pendingAcks
-= 1;
2372 nextObject
->timer
= (k
/ (ACK_TIMER_PERIOD
/ ns_per_us
)) + 1;
2378 //*********************************************************************************
2379 // OurChangeTellClientsPowerDown
2381 // All registered applications and kernel clients have positively acknowledged our
2382 // intention of lowering power. Here we notify them all that we will definitely
2383 // lower the power. If we don't have to wait for any of them to acknowledge, we
2384 // carry on by notifying interested drivers. Otherwise, we do wait.
2385 //*********************************************************************************
2387 void IOService::OurChangeTellClientsPowerDown ( void )
2390 priv
->machine_state
= kIOPM_OurChangeTellPriorityClientsPowerDown
;
2392 // are we waiting for responses?
2393 if ( tellChangeDown1(priv
->head_note_state
) )
2395 // no, notify priority clients
2396 OurChangeTellPriorityClientsPowerDown();
2398 // If we are waiting for responses, execution will resume via
2399 // allowCancelCommon() or ack timeout
2403 //*********************************************************************************
2404 // OurChangeTellPriorityClientsPowerDown
2406 // All registered applications and kernel clients have positively acknowledged our
2407 // intention of lowering power. Here we notify "priority" clients that we are
2408 // lowering power. If we don't have to wait for any of them to acknowledge, we
2409 // carry on by notifying interested drivers. Otherwise, we do wait.
2410 //*********************************************************************************
2412 void IOService::OurChangeTellPriorityClientsPowerDown ( void )
2415 priv
->machine_state
= kIOPM_OurChangeNotifyInterestedDriversWillChange
;
2416 // are we waiting for responses?
2417 if ( tellChangeDown2(priv
->head_note_state
) )
2419 // no, notify interested drivers
2420 return OurChangeNotifyInterestedDriversWillChange();
2422 // If we are waiting for responses, execution will resume via
2423 // allowCancelCommon() or ack timeout
2427 //*********************************************************************************
2428 // OurChangeNotifyInterestedDriversWillChange
2430 // All registered applications and kernel clients have acknowledged our notification
2431 // that we are lowering power. Here we notify interested drivers. If we don't have
2432 // to wait for any of them to acknowledge, we instruct our power driver to make the change.
2433 // Otherwise, we do wait.
2434 //*********************************************************************************
2436 void IOService::OurChangeNotifyInterestedDriversWillChange ( void )
2438 // no, in case they don't all ack
2439 priv
->machine_state
= kIOPM_OurChangeSetPowerState
;
2440 if ( notifyAll(true) == IOPMAckImplied
)
2442 // not waiting for responses
2443 OurChangeSetPowerState();
2445 // If we are waiting for responses, execution will resume via
2446 // all_acked() or ack timeout
2450 //*********************************************************************************
2451 // OurChangeSetPowerState
2453 // All interested drivers have acknowledged our pre-change notification of a power
2454 // change we initiated. Here we instruct our controlling driver to make
2455 // the change to the hardware. If it does so, we continue processing
2456 // (waiting for settle and notifying interested parties post-change.)
2457 // If it doesn't, we have to wait for it to acknowledge and then continue.
2458 //*********************************************************************************
2460 void IOService::OurChangeSetPowerState ( void )
2462 priv
->machine_state
= kIOPM_OurChangeWaitForPowerSettle
;
2464 if ( instruct_driver(priv
->head_note_state
) == IOPMAckImplied
)
2466 // it's done, carry on
2467 OurChangeWaitForPowerSettle();
2469 // it's not, wait for it
2470 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogStartAckTimer
,0,0);
2472 // execution will resume via ack_timer_ticked()
2477 //*********************************************************************************
2478 // OurChangeWaitForPowerSettle
2480 // Our controlling driver has changed power state on the hardware
2481 // during a power change we initiated. Here we see if we need to wait
2482 // for power to settle before continuing. If not, we continue processing
2483 // (notifying interested parties post-change). If so, we wait and
2485 //*********************************************************************************
2487 void IOService::OurChangeWaitForPowerSettle ( void )
2489 priv
->settle_time
= compute_settle_time();
2490 if ( priv
->settle_time
== 0 )
2492 OurChangeNotifyInterestedDriversDidChange();
2494 priv
->machine_state
= kIOPM_OurChangeNotifyInterestedDriversDidChange
;
2495 startSettleTimer(priv
->settle_time
);
2500 //*********************************************************************************
2501 // OurChangeNotifyInterestedDriversDidChange
2503 // Power has settled on a power change we initiated. Here we notify
2504 // all our interested parties post-change. If they all acknowledge, we're
2505 // done with this change note, and we can start on the next one.
2506 // Otherwise we have to wait for acknowledgements and finish up later.
2507 //*********************************************************************************
2509 void IOService::OurChangeNotifyInterestedDriversDidChange ( void )
2511 // in case they don't all ack
2512 priv
->machine_state
= kIOPM_OurChangeFinish
;
2513 if ( notifyAll(false) == IOPMAckImplied
)
2515 // not waiting for responses
2518 // If we are waiting for responses, execution will resume via
2519 // all_acked() or ack timeout
2523 //*********************************************************************************
2526 // Power has settled on a power change we initiated, and
2527 // all our interested parties have acknowledged. We're
2528 // done with this change note, and we can start on the next one.
2529 //*********************************************************************************
2531 void IOService::OurChangeFinish ( void )
2537 //*********************************************************************************
2538 // ParentDownTellPriorityClientsPowerDown_Immediate
2540 // All applications and kernel clients have been notified of a power lowering
2541 // initiated by the parent and we didn't have to wait for any responses. Here
2542 // we notify any priority clients. If they all ack, we continue with the power change.
2543 // If at least one doesn't, we have to wait for it to acknowledge and then continue.
2544 //*********************************************************************************
2546 IOReturn
IOService::ParentDownTellPriorityClientsPowerDown_Immediate ( void )
2548 // in case they don't all ack
2549 priv
->machine_state
= kIOPM_ParentDownNotifyInterestedDriversWillChange_Delayed
;
2550 // are we waiting for responses?
2551 if ( tellChangeDown2(priv
->head_note_state
) )
2553 // no, notify interested drivers
2554 return ParentDownNotifyInterestedDriversWillChange_Immediate();
2556 // If we are waiting for responses, execution will resume via
2557 // allowCancelCommon() or ack timeout
2558 return IOPMWillAckLater
;
2562 //*********************************************************************************
2563 // ParentDownTellPriorityClientsPowerDown_Immediate2
2565 // All priority kernel clients have been notified of a power lowering
2566 // initiated by the parent and we didn't have to wait for any responses. Here
2567 // we notify any interested drivers and power domain children. If they all ack,
2568 // we continue with the power change.
2569 // If at least one doesn't, we have to wait for it to acknowledge and then continue.
2570 //*********************************************************************************
2572 IOReturn
IOService::ParentDownNotifyInterestedDriversWillChange_Immediate ( void )
2574 // in case they don't all ack
2575 priv
->machine_state
= kIOPM_ParentDownSetPowerState_Delayed
;
2576 if ( notifyAll(true) == IOPMAckImplied
)
2579 return ParentDownSetPowerState_Immediate();
2581 // If we are waiting for responses, execution will resume via
2582 // all_acked() or ack timeout
2583 return IOPMWillAckLater
;
2587 //*********************************************************************************
2588 // ParentDownTellPriorityClientsPowerDown_Immediate4
2590 // All applications and kernel clients have been notified of a power lowering
2591 // initiated by the parent and we had to wait for responses. Here
2592 // we notify any priority clients. If they all ack, we continue with the power change.
2593 // If at least one doesn't, we have to wait for it to acknowledge and then continue.
2594 //*********************************************************************************
2596 void IOService::ParentDownTellPriorityClientsPowerDown_Delayed ( void )
2598 // in case they don't all ack
2599 priv
->machine_state
= kIOPM_ParentDownNotifyInterestedDriversWillChange_Delayed
;
2601 // are we waiting for responses?
2602 if ( tellChangeDown2(priv
->head_note_state
) )
2604 // no, notify interested drivers
2605 ParentDownNotifyInterestedDriversWillChange_Delayed();
2607 // If we are waiting for responses, execution will resume via
2608 // allowCancelCommon() or ack timeout
2612 //*********************************************************************************
2613 // ParentDownTellPriorityClientsPowerDown_Immediate5
2615 // All applications and kernel clients have been notified of a power lowering
2616 // initiated by the parent and we had to wait for their responses. Here we notify
2617 // any interested drivers and power domain children. If they all ack, we continue
2618 // with the power change.
2619 // If at least one doesn't, we have to wait for it to acknowledge and then continue.
2620 //*********************************************************************************
2622 void IOService::ParentDownNotifyInterestedDriversWillChange_Delayed ( void )
2624 // in case they don't all ack
2625 priv
->machine_state
= kIOPM_ParentDownSetPowerState_Delayed
;
2626 if ( notifyAll(true) == IOPMAckImplied
)
2629 ParentDownSetPowerState_Delayed();
2631 // If we are waiting for responses, execution will resume via
2632 // all_acked() or ack timeout
2636 //*********************************************************************************
2637 // ParentDownSetPowerState_Immediate
2639 // All parties have acknowledged our pre-change notification of a power
2640 // lowering initiated by the parent. Here we instruct our controlling driver
2641 // to put the hardware in the state it needs to be in when the domain is
2642 // lowered. If it does so, we continue processing
2643 // (waiting for settle and acknowledging the parent.)
2644 // If it doesn't, we have to wait for it to acknowledge and then continue.
2645 //*********************************************************************************
2647 IOReturn
IOService::ParentDownSetPowerState_Immediate ( void )
2649 priv
->machine_state
= kIOPM_ParentDownWaitForPowerSettle_Delayed
;
2651 if ( instruct_driver(priv
->head_note_state
) == IOPMAckImplied
)
2653 // it's done, carry on
2654 return ParentDownWaitForPowerSettleAndNotifyDidChange_Immediate();
2656 // it's not, wait for it
2657 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogStartAckTimer
,0,0);
2659 return IOPMWillAckLater
;
2663 //*********************************************************************************
2664 // ParentDownSetPowerState_Delayed
2666 // We had to wait for it, but all parties have acknowledged our pre-change
2667 // notification of a power lowering initiated by the parent.
2668 // Here we instruct our controlling driver
2669 // to put the hardware in the state it needs to be in when the domain is
2670 // lowered. If it does so, we continue processing
2671 // (waiting for settle and acknowledging the parent.)
2672 // If it doesn't, we have to wait for it to acknowledge and then continue.
2673 //*********************************************************************************
2675 void IOService::ParentDownSetPowerState_Delayed ( void )
2677 priv
-> machine_state
= kIOPM_ParentDownWaitForPowerSettle_Delayed
;
2679 if ( instruct_driver(priv
->head_note_state
) == IOPMAckImplied
)
2681 // it's done, carry on
2682 ParentDownWaitForPowerSettle_Delayed();
2684 // it's not, wait for it
2685 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogStartAckTimer
,0,0);
2691 //*********************************************************************************
2692 // ParentDownWaitForPowerSettleAndNotifyDidChange_Immediate
2694 // Our controlling driver has changed power state on the hardware
2695 // during a power change initiated by our parent. Here we see if we need
2696 // to wait for power to settle before continuing. If not, we continue
2697 // processing (acknowledging our preparedness to the parent).
2698 // If so, we wait and continue later.
2699 //*********************************************************************************
2701 IOReturn
IOService::ParentDownWaitForPowerSettleAndNotifyDidChange_Immediate ( void )
2705 priv
->settle_time
= compute_settle_time();
2706 if ( priv
->settle_time
== 0 )
2708 // store current state in case they don't all ack
2709 priv
->machine_state
= kIOPM_ParentDownAcknowledgeChange_Delayed
;
2710 if ( notifyAll(false) == IOPMAckImplied
)
2712 // not waiting for responses
2713 nub
= priv
->head_note_parent
;
2717 return IOPMAckImplied
;
2719 // If we are waiting for responses, execution will resume via
2720 // all_acked() or ack timeout
2721 return IOPMWillAckLater
;
2723 // let settle time elapse, then notify interest drivers of our power state change in ParentDownNotifyDidChangeAndAcknowledgeChange_Delayed
2724 priv
->machine_state
= kIOPM_ParentDownNotifyDidChangeAndAcknowledgeChange_Delayed
;
2725 startSettleTimer(priv
->settle_time
);
2726 return IOPMWillAckLater
;
2731 //*********************************************************************************
2732 // ParentDownWaitForPowerSettle_Delayed
2734 // Our controlling driver has changed power state on the hardware
2735 // during a power change initiated by our parent. We have had to wait
2736 // for acknowledgement from interested parties, or we have had to wait
2737 // for the controlling driver to change the state. Here we see if we need
2738 // to wait for power to settle before continuing. If not, we continue
2739 // processing (acknowledging our preparedness to the parent).
2740 // If so, we wait and continue later.
2741 //*********************************************************************************
2743 void IOService::ParentDownWaitForPowerSettle_Delayed ( void )
2745 priv
->settle_time
= compute_settle_time();
2746 if ( priv
->settle_time
== 0 )
2748 ParentDownNotifyDidChangeAndAcknowledgeChange_Delayed();
2750 priv
->machine_state
= kIOPM_ParentDownNotifyDidChangeAndAcknowledgeChange_Delayed
;
2751 startSettleTimer(priv
->settle_time
);
2756 //*********************************************************************************
2757 // ParentDownNotifyDidChangeAndAcknowledgeChange_Delayed
2759 // Power has settled on a power change initiated by our parent. Here we
2760 // notify interested parties.
2761 //*********************************************************************************
2763 void IOService::ParentDownNotifyDidChangeAndAcknowledgeChange_Delayed ( void )
2765 IORegistryEntry
*nub
;
2768 // in case they don't all ack
2769 priv
->machine_state
= kIOPM_ParentDownAcknowledgeChange_Delayed
;
2770 if ( notifyAll(false) == IOPMAckImplied
) {
2771 nub
= priv
->head_note_parent
;
2774 parent
= (IOService
*)nub
->copyParentEntry(gIOPowerPlane
);
2776 parent
->acknowledgePowerChange((IOService
*)nub
);
2781 // If we are waiting for responses, execution will resume via
2782 // all_acked() or ack timeout in ParentDownAcknowledgeChange_Delayed.
2783 // Notice the duplication of code just above and in ParentDownAcknowledgeChange_Delayed.
2787 //*********************************************************************************
2788 // ParentDownAcknowledgeChange_Delayed
2790 // We had to wait for it, but all parties have acknowledged our post-change
2791 // notification of a power lowering initiated by the parent.
2792 // Here we acknowledge the parent.
2793 // We are done with this change note, and we can start on the next one.
2794 //*********************************************************************************
2796 void IOService::ParentDownAcknowledgeChange_Delayed ( void )
2798 IORegistryEntry
*nub
;
2801 nub
= priv
->head_note_parent
;
2804 parent
= (IOService
*)nub
->copyParentEntry(gIOPowerPlane
);
2807 parent
->acknowledgePowerChange((IOService
*)nub
);
2814 //*********************************************************************************
2815 // ParentUpSetPowerState_Delayed
2817 // Our parent has informed us via powerStateDidChange that it has
2818 // raised the power in our power domain, and we have had to wait
2819 // for some interested party to acknowledge our notification.
2820 // Here we instruct our controlling
2821 // driver to program the hardware to take advantage of the higher domain
2822 // power. If it does so, we continue processing
2823 // (waiting for settle and notifying interested parties post-change.)
2824 // If it doesn't, we have to wait for it to acknowledge and then continue.
2825 //*********************************************************************************
2827 void IOService::ParentUpSetPowerState_Delayed ( void )
2829 priv
->machine_state
= kIOPM_ParentUpWaitForSettleTime_Delayed
;
2831 if ( instruct_driver(priv
->head_note_state
) == IOPMAckImplied
)
2833 // it did it, carry on
2834 ParentUpWaitForSettleTime_Delayed();
2836 // it didn't, wait for it
2837 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogStartAckTimer
,0,0);
2843 //*********************************************************************************
2844 // ParentUpSetPowerState_Immediate
2846 // Our parent has informed us via powerStateDidChange that it has
2847 // raised the power in our power domain. Here we instruct our controlling
2848 // driver to program the hardware to take advantage of the higher domain
2849 // power. If it does so, we continue processing
2850 // (waiting for settle and notifying interested parties post-change.)
2851 // If it doesn't, we have to wait for it to acknowledge and then continue.
2852 //*********************************************************************************
2854 IOReturn
IOService::ParentUpSetPowerState_Immediate ( void )
2856 priv
->machine_state
= kIOPM_ParentUpWaitForSettleTime_Delayed
;
2858 if ( instruct_driver(priv
->head_note_state
) == IOPMAckImplied
)
2860 // it did it, carry on
2861 return ParentUpWaitForSettleTime_Immediate();
2864 // it didn't, wait for it
2865 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogStartAckTimer
,0,0);
2867 return IOPMWillAckLater
;
2872 //*********************************************************************************
2873 // ParentUpWaitForSettleTime_Immediate
2875 // Our controlling driver has changed power state on the hardware
2876 // during a power raise initiated by the parent. Here we see if we need to wait
2877 // for power to settle before continuing. If not, we continue processing
2878 // (notifying interested parties post-change). If so, we wait and
2880 //*********************************************************************************
2882 IOReturn
IOService::ParentUpWaitForSettleTime_Immediate ( void )
2884 priv
->settle_time
= compute_settle_time();
2885 if ( priv
->settle_time
== 0 )
2887 return ParentUpNotifyInterestedDriversDidChange_Immediate();
2889 priv
->machine_state
= kIOPM_ParentUpNotifyInterestedDriversDidChange_Delayed
;
2890 startSettleTimer(priv
->settle_time
);
2891 return IOPMWillAckLater
;
2896 //*********************************************************************************
2897 // ParentUpWaitForSettleTime_Delayed
2899 // Our controlling driver has changed power state on the hardware
2900 // during a power raise initiated by the parent, but we had to wait for it.
2901 // Here we see if we need to wait for power to settle before continuing.
2902 // If not, we continue processing (notifying interested parties post-change).
2903 // If so, we wait and continue later.
2904 //*********************************************************************************
2906 void IOService::ParentUpWaitForSettleTime_Delayed ( void )
2908 priv
->settle_time
= compute_settle_time();
2909 if ( priv
->settle_time
== 0 )
2911 ParentUpNotifyInterestedDriversDidChange_Delayed();
2913 priv
->machine_state
= kIOPM_ParentUpNotifyInterestedDriversDidChange_Delayed
;
2914 startSettleTimer(priv
->settle_time
);
2919 //*********************************************************************************
2920 // ParentUpNotifyInterestedDriversDidChange_Immediate
2922 // No power settling was required on a power raise initiated by the parent.
2923 // Here we notify all our interested parties post-change. If they all acknowledge,
2924 // we're done with this change note, and we can start on the next one.
2925 // Otherwise we have to wait for acknowledgements and finish up later.
2926 //*********************************************************************************
2928 IOReturn
IOService::ParentUpNotifyInterestedDriversDidChange_Immediate ( void )
2932 // in case they don't all ack
2933 priv
->machine_state
= kIOPM_ParentUpAcknowledgePowerChange_Delayed
;
2934 if ( notifyAll(false) == IOPMAckImplied
)
2936 nub
= priv
->head_note_parent
;
2940 return IOPMAckImplied
;
2942 // If we are waiting for responses, execution will resume via
2943 // all_acked() or ack timeout in ParentUpAcknowledgePowerChange_Delayed.
2944 return IOPMWillAckLater
;
2948 //*********************************************************************************
2949 // ParentUpNotifyInterestedDriversDidChange_Delayed
2951 // Power has settled on a power raise initiated by the parent.
2952 // Here we notify all our interested parties post-change. If they all acknowledge,
2953 // we're done with this change note, and we can start on the next one.
2954 // Otherwise we have to wait for acknowledgements and finish up later.
2955 //*********************************************************************************
2957 void IOService::ParentUpNotifyInterestedDriversDidChange_Delayed ( void )
2959 // in case they don't all ack
2960 priv
->machine_state
= kIOPM_ParentUpAcknowledgePowerChange_Delayed
;
2961 if ( notifyAll(false) == IOPMAckImplied
)
2963 ParentUpAcknowledgePowerChange_Delayed();
2965 // If we are waiting for responses, execution will resume via
2966 // all_acked() or ack timeout in ParentUpAcknowledgePowerChange_Delayed.
2970 //*********************************************************************************
2971 // ParentUpAcknowledgePowerChange_Delayed
2973 // All parties have acknowledged our post-change notification of a power
2974 // raising initiated by the parent. Here we acknowledge the parent.
2975 // We are done with this change note, and we can start on the next one.
2976 //*********************************************************************************
2978 void IOService::ParentUpAcknowledgePowerChange_Delayed ( void )
2980 IORegistryEntry
*nub
;
2983 nub
= priv
->head_note_parent
;
2986 parent
= (IOService
*)nub
->copyParentEntry(gIOPowerPlane
);
2989 parent
->acknowledgePowerChange((IOService
*)nub
);
2996 //*********************************************************************************
2999 // A power change is complete, and the used post-change note is at
3000 // the head of the queue. Remove it and set myCurrentState to the result
3001 // of the change. Start up the next change in queue.
3002 //*********************************************************************************
3004 void IOService::all_done ( void )
3006 unsigned long previous_state
;
3007 IORegistryEntry
*nub
;
3010 priv
->machine_state
= kIOPM_Finished
;
3013 if ( priv
->head_note_flags
& IOPMWeInitiated
)
3015 // could our driver switch to the new state?
3016 if ( !( priv
->head_note_flags
& IOPMNotDone
) )
3018 // yes, did power raise?
3019 if ( pm_vars
->myCurrentState
< priv
->head_note_state
)
3021 // yes, inform clients and apps
3022 tellChangeUp (priv
->head_note_state
);
3024 // no, if this lowers our
3025 if ( ! priv
->we_are_root
)
3027 // power requirements, tell the parent
3028 ask_parent(priv
->head_note_state
);
3031 previous_state
= pm_vars
->myCurrentState
;
3033 pm_vars
->myCurrentState
= priv
->head_note_state
;
3034 priv
->imminentState
= pm_vars
->myCurrentState
;
3035 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogChangeDone
,(unsigned long)pm_vars
->myCurrentState
,0);
3036 // inform subclass policy-maker
3037 powerChangeDone(previous_state
);
3041 // parent's power change
3042 if ( priv
->head_note_flags
& IOPMParentInitiated
)
3044 if ( ((priv
->head_note_flags
& IOPMDomainWillChange
) && (pm_vars
->myCurrentState
>= priv
->head_note_state
)) ||
3045 ((priv
->head_note_flags
& IOPMDomainDidChange
) && (pm_vars
->myCurrentState
< priv
->head_note_state
)) )
3048 if ( pm_vars
->myCurrentState
< priv
->head_note_state
)
3050 // yes, inform clients and apps
3051 tellChangeUp (priv
->head_note_state
);
3054 previous_state
= pm_vars
->myCurrentState
;
3055 pm_vars
->myCurrentState
= priv
->head_note_state
;
3056 priv
->imminentState
= pm_vars
->myCurrentState
;
3057 pm_vars
->maxCapability
= pm_vars
->theControllingDriver
->maxCapabilityForDomainState(priv
->head_note_domainState
);
3059 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogChangeDone
,(unsigned long)pm_vars
->myCurrentState
,0);
3060 // inform subclass policy-maker
3061 powerChangeDone(previous_state
);
3065 IOLockLock(priv
->queue_lock
);
3066 // we're done with this
3067 priv
->changeList
->releaseHeadChangeNote();
3069 // start next one in queue
3070 priv
->head_note
= priv
->changeList
->currentChange();
3071 if ( priv
->head_note
!= -1 )
3074 IOLockUnlock(priv
->queue_lock
);
3075 if (priv
->changeList
->changeNote
[priv
->head_note
].flags
& IOPMWeInitiated
)
3077 start_our_change(priv
->head_note
);
3079 nub
= priv
->changeList
->changeNote
[priv
->head_note
].parent
;
3080 if ( start_parent_change(priv
->head_note
) == IOPMAckImplied
)
3082 parent
= (IOService
*)nub
->copyParentEntry(gIOPowerPlane
);
3085 parent
->acknowledgePowerChange((IOService
*)nub
);
3091 IOLockUnlock(priv
->queue_lock
);
3097 //*********************************************************************************
3100 // A driver or child has acknowledged our notification of an upcoming power
3101 // change, and this acknowledgement is the last one pending
3102 // before we change power or after changing power.
3104 //*********************************************************************************
3106 void IOService::all_acked ( void )
3108 switch (priv
->machine_state
) {
3109 case kIOPM_OurChangeSetPowerState
:
3110 OurChangeSetPowerState();
3112 case kIOPM_OurChangeFinish
:
3115 case kIOPM_ParentDownSetPowerState_Delayed
:
3116 ParentDownSetPowerState_Delayed();
3118 case kIOPM_ParentDownAcknowledgeChange_Delayed
:
3119 ParentDownAcknowledgeChange_Delayed();
3121 case kIOPM_ParentUpSetPowerState_Delayed
:
3122 ParentUpSetPowerState_Delayed();
3124 case kIOPM_ParentUpAcknowledgePowerChange_Delayed
:
3125 ParentUpAcknowledgePowerChange_Delayed();
3130 //*********************************************************************************
3131 // settleTimerExpired
3133 // Power has settled after our last change. Notify interested parties that
3134 // there is a new power state.
3135 //*********************************************************************************
3137 void IOService::settleTimerExpired ( void )
3139 if ( ! initialized
)
3145 switch (priv
->machine_state
) {
3146 case kIOPM_OurChangeNotifyInterestedDriversDidChange
:
3147 OurChangeNotifyInterestedDriversDidChange();
3149 case kIOPM_ParentDownNotifyDidChangeAndAcknowledgeChange_Delayed
:
3150 ParentDownNotifyDidChangeAndAcknowledgeChange_Delayed();
3152 case kIOPM_ParentUpNotifyInterestedDriversDidChange_Delayed
:
3153 ParentUpNotifyInterestedDriversDidChange_Delayed();
3159 //*********************************************************************************
3160 // compute_settle_time
3162 // Compute the power-settling delay in microseconds for the
3163 // change from myCurrentState to head_note_state.
3164 //*********************************************************************************
3166 unsigned long IOService::compute_settle_time ( void )
3168 unsigned long totalTime
;
3171 // compute total time to attain the new state
3173 i
= pm_vars
->myCurrentState
;
3175 // we're lowering power
3176 if ( priv
->head_note_state
< pm_vars
->myCurrentState
)
3178 while ( i
> priv
->head_note_state
)
3180 totalTime
+= pm_vars
->thePowerStates
[i
].settleDownTime
;
3185 // we're raising power
3186 if ( priv
->head_note_state
> pm_vars
->myCurrentState
)
3188 while ( i
< priv
->head_note_state
)
3190 totalTime
+= pm_vars
->thePowerStates
[i
+1].settleUpTime
;
3199 //*********************************************************************************
3202 // Enter with a power-settling delay in microseconds and start a nano-second
3203 // timer for that delay.
3204 //*********************************************************************************
3206 IOReturn
IOService::startSettleTimer ( unsigned long delay
)
3208 AbsoluteTime deadline
;
3210 clock_interval_to_deadline(delay
, kMicrosecondScale
, &deadline
);
3212 thread_call_enter_delayed(priv
->settleTimer
, deadline
);
3217 //*********************************************************************************
3220 // The acknowledgement timeout periodic timer has ticked.
3221 // If we are awaiting acks for a power change notification,
3222 // we decrement the timer word of each interested driver which hasn't acked.
3223 // If a timer word becomes zero, we pretend the driver aknowledged.
3224 // If we are waiting for the controlling driver to change the power
3225 // state of the hardware, we decrement its timer word, and if it becomes
3226 // zero, we pretend the driver acknowledged.
3227 //*********************************************************************************
3229 void IOService::ack_timer_ticked ( void )
3231 IOPMinformee
* nextObject
;
3233 if ( ! initialized
)
3239 if (! acquire_lock() )
3244 switch (priv
->machine_state
) {
3245 case kIOPM_OurChangeWaitForPowerSettle
:
3246 case kIOPM_ParentDownWaitForPowerSettle_Delayed
:
3247 case kIOPM_ParentUpWaitForSettleTime_Delayed
:
3248 // are we waiting for our driver to make its change?
3249 if ( priv
->driver_timer
!= 0 ) {
3251 priv
->driver_timer
-= 1;
3252 // it's tardy, we'll go on without it
3253 if ( priv
->driver_timer
== 0 )
3255 IOUnlock(priv
->our_lock
);
3256 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogCtrlDriverTardy
,0,0);
3259 // still waiting, set timer again
3261 IOUnlock(priv
->our_lock
);
3265 IOUnlock(priv
->our_lock
);
3269 case kIOPM_OurChangeSetPowerState
:
3270 case kIOPM_OurChangeFinish
:
3271 case kIOPM_ParentDownSetPowerState_Delayed
:
3272 case kIOPM_ParentDownAcknowledgeChange_Delayed
:
3273 case kIOPM_ParentUpSetPowerState_Delayed
:
3274 case kIOPM_ParentUpAcknowledgePowerChange_Delayed
:
3275 // are we waiting for interested parties to acknowledge?
3276 if (priv
->head_note_pendingAcks
!= 0 )
3278 // yes, go through the list of interested drivers
3279 nextObject
= priv
->interestedDrivers
->firstInList();
3280 // and check each one
3281 while ( nextObject
!= NULL
)
3283 if ( nextObject
->timer
> 0 )
3285 nextObject
->timer
-= 1;
3286 // this one should have acked by now
3287 if ( nextObject
->timer
== 0 )
3289 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogIntDriverTardy
,0,0);
3290 //kprintf("interested driver tardy: %s\n",nextObject->whatObject->getName());
3291 priv
->head_note_pendingAcks
-= 1;
3294 nextObject
= priv
->interestedDrivers
->nextInList(nextObject
);
3297 // is that the last?
3298 if ( priv
->head_note_pendingAcks
== 0 )
3300 IOUnlock(priv
->our_lock
);
3301 // yes, we can continue
3304 // no, set timer again
3306 IOUnlock(priv
->our_lock
);
3309 IOUnlock(priv
->our_lock
);
3313 // apps didn't respond to parent-down notification
3314 case kIOPM_ParentDownTellPriorityClientsPowerDown_Immediate
:
3315 IOUnlock(priv
->our_lock
);
3316 IOLockLock(priv
->flags_lock
);
3317 if (pm_vars
->responseFlags
)
3319 // get rid of this stuff
3320 pm_vars
->responseFlags
->release();
3321 pm_vars
->responseFlags
= NULL
;
3323 IOLockUnlock(priv
->flags_lock
);
3324 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogClientTardy
,0,5);
3325 // carry on with the change
3326 ParentDownTellPriorityClientsPowerDown_Delayed();
3329 case kIOPM_ParentDownNotifyInterestedDriversWillChange_Delayed
:
3330 IOUnlock(priv
->our_lock
);
3331 IOLockLock(priv
->flags_lock
);
3332 if (pm_vars
->responseFlags
)
3334 // get rid of this stuff
3335 pm_vars
->responseFlags
->release();
3336 pm_vars
->responseFlags
= NULL
;
3338 IOLockUnlock(priv
->flags_lock
);
3339 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogClientTardy
,0,1);
3340 // carry on with the change
3341 ParentDownNotifyInterestedDriversWillChange_Delayed();
3344 case kIOPM_OurChangeTellClientsPowerDown
:
3345 // apps didn't respond to our power-down request
3346 IOUnlock(priv
->our_lock
);
3347 IOLockLock(priv
->flags_lock
);
3348 if (pm_vars
->responseFlags
)
3350 // get rid of this stuff
3351 pm_vars
->responseFlags
->release();
3352 pm_vars
->responseFlags
= NULL
;
3354 IOLockUnlock(priv
->flags_lock
);
3355 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogClientTardy
,0,2);
3356 // rescind the request
3357 tellNoChangeDown(priv
->head_note_state
);
3358 // mark the change note un-actioned
3359 priv
->head_note_flags
|= IOPMNotDone
;
3364 case kIOPM_OurChangeTellPriorityClientsPowerDown
:
3365 // clients didn't respond to our power-down note
3366 IOUnlock(priv
->our_lock
);
3367 IOLockLock(priv
->flags_lock
);
3368 if (pm_vars
->responseFlags
)
3370 // get rid of this stuff
3371 pm_vars
->responseFlags
->release();
3372 pm_vars
->responseFlags
= NULL
;
3374 IOLockUnlock(priv
->flags_lock
);
3375 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogClientTardy
,0,4);
3376 // carry on with the change
3377 OurChangeTellPriorityClientsPowerDown();
3380 case kIOPM_OurChangeNotifyInterestedDriversWillChange
:
3381 // apps didn't respond to our power-down notification
3382 IOUnlock(priv
->our_lock
);
3383 IOLockLock(priv
->flags_lock
);
3384 if (pm_vars
->responseFlags
)
3386 // get rid of this stuff
3387 pm_vars
->responseFlags
->release();
3388 pm_vars
->responseFlags
= NULL
;
3390 IOLockUnlock(priv
->flags_lock
);
3391 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogClientTardy
,0,3);
3392 // carry on with the change
3393 OurChangeNotifyInterestedDriversWillChange();
3397 // not waiting for acks
3398 IOUnlock(priv
->our_lock
);
3404 //*********************************************************************************
3407 //*********************************************************************************
3409 void IOService::start_ack_timer ( void )
3411 AbsoluteTime deadline
;
3413 clock_interval_to_deadline(ACK_TIMER_PERIOD
, kNanosecondScale
, &deadline
);
3415 thread_call_enter_delayed(priv
->ackTimer
, deadline
);
3419 //*********************************************************************************
3422 //*********************************************************************************
3424 void IOService::stop_ack_timer ( void )
3426 thread_call_cancel(priv
->ackTimer
);
3430 //*********************************************************************************
3431 // c-language timer expiration functions
3433 //*********************************************************************************
3435 static void ack_timer_expired ( thread_call_param_t us
)
3437 ((IOService
*)us
)->ack_timer_ticked();
3441 static void settle_timer_expired ( thread_call_param_t us
)
3443 ((IOService
*)us
)->settleTimerExpired();
3447 //*********************************************************************************
3448 // add_child_to_active_change
3450 // A child has just registered with us. If there is
3451 // currently a change in progress, get the new party involved: if we
3452 // have notified all parties and are waiting for acks, notify the new
3454 //*********************************************************************************
3456 IOReturn
IOService::add_child_to_active_change ( IOPowerConnection
* newObject
)
3458 if (! acquire_lock() )
3463 switch (priv
->machine_state
)
3465 case kIOPM_OurChangeSetPowerState
:
3466 case kIOPM_ParentDownSetPowerState_Delayed
:
3467 case kIOPM_ParentUpSetPowerState_Delayed
:
3468 // one for this child and one to prevent
3469 priv
->head_note_pendingAcks
+= 2;
3470 // incoming acks from changing our state
3471 IOUnlock(priv
->our_lock
);
3472 notifyChild(newObject
, true);
3473 if (! acquire_lock() )
3476 --priv
->head_note_pendingAcks
;
3479 // are we still waiting for acks?
3480 if ( --priv
->head_note_pendingAcks
== 0 )
3482 // no, stop the timer
3484 IOUnlock(priv
->our_lock
);
3486 // and now we can continue
3491 case kIOPM_OurChangeFinish
:
3492 case kIOPM_ParentDownAcknowledgeChange_Delayed
:
3493 case kIOPM_ParentUpAcknowledgePowerChange_Delayed
:
3494 // one for this child and one to prevent
3495 priv
->head_note_pendingAcks
+= 2;
3496 // incoming acks from changing our state
3497 IOUnlock(priv
->our_lock
);
3498 notifyChild(newObject
, false);
3499 if (! acquire_lock() )
3502 --priv
->head_note_pendingAcks
;
3505 // are we still waiting for acks?
3506 if ( --priv
->head_note_pendingAcks
== 0 )
3508 // no, stop the timer
3510 IOUnlock(priv
->our_lock
);
3512 // and now we can continue
3518 IOUnlock(priv
->our_lock
);
3523 //*********************************************************************************
3524 // add_driver_to_active_change
3526 // An interested driver has just registered with us. If there is
3527 // currently a change in progress, get the new party involved: if we
3528 // have notified all parties and are waiting for acks, notify the new
3530 //*********************************************************************************
3532 IOReturn
IOService::add_driver_to_active_change ( IOPMinformee
* newObject
)
3534 if (! acquire_lock() )
3539 switch (priv
->machine_state
) {
3540 case kIOPM_OurChangeSetPowerState
:
3541 case kIOPM_ParentDownSetPowerState_Delayed
:
3542 case kIOPM_ParentUpSetPowerState_Delayed
:
3543 // one for this driver and one to prevent
3544 priv
->head_note_pendingAcks
+= 2;
3545 // incoming acks from changing our state
3546 IOUnlock(priv
->our_lock
);
3547 // inform the driver
3548 inform(newObject
, true);
3549 if (! acquire_lock() )
3552 --priv
->head_note_pendingAcks
;
3555 // are we still waiting for acks?
3556 if ( --priv
->head_note_pendingAcks
== 0 )
3558 // no, stop the timer
3560 IOUnlock(priv
->our_lock
);
3562 // and now we can continue
3567 case kIOPM_OurChangeFinish
:
3568 case kIOPM_ParentDownAcknowledgeChange_Delayed
:
3569 case kIOPM_ParentUpAcknowledgePowerChange_Delayed
:
3570 // one for this driver and one to prevent
3571 priv
->head_note_pendingAcks
+= 2;
3572 // incoming acks from changing our state
3573 IOUnlock(priv
->our_lock
);
3574 // inform the driver
3575 inform(newObject
, false);
3576 if (! acquire_lock() ) {
3578 --priv
->head_note_pendingAcks
;
3581 // are we still waiting for acks?
3582 if ( --priv
->head_note_pendingAcks
== 0 ) {
3583 // no, stop the timer
3585 IOUnlock(priv
->our_lock
);
3587 // and now we can continue
3593 IOUnlock(priv
->our_lock
);
3598 //*********************************************************************************
3599 // start_parent_change
3601 // Here we begin the processing of a change note initiated by our parent
3602 // which is at the head of the queue.
3604 // It is possible for the change to be processed to completion and removed from the queue.
3605 // There are several possible interruptions to the processing, though, and they are:
3606 // we may have to wait for interested parties to acknowledge our pre-change notification,
3607 // we may have to wait for our controlling driver to change the hardware power state,
3608 // there may be a settling time after changing the hardware power state,
3609 // we may have to wait for interested parties to acknowledge our post-change notification,
3610 // we may have to wait for the acknowledgement timer expiration to substitute for the
3611 // acknowledgement from a failing driver.
3612 //*********************************************************************************
3614 IOReturn
IOService::start_parent_change ( unsigned long queue_head
)
3616 priv
->head_note
= queue_head
;
3617 priv
->head_note_flags
= priv
-> changeList
->changeNote
[priv
->head_note
].flags
;
3618 priv
->head_note_state
= priv
->changeList
->changeNote
[priv
->head_note
].newStateNumber
;
3619 priv
->imminentState
= priv
->head_note_state
;
3620 priv
->head_note_outputFlags
= priv
->changeList
->changeNote
[priv
->head_note
].outputPowerCharacter
;
3621 priv
->head_note_domainState
= priv
->changeList
->changeNote
[priv
->head_note
].domainState
;
3622 priv
->head_note_parent
= priv
->changeList
->changeNote
[priv
->head_note
].parent
;
3623 priv
->head_note_capabilityFlags
= priv
->changeList
->changeNote
[priv
->head_note
].capabilityFlags
;
3625 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogStartParentChange
,
3626 (unsigned long)priv
->head_note_state
,(unsigned long)pm_vars
->myCurrentState
);
3628 // if we need something and haven't told the parent, do so
3629 ask_parent( priv
->ourDesiredPowerState
);
3631 // power domain is lowering
3632 if ( priv
->head_note_state
< pm_vars
->myCurrentState
)
3634 setParentInfo(priv
->changeList
->changeNote
[priv
->head_note
].singleParentState
,priv
->head_note_parent
);
3635 priv
->initial_change
= false;
3636 // tell apps and kernel clients
3637 priv
->machine_state
= kIOPM_ParentDownTellPriorityClientsPowerDown_Immediate
;
3639 // are we waiting for responses?
3640 if ( tellChangeDown1(priv
->head_note_state
) )
3642 // no, notify priority clients
3643 return ParentDownTellPriorityClientsPowerDown_Immediate();
3646 return IOPMWillAckLater
;
3649 // parent is raising power, we may or may not
3650 if ( priv
->head_note_state
> pm_vars
->myCurrentState
)
3652 if ( priv
->ourDesiredPowerState
> pm_vars
->myCurrentState
)
3654 if ( priv
->ourDesiredPowerState
< priv
->head_note_state
)
3656 // we do, but not all the way
3657 priv
->head_note_state
= priv
->ourDesiredPowerState
;
3658 priv
->imminentState
= priv
->head_note_state
;
3659 priv
->head_note_outputFlags
= pm_vars
->thePowerStates
[priv
->head_note_state
].outputPowerCharacter
;
3660 priv
->head_note_capabilityFlags
= pm_vars
->thePowerStates
[priv
->head_note_state
].capabilityFlags
;
3661 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogAmendParentChange
,(unsigned long)priv
->head_note_state
,0);
3665 priv
->head_note_state
= pm_vars
->myCurrentState
;
3666 priv
->imminentState
= priv
->head_note_state
;
3667 priv
->head_note_outputFlags
= pm_vars
->thePowerStates
[priv
->head_note_state
].outputPowerCharacter
;
3668 priv
->head_note_capabilityFlags
= pm_vars
->thePowerStates
[priv
->head_note_state
].capabilityFlags
;
3669 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogAmendParentChange
,(unsigned long)priv
->head_note_state
,0);
3673 if ( (priv
->head_note_state
> pm_vars
->myCurrentState
) &&
3674 (priv
->head_note_flags
& IOPMDomainDidChange
) )
3677 priv
->initial_change
= false;
3678 priv
->machine_state
= kIOPM_ParentUpSetPowerState_Delayed
;
3679 if ( notifyAll(true) == IOPMAckImplied
) {
3680 return ParentUpSetPowerState_Immediate();
3682 // they didn't all ack
3683 return IOPMWillAckLater
;
3687 // a null change or power will go up
3688 return IOPMAckImplied
;
3692 //*********************************************************************************
3695 // Here we begin the processing of a change note initiated by us
3696 // which is at the head of the queue.
3698 // It is possible for the change to be processed to completion and removed from the queue.
3699 // There are several possible interruptions to the processing, though, and they are:
3700 // we may have to wait for interested parties to acknowledge our pre-change notification,
3701 // changes initiated by the parent will wait in the middle for powerStateDidChange,
3702 // we may have to wait for our controlling driver to change the hardware power state,
3703 // there may be a settling time after changing the hardware power state,
3704 // we may have to wait for interested parties to acknowledge our post-change notification,
3705 // we may have to wait for the acknowledgement timer expiration to substitute for the
3706 // acknowledgement from a failing driver.
3707 //*********************************************************************************
3709 void IOService::start_our_change ( unsigned long queue_head
)
3711 priv
->head_note
= queue_head
;
3712 priv
->head_note_flags
= priv
->changeList
->changeNote
[priv
->head_note
].flags
;
3713 priv
->head_note_state
= priv
->changeList
->changeNote
[priv
->head_note
].newStateNumber
;
3714 priv
->imminentState
= priv
->head_note_state
;
3715 priv
->head_note_outputFlags
= priv
->changeList
->changeNote
[priv
->head_note
].outputPowerCharacter
;
3716 priv
->head_note_capabilityFlags
= priv
->changeList
->changeNote
[priv
->head_note
].capabilityFlags
;
3718 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogStartDeviceChange
,
3719 (unsigned long)priv
->head_note_state
,(unsigned long)pm_vars
->myCurrentState
);
3721 // can our driver switch to the new state?
3722 if ( priv
->head_note_capabilityFlags
& IOPMNotAttainable
)
3724 // no, ask the parent to do it then
3725 if ( ! priv
->we_are_root
)
3727 ask_parent(priv
->head_note_state
);
3729 // mark the change note un-actioned
3730 priv
-> head_note_flags
|= IOPMNotDone
;
3736 // is there enough power in the domain?
3737 if ( (pm_vars
->maxCapability
< priv
->head_note_state
) && (! priv
->we_are_root
) )
3739 // no, ask the parent to raise it
3740 if ( ! priv
->we_are_root
)
3742 ask_parent(priv
->head_note_state
);
3744 // no, mark the change note un-actioned
3745 priv
->head_note_flags
|= IOPMNotDone
;
3747 // till the parent raises power
3752 if ( ! priv
->initial_change
)
3754 if ( priv
->head_note_state
== pm_vars
->myCurrentState
)
3756 // we initiated a null change; forget it
3761 priv
->initial_change
= false;
3764 if ( priv
->head_note_state
< pm_vars
->myCurrentState
)
3766 // yes, in case we have to wait for acks
3767 priv
->machine_state
= kIOPM_OurChangeTellClientsPowerDown
;
3768 pm_vars
->doNotPowerDown
= false;
3770 // ask apps and kernel clients if we can drop power
3771 pm_vars
->outofbandparameter
= kNotifyApps
;
3772 if ( askChangeDown(priv
->head_note_state
) )
3774 // don't have to wait, did any clients veto?
3775 if ( pm_vars
->doNotPowerDown
)
3777 // yes, rescind the warning
3778 tellNoChangeDown(priv
->head_note_state
);
3779 // mark the change note un-actioned
3780 priv
-> head_note_flags
|= IOPMNotDone
;
3784 // no, tell'em we're dropping power
3785 OurChangeTellClientsPowerDown();
3789 // we are raising power
3790 if ( ! priv
->we_are_root
)
3792 // if this changes our power requirement, tell the parent
3793 ask_parent(priv
->head_note_state
);
3795 // in case they don't all ack
3796 priv
->machine_state
= kIOPM_OurChangeSetPowerState
;
3798 // notify interested drivers and children
3799 if ( notifyAll(true) == IOPMAckImplied
)
3801 OurChangeSetPowerState();
3807 //*********************************************************************************
3810 // Call the power domain parent to ask for a higher power state in the domain
3811 // or to suggest a lower power state.
3812 //*********************************************************************************
3814 IOReturn
IOService::ask_parent ( unsigned long requestedState
)
3818 IOPowerConnection
*connection
;
3820 unsigned long ourRequest
= pm_vars
->thePowerStates
[requestedState
].inputPowerRequirement
;
3822 if ( pm_vars
->thePowerStates
[requestedState
].capabilityFlags
& (kIOPMChildClamp
| kIOPMPreventIdleSleep
) )
3824 ourRequest
|= kIOPMPreventIdleSleep
;
3826 if ( pm_vars
->thePowerStates
[requestedState
].capabilityFlags
& (kIOPMChildClamp2
| kIOPMPreventSystemSleep
) )
3828 ourRequest
|= kIOPMPreventSystemSleep
;
3831 // is this a new desire?
3832 if ( priv
->previousRequest
== ourRequest
)
3834 // no, the parent knows already, just return
3838 if ( priv
->we_are_root
)
3842 priv
->previousRequest
= ourRequest
;
3844 iter
= getParentIterator(gIOPowerPlane
);
3848 while ( (next
= iter
->getNextObject()) )
3850 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) )
3852 parent
= (IOService
*)connection
->copyParentEntry(gIOPowerPlane
);
3854 if ( parent
->requestPowerDomainState(ourRequest
,connection
,IOPMLowestState
)!= IOPMNoErr
)
3856 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogRequestDenied
,
3857 (unsigned long)priv
->previousRequest
,0);
3870 //*********************************************************************************
3873 // Call the controlling driver and have it change the power state of the
3874 // hardware. If it returns IOPMAckImplied, the change is complete, and
3875 // we return IOPMAckImplied. Otherwise, it will ack when the change
3876 // is done; we return IOPMWillAckLater.
3877 //*********************************************************************************
3878 IOReturn
IOService::instruct_driver ( unsigned long newState
)
3882 // can our driver switch to the desired state?
3883 if ( pm_vars
->thePowerStates
[newState
].capabilityFlags
& IOPMNotAttainable
)
3886 return IOPMAckImplied
;
3889 priv
->driver_timer
= -1;
3892 OUR_PMLog( kPMLogProgramHardware
, (UInt32
) this, newState
);
3893 delay
= pm_vars
->theControllingDriver
->setPowerState( newState
,this );
3894 OUR_PMLog((UInt32
) -kPMLogProgramHardware
, (UInt32
) this, (UInt32
) delay
);
3897 if ( delay
== IOPMAckImplied
)
3899 priv
->driver_timer
= 0;
3900 return IOPMAckImplied
;
3903 // it acked behind our back
3904 if ( priv
->driver_timer
== 0 )
3906 return IOPMAckImplied
;
3912 return IOPMAckImplied
;
3916 priv
->driver_timer
= (delay
/ ( ACK_TIMER_PERIOD
/ ns_per_us
)) + 1;
3917 return IOPMWillAckLater
;
3921 //*********************************************************************************
3924 // We are acquiring the lock we use to protect our queue head from
3925 // simutaneous access by a thread which calls acknowledgePowerStateChange
3926 // or acknowledgeSetPowerState and the ack timer expiration thread.
3927 // Return TRUE if we acquire the lock, and the queue head didn't change
3928 // while we were acquiring the lock (and maybe blocked).
3929 // If there is no queue head, or it changes while we are blocked,
3930 // return FALSE with the lock unlocked.
3931 //*********************************************************************************
3933 bool IOService::acquire_lock ( void )
3935 long current_change_note
;
3937 current_change_note
= priv
->head_note
;
3938 if ( current_change_note
== -1 ) {
3942 IOTakeLock(priv
->our_lock
);
3943 if ( current_change_note
== priv
->head_note
)
3947 // we blocked and something changed radically
3948 // so there's nothing to do any more
3949 IOUnlock(priv
->our_lock
);
3955 //*********************************************************************************
3958 // Ask registered applications and kernel clients if we can change to a lower
3961 // Subclass can override this to send a different message type. Parameter is
3962 // the destination state number.
3964 // Return true if we don't have to wait for acknowledgements
3965 //*********************************************************************************
3967 bool IOService::askChangeDown ( unsigned long stateNum
)
3969 return tellClientsWithResponse(kIOMessageCanDevicePowerOff
);
3973 //*********************************************************************************
3976 // Notify registered applications and kernel clients that we are definitely
3979 // Return true if we don't have to wait for acknowledgements
3980 //*********************************************************************************
3982 bool IOService::tellChangeDown1 ( unsigned long stateNum
)
3984 pm_vars
->outofbandparameter
= kNotifyApps
;
3985 return tellChangeDown(stateNum
);
3989 //*********************************************************************************
3992 // Notify priority clients that we are definitely dropping power.
3994 // Return true if we don't have to wait for acknowledgements
3995 //*********************************************************************************
3997 bool IOService::tellChangeDown2 ( unsigned long stateNum
)
3999 pm_vars
->outofbandparameter
= kNotifyPriority
;
4000 return tellChangeDown(stateNum
);
4004 //*********************************************************************************
4007 // Notify registered applications and kernel clients that we are definitely
4010 // Subclass can override this to send a different message type. Parameter is
4011 // the destination state number.
4013 // Return true if we don't have to wait for acknowledgements
4014 //*********************************************************************************
4016 bool IOService::tellChangeDown ( unsigned long stateNum
)
4018 return tellClientsWithResponse(kIOMessageDeviceWillPowerOff
);
4022 //*********************************************************************************
4023 // tellClientsWithResponse
4025 // Notify registered applications and kernel clients that we are definitely
4028 // Return true if we don't have to wait for acknowledgements
4029 //*********************************************************************************
4031 bool IOService::tellClientsWithResponse ( int messageType
)
4033 struct context theContext
;
4034 AbsoluteTime deadline
;
4037 pm_vars
->responseFlags
= OSArray::withCapacity( 1 );
4038 pm_vars
->serialNumber
+= 1;
4040 theContext
.responseFlags
= pm_vars
->responseFlags
;
4041 theContext
.serialNumber
= pm_vars
->serialNumber
;
4042 theContext
.flags_lock
= priv
->flags_lock
;
4043 theContext
.counter
= 1;
4044 theContext
.msgType
= messageType
;
4045 theContext
.us
= this;
4046 theContext
.maxTimeRequested
= 0;
4047 theContext
.stateNumber
= priv
->head_note_state
;
4048 theContext
.stateFlags
= priv
->head_note_capabilityFlags
;
4050 IOLockLock(priv
->flags_lock
);
4052 // position zero is false to
4053 // prevent allowCancelCommon from succeeding
4054 aBool
= OSBoolean::withBoolean(false);
4055 theContext
.responseFlags
->setObject(0,aBool
);
4057 IOLockUnlock(priv
->flags_lock
);
4059 switch ( pm_vars
->outofbandparameter
) {
4061 applyToInterested(gIOAppPowerStateInterest
,tellAppWithResponse
,(void *)&theContext
);
4062 applyToInterested(gIOGeneralInterest
,tellClientWithResponse
,(void *)&theContext
);
4064 case kNotifyPriority
:
4065 applyToInterested(gIOPriorityPowerStateInterest
,tellClientWithResponse
,(void *)&theContext
);
4069 if (! acquire_lock() )
4073 IOLockLock(priv
->flags_lock
);
4074 // now fix position zero
4075 aBool
= OSBoolean::withBoolean(true);
4076 theContext
.responseFlags
->replaceObject(0,aBool
);
4078 IOLockUnlock(priv
->flags_lock
);
4080 // do we have to wait for somebody?
4081 if ( ! checkForDone() )
4083 // yes, start the ackTimer
4084 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogStartAckTimer
,theContext
.maxTimeRequested
,0);
4085 clock_interval_to_deadline(theContext
.maxTimeRequested
/ 1000, kMillisecondScale
, &deadline
);
4087 thread_call_enter_delayed(priv
->ackTimer
, deadline
);
4089 IOUnlock(priv
->our_lock
);
4093 IOUnlock(priv
->our_lock
);
4094 IOLockLock(priv
->flags_lock
);
4096 // everybody responded
4097 pm_vars
->responseFlags
->release();
4098 pm_vars
->responseFlags
= NULL
;
4099 IOLockUnlock(priv
->flags_lock
);
4105 //*********************************************************************************
4106 // tellAppWithResponse
4108 // We send a message to an application, and we expect a response, so we compute a
4109 // cookie we can identify the response with.
4110 //*********************************************************************************
4111 void tellAppWithResponse ( OSObject
* object
, void * context
)
4113 struct context
*theContext
= (struct context
*)context
;
4115 IOPMprot
*pm_vars
= theContext
->us
->pm_vars
;
4117 if( OSDynamicCast( IOService
, object
) )
4119 // Automatically 'ack' in kernel clients
4120 IOLockLock(theContext
->flags_lock
);
4121 aBool
= OSBoolean::withBoolean(true);
4122 theContext
->responseFlags
->setObject(theContext
->counter
,aBool
);
4124 IOLockUnlock(theContext
->flags_lock
);
4126 const char *who
= ((IOService
*) object
)->getName();
4127 pm_vars
->thePlatform
->PMLog(who
,
4128 kPMLogClientAcknowledge
, theContext
->msgType
, * (UInt32
*) object
);
4130 UInt32 refcon
= ((theContext
->serialNumber
& 0xFFFF)<<16)
4131 + (theContext
->counter
& 0xFFFF);
4132 IOLockLock(theContext
->flags_lock
);
4133 aBool
= OSBoolean::withBoolean(false);
4134 theContext
->responseFlags
->setObject(theContext
->counter
,aBool
);
4136 IOLockUnlock(theContext
->flags_lock
);
4138 OUR_PMLog(kPMLogAppNotify
, theContext
->msgType
, refcon
);
4139 theContext
->us
->messageClient(theContext
->msgType
,object
,(void *)refcon
);
4140 if ( theContext
->maxTimeRequested
< k30seconds
)
4142 theContext
->maxTimeRequested
= k30seconds
;
4145 theContext
->counter
+= 1;
4148 //*********************************************************************************
4149 // tellClientWithResponse
4151 // We send a message to an in-kernel client, and we expect a response, so we compute a
4152 // cookie we can identify the response with.
4153 // If it doesn't understand the notification (it is not power-management savvy)
4154 // we won't wait for it to prepare for sleep. If it tells us via a return code
4155 // in the passed struct that it is currently ready, we won't wait for it to prepare.
4156 // If it tells us via the return code in the struct that it does need time, we will chill.
4157 //*********************************************************************************
4158 void tellClientWithResponse ( OSObject
* object
, void * context
)
4160 struct context
*theContext
= (struct context
*)context
;
4161 IOPowerStateChangeNotification notify
;
4167 refcon
= ((theContext
->serialNumber
& 0xFFFF)<<16) + (theContext
->counter
& 0xFFFF);
4168 IOLockLock(theContext
->flags_lock
);
4169 aBool
= OSBoolean::withBoolean(false);
4170 theContext
->responseFlags
->setObject(theContext
->counter
,aBool
);
4172 IOLockUnlock(theContext
->flags_lock
);
4174 IOPMprot
*pm_vars
= theContext
->us
->pm_vars
;
4175 if (gIOKitDebug
& kIOLogPower
) {
4176 OUR_PMLog(kPMLogClientNotify
, refcon
, (UInt32
) theContext
->msgType
);
4177 if (OSDynamicCast(IOService
, object
)) {
4178 const char *who
= ((IOService
*) object
)->getName();
4179 pm_vars
->thePlatform
->PMLog(who
,
4180 kPMLogClientNotify
, * (UInt32
*) object
, (UInt32
) object
);
4181 } else if (OSDynamicCast(_IOServiceInterestNotifier
, object
)) {
4182 _IOServiceInterestNotifier
*n
= (_IOServiceInterestNotifier
*) object
;
4183 OUR_PMLog(kPMLogClientNotify
, (UInt32
) n
->handler
, 0);
4187 notify
.powerRef
= (void *)refcon
;
4188 notify
.returnValue
= 0;
4189 notify
.stateNumber
= theContext
->stateNumber
;
4190 notify
.stateFlags
= theContext
->stateFlags
;
4191 retCode
= theContext
->us
->messageClient(theContext
->msgType
,object
,(void *)¬ify
);
4192 if ( retCode
== kIOReturnSuccess
)
4194 if ( notify
.returnValue
== 0 )
4196 // client doesn't want time to respond
4197 IOLockLock(theContext
->flags_lock
);
4198 aBool
= OSBoolean::withBoolean(true);
4199 // so set its flag true
4200 theContext
->responseFlags
->replaceObject(theContext
->counter
,aBool
);
4202 IOLockUnlock(theContext
->flags_lock
);
4203 OUR_PMLog(kPMLogClientAcknowledge
, refcon
, (UInt32
) object
);
4205 IOLockLock(theContext
->flags_lock
);
4207 // it does want time, and it hasn't responded yet
4208 theFlag
= theContext
->responseFlags
->getObject(theContext
->counter
);
4211 if ( ((OSBoolean
*)theFlag
)->isFalse() )
4213 // so note its time requirement
4214 if ( theContext
->maxTimeRequested
< notify
.returnValue
)
4216 theContext
->maxTimeRequested
= notify
.returnValue
;
4220 IOLockUnlock(theContext
->flags_lock
);
4223 OUR_PMLog(kPMLogClientAcknowledge
, refcon
, 0);
4224 // not a client of ours
4225 IOLockLock(theContext
->flags_lock
);
4226 // so we won't be waiting for response
4227 aBool
= OSBoolean::withBoolean(true);
4228 theContext
->responseFlags
->replaceObject(theContext
->counter
,aBool
);
4230 IOLockUnlock(theContext
->flags_lock
);
4232 theContext
->counter
+= 1;
4236 //*********************************************************************************
4239 // Notify registered applications and kernel clients that we are not
4242 // Subclass can override this to send a different message type. Parameter is
4243 // the aborted destination state number.
4244 //*********************************************************************************
4246 void IOService::tellNoChangeDown ( unsigned long )
4248 return tellClients(kIOMessageDeviceWillNotPowerOff
);
4252 //*********************************************************************************
4255 // Notify registered applications and kernel clients that we are raising power.
4257 // Subclass can override this to send a different message type. Parameter is
4258 // the aborted destination state number.
4259 //*********************************************************************************
4261 void IOService::tellChangeUp ( unsigned long )
4263 return tellClients(kIOMessageDeviceHasPoweredOn
);
4267 //*********************************************************************************
4270 // Notify registered applications and kernel clients of something.
4271 //*********************************************************************************
4273 void IOService::tellClients ( int messageType
)
4275 struct context theContext
;
4277 theContext
.msgType
= messageType
;
4278 theContext
.us
= this;
4279 theContext
.stateNumber
= priv
->head_note_state
;
4280 theContext
.stateFlags
= priv
->head_note_capabilityFlags
;
4282 applyToInterested(gIOAppPowerStateInterest
,tellClient
,(void *)&theContext
);
4283 applyToInterested(gIOGeneralInterest
,tellClient
,(void *)&theContext
);
4287 //*********************************************************************************
4290 // Notify a registered application or kernel client of something.
4291 //*********************************************************************************
4292 void tellClient ( OSObject
* object
, void * context
)
4294 struct context
*theContext
= (struct context
*)context
;
4295 IOPowerStateChangeNotification notify
;
4297 notify
.powerRef
= (void *) 0;
4298 notify
.returnValue
= 0;
4299 notify
.stateNumber
= theContext
->stateNumber
;
4300 notify
.stateFlags
= theContext
->stateFlags
;
4302 theContext
->us
->messageClient(theContext
->msgType
,object
, ¬ify
);
4306 // **********************************************************************************
4309 // **********************************************************************************
4310 bool IOService::checkForDone ( void )
4315 IOLockLock(priv
->flags_lock
);
4316 if ( pm_vars
->responseFlags
== NULL
)
4318 IOLockUnlock(priv
->flags_lock
);
4322 for ( i
= 0; ; i
++ )
4324 theFlag
= pm_vars
->responseFlags
->getObject(i
);
4325 if ( theFlag
== NULL
)
4329 if ( ((OSBoolean
*)theFlag
)->isFalse() )
4331 IOLockUnlock(priv
->flags_lock
);
4335 IOLockUnlock(priv
->flags_lock
);
4340 // **********************************************************************************
4343 // **********************************************************************************
4344 bool IOService::responseValid ( unsigned long x
)
4346 UInt16 serialComponent
;
4347 UInt16 ordinalComponent
;
4349 unsigned long refcon
= (unsigned long)x
;
4352 serialComponent
= (refcon
>>16) & 0xFFFF;
4353 ordinalComponent
= refcon
& 0xFFFF;
4355 if ( serialComponent
!= pm_vars
->serialNumber
)
4360 IOLockLock(priv
->flags_lock
);
4361 if ( pm_vars
->responseFlags
== NULL
)
4363 IOLockUnlock(priv
->flags_lock
);
4367 theFlag
= pm_vars
->responseFlags
->getObject(ordinalComponent
);
4371 IOLockUnlock(priv
->flags_lock
);
4375 if ( ((OSBoolean
*)theFlag
)->isFalse() )
4377 aBool
= OSBoolean::withBoolean(true);
4378 pm_vars
->responseFlags
->replaceObject(ordinalComponent
,aBool
);
4382 IOLockUnlock(priv
->flags_lock
);
4387 // **********************************************************************************
4390 // Our power state is about to lower, and we have notified applications
4391 // and kernel clients, and one of them has acknowledged. If this is the last to do
4392 // so, and all acknowledgements are positive, we continue with the power change.
4394 // We serialize this processing with timer expiration with a command gate on the
4395 // power management workloop, which the timer expiration is command gated to as well.
4396 // **********************************************************************************
4397 IOReturn
IOService::allowPowerChange ( unsigned long refcon
)
4399 if ( ! initialized
)
4402 return kIOReturnSuccess
;
4405 return pm_vars
->PMcommandGate
->runAction(serializedAllowPowerChange
,(void *)refcon
);
4409 IOReturn
serializedAllowPowerChange ( OSObject
*owner
, void * refcon
, void *, void *, void *)
4411 return ((IOService
*)owner
)->serializedAllowPowerChange2((unsigned long)refcon
);
4414 IOReturn
IOService::serializedAllowPowerChange2 ( unsigned long refcon
)
4417 if ( ! responseValid(refcon
) )
4419 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogAcknowledgeErr5
,refcon
,0);
4421 return kIOReturnSuccess
;
4423 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogClientAcknowledge
,refcon
,0);
4425 return allowCancelCommon();
4429 // **********************************************************************************
4430 // cancelPowerChange
4432 // Our power state is about to lower, and we have notified applications
4433 // and kernel clients, and one of them has vetoed the change. If this is the last
4434 // client to respond, we abandon the power change.
4436 // We serialize this processing with timer expiration with a command gate on the
4437 // power management workloop, which the timer expiration is command gated to as well.
4438 // **********************************************************************************
4439 IOReturn
IOService::cancelPowerChange ( unsigned long refcon
)
4441 if ( ! initialized
)
4444 return kIOReturnSuccess
;
4447 return pm_vars
->PMcommandGate
->runAction(serializedCancelPowerChange
,(void *)refcon
);
4451 IOReturn
serializedCancelPowerChange ( OSObject
*owner
, void * refcon
, void *, void *, void *)
4453 return ((IOService
*)owner
)->serializedCancelPowerChange2((unsigned long)refcon
);
4456 IOReturn
IOService::serializedCancelPowerChange2 ( unsigned long refcon
)
4459 if ( ! responseValid(refcon
) )
4461 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogAcknowledgeErr5
,refcon
,0);
4463 return kIOReturnSuccess
;
4465 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogClientCancel
,refcon
,0);
4467 pm_vars
->doNotPowerDown
= true;
4469 return allowCancelCommon();
4473 // **********************************************************************************
4474 // allowCancelCommon
4476 // **********************************************************************************
4477 IOReturn
IOService::allowCancelCommon ( void )
4479 if (! acquire_lock() )
4481 return kIOReturnSuccess
;
4484 // is this the last response?
4485 if ( checkForDone() )
4487 // yes, stop the timer
4489 IOUnlock(priv
->our_lock
);
4490 IOLockLock(priv
->flags_lock
);
4491 if ( pm_vars
->responseFlags
)
4493 pm_vars
->responseFlags
->release();
4494 pm_vars
->responseFlags
= NULL
;
4496 IOLockUnlock(priv
->flags_lock
);
4497 switch (priv
->machine_state
) {
4498 case kIOPM_OurChangeTellClientsPowerDown
:
4499 // our change, was it vetoed?
4500 if ( ! pm_vars
->doNotPowerDown
)
4502 // no, we can continue
4503 OurChangeTellClientsPowerDown();
4505 // yes, rescind the warning
4506 tellNoChangeDown(priv
->head_note_state
);
4507 // mark the change note un-actioned
4508 priv
->head_note_flags
|= IOPMNotDone
;
4514 case kIOPM_OurChangeTellPriorityClientsPowerDown
:
4515 OurChangeTellPriorityClientsPowerDown();
4517 case kIOPM_OurChangeNotifyInterestedDriversWillChange
:
4518 // our change, continue
4519 OurChangeNotifyInterestedDriversWillChange();
4521 case kIOPM_ParentDownTellPriorityClientsPowerDown_Immediate
:
4522 // parent change, continue
4523 ParentDownTellPriorityClientsPowerDown_Delayed();
4525 case kIOPM_ParentDownNotifyInterestedDriversWillChange_Delayed
:
4526 // parent change, continue
4527 ParentDownNotifyInterestedDriversWillChange_Delayed();
4532 IOUnlock(priv
->our_lock
);
4535 return kIOReturnSuccess
;
4540 //*********************************************************************************
4541 // c_PM_clamp_Timer_Expired (C Func)
4543 // Called when our clamp timer expires...we will call the object method.
4544 //*********************************************************************************
4546 static void c_PM_Clamp_Timer_Expired (OSObject
* client
, IOTimerEventSource
*)
4549 ((IOService
*)client
)->PM_Clamp_Timer_Expired ();
4554 //*********************************************************************************
4555 // PM_Clamp_Timer_Expired
4557 // called when clamp timer expires...set power state to 0.
4558 //*********************************************************************************
4560 void IOService::PM_Clamp_Timer_Expired (void)
4563 if ( ! initialized
)
4569 changePowerStateToPriv (0);
4573 //******************************************************************************
4576 // Set to highest available power state for a minimum of duration milliseconds
4577 //******************************************************************************
4579 #define kFiveMinutesInNanoSeconds (300 * NSEC_PER_SEC)
4581 void IOService::clampPowerOn (unsigned long duration
)
4584 changePowerStateToPriv (pm_vars
->theNumberOfPowerStates
-1);
4586 if ( priv
->clampTimerEventSrc
== NULL
) {
4587 priv
->clampTimerEventSrc
= IOTimerEventSource::timerEventSource(this,
4588 c_PM_Clamp_Timer_Expired
);
4590 IOWorkLoop
* workLoop
= getPMworkloop ();
4592 if ( !priv
->clampTimerEventSrc
|| !workLoop
||
4593 ( workLoop
->addEventSource( priv
->clampTimerEventSrc
) != kIOReturnSuccess
) ) {
4598 priv
->clampTimerEventSrc
->setTimeout(300*USEC_PER_SEC
, USEC_PER_SEC
);
4602 //*********************************************************************************
4605 // Does nothing here. This should be implemented in a subclass driver.
4606 //*********************************************************************************
4608 IOReturn
IOService::setPowerState ( unsigned long powerStateOrdinal
, IOService
* whatDevice
)
4614 //*********************************************************************************
4615 // maxCapabilityForDomainState
4617 // Finds the highest power state in the array whose input power
4618 // requirement is equal to the input parameter. Where a more intelligent
4619 // decision is possible, override this in the subclassed driver.
4620 //*********************************************************************************
4622 unsigned long IOService::maxCapabilityForDomainState ( IOPMPowerFlags domainState
)
4626 if (pm_vars
->theNumberOfPowerStates
== 0 )
4630 for ( i
= (pm_vars
->theNumberOfPowerStates
)-1; i
>= 0; i
-- )
4632 if ( (domainState
& pm_vars
->thePowerStates
[i
].inputPowerRequirement
) == pm_vars
->thePowerStates
[i
].inputPowerRequirement
)
4641 //*********************************************************************************
4642 // initialPowerStateForDomainState
4644 // Finds the highest power state in the array whose input power
4645 // requirement is equal to the input parameter. Where a more intelligent
4646 // decision is possible, override this in the subclassed driver.
4647 //*********************************************************************************
4649 unsigned long IOService::initialPowerStateForDomainState ( IOPMPowerFlags domainState
)
4653 if (pm_vars
->theNumberOfPowerStates
== 0 )
4657 for ( i
= (pm_vars
->theNumberOfPowerStates
)-1; i
>= 0; i
-- )
4659 if ( (domainState
& pm_vars
->thePowerStates
[i
].inputPowerRequirement
) == pm_vars
->thePowerStates
[i
].inputPowerRequirement
)
4668 //*********************************************************************************
4669 // powerStateForDomainState
4671 // Finds the highest power state in the array whose input power
4672 // requirement is equal to the input parameter. Where a more intelligent
4673 // decision is possible, override this in the subclassed driver.
4674 //*********************************************************************************
4676 unsigned long IOService::powerStateForDomainState ( IOPMPowerFlags domainState
)
4680 if (pm_vars
->theNumberOfPowerStates
== 0 )
4684 for ( i
= (pm_vars
->theNumberOfPowerStates
)-1; i
>= 0; i
-- )
4686 if ( (domainState
& pm_vars
->thePowerStates
[i
].inputPowerRequirement
) == pm_vars
->thePowerStates
[i
].inputPowerRequirement
)
4695 //*********************************************************************************
4698 // Does nothing here. This should be implemented in a subclass driver.
4699 //*********************************************************************************
4701 bool IOService::didYouWakeSystem ( void )
4707 //*********************************************************************************
4708 // powerStateWillChangeTo
4710 // Does nothing here. This should be implemented in a subclass driver.
4711 //*********************************************************************************
4713 IOReturn
IOService::powerStateWillChangeTo ( IOPMPowerFlags
, unsigned long, IOService
*)
4719 //*********************************************************************************
4720 // powerStateDidChangeTo
4722 // Does nothing here. This should be implemented in a subclass driver.
4723 //*********************************************************************************
4725 IOReturn
IOService::powerStateDidChangeTo ( IOPMPowerFlags
, unsigned long, IOService
*)
4731 //*********************************************************************************
4734 // Does nothing here. This should be implemented in a subclass policy-maker.
4735 //*********************************************************************************
4737 void IOService::powerChangeDone ( unsigned long )
4742 //*********************************************************************************
4745 // Does nothing here. This should be implemented in a subclass driver.
4746 //*********************************************************************************
4748 IOReturn
IOService::newTemperature ( long currentTemp
, IOService
* whichZone
)
4756 #define super OSObject
4758 OSDefineMetaClassAndStructors(IOPMprot
, OSObject
)
4759 //*********************************************************************************
4762 // Serialize protected instance variables for debug output.
4763 //*********************************************************************************
4764 bool IOPMprot::serialize(OSSerialize
*s
) const
4766 OSString
* theOSString
;
4773 // estimate how many bytes we need to present all power states
4774 buf_size
= 150 // beginning and end of string
4775 + (275 * (int)theNumberOfPowerStates
) // size per state
4776 + 100; // extra room just for kicks
4778 buffer
= ptr
= IONew(char, buf_size
);
4782 ptr
+= sprintf(ptr
,"{ theNumberOfPowerStates = %d, ",(unsigned int)theNumberOfPowerStates
);
4784 if ( theNumberOfPowerStates
!= 0 ) {
4785 ptr
+= sprintf(ptr
,"version %d, ",(unsigned int)thePowerStates
[0].version
);
4788 if ( theNumberOfPowerStates
!= 0 ) {
4789 for ( i
= 0; i
< (int)theNumberOfPowerStates
; i
++ ) {
4790 ptr
+= sprintf(ptr
, "power state %d = { ",i
);
4791 ptr
+= sprintf(ptr
,"capabilityFlags %08x, ",(unsigned int)thePowerStates
[i
].capabilityFlags
);
4792 ptr
+= sprintf(ptr
,"outputPowerCharacter %08x, ",(unsigned int)thePowerStates
[i
].outputPowerCharacter
);
4793 ptr
+= sprintf(ptr
,"inputPowerRequirement %08x, ",(unsigned int)thePowerStates
[i
].inputPowerRequirement
);
4794 ptr
+= sprintf(ptr
,"staticPower %d, ",(unsigned int)thePowerStates
[i
].staticPower
);
4795 ptr
+= sprintf(ptr
,"unbudgetedPower %d, ",(unsigned int)thePowerStates
[i
].unbudgetedPower
);
4796 ptr
+= sprintf(ptr
,"powerToAttain %d, ",(unsigned int)thePowerStates
[i
].powerToAttain
);
4797 ptr
+= sprintf(ptr
,"timeToAttain %d, ",(unsigned int)thePowerStates
[i
].timeToAttain
);
4798 ptr
+= sprintf(ptr
,"settleUpTime %d, ",(unsigned int)thePowerStates
[i
].settleUpTime
);
4799 ptr
+= sprintf(ptr
,"timeToLower %d, ",(unsigned int)thePowerStates
[i
].timeToLower
);
4800 ptr
+= sprintf(ptr
,"settleDownTime %d, ",(unsigned int)thePowerStates
[i
].settleDownTime
);
4801 ptr
+= sprintf(ptr
,"powerDomainBudget %d }, ",(unsigned int)thePowerStates
[i
].powerDomainBudget
);
4805 ptr
+= sprintf(ptr
,"aggressiveness = %d, ",(unsigned int)aggressiveness
);
4806 ptr
+= sprintf(ptr
,"myCurrentState = %d, ",(unsigned int)myCurrentState
);
4807 ptr
+= sprintf(ptr
,"parentsCurrentPowerFlags = %08x, ",(unsigned int)parentsCurrentPowerFlags
);
4808 ptr
+= sprintf(ptr
,"maxCapability = %d }",(unsigned int)maxCapability
);
4810 theOSString
= OSString::withCString(buffer
);
4811 rtn_code
= theOSString
->serialize(s
);
4812 theOSString
->release();
4813 IODelete(buffer
, char, buf_size
);
4820 #define super OSObject
4822 OSDefineMetaClassAndStructors(IOPMpriv
, OSObject
)
4823 //*********************************************************************************
4826 // Serialize private instance variables for debug output.
4827 //*********************************************************************************
4828 bool IOPMpriv::serialize(OSSerialize
*s
) const
4830 OSString
* theOSString
;
4834 IOPMinformee
* nextObject
;
4836 buffer
= ptr
= IONew(char, 2000);
4840 ptr
+= sprintf(ptr
,"{ this object = %08x",(unsigned int)owner
);
4841 if ( we_are_root
) {
4842 ptr
+= sprintf(ptr
," (root)");
4844 ptr
+= sprintf(ptr
,", ");
4846 nextObject
= interestedDrivers
->firstInList(); // display interested drivers
4847 while ( nextObject
!= NULL
) {
4848 ptr
+= sprintf(ptr
,"interested driver = %08x, ",(unsigned int)nextObject
->whatObject
);
4849 nextObject
= interestedDrivers
->nextInList(nextObject
);
4852 if ( machine_state
!= kIOPM_Finished
) {
4853 ptr
+= sprintf(ptr
,"machine_state = %d, ",(unsigned int)machine_state
);
4854 ptr
+= sprintf(ptr
,"driver_timer = %d, ",(unsigned int)driver_timer
);
4855 ptr
+= sprintf(ptr
,"settle_time = %d, ",(unsigned int)settle_time
);
4856 ptr
+= sprintf(ptr
,"head_note_flags = %08x, ",(unsigned int)head_note_flags
);
4857 ptr
+= sprintf(ptr
,"head_note_state = %d, ",(unsigned int)head_note_state
);
4858 ptr
+= sprintf(ptr
,"head_note_outputFlags = %08x, ",(unsigned int)head_note_outputFlags
);
4859 ptr
+= sprintf(ptr
,"head_note_domainState = %08x, ",(unsigned int)head_note_domainState
);
4860 ptr
+= sprintf(ptr
,"head_note_capabilityFlags = %08x, ",(unsigned int)head_note_capabilityFlags
);
4861 ptr
+= sprintf(ptr
,"head_note_pendingAcks = %d, ",(unsigned int)head_note_pendingAcks
);
4864 if ( device_overrides
) {
4865 ptr
+= sprintf(ptr
,"device overrides, ");
4867 ptr
+= sprintf(ptr
,"driverDesire = %d, ",(unsigned int)driverDesire
);
4868 ptr
+= sprintf(ptr
,"deviceDesire = %d, ",(unsigned int)deviceDesire
);
4869 ptr
+= sprintf(ptr
,"ourDesiredPowerState = %d, ",(unsigned int)ourDesiredPowerState
);
4870 ptr
+= sprintf(ptr
,"previousRequest = %d }",(unsigned int)previousRequest
);
4872 theOSString
= OSString::withCString(buffer
);
4873 rtn_code
= theOSString
->serialize(s
);
4874 theOSString
->release();
4875 IODelete(buffer
, char, 2000);