2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
24 #include <IOKit/assert.h>
26 #include <IOKit/IOCommandGate.h>
27 #include <IOKit/IOKitDebug.h>
28 #include <IOKit/IOLib.h>
29 #include <IOKit/IOMessage.h>
30 #include <IOKit/IOPlatformExpert.h>
31 #include <IOKit/IOService.h>
32 #include <IOKit/IOTimerEventSource.h>
33 #include <IOKit/IOWorkLoop.h>
35 #include <IOKit/pwr_mgt/IOPMchangeNoteList.h>
36 #include <IOKit/pwr_mgt/IOPMinformee.h>
37 #include <IOKit/pwr_mgt/IOPMinformeeList.h>
38 #include <IOKit/pwr_mgt/IOPMlog.h>
39 #include <IOKit/pwr_mgt/IOPowerConnection.h>
40 #include <IOKit/pwr_mgt/RootDomain.h>
42 // Required for notification instrumentation
43 #include "IOServicePrivate.h"
45 #define super IORegistryEntry
47 #define OUR_PMLog(t, a, b) \
48 do { pm_vars->thePlatform->PMLog(pm_vars->ourName, t, a, b); } while(0)
50 static void ack_timer_expired(thread_call_param_t
);
51 static void settle_timer_expired(thread_call_param_t
);
52 static void PM_idle_timer_expired(OSObject
*, IOTimerEventSource
*);
53 void tellAppWithResponse ( OSObject
* object
, void * context
);
54 void tellClientWithResponse ( OSObject
* object
, void * context
);
55 void tellClient ( OSObject
* object
, void * context
);
56 IOReturn
serializedAllowPowerChange ( OSObject
*, void *, void *, void *, void *);
57 IOReturn
serializedCancelPowerChange ( OSObject
*, void *, void *, void *, void *);
59 extern const IORegistryPlane
* gIOPowerPlane
;
62 // and there's 1000 nanoseconds in a microsecond:
63 #define ns_per_us 1000
66 // The current change note is processed by a state machine.
67 // Inputs are acks from interested parties, ack from the controlling driver,
68 // ack timeouts, settle timeout, and powerStateDidChange from the parent.
69 // These are the states:
71 kIOPM_OurChangeTellClientsPowerDown
= 1,
72 kIOPM_OurChangeTellPriorityClientsPowerDown
,
73 kIOPM_OurChangeNotifyInterestedDriversWillChange
,
74 kIOPM_OurChangeSetPowerState
,
75 kIOPM_OurChangeWaitForPowerSettle
,
76 kIOPM_OurChangeNotifyInterestedDriversDidChange
,
77 kIOPM_OurChangeFinish
,
78 kIOPM_ParentDownTellPriorityClientsPowerDown_Immediate
,
79 kIOPM_ParentDownNotifyInterestedDriversWillChange_Delayed
,
80 kIOPM_ParentDownWaitForPowerSettleAndNotifyDidChange_Immediate
,
81 kIOPM_ParentDownNotifyDidChangeAndAcknowledgeChange_Delayed
,
82 kIOPM_ParentDownSetPowerState_Delayed
,
83 kIOPM_ParentDownWaitForPowerSettle_Delayed
,
84 kIOPM_ParentDownAcknowledgeChange_Delayed
,
85 kIOPM_ParentUpSetPowerState_Delayed
,
86 kIOPM_ParentUpSetPowerState_Immediate
,
87 kIOPM_ParentUpWaitForSettleTime_Delayed
,
88 kIOPM_ParentUpNotifyInterestedDriversDidChange_Delayed
,
89 kIOPM_ParentUpAcknowledgePowerChange_Delayed
,
93 // values of outofbandparameter
100 // used for applyToInterested
102 OSArray
* responseFlags
;
105 UInt32 maxTimeRequested
;
109 unsigned long stateNumber
;
110 IOPMPowerFlags stateFlags
;
113 // five minutes in microseconds
114 #define FIVE_MINUTES 5*60*1000000
115 #define k30seconds 30*1000000
118 There are two different kinds of power state changes. One is initiated by a subclassed device object which has either
119 decided to change power state, or its controlling driver has suggested it, or some other driver wants to use the
120 idle device and has asked it to become usable. The second kind of power state change is initiated by the power
121 domain parent. The two are handled slightly differently.
123 There is a queue of so-called change notifications, or change notes for short. Usually the queue is empty, and when
124 it isn't, usually there is one change note in it, but since it's possible to have more than one power state change pending
125 at one time, a queue is implemented. Example: the subclass device decides it's idle and initiates a change to a lower
126 power state. This causes interested parties to be notified, but they don't all acknowledge right away. This causes the
127 change note to sit in the queue until all the acks are received. During this time, the device decides it isn't idle anymore and
128 wants to raise power back up again. This change can't be started, however, because the previous one isn't complete yet,
129 so the second one waits in the queue. During this time, the parent decides to lower or raise the power state of the entire
130 power domain and notifies the device, and that notification goes into the queue, too, and can't be actioned until the
133 This is how a power change initiated by the subclass device is handled:
134 First, all interested parties are notified of the change via their powerStateWillChangeTo method. If they all don't
135 acknowledge via return code, then we have to wait. If they do, or when they finally all acknowledge via our
136 acknowledgePowerChange method, then we can continue. We call the controlling driver, instructing it to change to
137 the new state. Then we wait for power to settle. If there is no settling-time, or after it has passed, we notify
138 interested parties again, this time via their powerStateDidChangeTo methods. When they have all acked, we're done.
139 If we lowered power and don't need the power domain to be in its current power state, we suggest to the parent that
140 it lower the power domain state.
142 This is how a change to a lower power domain state initiated by the parent is handled:
143 First, we figure out what power state we will be in when the new domain state is reached. Then all interested parties are
144 notified that we are moving to that new state. When they have acknowledged, we call the controlling driver to assume
145 that state and we wait for power to settle. Then we acknowledge our preparedness to our parent. When all its interested
146 parties have acknowledged, it lowers power and then notifies its interested parties again. When we get this call, we notify
147 our interested parties that the power state has changed, and when they have all acknowledged, we're done.
149 This is how a change to a higher power domain state initiated by the parent is handled:
150 We figure out what power state we will be in when the new domain state is reached. If it is different from our current
151 state we acknowledge the parent. When all the parent's interested parties have acknowledged, it raises power in the
152 domain and waits for power to settle. Then it notifies everyone that the new state has been reached. When we get this call,
153 we call the controlling driver, instructing it to assume the new state, and wait for power to settle. Then we notify our interested
154 parties. When they all acknowledge we are done.
156 In either of the two cases above, it is possible that we will not be changing state even though the domain is. Examples:
157 A change to a lower domain state may not affect us because we are already in a low enough state, and
158 We will not take advantage of a change to a higher domain state, because we have no need of the higher power.
159 In such a case, there is nothing to do but acknowledge the parent. So when the parent calls our powerDomainWillChange
160 method, and we decide that we will not be changing state, we merely acknowledge the parent, via return code, and wait.
161 When the parent subsequently calls powerStateDidChange, we acknowledge again via return code, and the change is complete.
163 Power state changes are processed in a state machine, and since there are four varieties of power state changes, there are
164 four major paths through the state machine:
166 The fourth is nearly trivial. In this path, the parent is changing the domain state, but we are not changing the device state.
167 The change starts when the parent calls powerDomainWillChange. All we do is acknowledge the parent.
168 When the parent calls powerStateDidChange, we acknowledge the parent again, and we're done.
170 The first is fairly simple. It starts when a power domain child calls requestPowerDomainState and we decide to change power states
171 to accomodate the child, or if our power-controlling driver calls changePowerStateTo, or if some other driver which is using our
172 device calls makeUsable, or if a subclassed object calls changePowerStateToPriv. These are all power changes initiated by us, not
173 forced upon us by the parent. We start by notifying interested parties. If they all acknowledge via return code, we can go
174 on to state "OurChangeSetPowerState". Otherwise, we start the ack timer and wait for the stragglers to acknowlege by calling
175 acknowledgePowerChange. We move on to state "OurChangeSetPowerState" when all the stragglers have acknowledged,
176 or when the ack timer expires on all those which didn't acknowledge. In "OurChangeSetPowerState" we call the power-controlling
177 driver to change the power state of the hardware. If it returns saying it has done so, we go on to state "OurChangeWaitForPowerSettle".
178 Otherwise, we have to wait for it, so we set the ack timer and wait. When it calls acknowledgeSetPowerState, or when the
179 ack timer expires, we go on. In "OurChangeWaitForPowerSettle", we look in the power state array to see if there is any settle time required
180 when changing from our current state to the new state. If not, we go right away to "OurChangeNotifyInterestedDriversDidChange". Otherwise, we
181 set the settle timer and wait. When it expires, we move on. In "OurChangeNotifyInterestedDriversDidChange" state, we notify all our interested parties
182 via their powerStateDidChange methods that we have finished changing power state. If they all acknowledge via return
183 code, we move on to "OurChangeFinish". Otherwise we set the ack timer and wait. When they have all acknowledged, or
184 when the ack timer has expired for those that didn't, we move on to "OurChangeFinish", where we remove the used
185 change note from the head of the queue and start the next one if one exists.
187 Parent-initiated changes are more complex in the state machine. First, power going up and power going down are handled
188 differently, so they have different paths throught the state machine. Second, we can acknowledge the parent's notification
189 in two different ways, so each of the parent paths is really two.
191 When the parent calls our powerDomainWillChange method, notifying us that it will lower power in the domain, we decide
192 what state that will put our device in. Then we embark on the state machine path "IOPMParentDownSetPowerState_Immediate"
193 and "kIOPM_ParentDownWaitForPowerSettleAndNotifyDidChange_Immediate", in which we notify interested parties of the upcoming change, instruct our driver to make
194 the change, check for settle time, and notify interested parties of the completed change. If we get to the end of this path without
195 stalling due to an interested party which didn't acknowledge via return code, due to the controlling driver not able to change
196 state right away, or due to a non-zero settling time, then we return IOPMAckImplied to the parent, and we're done with the change.
197 If we do stall in any of those states, we return IOPMWillAckLater to the parent and enter the parallel path "kIOPM_ParentDownSetPowerState_Delayed"
198 "kIOPM_ParentDownWaitForPowerSettle_Delayed", and "kIOPM_ParentDownNotifyDidChangeAndAcknowledgeChange_Delayed", where we continue with the same processing, except that at the end we
199 acknowledge the parent explicitly via acknowledgePowerChange, and we're done with the change.
200 Then when the parent calls us at powerStateDidChange we acknowledging via return code, because we have already made
201 the power change. In any case, when we are done we remove the used change note from the head of the queue and start on the next one.
203 The case of the parent raising power in the domain is handled similarly in that there are parallel paths, one for no-stall
204 that ends in implicit acknowleging the parent, and one that has stalled at least once that ends in explicit acknowledging
205 the parent. This case is different, though in that our device changes state in the second half, after the parent calls
206 powerStateDidChange rather than before, as in the power-lowering case.
208 When the parent calls our powerDomainWillChange method, notifying us that it will raise power in the domain, we acknowledge
209 via return code, because there's really nothing we can do until the power is actually raised in the domain.
210 When the parent calls us at powerStateDidChange, we start by notifying our interested parties. If they all acknowledge via return code,
211 we go on to" kIOPM_ParentUpSetPowerState_Immediate" to instruct the driver to raise its power level. After that, we check for any
212 necessary settling time in "IOPMParentUpWaitForSettleTime_Immediate", and we notify all interested parties that power has changed
213 in "IOPMParentUpNotifyInterestedDriversDidChange_Immediate". If none of these operations stall, we acknowledge the parent via return code, release
214 the change note, and start the next, if there is one. If one of them does stall, we enter the parallel path "kIOPM_ParentUpSetPowerState_Delayed",
215 "kIOPM_ParentUpWaitForSettleTime_Delayed", "kIOPM_ParentUpNotifyInterestedDriversDidChange_Delayed", and "kIOPM_ParentUpAcknowledgePowerChange_Delayed", which ends with
216 our explicit acknowledgement to the parent.
221 const char priv_key
[ ] = "Power Management private data";
222 const char prot_key
[ ] = "Power Management protected data";
225 void IOService::PMinit ( void )
227 if ( ! initialized
) {
229 // make space for our variables
230 pm_vars
= new IOPMprot
;
236 // add pm_vars & priv to the properties
237 setProperty(prot_key
, (OSObject
*) pm_vars
);
238 setProperty(priv_key
, (OSObject
*) priv
);
240 // then initialize them
242 pm_vars
->theNumberOfPowerStates
= 0;
243 priv
->we_are_root
= false;
244 pm_vars
->theControllingDriver
= NULL
;
245 priv
->our_lock
= IOLockAlloc();
246 priv
->flags_lock
= IOLockAlloc();
247 priv
->queue_lock
= IOLockAlloc();
248 pm_vars
->childLock
= IOLockAlloc();
249 pm_vars
->parentLock
= IOLockAlloc();
250 priv
->interestedDrivers
= new IOPMinformeeList
;
251 priv
->interestedDrivers
->initialize();
252 priv
->changeList
= new IOPMchangeNoteList
;
253 priv
->changeList
->initialize();
254 pm_vars
->aggressiveness
= 0;
255 for (unsigned int i
= 0; i
<= kMaxType
; i
++)
257 pm_vars
->current_aggressiveness_values
[i
] = 0;
258 pm_vars
->current_aggressiveness_valid
[i
] = false;
260 pm_vars
->myCurrentState
= 0;
261 priv
->imminentState
= 0;
262 priv
->ourDesiredPowerState
= 0;
263 pm_vars
->parentsCurrentPowerFlags
= 0;
264 pm_vars
->maxCapability
= 0;
265 priv
->driverDesire
= 0;
266 priv
->deviceDesire
= 0;
267 priv
->initial_change
= true;
268 priv
->need_to_become_usable
= false;
269 priv
->previousRequest
= 0;
270 priv
->device_overrides
= false;
271 priv
->machine_state
= kIOPM_Finished
;
272 priv
->timerEventSrc
= NULL
;
273 priv
->clampTimerEventSrc
= NULL
;
274 pm_vars
->PMworkloop
= NULL
;
275 priv
->activityLock
= NULL
;
276 pm_vars
->ourName
= getName();
277 pm_vars
->thePlatform
= getPlatform();
278 pm_vars
->parentsKnowState
= false;
279 assert( pm_vars
->thePlatform
!= 0 );
280 priv
->clampOn
= false;
281 pm_vars
->serialNumber
= 0;
282 pm_vars
->responseFlags
= NULL
;
283 pm_vars
->doNotPowerDown
= true;
284 pm_vars
->PMcommandGate
= NULL
;
285 priv
->ackTimer
= thread_call_allocate((thread_call_func_t
)ack_timer_expired
, (thread_call_param_t
)this);
286 priv
->settleTimer
= thread_call_allocate((thread_call_func_t
)settle_timer_expired
, (thread_call_param_t
)this);
292 //*********************************************************************************
295 // Free up the data created in PMinit, if it exists.
296 //*********************************************************************************
297 void IOService::PMfree ( void )
300 if ( priv
->clampTimerEventSrc
!= NULL
) {
301 getPMworkloop()->removeEventSource(priv
->clampTimerEventSrc
);
302 priv
->clampTimerEventSrc
->release();
303 priv
->clampTimerEventSrc
= NULL
;
305 if ( priv
->timerEventSrc
!= NULL
) {
306 pm_vars
->PMworkloop
->removeEventSource(priv
->timerEventSrc
);
307 priv
->timerEventSrc
->release();
308 priv
->timerEventSrc
= NULL
;
310 if ( priv
->settleTimer
) {
311 thread_call_cancel(priv
->settleTimer
);
312 thread_call_free(priv
->settleTimer
);
313 priv
->settleTimer
= NULL
;
315 if ( priv
->ackTimer
) {
316 thread_call_cancel(priv
->ackTimer
);
317 thread_call_free(priv
->ackTimer
);
318 priv
->ackTimer
= NULL
;
320 if ( priv
->our_lock
) {
321 IOLockFree(priv
->our_lock
);
322 priv
->our_lock
= NULL
;
324 if ( priv
->flags_lock
) {
325 IOLockFree(priv
->flags_lock
);
326 priv
->flags_lock
= NULL
;
328 if ( priv
->activityLock
) {
329 IOLockFree(priv
->activityLock
);
330 priv
->activityLock
= NULL
;
332 priv
->interestedDrivers
->release();
333 priv
->changeList
->release();
334 // remove instance variables
339 if ( pm_vars
->PMcommandGate
) {
340 if(pm_vars
->PMworkloop
)
341 pm_vars
->PMworkloop
->removeEventSource(pm_vars
->PMcommandGate
);
342 pm_vars
->PMcommandGate
->release();
343 pm_vars
->PMcommandGate
= NULL
;
345 if ( pm_vars
->PMworkloop
) {
346 // The work loop object returned from getPMworkLoop() is
347 // never retained, therefore it should not be released.
348 // pm_vars->PMworkloop->release();
349 pm_vars
->PMworkloop
= NULL
;
351 if ( pm_vars
->responseFlags
) {
352 pm_vars
->responseFlags
->release();
353 pm_vars
->responseFlags
= NULL
;
355 // remove instance variables
361 //*********************************************************************************
364 // Disconnect the node from its parents and children in the Power Plane.
365 //*********************************************************************************
366 void IOService::PMstop ( void )
370 IOPowerConnection
* connection
;
371 IOService
* theChild
;
372 IOService
* theParent
;
374 // remove the properties
375 removeProperty(prot_key
);
376 removeProperty(priv_key
);
379 iter
= getParentIterator(gIOPowerPlane
);
383 while ( (next
= iter
->getNextObject()) )
385 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) )
387 theParent
= (IOService
*)connection
->copyParentEntry(gIOPowerPlane
);
390 theParent
->removePowerChild(connection
);
391 theParent
->release();
398 // detach IOConnections
399 detachAbove( gIOPowerPlane
);
403 // no more power state changes
404 pm_vars
->parentsKnowState
= false;
408 iter
= getChildIterator(gIOPowerPlane
);
412 while ( (next
= iter
->getNextObject()) )
414 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) )
416 theChild
= ((IOService
*)(connection
->copyChildEntry(gIOPowerPlane
)));
419 // detach nub from child
420 connection
->detachFromChild(theChild
,gIOPowerPlane
);
423 // detach us from nub
424 detachFromChild(connection
,gIOPowerPlane
);
430 // Remove all interested drivers from the list, including the power
431 // controlling driver.
433 // Usually, the controlling driver and the policy-maker functionality
434 // are implemented by the same object, and without the deregistration,
435 // the object will be holding an extra retain on itself, and cannot
438 if ( priv
&& priv
->interestedDrivers
)
440 IOPMinformee
* informee
;
442 while (( informee
= priv
->interestedDrivers
->firstInList() ))
443 deRegisterInterestedDriver( informee
->whatObject
);
448 //*********************************************************************************
451 // A policy-maker calls its nub here when initializing, to be attached into
452 // the power management hierarchy. The default function is to call the
453 // platform expert, which knows how to do it. This method is overridden
454 // by a nub subclass which may either know how to do it, or may need
455 // to take other action.
457 // This may be the only "power management" method used in a nub,
458 // meaning it may not be initialized for power management.
459 //*********************************************************************************
460 void IOService::joinPMtree ( IOService
* driver
)
462 IOPlatformExpert
* thePlatform
;
464 thePlatform
= getPlatform();
465 assert(thePlatform
!= 0 );
466 thePlatform
->PMRegisterDevice(this,driver
);
470 //*********************************************************************************
473 // Power Managment is informing us that we are the root power domain.
474 // The only difference between us and any other power domain is that
475 // we have no parent and therefore never call it.
476 //*********************************************************************************
477 IOReturn
IOService::youAreRoot ( void )
479 priv
-> we_are_root
= true;
480 pm_vars
->parentsKnowState
= true;
481 attachToParent( getRegistryRoot(),gIOPowerPlane
);
487 //*********************************************************************************
490 // Power Management is informing us who our parent is.
491 // If we have a controlling driver, find out, given our newly-informed
492 // power domain state, what state it would be in, and then tell it
493 // to assume that state.
494 //*********************************************************************************
495 IOReturn
IOService::setPowerParent ( IOPowerConnection
* theParent
, bool stateKnown
, IOPMPowerFlags currentState
)
499 IOPowerConnection
* connection
;
500 unsigned long tempDesire
;
502 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogSetParent
,stateKnown
,currentState
);
504 IOLockLock(pm_vars
->parentLock
);
506 if ( stateKnown
&& ((pm_vars
->PMworkloop
== NULL
) || (pm_vars
->PMcommandGate
== NULL
)) )
508 // we have a path to the root
509 // find out the workloop
511 if ( pm_vars
->PMworkloop
!= NULL
)
513 if ( pm_vars
->PMcommandGate
== NULL
)
515 // and make our command gate
516 pm_vars
->PMcommandGate
= IOCommandGate::commandGate((OSObject
*)this);
517 if ( pm_vars
->PMcommandGate
!= NULL
)
519 pm_vars
->PMworkloop
->addEventSource(pm_vars
->PMcommandGate
);
525 IOLockUnlock(pm_vars
->parentLock
);
527 // set our connection data
528 theParent
->setParentCurrentPowerFlags(currentState
);
529 theParent
->setParentKnowsState(stateKnown
);
531 // combine parent knowledge
532 pm_vars
->parentsKnowState
= true;
533 pm_vars
->parentsCurrentPowerFlags
= 0;
535 iter
= getParentIterator(gIOPowerPlane
);
539 while ( (next
= iter
->getNextObject()) )
541 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) )
543 pm_vars
->parentsKnowState
&= connection
->parentKnowsState();
544 pm_vars
->parentsCurrentPowerFlags
|= connection
->parentCurrentPowerFlags();
550 if ( (pm_vars
->theControllingDriver
!= NULL
) &&
551 (pm_vars
->parentsKnowState
) )
553 pm_vars
->maxCapability
= pm_vars
->theControllingDriver
->maxCapabilityForDomainState(pm_vars
->parentsCurrentPowerFlags
);
554 // initially change into the state we are already in
555 tempDesire
= priv
->deviceDesire
;
556 priv
->deviceDesire
= pm_vars
->theControllingDriver
->initialPowerStateForDomainState(pm_vars
->parentsCurrentPowerFlags
);
557 computeDesiredState();
558 priv
->previousRequest
= 0xffffffff;
560 // put this back like before
561 priv
->deviceDesire
= tempDesire
;
568 //*********************************************************************************
571 // Power Management is informing us who our children are.
572 //*********************************************************************************
573 IOReturn
IOService::addPowerChild ( IOService
* theChild
)
575 IOPowerConnection
*connection
;
580 // we're not a power-managed IOService
581 return IOPMNotYetInitialized
;
584 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogAddChild
,0,0);
586 // Put ourselves into a usable power state.
587 // We must be in an "on" power state, as our children must be able to access
588 // our hardware after joining the power plane.
592 connection
= new IOPowerConnection
;
595 connection
->start(this);
596 connection
->setAwaitingAck(false);
599 attachToChild( connection
,gIOPowerPlane
);
600 connection
->attachToChild( theChild
,gIOPowerPlane
);
601 connection
->release();
603 // tell it the current state of the power domain
604 if ( (pm_vars
->theControllingDriver
== NULL
) ||
605 ! (inPlane(gIOPowerPlane
)) ||
606 ! (pm_vars
->parentsKnowState
) )
608 theChild
->setPowerParent(connection
,false,0);
609 if ( inPlane(gIOPowerPlane
) )
611 for (i
= 0; i
<= kMaxType
; i
++) {
612 if ( pm_vars
->current_aggressiveness_valid
[i
] )
614 theChild
->setAggressiveness (i
, pm_vars
->current_aggressiveness_values
[i
]);
619 theChild
->setPowerParent(connection
,true,pm_vars
->thePowerStates
[pm_vars
->myCurrentState
].outputPowerCharacter
);
620 for (i
= 0; i
<= kMaxType
; i
++)
622 if ( pm_vars
->current_aggressiveness_valid
[i
] )
624 theChild
->setAggressiveness (i
, pm_vars
->current_aggressiveness_values
[i
]);
627 // catch it up if change is in progress
628 add_child_to_active_change(connection
);
635 //*********************************************************************************
638 //*********************************************************************************
639 IOReturn
IOService::removePowerChild ( IOPowerConnection
* theNub
)
641 IORegistryEntry
*theChild
;
644 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogRemoveChild
,0,0);
648 // detach nub from child
649 theChild
= theNub
->copyChildEntry(gIOPowerPlane
);
652 theNub
->detachFromChild(theChild
, gIOPowerPlane
);
655 // detach from the nub
656 detachFromChild(theNub
,gIOPowerPlane
);
658 // are we awaiting an ack from this child?
659 if ( theNub
->getAwaitingAck() )
661 // yes, pretend we got one
662 theNub
->setAwaitingAck(false);
663 if ( acquire_lock() )
665 if (priv
->head_note_pendingAcks
!= 0 )
667 // that's one fewer ack to worry about
668 priv
->head_note_pendingAcks
-= 1;
670 if ( priv
->head_note_pendingAcks
== 0 )
672 // yes, stop the timer
674 IOUnlock(priv
->our_lock
);
675 // and now we can continue our power change
678 IOUnlock(priv
->our_lock
);
681 IOUnlock(priv
->our_lock
);
688 // if not fully initialized
689 if ( (pm_vars
->theControllingDriver
== NULL
) ||
690 !(inPlane(gIOPowerPlane
)) ||
691 !(pm_vars
->parentsKnowState
) )
697 // Perhaps the departing child was holding up idle or system sleep - we need to re-evaluate our
698 // childrens' requests. Clear and re-calculate our kIOPMChildClamp and kIOPMChildClamp2 bits.
699 rebuildChildClampBits();
704 iter
= getChildIterator(gIOPowerPlane
);
705 if ( !iter
|| !iter
->getNextObject() )
707 // paired to match the makeUsable() call in addPowerChild()
708 changePowerStateToPriv(0);
710 if(iter
) iter
->release();
713 // this may be different now
714 computeDesiredState();
715 // change state if we can now tolerate lower power
722 //*********************************************************************************
723 // registerPowerDriver
725 // A driver has called us volunteering to control power to our device.
726 // If the power state array it provides is richer than the one we already
727 // know about (supplied by an earlier volunteer), then accept the offer.
728 // Notify all interested parties of our power state, which we now know.
729 //*********************************************************************************
731 IOReturn
IOService::registerPowerDriver ( IOService
* controllingDriver
, IOPMPowerState
* powerStates
, unsigned long numberOfStates
)
734 unsigned long tempDesire
;
736 if ( (numberOfStates
> pm_vars
->theNumberOfPowerStates
)
737 && (numberOfStates
> 1) )
739 if ( priv
->changeList
->currentChange() == -1 )
741 if ( controllingDriver
!= NULL
)
743 if ( numberOfStates
<= IOPMMaxPowerStates
)
745 switch ( powerStates
[0].version
)
748 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogControllingDriver
,
749 (unsigned long)numberOfStates
, (unsigned long)powerStates
[0].version
);
750 for ( i
= 0; i
< numberOfStates
; i
++ )
752 pm_vars
->thePowerStates
[i
] = powerStates
[i
];
756 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogControllingDriver
,
757 (unsigned long) numberOfStates
,(unsigned long) powerStates
[0].version
);
758 for ( i
= 0; i
< numberOfStates
; i
++ )
760 pm_vars
->thePowerStates
[i
].version
= powerStates
[i
].version
;
761 pm_vars
->thePowerStates
[i
].capabilityFlags
= powerStates
[i
].capabilityFlags
;
762 pm_vars
->thePowerStates
[i
].outputPowerCharacter
= powerStates
[i
].outputPowerCharacter
;
763 pm_vars
->thePowerStates
[i
].inputPowerRequirement
= powerStates
[i
].inputPowerRequirement
;
764 pm_vars
->thePowerStates
[i
].staticPower
= powerStates
[i
].staticPower
;
765 pm_vars
->thePowerStates
[i
].unbudgetedPower
= powerStates
[i
].unbudgetedPower
;
766 pm_vars
->thePowerStates
[i
].powerToAttain
= powerStates
[i
].powerToAttain
;
767 pm_vars
->thePowerStates
[i
].timeToAttain
= powerStates
[i
].timeToAttain
;
768 pm_vars
->thePowerStates
[i
].settleUpTime
= powerStates
[i
].settleUpTime
;
769 pm_vars
->thePowerStates
[i
].timeToLower
= powerStates
[i
].timeToLower
;
770 pm_vars
->thePowerStates
[i
].settleDownTime
= powerStates
[i
].settleDownTime
;
771 pm_vars
->thePowerStates
[i
].powerDomainBudget
= powerStates
[i
].powerDomainBudget
;
775 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogControllingDriverErr1
,
776 (unsigned long)powerStates
[0].version
,0);
780 // make a mask of all the character bits we know about
781 pm_vars
->myCharacterFlags
= 0;
782 for ( i
= 0; i
< numberOfStates
; i
++ ) {
783 pm_vars
->myCharacterFlags
|= pm_vars
->thePowerStates
[i
].outputPowerCharacter
;
786 pm_vars
->theNumberOfPowerStates
= numberOfStates
;
787 pm_vars
->theControllingDriver
= controllingDriver
;
788 if ( priv
->interestedDrivers
->findItem(controllingDriver
) == NULL
)
790 // register it as interested, unless already done
791 registerInterestedDriver (controllingDriver
);
793 if ( priv
->need_to_become_usable
) {
794 priv
->need_to_become_usable
= false;
795 priv
->deviceDesire
= pm_vars
->theNumberOfPowerStates
- 1;
798 if ( inPlane(gIOPowerPlane
) &&
799 (pm_vars
->parentsKnowState
) ) {
800 pm_vars
->maxCapability
= pm_vars
->theControllingDriver
->maxCapabilityForDomainState(pm_vars
->parentsCurrentPowerFlags
);
801 // initially change into the state we are already in
802 tempDesire
= priv
->deviceDesire
;
803 priv
->deviceDesire
= pm_vars
->theControllingDriver
->initialPowerStateForDomainState(pm_vars
->parentsCurrentPowerFlags
);
804 computeDesiredState();
806 // put this back like before
807 priv
->deviceDesire
= tempDesire
;
810 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogControllingDriverErr2
,(unsigned long)numberOfStates
,0);
813 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogControllingDriverErr4
,0,0);
818 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogControllingDriverErr5
,(unsigned long)numberOfStates
,0);
823 //*********************************************************************************
824 // registerInterestedDriver
826 // Add the caller to our list of interested drivers and return our current
827 // power state. If we don't have a power-controlling driver yet, we will
828 // call this interested driver again later when we do get a driver and find
829 // out what the current power state of the device is.
830 //*********************************************************************************
832 IOPMPowerFlags
IOService::registerInterestedDriver ( IOService
* theDriver
)
834 IOPMinformee
*newInformee
;
835 IOPMPowerFlags futureCapability
;
837 if (theDriver
== NULL
) {
841 // make new driver node
842 newInformee
= new IOPMinformee
;
843 newInformee
->initialize(theDriver
);
844 // add it to list of drivers
845 priv
->interestedDrivers
->addToList(newInformee
);
847 if ( (pm_vars
->theControllingDriver
== NULL
) ||
848 !(inPlane(gIOPowerPlane
)) ||
849 !(pm_vars
->parentsKnowState
) )
851 // can't tell it a state yet
852 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogInterestedDriver
,IOPMNotPowerManaged
,0);
853 return IOPMNotPowerManaged
;
856 // can we notify new driver of a change in progress?
857 switch (priv
->machine_state
) {
858 case kIOPM_OurChangeSetPowerState
:
859 case kIOPM_OurChangeFinish
:
860 case kIOPM_ParentDownSetPowerState_Delayed
:
861 case kIOPM_ParentDownAcknowledgeChange_Delayed
:
862 case kIOPM_ParentUpSetPowerState_Delayed
:
863 case kIOPM_ParentUpAcknowledgePowerChange_Delayed
:
864 // yes, remember what we tell it
865 futureCapability
= priv
->head_note_capabilityFlags
;
866 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogInterestedDriver
,(unsigned long)futureCapability
,1);
868 add_driver_to_active_change(newInformee
);
869 // and return the same thing
870 return futureCapability
;
873 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogInterestedDriver
,
874 (unsigned long) pm_vars
->thePowerStates
[pm_vars
->myCurrentState
].capabilityFlags
,2);
876 // no, return current capability
877 return pm_vars
->thePowerStates
[pm_vars
->myCurrentState
].capabilityFlags
;
881 //*********************************************************************************
882 // deRegisterInterestedDriver
884 //*********************************************************************************
885 IOReturn
IOService::deRegisterInterestedDriver ( IOService
* theDriver
)
887 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogRemoveDriver
,0,0);
889 // remove the departing driver
890 priv
->interestedDrivers
->removeFromList(theDriver
);
896 //*********************************************************************************
897 // acknowledgePowerChange
899 // After we notified one of the interested drivers or a power-domain child
900 // of an impending change in power, it has called to say it is now
901 // prepared for the change. If this object is the last to
902 // acknowledge this change, we take whatever action we have been waiting
904 // That may include acknowledging to our parent. In this case, we do it
905 // last of all to insure that this doesn't cause the parent to call us some-
906 // where else and alter data we are relying on here (like the very existance
907 // of a "current change note".)
908 //*********************************************************************************
910 IOReturn
IOService::acknowledgePowerChange ( IOService
* whichObject
)
912 IOPMinformee
*ackingObject
;
913 unsigned long childPower
= kIOPMUnknown
;
916 // one of our interested drivers?
917 ackingObject
= priv
->interestedDrivers
->findItem(whichObject
);
918 if ( ackingObject
== NULL
)
920 if ( ! isChild(whichObject
,gIOPowerPlane
) )
922 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogAcknowledgeErr1
,0,0);
923 //kprintf("errant driver: %s\n",whichObject->getName());
927 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogChildAcknowledge
,priv
->head_note_pendingAcks
,0);
930 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogDriverAcknowledge
,priv
->head_note_pendingAcks
,0);
933 if (! acquire_lock() )
938 if (priv
->head_note_pendingAcks
!= 0 )
940 // yes, make sure we're expecting acks
941 if ( ackingObject
!= NULL
)
943 // it's an interested driver
944 // make sure we're expecting this ack
945 if ( ackingObject
->timer
!= 0 )
948 ackingObject
->timer
= 0;
949 // that's one fewer to worry about
950 priv
->head_note_pendingAcks
-= 1;
952 if ( priv
->head_note_pendingAcks
== 0 )
954 // yes, stop the timer
956 IOUnlock(priv
->our_lock
);
957 // and now we can continue
962 // this driver has already acked
963 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogAcknowledgeErr2
,0,0);
964 //kprintf("errant driver: %s\n",whichObject->getName());
968 // make sure we're expecting this ack
969 if ( ((IOPowerConnection
*)whichObject
)->getAwaitingAck() )
971 // that's one fewer to worry about
972 priv
->head_note_pendingAcks
-= 1;
973 ((IOPowerConnection
*)whichObject
)->setAwaitingAck(false);
974 theChild
= (IOService
*)whichObject
->copyChildEntry(gIOPowerPlane
);
977 childPower
= theChild
->currentPowerConsumption();
980 if ( childPower
== kIOPMUnknown
)
982 pm_vars
->thePowerStates
[priv
->head_note_state
].staticPower
= kIOPMUnknown
;
984 if ( pm_vars
->thePowerStates
[priv
->head_note_state
].staticPower
!= kIOPMUnknown
)
986 pm_vars
->thePowerStates
[priv
->head_note_state
].staticPower
+= childPower
;
990 if ( priv
->head_note_pendingAcks
== 0 ) {
991 // yes, stop the timer
993 IOUnlock(priv
->our_lock
);
994 // and now we can continue
1001 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogAcknowledgeErr3
,0,0); // not expecting anybody to ack
1002 //kprintf("errant driver: %s\n",whichObject->getName());
1004 IOUnlock(priv
->our_lock
);
1008 //*********************************************************************************
1009 // acknowledgeSetPowerState
1011 // After we instructed our controlling driver to change power states,
1012 // it has called to say it has finished doing so.
1013 // We continue to process the power state change.
1014 //*********************************************************************************
1016 IOReturn
IOService::acknowledgeSetPowerState ( void )
1018 if (!acquire_lock())
1021 IOReturn timer
= priv
->driver_timer
;
1022 if ( timer
== -1 ) {
1023 // driver is acking instead of using return code
1024 OUR_PMLog(kPMLogDriverAcknowledgeSet
, (UInt32
) this, timer
);
1025 priv
->driver_timer
= 0;
1027 else if ( timer
> 0 ) { // are we expecting this?
1028 // yes, stop the timer
1030 priv
->driver_timer
= 0;
1031 OUR_PMLog(kPMLogDriverAcknowledgeSet
, (UInt32
) this, timer
);
1032 IOUnlock(priv
->our_lock
);
1036 // not expecting this
1037 OUR_PMLog(kPMLogAcknowledgeErr4
, (UInt32
) this, 0);
1040 IOUnlock(priv
->our_lock
);
1045 //*********************************************************************************
1048 // Either the controlling driver has called acknowledgeSetPowerState
1049 // or the acknowledgement timer has expired while waiting for that.
1050 // We carry on processing the current change note.
1051 //*********************************************************************************
1053 void IOService::driver_acked ( void )
1055 switch (priv
->machine_state
) {
1056 case kIOPM_OurChangeWaitForPowerSettle
:
1057 OurChangeWaitForPowerSettle();
1059 case kIOPM_ParentDownWaitForPowerSettle_Delayed
:
1060 ParentDownWaitForPowerSettle_Delayed();
1062 case kIOPM_ParentUpWaitForSettleTime_Delayed
:
1063 ParentUpWaitForSettleTime_Delayed();
1069 //*********************************************************************************
1070 // powerDomainWillChangeTo
1072 // Called by the power-hierarchy parent notifying of a new power state
1073 // in the power domain.
1074 // We enqueue a parent power-change to our queue of power changes.
1075 // This may or may not cause us to change power, depending on what
1076 // kind of change is occuring in the domain.
1077 //*********************************************************************************
1079 IOReturn
IOService::powerDomainWillChangeTo ( IOPMPowerFlags newPowerStateFlags
, IOPowerConnection
* whichParent
)
1083 IOPowerConnection
*connection
;
1084 unsigned long newStateNumber
;
1085 IOPMPowerFlags combinedPowerFlags
;
1087 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogWillChange
,(unsigned long)newPowerStateFlags
,0);
1089 if ( ! inPlane(gIOPowerPlane
) )
1092 return IOPMAckImplied
;
1095 IOLockLock(pm_vars
->parentLock
);
1097 if ( (pm_vars
->PMworkloop
== NULL
) || (pm_vars
->PMcommandGate
== NULL
) )
1099 // we have a path to the root
1101 // so find out the workloop
1102 if ( pm_vars
->PMworkloop
!= NULL
)
1104 // and make our command gate
1105 if ( pm_vars
->PMcommandGate
== NULL
)
1107 pm_vars
->PMcommandGate
= IOCommandGate::commandGate((OSObject
*)this);
1108 if ( pm_vars
->PMcommandGate
!= NULL
)
1110 pm_vars
->PMworkloop
->addEventSource(pm_vars
->PMcommandGate
);
1116 IOLockUnlock(pm_vars
->parentLock
);
1118 // combine parents' power states
1119 // to determine our maximum state within the new power domain
1120 combinedPowerFlags
= 0;
1122 iter
= getParentIterator(gIOPowerPlane
);
1126 while ( (next
= iter
->getNextObject()) )
1128 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) )
1130 if ( connection
== whichParent
){
1131 combinedPowerFlags
|= newPowerStateFlags
;
1133 combinedPowerFlags
|= connection
->parentCurrentPowerFlags();
1140 if ( pm_vars
->theControllingDriver
== NULL
)
1142 // we can't take any more action
1143 return IOPMAckImplied
;
1145 newStateNumber
= pm_vars
->theControllingDriver
->maxCapabilityForDomainState(combinedPowerFlags
);
1147 return enqueuePowerChange(IOPMParentInitiated
| IOPMDomainWillChange
,
1148 newStateNumber
,combinedPowerFlags
,whichParent
,newPowerStateFlags
);
1152 //*********************************************************************************
1153 // powerDomainDidChangeTo
1155 // Called by the power-hierarchy parent after the power state of the power domain
1156 // has settled at a new level.
1157 // We enqueue a parent power-change to our queue of power changes.
1158 // This may or may not cause us to change power, depending on what
1159 // kind of change is occuring in the domain.
1160 //*********************************************************************************
1162 IOReturn
IOService::powerDomainDidChangeTo ( IOPMPowerFlags newPowerStateFlags
, IOPowerConnection
* whichParent
)
1164 unsigned long newStateNumber
;
1166 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogDidChange
,newPowerStateFlags
,0);
1168 setParentInfo(newPowerStateFlags
,whichParent
);
1170 if ( pm_vars
->theControllingDriver
== NULL
) {
1171 return IOPMAckImplied
;
1174 newStateNumber
= pm_vars
->theControllingDriver
->maxCapabilityForDomainState(pm_vars
->parentsCurrentPowerFlags
);
1175 // tell interested parties about it
1176 return enqueuePowerChange(IOPMParentInitiated
| IOPMDomainDidChange
,
1177 newStateNumber
,pm_vars
->parentsCurrentPowerFlags
,whichParent
,0);
1181 //*********************************************************************************
1184 // Set our connection data for one specific parent, and then combine all the parent
1186 //*********************************************************************************
1188 void IOService::setParentInfo ( IOPMPowerFlags newPowerStateFlags
, IOPowerConnection
* whichParent
)
1192 IOPowerConnection
*connection
;
1194 // set our connection data
1195 whichParent
->setParentCurrentPowerFlags(newPowerStateFlags
);
1196 whichParent
->setParentKnowsState(true);
1198 IOLockLock(pm_vars
->parentLock
);
1200 // recompute our parent info
1201 pm_vars
->parentsCurrentPowerFlags
= 0;
1202 pm_vars
->parentsKnowState
= true;
1204 iter
= getParentIterator(gIOPowerPlane
);
1208 while ( (next
= iter
->getNextObject()) )
1210 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) )
1212 pm_vars
->parentsKnowState
&= connection
->parentKnowsState();
1213 pm_vars
->parentsCurrentPowerFlags
|= connection
->parentCurrentPowerFlags();
1218 IOLockUnlock(pm_vars
->parentLock
);
1221 //*********************************************************************************
1222 // rebuildChildClampBits
1224 // The ChildClamp bits (kIOPMChildClamp & kIOPMChildClamp2) in our capabilityFlags
1225 // indicate that one of our children (or grandchildren or great-grandchildren or ...)
1226 // doesn't support idle or system sleep in its current state. Since we don't track the
1227 // origin of each bit, every time any child changes state we have to clear these bits
1228 // and rebuild them.
1229 //*********************************************************************************
1231 void IOService::rebuildChildClampBits(void)
1236 IOPowerConnection
*connection
;
1239 // A child's desires has changed. We need to rebuild the child-clamp bits in our
1240 // power state array. Start by clearing the bits in each power state.
1242 for ( i
= 0; i
< pm_vars
->theNumberOfPowerStates
; i
++ )
1244 pm_vars
->thePowerStates
[i
].capabilityFlags
&= ~(kIOPMChildClamp
| kIOPMChildClamp2
);
1247 // Now loop through the children. When we encounter the calling child, save
1248 // the computed state as this child's desire. And while we're at it, set the ChildClamp bits
1249 // in any of our states that some child has requested with clamp on.
1251 iter
= getChildIterator(gIOPowerPlane
);
1255 while ( (next
= iter
->getNextObject()) )
1257 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) )
1259 if ( connection
->getPreventIdleSleepFlag() )
1260 pm_vars
->thePowerStates
[connection
->getDesiredDomainState()].capabilityFlags
|= kIOPMChildClamp
;
1261 if ( connection
->getPreventSystemSleepFlag() )
1262 pm_vars
->thePowerStates
[connection
->getDesiredDomainState()].capabilityFlags
|= kIOPMChildClamp2
;
1271 //*********************************************************************************
1272 // requestPowerDomainState
1274 // The kIOPMPreventIdleSleep and/or kIOPMPreventIdleSleep bits may be be set in the parameter.
1275 // It is not considered part of the state specification.
1276 //*********************************************************************************
1277 IOReturn
IOService::requestPowerDomainState ( IOPMPowerFlags desiredState
, IOPowerConnection
* whichChild
, unsigned long specification
)
1280 unsigned long computedState
;
1281 unsigned long theDesiredState
= desiredState
& ~(kIOPMPreventIdleSleep
| kIOPMPreventSystemSleep
);
1284 IOPowerConnection
*connection
;
1286 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogRequestDomain
,
1287 (unsigned long)desiredState
,(unsigned long)specification
);
1289 if ( pm_vars
->theControllingDriver
== NULL
)
1291 return IOPMNotYetInitialized
;
1294 switch (specification
) {
1295 case IOPMLowestState
:
1297 while ( i
< pm_vars
->theNumberOfPowerStates
)
1299 if ( ( pm_vars
->thePowerStates
[i
].outputPowerCharacter
& theDesiredState
) == (theDesiredState
& pm_vars
->myCharacterFlags
) )
1305 if ( i
>= pm_vars
->theNumberOfPowerStates
)
1307 return IOPMNoSuchState
;
1311 case IOPMNextLowerState
:
1312 i
= pm_vars
->myCurrentState
- 1;
1313 while ( (int) i
>= 0 )
1315 if ( ( pm_vars
->thePowerStates
[i
].outputPowerCharacter
& theDesiredState
) == (theDesiredState
& pm_vars
->myCharacterFlags
) )
1323 return IOPMNoSuchState
;
1327 case IOPMHighestState
:
1328 i
= pm_vars
->theNumberOfPowerStates
;
1329 while ( (int) i
>= 0 )
1332 if ( ( pm_vars
->thePowerStates
[i
].outputPowerCharacter
& theDesiredState
) == (theDesiredState
& pm_vars
->myCharacterFlags
) )
1339 return IOPMNoSuchState
;
1343 case IOPMNextHigherState
:
1344 i
= pm_vars
->myCurrentState
+ 1;
1345 while ( i
< pm_vars
->theNumberOfPowerStates
)
1347 if ( ( pm_vars
->thePowerStates
[i
].outputPowerCharacter
& theDesiredState
) == (theDesiredState
& pm_vars
->myCharacterFlags
) )
1353 if ( i
== pm_vars
->theNumberOfPowerStates
)
1355 return IOPMNoSuchState
;
1360 return IOPMBadSpecification
;
1365 IOLockLock(pm_vars
->childLock
);
1367 // Now loop through the children. When we encounter the calling child, save
1368 // the computed state as this child's desire.
1369 iter
= getChildIterator(gIOPowerPlane
);
1373 while ( (next
= iter
->getNextObject()) )
1375 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) )
1377 if ( connection
== whichChild
)
1379 connection
->setDesiredDomainState(computedState
);
1380 connection
->setPreventIdleSleepFlag(desiredState
& kIOPMPreventIdleSleep
);
1381 connection
->setPreventSystemSleepFlag(desiredState
& kIOPMPreventSystemSleep
);
1382 connection
->setChildHasRequestedPower();
1389 // Since a child's power requirements may have changed, clear and rebuild
1390 // kIOPMChildClamp and kIOPMChildClamp2 (idle and system sleep clamps)
1391 rebuildChildClampBits();
1393 IOLockUnlock(pm_vars
->childLock
);
1395 // this may be different now
1396 computeDesiredState();
1398 if ( inPlane(gIOPowerPlane
) &&
1399 (pm_vars
->parentsKnowState
) ) {
1400 // change state if all children can now tolerate lower power
1404 // are we clamped on, waiting for this child?
1405 if ( priv
->clampOn
) {
1406 // yes, remove the clamp
1407 priv
->clampOn
= false;
1408 changePowerStateToPriv(0);
1415 //*********************************************************************************
1416 // temporaryPowerClampOn
1418 // A power domain wants to clamp its power on till it has children which
1419 // will thendetermine the power domain state.
1421 // We enter the highest state until addPowerChild is called.
1422 //*********************************************************************************
1424 IOReturn
IOService::temporaryPowerClampOn ( void )
1426 priv
->clampOn
= true;
1432 //*********************************************************************************
1435 // Some client of our device is asking that we become usable. Although
1436 // this has not come from a subclassed device object, treat it exactly
1437 // as if it had. In this way, subsequent requests for lower power from
1438 // a subclassed device object will pre-empt this request.
1440 // We treat this as a subclass object request to switch to the
1441 // highest power state.
1442 //*********************************************************************************
1444 IOReturn
IOService::makeUsable ( void )
1446 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogMakeUsable
,0,0);
1448 if ( pm_vars
->theControllingDriver
== NULL
)
1450 priv
->need_to_become_usable
= true;
1453 priv
->deviceDesire
= pm_vars
->theNumberOfPowerStates
- 1;
1454 computeDesiredState();
1455 if ( inPlane(gIOPowerPlane
) && (pm_vars
->parentsKnowState
) )
1457 return changeState();
1463 //*********************************************************************************
1464 // currentCapability
1466 //*********************************************************************************
1468 IOPMPowerFlags
IOService::currentCapability ( void )
1470 if ( pm_vars
->theControllingDriver
== NULL
)
1474 return pm_vars
->thePowerStates
[pm_vars
->myCurrentState
].capabilityFlags
;
1479 //*********************************************************************************
1480 // changePowerStateTo
1482 // For some reason, our power-controlling driver has decided it needs to change
1483 // power state. We enqueue the power change so that appropriate parties
1484 // will be notified, and then we will instruct the driver to make the change.
1485 //*********************************************************************************
1487 IOReturn
IOService::changePowerStateTo ( unsigned long ordinal
)
1489 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogChangeStateTo
,ordinal
,0);
1491 if ( ordinal
>= pm_vars
->theNumberOfPowerStates
)
1493 return IOPMParameterError
;
1495 priv
->driverDesire
= ordinal
;
1496 computeDesiredState();
1497 if ( inPlane(gIOPowerPlane
) && (pm_vars
->parentsKnowState
) )
1499 return changeState();
1505 //*********************************************************************************
1506 // changePowerStateToPriv
1508 // For some reason, a subclassed device object has decided it needs to change
1509 // power state. We enqueue the power change so that appropriate parties
1510 // will be notified, and then we will instruct the driver to make the change.
1511 //*********************************************************************************
1513 IOReturn
IOService::changePowerStateToPriv ( unsigned long ordinal
)
1515 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogChangeStateToPriv
,ordinal
,0);
1517 if ( pm_vars
->theControllingDriver
== NULL
)
1519 return IOPMNotYetInitialized
;
1521 if ( ordinal
>= pm_vars
->theNumberOfPowerStates
)
1523 return IOPMParameterError
;
1525 priv
->deviceDesire
= ordinal
;
1526 computeDesiredState();
1527 if ( inPlane(gIOPowerPlane
) && (pm_vars
->parentsKnowState
) )
1529 return changeState();
1536 //*********************************************************************************
1537 // computeDesiredState
1539 //*********************************************************************************
1541 void IOService::computeDesiredState ( void )
1545 IOPowerConnection
*connection
;
1546 unsigned long newDesiredState
= 0;
1548 // Compute the maximum of our children's desires, our controlling driver's desire, and the subclass device's desire.
1549 if ( ! priv
->device_overrides
)
1551 iter
= getChildIterator(gIOPowerPlane
);
1555 while ( (next
= iter
->getNextObject()) )
1557 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) )
1559 if ( connection
->getDesiredDomainState() > newDesiredState
)
1561 newDesiredState
= connection
->getDesiredDomainState();
1568 if ( priv
->driverDesire
> newDesiredState
)
1570 newDesiredState
= priv
->driverDesire
;
1574 if ( priv
->deviceDesire
> newDesiredState
)
1576 newDesiredState
= priv
->deviceDesire
;
1579 priv
->ourDesiredPowerState
= newDesiredState
;
1583 //*********************************************************************************
1586 // A subclass object, our controlling driver, or a power domain child
1587 // has asked for a different power state. Here we compute what new
1588 // state we should enter and enqueue the change (or start it).
1589 //*********************************************************************************
1591 IOReturn
IOService::changeState ( void )
1593 // if not fully initialized
1594 if ( (pm_vars
->theControllingDriver
== NULL
) ||
1595 !(inPlane(gIOPowerPlane
)) ||
1596 !(pm_vars
->parentsKnowState
) )
1598 // we can do no more
1602 return enqueuePowerChange(IOPMWeInitiated
,priv
->ourDesiredPowerState
,0,0,0);
1606 //*********************************************************************************
1607 // currentPowerConsumption
1609 //*********************************************************************************
1611 unsigned long IOService::currentPowerConsumption ( void )
1613 if ( pm_vars
->theControllingDriver
== NULL
)
1615 return kIOPMUnknown
;
1617 if ( pm_vars
->thePowerStates
[pm_vars
->myCurrentState
].capabilityFlags
& kIOPMStaticPowerValid
)
1619 return pm_vars
->thePowerStates
[pm_vars
->myCurrentState
].staticPower
;
1621 return kIOPMUnknown
;
1624 //*********************************************************************************
1627 // The activity tickle with parameter kIOPMSubclassPolicyis not handled
1628 // here and should have been intercepted by the subclass.
1629 // The tickle with parameter kIOPMSuperclassPolicy1 causes the activity
1630 // flag to be set, and the device state checked. If the device has been
1631 // powered down, it is powered up again.
1632 //*********************************************************************************
1634 bool IOService::activityTickle ( unsigned long type
, unsigned long stateNumber
)
1636 IOPMrootDomain
*pmRootDomain
;
1637 AbsoluteTime uptime
;
1639 if ( type
== kIOPMSuperclassPolicy1
)
1641 if ( pm_vars
->theControllingDriver
== NULL
)
1646 if( priv
->activityLock
== NULL
)
1648 priv
->activityLock
= IOLockAlloc();
1651 IOTakeLock(priv
->activityLock
);
1652 priv
->device_active
= true;
1654 clock_get_uptime(&uptime
);
1655 priv
->device_active_timestamp
= uptime
;
1657 if ( pm_vars
->myCurrentState
>= stateNumber
)
1659 IOUnlock(priv
->activityLock
);
1662 IOUnlock(priv
->activityLock
);
1664 // Transfer execution to the PM workloop
1665 if( (pmRootDomain
= getPMRootDomain()) )
1666 pmRootDomain
->unIdleDevice(this, stateNumber
);
1673 //*********************************************************************************
1676 // A child is calling to get a pointer to the Power Management workloop.
1677 // We got it or get it from one of our parents.
1678 //*********************************************************************************
1680 IOWorkLoop
* IOService::getPMworkloop ( void )
1685 if ( ! inPlane(gIOPowerPlane
) )
1689 // we have no workloop yet
1690 if ( pm_vars
->PMworkloop
== NULL
)
1692 nub
= (IOService
*)copyParentEntry(gIOPowerPlane
);
1695 parent
= (IOService
*)nub
->copyParentEntry(gIOPowerPlane
);
1697 // ask one of our parents for the workloop
1700 pm_vars
->PMworkloop
= parent
->getPMworkloop();
1705 return pm_vars
->PMworkloop
;
1709 //*********************************************************************************
1710 // setIdleTimerPeriod
1712 // A subclass policy-maker is going to use our standard idleness
1713 // detection service. Make a command queue and an idle timer and
1714 // connect them to the power management workloop. Finally,
1716 //*********************************************************************************
1718 IOReturn
IOService::setIdleTimerPeriod ( unsigned long period
)
1720 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMsetIdleTimerPeriod
,period
, 0);
1722 priv
->idle_timer_period
= period
;
1726 if ( getPMworkloop() == NULL
)
1728 return kIOReturnError
;
1731 // make the timer event
1732 if ( priv
->timerEventSrc
== NULL
)
1734 priv
->timerEventSrc
= IOTimerEventSource::timerEventSource(this,
1735 PM_idle_timer_expired
);
1736 if ((!priv
->timerEventSrc
) ||
1737 (pm_vars
->PMworkloop
->addEventSource(priv
->timerEventSrc
) != kIOReturnSuccess
) )
1739 return kIOReturnError
;
1743 if ( priv
->activityLock
== NULL
)
1745 priv
->activityLock
= IOLockAlloc();
1748 start_PM_idle_timer();
1753 //******************************************************************************
1756 // Returns how many "seconds from now" the device should idle into its
1757 // next lowest power state.
1758 //******************************************************************************
1759 SInt32
IOService::nextIdleTimeout(
1760 AbsoluteTime currentTime
,
1761 AbsoluteTime lastActivity
,
1762 unsigned int powerState
)
1769 // Calculate time difference using funky macro from clock.h.
1770 delta
= currentTime
;
1771 SUB_ABSOLUTETIME(&delta
, &lastActivity
);
1773 // Figure it in seconds.
1774 absolutetime_to_nanoseconds(delta
, &delta_ns
);
1775 delta_secs
= (SInt32
)(delta_ns
/ NSEC_PER_SEC
);
1777 // Be paranoid about delta somehow exceeding timer period.
1778 if (delta_secs
< (int) priv
->idle_timer_period
)
1779 delay_secs
= (int) priv
->idle_timer_period
- delta_secs
;
1781 delay_secs
= (int) priv
->idle_timer_period
;
1783 return (SInt32
)delay_secs
;
1786 //******************************************************************************
1787 // start_PM_idle_timer
1789 // The parameter is a pointer to us. Use it to call our timeout method.
1790 //******************************************************************************
1791 void IOService::start_PM_idle_timer ( void )
1793 static const int maxTimeout
= 100000;
1794 static const int minTimeout
= 1;
1795 AbsoluteTime uptime
;
1798 IOLockLock(priv
->activityLock
);
1800 clock_get_uptime(&uptime
);
1802 // Subclasses may modify idle sleep algorithm
1803 idle_in
= nextIdleTimeout(uptime
,
1804 priv
->device_active_timestamp
,
1805 pm_vars
->myCurrentState
);
1807 // Check for out-of range responses
1808 if(idle_in
> maxTimeout
)
1810 // use standard implementation
1811 idle_in
= IOService::nextIdleTimeout(uptime
,
1812 priv
->device_active_timestamp
,
1813 pm_vars
->myCurrentState
);
1814 } else if(idle_in
< minTimeout
) {
1819 priv
->timerEventSrc
->setTimeout(idle_in
, NSEC_PER_SEC
);
1821 IOLockUnlock(priv
->activityLock
);
1826 //*********************************************************************************
1827 // PM_idle_timer_expired
1829 // The parameter is a pointer to us. Use it to call our timeout method.
1830 //*********************************************************************************
1832 void PM_idle_timer_expired(OSObject
* ourSelves
, IOTimerEventSource
*)
1834 ((IOService
*)ourSelves
)->PM_idle_timer_expiration();
1838 //*********************************************************************************
1839 // PM_idle_timer_expiration
1841 // The idle timer has expired. If there has been activity since the last
1842 // expiration, just restart the timer and return. If there has not been
1843 // activity, switch to the next lower power state and restart the timer.
1844 //*********************************************************************************
1846 void IOService::PM_idle_timer_expiration ( void )
1848 if ( ! initialized
)
1854 if ( priv
->idle_timer_period
> 0 )
1856 IOTakeLock(priv
->activityLock
);
1857 if ( priv
->device_active
)
1859 priv
->device_active
= false;
1860 IOUnlock(priv
->activityLock
);
1861 start_PM_idle_timer();
1864 if ( pm_vars
->myCurrentState
> 0 )
1866 IOUnlock(priv
->activityLock
);
1867 changePowerStateToPriv(pm_vars
->myCurrentState
- 1);
1868 start_PM_idle_timer();
1871 IOUnlock(priv
->activityLock
);
1872 start_PM_idle_timer();
1877 // **********************************************************************************
1880 // We are un-idling a device due to its activity tickle. This routine runs on the
1881 // PM workloop, and is initiated by IOService::activityTickle.
1882 // We process all activityTickle state requests on the list.
1883 // **********************************************************************************
1884 void IOService::command_received ( void *statePtr
, void *, void * , void * )
1886 unsigned long stateNumber
;
1888 stateNumber
= (unsigned long)statePtr
;
1890 // If not initialized, we're unloading
1891 if ( ! initialized
) return;
1893 if ( (pm_vars
->myCurrentState
< stateNumber
) &&
1894 (priv
->imminentState
< stateNumber
) )
1896 changePowerStateToPriv(stateNumber
);
1898 // After we raise our state, re-schedule the idle timer.
1899 if(priv
->timerEventSrc
)
1900 start_PM_idle_timer();
1905 //*********************************************************************************
1906 // setAggressiveness
1908 // Pass on the input parameters to all power domain children. All those which are
1909 // power domains will pass it on to their children, etc.
1910 //*********************************************************************************
1912 IOReturn
IOService::setAggressiveness ( unsigned long type
, unsigned long newLevel
)
1916 IOPowerConnection
*connection
;
1919 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogSetAggressiveness
,type
, newLevel
);
1921 if ( type
<= kMaxType
)
1923 pm_vars
->current_aggressiveness_values
[type
] = newLevel
;
1924 pm_vars
->current_aggressiveness_valid
[type
] = true;
1927 iter
= getChildIterator(gIOPowerPlane
);
1931 while ( (next
= iter
->getNextObject()) )
1933 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) )
1935 child
= ((IOService
*)(connection
->copyChildEntry(gIOPowerPlane
)));
1938 child
->setAggressiveness(type
, newLevel
);
1949 //*********************************************************************************
1950 // getAggressiveness
1952 // Called by the user client.
1953 //*********************************************************************************
1955 IOReturn
IOService::getAggressiveness ( unsigned long type
, unsigned long * currentLevel
)
1957 if ( type
> kMaxType
)
1958 return kIOReturnBadArgument
;
1960 if ( !pm_vars
->current_aggressiveness_valid
[type
] )
1961 return kIOReturnInvalid
;
1963 *currentLevel
= pm_vars
->current_aggressiveness_values
[type
];
1965 return kIOReturnSuccess
;
1968 //*********************************************************************************
1971 // Pass this to all power domain children. All those which are
1972 // power domains will pass it on to their children, etc.
1973 //*********************************************************************************
1975 IOReturn
IOService::systemWake ( void )
1979 IOPowerConnection
*connection
;
1980 IOService
*theChild
;
1982 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogSystemWake
,0, 0);
1984 iter
= getChildIterator(gIOPowerPlane
);
1988 while ( (next
= iter
->getNextObject()) )
1990 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) )
1992 theChild
= (IOService
*)connection
->copyChildEntry(gIOPowerPlane
);
1995 theChild
->systemWake();
1996 theChild
->release();
2003 if ( pm_vars
->theControllingDriver
!= NULL
)
2005 if ( pm_vars
->theControllingDriver
->didYouWakeSystem() )
2015 //*********************************************************************************
2016 // temperatureCriticalForZone
2018 //*********************************************************************************
2020 IOReturn
IOService::temperatureCriticalForZone ( IOService
* whichZone
)
2022 IOService
*theParent
;
2025 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogCriticalTemp
,0,0);
2027 if ( inPlane(gIOPowerPlane
) && !(priv
->we_are_root
) )
2029 theNub
= (IOService
*)copyParentEntry(gIOPowerPlane
);
2032 theParent
= (IOService
*)theNub
->copyParentEntry(gIOPowerPlane
);
2036 theParent
->temperatureCriticalForZone(whichZone
);
2037 theParent
->release();
2045 //*********************************************************************************
2046 // powerOverrideOnPriv
2048 //*********************************************************************************
2051 IOReturn
IOService::powerOverrideOnPriv ( void )
2053 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogOverrideOn
,0,0);
2055 // turn on the override
2056 priv
->device_overrides
= true;
2057 computeDesiredState();
2059 // change state if that changed something
2060 return changeState();
2064 //*********************************************************************************
2065 // powerOverrideOffPriv
2067 //*********************************************************************************
2068 IOReturn
IOService::powerOverrideOffPriv ( void )
2070 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogOverrideOff
,0,0);
2072 // turn off the override
2073 priv
->device_overrides
= false;
2074 computeDesiredState();
2077 return makeUsable();
2079 // change state if that changed something
2080 return changeState();
2085 //*********************************************************************************
2086 // enqueuePowerChange
2088 // Allocate a new state change notification, initialize it with fields from the
2089 // caller, and add it to the tail of the list of pending power changes.
2091 // If it is early enough in the list, and almost all the time it is the only one in
2092 // the list, start the power change.
2094 // In rare instances, this change will preempt the previous change in the list.
2095 // If the previous change is un-actioned in any way (because we are still
2096 // processing an even earlier power change), and if both the previous change
2097 // in the list and this change are initiated by us (not the parent), then we
2098 // needn't perform the previous change, so we collapse the list a little.
2099 //*********************************************************************************
2101 IOReturn
IOService::enqueuePowerChange ( unsigned long flags
, unsigned long whatStateOrdinal
, unsigned long domainState
, IOPowerConnection
* whichParent
, unsigned long singleParentState
)
2106 // Create and initialize the new change note
2108 IOLockLock(priv
->queue_lock
);
2109 newNote
= priv
->changeList
->createChangeNote();
2110 if ( newNote
== -1 ) {
2111 // uh-oh, our list is full
2112 IOLockUnlock(priv
->queue_lock
);
2113 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogEnqueueErr
,0,0);
2114 return IOPMAckImplied
;
2117 priv
->changeList
->changeNote
[newNote
].newStateNumber
= whatStateOrdinal
;
2118 priv
->changeList
->changeNote
[newNote
].outputPowerCharacter
= pm_vars
->thePowerStates
[whatStateOrdinal
].outputPowerCharacter
;
2119 priv
->changeList
->changeNote
[newNote
].inputPowerRequirement
= pm_vars
->thePowerStates
[whatStateOrdinal
].inputPowerRequirement
;
2120 priv
->changeList
->changeNote
[newNote
].capabilityFlags
= pm_vars
->thePowerStates
[whatStateOrdinal
].capabilityFlags
;
2121 priv
->changeList
->changeNote
[newNote
].flags
= flags
;
2122 priv
->changeList
->changeNote
[newNote
].parent
= NULL
;
2123 if (flags
& IOPMParentInitiated
)
2125 priv
->changeList
->changeNote
[newNote
].domainState
= domainState
;
2126 priv
->changeList
->changeNote
[newNote
].parent
= whichParent
;
2127 whichParent
->retain();
2128 priv
->changeList
->changeNote
[newNote
].singleParentState
= singleParentState
;
2131 previousNote
= priv
->changeList
->previousChangeNote(newNote
);
2133 if ( previousNote
== -1 )
2136 // Queue is empty, we can start this change.
2138 if (flags
& IOPMWeInitiated
)
2140 IOLockUnlock(priv
->queue_lock
);
2141 start_our_change(newNote
);
2144 IOLockUnlock(priv
->queue_lock
);
2145 return start_parent_change(newNote
);
2149 // The queue is not empty. Try to collapse this new change and the previous one in queue into one change.
2150 // This is possible only if both changes are initiated by us, and neither has been started yet.
2151 // Do this more than once if possible.
2153 // (A change is started iff it is at the head of the queue)
2155 while ( (previousNote
!= priv
->head_note
) && (previousNote
!= -1) &&
2156 (priv
->changeList
->changeNote
[newNote
].flags
& priv
->changeList
->changeNote
[previousNote
].flags
& IOPMWeInitiated
) )
2158 priv
->changeList
->changeNote
[previousNote
].outputPowerCharacter
= priv
->changeList
->changeNote
[newNote
].outputPowerCharacter
;
2159 priv
->changeList
->changeNote
[previousNote
].inputPowerRequirement
= priv
->changeList
->changeNote
[newNote
].inputPowerRequirement
;
2160 priv
->changeList
->changeNote
[previousNote
].capabilityFlags
=priv
-> changeList
->changeNote
[newNote
].capabilityFlags
;
2161 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogCollapseQueue
,priv
->changeList
->changeNote
[newNote
].newStateNumber
,
2162 priv
->changeList
->changeNote
[previousNote
].newStateNumber
);
2163 priv
->changeList
->changeNote
[previousNote
].newStateNumber
= priv
->changeList
->changeNote
[newNote
].newStateNumber
;
2164 priv
->changeList
->releaseTailChangeNote();
2165 newNote
= previousNote
;
2166 previousNote
= priv
->changeList
->previousChangeNote(newNote
);
2168 IOLockUnlock(priv
->queue_lock
);
2169 // in any case, we can't start yet
2170 return IOPMWillAckLater
;
2173 //*********************************************************************************
2176 // Notify all interested parties either that a change is impending or that the
2177 // previously-notified change is done and power has settled.
2178 // The parameter identifies whether this is the
2179 // pre-change notification or the post-change notification.
2181 //*********************************************************************************
2183 IOReturn
IOService::notifyAll ( bool is_prechange
)
2185 IOPMinformee
* nextObject
;
2188 IOPowerConnection
* connection
;
2190 // To prevent acknowledgePowerChange from finishing the change note and removing it from the queue if
2191 // some driver calls it, we inflate the number of pending acks so it cannot become zero. We'll fix it later.
2193 priv
->head_note_pendingAcks
=1;
2195 // OK, we will go through the lists of interested drivers and power domain children
2196 // and notify each one of this change.
2198 nextObject
= priv
->interestedDrivers
->firstInList();
2199 while ( nextObject
!= NULL
) {
2200 priv
->head_note_pendingAcks
+=1;
2201 if (! inform(nextObject
, is_prechange
) )
2204 nextObject
= priv
->interestedDrivers
->nextInList(nextObject
);
2207 if (! acquire_lock() ) {
2210 // did they all ack?
2211 if ( priv
->head_note_pendingAcks
> 1 ) {
2213 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogStartAckTimer
,0,0);
2217 IOUnlock(priv
->our_lock
);
2220 iter
= getChildIterator(gIOPowerPlane
);
2221 // summing their power consumption
2222 pm_vars
->thePowerStates
[priv
->head_note_state
].staticPower
= 0;
2226 while ( (next
= iter
->getNextObject()) )
2228 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) )
2230 priv
->head_note_pendingAcks
+=1;
2231 notifyChild(connection
, is_prechange
);
2237 if (! acquire_lock() ) {
2240 // now make this real
2241 priv
->head_note_pendingAcks
-= 1;
2243 if (priv
->head_note_pendingAcks
== 0 ) {
2245 IOUnlock(priv
->our_lock
);
2246 // return ack to parent
2247 return IOPMAckImplied
;
2251 IOUnlock(priv
->our_lock
);
2252 return IOPMWillAckLater
;
2256 //*********************************************************************************
2259 // Notify a power domain child of an upcoming power change.
2261 // If the object acknowledges the current change, we return TRUE.
2262 //*********************************************************************************
2264 bool IOService::notifyChild ( IOPowerConnection
* theNub
, bool is_prechange
)
2266 IOReturn k
= IOPMAckImplied
;
2267 unsigned long childPower
;
2268 IOService
*theChild
;
2270 theChild
= (IOService
*)(theNub
->copyChildEntry(gIOPowerPlane
));
2273 // The child has been detached since we grabbed the child iterator.
2274 // Decrement pending_acks, already incremented in notifyAll,
2275 // to account for this unexpected departure.
2276 priv
->head_note_pendingAcks
--;
2280 // Unless the child handles the notification immediately and returns
2281 // kIOPMAckImplied, we'll be awaiting their acknowledgement later.
2282 theNub
->setAwaitingAck(true);
2286 k
= theChild
->powerDomainWillChangeTo(priv
->head_note_outputFlags
,theNub
);
2288 k
= theChild
->powerDomainDidChangeTo(priv
->head_note_outputFlags
,theNub
);
2291 // did the return code ack?
2292 if ( k
== IOPMAckImplied
)
2295 priv
->head_note_pendingAcks
--;
2296 theNub
->setAwaitingAck(false);
2297 childPower
= theChild
->currentPowerConsumption();
2298 if ( childPower
== kIOPMUnknown
)
2300 pm_vars
->thePowerStates
[priv
->head_note_state
].staticPower
= kIOPMUnknown
;
2302 if ( pm_vars
->thePowerStates
[priv
->head_note_state
].staticPower
!= kIOPMUnknown
)
2304 pm_vars
->thePowerStates
[priv
->head_note_state
].staticPower
+= childPower
;
2307 theChild
->release();
2310 theChild
->release();
2315 //*********************************************************************************
2318 // Notify an interested driver of an upcoming power change.
2320 // If the object acknowledges the current change, we return TRUE.
2321 //*********************************************************************************
2323 bool IOService::inform ( IOPMinformee
* nextObject
, bool is_prechange
)
2325 IOReturn k
= IOPMAckImplied
;
2328 nextObject
->timer
= -1;
2332 pm_vars
->thePlatform
->PMLog (pm_vars
->ourName
,PMlogInformDriverPreChange
,
2333 (unsigned long)priv
->head_note_capabilityFlags
,(unsigned long)priv
->head_note_state
);
2334 k
= nextObject
->whatObject
->powerStateWillChangeTo( priv
->head_note_capabilityFlags
,priv
->head_note_state
,this);
2336 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogInformDriverPostChange
,
2337 (unsigned long)priv
->head_note_capabilityFlags
,(unsigned long)priv
->head_note_state
);
2338 k
= nextObject
->whatObject
->powerStateDidChangeTo(priv
->head_note_capabilityFlags
,priv
->head_note_state
,this);
2341 // did it ack behind our back?
2342 if ( nextObject
->timer
== 0 )
2348 // no, did the return code ack?
2349 if ( k
==IOPMAckImplied
)
2352 nextObject
->timer
= 0;
2353 priv
->head_note_pendingAcks
-= 1;
2359 nextObject
->timer
= 0;
2360 priv
-> head_note_pendingAcks
-= 1;
2365 nextObject
->timer
= (k
/ (ACK_TIMER_PERIOD
/ ns_per_us
)) + 1;
2371 //*********************************************************************************
2372 // OurChangeTellClientsPowerDown
2374 // All registered applications and kernel clients have positively acknowledged our
2375 // intention of lowering power. Here we notify them all that we will definitely
2376 // lower the power. If we don't have to wait for any of them to acknowledge, we
2377 // carry on by notifying interested drivers. Otherwise, we do wait.
2378 //*********************************************************************************
2380 void IOService::OurChangeTellClientsPowerDown ( void )
2383 priv
->machine_state
= kIOPM_OurChangeTellPriorityClientsPowerDown
;
2385 // are we waiting for responses?
2386 if ( tellChangeDown1(priv
->head_note_state
) )
2388 // no, notify priority clients
2389 OurChangeTellPriorityClientsPowerDown();
2391 // If we are waiting for responses, execution will resume via
2392 // allowCancelCommon() or ack timeout
2396 //*********************************************************************************
2397 // OurChangeTellPriorityClientsPowerDown
2399 // All registered applications and kernel clients have positively acknowledged our
2400 // intention of lowering power. Here we notify "priority" clients that we are
2401 // lowering power. If we don't have to wait for any of them to acknowledge, we
2402 // carry on by notifying interested drivers. Otherwise, we do wait.
2403 //*********************************************************************************
2405 void IOService::OurChangeTellPriorityClientsPowerDown ( void )
2408 priv
->machine_state
= kIOPM_OurChangeNotifyInterestedDriversWillChange
;
2409 // are we waiting for responses?
2410 if ( tellChangeDown2(priv
->head_note_state
) )
2412 // no, notify interested drivers
2413 return OurChangeNotifyInterestedDriversWillChange();
2415 // If we are waiting for responses, execution will resume via
2416 // allowCancelCommon() or ack timeout
2420 //*********************************************************************************
2421 // OurChangeNotifyInterestedDriversWillChange
2423 // All registered applications and kernel clients have acknowledged our notification
2424 // that we are lowering power. Here we notify interested drivers. If we don't have
2425 // to wait for any of them to acknowledge, we instruct our power driver to make the change.
2426 // Otherwise, we do wait.
2427 //*********************************************************************************
2429 void IOService::OurChangeNotifyInterestedDriversWillChange ( void )
2431 // no, in case they don't all ack
2432 priv
->machine_state
= kIOPM_OurChangeSetPowerState
;
2433 if ( notifyAll(true) == IOPMAckImplied
)
2435 // not waiting for responses
2436 OurChangeSetPowerState();
2438 // If we are waiting for responses, execution will resume via
2439 // all_acked() or ack timeout
2443 //*********************************************************************************
2444 // OurChangeSetPowerState
2446 // All interested drivers have acknowledged our pre-change notification of a power
2447 // change we initiated. Here we instruct our controlling driver to make
2448 // the change to the hardware. If it does so, we continue processing
2449 // (waiting for settle and notifying interested parties post-change.)
2450 // If it doesn't, we have to wait for it to acknowledge and then continue.
2451 //*********************************************************************************
2453 void IOService::OurChangeSetPowerState ( void )
2455 priv
->machine_state
= kIOPM_OurChangeWaitForPowerSettle
;
2457 if ( instruct_driver(priv
->head_note_state
) == IOPMAckImplied
)
2459 // it's done, carry on
2460 OurChangeWaitForPowerSettle();
2462 // it's not, wait for it
2463 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogStartAckTimer
,0,0);
2465 // execution will resume via ack_timer_ticked()
2470 //*********************************************************************************
2471 // OurChangeWaitForPowerSettle
2473 // Our controlling driver has changed power state on the hardware
2474 // during a power change we initiated. Here we see if we need to wait
2475 // for power to settle before continuing. If not, we continue processing
2476 // (notifying interested parties post-change). If so, we wait and
2478 //*********************************************************************************
2480 void IOService::OurChangeWaitForPowerSettle ( void )
2482 priv
->settle_time
= compute_settle_time();
2483 if ( priv
->settle_time
== 0 )
2485 OurChangeNotifyInterestedDriversDidChange();
2487 priv
->machine_state
= kIOPM_OurChangeNotifyInterestedDriversDidChange
;
2488 startSettleTimer(priv
->settle_time
);
2493 //*********************************************************************************
2494 // OurChangeNotifyInterestedDriversDidChange
2496 // Power has settled on a power change we initiated. Here we notify
2497 // all our interested parties post-change. If they all acknowledge, we're
2498 // done with this change note, and we can start on the next one.
2499 // Otherwise we have to wait for acknowledgements and finish up later.
2500 //*********************************************************************************
2502 void IOService::OurChangeNotifyInterestedDriversDidChange ( void )
2504 // in case they don't all ack
2505 priv
->machine_state
= kIOPM_OurChangeFinish
;
2506 if ( notifyAll(false) == IOPMAckImplied
)
2508 // not waiting for responses
2511 // If we are waiting for responses, execution will resume via
2512 // all_acked() or ack timeout
2516 //*********************************************************************************
2519 // Power has settled on a power change we initiated, and
2520 // all our interested parties have acknowledged. We're
2521 // done with this change note, and we can start on the next one.
2522 //*********************************************************************************
2524 void IOService::OurChangeFinish ( void )
2530 //*********************************************************************************
2531 // ParentDownTellPriorityClientsPowerDown_Immediate
2533 // All applications and kernel clients have been notified of a power lowering
2534 // initiated by the parent and we didn't have to wait for any responses. Here
2535 // we notify any priority clients. If they all ack, we continue with the power change.
2536 // If at least one doesn't, we have to wait for it to acknowledge and then continue.
2537 //*********************************************************************************
2539 IOReturn
IOService::ParentDownTellPriorityClientsPowerDown_Immediate ( void )
2541 // in case they don't all ack
2542 priv
->machine_state
= kIOPM_ParentDownNotifyInterestedDriversWillChange_Delayed
;
2543 // are we waiting for responses?
2544 if ( tellChangeDown2(priv
->head_note_state
) )
2546 // no, notify interested drivers
2547 return ParentDownNotifyInterestedDriversWillChange_Immediate();
2549 // If we are waiting for responses, execution will resume via
2550 // allowCancelCommon() or ack timeout
2551 return IOPMWillAckLater
;
2555 //*********************************************************************************
2556 // ParentDownTellPriorityClientsPowerDown_Immediate2
2558 // All priority kernel clients have been notified of a power lowering
2559 // initiated by the parent and we didn't have to wait for any responses. Here
2560 // we notify any interested drivers and power domain children. If they all ack,
2561 // we continue with the power change.
2562 // If at least one doesn't, we have to wait for it to acknowledge and then continue.
2563 //*********************************************************************************
2565 IOReturn
IOService::ParentDownNotifyInterestedDriversWillChange_Immediate ( void )
2567 // in case they don't all ack
2568 priv
->machine_state
= kIOPM_ParentDownSetPowerState_Delayed
;
2569 if ( notifyAll(true) == IOPMAckImplied
)
2572 return ParentDownSetPowerState_Immediate();
2574 // If we are waiting for responses, execution will resume via
2575 // all_acked() or ack timeout
2576 return IOPMWillAckLater
;
2580 //*********************************************************************************
2581 // ParentDownTellPriorityClientsPowerDown_Immediate4
2583 // All applications and kernel clients have been notified of a power lowering
2584 // initiated by the parent and we had to wait for responses. Here
2585 // we notify any priority clients. If they all ack, we continue with the power change.
2586 // If at least one doesn't, we have to wait for it to acknowledge and then continue.
2587 //*********************************************************************************
2589 void IOService::ParentDownTellPriorityClientsPowerDown_Delayed ( void )
2591 // in case they don't all ack
2592 priv
->machine_state
= kIOPM_ParentDownNotifyInterestedDriversWillChange_Delayed
;
2594 // are we waiting for responses?
2595 if ( tellChangeDown2(priv
->head_note_state
) )
2597 // no, notify interested drivers
2598 ParentDownNotifyInterestedDriversWillChange_Delayed();
2600 // If we are waiting for responses, execution will resume via
2601 // allowCancelCommon() or ack timeout
2605 //*********************************************************************************
2606 // ParentDownTellPriorityClientsPowerDown_Immediate5
2608 // All applications and kernel clients have been notified of a power lowering
2609 // initiated by the parent and we had to wait for their responses. Here we notify
2610 // any interested drivers and power domain children. If they all ack, we continue
2611 // with the power change.
2612 // If at least one doesn't, we have to wait for it to acknowledge and then continue.
2613 //*********************************************************************************
2615 void IOService::ParentDownNotifyInterestedDriversWillChange_Delayed ( void )
2617 // in case they don't all ack
2618 priv
->machine_state
= kIOPM_ParentDownSetPowerState_Delayed
;
2619 if ( notifyAll(true) == IOPMAckImplied
)
2622 ParentDownSetPowerState_Delayed();
2624 // If we are waiting for responses, execution will resume via
2625 // all_acked() or ack timeout
2629 //*********************************************************************************
2630 // ParentDownSetPowerState_Immediate
2632 // All parties have acknowledged our pre-change notification of a power
2633 // lowering initiated by the parent. Here we instruct our controlling driver
2634 // to put the hardware in the state it needs to be in when the domain is
2635 // lowered. If it does so, we continue processing
2636 // (waiting for settle and acknowledging the parent.)
2637 // If it doesn't, we have to wait for it to acknowledge and then continue.
2638 //*********************************************************************************
2640 IOReturn
IOService::ParentDownSetPowerState_Immediate ( void )
2642 priv
->machine_state
= kIOPM_ParentDownWaitForPowerSettle_Delayed
;
2644 if ( instruct_driver(priv
->head_note_state
) == IOPMAckImplied
)
2646 // it's done, carry on
2647 return ParentDownWaitForPowerSettleAndNotifyDidChange_Immediate();
2649 // it's not, wait for it
2650 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogStartAckTimer
,0,0);
2652 return IOPMWillAckLater
;
2656 //*********************************************************************************
2657 // ParentDownSetPowerState_Delayed
2659 // We had to wait for it, but all parties have acknowledged our pre-change
2660 // notification of a power lowering initiated by the parent.
2661 // Here we instruct our controlling driver
2662 // to put the hardware in the state it needs to be in when the domain is
2663 // lowered. If it does so, we continue processing
2664 // (waiting for settle and acknowledging the parent.)
2665 // If it doesn't, we have to wait for it to acknowledge and then continue.
2666 //*********************************************************************************
2668 void IOService::ParentDownSetPowerState_Delayed ( void )
2670 priv
-> machine_state
= kIOPM_ParentDownWaitForPowerSettle_Delayed
;
2672 if ( instruct_driver(priv
->head_note_state
) == IOPMAckImplied
)
2674 // it's done, carry on
2675 ParentDownWaitForPowerSettle_Delayed();
2677 // it's not, wait for it
2678 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogStartAckTimer
,0,0);
2684 //*********************************************************************************
2685 // ParentDownWaitForPowerSettleAndNotifyDidChange_Immediate
2687 // Our controlling driver has changed power state on the hardware
2688 // during a power change initiated by our parent. Here we see if we need
2689 // to wait for power to settle before continuing. If not, we continue
2690 // processing (acknowledging our preparedness to the parent).
2691 // If so, we wait and continue later.
2692 //*********************************************************************************
2694 IOReturn
IOService::ParentDownWaitForPowerSettleAndNotifyDidChange_Immediate ( void )
2698 priv
->settle_time
= compute_settle_time();
2699 if ( priv
->settle_time
== 0 )
2701 // store current state in case they don't all ack
2702 priv
->machine_state
= kIOPM_ParentDownAcknowledgeChange_Delayed
;
2703 if ( notifyAll(false) == IOPMAckImplied
)
2705 // not waiting for responses
2706 nub
= priv
->head_note_parent
;
2710 return IOPMAckImplied
;
2712 // If we are waiting for responses, execution will resume via
2713 // all_acked() or ack timeout
2714 return IOPMWillAckLater
;
2716 // let settle time elapse, then notify interest drivers of our power state change in ParentDownNotifyDidChangeAndAcknowledgeChange_Delayed
2717 priv
->machine_state
= kIOPM_ParentDownNotifyDidChangeAndAcknowledgeChange_Delayed
;
2718 startSettleTimer(priv
->settle_time
);
2719 return IOPMWillAckLater
;
2724 //*********************************************************************************
2725 // ParentDownWaitForPowerSettle_Delayed
2727 // Our controlling driver has changed power state on the hardware
2728 // during a power change initiated by our parent. We have had to wait
2729 // for acknowledgement from interested parties, or we have had to wait
2730 // for the controlling driver to change the state. Here we see if we need
2731 // to wait for power to settle before continuing. If not, we continue
2732 // processing (acknowledging our preparedness to the parent).
2733 // If so, we wait and continue later.
2734 //*********************************************************************************
2736 void IOService::ParentDownWaitForPowerSettle_Delayed ( void )
2738 priv
->settle_time
= compute_settle_time();
2739 if ( priv
->settle_time
== 0 )
2741 ParentDownNotifyDidChangeAndAcknowledgeChange_Delayed();
2743 priv
->machine_state
= kIOPM_ParentDownNotifyDidChangeAndAcknowledgeChange_Delayed
;
2744 startSettleTimer(priv
->settle_time
);
2749 //*********************************************************************************
2750 // ParentDownNotifyDidChangeAndAcknowledgeChange_Delayed
2752 // Power has settled on a power change initiated by our parent. Here we
2753 // notify interested parties.
2754 //*********************************************************************************
2756 void IOService::ParentDownNotifyDidChangeAndAcknowledgeChange_Delayed ( void )
2758 IORegistryEntry
*nub
;
2761 // in case they don't all ack
2762 priv
->machine_state
= kIOPM_ParentDownAcknowledgeChange_Delayed
;
2763 if ( notifyAll(false) == IOPMAckImplied
) {
2764 nub
= priv
->head_note_parent
;
2767 parent
= (IOService
*)nub
->copyParentEntry(gIOPowerPlane
);
2769 parent
->acknowledgePowerChange((IOService
*)nub
);
2774 // If we are waiting for responses, execution will resume via
2775 // all_acked() or ack timeout in ParentDownAcknowledgeChange_Delayed.
2776 // Notice the duplication of code just above and in ParentDownAcknowledgeChange_Delayed.
2780 //*********************************************************************************
2781 // ParentDownAcknowledgeChange_Delayed
2783 // We had to wait for it, but all parties have acknowledged our post-change
2784 // notification of a power lowering initiated by the parent.
2785 // Here we acknowledge the parent.
2786 // We are done with this change note, and we can start on the next one.
2787 //*********************************************************************************
2789 void IOService::ParentDownAcknowledgeChange_Delayed ( void )
2791 IORegistryEntry
*nub
;
2794 nub
= priv
->head_note_parent
;
2797 parent
= (IOService
*)nub
->copyParentEntry(gIOPowerPlane
);
2800 parent
->acknowledgePowerChange((IOService
*)nub
);
2807 //*********************************************************************************
2808 // ParentUpSetPowerState_Delayed
2810 // Our parent has informed us via powerStateDidChange that it has
2811 // raised the power in our power domain, and we have had to wait
2812 // for some interested party to acknowledge our notification.
2813 // Here we instruct our controlling
2814 // driver to program the hardware to take advantage of the higher domain
2815 // power. If it does so, we continue processing
2816 // (waiting for settle and notifying interested parties post-change.)
2817 // If it doesn't, we have to wait for it to acknowledge and then continue.
2818 //*********************************************************************************
2820 void IOService::ParentUpSetPowerState_Delayed ( void )
2822 priv
->machine_state
= kIOPM_ParentUpWaitForSettleTime_Delayed
;
2824 if ( instruct_driver(priv
->head_note_state
) == IOPMAckImplied
)
2826 // it did it, carry on
2827 ParentUpWaitForSettleTime_Delayed();
2829 // it didn't, wait for it
2830 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogStartAckTimer
,0,0);
2836 //*********************************************************************************
2837 // ParentUpSetPowerState_Immediate
2839 // Our parent has informed us via powerStateDidChange that it has
2840 // raised the power in our power domain. Here we instruct our controlling
2841 // driver to program the hardware to take advantage of the higher domain
2842 // power. If it does so, we continue processing
2843 // (waiting for settle and notifying interested parties post-change.)
2844 // If it doesn't, we have to wait for it to acknowledge and then continue.
2845 //*********************************************************************************
2847 IOReturn
IOService::ParentUpSetPowerState_Immediate ( void )
2849 priv
->machine_state
= kIOPM_ParentUpWaitForSettleTime_Delayed
;
2851 if ( instruct_driver(priv
->head_note_state
) == IOPMAckImplied
)
2853 // it did it, carry on
2854 return ParentUpWaitForSettleTime_Immediate();
2857 // it didn't, wait for it
2858 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogStartAckTimer
,0,0);
2860 return IOPMWillAckLater
;
2865 //*********************************************************************************
2866 // ParentUpWaitForSettleTime_Immediate
2868 // Our controlling driver has changed power state on the hardware
2869 // during a power raise initiated by the parent. Here we see if we need to wait
2870 // for power to settle before continuing. If not, we continue processing
2871 // (notifying interested parties post-change). If so, we wait and
2873 //*********************************************************************************
2875 IOReturn
IOService::ParentUpWaitForSettleTime_Immediate ( void )
2877 priv
->settle_time
= compute_settle_time();
2878 if ( priv
->settle_time
== 0 )
2880 return ParentUpNotifyInterestedDriversDidChange_Immediate();
2882 priv
->machine_state
= kIOPM_ParentUpNotifyInterestedDriversDidChange_Delayed
;
2883 startSettleTimer(priv
->settle_time
);
2884 return IOPMWillAckLater
;
2889 //*********************************************************************************
2890 // ParentUpWaitForSettleTime_Delayed
2892 // Our controlling driver has changed power state on the hardware
2893 // during a power raise initiated by the parent, but we had to wait for it.
2894 // Here we see if we need to wait for power to settle before continuing.
2895 // If not, we continue processing (notifying interested parties post-change).
2896 // If so, we wait and continue later.
2897 //*********************************************************************************
2899 void IOService::ParentUpWaitForSettleTime_Delayed ( void )
2901 priv
->settle_time
= compute_settle_time();
2902 if ( priv
->settle_time
== 0 )
2904 ParentUpNotifyInterestedDriversDidChange_Delayed();
2906 priv
->machine_state
= kIOPM_ParentUpNotifyInterestedDriversDidChange_Delayed
;
2907 startSettleTimer(priv
->settle_time
);
2912 //*********************************************************************************
2913 // ParentUpNotifyInterestedDriversDidChange_Immediate
2915 // No power settling was required on a power raise initiated by the parent.
2916 // Here we notify all our interested parties post-change. If they all acknowledge,
2917 // we're done with this change note, and we can start on the next one.
2918 // Otherwise we have to wait for acknowledgements and finish up later.
2919 //*********************************************************************************
2921 IOReturn
IOService::ParentUpNotifyInterestedDriversDidChange_Immediate ( void )
2925 // in case they don't all ack
2926 priv
->machine_state
= kIOPM_ParentUpAcknowledgePowerChange_Delayed
;
2927 if ( notifyAll(false) == IOPMAckImplied
)
2929 nub
= priv
->head_note_parent
;
2933 return IOPMAckImplied
;
2935 // If we are waiting for responses, execution will resume via
2936 // all_acked() or ack timeout in ParentUpAcknowledgePowerChange_Delayed.
2937 return IOPMWillAckLater
;
2941 //*********************************************************************************
2942 // ParentUpNotifyInterestedDriversDidChange_Delayed
2944 // Power has settled on a power raise initiated by the parent.
2945 // Here we notify all our interested parties post-change. If they all acknowledge,
2946 // we're done with this change note, and we can start on the next one.
2947 // Otherwise we have to wait for acknowledgements and finish up later.
2948 //*********************************************************************************
2950 void IOService::ParentUpNotifyInterestedDriversDidChange_Delayed ( void )
2952 // in case they don't all ack
2953 priv
->machine_state
= kIOPM_ParentUpAcknowledgePowerChange_Delayed
;
2954 if ( notifyAll(false) == IOPMAckImplied
)
2956 ParentUpAcknowledgePowerChange_Delayed();
2958 // If we are waiting for responses, execution will resume via
2959 // all_acked() or ack timeout in ParentUpAcknowledgePowerChange_Delayed.
2963 //*********************************************************************************
2964 // ParentUpAcknowledgePowerChange_Delayed
2966 // All parties have acknowledged our post-change notification of a power
2967 // raising initiated by the parent. Here we acknowledge the parent.
2968 // We are done with this change note, and we can start on the next one.
2969 //*********************************************************************************
2971 void IOService::ParentUpAcknowledgePowerChange_Delayed ( void )
2973 IORegistryEntry
*nub
;
2976 nub
= priv
->head_note_parent
;
2979 parent
= (IOService
*)nub
->copyParentEntry(gIOPowerPlane
);
2982 parent
->acknowledgePowerChange((IOService
*)nub
);
2989 //*********************************************************************************
2992 // A power change is complete, and the used post-change note is at
2993 // the head of the queue. Remove it and set myCurrentState to the result
2994 // of the change. Start up the next change in queue.
2995 //*********************************************************************************
2997 void IOService::all_done ( void )
2999 unsigned long previous_state
;
3000 IORegistryEntry
*nub
;
3003 priv
->machine_state
= kIOPM_Finished
;
3006 if ( priv
->head_note_flags
& IOPMWeInitiated
)
3008 // could our driver switch to the new state?
3009 if ( !( priv
->head_note_flags
& IOPMNotDone
) )
3011 // yes, did power raise?
3012 if ( pm_vars
->myCurrentState
< priv
->head_note_state
)
3014 // yes, inform clients and apps
3015 tellChangeUp (priv
->head_note_state
);
3017 // no, if this lowers our
3018 if ( ! priv
->we_are_root
)
3020 // power requirements, tell the parent
3021 ask_parent(priv
->head_note_state
);
3024 previous_state
= pm_vars
->myCurrentState
;
3026 pm_vars
->myCurrentState
= priv
->head_note_state
;
3027 priv
->imminentState
= pm_vars
->myCurrentState
;
3028 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogChangeDone
,(unsigned long)pm_vars
->myCurrentState
,0);
3029 // inform subclass policy-maker
3030 powerChangeDone(previous_state
);
3034 // parent's power change
3035 if ( priv
->head_note_flags
& IOPMParentInitiated
)
3037 if ( ((priv
->head_note_flags
& IOPMDomainWillChange
) && (pm_vars
->myCurrentState
>= priv
->head_note_state
)) ||
3038 ((priv
->head_note_flags
& IOPMDomainDidChange
) && (pm_vars
->myCurrentState
< priv
->head_note_state
)) )
3041 if ( pm_vars
->myCurrentState
< priv
->head_note_state
)
3043 // yes, inform clients and apps
3044 tellChangeUp (priv
->head_note_state
);
3047 previous_state
= pm_vars
->myCurrentState
;
3048 pm_vars
->myCurrentState
= priv
->head_note_state
;
3049 priv
->imminentState
= pm_vars
->myCurrentState
;
3050 pm_vars
->maxCapability
= pm_vars
->theControllingDriver
->maxCapabilityForDomainState(priv
->head_note_domainState
);
3052 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogChangeDone
,(unsigned long)pm_vars
->myCurrentState
,0);
3053 // inform subclass policy-maker
3054 powerChangeDone(previous_state
);
3058 IOLockLock(priv
->queue_lock
);
3059 // we're done with this
3060 priv
->changeList
->releaseHeadChangeNote();
3062 // start next one in queue
3063 priv
->head_note
= priv
->changeList
->currentChange();
3064 if ( priv
->head_note
!= -1 )
3067 IOLockUnlock(priv
->queue_lock
);
3068 if (priv
->changeList
->changeNote
[priv
->head_note
].flags
& IOPMWeInitiated
)
3070 start_our_change(priv
->head_note
);
3072 nub
= priv
->changeList
->changeNote
[priv
->head_note
].parent
;
3073 if ( start_parent_change(priv
->head_note
) == IOPMAckImplied
)
3075 parent
= (IOService
*)nub
->copyParentEntry(gIOPowerPlane
);
3078 parent
->acknowledgePowerChange((IOService
*)nub
);
3084 IOLockUnlock(priv
->queue_lock
);
3090 //*********************************************************************************
3093 // A driver or child has acknowledged our notification of an upcoming power
3094 // change, and this acknowledgement is the last one pending
3095 // before we change power or after changing power.
3097 //*********************************************************************************
3099 void IOService::all_acked ( void )
3101 switch (priv
->machine_state
) {
3102 case kIOPM_OurChangeSetPowerState
:
3103 OurChangeSetPowerState();
3105 case kIOPM_OurChangeFinish
:
3108 case kIOPM_ParentDownSetPowerState_Delayed
:
3109 ParentDownSetPowerState_Delayed();
3111 case kIOPM_ParentDownAcknowledgeChange_Delayed
:
3112 ParentDownAcknowledgeChange_Delayed();
3114 case kIOPM_ParentUpSetPowerState_Delayed
:
3115 ParentUpSetPowerState_Delayed();
3117 case kIOPM_ParentUpAcknowledgePowerChange_Delayed
:
3118 ParentUpAcknowledgePowerChange_Delayed();
3123 //*********************************************************************************
3124 // settleTimerExpired
3126 // Power has settled after our last change. Notify interested parties that
3127 // there is a new power state.
3128 //*********************************************************************************
3130 void IOService::settleTimerExpired ( void )
3132 if ( ! initialized
)
3138 switch (priv
->machine_state
) {
3139 case kIOPM_OurChangeNotifyInterestedDriversDidChange
:
3140 OurChangeNotifyInterestedDriversDidChange();
3142 case kIOPM_ParentDownNotifyDidChangeAndAcknowledgeChange_Delayed
:
3143 ParentDownNotifyDidChangeAndAcknowledgeChange_Delayed();
3145 case kIOPM_ParentUpNotifyInterestedDriversDidChange_Delayed
:
3146 ParentUpNotifyInterestedDriversDidChange_Delayed();
3152 //*********************************************************************************
3153 // compute_settle_time
3155 // Compute the power-settling delay in microseconds for the
3156 // change from myCurrentState to head_note_state.
3157 //*********************************************************************************
3159 unsigned long IOService::compute_settle_time ( void )
3161 unsigned long totalTime
;
3164 // compute total time to attain the new state
3166 i
= pm_vars
->myCurrentState
;
3168 // we're lowering power
3169 if ( priv
->head_note_state
< pm_vars
->myCurrentState
)
3171 while ( i
> priv
->head_note_state
)
3173 totalTime
+= pm_vars
->thePowerStates
[i
].settleDownTime
;
3178 // we're raising power
3179 if ( priv
->head_note_state
> pm_vars
->myCurrentState
)
3181 while ( i
< priv
->head_note_state
)
3183 totalTime
+= pm_vars
->thePowerStates
[i
+1].settleUpTime
;
3192 //*********************************************************************************
3195 // Enter with a power-settling delay in microseconds and start a nano-second
3196 // timer for that delay.
3197 //*********************************************************************************
3199 IOReturn
IOService::startSettleTimer ( unsigned long delay
)
3201 AbsoluteTime deadline
;
3203 clock_interval_to_deadline(delay
, kMicrosecondScale
, &deadline
);
3205 thread_call_enter_delayed(priv
->settleTimer
, deadline
);
3210 //*********************************************************************************
3213 // The acknowledgement timeout periodic timer has ticked.
3214 // If we are awaiting acks for a power change notification,
3215 // we decrement the timer word of each interested driver which hasn't acked.
3216 // If a timer word becomes zero, we pretend the driver aknowledged.
3217 // If we are waiting for the controlling driver to change the power
3218 // state of the hardware, we decrement its timer word, and if it becomes
3219 // zero, we pretend the driver acknowledged.
3220 //*********************************************************************************
3222 void IOService::ack_timer_ticked ( void )
3224 IOPMinformee
* nextObject
;
3226 if ( ! initialized
)
3232 if (! acquire_lock() )
3237 switch (priv
->machine_state
) {
3238 case kIOPM_OurChangeWaitForPowerSettle
:
3239 case kIOPM_ParentDownWaitForPowerSettle_Delayed
:
3240 case kIOPM_ParentUpWaitForSettleTime_Delayed
:
3241 // are we waiting for our driver to make its change?
3242 if ( priv
->driver_timer
!= 0 ) {
3244 priv
->driver_timer
-= 1;
3245 // it's tardy, we'll go on without it
3246 if ( priv
->driver_timer
== 0 )
3248 IOUnlock(priv
->our_lock
);
3249 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogCtrlDriverTardy
,0,0);
3252 // still waiting, set timer again
3254 IOUnlock(priv
->our_lock
);
3258 IOUnlock(priv
->our_lock
);
3262 case kIOPM_OurChangeSetPowerState
:
3263 case kIOPM_OurChangeFinish
:
3264 case kIOPM_ParentDownSetPowerState_Delayed
:
3265 case kIOPM_ParentDownAcknowledgeChange_Delayed
:
3266 case kIOPM_ParentUpSetPowerState_Delayed
:
3267 case kIOPM_ParentUpAcknowledgePowerChange_Delayed
:
3268 // are we waiting for interested parties to acknowledge?
3269 if (priv
->head_note_pendingAcks
!= 0 )
3271 // yes, go through the list of interested drivers
3272 nextObject
= priv
->interestedDrivers
->firstInList();
3273 // and check each one
3274 while ( nextObject
!= NULL
)
3276 if ( nextObject
->timer
> 0 )
3278 nextObject
->timer
-= 1;
3279 // this one should have acked by now
3280 if ( nextObject
->timer
== 0 )
3282 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogIntDriverTardy
,0,0);
3283 //kprintf("interested driver tardy: %s\n",nextObject->whatObject->getName());
3284 priv
->head_note_pendingAcks
-= 1;
3287 nextObject
= priv
->interestedDrivers
->nextInList(nextObject
);
3290 // is that the last?
3291 if ( priv
->head_note_pendingAcks
== 0 )
3293 IOUnlock(priv
->our_lock
);
3294 // yes, we can continue
3297 // no, set timer again
3299 IOUnlock(priv
->our_lock
);
3302 IOUnlock(priv
->our_lock
);
3306 // apps didn't respond to parent-down notification
3307 case kIOPM_ParentDownTellPriorityClientsPowerDown_Immediate
:
3308 IOUnlock(priv
->our_lock
);
3309 IOLockLock(priv
->flags_lock
);
3310 if (pm_vars
->responseFlags
)
3312 // get rid of this stuff
3313 pm_vars
->responseFlags
->release();
3314 pm_vars
->responseFlags
= NULL
;
3316 IOLockUnlock(priv
->flags_lock
);
3317 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogClientTardy
,0,5);
3318 // carry on with the change
3319 ParentDownTellPriorityClientsPowerDown_Delayed();
3322 case kIOPM_ParentDownNotifyInterestedDriversWillChange_Delayed
:
3323 IOUnlock(priv
->our_lock
);
3324 IOLockLock(priv
->flags_lock
);
3325 if (pm_vars
->responseFlags
)
3327 // get rid of this stuff
3328 pm_vars
->responseFlags
->release();
3329 pm_vars
->responseFlags
= NULL
;
3331 IOLockUnlock(priv
->flags_lock
);
3332 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogClientTardy
,0,1);
3333 // carry on with the change
3334 ParentDownNotifyInterestedDriversWillChange_Delayed();
3337 case kIOPM_OurChangeTellClientsPowerDown
:
3338 // apps didn't respond to our power-down request
3339 IOUnlock(priv
->our_lock
);
3340 IOLockLock(priv
->flags_lock
);
3341 if (pm_vars
->responseFlags
)
3343 // get rid of this stuff
3344 pm_vars
->responseFlags
->release();
3345 pm_vars
->responseFlags
= NULL
;
3347 IOLockUnlock(priv
->flags_lock
);
3348 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogClientTardy
,0,2);
3349 // rescind the request
3350 tellNoChangeDown(priv
->head_note_state
);
3351 // mark the change note un-actioned
3352 priv
->head_note_flags
|= IOPMNotDone
;
3357 case kIOPM_OurChangeTellPriorityClientsPowerDown
:
3358 // clients didn't respond to our power-down note
3359 IOUnlock(priv
->our_lock
);
3360 IOLockLock(priv
->flags_lock
);
3361 if (pm_vars
->responseFlags
)
3363 // get rid of this stuff
3364 pm_vars
->responseFlags
->release();
3365 pm_vars
->responseFlags
= NULL
;
3367 IOLockUnlock(priv
->flags_lock
);
3368 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogClientTardy
,0,4);
3369 // carry on with the change
3370 OurChangeTellPriorityClientsPowerDown();
3373 case kIOPM_OurChangeNotifyInterestedDriversWillChange
:
3374 // apps didn't respond to our power-down notification
3375 IOUnlock(priv
->our_lock
);
3376 IOLockLock(priv
->flags_lock
);
3377 if (pm_vars
->responseFlags
)
3379 // get rid of this stuff
3380 pm_vars
->responseFlags
->release();
3381 pm_vars
->responseFlags
= NULL
;
3383 IOLockUnlock(priv
->flags_lock
);
3384 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogClientTardy
,0,3);
3385 // carry on with the change
3386 OurChangeNotifyInterestedDriversWillChange();
3390 // not waiting for acks
3391 IOUnlock(priv
->our_lock
);
3397 //*********************************************************************************
3400 //*********************************************************************************
3402 void IOService::start_ack_timer ( void )
3404 AbsoluteTime deadline
;
3406 clock_interval_to_deadline(ACK_TIMER_PERIOD
, kNanosecondScale
, &deadline
);
3408 thread_call_enter_delayed(priv
->ackTimer
, deadline
);
3412 //*********************************************************************************
3415 //*********************************************************************************
3417 void IOService::stop_ack_timer ( void )
3419 thread_call_cancel(priv
->ackTimer
);
3423 //*********************************************************************************
3424 // c-language timer expiration functions
3426 //*********************************************************************************
3428 static void ack_timer_expired ( thread_call_param_t us
)
3430 ((IOService
*)us
)->ack_timer_ticked();
3434 static void settle_timer_expired ( thread_call_param_t us
)
3436 ((IOService
*)us
)->settleTimerExpired();
3440 //*********************************************************************************
3441 // add_child_to_active_change
3443 // A child has just registered with us. If there is
3444 // currently a change in progress, get the new party involved: if we
3445 // have notified all parties and are waiting for acks, notify the new
3447 //*********************************************************************************
3449 IOReturn
IOService::add_child_to_active_change ( IOPowerConnection
* newObject
)
3451 if (! acquire_lock() )
3456 switch (priv
->machine_state
)
3458 case kIOPM_OurChangeSetPowerState
:
3459 case kIOPM_ParentDownSetPowerState_Delayed
:
3460 case kIOPM_ParentUpSetPowerState_Delayed
:
3461 // one for this child and one to prevent
3462 priv
->head_note_pendingAcks
+= 2;
3463 // incoming acks from changing our state
3464 IOUnlock(priv
->our_lock
);
3465 notifyChild(newObject
, true);
3466 if (! acquire_lock() )
3469 --priv
->head_note_pendingAcks
;
3472 // are we still waiting for acks?
3473 if ( --priv
->head_note_pendingAcks
== 0 )
3475 // no, stop the timer
3477 IOUnlock(priv
->our_lock
);
3479 // and now we can continue
3484 case kIOPM_OurChangeFinish
:
3485 case kIOPM_ParentDownAcknowledgeChange_Delayed
:
3486 case kIOPM_ParentUpAcknowledgePowerChange_Delayed
:
3487 // one for this child and one to prevent
3488 priv
->head_note_pendingAcks
+= 2;
3489 // incoming acks from changing our state
3490 IOUnlock(priv
->our_lock
);
3491 notifyChild(newObject
, false);
3492 if (! acquire_lock() )
3495 --priv
->head_note_pendingAcks
;
3498 // are we still waiting for acks?
3499 if ( --priv
->head_note_pendingAcks
== 0 )
3501 // no, stop the timer
3503 IOUnlock(priv
->our_lock
);
3505 // and now we can continue
3511 IOUnlock(priv
->our_lock
);
3516 //*********************************************************************************
3517 // add_driver_to_active_change
3519 // An interested driver has just registered with us. If there is
3520 // currently a change in progress, get the new party involved: if we
3521 // have notified all parties and are waiting for acks, notify the new
3523 //*********************************************************************************
3525 IOReturn
IOService::add_driver_to_active_change ( IOPMinformee
* newObject
)
3527 if (! acquire_lock() )
3532 switch (priv
->machine_state
) {
3533 case kIOPM_OurChangeSetPowerState
:
3534 case kIOPM_ParentDownSetPowerState_Delayed
:
3535 case kIOPM_ParentUpSetPowerState_Delayed
:
3536 // one for this driver and one to prevent
3537 priv
->head_note_pendingAcks
+= 2;
3538 // incoming acks from changing our state
3539 IOUnlock(priv
->our_lock
);
3540 // inform the driver
3541 inform(newObject
, true);
3542 if (! acquire_lock() )
3545 --priv
->head_note_pendingAcks
;
3548 // are we still waiting for acks?
3549 if ( --priv
->head_note_pendingAcks
== 0 )
3551 // no, stop the timer
3553 IOUnlock(priv
->our_lock
);
3555 // and now we can continue
3560 case kIOPM_OurChangeFinish
:
3561 case kIOPM_ParentDownAcknowledgeChange_Delayed
:
3562 case kIOPM_ParentUpAcknowledgePowerChange_Delayed
:
3563 // one for this driver and one to prevent
3564 priv
->head_note_pendingAcks
+= 2;
3565 // incoming acks from changing our state
3566 IOUnlock(priv
->our_lock
);
3567 // inform the driver
3568 inform(newObject
, false);
3569 if (! acquire_lock() ) {
3571 --priv
->head_note_pendingAcks
;
3574 // are we still waiting for acks?
3575 if ( --priv
->head_note_pendingAcks
== 0 ) {
3576 // no, stop the timer
3578 IOUnlock(priv
->our_lock
);
3580 // and now we can continue
3586 IOUnlock(priv
->our_lock
);
3591 //*********************************************************************************
3592 // start_parent_change
3594 // Here we begin the processing of a change note initiated by our parent
3595 // which is at the head of the queue.
3597 // It is possible for the change to be processed to completion and removed from the queue.
3598 // There are several possible interruptions to the processing, though, and they are:
3599 // we may have to wait for interested parties to acknowledge our pre-change notification,
3600 // we may have to wait for our controlling driver to change the hardware power state,
3601 // there may be a settling time after changing the hardware power state,
3602 // we may have to wait for interested parties to acknowledge our post-change notification,
3603 // we may have to wait for the acknowledgement timer expiration to substitute for the
3604 // acknowledgement from a failing driver.
3605 //*********************************************************************************
3607 IOReturn
IOService::start_parent_change ( unsigned long queue_head
)
3609 priv
->head_note
= queue_head
;
3610 priv
->head_note_flags
= priv
-> changeList
->changeNote
[priv
->head_note
].flags
;
3611 priv
->head_note_state
= priv
->changeList
->changeNote
[priv
->head_note
].newStateNumber
;
3612 priv
->imminentState
= priv
->head_note_state
;
3613 priv
->head_note_outputFlags
= priv
->changeList
->changeNote
[priv
->head_note
].outputPowerCharacter
;
3614 priv
->head_note_domainState
= priv
->changeList
->changeNote
[priv
->head_note
].domainState
;
3615 priv
->head_note_parent
= priv
->changeList
->changeNote
[priv
->head_note
].parent
;
3616 priv
->head_note_capabilityFlags
= priv
->changeList
->changeNote
[priv
->head_note
].capabilityFlags
;
3618 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogStartParentChange
,
3619 (unsigned long)priv
->head_note_state
,(unsigned long)pm_vars
->myCurrentState
);
3621 // if we need something and haven't told the parent, do so
3622 ask_parent( priv
->ourDesiredPowerState
);
3624 // power domain is lowering
3625 if ( priv
->head_note_state
< pm_vars
->myCurrentState
)
3627 setParentInfo(priv
->changeList
->changeNote
[priv
->head_note
].singleParentState
,priv
->head_note_parent
);
3628 priv
->initial_change
= false;
3629 // tell apps and kernel clients
3630 priv
->machine_state
= kIOPM_ParentDownTellPriorityClientsPowerDown_Immediate
;
3632 // are we waiting for responses?
3633 if ( tellChangeDown1(priv
->head_note_state
) )
3635 // no, notify priority clients
3636 return ParentDownTellPriorityClientsPowerDown_Immediate();
3639 return IOPMWillAckLater
;
3642 // parent is raising power, we may or may not
3643 if ( priv
->head_note_state
> pm_vars
->myCurrentState
)
3645 if ( priv
->ourDesiredPowerState
> pm_vars
->myCurrentState
)
3647 if ( priv
->ourDesiredPowerState
< priv
->head_note_state
)
3649 // we do, but not all the way
3650 priv
->head_note_state
= priv
->ourDesiredPowerState
;
3651 priv
->imminentState
= priv
->head_note_state
;
3652 priv
->head_note_outputFlags
= pm_vars
->thePowerStates
[priv
->head_note_state
].outputPowerCharacter
;
3653 priv
->head_note_capabilityFlags
= pm_vars
->thePowerStates
[priv
->head_note_state
].capabilityFlags
;
3654 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogAmendParentChange
,(unsigned long)priv
->head_note_state
,0);
3658 priv
->head_note_state
= pm_vars
->myCurrentState
;
3659 priv
->imminentState
= priv
->head_note_state
;
3660 priv
->head_note_outputFlags
= pm_vars
->thePowerStates
[priv
->head_note_state
].outputPowerCharacter
;
3661 priv
->head_note_capabilityFlags
= pm_vars
->thePowerStates
[priv
->head_note_state
].capabilityFlags
;
3662 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogAmendParentChange
,(unsigned long)priv
->head_note_state
,0);
3666 if ( (priv
->head_note_state
> pm_vars
->myCurrentState
) &&
3667 (priv
->head_note_flags
& IOPMDomainDidChange
) )
3670 priv
->initial_change
= false;
3671 priv
->machine_state
= kIOPM_ParentUpSetPowerState_Delayed
;
3672 if ( notifyAll(true) == IOPMAckImplied
) {
3673 return ParentUpSetPowerState_Immediate();
3675 // they didn't all ack
3676 return IOPMWillAckLater
;
3680 // a null change or power will go up
3681 return IOPMAckImplied
;
3685 //*********************************************************************************
3688 // Here we begin the processing of a change note initiated by us
3689 // which is at the head of the queue.
3691 // It is possible for the change to be processed to completion and removed from the queue.
3692 // There are several possible interruptions to the processing, though, and they are:
3693 // we may have to wait for interested parties to acknowledge our pre-change notification,
3694 // changes initiated by the parent will wait in the middle for powerStateDidChange,
3695 // we may have to wait for our controlling driver to change the hardware power state,
3696 // there may be a settling time after changing the hardware power state,
3697 // we may have to wait for interested parties to acknowledge our post-change notification,
3698 // we may have to wait for the acknowledgement timer expiration to substitute for the
3699 // acknowledgement from a failing driver.
3700 //*********************************************************************************
3702 void IOService::start_our_change ( unsigned long queue_head
)
3704 priv
->head_note
= queue_head
;
3705 priv
->head_note_flags
= priv
->changeList
->changeNote
[priv
->head_note
].flags
;
3706 priv
->head_note_state
= priv
->changeList
->changeNote
[priv
->head_note
].newStateNumber
;
3707 priv
->imminentState
= priv
->head_note_state
;
3708 priv
->head_note_outputFlags
= priv
->changeList
->changeNote
[priv
->head_note
].outputPowerCharacter
;
3709 priv
->head_note_capabilityFlags
= priv
->changeList
->changeNote
[priv
->head_note
].capabilityFlags
;
3711 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogStartDeviceChange
,
3712 (unsigned long)priv
->head_note_state
,(unsigned long)pm_vars
->myCurrentState
);
3714 // can our driver switch to the new state?
3715 if ( priv
->head_note_capabilityFlags
& IOPMNotAttainable
)
3717 // no, ask the parent to do it then
3718 if ( ! priv
->we_are_root
)
3720 ask_parent(priv
->head_note_state
);
3722 // mark the change note un-actioned
3723 priv
-> head_note_flags
|= IOPMNotDone
;
3729 // is there enough power in the domain?
3730 if ( (pm_vars
->maxCapability
< priv
->head_note_state
) && (! priv
->we_are_root
) )
3732 // no, ask the parent to raise it
3733 if ( ! priv
->we_are_root
)
3735 ask_parent(priv
->head_note_state
);
3737 // no, mark the change note un-actioned
3738 priv
->head_note_flags
|= IOPMNotDone
;
3740 // till the parent raises power
3745 if ( ! priv
->initial_change
)
3747 if ( priv
->head_note_state
== pm_vars
->myCurrentState
)
3749 // we initiated a null change; forget it
3754 priv
->initial_change
= false;
3757 if ( priv
->head_note_state
< pm_vars
->myCurrentState
)
3759 // yes, in case we have to wait for acks
3760 priv
->machine_state
= kIOPM_OurChangeTellClientsPowerDown
;
3761 pm_vars
->doNotPowerDown
= false;
3763 // ask apps and kernel clients if we can drop power
3764 pm_vars
->outofbandparameter
= kNotifyApps
;
3765 if ( askChangeDown(priv
->head_note_state
) )
3767 // don't have to wait, did any clients veto?
3768 if ( pm_vars
->doNotPowerDown
)
3770 // yes, rescind the warning
3771 tellNoChangeDown(priv
->head_note_state
);
3772 // mark the change note un-actioned
3773 priv
-> head_note_flags
|= IOPMNotDone
;
3777 // no, tell'em we're dropping power
3778 OurChangeTellClientsPowerDown();
3782 // we are raising power
3783 if ( ! priv
->we_are_root
)
3785 // if this changes our power requirement, tell the parent
3786 ask_parent(priv
->head_note_state
);
3788 // in case they don't all ack
3789 priv
->machine_state
= kIOPM_OurChangeSetPowerState
;
3791 // notify interested drivers and children
3792 if ( notifyAll(true) == IOPMAckImplied
)
3794 OurChangeSetPowerState();
3800 //*********************************************************************************
3803 // Call the power domain parent to ask for a higher power state in the domain
3804 // or to suggest a lower power state.
3805 //*********************************************************************************
3807 IOReturn
IOService::ask_parent ( unsigned long requestedState
)
3811 IOPowerConnection
*connection
;
3813 unsigned long ourRequest
= pm_vars
->thePowerStates
[requestedState
].inputPowerRequirement
;
3815 if ( pm_vars
->thePowerStates
[requestedState
].capabilityFlags
& (kIOPMChildClamp
| kIOPMPreventIdleSleep
) )
3817 ourRequest
|= kIOPMPreventIdleSleep
;
3819 if ( pm_vars
->thePowerStates
[requestedState
].capabilityFlags
& (kIOPMChildClamp2
| kIOPMPreventSystemSleep
) )
3821 ourRequest
|= kIOPMPreventSystemSleep
;
3824 // is this a new desire?
3825 if ( priv
->previousRequest
== ourRequest
)
3827 // no, the parent knows already, just return
3831 if ( priv
->we_are_root
)
3835 priv
->previousRequest
= ourRequest
;
3837 iter
= getParentIterator(gIOPowerPlane
);
3841 while ( (next
= iter
->getNextObject()) )
3843 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) )
3845 parent
= (IOService
*)connection
->copyParentEntry(gIOPowerPlane
);
3847 if ( parent
->requestPowerDomainState(ourRequest
,connection
,IOPMLowestState
)!= IOPMNoErr
)
3849 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogRequestDenied
,
3850 (unsigned long)priv
->previousRequest
,0);
3863 //*********************************************************************************
3866 // Call the controlling driver and have it change the power state of the
3867 // hardware. If it returns IOPMAckImplied, the change is complete, and
3868 // we return IOPMAckImplied. Otherwise, it will ack when the change
3869 // is done; we return IOPMWillAckLater.
3870 //*********************************************************************************
3871 IOReturn
IOService::instruct_driver ( unsigned long newState
)
3875 // can our driver switch to the desired state?
3876 if ( pm_vars
->thePowerStates
[newState
].capabilityFlags
& IOPMNotAttainable
)
3879 return IOPMAckImplied
;
3882 priv
->driver_timer
= -1;
3885 OUR_PMLog( kPMLogProgramHardware
, (UInt32
) this, newState
);
3886 delay
= pm_vars
->theControllingDriver
->setPowerState( newState
,this );
3887 OUR_PMLog((UInt32
) -kPMLogProgramHardware
, (UInt32
) this, (UInt32
) delay
);
3890 if ( delay
== IOPMAckImplied
)
3892 priv
->driver_timer
= 0;
3893 return IOPMAckImplied
;
3896 // it acked behind our back
3897 if ( priv
->driver_timer
== 0 )
3899 return IOPMAckImplied
;
3905 return IOPMAckImplied
;
3909 priv
->driver_timer
= (delay
/ ( ACK_TIMER_PERIOD
/ ns_per_us
)) + 1;
3910 return IOPMWillAckLater
;
3914 //*********************************************************************************
3917 // We are acquiring the lock we use to protect our queue head from
3918 // simutaneous access by a thread which calls acknowledgePowerStateChange
3919 // or acknowledgeSetPowerState and the ack timer expiration thread.
3920 // Return TRUE if we acquire the lock, and the queue head didn't change
3921 // while we were acquiring the lock (and maybe blocked).
3922 // If there is no queue head, or it changes while we are blocked,
3923 // return FALSE with the lock unlocked.
3924 //*********************************************************************************
3926 bool IOService::acquire_lock ( void )
3928 long current_change_note
;
3930 current_change_note
= priv
->head_note
;
3931 if ( current_change_note
== -1 ) {
3935 IOTakeLock(priv
->our_lock
);
3936 if ( current_change_note
== priv
->head_note
)
3940 // we blocked and something changed radically
3941 // so there's nothing to do any more
3942 IOUnlock(priv
->our_lock
);
3948 //*********************************************************************************
3951 // Ask registered applications and kernel clients if we can change to a lower
3954 // Subclass can override this to send a different message type. Parameter is
3955 // the destination state number.
3957 // Return true if we don't have to wait for acknowledgements
3958 //*********************************************************************************
3960 bool IOService::askChangeDown ( unsigned long stateNum
)
3962 return tellClientsWithResponse(kIOMessageCanDevicePowerOff
);
3966 //*********************************************************************************
3969 // Notify registered applications and kernel clients that we are definitely
3972 // Return true if we don't have to wait for acknowledgements
3973 //*********************************************************************************
3975 bool IOService::tellChangeDown1 ( unsigned long stateNum
)
3977 pm_vars
->outofbandparameter
= kNotifyApps
;
3978 return tellChangeDown(stateNum
);
3982 //*********************************************************************************
3985 // Notify priority clients that we are definitely dropping power.
3987 // Return true if we don't have to wait for acknowledgements
3988 //*********************************************************************************
3990 bool IOService::tellChangeDown2 ( unsigned long stateNum
)
3992 pm_vars
->outofbandparameter
= kNotifyPriority
;
3993 return tellChangeDown(stateNum
);
3997 //*********************************************************************************
4000 // Notify registered applications and kernel clients that we are definitely
4003 // Subclass can override this to send a different message type. Parameter is
4004 // the destination state number.
4006 // Return true if we don't have to wait for acknowledgements
4007 //*********************************************************************************
4009 bool IOService::tellChangeDown ( unsigned long stateNum
)
4011 return tellClientsWithResponse(kIOMessageDeviceWillPowerOff
);
4015 //*********************************************************************************
4016 // tellClientsWithResponse
4018 // Notify registered applications and kernel clients that we are definitely
4021 // Return true if we don't have to wait for acknowledgements
4022 //*********************************************************************************
4024 bool IOService::tellClientsWithResponse ( int messageType
)
4026 struct context theContext
;
4027 AbsoluteTime deadline
;
4030 pm_vars
->responseFlags
= OSArray::withCapacity( 1 );
4031 pm_vars
->serialNumber
+= 1;
4033 theContext
.responseFlags
= pm_vars
->responseFlags
;
4034 theContext
.serialNumber
= pm_vars
->serialNumber
;
4035 theContext
.flags_lock
= priv
->flags_lock
;
4036 theContext
.counter
= 1;
4037 theContext
.msgType
= messageType
;
4038 theContext
.us
= this;
4039 theContext
.maxTimeRequested
= 0;
4040 theContext
.stateNumber
= priv
->head_note_state
;
4041 theContext
.stateFlags
= priv
->head_note_capabilityFlags
;
4043 IOLockLock(priv
->flags_lock
);
4045 // position zero is false to
4046 // prevent allowCancelCommon from succeeding
4047 aBool
= OSBoolean::withBoolean(false);
4048 theContext
.responseFlags
->setObject(0,aBool
);
4050 IOLockUnlock(priv
->flags_lock
);
4052 switch ( pm_vars
->outofbandparameter
) {
4054 applyToInterested(gIOAppPowerStateInterest
,tellAppWithResponse
,(void *)&theContext
);
4055 applyToInterested(gIOGeneralInterest
,tellClientWithResponse
,(void *)&theContext
);
4057 case kNotifyPriority
:
4058 applyToInterested(gIOPriorityPowerStateInterest
,tellClientWithResponse
,(void *)&theContext
);
4062 if (! acquire_lock() )
4066 IOLockLock(priv
->flags_lock
);
4067 // now fix position zero
4068 aBool
= OSBoolean::withBoolean(true);
4069 theContext
.responseFlags
->replaceObject(0,aBool
);
4071 IOLockUnlock(priv
->flags_lock
);
4073 // do we have to wait for somebody?
4074 if ( ! checkForDone() )
4076 // yes, start the ackTimer
4077 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogStartAckTimer
,theContext
.maxTimeRequested
,0);
4078 clock_interval_to_deadline(theContext
.maxTimeRequested
/ 1000, kMillisecondScale
, &deadline
);
4080 thread_call_enter_delayed(priv
->ackTimer
, deadline
);
4082 IOUnlock(priv
->our_lock
);
4086 IOUnlock(priv
->our_lock
);
4087 IOLockLock(priv
->flags_lock
);
4089 // everybody responded
4090 pm_vars
->responseFlags
->release();
4091 pm_vars
->responseFlags
= NULL
;
4092 IOLockUnlock(priv
->flags_lock
);
4098 //*********************************************************************************
4099 // tellAppWithResponse
4101 // We send a message to an application, and we expect a response, so we compute a
4102 // cookie we can identify the response with.
4103 //*********************************************************************************
4104 void tellAppWithResponse ( OSObject
* object
, void * context
)
4106 struct context
*theContext
= (struct context
*)context
;
4108 IOPMprot
*pm_vars
= theContext
->us
->pm_vars
;
4110 if( OSDynamicCast( IOService
, object
) )
4112 // Automatically 'ack' in kernel clients
4113 IOLockLock(theContext
->flags_lock
);
4114 aBool
= OSBoolean::withBoolean(true);
4115 theContext
->responseFlags
->setObject(theContext
->counter
,aBool
);
4117 IOLockUnlock(theContext
->flags_lock
);
4119 const char *who
= ((IOService
*) object
)->getName();
4120 pm_vars
->thePlatform
->PMLog(who
,
4121 kPMLogClientAcknowledge
, theContext
->msgType
, * (UInt32
*) object
);
4123 UInt32 refcon
= ((theContext
->serialNumber
& 0xFFFF)<<16)
4124 + (theContext
->counter
& 0xFFFF);
4125 IOLockLock(theContext
->flags_lock
);
4126 aBool
= OSBoolean::withBoolean(false);
4127 theContext
->responseFlags
->setObject(theContext
->counter
,aBool
);
4129 IOLockUnlock(theContext
->flags_lock
);
4131 OUR_PMLog(kPMLogAppNotify
, theContext
->msgType
, refcon
);
4132 theContext
->us
->messageClient(theContext
->msgType
,object
,(void *)refcon
);
4133 if ( theContext
->maxTimeRequested
< k30seconds
)
4135 theContext
->maxTimeRequested
= k30seconds
;
4138 theContext
->counter
+= 1;
4141 //*********************************************************************************
4142 // tellClientWithResponse
4144 // We send a message to an in-kernel client, and we expect a response, so we compute a
4145 // cookie we can identify the response with.
4146 // If it doesn't understand the notification (it is not power-management savvy)
4147 // we won't wait for it to prepare for sleep. If it tells us via a return code
4148 // in the passed struct that it is currently ready, we won't wait for it to prepare.
4149 // If it tells us via the return code in the struct that it does need time, we will chill.
4150 //*********************************************************************************
4151 void tellClientWithResponse ( OSObject
* object
, void * context
)
4153 struct context
*theContext
= (struct context
*)context
;
4154 IOPowerStateChangeNotification notify
;
4160 refcon
= ((theContext
->serialNumber
& 0xFFFF)<<16) + (theContext
->counter
& 0xFFFF);
4161 IOLockLock(theContext
->flags_lock
);
4162 aBool
= OSBoolean::withBoolean(false);
4163 theContext
->responseFlags
->setObject(theContext
->counter
,aBool
);
4165 IOLockUnlock(theContext
->flags_lock
);
4167 IOPMprot
*pm_vars
= theContext
->us
->pm_vars
;
4168 if (gIOKitDebug
& kIOLogPower
) {
4169 OUR_PMLog(kPMLogClientNotify
, refcon
, (UInt32
) theContext
->msgType
);
4170 if (OSDynamicCast(IOService
, object
)) {
4171 const char *who
= ((IOService
*) object
)->getName();
4172 pm_vars
->thePlatform
->PMLog(who
,
4173 kPMLogClientNotify
, * (UInt32
*) object
, (UInt32
) object
);
4174 } else if (OSDynamicCast(_IOServiceInterestNotifier
, object
)) {
4175 _IOServiceInterestNotifier
*n
= (_IOServiceInterestNotifier
*) object
;
4176 OUR_PMLog(kPMLogClientNotify
, (UInt32
) n
->handler
, 0);
4180 notify
.powerRef
= (void *)refcon
;
4181 notify
.returnValue
= 0;
4182 notify
.stateNumber
= theContext
->stateNumber
;
4183 notify
.stateFlags
= theContext
->stateFlags
;
4184 retCode
= theContext
->us
->messageClient(theContext
->msgType
,object
,(void *)¬ify
);
4185 if ( retCode
== kIOReturnSuccess
)
4187 if ( notify
.returnValue
== 0 )
4189 // client doesn't want time to respond
4190 IOLockLock(theContext
->flags_lock
);
4191 aBool
= OSBoolean::withBoolean(true);
4192 // so set its flag true
4193 theContext
->responseFlags
->replaceObject(theContext
->counter
,aBool
);
4195 IOLockUnlock(theContext
->flags_lock
);
4196 OUR_PMLog(kPMLogClientAcknowledge
, refcon
, (UInt32
) object
);
4198 IOLockLock(theContext
->flags_lock
);
4200 // it does want time, and it hasn't responded yet
4201 theFlag
= theContext
->responseFlags
->getObject(theContext
->counter
);
4204 if ( ((OSBoolean
*)theFlag
)->isFalse() )
4206 // so note its time requirement
4207 if ( theContext
->maxTimeRequested
< notify
.returnValue
)
4209 theContext
->maxTimeRequested
= notify
.returnValue
;
4213 IOLockUnlock(theContext
->flags_lock
);
4216 OUR_PMLog(kPMLogClientAcknowledge
, refcon
, 0);
4217 // not a client of ours
4218 IOLockLock(theContext
->flags_lock
);
4219 // so we won't be waiting for response
4220 aBool
= OSBoolean::withBoolean(true);
4221 theContext
->responseFlags
->replaceObject(theContext
->counter
,aBool
);
4223 IOLockUnlock(theContext
->flags_lock
);
4225 theContext
->counter
+= 1;
4229 //*********************************************************************************
4232 // Notify registered applications and kernel clients that we are not
4235 // Subclass can override this to send a different message type. Parameter is
4236 // the aborted destination state number.
4237 //*********************************************************************************
4239 void IOService::tellNoChangeDown ( unsigned long )
4241 return tellClients(kIOMessageDeviceWillNotPowerOff
);
4245 //*********************************************************************************
4248 // Notify registered applications and kernel clients that we are raising power.
4250 // Subclass can override this to send a different message type. Parameter is
4251 // the aborted destination state number.
4252 //*********************************************************************************
4254 void IOService::tellChangeUp ( unsigned long )
4256 return tellClients(kIOMessageDeviceHasPoweredOn
);
4260 //*********************************************************************************
4263 // Notify registered applications and kernel clients of something.
4264 //*********************************************************************************
4266 void IOService::tellClients ( int messageType
)
4268 struct context theContext
;
4270 theContext
.msgType
= messageType
;
4271 theContext
.us
= this;
4272 theContext
.stateNumber
= priv
->head_note_state
;
4273 theContext
.stateFlags
= priv
->head_note_capabilityFlags
;
4275 applyToInterested(gIOAppPowerStateInterest
,tellClient
,(void *)&theContext
);
4276 applyToInterested(gIOGeneralInterest
,tellClient
,(void *)&theContext
);
4280 //*********************************************************************************
4283 // Notify a registered application or kernel client of something.
4284 //*********************************************************************************
4285 void tellClient ( OSObject
* object
, void * context
)
4287 struct context
*theContext
= (struct context
*)context
;
4288 IOPowerStateChangeNotification notify
;
4290 notify
.powerRef
= (void *) 0;
4291 notify
.returnValue
= 0;
4292 notify
.stateNumber
= theContext
->stateNumber
;
4293 notify
.stateFlags
= theContext
->stateFlags
;
4295 theContext
->us
->messageClient(theContext
->msgType
,object
, ¬ify
);
4299 // **********************************************************************************
4302 // **********************************************************************************
4303 bool IOService::checkForDone ( void )
4308 IOLockLock(priv
->flags_lock
);
4309 if ( pm_vars
->responseFlags
== NULL
)
4311 IOLockUnlock(priv
->flags_lock
);
4315 for ( i
= 0; ; i
++ )
4317 theFlag
= pm_vars
->responseFlags
->getObject(i
);
4318 if ( theFlag
== NULL
)
4322 if ( ((OSBoolean
*)theFlag
)->isFalse() )
4324 IOLockUnlock(priv
->flags_lock
);
4328 IOLockUnlock(priv
->flags_lock
);
4333 // **********************************************************************************
4336 // **********************************************************************************
4337 bool IOService::responseValid ( unsigned long x
)
4339 UInt16 serialComponent
;
4340 UInt16 ordinalComponent
;
4342 unsigned long refcon
= (unsigned long)x
;
4345 serialComponent
= (refcon
>>16) & 0xFFFF;
4346 ordinalComponent
= refcon
& 0xFFFF;
4348 if ( serialComponent
!= pm_vars
->serialNumber
)
4353 IOLockLock(priv
->flags_lock
);
4354 if ( pm_vars
->responseFlags
== NULL
)
4356 IOLockUnlock(priv
->flags_lock
);
4360 theFlag
= pm_vars
->responseFlags
->getObject(ordinalComponent
);
4364 IOLockUnlock(priv
->flags_lock
);
4368 if ( ((OSBoolean
*)theFlag
)->isFalse() )
4370 aBool
= OSBoolean::withBoolean(true);
4371 pm_vars
->responseFlags
->replaceObject(ordinalComponent
,aBool
);
4375 IOLockUnlock(priv
->flags_lock
);
4380 // **********************************************************************************
4383 // Our power state is about to lower, and we have notified applications
4384 // and kernel clients, and one of them has acknowledged. If this is the last to do
4385 // so, and all acknowledgements are positive, we continue with the power change.
4387 // We serialize this processing with timer expiration with a command gate on the
4388 // power management workloop, which the timer expiration is command gated to as well.
4389 // **********************************************************************************
4390 IOReturn
IOService::allowPowerChange ( unsigned long refcon
)
4392 if ( ! initialized
)
4395 return kIOReturnSuccess
;
4398 return pm_vars
->PMcommandGate
->runAction(serializedAllowPowerChange
,(void *)refcon
);
4402 IOReturn
serializedAllowPowerChange ( OSObject
*owner
, void * refcon
, void *, void *, void *)
4404 return ((IOService
*)owner
)->serializedAllowPowerChange2((unsigned long)refcon
);
4407 IOReturn
IOService::serializedAllowPowerChange2 ( unsigned long refcon
)
4410 if ( ! responseValid(refcon
) )
4412 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogAcknowledgeErr5
,refcon
,0);
4414 return kIOReturnSuccess
;
4416 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogClientAcknowledge
,refcon
,0);
4418 return allowCancelCommon();
4422 // **********************************************************************************
4423 // cancelPowerChange
4425 // Our power state is about to lower, and we have notified applications
4426 // and kernel clients, and one of them has vetoed the change. If this is the last
4427 // client to respond, we abandon the power change.
4429 // We serialize this processing with timer expiration with a command gate on the
4430 // power management workloop, which the timer expiration is command gated to as well.
4431 // **********************************************************************************
4432 IOReturn
IOService::cancelPowerChange ( unsigned long refcon
)
4434 if ( ! initialized
)
4437 return kIOReturnSuccess
;
4440 return pm_vars
->PMcommandGate
->runAction(serializedCancelPowerChange
,(void *)refcon
);
4444 IOReturn
serializedCancelPowerChange ( OSObject
*owner
, void * refcon
, void *, void *, void *)
4446 return ((IOService
*)owner
)->serializedCancelPowerChange2((unsigned long)refcon
);
4449 IOReturn
IOService::serializedCancelPowerChange2 ( unsigned long refcon
)
4452 if ( ! responseValid(refcon
) )
4454 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogAcknowledgeErr5
,refcon
,0);
4456 return kIOReturnSuccess
;
4458 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogClientCancel
,refcon
,0);
4460 pm_vars
->doNotPowerDown
= true;
4462 return allowCancelCommon();
4466 // **********************************************************************************
4467 // allowCancelCommon
4469 // **********************************************************************************
4470 IOReturn
IOService::allowCancelCommon ( void )
4472 if (! acquire_lock() )
4474 return kIOReturnSuccess
;
4477 // is this the last response?
4478 if ( checkForDone() )
4480 // yes, stop the timer
4482 IOUnlock(priv
->our_lock
);
4483 IOLockLock(priv
->flags_lock
);
4484 if ( pm_vars
->responseFlags
)
4486 pm_vars
->responseFlags
->release();
4487 pm_vars
->responseFlags
= NULL
;
4489 IOLockUnlock(priv
->flags_lock
);
4490 switch (priv
->machine_state
) {
4491 case kIOPM_OurChangeTellClientsPowerDown
:
4492 // our change, was it vetoed?
4493 if ( ! pm_vars
->doNotPowerDown
)
4495 // no, we can continue
4496 OurChangeTellClientsPowerDown();
4498 // yes, rescind the warning
4499 tellNoChangeDown(priv
->head_note_state
);
4500 // mark the change note un-actioned
4501 priv
->head_note_flags
|= IOPMNotDone
;
4507 case kIOPM_OurChangeTellPriorityClientsPowerDown
:
4508 OurChangeTellPriorityClientsPowerDown();
4510 case kIOPM_OurChangeNotifyInterestedDriversWillChange
:
4511 // our change, continue
4512 OurChangeNotifyInterestedDriversWillChange();
4514 case kIOPM_ParentDownTellPriorityClientsPowerDown_Immediate
:
4515 // parent change, continue
4516 ParentDownTellPriorityClientsPowerDown_Delayed();
4518 case kIOPM_ParentDownNotifyInterestedDriversWillChange_Delayed
:
4519 // parent change, continue
4520 ParentDownNotifyInterestedDriversWillChange_Delayed();
4525 IOUnlock(priv
->our_lock
);
4528 return kIOReturnSuccess
;
4533 //*********************************************************************************
4534 // c_PM_clamp_Timer_Expired (C Func)
4536 // Called when our clamp timer expires...we will call the object method.
4537 //*********************************************************************************
4539 static void c_PM_Clamp_Timer_Expired (OSObject
* client
, IOTimerEventSource
*)
4542 ((IOService
*)client
)->PM_Clamp_Timer_Expired ();
4547 //*********************************************************************************
4548 // PM_Clamp_Timer_Expired
4550 // called when clamp timer expires...set power state to 0.
4551 //*********************************************************************************
4553 void IOService::PM_Clamp_Timer_Expired (void)
4556 if ( ! initialized
)
4562 changePowerStateToPriv (0);
4566 //******************************************************************************
4569 // Set to highest available power state for a minimum of duration milliseconds
4570 //******************************************************************************
4572 #define kFiveMinutesInNanoSeconds (300 * NSEC_PER_SEC)
4574 void IOService::clampPowerOn (unsigned long duration
)
4577 changePowerStateToPriv (pm_vars
->theNumberOfPowerStates
-1);
4579 if ( priv
->clampTimerEventSrc
== NULL
) {
4580 priv
->clampTimerEventSrc
= IOTimerEventSource::timerEventSource(this,
4581 c_PM_Clamp_Timer_Expired
);
4583 IOWorkLoop
* workLoop
= getPMworkloop ();
4585 if ( !priv
->clampTimerEventSrc
|| !workLoop
||
4586 ( workLoop
->addEventSource( priv
->clampTimerEventSrc
) != kIOReturnSuccess
) ) {
4591 priv
->clampTimerEventSrc
->setTimeout(300*USEC_PER_SEC
, USEC_PER_SEC
);
4595 //*********************************************************************************
4598 // Does nothing here. This should be implemented in a subclass driver.
4599 //*********************************************************************************
4601 IOReturn
IOService::setPowerState ( unsigned long powerStateOrdinal
, IOService
* whatDevice
)
4607 //*********************************************************************************
4608 // maxCapabilityForDomainState
4610 // Finds the highest power state in the array whose input power
4611 // requirement is equal to the input parameter. Where a more intelligent
4612 // decision is possible, override this in the subclassed driver.
4613 //*********************************************************************************
4615 unsigned long IOService::maxCapabilityForDomainState ( IOPMPowerFlags domainState
)
4619 if (pm_vars
->theNumberOfPowerStates
== 0 )
4623 for ( i
= (pm_vars
->theNumberOfPowerStates
)-1; i
>= 0; i
-- )
4625 if ( (domainState
& pm_vars
->thePowerStates
[i
].inputPowerRequirement
) == pm_vars
->thePowerStates
[i
].inputPowerRequirement
)
4634 //*********************************************************************************
4635 // initialPowerStateForDomainState
4637 // Finds the highest power state in the array whose input power
4638 // requirement is equal to the input parameter. Where a more intelligent
4639 // decision is possible, override this in the subclassed driver.
4640 //*********************************************************************************
4642 unsigned long IOService::initialPowerStateForDomainState ( IOPMPowerFlags domainState
)
4646 if (pm_vars
->theNumberOfPowerStates
== 0 )
4650 for ( i
= (pm_vars
->theNumberOfPowerStates
)-1; i
>= 0; i
-- )
4652 if ( (domainState
& pm_vars
->thePowerStates
[i
].inputPowerRequirement
) == pm_vars
->thePowerStates
[i
].inputPowerRequirement
)
4661 //*********************************************************************************
4662 // powerStateForDomainState
4664 // Finds the highest power state in the array whose input power
4665 // requirement is equal to the input parameter. Where a more intelligent
4666 // decision is possible, override this in the subclassed driver.
4667 //*********************************************************************************
4669 unsigned long IOService::powerStateForDomainState ( IOPMPowerFlags domainState
)
4673 if (pm_vars
->theNumberOfPowerStates
== 0 )
4677 for ( i
= (pm_vars
->theNumberOfPowerStates
)-1; i
>= 0; i
-- )
4679 if ( (domainState
& pm_vars
->thePowerStates
[i
].inputPowerRequirement
) == pm_vars
->thePowerStates
[i
].inputPowerRequirement
)
4688 //*********************************************************************************
4691 // Does nothing here. This should be implemented in a subclass driver.
4692 //*********************************************************************************
4694 bool IOService::didYouWakeSystem ( void )
4700 //*********************************************************************************
4701 // powerStateWillChangeTo
4703 // Does nothing here. This should be implemented in a subclass driver.
4704 //*********************************************************************************
4706 IOReturn
IOService::powerStateWillChangeTo ( IOPMPowerFlags
, unsigned long, IOService
*)
4712 //*********************************************************************************
4713 // powerStateDidChangeTo
4715 // Does nothing here. This should be implemented in a subclass driver.
4716 //*********************************************************************************
4718 IOReturn
IOService::powerStateDidChangeTo ( IOPMPowerFlags
, unsigned long, IOService
*)
4724 //*********************************************************************************
4727 // Does nothing here. This should be implemented in a subclass policy-maker.
4728 //*********************************************************************************
4730 void IOService::powerChangeDone ( unsigned long )
4735 //*********************************************************************************
4738 // Does nothing here. This should be implemented in a subclass driver.
4739 //*********************************************************************************
4741 IOReturn
IOService::newTemperature ( long currentTemp
, IOService
* whichZone
)
4749 #define super OSObject
4751 OSDefineMetaClassAndStructors(IOPMprot
, OSObject
)
4752 //*********************************************************************************
4755 // Serialize protected instance variables for debug output.
4756 //*********************************************************************************
4757 bool IOPMprot::serialize(OSSerialize
*s
) const
4759 OSString
* theOSString
;
4766 // estimate how many bytes we need to present all power states
4767 buf_size
= 150 // beginning and end of string
4768 + (275 * (int)theNumberOfPowerStates
) // size per state
4769 + 100; // extra room just for kicks
4771 buffer
= ptr
= IONew(char, buf_size
);
4775 ptr
+= sprintf(ptr
,"{ theNumberOfPowerStates = %d, ",(unsigned int)theNumberOfPowerStates
);
4777 if ( theNumberOfPowerStates
!= 0 ) {
4778 ptr
+= sprintf(ptr
,"version %d, ",(unsigned int)thePowerStates
[0].version
);
4781 if ( theNumberOfPowerStates
!= 0 ) {
4782 for ( i
= 0; i
< (int)theNumberOfPowerStates
; i
++ ) {
4783 ptr
+= sprintf(ptr
, "power state %d = { ",i
);
4784 ptr
+= sprintf(ptr
,"capabilityFlags %08x, ",(unsigned int)thePowerStates
[i
].capabilityFlags
);
4785 ptr
+= sprintf(ptr
,"outputPowerCharacter %08x, ",(unsigned int)thePowerStates
[i
].outputPowerCharacter
);
4786 ptr
+= sprintf(ptr
,"inputPowerRequirement %08x, ",(unsigned int)thePowerStates
[i
].inputPowerRequirement
);
4787 ptr
+= sprintf(ptr
,"staticPower %d, ",(unsigned int)thePowerStates
[i
].staticPower
);
4788 ptr
+= sprintf(ptr
,"unbudgetedPower %d, ",(unsigned int)thePowerStates
[i
].unbudgetedPower
);
4789 ptr
+= sprintf(ptr
,"powerToAttain %d, ",(unsigned int)thePowerStates
[i
].powerToAttain
);
4790 ptr
+= sprintf(ptr
,"timeToAttain %d, ",(unsigned int)thePowerStates
[i
].timeToAttain
);
4791 ptr
+= sprintf(ptr
,"settleUpTime %d, ",(unsigned int)thePowerStates
[i
].settleUpTime
);
4792 ptr
+= sprintf(ptr
,"timeToLower %d, ",(unsigned int)thePowerStates
[i
].timeToLower
);
4793 ptr
+= sprintf(ptr
,"settleDownTime %d, ",(unsigned int)thePowerStates
[i
].settleDownTime
);
4794 ptr
+= sprintf(ptr
,"powerDomainBudget %d }, ",(unsigned int)thePowerStates
[i
].powerDomainBudget
);
4798 ptr
+= sprintf(ptr
,"aggressiveness = %d, ",(unsigned int)aggressiveness
);
4799 ptr
+= sprintf(ptr
,"myCurrentState = %d, ",(unsigned int)myCurrentState
);
4800 ptr
+= sprintf(ptr
,"parentsCurrentPowerFlags = %08x, ",(unsigned int)parentsCurrentPowerFlags
);
4801 ptr
+= sprintf(ptr
,"maxCapability = %d }",(unsigned int)maxCapability
);
4803 theOSString
= OSString::withCString(buffer
);
4804 rtn_code
= theOSString
->serialize(s
);
4805 theOSString
->release();
4806 IODelete(buffer
, char, buf_size
);
4813 #define super OSObject
4815 OSDefineMetaClassAndStructors(IOPMpriv
, OSObject
)
4816 //*********************************************************************************
4819 // Serialize private instance variables for debug output.
4820 //*********************************************************************************
4821 bool IOPMpriv::serialize(OSSerialize
*s
) const
4823 OSString
* theOSString
;
4827 IOPMinformee
* nextObject
;
4829 buffer
= ptr
= IONew(char, 2000);
4833 ptr
+= sprintf(ptr
,"{ this object = %08x",(unsigned int)owner
);
4834 if ( we_are_root
) {
4835 ptr
+= sprintf(ptr
," (root)");
4837 ptr
+= sprintf(ptr
,", ");
4839 nextObject
= interestedDrivers
->firstInList(); // display interested drivers
4840 while ( nextObject
!= NULL
) {
4841 ptr
+= sprintf(ptr
,"interested driver = %08x, ",(unsigned int)nextObject
->whatObject
);
4842 nextObject
= interestedDrivers
->nextInList(nextObject
);
4845 if ( machine_state
!= kIOPM_Finished
) {
4846 ptr
+= sprintf(ptr
,"machine_state = %d, ",(unsigned int)machine_state
);
4847 ptr
+= sprintf(ptr
,"driver_timer = %d, ",(unsigned int)driver_timer
);
4848 ptr
+= sprintf(ptr
,"settle_time = %d, ",(unsigned int)settle_time
);
4849 ptr
+= sprintf(ptr
,"head_note_flags = %08x, ",(unsigned int)head_note_flags
);
4850 ptr
+= sprintf(ptr
,"head_note_state = %d, ",(unsigned int)head_note_state
);
4851 ptr
+= sprintf(ptr
,"head_note_outputFlags = %08x, ",(unsigned int)head_note_outputFlags
);
4852 ptr
+= sprintf(ptr
,"head_note_domainState = %08x, ",(unsigned int)head_note_domainState
);
4853 ptr
+= sprintf(ptr
,"head_note_capabilityFlags = %08x, ",(unsigned int)head_note_capabilityFlags
);
4854 ptr
+= sprintf(ptr
,"head_note_pendingAcks = %d, ",(unsigned int)head_note_pendingAcks
);
4857 if ( device_overrides
) {
4858 ptr
+= sprintf(ptr
,"device overrides, ");
4860 ptr
+= sprintf(ptr
,"driverDesire = %d, ",(unsigned int)driverDesire
);
4861 ptr
+= sprintf(ptr
,"deviceDesire = %d, ",(unsigned int)deviceDesire
);
4862 ptr
+= sprintf(ptr
,"ourDesiredPowerState = %d, ",(unsigned int)ourDesiredPowerState
);
4863 ptr
+= sprintf(ptr
,"previousRequest = %d }",(unsigned int)previousRequest
);
4865 theOSString
= OSString::withCString(buffer
);
4866 rtn_code
= theOSString
->serialize(s
);
4867 theOSString
->release();
4868 IODelete(buffer
, char, 2000);