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