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