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