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