2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
26 #include <IOKit/IOService.h>
27 #include <IOKit/IOLib.h>
28 #include <IOKit/IOCommandGate.h>
29 #include <IOKit/IOTimerEventSource.h>
30 #include <IOKit/IOWorkLoop.h>
31 #include <IOKit/IOPlatformExpert.h>
32 #include <IOKit/assert.h>
33 #include <IOKit/IOMessage.h>
34 #include <IOKit/IOKitDebug.h>
35 #include <IOKit/IOTimeStamp.h>
36 #include <IOKit/pwr_mgt/IOPMinformee.h>
37 #include "IOKit/pwr_mgt/IOPMinformeeList.h"
38 #include "IOKit/pwr_mgt/IOPMchangeNoteList.h"
39 #include "IOKit/pwr_mgt/IOPMlog.h"
40 #include "IOKit/pwr_mgt/IOPowerConnection.h"
41 #include <kern/clock.h>
43 #define super IORegistryEntry
45 // Some debug functions
47 ioSPMTrace(unsigned int csc
,
48 unsigned int a
= 0, unsigned int b
= 0,
49 unsigned int c
= 0, unsigned int d
= 0)
51 if (gIOKitDebug
& kIOLogTracePower
)
52 IOTimeStampConstant(IODBG_POWER(csc
), a
, b
, c
, d
);
56 ioSPMTraceStart(unsigned int csc
,
57 unsigned int a
= 0, unsigned int b
= 0,
58 unsigned int c
= 0, unsigned int d
= 0)
60 if (gIOKitDebug
& kIOLogTracePower
)
61 IOTimeStampConstant(IODBG_POWER(csc
)|DBG_FUNC_START
, a
, b
, c
, d
);
65 ioSPMTraceEnd(unsigned int csc
,
66 unsigned int a
= 0, unsigned int b
= 0,
67 unsigned int c
= 0, unsigned int d
= 0)
69 if (gIOKitDebug
& kIOLogTracePower
)
70 IOTimeStampConstant(IODBG_POWER(csc
)|DBG_FUNC_END
, a
, b
, c
, d
);
74 static void ack_timer_expired(thread_call_param_t
);
75 static void settle_timer_expired(thread_call_param_t
);
76 IOReturn
unIdleDevice ( OSObject
*, void *, void *, void *, void * );
77 static void PM_idle_timer_expired(OSObject
*, IOTimerEventSource
*);
78 static void c_PM_Clamp_Timer_Expired (OSObject
* client
,IOTimerEventSource
*);
79 void tellAppWithResponse ( OSObject
* object
, void * context
);
80 void tellClientWithResponse ( OSObject
* object
, void * context
);
81 void tellClient ( OSObject
* object
, void * context
);
82 IOReturn
serializedAllowPowerChange ( OSObject
*, void *, void *, void *, void *);
83 IOReturn
serializedCancelPowerChange ( OSObject
*, void *, void *, void *, void *);
85 extern const IORegistryPlane
* gIOPowerPlane
;
88 // and there's 1000 nanoseconds in a microsecond:
89 #define ns_per_us 1000
92 // The current change note is processed by a state machine.
93 // Inputs are acks from interested parties, ack from the controlling driver,
94 // ack timeouts, settle timeout, and powerStateDidChange from the parent.
95 // These are the states:
98 IOPMour_prechange_03
= 1,
100 IOPMour_prechange_05
,
120 enum { // values of outofbandparameter
125 struct context
{ // used for applyToInterested
126 OSArray
* responseFlags
;
129 UInt32 maxTimeRequested
;
133 unsigned long stateNumber
;
134 IOPMPowerFlags stateFlags
;
137 // five minutes in microseconds
138 #define FIVE_MINUTES 5*60*1000000
139 #define k30seconds 30*1000000
142 There are two different kinds of power state changes. One is initiated by a subclassed device object which has either
143 decided to change power state, or its controlling driver has suggested it, or some other driver wants to use the
144 idle device and has asked it to become usable. The second kind of power state change is initiated by the power
145 domain parent. The two are handled slightly differently.
147 There is a queue of so-called change notifications, or change notes for short. Usually the queue is empty, and when
148 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
149 at one time, a queue is implemented. Example: the subclass device decides it's idle and initiates a change to a lower
150 power state. This causes interested parties to be notified, but they don't all acknowledge right away. This causes the
151 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
152 wants to raise power back up again. This change can't be started, however, because the previous one isn't complete yet,
153 so the second one waits in the queue. During this time, the parent decides to lower or raise the power state of the entire
154 power domain and notifies the device, and that notification goes into the queue, too, and can't be actioned until the
157 This is how a power change initiated by the subclass device is handled:
158 First, all interested parties are notified of the change via their powerStateWillChangeTo method. If they all don't
159 acknowledge via return code, then we have to wait. If they do, or when they finally all acknowledge via our
160 acknowledgePowerChange method, then we can continue. We call the controlling driver, instructing it to change to
161 the new state. Then we wait for power to settle. If there is no settling-time, or after it has passed, we notify
162 interested parties again, this time via their powerStateDidChangeTo methods. When they have all acked, we're done.
163 If we lowered power and don't need the power domain to be in its current power state, we suggest to the parent that
164 it lower the power domain state.
166 This is how a change to a lower power domain state initiated by the parent is handled:
167 First, we figure out what power state we will be in when the new domain state is reached. Then all interested parties are
168 notified that we are moving to that new state. When they have acknowledged, we call the controlling driver to assume
169 that state and we wait for power to settle. Then we acknowledge our preparedness to our parent. When all its interested
170 parties have acknowledged, it lowers power and then notifies its interested parties again. When we get this call, we notify
171 our interested parties that the power state has changed, and when they have all acknowledged, we're done.
173 This is how a change to a higher power domain state initiated by the parent is handled:
174 We figure out what power state we will be in when the new domain state is reached. If it is different from our current
175 state we acknowledge the parent. When all the parent's interested parties have acknowledged, it raises power in the
176 domain and waits for power to settle. Then it notifies everyone that the new state has been reached. When we get this call,
177 we call the controlling driver, instructing it to assume the new state, and wait for power to settle. Then we notify our interested
178 parties. When they all acknowledge we are done.
180 In either of the two cases above, it is possible that we will not be changing state even though the domain is. Examples:
181 A change to a lower domain state may not affect us because we are already in a low enough state, and
182 We will not take advantage of a change to a higher domain state, because we have no need of the higher power.
183 In such a case, there is nothing to do but acknowledge the parent. So when the parent calls our powerDomainWillChange
184 method, and we decide that we will not be changing state, we merely acknowledge the parent, via return code, and wait.
185 When the parent subsequently calls powerStateDidChange, we acknowledge again via return code, and the change is complete.
187 Power state changes are processed in a state machine, and since there are four varieties of power state changes, there are
188 four major paths through the state machine:
190 The fourth is nearly trivial. In this path, the parent is changing the domain state, but we are not changing the device state.
191 The change starts when the parent calls powerDomainWillChange. All we do is acknowledge the parent.
192 When the parent calls powerStateDidChange, we acknowledge the parent again, and we're done.
194 The first is fairly simple. It starts when a power domain child calls requestPowerDomainState and we decide to change power states
195 to accomodate the child, or if our power-controlling driver calls changePowerStateTo, or if some other driver which is using our
196 device calls makeUsable, or if a subclassed object calls changePowerStateToPriv. These are all power changes initiated by us, not
197 forced upon us by the parent. We start by notifying interested parties. If they all acknowledge via return code, we can go
198 on to state "our_prechange_1". Otherwise, we start the ack timer and wait for the stragglers to acknowlege by calling
199 acknowledgePowerChange. We move on to state "our_prechange_1" when all the stragglers have acknowledged,
200 or when the ack timer expires on all those which didn't acknowledge. In "our_prechange_1" we call the power-controlling
201 driver to change the power state of the hardware. If it returns saying it has done so, we go on to state "our_prechange_2".
202 Otherwise, we have to wait for it, so we set the ack timer and wait. When it calls acknowledgeSetPowerState, or when the
203 ack timer expires, we go on. In "our_prechange_2", we look in the power state array to see if there is any settle time required
204 when changing from our current state to the new state. If not, we go right away to "our_prechange_3". Otherwise, we
205 set the settle timer and wait. When it expires, we move on. In "our_prechange_3" state, we notify all our interested parties
206 via their powerStateDidChange methods that we have finished changing power state. If they all acknowledge via return
207 code, we move on to "our_prechange_4". Otherwise we set the ack timer and wait. When they have all acknowledged, or
208 when the ack timer has expired for those that didn't, we move on to "our_prechange_4", where we remove the used
209 change note from the head of the queue and start the next one if one exists.
211 Parent-initiated changes are more complex in the state machine. First, power going up and power going down are handled
212 differently, so they have different paths throught the state machine. Second, we can acknowledge the parent's notification
213 in two different ways, so each of the parent paths is really two.
215 When the parent calls our powerDomainWillChange method, notifying us that it will lower power in the domain, we decide
216 what state that will put our device in. Then we embark on the state machine path "IOPMparent_down_1"
217 and "IOPMparent_down_2", in which we notify interested parties of the upcoming change, instruct our driver to make
218 the change, check for settle time, and notify interested parties of the completed change. If we get to the end of this path without
219 stalling due to an interested party which didn't acknowledge via return code, due to the controlling driver not able to change
220 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.
221 If we do stall in any of those states, we return IOPMWillAckLater to the parent and enter the parallel path "IOPMparent_down_4"
222 "IOPMparent_down_5", and "IOPMparent_down_3", where we continue with the same processing, except that at the end we
223 acknowledge the parent explicitly via acknowledgePowerChange, and we're done with the change.
224 Then when the parent calls us at powerStateDidChange we acknowledging via return code, because we have already made
225 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.
227 The case of the parent raising power in the domain is handled similarly in that there are parallel paths, one for no-stall
228 that ends in implicit acknowleging the parent, and one that has stalled at least once that ends in explicit acknowledging
229 the parent. This case is different, though in that our device changes state in the second half, after the parent calls
230 powerStateDidChange rather than before, as in the power-lowering case.
232 When the parent calls our powerDomainWillChange method, notifying us that it will raise power in the domain, we acknowledge
233 via return code, because there's really nothing we can do until the power is actually raised in the domain.
234 When the parent calls us at powerStateDidChange, we start by notifying our interested parties. If they all acknowledge via return code,
235 we go on to" IOPMparent_up_1" to instruct the driver to raise its power level. After that, we check for any
236 necessary settling time in "IOPMparent_up_2", and we notify all interested parties that power has changed
237 in "IOPMparent_up_3". If none of these operations stall, we acknowledge the parent via return code, release
238 the change note, and start the next, if there is one. If one of them does stall, we enter the parallel path "IOPMparent_up_0",
239 "IOPMparent_up_4", "IOPMparent_up_5", and "IOPMparent_up_6", which ends with
240 our explicit acknowledgement to the parent.
245 const char priv_key
[ ] = "Power Management private data";
246 const char prot_key
[ ] = "Power Management protected data";
249 void IOService::PMinit ( void )
251 if ( ! initialized
) {
253 pm_vars
= new IOPMprot
; // make space for our variables
258 setProperty(prot_key
, (OSObject
*) pm_vars
); // add these to the properties
259 setProperty(priv_key
, (OSObject
*) priv
);
262 pm_vars
->theNumberOfPowerStates
= 0; // then initialize them
263 priv
->we_are_root
= false;
264 pm_vars
->theControllingDriver
= NULL
;
265 priv
->our_lock
= IOLockAlloc();
266 priv
->flags_lock
= IOLockAlloc();
267 priv
->queue_lock
= IOLockAlloc();
268 pm_vars
->childLock
= IOLockAlloc();
269 pm_vars
->parentLock
= IOLockAlloc();
270 priv
->interestedDrivers
= new IOPMinformeeList
;
271 priv
->interestedDrivers
->initialize();
272 priv
->changeList
= new IOPMchangeNoteList
;
273 priv
->changeList
->initialize();
274 pm_vars
->aggressiveness
= 0;
275 for (unsigned int i
= 0; i
<= kMaxType
; i
++) {
276 pm_vars
->current_aggressiveness_values
[i
] = 0;
277 pm_vars
->current_aggressiveness_valid
[i
] = false;
279 pm_vars
->myCurrentState
= 0;
280 priv
->imminentState
= 0;
281 priv
->ourDesiredPowerState
= 0;
282 pm_vars
->parentsCurrentPowerFlags
= 0;
283 pm_vars
->maxCapability
= 0;
284 priv
->driverDesire
= 0;
285 priv
->deviceDesire
= 0;
286 priv
->initial_change
= true;
287 priv
->need_to_become_usable
= false;
288 priv
->previousRequest
= 0;
289 priv
->device_overrides
= false;
290 priv
->machine_state
= IOPMfinished
;
291 priv
->timerEventSrc
= NULL
;
292 priv
->clampTimerEventSrc
= NULL
;
293 pm_vars
->PMworkloop
= NULL
;
294 priv
->activityLock
= NULL
;
295 pm_vars
->ourName
= getName();
296 pm_vars
->thePlatform
= getPlatform();
297 pm_vars
->parentsKnowState
= false;
298 assert( pm_vars
->thePlatform
!= 0 );
299 priv
->clampOn
= false;
300 pm_vars
->serialNumber
= 0;
301 pm_vars
->responseFlags
= NULL
;
302 pm_vars
->doNotPowerDown
= true;
303 pm_vars
->PMcommandGate
= NULL
;
304 priv
->ackTimer
= thread_call_allocate((thread_call_func_t
)ack_timer_expired
, (thread_call_param_t
)this);
305 priv
->settleTimer
= thread_call_allocate((thread_call_func_t
)settle_timer_expired
, (thread_call_param_t
)this);
311 //*********************************************************************************
314 // Free up the data created in PMinit, if it exists.
315 //*********************************************************************************
316 void IOService::PMfree ( void )
319 if ( priv
->clampTimerEventSrc
!= NULL
) {
320 getPMworkloop()->removeEventSource(priv
->clampTimerEventSrc
);
321 priv
->clampTimerEventSrc
->release();
322 priv
->clampTimerEventSrc
= NULL
;
324 if ( priv
->timerEventSrc
!= NULL
) {
325 pm_vars
->PMworkloop
->removeEventSource(priv
->timerEventSrc
);
326 priv
->timerEventSrc
->release();
327 priv
->timerEventSrc
= NULL
;
329 if ( priv
->settleTimer
) {
330 thread_call_cancel(priv
->settleTimer
);
331 thread_call_free(priv
->settleTimer
);
332 priv
->settleTimer
= NULL
;
334 if ( priv
->ackTimer
) {
335 thread_call_cancel(priv
->ackTimer
);
336 thread_call_free(priv
->ackTimer
);
337 priv
->ackTimer
= NULL
;
339 if ( priv
->our_lock
) {
340 IOLockFree(priv
->our_lock
);
341 priv
->our_lock
= NULL
;
343 if ( priv
->flags_lock
) {
344 IOLockFree(priv
->flags_lock
);
345 priv
->flags_lock
= NULL
;
347 if ( priv
->activityLock
) {
348 IOLockFree(priv
->activityLock
);
349 priv
->activityLock
= NULL
;
351 priv
->interestedDrivers
->release();
352 priv
->changeList
->release();
353 priv
->release(); // remove instance variables
357 if ( pm_vars
->PMcommandGate
) {
358 pm_vars
->PMcommandGate
->release();
359 pm_vars
->PMcommandGate
= NULL
;
361 if ( pm_vars
->PMworkloop
) {
362 // The work loop object returned from getPMworkLoop() is
363 // never retained, therefore it should not be released.
364 // pm_vars->PMworkloop->release();
365 pm_vars
->PMworkloop
= NULL
;
367 if ( pm_vars
->responseFlags
) {
368 pm_vars
->responseFlags
->release();
369 pm_vars
->responseFlags
= NULL
;
371 pm_vars
->release(); // remove instance variables
376 //*********************************************************************************
379 // Disconnect the node from its parents and children in the Power Plane.
380 //*********************************************************************************
381 void IOService::PMstop ( void )
385 IOPowerConnection
* connection
;
386 IOService
* theChild
;
387 IOService
* theParent
;
389 removeProperty(prot_key
); // remove the properties
390 removeProperty(priv_key
);
392 iter
= getParentIterator(gIOPowerPlane
); // detach parents
395 while ( (next
= iter
->getNextObject()) ) {
396 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) ) {
397 theParent
= (IOService
*)connection
->copyParentEntry(gIOPowerPlane
);
399 theParent
->removePowerChild(connection
);
400 theParent
->release();
406 detachAbove( gIOPowerPlane
); // detach IOConnections
408 pm_vars
->parentsKnowState
= false; // no more power state changes
410 iter
= getChildIterator(gIOPowerPlane
); // detach children
413 while ( (next
= iter
->getNextObject()) ) {
414 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) ) {
415 theChild
= ((IOService
*)(connection
->copyChildEntry(gIOPowerPlane
)));
417 connection
->detachFromChild(theChild
,gIOPowerPlane
); // detach nub from child
420 detachFromChild(connection
,gIOPowerPlane
); // detach us from nub
426 // Remove all interested drivers from the list, including the power
427 // controlling driver.
429 // Usually, the controlling driver and the policy-maker functionality
430 // are implemented by the same object, and without the deregistration,
431 // the object will be holding an extra retain on itself, and cannot
434 if ( priv
&& priv
->interestedDrivers
)
436 IOPMinformee
* informee
;
438 while (( informee
= priv
->interestedDrivers
->firstInList() ))
439 deRegisterInterestedDriver( informee
->whatObject
);
444 //*********************************************************************************
447 // A policy-maker calls its nub here when initializing, to be attached into
448 // the power management hierarchy. The default function is to call the
449 // platform expert, which knows how to do it. This method is overridden
450 // by a nub subclass which may either know how to do it, or may need
451 // to take other action.
453 // This may be the only "power management" method used in a nub,
454 // meaning it may not be initialized for power management.
455 //*********************************************************************************
456 void IOService::joinPMtree ( IOService
* driver
)
458 IOPlatformExpert
* thePlatform
;
460 thePlatform
= getPlatform();
461 assert(thePlatform
!= 0 );
462 thePlatform
->PMRegisterDevice(this,driver
);
466 //*********************************************************************************
469 // Power Managment is informing us that we are the root power domain.
470 // The only difference between us and any other power domain is that
471 // we have no parent and therefore never call it.
472 //*********************************************************************************
473 IOReturn
IOService::youAreRoot ( void )
475 priv
-> we_are_root
= true;
476 pm_vars
->parentsKnowState
= true;
477 attachToParent( getRegistryRoot(),gIOPowerPlane
);
483 //*********************************************************************************
486 // Power Management is informing us who our parent is.
487 // If we have a controlling driver, find out, given our newly-informed
488 // power domain state, what state it would be in, and then tell it
489 // to assume that state.
490 //*********************************************************************************
491 IOReturn
IOService::setPowerParent ( IOPowerConnection
* theParent
, bool stateKnown
, IOPMPowerFlags currentState
)
495 IOPowerConnection
* connection
;
496 unsigned long tempDesire
;
498 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogSetParent
,stateKnown
,currentState
);
500 IOLockLock(pm_vars
->parentLock
);
502 if ( stateKnown
&& ((pm_vars
->PMworkloop
== NULL
) || (pm_vars
->PMcommandGate
== NULL
)) ) {
503 getPMworkloop(); // we have a path to the root
504 if ( pm_vars
->PMworkloop
!= NULL
) { // find out the workloop
505 if ( pm_vars
->PMcommandGate
== NULL
) { // and make our command gate
506 pm_vars
->PMcommandGate
= IOCommandGate::commandGate((OSObject
*)this);
507 if ( pm_vars
->PMcommandGate
!= NULL
) {
508 pm_vars
->PMworkloop
->addEventSource(pm_vars
->PMcommandGate
);
514 IOLockUnlock(pm_vars
->parentLock
);
516 theParent
->setParentCurrentPowerFlags(currentState
); // set our connection data
517 theParent
->setParentKnowsState(stateKnown
);
519 pm_vars
->parentsKnowState
= true; // combine parent knowledge
520 pm_vars
->parentsCurrentPowerFlags
= 0;
522 iter
= getParentIterator(gIOPowerPlane
);
525 while ( (next
= iter
->getNextObject()) ) {
526 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) ) {
527 pm_vars
->parentsKnowState
&= connection
->parentKnowsState();
528 pm_vars
->parentsCurrentPowerFlags
|= connection
->parentCurrentPowerFlags();
534 if ( (pm_vars
->theControllingDriver
!= NULL
) &&
535 (pm_vars
->parentsKnowState
) ) {
536 pm_vars
->maxCapability
= pm_vars
->theControllingDriver
->maxCapabilityForDomainState(pm_vars
->parentsCurrentPowerFlags
);
537 tempDesire
= priv
->deviceDesire
; // initially change into the state we are already in
538 priv
->deviceDesire
= pm_vars
->theControllingDriver
->initialPowerStateForDomainState(pm_vars
->parentsCurrentPowerFlags
);
539 computeDesiredState();
540 priv
->previousRequest
= 0xffffffff;
542 priv
->deviceDesire
= tempDesire
; // put this back like before
549 //*********************************************************************************
552 // Power Management is informing us who our children are.
553 //*********************************************************************************
554 IOReturn
IOService::addPowerChild ( IOService
* theChild
)
556 IOPowerConnection
* connection
;
559 if ( ! initialized
) {
560 return IOPMNotYetInitialized
; // we're not a power-managed IOService
563 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogAddChild
,0,0);
565 connection
= new IOPowerConnection
; // make a nub
568 connection
->start(this);
569 connection
->setAwaitingAck(false);
571 attachToChild( connection
,gIOPowerPlane
); // connect it up
572 connection
->attachToChild( theChild
,gIOPowerPlane
);
573 connection
->release();
575 if ( (pm_vars
->theControllingDriver
== NULL
) || // tell it the current state of the power domain
576 ! (inPlane(gIOPowerPlane
)) ||
577 ! (pm_vars
->parentsKnowState
) ) {
578 theChild
->setPowerParent(connection
,false,0);
579 if ( inPlane(gIOPowerPlane
) ) {
580 for (i
= 0; i
<= kMaxType
; i
++) {
581 if ( pm_vars
->current_aggressiveness_valid
[i
] ) {
582 theChild
->setAggressiveness (i
, pm_vars
->current_aggressiveness_values
[i
]);
588 theChild
->setPowerParent(connection
,true,pm_vars
->thePowerStates
[pm_vars
->myCurrentState
].outputPowerCharacter
);
589 for (i
= 0; i
<= kMaxType
; i
++) {
590 if ( pm_vars
->current_aggressiveness_valid
[i
] ) {
591 theChild
->setAggressiveness (i
, pm_vars
->current_aggressiveness_values
[i
]);
594 add_child_to_active_change(connection
); // catch it up if change is in progress
601 //*********************************************************************************
604 //*********************************************************************************
605 IOReturn
IOService::removePowerChild ( IOPowerConnection
* theNub
)
607 IORegistryEntry
* theChild
;
609 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogRemoveChild
,0,0);
613 theChild
= theNub
->copyChildEntry(gIOPowerPlane
); // detach nub from child
615 theNub
->detachFromChild(theChild
, gIOPowerPlane
);
618 detachFromChild(theNub
,gIOPowerPlane
); // detach from the nub
620 if ( theNub
->getAwaitingAck() ) { // are we awaiting an ack from this child?
621 theNub
->setAwaitingAck(false); // yes, pretend we got one
622 if ( acquire_lock() ) {
623 if (priv
->head_note_pendingAcks
!= 0 ) {
624 priv
->head_note_pendingAcks
-= 1; // that's one fewer ack to worry about
625 if ( priv
->head_note_pendingAcks
== 0 ) { // is that the last?
626 stop_ack_timer(); // yes, stop the timer
627 IOUnlock(priv
->our_lock
);
628 all_acked(); // and now we can continue our power change
631 IOUnlock(priv
->our_lock
);
635 IOUnlock(priv
->our_lock
);
642 if ( (pm_vars
->theControllingDriver
== NULL
) || // if not fully initialized
643 ! (inPlane(gIOPowerPlane
)) ||
644 ! (pm_vars
->parentsKnowState
) ) {
645 return IOPMNoErr
; // we can do no more
648 // Perhaps the departing child was holding up idle or system sleep - we need to re-evaluate our
649 // childrens' requests. Clear and re-calculate our kIOPMChildClamp and kIOPMChildClamp2 bits.
650 rebuildChildClampBits();
652 computeDesiredState(); // this may be different now
653 changeState(); // change state if we can now tolerate lower power
659 //*********************************************************************************
660 // registerPowerDriver
662 // A driver has called us volunteering to control power to our device.
663 // If the power state array it provides is richer than the one we already
664 // know about (supplied by an earlier volunteer), then accept the offer.
665 // Notify all interested parties of our power state, which we now know.
666 //*********************************************************************************
668 IOReturn
IOService::registerPowerDriver ( IOService
* controllingDriver
, IOPMPowerState
* powerStates
, unsigned long numberOfStates
)
671 unsigned long tempDesire
;
673 if ( (numberOfStates
> pm_vars
->theNumberOfPowerStates
) && (numberOfStates
> 1) ) {
674 if ( priv
->changeList
->currentChange() == -1 ) {
675 if ( controllingDriver
!= NULL
) {
676 if ( numberOfStates
<= IOPMMaxPowerStates
) {
677 switch ( powerStates
[0].version
) {
679 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogControllingDriver
,
680 (unsigned long)numberOfStates
, (unsigned long)powerStates
[0].version
);
681 for ( i
= 0; i
< numberOfStates
; i
++ ) {
682 pm_vars
->thePowerStates
[i
] = powerStates
[i
];
686 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogControllingDriver
,
687 (unsigned long) numberOfStates
,(unsigned long) powerStates
[0].version
);
688 for ( i
= 0; i
< numberOfStates
; i
++ ) {
689 pm_vars
->thePowerStates
[i
].version
= powerStates
[i
].version
;
690 pm_vars
->thePowerStates
[i
].capabilityFlags
= powerStates
[i
].capabilityFlags
;
691 pm_vars
->thePowerStates
[i
].outputPowerCharacter
= powerStates
[i
].outputPowerCharacter
;
692 pm_vars
->thePowerStates
[i
].inputPowerRequirement
= powerStates
[i
].inputPowerRequirement
;
693 pm_vars
->thePowerStates
[i
].staticPower
= powerStates
[i
].staticPower
;
694 pm_vars
->thePowerStates
[i
].unbudgetedPower
= powerStates
[i
].unbudgetedPower
;
695 pm_vars
->thePowerStates
[i
].powerToAttain
= powerStates
[i
].powerToAttain
;
696 pm_vars
->thePowerStates
[i
].timeToAttain
= powerStates
[i
].timeToAttain
;
697 pm_vars
->thePowerStates
[i
].settleUpTime
= powerStates
[i
].settleUpTime
;
698 pm_vars
->thePowerStates
[i
].timeToLower
= powerStates
[i
].timeToLower
;
699 pm_vars
->thePowerStates
[i
].settleDownTime
= powerStates
[i
].settleDownTime
;
700 pm_vars
->thePowerStates
[i
].powerDomainBudget
= powerStates
[i
].powerDomainBudget
;
704 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogControllingDriverErr1
,
705 (unsigned long)powerStates
[0].version
,0);
709 pm_vars
->myCharacterFlags
= 0; // make a mask of all the character bits we know about
710 for ( i
= 0; i
< numberOfStates
; i
++ ) {
711 pm_vars
->myCharacterFlags
|= pm_vars
->thePowerStates
[i
].outputPowerCharacter
;
714 pm_vars
->theNumberOfPowerStates
= numberOfStates
;
715 pm_vars
->theControllingDriver
= controllingDriver
;
716 if ( priv
->interestedDrivers
->findItem(controllingDriver
) == NULL
) { // register it as interested
717 registerInterestedDriver (controllingDriver
); // unless already done
719 if ( priv
->need_to_become_usable
) {
720 priv
->need_to_become_usable
= false;
721 priv
->deviceDesire
= pm_vars
->theNumberOfPowerStates
- 1;
724 if ( inPlane(gIOPowerPlane
) &&
725 (pm_vars
->parentsKnowState
) ) {
726 pm_vars
->maxCapability
= pm_vars
->theControllingDriver
->maxCapabilityForDomainState(pm_vars
->parentsCurrentPowerFlags
);
727 tempDesire
= priv
->deviceDesire
; // initially change into the state we are already in
728 priv
->deviceDesire
= pm_vars
->theControllingDriver
->initialPowerStateForDomainState(pm_vars
->parentsCurrentPowerFlags
);
729 computeDesiredState();
731 priv
->deviceDesire
= tempDesire
; // put this back like before
735 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogControllingDriverErr2
,(unsigned long)numberOfStates
,0);
739 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogControllingDriverErr4
,0,0);
744 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogControllingDriverErr5
,(unsigned long)numberOfStates
,0);
749 //*********************************************************************************
750 // registerInterestedDriver
752 // Add the caller to our list of interested drivers and return our current
753 // power state. If we don't have a power-controlling driver yet, we will
754 // call this interested driver again later when we do get a driver and find
755 // out what the current power state of the device is.
756 //*********************************************************************************
758 IOPMPowerFlags
IOService::registerInterestedDriver ( IOService
* theDriver
)
760 IOPMinformee
* newInformee
;
761 IOPMPowerFlags futureCapability
;
763 if (theDriver
== NULL
) {
767 newInformee
= new IOPMinformee
; // make new driver node
768 newInformee
->initialize(theDriver
);
769 priv
->interestedDrivers
->addToList(newInformee
); // add it to list of drivers
771 if ( (pm_vars
->theControllingDriver
== NULL
) ||
772 ! (inPlane(gIOPowerPlane
)) ||
773 ! (pm_vars
->parentsKnowState
) ) {
774 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogInterestedDriver
,IOPMNotPowerManaged
,0);
775 return IOPMNotPowerManaged
; // can't tell it a state yet
778 switch (priv
->machine_state
) { // can we notify new driver of a change in progress?
779 case IOPMour_prechange_1
:
780 case IOPMour_prechange_4
:
781 case IOPMparent_down_4
:
782 case IOPMparent_down_6
:
783 case IOPMparent_up_0
:
784 case IOPMparent_up_6
:
785 futureCapability
= priv
->head_note_capabilityFlags
; // yes, remember what we tell it
786 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogInterestedDriver
,(unsigned long)futureCapability
,1);
787 add_driver_to_active_change(newInformee
); // notify it
788 return futureCapability
; // and return the same thing
791 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogInterestedDriver
,
792 (unsigned long) pm_vars
->thePowerStates
[pm_vars
->myCurrentState
].capabilityFlags
,2);
793 return pm_vars
->thePowerStates
[pm_vars
->myCurrentState
].capabilityFlags
; // no, return current capability
797 //*********************************************************************************
798 // deRegisterInterestedDriver
800 //*********************************************************************************
801 IOReturn
IOService::deRegisterInterestedDriver ( IOService
* theDriver
)
803 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogRemoveDriver
,0,0);
805 priv
->interestedDrivers
->removeFromList(theDriver
); // remove the departing driver
811 //*********************************************************************************
812 // acknowledgePowerChange
814 // After we notified one of the interested drivers or a power-domain child
815 // of an impending change in power, it has called to say it is now
816 // prepared for the change. If this object is the last to
817 // acknowledge this change, we take whatever action we have been waiting
819 // That may include acknowledging to our parent. In this case, we do it
820 // last of all to insure that this doesn't cause the parent to call us some-
821 // where else and alter data we are relying on here (like the very existance
822 // of a "current change note".)
823 //*********************************************************************************
825 IOReturn
IOService::acknowledgePowerChange ( IOService
* whichObject
)
827 IOPMinformee
* ackingObject
;
828 unsigned long childPower
= kIOPMUnknown
;
829 IOService
* theChild
;
831 ackingObject
= priv
->interestedDrivers
->findItem(whichObject
); // one of our interested drivers?
832 if ( ackingObject
== NULL
) {
833 if ( ! isChild(whichObject
,gIOPowerPlane
) ) {
834 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogAcknowledgeErr1
,0,0);
835 kprintf("errant driver: %s\n",whichObject
->getName());
836 return IOPMNoErr
; // no, just return
839 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogChildAcknowledge
,priv
->head_note_pendingAcks
,0);
843 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogDriverAcknowledge
,priv
->head_note_pendingAcks
,0);
846 if (! acquire_lock() ) {
850 if (priv
->head_note_pendingAcks
!= 0 ) { // yes, make sure we're expecting acks
851 if ( ackingObject
!= NULL
) { // it's an interested driver
852 if ( ackingObject
->timer
!= 0 ) { // make sure we're expecting this ack
853 ackingObject
->timer
= 0; // mark it acked
854 priv
->head_note_pendingAcks
-= 1; // that's one fewer to worry about
855 if ( priv
->head_note_pendingAcks
== 0 ) { // is that the last?
856 stop_ack_timer(); // yes, stop the timer
857 IOUnlock(priv
->our_lock
);
858 all_acked(); // and now we can continue
863 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogAcknowledgeErr2
,0,0); // this driver has already acked
864 kprintf("errant driver: %s\n",whichObject
->getName());
867 else { // it's a child
868 if ( ((IOPowerConnection
*)whichObject
)->getAwaitingAck() ) { // make sure we're expecting this ack
869 priv
->head_note_pendingAcks
-= 1; // that's one fewer to worry about
870 ((IOPowerConnection
*)whichObject
)->setAwaitingAck(false);
871 theChild
= (IOService
*)whichObject
->copyChildEntry(gIOPowerPlane
);
873 childPower
= theChild
->currentPowerConsumption();
876 if ( childPower
== kIOPMUnknown
) {
877 pm_vars
->thePowerStates
[priv
->head_note_state
].staticPower
= kIOPMUnknown
;
880 if ( pm_vars
->thePowerStates
[priv
->head_note_state
].staticPower
!= kIOPMUnknown
) {
881 pm_vars
->thePowerStates
[priv
->head_note_state
].staticPower
+= childPower
;
884 if ( priv
->head_note_pendingAcks
== 0 ) { // is that the last?
885 stop_ack_timer(); // yes, stop the timer
886 IOUnlock(priv
->our_lock
);
887 all_acked(); // and now we can continue
894 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogAcknowledgeErr3
,0,0); // not expecting anybody to ack
895 kprintf("errant driver: %s\n",whichObject
->getName());
897 IOUnlock(priv
->our_lock
);
901 //*********************************************************************************
902 // acknowledgeSetPowerState
904 // After we instructed our controlling driver to change power states,
905 // it has called to say it has finished doing so.
906 // We continue to process the power state change.
907 //*********************************************************************************
909 IOReturn
IOService::acknowledgeSetPowerState ( void )
911 if (! acquire_lock() ) {
915 ioSPMTrace(IOPOWER_ACK
, * (int *) this);
917 if ( priv
->driver_timer
== -1 ) {
918 priv
->driver_timer
= 0; // driver is acking instead of using return code
921 if ( priv
->driver_timer
> 0 ) { // are we expecting this?
922 stop_ack_timer(); // yes, stop the timer
923 priv
->driver_timer
= 0;
924 IOUnlock(priv
->our_lock
);
925 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogDriverAcknowledgeSet
,0,0);
930 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogAcknowledgeErr4
,0,0); // no
933 IOUnlock(priv
->our_lock
);
938 //*********************************************************************************
941 // Either the controlling driver has called acknowledgeSetPowerState
942 // or the acknowledgement timer has expired while waiting for that.
943 // We carry on processing the current change note.
944 //*********************************************************************************
946 void IOService::driver_acked ( void )
948 switch (priv
->machine_state
) {
949 case IOPMour_prechange_2
:
952 case IOPMparent_down_5
:
955 case IOPMparent_up_4
:
962 //*********************************************************************************
963 // powerDomainWillChangeTo
965 // Called by the power-hierarchy parent notifying of a new power state
966 // in the power domain.
967 // We enqueue a parent power-change to our queue of power changes.
968 // This may or may not cause us to change power, depending on what
969 // kind of change is occuring in the domain.
970 //*********************************************************************************
972 IOReturn
IOService::powerDomainWillChangeTo ( IOPMPowerFlags newPowerStateFlags
, IOPowerConnection
* whichParent
)
976 IOPowerConnection
* connection
;
977 unsigned long newStateNumber
;
978 IOPMPowerFlags combinedPowerFlags
;
980 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogWillChange
,(unsigned long)newPowerStateFlags
,0);
982 if ( ! inPlane(gIOPowerPlane
) ) {
983 return IOPMAckImplied
; // somebody goofed
986 IOLockLock(pm_vars
->parentLock
);
988 if ( (pm_vars
->PMworkloop
== NULL
) || (pm_vars
->PMcommandGate
== NULL
) ) {
989 getPMworkloop(); // we have a path to the root,
990 if ( pm_vars
->PMworkloop
!= NULL
) { // so find out the workloop
991 if ( pm_vars
->PMcommandGate
== NULL
) { // and make our command gate
992 pm_vars
->PMcommandGate
= IOCommandGate::commandGate((OSObject
*)this);
993 if ( pm_vars
->PMcommandGate
!= NULL
) {
994 pm_vars
->PMworkloop
->addEventSource(pm_vars
->PMcommandGate
);
1000 IOLockUnlock(pm_vars
->parentLock
);
1002 combinedPowerFlags
= 0; // combine parents' power states
1004 iter
= getParentIterator(gIOPowerPlane
);
1007 while ( (next
= iter
->getNextObject()) ) {
1008 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) ) {
1009 if ( connection
== whichParent
){
1010 combinedPowerFlags
|= newPowerStateFlags
;
1013 combinedPowerFlags
|= connection
->parentCurrentPowerFlags();
1020 if ( pm_vars
->theControllingDriver
== NULL
) { // we can't take any more action
1021 return IOPMAckImplied
;
1023 newStateNumber
= pm_vars
->theControllingDriver
->maxCapabilityForDomainState(combinedPowerFlags
);
1024 return enqueuePowerChange(IOPMParentInitiated
| IOPMDomainWillChange
,
1025 newStateNumber
,combinedPowerFlags
,whichParent
,newPowerStateFlags
); //make the change
1029 //*********************************************************************************
1030 // powerDomainDidChangeTo
1032 // Called by the power-hierarchy parent after the power state of the power domain
1033 // has settled at a new level.
1034 // We enqueue a parent power-change to our queue of power changes.
1035 // This may or may not cause us to change power, depending on what
1036 // kind of change is occuring in the domain.
1037 //*********************************************************************************
1039 IOReturn
IOService::powerDomainDidChangeTo ( IOPMPowerFlags newPowerStateFlags
, IOPowerConnection
* whichParent
)
1041 unsigned long newStateNumber
;
1043 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogDidChange
,newPowerStateFlags
,0);
1045 setParentInfo(newPowerStateFlags
,whichParent
);
1047 if ( pm_vars
->theControllingDriver
== NULL
) {
1048 return IOPMAckImplied
;
1051 newStateNumber
= pm_vars
->theControllingDriver
->maxCapabilityForDomainState(pm_vars
->parentsCurrentPowerFlags
);
1052 return enqueuePowerChange(IOPMParentInitiated
| IOPMDomainDidChange
,
1053 newStateNumber
,pm_vars
->parentsCurrentPowerFlags
,whichParent
,0); // tell interested parties about it
1057 //*********************************************************************************
1060 // Set our connection data for one specific parent, and then combine all the parent
1062 //*********************************************************************************
1064 void IOService::setParentInfo ( IOPMPowerFlags newPowerStateFlags
, IOPowerConnection
* whichParent
)
1068 IOPowerConnection
* connection
;
1070 whichParent
->setParentCurrentPowerFlags(newPowerStateFlags
); // set our connection data
1071 whichParent
->setParentKnowsState(true);
1073 IOLockLock(pm_vars
->parentLock
);
1075 pm_vars
->parentsCurrentPowerFlags
= 0; // recompute our parent info
1076 pm_vars
->parentsKnowState
= true;
1078 iter
= getParentIterator(gIOPowerPlane
);
1081 while ( (next
= iter
->getNextObject()) ) {
1082 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) ) {
1083 pm_vars
->parentsKnowState
&= connection
->parentKnowsState();
1084 pm_vars
->parentsCurrentPowerFlags
|= connection
->parentCurrentPowerFlags();
1089 IOLockUnlock(pm_vars
->parentLock
);
1092 //*********************************************************************************
1093 // rebuildChildClampBits
1095 // The ChildClamp bits (kIOPMChildClamp & kIOPMChildClamp2) in our capabilityFlags
1096 // indicate that one of our children (or grandchildren or great-grandchildren or ...)
1097 // doesn't support idle or system sleep in its current state. Since we don't track the
1098 // origin of each bit, every time any child changes state we have to clear these bits
1099 // and rebuild them.
1100 //*********************************************************************************
1102 void IOService::rebuildChildClampBits(void)
1107 IOPowerConnection
* connection
;
1110 // A child's desires has changed. We need to rebuild the child-clamp bits in our
1111 // power state array. Start by clearing the bits in each power state.
1113 for ( i
= 0; i
< pm_vars
->theNumberOfPowerStates
; i
++ ) {
1114 pm_vars
->thePowerStates
[i
].capabilityFlags
&= ~(kIOPMChildClamp
| kIOPMChildClamp2
);
1117 // Now loop through the children. When we encounter the calling child, save
1118 // the computed state as this child's desire. And while we're at it, set the ChildClamp bits
1119 // in any of our states that some child has requested with clamp on.
1121 iter
= getChildIterator(gIOPowerPlane
);
1125 while ( (next
= iter
->getNextObject()) )
1127 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) )
1129 if ( connection
->getPreventIdleSleepFlag() )
1130 pm_vars
->thePowerStates
[connection
->getDesiredDomainState()].capabilityFlags
|= kIOPMChildClamp
;
1131 if ( connection
->getPreventSystemSleepFlag() )
1132 pm_vars
->thePowerStates
[connection
->getDesiredDomainState()].capabilityFlags
|= kIOPMChildClamp2
;
1141 //*********************************************************************************
1142 // requestPowerDomainState
1144 // The kIOPMPreventIdleSleep and/or kIOPMPreventIdleSleep bits may be be set in the parameter.
1145 // It is not considered part of the state specification.
1146 //*********************************************************************************
1147 IOReturn
IOService::requestPowerDomainState ( IOPMPowerFlags desiredState
, IOPowerConnection
* whichChild
, unsigned long specification
)
1150 unsigned long computedState
;
1151 unsigned long theDesiredState
= desiredState
& ~(kIOPMPreventIdleSleep
| kIOPMPreventSystemSleep
);
1154 IOPowerConnection
* connection
;
1156 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogRequestDomain
,
1157 (unsigned long)desiredState
,(unsigned long)specification
);
1159 if ( pm_vars
->theControllingDriver
== NULL
) {
1160 return IOPMNotYetInitialized
;
1163 switch (specification
) {
1164 case IOPMLowestState
:
1166 while ( i
< pm_vars
->theNumberOfPowerStates
) {
1167 if ( ( pm_vars
->thePowerStates
[i
].outputPowerCharacter
& theDesiredState
) == (theDesiredState
& pm_vars
->myCharacterFlags
) ) {
1172 if ( i
>= pm_vars
->theNumberOfPowerStates
) {
1173 return IOPMNoSuchState
;
1177 case IOPMNextLowerState
:
1178 i
= pm_vars
->myCurrentState
- 1;
1180 if ( ( pm_vars
->thePowerStates
[i
].outputPowerCharacter
& theDesiredState
) == (theDesiredState
& pm_vars
->myCharacterFlags
) ) {
1186 return IOPMNoSuchState
;
1190 case IOPMHighestState
:
1191 i
= pm_vars
->theNumberOfPowerStates
;
1194 if ( ( pm_vars
->thePowerStates
[i
].outputPowerCharacter
& theDesiredState
) == (theDesiredState
& pm_vars
->myCharacterFlags
) ) {
1199 return IOPMNoSuchState
;
1203 case IOPMNextHigherState
:
1204 i
= pm_vars
->myCurrentState
+ 1;
1205 while ( i
< pm_vars
->theNumberOfPowerStates
) {
1206 if ( ( pm_vars
->thePowerStates
[i
].outputPowerCharacter
& theDesiredState
) == (theDesiredState
& pm_vars
->myCharacterFlags
) ) {
1211 if ( i
== pm_vars
->theNumberOfPowerStates
) {
1212 return IOPMNoSuchState
;
1217 return IOPMBadSpecification
;
1222 IOLockLock(pm_vars
->childLock
);
1224 // Now loop through the children. When we encounter the calling child, save
1225 // the computed state as this child's desire.
1226 iter
= getChildIterator(gIOPowerPlane
);
1229 while ( (next
= iter
->getNextObject()) ) {
1230 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) ) {
1231 if ( connection
== whichChild
) {
1232 connection
->setDesiredDomainState(computedState
);
1233 connection
->setPreventIdleSleepFlag(desiredState
& kIOPMPreventIdleSleep
);
1234 connection
->setPreventSystemSleepFlag(desiredState
& kIOPMPreventSystemSleep
);
1235 connection
->setChildHasRequestedPower();
1242 // Since a child's power requirements may have changed, clear and rebuild
1243 // kIOPMChildClamp and kIOPMChildClamp2 (idle and system sleep clamps)
1244 rebuildChildClampBits();
1246 IOLockUnlock(pm_vars
->childLock
);
1248 computeDesiredState(); // this may be different now
1250 if ( inPlane(gIOPowerPlane
) &&
1251 (pm_vars
->parentsKnowState
) ) {
1252 changeState(); // change state if all children can now tolerate lower power
1255 if ( priv
->clampOn
) { // are we clamped on, waiting for this child?
1256 priv
->clampOn
= false; // yes, remove the clamp
1257 changePowerStateToPriv(0);
1264 //*********************************************************************************
1265 // temporaryPowerClampOn
1267 // A power domain wants to clamp its power on till it has children which
1268 // will thendetermine the power domain state.
1270 // We enter the highest state until addPowerChild is called.
1271 //*********************************************************************************
1273 IOReturn
IOService::temporaryPowerClampOn ( void )
1275 priv
->clampOn
= true;
1281 //*********************************************************************************
1284 // Some client of our device is asking that we become usable. Although
1285 // this has not come from a subclassed device object, treat it exactly
1286 // as if it had. In this way, subsequent requests for lower power from
1287 // a subclassed device object will pre-empt this request.
1289 // We treat this as a subclass object request to switch to the
1290 // highest power state.
1291 //*********************************************************************************
1293 IOReturn
IOService::makeUsable ( void )
1295 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogMakeUsable
,0,0);
1297 if ( pm_vars
->theControllingDriver
== NULL
) {
1298 priv
->need_to_become_usable
= true;
1301 priv
->deviceDesire
= pm_vars
->theNumberOfPowerStates
- 1;
1302 computeDesiredState();
1303 if ( inPlane(gIOPowerPlane
) && (pm_vars
->parentsKnowState
) ) {
1304 return changeState();
1310 //*********************************************************************************
1311 // currentCapability
1313 //*********************************************************************************
1315 IOPMPowerFlags
IOService::currentCapability ( void )
1317 if ( pm_vars
->theControllingDriver
== NULL
) {
1321 return pm_vars
->thePowerStates
[pm_vars
->myCurrentState
].capabilityFlags
;
1326 //*********************************************************************************
1327 // changePowerStateTo
1329 // For some reason, our power-controlling driver has decided it needs to change
1330 // power state. We enqueue the power change so that appropriate parties
1331 // will be notified, and then we will instruct the driver to make the change.
1332 //*********************************************************************************
1334 IOReturn
IOService::changePowerStateTo ( unsigned long ordinal
)
1336 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogChangeStateTo
,ordinal
,0);
1338 if ( ordinal
>= pm_vars
->theNumberOfPowerStates
) {
1339 return IOPMParameterError
;
1341 priv
->driverDesire
= ordinal
;
1342 computeDesiredState();
1343 if ( inPlane(gIOPowerPlane
) && (pm_vars
->parentsKnowState
) ) {
1344 return changeState();
1350 //*********************************************************************************
1351 // changePowerStateToPriv
1353 // For some reason, a subclassed device object has decided it needs to change
1354 // power state. We enqueue the power change so that appropriate parties
1355 // will be notified, and then we will instruct the driver to make the change.
1356 //*********************************************************************************
1358 IOReturn
IOService::changePowerStateToPriv ( unsigned long ordinal
)
1360 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogChangeStateToPriv
,ordinal
,0);
1362 if ( pm_vars
->theControllingDriver
== NULL
) {
1363 return IOPMNotYetInitialized
;
1365 if ( ordinal
>= pm_vars
->theNumberOfPowerStates
) {
1366 return IOPMParameterError
;
1368 priv
->deviceDesire
= ordinal
;
1369 computeDesiredState();
1370 if ( inPlane(gIOPowerPlane
) && (pm_vars
->parentsKnowState
) ) {
1371 return changeState();
1378 //*********************************************************************************
1379 // computeDesiredState
1381 //*********************************************************************************
1383 void IOService::computeDesiredState ( void )
1387 IOPowerConnection
* connection
;
1388 unsigned long newDesiredState
= 0;
1390 // Compute the maximum of our children's desires, our controlling driver's desire, and the subclass device's desire.
1392 if ( ! priv
->device_overrides
) {
1393 iter
= getChildIterator(gIOPowerPlane
);
1396 while ( (next
= iter
->getNextObject()) ) {
1397 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) ) {
1398 if ( connection
->getDesiredDomainState() > newDesiredState
) {
1399 newDesiredState
= connection
->getDesiredDomainState();
1406 if ( priv
->driverDesire
> newDesiredState
) {
1407 newDesiredState
= priv
->driverDesire
;
1411 if ( priv
->deviceDesire
> newDesiredState
) {
1412 newDesiredState
= priv
->deviceDesire
;
1415 priv
->ourDesiredPowerState
= newDesiredState
;
1419 //*********************************************************************************
1422 // A subclass object, our controlling driver, or a power domain child
1423 // has asked for a different power state. Here we compute what new
1424 // state we should enter and enqueue the change (or start it).
1425 //*********************************************************************************
1427 IOReturn
IOService::changeState ( void )
1429 if ( (pm_vars
->theControllingDriver
== NULL
) || // if not fully initialized
1430 ! (inPlane(gIOPowerPlane
)) ||
1431 ! (pm_vars
->parentsKnowState
) ) {
1432 return IOPMNoErr
; // we can do no more
1435 return enqueuePowerChange(IOPMWeInitiated
,priv
->ourDesiredPowerState
,0,0,0);
1439 //*********************************************************************************
1440 // currentPowerConsumption
1442 //*********************************************************************************
1444 unsigned long IOService::currentPowerConsumption ( void )
1446 if ( pm_vars
->theControllingDriver
== NULL
) {
1447 return kIOPMUnknown
;
1449 if ( pm_vars
->thePowerStates
[pm_vars
->myCurrentState
].capabilityFlags
& kIOPMStaticPowerValid
) {
1450 return pm_vars
->thePowerStates
[pm_vars
->myCurrentState
].staticPower
;
1452 return kIOPMUnknown
;
1455 //*********************************************************************************
1458 // The activity tickle with parameter kIOPMSubclassPolicyis not handled
1459 // here and should have been intercepted by the subclass.
1460 // The tickle with parameter kIOPMSuperclassPolicy1 causes the activity
1461 // flag to be set, and the device state checked. If the device has been
1462 // powered down, it is powered up again.
1463 //*********************************************************************************
1465 bool IOService::activityTickle ( unsigned long type
, unsigned long stateNumber
=0 )
1467 AbsoluteTime uptime
;
1469 if ( type
== kIOPMSuperclassPolicy1
) {
1470 if ( (priv
->activityLock
== NULL
) ||
1471 (pm_vars
->theControllingDriver
== NULL
) ) {
1474 IOTakeLock(priv
->activityLock
);
1475 priv
->device_active
= true;
1477 clock_get_uptime(&uptime
);
1478 priv
->device_active_timestamp
= uptime
;
1480 if ( pm_vars
->myCurrentState
>= stateNumber
) {
1481 IOUnlock(priv
->activityLock
);
1484 IOUnlock(priv
->activityLock
);
1485 pm_vars
->PMcommandGate
->runAction(unIdleDevice
,(void *)stateNumber
);
1491 //*********************************************************************************
1494 // A child is calling to get a pointer to the Power Management workloop.
1495 // We got it or get it from one of our parents.
1496 //*********************************************************************************
1498 IOWorkLoop
* IOService::getPMworkloop ( void )
1503 if ( ! inPlane(gIOPowerPlane
) ) {
1506 if ( pm_vars
->PMworkloop
== NULL
) { // we have no workloop yet
1507 nub
= (IOService
*)copyParentEntry(gIOPowerPlane
);
1509 parent
= (IOService
*)nub
->copyParentEntry(gIOPowerPlane
);
1511 if ( parent
) { // ask one of our parents for the workloop
1512 pm_vars
->PMworkloop
= parent
->getPMworkloop();
1517 return pm_vars
->PMworkloop
;
1521 //*********************************************************************************
1522 // setIdleTimerPeriod
1524 // A subclass policy-maker is going to use our standard idleness
1525 // detection service. Make a command queue and an idle timer and
1526 // connect them to the power management workloop. Finally,
1528 //*********************************************************************************
1530 IOReturn
IOService::setIdleTimerPeriod ( unsigned long period
)
1532 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMsetIdleTimerPeriod
,period
, 0);
1534 priv
->idle_timer_period
= period
;
1537 if ( getPMworkloop() == NULL
) {
1538 return kIOReturnError
;
1540 // make the timer event
1541 if ( priv
->timerEventSrc
== NULL
) {
1542 priv
->timerEventSrc
= IOTimerEventSource::timerEventSource(this,
1543 PM_idle_timer_expired
);
1544 if ( ! priv
->timerEventSrc
||
1545 ( pm_vars
->PMworkloop
->addEventSource( priv
->timerEventSrc
) != kIOReturnSuccess
) ) {
1546 return kIOReturnError
;
1550 if ( priv
->activityLock
== NULL
) {
1551 priv
->activityLock
= IOLockAlloc();
1554 start_PM_idle_timer();
1560 //*********************************************************************************
1561 // start_PM_idle_timer
1563 // The parameter is a pointer to us. Use it to call our timeout method.
1564 //*********************************************************************************
1565 void IOService::start_PM_idle_timer ( void )
1567 AbsoluteTime uptime
;
1573 IOLockLock(priv
->activityLock
);
1575 clock_get_uptime(&uptime
);
1577 /* Calculate time difference using funky macro from clock.h.
1580 SUB_ABSOLUTETIME(&delta
, &(priv
->device_active_timestamp
));
1582 /* Figure it in seconds.
1584 absolutetime_to_nanoseconds(delta
, &delta_ns
);
1585 delta_secs
= delta_ns
/ NSEC_PER_SEC
;
1587 /* Be paranoid about delta somehow exceeding timer period.
1589 if (delta_secs
< priv
->idle_timer_period
) {
1590 delay_secs
= priv
->idle_timer_period
- delta_secs
;
1592 delay_secs
= priv
->idle_timer_period
;
1595 priv
->timerEventSrc
->setTimeout(delay_secs
, NSEC_PER_SEC
);
1597 IOLockUnlock(priv
->activityLock
);
1602 //*********************************************************************************
1603 // PM_idle_timer_expired
1605 // The parameter is a pointer to us. Use it to call our timeout method.
1606 //*********************************************************************************
1608 void PM_idle_timer_expired(OSObject
* ourSelves
, IOTimerEventSource
*)
1610 ((IOService
*)ourSelves
)->PM_idle_timer_expiration();
1614 //*********************************************************************************
1615 // PM_idle_timer_expiration
1617 // The idle timer has expired. If there has been activity since the last
1618 // expiration, just restart the timer and return. If there has not been
1619 // activity, switch to the next lower power state and restart the timer.
1620 //*********************************************************************************
1622 void IOService::PM_idle_timer_expiration ( void )
1624 if ( ! initialized
) {
1625 return; // we're unloading
1628 if ( priv
->idle_timer_period
> 0 ) {
1629 IOTakeLock(priv
->activityLock
);
1630 if ( priv
->device_active
) {
1631 priv
->device_active
= false;
1632 IOUnlock(priv
->activityLock
);
1633 start_PM_idle_timer();
1636 if ( pm_vars
->myCurrentState
> 0 ) {
1637 IOUnlock(priv
->activityLock
);
1638 changePowerStateToPriv(pm_vars
->myCurrentState
- 1);
1639 start_PM_idle_timer();
1642 IOUnlock(priv
->activityLock
);
1643 start_PM_idle_timer();
1649 // **********************************************************************************
1652 // We are behind the command gate. This serializes with respect to timer expiration.
1653 // **********************************************************************************
1654 IOReturn
unIdleDevice ( OSObject
* theDriver
, void * param1
, void * param2
, void * param3
, void * param4
)
1656 ((IOService
*)theDriver
)->command_received(param1
,param2
,param3
,param4
);
1657 return kIOReturnSuccess
;
1661 // **********************************************************************************
1664 // We are un-idling a device due to its activity tickle.
1665 // **********************************************************************************
1666 void IOService::command_received ( void * stateNumber
, void *, void * , void * )
1668 if ( ! initialized
) {
1669 return; // we're unloading
1672 if ( (pm_vars
->myCurrentState
< (unsigned long)stateNumber
) &&
1673 (priv
->imminentState
< (unsigned long)stateNumber
) ) {
1674 changePowerStateToPriv((unsigned long)stateNumber
);
1679 //*********************************************************************************
1680 // setAggressiveness
1682 // Pass on the input parameters to all power domain children. All those which are
1683 // power domains will pass it on to their children, etc.
1684 //*********************************************************************************
1686 IOReturn
IOService::setAggressiveness ( unsigned long type
, unsigned long newLevel
)
1690 IOPowerConnection
* connection
;
1693 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogSetAggressiveness
,type
, newLevel
);
1695 if ( type
<= kMaxType
) {
1696 pm_vars
->current_aggressiveness_values
[type
] = newLevel
;
1697 pm_vars
->current_aggressiveness_valid
[type
] = true;
1700 iter
= getChildIterator(gIOPowerPlane
);
1703 while ( (next
= iter
->getNextObject()) ) {
1704 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) ) {
1705 child
= ((IOService
*)(connection
->copyChildEntry(gIOPowerPlane
)));
1707 child
->setAggressiveness(type
, newLevel
);
1718 //*********************************************************************************
1719 // getAggressiveness
1721 // Called by the user client.
1722 //*********************************************************************************
1724 IOReturn
IOService::getAggressiveness ( unsigned long type
, unsigned long * currentLevel
)
1726 if ( type
<= kMaxType
) {
1727 *currentLevel
= pm_vars
->current_aggressiveness_values
[type
];
1729 return kIOReturnSuccess
;
1732 //*********************************************************************************
1735 // Pass this to all power domain children. All those which are
1736 // power domains will pass it on to their children, etc.
1737 //*********************************************************************************
1739 IOReturn
IOService::systemWake ( void )
1743 IOPowerConnection
* connection
;
1744 IOService
* theChild
;
1746 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogSystemWake
,0, 0);
1748 iter
= getChildIterator(gIOPowerPlane
);
1751 while ( (next
= iter
->getNextObject()) ) {
1752 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) ) {
1753 theChild
= (IOService
*)connection
->copyChildEntry(gIOPowerPlane
);
1755 theChild
->systemWake();
1756 theChild
->release();
1763 if ( pm_vars
->theControllingDriver
!= NULL
) {
1764 if ( pm_vars
->theControllingDriver
->didYouWakeSystem() ) {
1773 //*********************************************************************************
1774 // temperatureCriticalForZone
1776 //*********************************************************************************
1778 IOReturn
IOService::temperatureCriticalForZone ( IOService
* whichZone
)
1780 IOService
* theParent
;
1783 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogCriticalTemp
,0,0);
1785 if ( inPlane(gIOPowerPlane
) && ! (priv
->we_are_root
) ) {
1786 theNub
= (IOService
*)copyParentEntry(gIOPowerPlane
);
1788 theParent
= (IOService
*)theNub
->copyParentEntry(gIOPowerPlane
);
1791 theParent
->temperatureCriticalForZone(whichZone
);
1792 theParent
->release();
1800 //*********************************************************************************
1801 // powerOverrideOnPriv
1803 //*********************************************************************************
1806 IOReturn
IOService::powerOverrideOnPriv ( void )
1808 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogOverrideOn
,0,0);
1810 priv
->device_overrides
= true; // turn on the override
1811 computeDesiredState();
1812 return changeState(); // change state if that changed something
1816 //*********************************************************************************
1817 // powerOverrideOffPriv
1819 //*********************************************************************************
1820 IOReturn
IOService::powerOverrideOffPriv ( void )
1822 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogOverrideOff
,0,0);
1824 priv
->device_overrides
= false; // turn off the override
1825 computeDesiredState();
1827 return makeUsable();
1829 return changeState(); // change state if that changed something
1833 //*********************************************************************************
1834 // enqueuePowerChange
1836 // Allocate a new state change notification, initialize it with fields from the
1837 // caller, and add it to the tail of the list of pending power changes.
1839 // If it is early enough in the list, and almost all the time it is the only one in
1840 // the list, start the power change.
1842 // In rare instances, this change will preempt the previous change in the list.
1843 // If the previous change is un-actioned in any way (because we are still
1844 // processing an even earlier power change), and if both the previous change
1845 // in the list and this change are initiated by us (not the parent), then we
1846 // needn't perform the previous change, so we collapse the list a little.
1847 //*********************************************************************************
1849 IOReturn
IOService::enqueuePowerChange ( unsigned long flags
, unsigned long whatStateOrdinal
, unsigned long domainState
, IOPowerConnection
* whichParent
, unsigned long singleParentState
)
1854 // Create and initialize the new change note
1856 IOLockLock(priv
->queue_lock
);
1857 newNote
= priv
->changeList
->createChangeNote();
1858 if ( newNote
== -1 ) {
1859 IOLockUnlock(priv
->queue_lock
);
1860 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogEnqueueErr
,0,0);
1861 return IOPMAckImplied
; // uh-oh, our list is full
1864 priv
->changeList
->changeNote
[newNote
].newStateNumber
= whatStateOrdinal
;
1865 priv
->changeList
->changeNote
[newNote
].outputPowerCharacter
= pm_vars
->thePowerStates
[whatStateOrdinal
].outputPowerCharacter
;
1866 priv
->changeList
->changeNote
[newNote
].inputPowerRequirement
= pm_vars
->thePowerStates
[whatStateOrdinal
].inputPowerRequirement
;
1867 priv
->changeList
->changeNote
[newNote
].capabilityFlags
= pm_vars
->thePowerStates
[whatStateOrdinal
].capabilityFlags
;
1868 priv
->changeList
->changeNote
[newNote
].flags
= flags
;
1869 if (flags
& IOPMParentInitiated
) {
1870 priv
->changeList
->changeNote
[newNote
].domainState
= domainState
;
1871 priv
->changeList
->changeNote
[newNote
].parent
= whichParent
;
1872 whichParent
->retain();
1873 priv
->changeList
->changeNote
[newNote
].singleParentState
= singleParentState
;
1876 previousNote
= priv
->changeList
->previousChangeNote(newNote
);
1878 if ( previousNote
== -1 ) {
1880 // Queue is empty, we can start this change.
1882 if (flags
& IOPMWeInitiated
) {
1883 IOLockUnlock(priv
->queue_lock
);
1884 start_our_change(newNote
);
1888 IOLockUnlock(priv
->queue_lock
);
1889 return start_parent_change(newNote
);
1893 // The queue is not empty. Try to collapse this new change and the previous one in queue into one change.
1894 // This is possible only if both changes are initiated by us, and neither has been started yet.
1895 // Do this more than once if possible.
1897 // (A change is started iff it is at the head of the queue)
1899 while ( (previousNote
!= priv
->head_note
) && (previousNote
!= -1) &&
1900 (priv
->changeList
->changeNote
[newNote
].flags
& priv
->changeList
->changeNote
[previousNote
].flags
& IOPMWeInitiated
) ) {
1901 priv
->changeList
->changeNote
[previousNote
].outputPowerCharacter
= priv
->changeList
->changeNote
[newNote
].outputPowerCharacter
;
1902 priv
->changeList
->changeNote
[previousNote
].inputPowerRequirement
= priv
->changeList
->changeNote
[newNote
].inputPowerRequirement
;
1903 priv
->changeList
->changeNote
[previousNote
].capabilityFlags
=priv
-> changeList
->changeNote
[newNote
].capabilityFlags
;
1904 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogCollapseQueue
,priv
->changeList
->changeNote
[newNote
].newStateNumber
,
1905 priv
->changeList
->changeNote
[previousNote
].newStateNumber
);
1906 priv
->changeList
->changeNote
[previousNote
].newStateNumber
= priv
->changeList
->changeNote
[newNote
].newStateNumber
;
1907 priv
->changeList
->releaseTailChangeNote();
1908 newNote
= previousNote
;
1909 previousNote
= priv
->changeList
->previousChangeNote(newNote
);
1911 IOLockUnlock(priv
->queue_lock
);
1912 return IOPMWillAckLater
; // in any case, we can't start yet
1915 //*********************************************************************************
1918 // Notify all interested parties either that a change is impending or that the
1919 // previously-notified change is done and power has settled.
1920 // The parameter identifies whether this is the
1921 // pre-change notification or the post-change notification.
1923 //*********************************************************************************
1925 IOReturn
IOService::notifyAll ( bool is_prechange
)
1927 IOPMinformee
* nextObject
;
1930 IOPowerConnection
* connection
;
1932 // To prevent acknowledgePowerChange from finishing the change note and removing it from the queue if
1933 // some driver calls it, we inflate the number of pending acks so it cannot become zero. We'll fix it later.
1935 priv
->head_note_pendingAcks
=1;
1937 // OK, we will go through the lists of interested drivers and power domain children
1938 // and notify each one of this change.
1939 nextObject
= priv
->interestedDrivers
->firstInList(); // notify interested drivers
1940 while ( nextObject
!= NULL
) {
1941 priv
->head_note_pendingAcks
+=1;
1942 if (! inform(nextObject
, is_prechange
) ) {
1944 nextObject
= priv
->interestedDrivers
->nextInList(nextObject
);
1947 if (! acquire_lock() ) {
1950 if ( priv
->head_note_pendingAcks
> 1 ) { // did they all ack?
1951 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogStartAckTimer
,0,0); // no
1954 IOUnlock(priv
->our_lock
); // either way
1956 iter
= getChildIterator(gIOPowerPlane
); // notify children
1957 pm_vars
->thePowerStates
[priv
->head_note_state
].staticPower
= 0; // summing their power consumption
1960 while ( (next
= iter
->getNextObject()) ) {
1961 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) ) {
1962 priv
->head_note_pendingAcks
+=1;
1963 notifyChild(connection
, is_prechange
);
1969 if (! acquire_lock() ) {
1972 priv
->head_note_pendingAcks
-= 1; // now make this real
1973 if (priv
->head_note_pendingAcks
== 0 ) { // is it all acked?
1974 IOUnlock(priv
->our_lock
); // yes
1975 return IOPMAckImplied
; // return ack to parent
1977 IOUnlock(priv
->our_lock
); // no
1978 return IOPMWillAckLater
;
1982 //*********************************************************************************
1985 // Notify a power domain child of an upcoming power change.
1987 // If the object acknowledges the current change, we return TRUE.
1988 //*********************************************************************************
1990 bool IOService::notifyChild ( IOPowerConnection
* theNub
, bool is_prechange
)
1992 IOReturn k
= IOPMAckImplied
;
1993 unsigned long childPower
;
1994 IOService
* theChild
= (IOService
*)(theNub
->copyChildEntry(gIOPowerPlane
));
1996 theNub
->setAwaitingAck(true); // in case they don't ack
2002 if ( is_prechange
) {
2003 k
= theChild
->powerDomainWillChangeTo(priv
->head_note_outputFlags
,theNub
);
2006 k
= theChild
->powerDomainDidChangeTo(priv
->head_note_outputFlags
,theNub
);
2009 if ( k
== IOPMAckImplied
) { // did the return code ack?
2010 priv
->head_note_pendingAcks
-=1; // yes
2011 theNub
->setAwaitingAck(false);
2012 childPower
= theChild
->currentPowerConsumption();
2013 if ( childPower
== kIOPMUnknown
) {
2014 pm_vars
->thePowerStates
[priv
->head_note_state
].staticPower
= kIOPMUnknown
;
2017 if ( pm_vars
->thePowerStates
[priv
->head_note_state
].staticPower
!= kIOPMUnknown
) {
2018 pm_vars
->thePowerStates
[priv
->head_note_state
].staticPower
+= childPower
;
2021 theChild
->release();
2024 theChild
->release();
2029 //*********************************************************************************
2032 // Notify an interested driver of an upcoming power change.
2034 // If the object acknowledges the current change, we return TRUE.
2035 //*********************************************************************************
2037 bool IOService::inform ( IOPMinformee
* nextObject
, bool is_prechange
)
2039 IOReturn k
= IOPMAckImplied
;
2041 nextObject
->timer
= -1; // initialize this
2043 if ( is_prechange
) {
2044 pm_vars
->thePlatform
->PMLog (pm_vars
->ourName
,PMlogInformDriverPreChange
,
2045 (unsigned long)priv
->head_note_capabilityFlags
,(unsigned long)priv
->head_note_state
);
2046 k
= nextObject
->whatObject
->powerStateWillChangeTo( priv
->head_note_capabilityFlags
,priv
->head_note_state
,this);
2049 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogInformDriverPostChange
,
2050 (unsigned long)priv
->head_note_capabilityFlags
,(unsigned long)priv
->head_note_state
);
2051 k
= nextObject
->whatObject
->powerStateDidChangeTo(priv
->head_note_capabilityFlags
,priv
->head_note_state
,this);
2053 if ( nextObject
->timer
== 0 ) { // did it ack behind our back?
2056 if ( k
==IOPMAckImplied
) { // no, did the return code ack?
2057 nextObject
->timer
= 0; // yes
2058 priv
->head_note_pendingAcks
-= 1;
2062 nextObject
->timer
= 0; // somebody goofed
2063 priv
-> head_note_pendingAcks
-= 1;
2066 nextObject
->timer
= (k
* ns_per_us
/ ACK_TIMER_PERIOD
) + 1; // no, it's a timer
2071 //*********************************************************************************
2074 // All registered applications and kernel clients have positively acknowledged our
2075 // intention of lowering power. Here we notify them all that we will definitely
2076 // lower the power. If we don't have to wait for any of them to acknowledge, we
2077 // carry on by notifying interested drivers. Otherwise, we do wait.
2078 //*********************************************************************************
2080 void IOService::our_prechange_03 ( void )
2082 priv
->machine_state
= IOPMour_prechange_04
; // next state
2083 if ( tellChangeDown1(priv
->head_note_state
) ) { // are we waiting for responses?
2084 our_prechange_04(); // no, notify priority clients
2089 //*********************************************************************************
2092 // All registered applications and kernel clients have positively acknowledged our
2093 // intention of lowering power. Here we notify "priority" clients that we are
2094 // lowering power. If we don't have to wait for any of them to acknowledge, we
2095 // carry on by notifying interested drivers. Otherwise, we do wait.
2096 //*********************************************************************************
2098 void IOService::our_prechange_04 ( void )
2100 priv
->machine_state
= IOPMour_prechange_05
; // next state
2101 if ( tellChangeDown2(priv
->head_note_state
) ) { // are we waiting for responses?
2102 return our_prechange_05(); // no, notify interested drivers
2107 //*********************************************************************************
2110 // All registered applications and kernel clients have acknowledged our notification
2111 // that we are lowering power. Here we notify interested drivers. If we don't have
2112 // to wait for any of them to acknowledge, we instruct our power driver to make the change.
2113 // Otherwise, we do wait.
2114 //*********************************************************************************
2116 void IOService::our_prechange_05 ( void )
2118 priv
->machine_state
= IOPMour_prechange_1
; // no, in case they don't all ack
2119 if ( notifyAll(true) == IOPMAckImplied
) {
2125 //*********************************************************************************
2128 // All interested drivers have acknowledged our pre-change notification of a power
2129 // change we initiated. Here we instruct our controlling driver to make
2130 // the change to the hardware. If it does so, we continue processing
2131 // (waiting for settle and notifying interested parties post-change.)
2132 // If it doesn't, we have to wait for it to acknowledge and then continue.
2133 //*********************************************************************************
2135 void IOService::our_prechange_1 ( void )
2137 if ( instruct_driver(priv
->head_note_state
) == IOPMAckImplied
) {
2138 our_prechange_2(); // it's done, carry on
2141 priv
->machine_state
= IOPMour_prechange_2
; // it's not, wait for it
2142 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogStartAckTimer
,0,0);
2148 //*********************************************************************************
2151 // Our controlling driver has changed power state on the hardware
2152 // during a power change we initiated. Here we see if we need to wait
2153 // for power to settle before continuing. If not, we continue processing
2154 // (notifying interested parties post-change). If so, we wait and
2156 //*********************************************************************************
2158 void IOService::our_prechange_2 ( void )
2160 priv
->settle_time
= compute_settle_time();
2161 if ( priv
->settle_time
== 0 ) {
2165 priv
->machine_state
= IOPMour_prechange_3
;
2166 startSettleTimer(priv
->settle_time
);
2171 //*********************************************************************************
2174 // Power has settled on a power change we initiated. Here we notify
2175 // all our interested parties post-change. If they all acknowledge, we're
2176 // done with this change note, and we can start on the next one.
2177 // Otherwise we have to wait for acknowledgements and finish up later.
2178 //*********************************************************************************
2180 void IOService::our_prechange_3 ( void )
2182 priv
->machine_state
= IOPMour_prechange_4
; // in case they don't all ack
2183 if ( notifyAll(false) == IOPMAckImplied
) {
2189 //*********************************************************************************
2192 // Power has settled on a power change we initiated, and
2193 // all our interested parties have acknowledged. We're
2194 // done with this change note, and we can start on the next one.
2195 //*********************************************************************************
2197 void IOService::our_prechange_4 ( void )
2203 //*********************************************************************************
2206 // All applications and kernel clients have been notified of a power lowering
2207 // initiated by the parent and we didn't have to wait for any responses. Here
2208 // we notify any priority clients. If they all ack, we continue with the power change.
2209 // If at least one doesn't, we have to wait for it to acknowledge and then continue.
2210 //*********************************************************************************
2212 IOReturn
IOService::parent_down_0 ( void )
2214 priv
->machine_state
= IOPMparent_down_05
; // in case they don't all ack
2215 if ( tellChangeDown2(priv
->head_note_state
) ) { // are we waiting for responses?
2216 return parent_down_02(); // no, notify interested drivers
2218 return IOPMWillAckLater
; // they didn't
2222 //*********************************************************************************
2225 // All priority kernel clients have been notified of a power lowering
2226 // initiated by the parent and we didn't have to wait for any responses. Here
2227 // we notify any interested drivers and power domain children. If they all ack,
2228 // we continue with the power change.
2229 // If at least one doesn't, we have to wait for it to acknowledge and then continue.
2230 //*********************************************************************************
2232 IOReturn
IOService::parent_down_02 ( void )
2234 priv
->machine_state
= IOPMparent_down_4
; // in case they don't all ack
2235 if ( notifyAll(true) == IOPMAckImplied
) {
2236 return parent_down_1(); // they did
2238 return IOPMWillAckLater
; // they didn't
2242 //*********************************************************************************
2245 // All applications and kernel clients have been notified of a power lowering
2246 // initiated by the parent and we had to wait for responses. Here
2247 // we notify any priority clients. If they all ack, we continue with the power change.
2248 // If at least one doesn't, we have to wait for it to acknowledge and then continue.
2249 //*********************************************************************************
2251 void IOService::parent_down_04 ( void )
2253 priv
->machine_state
= IOPMparent_down_05
; // in case they don't all ack
2254 if ( tellChangeDown2(priv
->head_note_state
) ) { // are we waiting for responses?
2255 parent_down_05(); // no, notify interested drivers
2260 //*********************************************************************************
2263 // All applications and kernel clients have been notified of a power lowering
2264 // initiated by the parent and we had to wait for their responses. Here we notify
2265 // any interested drivers and power domain children. If they all ack, we continue
2266 // with the power change.
2267 // If at least one doesn't, we have to wait for it to acknowledge and then continue.
2268 //*********************************************************************************
2270 void IOService::parent_down_05 ( void )
2272 priv
->machine_state
= IOPMparent_down_4
; // in case they don't all ack
2273 if ( notifyAll(true) == IOPMAckImplied
) {
2274 parent_down_4(); // they did
2279 //*********************************************************************************
2282 // All parties have acknowledged our pre-change notification of a power
2283 // lowering initiated by the parent. Here we instruct our controlling driver
2284 // to put the hardware in the state it needs to be in when the domain is
2285 // lowered. If it does so, we continue processing
2286 // (waiting for settle and acknowledging the parent.)
2287 // If it doesn't, we have to wait for it to acknowledge and then continue.
2288 //*********************************************************************************
2290 IOReturn
IOService::parent_down_1 ( void )
2292 if ( instruct_driver(priv
->head_note_state
) == IOPMAckImplied
) {
2293 return parent_down_2(); // it's done, carry on
2295 priv
->machine_state
= IOPMparent_down_5
; // it's not, wait for it
2296 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogStartAckTimer
,0,0);
2298 return IOPMWillAckLater
;
2302 //*********************************************************************************
2305 // We had to wait for it, but all parties have acknowledged our pre-change
2306 // notification of a power lowering initiated by the parent.
2307 // Here we instruct our controlling driver
2308 // to put the hardware in the state it needs to be in when the domain is
2309 // lowered. If it does so, we continue processing
2310 // (waiting for settle and acknowledging the parent.)
2311 // If it doesn't, we have to wait for it to acknowledge and then continue.
2312 //*********************************************************************************
2314 void IOService::parent_down_4 ( void )
2316 if ( instruct_driver(priv
->head_note_state
) == IOPMAckImplied
) {
2317 parent_down_5(); // it's done, carry on
2320 priv
-> machine_state
= IOPMparent_down_5
; // it's not, wait for it
2321 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogStartAckTimer
,0,0);
2327 //*********************************************************************************
2330 // Our controlling driver has changed power state on the hardware
2331 // during a power change initiated by our parent. Here we see if we need
2332 // to wait for power to settle before continuing. If not, we continue
2333 // processing (acknowledging our preparedness to the parent).
2334 // If so, we wait and continue later.
2335 //*********************************************************************************
2337 IOReturn
IOService::parent_down_2 ( void )
2341 priv
->settle_time
= compute_settle_time();
2342 if ( priv
->settle_time
== 0 ) {
2343 priv
->machine_state
= IOPMparent_down_6
; // in case they don't all ack
2344 if ( notifyAll(false) == IOPMAckImplied
) {
2345 nub
= priv
->head_note_parent
;
2348 return IOPMAckImplied
;
2350 return IOPMWillAckLater
; // they didn't
2353 priv
->machine_state
= IOPMparent_down_3
;
2354 startSettleTimer(priv
->settle_time
);
2355 return IOPMWillAckLater
;
2360 //*********************************************************************************
2363 // Our controlling driver has changed power state on the hardware
2364 // during a power change initiated by our parent. We have had to wait
2365 // for acknowledgement from interested parties, or we have had to wait
2366 // for the controlling driver to change the state. Here we see if we need
2367 // to wait for power to settle before continuing. If not, we continue
2368 // processing (acknowledging our preparedness to the parent).
2369 // If so, we wait and continue later.
2370 //*********************************************************************************
2372 void IOService::parent_down_5 ( void )
2374 priv
->settle_time
= compute_settle_time();
2375 if ( priv
->settle_time
== 0 ) {
2379 priv
->machine_state
= IOPMparent_down_3
;
2380 startSettleTimer(priv
->settle_time
);
2385 //*********************************************************************************
2388 // Power has settled on a power change initiated by our parent. Here we
2389 // notify interested parties.
2390 //*********************************************************************************
2392 void IOService::parent_down_3 ( void )
2394 IORegistryEntry
* nub
;
2397 priv
->machine_state
= IOPMparent_down_6
; // in case they don't all ack
2398 if ( notifyAll(false) == IOPMAckImplied
) {
2399 nub
= priv
->head_note_parent
;
2401 parent
= (IOService
*)nub
->copyParentEntry(gIOPowerPlane
);
2403 parent
->acknowledgePowerChange((IOService
*)nub
);
2411 //*********************************************************************************
2414 // We had to wait for it, but all parties have acknowledged our post-change
2415 // notification of a power lowering initiated by the parent.
2416 // Here we acknowledge the parent.
2417 // We are done with this change note, and we can start on the next one.
2418 //*********************************************************************************
2420 void IOService::parent_down_6 ( void )
2422 IORegistryEntry
* nub
;
2425 nub
= priv
->head_note_parent
;
2427 parent
= (IOService
*)nub
->copyParentEntry(gIOPowerPlane
);
2429 parent
->acknowledgePowerChange((IOService
*)nub
);
2436 //*********************************************************************************
2439 // Our parent has informed us via powerStateDidChange that it has
2440 // raised the power in our power domain, and we have had to wait
2441 // for some interested party to acknowledge our notification.
2442 // Here we instruct our controlling
2443 // driver to program the hardware to take advantage of the higher domain
2444 // power. If it does so, we continue processing
2445 // (waiting for settle and notifying interested parties post-change.)
2446 // If it doesn't, we have to wait for it to acknowledge and then continue.
2447 //*********************************************************************************
2449 void IOService::parent_up_0 ( void )
2451 if ( instruct_driver(priv
->head_note_state
) == IOPMAckImplied
) {
2452 parent_up_4(); // it did it, carry on
2455 priv
->machine_state
= IOPMparent_up_4
; // it didn't, wait for it
2456 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogStartAckTimer
,0,0);
2462 //*********************************************************************************
2465 // Our parent has informed us via powerStateDidChange that it has
2466 // raised the power in our power domain. Here we instruct our controlling
2467 // driver to program the hardware to take advantage of the higher domain
2468 // power. If it does so, we continue processing
2469 // (waiting for settle and notifying interested parties post-change.)
2470 // If it doesn't, we have to wait for it to acknowledge and then continue.
2471 //*********************************************************************************
2473 IOReturn
IOService::parent_up_1 ( void )
2475 if ( instruct_driver(priv
->head_note_state
) == IOPMAckImplied
) {
2476 return parent_up_2(); // it did it, carry on
2479 priv
->machine_state
= IOPMparent_up_4
; // it didn't, wait for it
2480 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogStartAckTimer
,0,0);
2482 return IOPMWillAckLater
;
2487 //*********************************************************************************
2490 // Our controlling driver has changed power state on the hardware
2491 // during a power raise initiated by the parent. Here we see if we need to wait
2492 // for power to settle before continuing. If not, we continue processing
2493 // (notifying interested parties post-change). If so, we wait and
2495 //*********************************************************************************
2497 IOReturn
IOService::parent_up_2 ( void )
2499 priv
->settle_time
= compute_settle_time();
2500 if ( priv
->settle_time
== 0 ) {
2501 return parent_up_3();
2504 priv
->machine_state
= IOPMparent_up_5
;
2505 startSettleTimer(priv
->settle_time
);
2506 return IOPMWillAckLater
;
2511 //*********************************************************************************
2514 // Our controlling driver has changed power state on the hardware
2515 // during a power raise initiated by the parent, but we had to wait for it.
2516 // Here we see if we need to wait for power to settle before continuing.
2517 // If not, we continue processing (notifying interested parties post-change).
2518 // If so, we wait and continue later.
2519 //*********************************************************************************
2521 void IOService::parent_up_4 ( void )
2523 priv
->settle_time
= compute_settle_time();
2524 if ( priv
->settle_time
== 0 ) {
2528 priv
->machine_state
= IOPMparent_up_5
;
2529 startSettleTimer(priv
->settle_time
);
2534 //*********************************************************************************
2537 // No power settling was required on a power raise initiated by the parent.
2538 // Here we notify all our interested parties post-change. If they all acknowledge,
2539 // we're done with this change note, and we can start on the next one.
2540 // Otherwise we have to wait for acknowledgements and finish up later.
2541 //*********************************************************************************
2543 IOReturn
IOService::parent_up_3 ( void )
2547 priv
->machine_state
= IOPMparent_up_6
; // in case they don't all ack
2548 if ( notifyAll(false) == IOPMAckImplied
) {
2549 nub
= priv
->head_note_parent
;
2552 return IOPMAckImplied
;
2554 return IOPMWillAckLater
; // they didn't
2558 //*********************************************************************************
2561 // Power has settled on a power raise initiated by the parent.
2562 // Here we notify all our interested parties post-change. If they all acknowledge,
2563 // we're done with this change note, and we can start on the next one.
2564 // Otherwise we have to wait for acknowledgements and finish up later.
2565 //*********************************************************************************
2567 void IOService::parent_up_5 ( void )
2569 priv
->machine_state
= IOPMparent_up_6
; // in case they don't all ack
2570 if ( notifyAll(false) == IOPMAckImplied
) {
2576 //*********************************************************************************
2579 // All parties have acknowledged our post-change notification of a power
2580 // raising initiated by the parent. Here we acknowledge the parent.
2581 // We are done with this change note, and we can start on the next one.
2582 //*********************************************************************************
2584 void IOService::parent_up_6 ( void )
2586 IORegistryEntry
* nub
;
2589 nub
= priv
->head_note_parent
;
2591 parent
= (IOService
*)nub
->copyParentEntry(gIOPowerPlane
);
2593 parent
->acknowledgePowerChange((IOService
*)nub
);
2600 //*********************************************************************************
2603 // A power change is complete, and the used post-change note is at
2604 // the head of the queue. Remove it and set myCurrentState to the result
2605 // of the change. Start up the next change in queue.
2606 //*********************************************************************************
2608 void IOService::all_done ( void )
2610 unsigned long previous_state
;
2611 IORegistryEntry
* nub
;
2614 priv
->machine_state
= IOPMfinished
;
2616 if ( priv
->head_note_flags
& IOPMWeInitiated
) { // our power change
2617 if ( !( priv
->head_note_flags
& IOPMNotDone
) ) { // could our driver switch to the new state?
2618 if ( pm_vars
->myCurrentState
< priv
->head_note_state
) { // yes, did power raise?
2619 tellChangeUp (priv
->head_note_state
); // yes, inform clients and apps
2622 if ( ! priv
->we_are_root
) { // no, if this lowers our
2623 ask_parent(priv
->head_note_state
); // power requirements, tell the parent
2626 previous_state
= pm_vars
->myCurrentState
;
2627 pm_vars
->myCurrentState
= priv
->head_note_state
; // either way
2628 priv
->imminentState
= pm_vars
->myCurrentState
;
2629 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogChangeDone
,(unsigned long)pm_vars
->myCurrentState
,0);
2630 powerChangeDone(previous_state
); // inform subclass policy-maker
2633 // pm_vars->myCurrentState = pm_vars->theControllingDriver->powerStateForDomainState(pm_vars->parentsCurrentPowerFlags);
2636 if ( priv
->head_note_flags
& IOPMParentInitiated
) { // parent's power change
2637 if ( ((priv
->head_note_flags
& IOPMDomainWillChange
) && (pm_vars
->myCurrentState
>= priv
->head_note_state
)) ||
2638 ((priv
->head_note_flags
& IOPMDomainDidChange
) && (pm_vars
->myCurrentState
< priv
->head_note_state
)) ) {
2639 if ( pm_vars
->myCurrentState
< priv
->head_note_state
) { // did power raise?
2640 tellChangeUp (priv
->head_note_state
); // yes, inform clients and apps
2642 previous_state
= pm_vars
->myCurrentState
; // either way
2643 pm_vars
->myCurrentState
= priv
->head_note_state
;
2644 priv
->imminentState
= pm_vars
->myCurrentState
;
2645 pm_vars
->maxCapability
= pm_vars
->theControllingDriver
->maxCapabilityForDomainState(priv
->head_note_domainState
);
2647 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogChangeDone
,(unsigned long)pm_vars
->myCurrentState
,0);
2648 powerChangeDone(previous_state
); // inform subclass policy-maker
2652 IOLockLock(priv
->queue_lock
);
2653 priv
->changeList
->releaseHeadChangeNote(); // we're done with this
2655 priv
->head_note
= priv
->changeList
->currentChange(); // start next one in queue
2656 if ( priv
->head_note
!= -1 ) {
2658 IOLockUnlock(priv
->queue_lock
);
2659 if (priv
->changeList
->changeNote
[priv
->head_note
].flags
& IOPMWeInitiated
) {
2660 start_our_change(priv
->head_note
);
2663 nub
= priv
->changeList
->changeNote
[priv
->head_note
].parent
;
2664 if ( start_parent_change(priv
->head_note
) == IOPMAckImplied
) {
2665 parent
= (IOService
*)nub
->copyParentEntry(gIOPowerPlane
);
2667 parent
->acknowledgePowerChange((IOService
*)nub
);
2673 IOLockUnlock(priv
->queue_lock
);
2678 //*********************************************************************************
2681 // A driver or child has acknowledged our notification of an upcoming power
2682 // change, and this acknowledgement is the last one pending
2683 // before we change power or after changing power.
2685 //*********************************************************************************
2687 void IOService::all_acked ( void )
2689 switch (priv
->machine_state
) {
2690 case IOPMour_prechange_1
:
2693 case IOPMour_prechange_4
:
2696 case IOPMparent_down_4
:
2699 case IOPMparent_down_6
:
2702 case IOPMparent_up_0
:
2705 case IOPMparent_up_6
:
2712 //*********************************************************************************
2713 // settleTimerExpired
2715 // Power has settled after our last change. Notify interested parties that
2716 // there is a new power state.
2717 //*********************************************************************************
2719 void IOService::settleTimerExpired ( void )
2721 if ( ! initialized
) {
2722 return; // we're unloading
2725 switch (priv
->machine_state
) {
2726 case IOPMour_prechange_3
:
2729 case IOPMparent_down_3
:
2732 case IOPMparent_up_5
:
2739 //*********************************************************************************
2740 // compute_settle_time
2742 // Compute the power-settling delay in microseconds for the
2743 // change from myCurrentState to head_note_state.
2744 //*********************************************************************************
2746 unsigned long IOService::compute_settle_time ( void )
2748 unsigned long totalTime
;
2751 totalTime
= 0; // compute total time to attain the new state
2752 i
= pm_vars
->myCurrentState
;
2753 if ( priv
->head_note_state
< pm_vars
->myCurrentState
) { // we're lowering power
2754 while ( i
> priv
->head_note_state
) {
2755 totalTime
+= pm_vars
->thePowerStates
[i
].settleDownTime
;
2760 if ( priv
->head_note_state
> pm_vars
->myCurrentState
) { // we're raising power
2761 while ( i
< priv
->head_note_state
) {
2762 totalTime
+= pm_vars
->thePowerStates
[i
+1].settleUpTime
;
2771 //*********************************************************************************
2774 // Enter with a power-settling delay in microseconds and start a nano-second
2775 // timer for that delay.
2776 //*********************************************************************************
2778 IOReturn
IOService::startSettleTimer ( unsigned long delay
)
2780 AbsoluteTime deadline
;
2782 clock_interval_to_deadline(delay
, kMicrosecondScale
, &deadline
);
2784 thread_call_enter_delayed(priv
->settleTimer
, deadline
);
2789 //*********************************************************************************
2792 // The acknowledgement timeout periodic timer has ticked.
2793 // If we are awaiting acks for a power change notification,
2794 // we decrement the timer word of each interested driver which hasn't acked.
2795 // If a timer word becomes zero, we pretend the driver aknowledged.
2796 // If we are waiting for the controlling driver to change the power
2797 // state of the hardware, we decrement its timer word, and if it becomes
2798 // zero, we pretend the driver acknowledged.
2799 //*********************************************************************************
2801 void IOService::ack_timer_ticked ( void )
2803 IOPMinformee
* nextObject
;
2805 if ( ! initialized
) {
2806 return; // we're unloading
2809 if (! acquire_lock() ) {
2813 switch (priv
->machine_state
) {
2814 case IOPMour_prechange_2
:
2815 case IOPMparent_down_5
:
2816 case IOPMparent_up_4
:
2817 if ( priv
->driver_timer
!= 0 ) { // are we waiting for our driver to make its change?
2818 priv
->driver_timer
-= 1; // yes, tick once
2819 if ( priv
->driver_timer
== 0 ) { // it's tardy, we'll go on without it
2820 IOUnlock(priv
->our_lock
);
2821 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogCtrlDriverTardy
,0,0);
2824 else { // still waiting, set timer again
2826 IOUnlock(priv
->our_lock
);
2830 IOUnlock(priv
->our_lock
);
2834 case IOPMour_prechange_1
:
2835 case IOPMour_prechange_4
:
2836 case IOPMparent_down_4
:
2837 case IOPMparent_down_6
:
2838 case IOPMparent_up_0
:
2839 case IOPMparent_up_6
:
2840 if (priv
->head_note_pendingAcks
!= 0 ) { // are we waiting for interested parties to acknowledge?
2841 nextObject
= priv
->interestedDrivers
->firstInList(); // yes, go through the list of interested drivers
2842 while ( nextObject
!= NULL
) { // and check each one
2843 if ( nextObject
->timer
> 0 ) {
2844 nextObject
->timer
-= 1;
2845 if ( nextObject
->timer
== 0 ) { // this one should have acked by now
2846 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogIntDriverTardy
,0,0);
2847 kprintf("interested driver tardy: %s\n",nextObject
->whatObject
->getName());
2848 priv
->head_note_pendingAcks
-= 1;
2851 nextObject
= priv
->interestedDrivers
->nextInList(nextObject
);
2853 if ( priv
->head_note_pendingAcks
== 0 ) { // is that the last?
2854 IOUnlock(priv
->our_lock
);
2855 all_acked(); // yes, we can continue
2857 else { // no, set timer again
2859 IOUnlock(priv
->our_lock
);
2863 IOUnlock(priv
->our_lock
);
2867 case IOPMparent_down_0
: // apps didn't respond to parent-down notification
2868 IOUnlock(priv
->our_lock
);
2869 IOLockLock(priv
->flags_lock
);
2870 if (pm_vars
->responseFlags
) {
2871 pm_vars
->responseFlags
->release(); // get rid of this stuff
2872 pm_vars
->responseFlags
= NULL
;
2874 IOLockUnlock(priv
->flags_lock
);
2875 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogClientTardy
,0,5);
2876 parent_down_04(); // carry on with the change
2879 case IOPMparent_down_05
:
2880 IOUnlock(priv
->our_lock
);
2881 IOLockLock(priv
->flags_lock
);
2882 if (pm_vars
->responseFlags
) {
2883 pm_vars
->responseFlags
->release(); // get rid of this stuff
2884 pm_vars
->responseFlags
= NULL
;
2886 IOLockUnlock(priv
->flags_lock
);
2887 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogClientTardy
,0,1);
2888 parent_down_05(); // carry on with the change
2891 case IOPMour_prechange_03
: // apps didn't respond to our power-down request
2892 IOUnlock(priv
->our_lock
);
2893 IOLockLock(priv
->flags_lock
);
2894 if (pm_vars
->responseFlags
) {
2895 pm_vars
->responseFlags
->release(); // get rid of this stuff
2896 pm_vars
->responseFlags
= NULL
;
2898 IOLockUnlock(priv
->flags_lock
);
2899 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogClientTardy
,0,2);
2900 tellNoChangeDown(priv
->head_note_state
); // rescind the request
2901 priv
->head_note_flags
|= IOPMNotDone
; // mark the change note un-actioned
2902 all_done(); // and we're done
2905 case IOPMour_prechange_04
: // clients didn't respond to our power-down note
2906 IOUnlock(priv
->our_lock
);
2907 IOLockLock(priv
->flags_lock
);
2908 if (pm_vars
->responseFlags
) {
2909 pm_vars
->responseFlags
->release(); // get rid of this stuff
2910 pm_vars
->responseFlags
= NULL
;
2912 IOLockUnlock(priv
->flags_lock
);
2913 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogClientTardy
,0,4);
2914 our_prechange_04(); // carry on with the change
2917 case IOPMour_prechange_05
: // apps didn't respond to our power-down notification
2918 IOUnlock(priv
->our_lock
);
2919 IOLockLock(priv
->flags_lock
);
2920 if (pm_vars
->responseFlags
) {
2921 pm_vars
->responseFlags
->release(); // get rid of this stuff
2922 pm_vars
->responseFlags
= NULL
;
2924 IOLockUnlock(priv
->flags_lock
);
2925 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogClientTardy
,0,3);
2926 our_prechange_05(); // carry on with the change
2930 IOUnlock(priv
->our_lock
); // not waiting for acks
2936 //*********************************************************************************
2939 //*********************************************************************************
2941 void IOService::start_ack_timer ( void )
2943 AbsoluteTime deadline
;
2945 clock_interval_to_deadline(ACK_TIMER_PERIOD
, kNanosecondScale
, &deadline
);
2947 thread_call_enter_delayed(priv
->ackTimer
, deadline
);
2951 //*********************************************************************************
2954 //*********************************************************************************
2956 void IOService::stop_ack_timer ( void )
2958 thread_call_cancel(priv
->ackTimer
);
2962 //*********************************************************************************
2963 // c-language timer expiration functions
2965 //*********************************************************************************
2967 static void ack_timer_expired ( thread_call_param_t us
)
2969 ((IOService
*)us
)->ack_timer_ticked();
2973 static void settle_timer_expired ( thread_call_param_t us
)
2975 ((IOService
*)us
)->settleTimerExpired();
2979 //*********************************************************************************
2980 // add_child_to_active_change
2982 // A child has just registered with us. If there is
2983 // currently a change in progress, get the new party involved: if we
2984 // have notified all parties and are waiting for acks, notify the new
2986 //*********************************************************************************
2988 IOReturn
IOService::add_child_to_active_change ( IOPowerConnection
* newObject
)
2990 if (! acquire_lock() ) {
2994 switch (priv
->machine_state
) {
2995 case IOPMour_prechange_1
:
2996 case IOPMparent_down_4
:
2997 case IOPMparent_up_0
:
2998 priv
->head_note_pendingAcks
+= 2; // one for this child and one to prevent
2999 IOUnlock(priv
->our_lock
); // incoming acks from changing our state
3000 notifyChild(newObject
, true);
3001 if (! acquire_lock() ) {
3002 --priv
->head_note_pendingAcks
; // put it back
3005 if ( --priv
->head_note_pendingAcks
== 0 ) { // are we still waiting for acks?
3006 stop_ack_timer(); // no, stop the timer
3007 IOUnlock(priv
->our_lock
);
3008 all_acked(); // and now we can continue
3012 case IOPMour_prechange_4
:
3013 case IOPMparent_down_6
:
3014 case IOPMparent_up_6
:
3015 priv
->head_note_pendingAcks
+= 2; // one for this child and one to prevent
3016 IOUnlock(priv
->our_lock
); // incoming acks from changing our state
3017 notifyChild(newObject
, false);
3018 if (! acquire_lock() ) {
3019 --priv
->head_note_pendingAcks
; // put it back
3022 if ( --priv
->head_note_pendingAcks
== 0 ) { // are we still waiting for acks?
3023 stop_ack_timer(); // no, stop the timer
3024 IOUnlock(priv
->our_lock
);
3025 all_acked(); // and now we can continue
3030 IOUnlock(priv
->our_lock
);
3035 //*********************************************************************************
3036 // add_driver_to_active_change
3038 // An interested driver has just registered with us. If there is
3039 // currently a change in progress, get the new party involved: if we
3040 // have notified all parties and are waiting for acks, notify the new
3042 //*********************************************************************************
3044 IOReturn
IOService::add_driver_to_active_change ( IOPMinformee
* newObject
)
3046 if (! acquire_lock() ) {
3050 switch (priv
->machine_state
) {
3051 case IOPMour_prechange_1
:
3052 case IOPMparent_down_4
:
3053 case IOPMparent_up_0
:
3054 priv
->head_note_pendingAcks
+= 2; // one for this driver and one to prevent
3055 IOUnlock(priv
->our_lock
); // incoming acks from changing our state
3056 inform(newObject
, true); // inform the driver
3057 if (! acquire_lock() ) {
3058 --priv
->head_note_pendingAcks
; // put it back
3061 if ( --priv
->head_note_pendingAcks
== 0 ) { // are we still waiting for acks?
3062 stop_ack_timer(); // no, stop the timer
3063 IOUnlock(priv
->our_lock
);
3064 all_acked(); // and now we can continue
3068 case IOPMour_prechange_4
:
3069 case IOPMparent_down_6
:
3070 case IOPMparent_up_6
:
3071 priv
->head_note_pendingAcks
+= 2; // one for this driver and one to prevent
3072 IOUnlock(priv
->our_lock
); // incoming acks from changing our state
3073 inform(newObject
, false); // inform the driver
3074 if (! acquire_lock() ) {
3075 --priv
->head_note_pendingAcks
; // put it back
3078 if ( --priv
->head_note_pendingAcks
== 0 ) { // are we still waiting for acks?
3079 stop_ack_timer(); // no, stop the timer
3080 IOUnlock(priv
->our_lock
);
3081 all_acked(); // and now we can continue
3086 IOUnlock(priv
->our_lock
);
3091 //*********************************************************************************
3092 // start_parent_change
3094 // Here we begin the processing of a change note initiated by our parent
3095 // which is at the head of the queue.
3097 // It is possible for the change to be processed to completion and removed from the queue.
3098 // There are several possible interruptions to the processing, though, and they are:
3099 // we may have to wait for interested parties to acknowledge our pre-change notification,
3100 // we may have to wait for our controlling driver to change the hardware power state,
3101 // there may be a settling time after changing the hardware power state,
3102 // we may have to wait for interested parties to acknowledge our post-change notification,
3103 // we may have to wait for the acknowledgement timer expiration to substitute for the
3104 // acknowledgement from a failing driver.
3105 //*********************************************************************************
3107 IOReturn
IOService::start_parent_change ( unsigned long queue_head
)
3109 priv
->head_note
= queue_head
;
3110 priv
->head_note_flags
= priv
-> changeList
->changeNote
[priv
->head_note
].flags
;
3111 priv
->head_note_state
= priv
->changeList
->changeNote
[priv
->head_note
].newStateNumber
;
3112 priv
->imminentState
= priv
->head_note_state
;
3113 priv
->head_note_outputFlags
= priv
->changeList
->changeNote
[priv
->head_note
].outputPowerCharacter
;
3114 priv
->head_note_domainState
= priv
->changeList
->changeNote
[priv
->head_note
].domainState
;
3115 priv
->head_note_parent
= priv
->changeList
->changeNote
[priv
->head_note
].parent
;
3116 priv
->head_note_capabilityFlags
= priv
->changeList
->changeNote
[priv
->head_note
].capabilityFlags
;
3118 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogStartParentChange
,
3119 (unsigned long)priv
->head_note_state
,(unsigned long)pm_vars
->myCurrentState
);
3121 ask_parent( priv
->ourDesiredPowerState
); // if we need something and haven't told the parent, do so
3123 if ( priv
->head_note_state
< pm_vars
->myCurrentState
) { // power domain is lowering
3124 setParentInfo(priv
->changeList
->changeNote
[priv
->head_note
].singleParentState
,priv
->head_note_parent
);
3125 priv
->initial_change
= false;
3126 priv
->machine_state
= IOPMparent_down_0
; // tell apps and kernel clients
3127 if ( tellChangeDown1(priv
->head_note_state
) ) { // are we waiting for responses?
3128 return parent_down_0(); // no, notify priority clients
3130 return IOPMWillAckLater
; // yes
3133 if ( priv
->head_note_state
> pm_vars
->myCurrentState
) { // parent is raising power, we may or may not
3134 if ( priv
->ourDesiredPowerState
> pm_vars
->myCurrentState
) {
3135 if ( priv
->ourDesiredPowerState
< priv
->head_note_state
) {
3136 priv
->head_note_state
= priv
->ourDesiredPowerState
; // we do, but not all the way
3137 priv
->imminentState
= priv
->head_note_state
;
3138 priv
->head_note_outputFlags
= pm_vars
->thePowerStates
[priv
->head_note_state
].outputPowerCharacter
;
3139 priv
->head_note_capabilityFlags
= pm_vars
->thePowerStates
[priv
->head_note_state
].capabilityFlags
;
3140 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogAmendParentChange
,(unsigned long)priv
->head_note_state
,0);
3144 priv
->head_note_state
= pm_vars
->myCurrentState
; // we don't
3145 priv
->imminentState
= priv
->head_note_state
;
3146 priv
->head_note_outputFlags
= pm_vars
->thePowerStates
[priv
->head_note_state
].outputPowerCharacter
;
3147 priv
->head_note_capabilityFlags
= pm_vars
->thePowerStates
[priv
->head_note_state
].capabilityFlags
;
3148 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogAmendParentChange
,(unsigned long)priv
->head_note_state
,0);
3152 if ( (priv
->head_note_state
> pm_vars
->myCurrentState
) &&
3153 (priv
->head_note_flags
& IOPMDomainDidChange
) ) { // changing up
3154 priv
->initial_change
= false;
3155 priv
->machine_state
= IOPMparent_up_0
;
3156 if ( notifyAll(true) == IOPMAckImplied
) {
3157 return parent_up_1();
3159 return IOPMWillAckLater
; // they didn't all ack
3163 return IOPMAckImplied
; // a null change or power will go up
3167 //*********************************************************************************
3170 // Here we begin the processing of a change note initiated by us
3171 // which is at the head of the queue.
3173 // It is possible for the change to be processed to completion and removed from the queue.
3174 // There are several possible interruptions to the processing, though, and they are:
3175 // we may have to wait for interested parties to acknowledge our pre-change notification,
3176 // changes initiated by the parent will wait in the middle for powerStateDidChange,
3177 // we may have to wait for our controlling driver to change the hardware power state,
3178 // there may be a settling time after changing the hardware power state,
3179 // we may have to wait for interested parties to acknowledge our post-change notification,
3180 // we may have to wait for the acknowledgement timer expiration to substitute for the
3181 // acknowledgement from a failing driver.
3182 //*********************************************************************************
3184 void IOService::start_our_change ( unsigned long queue_head
)
3186 priv
->head_note
= queue_head
;
3187 priv
->head_note_flags
= priv
->changeList
->changeNote
[priv
->head_note
].flags
;
3188 priv
->head_note_state
= priv
->changeList
->changeNote
[priv
->head_note
].newStateNumber
;
3189 priv
->imminentState
= priv
->head_note_state
;
3190 priv
->head_note_outputFlags
= priv
->changeList
->changeNote
[priv
->head_note
].outputPowerCharacter
;
3191 priv
->head_note_capabilityFlags
= priv
->changeList
->changeNote
[priv
->head_note
].capabilityFlags
;
3193 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogStartDeviceChange
,
3194 (unsigned long)priv
->head_note_state
,(unsigned long)pm_vars
->myCurrentState
);
3196 if ( priv
->head_note_capabilityFlags
& IOPMNotAttainable
) { // can our driver switch to the new state?
3197 if ( ! priv
->we_are_root
) { // no, ask the parent to do it then
3198 ask_parent(priv
->head_note_state
);
3200 priv
-> head_note_flags
|= IOPMNotDone
; // mark the change note un-actioned
3201 all_done(); // and we're done
3204 // is there enough power in the domain?
3205 if ( (pm_vars
->maxCapability
< priv
->head_note_state
) && (! priv
->we_are_root
) ) {
3206 if ( ! priv
->we_are_root
) { // no, ask the parent to raise it
3207 ask_parent(priv
->head_note_state
);
3209 priv
->head_note_flags
|= IOPMNotDone
; // no, mark the change note un-actioned
3210 all_done(); // and we're done
3211 return; // till the parent raises power
3214 if ( ! priv
->initial_change
) {
3215 if ( priv
->head_note_state
== pm_vars
->myCurrentState
) {
3216 all_done(); // we initiated a null change; forget it
3220 priv
->initial_change
= false;
3222 if ( priv
->head_note_state
< pm_vars
->myCurrentState
) { // dropping power?
3223 priv
->machine_state
= IOPMour_prechange_03
; // yes, in case we have to wait for acks
3224 pm_vars
->doNotPowerDown
= false;
3225 pm_vars
->outofbandparameter
= kNotifyApps
; // ask apps and kernel clients if we can drop power
3226 if ( askChangeDown(priv
->head_note_state
) ) {
3227 if ( pm_vars
->doNotPowerDown
) { // don't have to wait, did any clients veto?
3228 tellNoChangeDown(priv
->head_note_state
); // yes, rescind the warning
3229 priv
-> head_note_flags
|= IOPMNotDone
; // mark the change note un-actioned
3230 all_done(); // and we're done
3233 our_prechange_03(); // no, tell'em we're dropping power
3238 if ( ! priv
->we_are_root
) { // we are raising power
3239 ask_parent(priv
->head_note_state
); // if this changes our power requirement, tell the parent
3241 priv
->machine_state
= IOPMour_prechange_1
; // in case they don't all ack
3242 if ( notifyAll(true) == IOPMAckImplied
) { // notify interested drivers and children
3249 //*********************************************************************************
3252 // Call the power domain parent to ask for a higher power state in the domain
3253 // or to suggest a lower power state.
3254 //*********************************************************************************
3256 IOReturn
IOService::ask_parent ( unsigned long requestedState
)
3260 IOPowerConnection
* connection
;
3262 unsigned long ourRequest
= pm_vars
->thePowerStates
[requestedState
].inputPowerRequirement
;
3264 if ( pm_vars
->thePowerStates
[requestedState
].capabilityFlags
& (kIOPMChildClamp
| kIOPMPreventIdleSleep
) ) {
3265 ourRequest
|= kIOPMPreventIdleSleep
;
3267 if ( pm_vars
->thePowerStates
[requestedState
].capabilityFlags
& (kIOPMChildClamp2
| kIOPMPreventSystemSleep
) ) {
3268 ourRequest
|= kIOPMPreventSystemSleep
;
3271 // is this a new desire?
3272 if ( priv
->previousRequest
== ourRequest
)
3274 // no, the parent knows already, just return
3278 if ( priv
->we_are_root
) {
3281 priv
->previousRequest
= ourRequest
;
3283 iter
= getParentIterator(gIOPowerPlane
);
3286 while ( (next
= iter
->getNextObject()) ) {
3287 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) ) {
3288 parent
= (IOService
*)connection
->copyParentEntry(gIOPowerPlane
);
3290 if ( parent
->requestPowerDomainState(ourRequest
,connection
,IOPMLowestState
)!= IOPMNoErr
) {
3291 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogRequestDenied
,
3292 (unsigned long)priv
->previousRequest
,0);
3305 //*********************************************************************************
3308 // Call the controlling driver and have it change the power state of the
3309 // hardware. If it returns IOPMAckImplied, the change is complete, and
3310 // we return IOPMAckImplied. Otherwise, it will ack when the change
3311 // is done; we return IOPMWillAckLater.
3312 //*********************************************************************************
3313 IOReturn
IOService::instruct_driver ( unsigned long newState
)
3315 IOReturn return_code
;
3317 if ( pm_vars
->thePowerStates
[newState
].capabilityFlags
& IOPMNotAttainable
) { // can our driver switch to the desired state?
3318 return IOPMAckImplied
; // no, so don't try
3320 priv
->driver_timer
= -1;
3322 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogProgramHardware
,newState
,0);
3324 ioSPMTraceStart(IOPOWER_STATE
, * (int *) this, (int) newState
);
3325 return_code
= pm_vars
->theControllingDriver
->setPowerState( newState
,this ); // yes, instruct it
3326 ioSPMTraceEnd(IOPOWER_STATE
, * (int *) this, (int) newState
, (int) return_code
);
3328 if ( return_code
== IOPMAckImplied
) { // it finished
3329 priv
->driver_timer
= 0;
3330 return IOPMAckImplied
;
3333 if ( priv
->driver_timer
== 0 ) { // it acked behind our back
3334 return IOPMAckImplied
;
3337 if ( return_code
< 0 ) { // somebody goofed
3338 return IOPMAckImplied
;
3340 priv
->driver_timer
= (return_code
* ns_per_us
/ ACK_TIMER_PERIOD
) + 1; // it didn't finish
3341 return IOPMWillAckLater
;
3345 //*********************************************************************************
3348 // We are acquiring the lock we use to protect our queue head from
3349 // simutaneous access by a thread which calls acknowledgePowerStateChange
3350 // or acknowledgeSetPowerState and the ack timer expiration thread.
3351 // Return TRUE if we acquire the lock, and the queue head didn't change
3352 // while we were acquiring the lock (and maybe blocked).
3353 // If there is no queue head, or it changes while we are blocked,
3354 // return FALSE with the lock unlocked.
3355 //*********************************************************************************
3357 bool IOService::acquire_lock ( void )
3359 long current_change_note
;
3361 current_change_note
= priv
->head_note
;
3362 if ( current_change_note
== -1 ) {
3366 IOTakeLock(priv
->our_lock
);
3367 if ( current_change_note
== priv
->head_note
) {
3370 else { // we blocked and something changed radically
3371 IOUnlock(priv
->our_lock
); // so there's nothing to do any more
3377 //*********************************************************************************
3380 // Ask registered applications and kernel clients if we can change to a lower
3383 // Subclass can override this to send a different message type. Parameter is
3384 // the destination state number.
3386 // Return true if we don't have to wait for acknowledgements
3387 //*********************************************************************************
3389 bool IOService::askChangeDown ( unsigned long stateNum
)
3391 return tellClientsWithResponse(kIOMessageCanDevicePowerOff
);
3395 //*********************************************************************************
3398 // Notify registered applications and kernel clients that we are definitely
3401 // Return true if we don't have to wait for acknowledgements
3402 //*********************************************************************************
3404 bool IOService::tellChangeDown1 ( unsigned long stateNum
)
3406 pm_vars
->outofbandparameter
= kNotifyApps
;
3407 return tellChangeDown(stateNum
);
3411 //*********************************************************************************
3414 // Notify priority clients that we are definitely dropping power.
3416 // Return true if we don't have to wait for acknowledgements
3417 //*********************************************************************************
3419 bool IOService::tellChangeDown2 ( unsigned long stateNum
)
3421 pm_vars
->outofbandparameter
= kNotifyPriority
;
3422 return tellChangeDown(stateNum
);
3426 //*********************************************************************************
3429 // Notify registered applications and kernel clients that we are definitely
3432 // Subclass can override this to send a different message type. Parameter is
3433 // the destination state number.
3435 // Return true if we don't have to wait for acknowledgements
3436 //*********************************************************************************
3438 bool IOService::tellChangeDown ( unsigned long stateNum
)
3440 return tellClientsWithResponse(kIOMessageDeviceWillPowerOff
);
3444 //*********************************************************************************
3445 // tellClientsWithResponse
3447 // Notify registered applications and kernel clients that we are definitely
3450 // Return true if we don't have to wait for acknowledgements
3451 //*********************************************************************************
3453 bool IOService::tellClientsWithResponse ( int messageType
)
3455 struct context theContext
;
3456 AbsoluteTime deadline
;
3459 pm_vars
->responseFlags
= OSArray::withCapacity( 1 );
3460 pm_vars
->serialNumber
+= 1;
3462 theContext
.responseFlags
= pm_vars
->responseFlags
;
3463 theContext
.serialNumber
= pm_vars
->serialNumber
;
3464 theContext
.flags_lock
= priv
->flags_lock
;
3465 theContext
.counter
= 1;
3466 theContext
.msgType
= messageType
;
3467 theContext
.us
= this;
3468 theContext
.maxTimeRequested
= 0;
3469 theContext
.stateNumber
= priv
->head_note_state
;
3470 theContext
.stateFlags
= priv
->head_note_capabilityFlags
;
3472 IOLockLock(priv
->flags_lock
);
3473 aBool
= OSBoolean::withBoolean(false); // position zero is false to
3474 theContext
.responseFlags
->setObject(0,aBool
); // prevent allowCancelCommon from succeeding
3476 IOLockUnlock(priv
->flags_lock
);
3478 switch ( pm_vars
->outofbandparameter
) {
3480 applyToInterested(gIOAppPowerStateInterest
,tellAppWithResponse
,(void *)&theContext
);
3481 applyToInterested(gIOGeneralInterest
,tellClientWithResponse
,(void *)&theContext
);
3483 case kNotifyPriority
:
3484 applyToInterested(gIOPriorityPowerStateInterest
,tellClientWithResponse
,(void *)&theContext
);
3488 if (! acquire_lock() ) {
3491 IOLockLock(priv
->flags_lock
);
3492 aBool
= OSBoolean::withBoolean(true); // now fix position zero
3493 theContext
.responseFlags
->replaceObject(0,aBool
);
3495 IOLockUnlock(priv
->flags_lock
);
3497 if ( ! checkForDone() ) { // we have to wait for somebody
3498 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogStartAckTimer
,theContext
.maxTimeRequested
,0);
3499 clock_interval_to_deadline(theContext
.maxTimeRequested
/ 1000, kMillisecondScale
, &deadline
);
3501 thread_call_enter_delayed(priv
->ackTimer
, deadline
);
3503 IOUnlock(priv
->our_lock
); // yes
3507 IOUnlock(priv
->our_lock
);
3508 IOLockLock(priv
->flags_lock
);
3509 pm_vars
->responseFlags
->release(); // everybody responded
3510 pm_vars
->responseFlags
= NULL
;
3511 IOLockUnlock(priv
->flags_lock
);
3517 //*********************************************************************************
3518 // tellAppWithResponse
3520 // We send a message to an application, and we expect a response, so we compute a
3521 // cookie we can identify the response with.
3522 //*********************************************************************************
3523 void tellAppWithResponse ( OSObject
* object
, void * context
)
3525 struct context
* theContext
= (struct context
*)context
;
3529 if( OSDynamicCast( IOService
, object
) ) {
3530 IOLockLock(theContext
->flags_lock
);
3531 aBool
= OSBoolean::withBoolean(true);
3532 theContext
->responseFlags
->setObject(theContext
->counter
,aBool
);
3534 IOLockUnlock(theContext
->flags_lock
);
3537 refcon
= ((theContext
->serialNumber
& 0xFFFF)<<16) + (theContext
->counter
& 0xFFFF);
3538 IOLockLock(theContext
->flags_lock
);
3539 aBool
= OSBoolean::withBoolean(false);
3540 theContext
->responseFlags
->setObject(theContext
->counter
,aBool
);
3542 IOLockUnlock(theContext
->flags_lock
);
3543 theContext
->us
->messageClient(theContext
->msgType
,object
,(void *)refcon
);
3544 if ( theContext
->maxTimeRequested
< k30seconds
) {
3545 theContext
->maxTimeRequested
= k30seconds
;
3548 theContext
->counter
+= 1;
3552 //*********************************************************************************
3553 // tellClientWithResponse
3555 // We send a message to an in-kernel client, and we expect a response, so we compute a
3556 // cookie we can identify the response with.
3557 // If it doesn't understand the notification (it is not power-management savvy)
3558 // we won't wait for it to prepare for sleep. If it tells us via a return code
3559 // in the passed struct that it is currently ready, we won't wait for it to prepare.
3560 // If it tells us via the return code in the struct that it does need time, we will chill.
3561 //*********************************************************************************
3562 void tellClientWithResponse ( OSObject
* object
, void * context
)
3564 struct context
* theContext
= (struct context
*)context
;
3565 IOPowerStateChangeNotification notify
;
3571 refcon
= ((theContext
->serialNumber
& 0xFFFF)<<16) + (theContext
->counter
& 0xFFFF);
3572 IOLockLock(theContext
->flags_lock
);
3573 aBool
= OSBoolean::withBoolean(false);
3574 theContext
->responseFlags
->setObject(theContext
->counter
,aBool
);
3576 IOLockUnlock(theContext
->flags_lock
);
3578 notify
.powerRef
= (void *)refcon
;
3579 notify
.returnValue
= 0;
3580 notify
.stateNumber
= theContext
->stateNumber
;
3581 notify
.stateFlags
= theContext
->stateFlags
;
3582 retCode
= theContext
->us
->messageClient(theContext
->msgType
,object
,(void *)¬ify
);
3583 if ( retCode
== kIOReturnSuccess
) {
3584 if ( notify
.returnValue
== 0 ) { // client doesn't want time to respond
3585 IOLockLock(theContext
->flags_lock
);
3586 aBool
= OSBoolean::withBoolean(true);
3587 theContext
->responseFlags
->replaceObject(theContext
->counter
,aBool
); // so set its flag true
3589 IOLockUnlock(theContext
->flags_lock
);
3592 IOLockLock(theContext
->flags_lock
);
3593 theFlag
= theContext
->responseFlags
->getObject(theContext
->counter
); // it does want time, and it hasn't
3594 if ( theFlag
!= 0 ) { // responded yet
3595 if ( ((OSBoolean
*)theFlag
)->isFalse() ) { // so note its time requirement
3596 if ( theContext
->maxTimeRequested
< notify
.returnValue
) {
3597 theContext
->maxTimeRequested
= notify
.returnValue
;
3601 IOLockUnlock(theContext
->flags_lock
);
3604 else { // not a client of ours
3605 IOLockLock(theContext
->flags_lock
);
3606 aBool
= OSBoolean::withBoolean(true); // so we won't be waiting for response
3607 theContext
->responseFlags
->replaceObject(theContext
->counter
,aBool
);
3609 IOLockUnlock(theContext
->flags_lock
);
3611 theContext
->counter
+= 1;
3615 //*********************************************************************************
3618 // Notify registered applications and kernel clients that we are not
3621 // Subclass can override this to send a different message type. Parameter is
3622 // the aborted destination state number.
3623 //*********************************************************************************
3625 void IOService::tellNoChangeDown ( unsigned long )
3627 return tellClients(kIOMessageDeviceWillNotPowerOff
);
3631 //*********************************************************************************
3634 // Notify registered applications and kernel clients that we are raising power.
3636 // Subclass can override this to send a different message type. Parameter is
3637 // the aborted destination state number.
3638 //*********************************************************************************
3640 void IOService::tellChangeUp ( unsigned long )
3642 return tellClients(kIOMessageDeviceHasPoweredOn
);
3646 //*********************************************************************************
3649 // Notify registered applications and kernel clients of something.
3650 //*********************************************************************************
3652 void IOService::tellClients ( int messageType
)
3654 struct context theContext
;
3656 theContext
.msgType
= messageType
;
3657 theContext
.us
= this;
3658 theContext
.stateNumber
= priv
->head_note_state
;
3659 theContext
.stateFlags
= priv
->head_note_capabilityFlags
;
3661 applyToInterested(gIOAppPowerStateInterest
,tellClient
,(void *)&theContext
);
3662 applyToInterested(gIOGeneralInterest
,tellClient
,(void *)&theContext
);
3666 //*********************************************************************************
3669 // Notify a registered application or kernel client of something.
3670 //*********************************************************************************
3671 void tellClient ( OSObject
* object
, void * context
)
3673 struct context
* theContext
= (struct context
*)context
;
3674 IOPowerStateChangeNotification notify
;
3676 notify
.powerRef
= (void *) 0;
3677 notify
.returnValue
= 0;
3678 notify
.stateNumber
= theContext
->stateNumber
;
3679 notify
.stateFlags
= theContext
->stateFlags
;
3681 theContext
->us
->messageClient(theContext
->msgType
,object
, ¬ify
);
3685 // **********************************************************************************
3688 // **********************************************************************************
3689 bool IOService::checkForDone ( void )
3694 IOLockLock(priv
->flags_lock
);
3695 if ( pm_vars
->responseFlags
== NULL
) {
3696 IOLockUnlock(priv
->flags_lock
);
3699 for ( i
= 0; ; i
++ ) {
3700 theFlag
= pm_vars
->responseFlags
->getObject(i
);
3701 if ( theFlag
== NULL
) {
3704 if ( ((OSBoolean
*)theFlag
)->isFalse() ) {
3705 IOLockUnlock(priv
->flags_lock
);
3709 IOLockUnlock(priv
->flags_lock
);
3714 // **********************************************************************************
3717 // **********************************************************************************
3718 bool IOService::responseValid ( unsigned long x
)
3720 UInt16 serialComponent
;
3721 UInt16 ordinalComponent
;
3723 unsigned long refcon
= (unsigned long)x
;
3726 serialComponent
= (refcon
>>16) & 0xFFFF;
3727 ordinalComponent
= refcon
& 0xFFFF;
3729 if ( serialComponent
!= pm_vars
->serialNumber
) {
3733 IOLockLock(priv
->flags_lock
);
3734 if ( pm_vars
->responseFlags
== NULL
) {
3735 IOLockUnlock(priv
->flags_lock
);
3739 theFlag
= pm_vars
->responseFlags
->getObject(ordinalComponent
);
3741 if ( theFlag
== 0 ) {
3742 IOLockUnlock(priv
->flags_lock
);
3746 if ( ((OSBoolean
*)theFlag
)->isFalse() ) {
3747 aBool
= OSBoolean::withBoolean(true);
3748 pm_vars
->responseFlags
->replaceObject(ordinalComponent
,aBool
);
3752 IOLockUnlock(priv
->flags_lock
);
3757 // **********************************************************************************
3760 // Our power state is about to lower, and we have notified applications
3761 // and kernel clients, and one of them has acknowledged. If this is the last to do
3762 // so, and all acknowledgements are positive, we continue with the power change.
3764 // We serialize this processing with timer expiration with a command gate on the
3765 // power management workloop, which the timer expiration is command gated to as well.
3766 // **********************************************************************************
3767 IOReturn
IOService::allowPowerChange ( unsigned long refcon
)
3769 if ( ! initialized
) {
3770 return kIOReturnSuccess
; // we're unloading
3773 return pm_vars
->PMcommandGate
->runAction(serializedAllowPowerChange
,(void *)refcon
);
3777 IOReturn
serializedAllowPowerChange ( OSObject
*owner
, void * refcon
, void *, void *, void *)
3779 return ((IOService
*)owner
)->serializedAllowPowerChange2((unsigned long)refcon
);
3782 IOReturn
IOService::serializedAllowPowerChange2 ( unsigned long refcon
)
3784 if ( ! responseValid(refcon
) ) { // response valid?
3785 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogAcknowledgeErr5
,refcon
,0);
3786 return kIOReturnSuccess
; // no, just return
3788 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogClientAcknowledge
,refcon
,0);
3790 return allowCancelCommon();
3794 // **********************************************************************************
3795 // cancelPowerChange
3797 // Our power state is about to lower, and we have notified applications
3798 // and kernel clients, and one of them has vetoed the change. If this is the last
3799 // client to respond, we abandon the power change.
3801 // We serialize this processing with timer expiration with a command gate on the
3802 // power management workloop, which the timer expiration is command gated to as well.
3803 // **********************************************************************************
3804 IOReturn
IOService::cancelPowerChange ( unsigned long refcon
)
3806 if ( ! initialized
) {
3807 return kIOReturnSuccess
; // we're unloading
3810 return pm_vars
->PMcommandGate
->runAction(serializedCancelPowerChange
,(void *)refcon
);
3814 IOReturn
serializedCancelPowerChange ( OSObject
*owner
, void * refcon
, void *, void *, void *)
3816 return ((IOService
*)owner
)->serializedCancelPowerChange2((unsigned long)refcon
);
3819 IOReturn
IOService::serializedCancelPowerChange2 ( unsigned long refcon
)
3821 if ( ! responseValid(refcon
) ) { // response valid?
3822 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogAcknowledgeErr5
,refcon
,0);
3823 return kIOReturnSuccess
; // no, just return
3825 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogClientCancel
,refcon
,0);
3827 pm_vars
->doNotPowerDown
= true;
3829 return allowCancelCommon();
3833 // **********************************************************************************
3834 // allowCancelCommon
3836 // **********************************************************************************
3837 IOReturn
IOService::allowCancelCommon ( void )
3839 if (! acquire_lock() ) {
3840 return kIOReturnSuccess
;
3843 if ( checkForDone() ) { // is this the last response?
3844 stop_ack_timer(); // yes, stop the timer
3845 IOUnlock(priv
->our_lock
);
3846 IOLockLock(priv
->flags_lock
);
3847 if ( pm_vars
->responseFlags
) {
3848 pm_vars
->responseFlags
->release();
3849 pm_vars
->responseFlags
= NULL
;
3851 IOLockUnlock(priv
->flags_lock
);
3852 switch (priv
->machine_state
) {
3853 case IOPMour_prechange_03
: // our change, was it vetoed?
3854 if ( ! pm_vars
->doNotPowerDown
) {
3855 our_prechange_03(); // no, we can continue
3858 tellNoChangeDown(priv
->head_note_state
); // yes, rescind the warning
3859 priv
->head_note_flags
|= IOPMNotDone
; // mark the change note un-actioned
3860 all_done(); // and we're done
3863 case IOPMour_prechange_04
:
3866 case IOPMour_prechange_05
:
3867 our_prechange_05(); // our change, continue
3869 case IOPMparent_down_0
:
3870 parent_down_04(); // parent change, continue
3872 case IOPMparent_down_05
:
3873 parent_down_05(); // parent change, continue
3878 IOUnlock(priv
->our_lock
); // not done yet
3879 return kIOReturnSuccess
;
3883 //*********************************************************************************
3886 // Set to highest available power state for a minimum of duration milliseconds
3887 //*********************************************************************************
3889 #define kFiveMinutesInNanoSeconds (300 * NSEC_PER_SEC)
3891 void IOService::clampPowerOn (unsigned long duration
)
3894 changePowerStateToPriv (pm_vars->theNumberOfPowerStates-1);
3896 if ( priv->clampTimerEventSrc == NULL ) {
3897 priv->clampTimerEventSrc = IOTimerEventSource::timerEventSource(this,
3898 c_PM_Clamp_Timer_Expired);
3900 IOWorkLoop * workLoop = getPMworkloop ();
3902 if ( !priv->clampTimerEventSrc || !workLoop ||
3903 ( workLoop->addEventSource( priv->clampTimerEventSrc) != kIOReturnSuccess) ) {
3908 priv->clampTimerEventSrc->setTimeout(300*USEC_PER_SEC, USEC_PER_SEC);
3912 //*********************************************************************************
3913 // PM_Clamp_Timer_Expired
3915 // called when clamp timer expires...set power state to 0.
3916 //*********************************************************************************
3918 void IOService::PM_Clamp_Timer_Expired (void)
3920 if ( ! initialized
) {
3921 return; // we're unloading
3924 changePowerStateToPriv (0);
3927 //*********************************************************************************
3928 // c_PM_clamp_Timer_Expired (C Func)
3930 // Called when our clamp timer expires...we will call the object method.
3931 //*********************************************************************************
3933 void c_PM_Clamp_Timer_Expired (OSObject
* client
, IOTimerEventSource
*)
3936 ((IOService
*)client
)->PM_Clamp_Timer_Expired ();
3940 //*********************************************************************************
3943 // Does nothing here. This should be implemented in a subclass driver.
3944 //*********************************************************************************
3946 IOReturn
IOService::setPowerState ( unsigned long powerStateOrdinal
, IOService
* whatDevice
)
3952 //*********************************************************************************
3953 // maxCapabilityForDomainState
3955 // Finds the highest power state in the array whose input power
3956 // requirement is equal to the input parameter. Where a more intelligent
3957 // decision is possible, override this in the subclassed driver.
3958 //*********************************************************************************
3960 unsigned long IOService::maxCapabilityForDomainState ( IOPMPowerFlags domainState
)
3964 if (pm_vars
->theNumberOfPowerStates
== 0 ) {
3967 for ( i
= (pm_vars
->theNumberOfPowerStates
)-1; i
>= 0; i
-- ) {
3968 if ( (domainState
& pm_vars
->thePowerStates
[i
].inputPowerRequirement
) == pm_vars
->thePowerStates
[i
].inputPowerRequirement
) {
3976 //*********************************************************************************
3977 // initialPowerStateForDomainState
3979 // Finds the highest power state in the array whose input power
3980 // requirement is equal to the input parameter. Where a more intelligent
3981 // decision is possible, override this in the subclassed driver.
3982 //*********************************************************************************
3984 unsigned long IOService::initialPowerStateForDomainState ( IOPMPowerFlags domainState
)
3988 if (pm_vars
->theNumberOfPowerStates
== 0 ) {
3991 for ( i
= (pm_vars
->theNumberOfPowerStates
)-1; i
>= 0; i
-- ) {
3992 if ( (domainState
& pm_vars
->thePowerStates
[i
].inputPowerRequirement
) == pm_vars
->thePowerStates
[i
].inputPowerRequirement
) {
4000 //*********************************************************************************
4001 // powerStateForDomainState
4003 // Finds the highest power state in the array whose input power
4004 // requirement is equal to the input parameter. Where a more intelligent
4005 // decision is possible, override this in the subclassed driver.
4006 //*********************************************************************************
4008 unsigned long IOService::powerStateForDomainState ( IOPMPowerFlags domainState
)
4012 if (pm_vars
->theNumberOfPowerStates
== 0 ) {
4015 for ( i
= (pm_vars
->theNumberOfPowerStates
)-1; i
>= 0; i
-- ) {
4016 if ( (domainState
& pm_vars
->thePowerStates
[i
].inputPowerRequirement
) == pm_vars
->thePowerStates
[i
].inputPowerRequirement
) {
4024 //*********************************************************************************
4027 // Does nothing here. This should be implemented in a subclass driver.
4028 //*********************************************************************************
4030 bool IOService::didYouWakeSystem ( void )
4036 //*********************************************************************************
4037 // powerStateWillChangeTo
4039 // Does nothing here. This should be implemented in a subclass driver.
4040 //*********************************************************************************
4042 IOReturn
IOService::powerStateWillChangeTo ( IOPMPowerFlags
, unsigned long, IOService
*)
4048 //*********************************************************************************
4049 // powerStateDidChangeTo
4051 // Does nothing here. This should be implemented in a subclass driver.
4052 //*********************************************************************************
4054 IOReturn
IOService::powerStateDidChangeTo ( IOPMPowerFlags
, unsigned long, IOService
*)
4060 //*********************************************************************************
4063 // Does nothing here. This should be implemented in a subclass policy-maker.
4064 //*********************************************************************************
4066 void IOService::powerChangeDone ( unsigned long )
4071 //*********************************************************************************
4074 // Does nothing here. This should be implemented in a subclass driver.
4075 //*********************************************************************************
4077 IOReturn
IOService::newTemperature ( long currentTemp
, IOService
* whichZone
)
4085 #define super OSObject
4087 OSDefineMetaClassAndStructors(IOPMprot
, OSObject
)
4088 //*********************************************************************************
4091 // Serialize protected instance variables for debug output.
4092 //*********************************************************************************
4093 bool IOPMprot::serialize(OSSerialize
*s
) const
4095 OSString
* theOSString
;
4101 buffer
= ptr
= IONew(char, 2000);
4105 ptr
+= sprintf(ptr
,"{ theNumberOfPowerStates = %d, ",(unsigned int)theNumberOfPowerStates
);
4107 if ( theNumberOfPowerStates
!= 0 ) {
4108 ptr
+= sprintf(ptr
,"version %d, ",(unsigned int)thePowerStates
[0].version
);
4111 if ( theNumberOfPowerStates
!= 0 ) {
4112 for ( i
= 0; i
< (int)theNumberOfPowerStates
; i
++ ) {
4113 ptr
+= sprintf(ptr
,"power state %d = { ",i
);
4114 ptr
+= sprintf(ptr
,"capabilityFlags %08x, ",(unsigned int)thePowerStates
[i
].capabilityFlags
);
4115 ptr
+= sprintf(ptr
,"outputPowerCharacter %08x, ",(unsigned int)thePowerStates
[i
].outputPowerCharacter
);
4116 ptr
+= sprintf(ptr
,"inputPowerRequirement %08x, ",(unsigned int)thePowerStates
[i
].inputPowerRequirement
);
4117 ptr
+= sprintf(ptr
,"staticPower %d, ",(unsigned int)thePowerStates
[i
].staticPower
);
4118 ptr
+= sprintf(ptr
,"unbudgetedPower %d, ",(unsigned int)thePowerStates
[i
].unbudgetedPower
);
4119 ptr
+= sprintf(ptr
,"powerToAttain %d, ",(unsigned int)thePowerStates
[i
].powerToAttain
);
4120 ptr
+= sprintf(ptr
,"timeToAttain %d, ",(unsigned int)thePowerStates
[i
].timeToAttain
);
4121 ptr
+= sprintf(ptr
,"settleUpTime %d, ",(unsigned int)thePowerStates
[i
].settleUpTime
);
4122 ptr
+= sprintf(ptr
,"timeToLower %d, ",(unsigned int)thePowerStates
[i
].timeToLower
);
4123 ptr
+= sprintf(ptr
,"settleDownTime %d, ",(unsigned int)thePowerStates
[i
].settleDownTime
);
4124 ptr
+= sprintf(ptr
,"powerDomainBudget %d }, ",(unsigned int)thePowerStates
[i
].powerDomainBudget
);
4128 ptr
+= sprintf(ptr
,"aggressiveness = %d, ",(unsigned int)aggressiveness
);
4129 ptr
+= sprintf(ptr
,"myCurrentState = %d, ",(unsigned int)myCurrentState
);
4130 ptr
+= sprintf(ptr
,"parentsCurrentPowerFlags = %08x, ",(unsigned int)parentsCurrentPowerFlags
);
4131 ptr
+= sprintf(ptr
,"maxCapability = %d }",(unsigned int)maxCapability
);
4133 theOSString
= OSString::withCString(buffer
);
4134 rtn_code
= theOSString
->serialize(s
);
4135 theOSString
->release();
4136 IODelete(buffer
, char, 2000);
4143 #define super OSObject
4145 OSDefineMetaClassAndStructors(IOPMpriv
, OSObject
)
4146 //*********************************************************************************
4149 // Serialize private instance variables for debug output.
4150 //*********************************************************************************
4151 bool IOPMpriv::serialize(OSSerialize
*s
) const
4153 OSString
* theOSString
;
4157 IOPMinformee
* nextObject
;
4159 buffer
= ptr
= IONew(char, 2000);
4163 ptr
+= sprintf(ptr
,"{ this object = %08x",(unsigned int)owner
);
4164 if ( we_are_root
) {
4165 ptr
+= sprintf(ptr
," (root)");
4167 ptr
+= sprintf(ptr
,", ");
4169 nextObject
= interestedDrivers
->firstInList(); // display interested drivers
4170 while ( nextObject
!= NULL
) {
4171 ptr
+= sprintf(ptr
,"interested driver = %08x, ",(unsigned int)nextObject
->whatObject
);
4172 nextObject
= interestedDrivers
->nextInList(nextObject
);
4175 if ( machine_state
!= IOPMfinished
) {
4176 ptr
+= sprintf(ptr
,"machine_state = %d, ",(unsigned int)machine_state
);
4177 ptr
+= sprintf(ptr
,"driver_timer = %d, ",(unsigned int)driver_timer
);
4178 ptr
+= sprintf(ptr
,"settle_time = %d, ",(unsigned int)settle_time
);
4179 ptr
+= sprintf(ptr
,"head_note_flags = %08x, ",(unsigned int)head_note_flags
);
4180 ptr
+= sprintf(ptr
,"head_note_state = %d, ",(unsigned int)head_note_state
);
4181 ptr
+= sprintf(ptr
,"head_note_outputFlags = %08x, ",(unsigned int)head_note_outputFlags
);
4182 ptr
+= sprintf(ptr
,"head_note_domainState = %08x, ",(unsigned int)head_note_domainState
);
4183 ptr
+= sprintf(ptr
,"head_note_capabilityFlags = %08x, ",(unsigned int)head_note_capabilityFlags
);
4184 ptr
+= sprintf(ptr
,"head_note_pendingAcks = %d, ",(unsigned int)head_note_pendingAcks
);
4187 if ( device_overrides
) {
4188 ptr
+= sprintf(ptr
,"device overrides, ");
4190 ptr
+= sprintf(ptr
,"driverDesire = %d, ",(unsigned int)driverDesire
);
4191 ptr
+= sprintf(ptr
,"deviceDesire = %d, ",(unsigned int)deviceDesire
);
4192 ptr
+= sprintf(ptr
,"ourDesiredPowerState = %d, ",(unsigned int)ourDesiredPowerState
);
4193 ptr
+= sprintf(ptr
,"previousRequest = %d }",(unsigned int)previousRequest
);
4195 theOSString
= OSString::withCString(buffer
);
4196 rtn_code
= theOSString
->serialize(s
);
4197 theOSString
->release();
4198 IODelete(buffer
, char, 2000);