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