|
|
1.1 root 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: #include <IOKit/IOService.h>
23: #include <IOKit/IOLib.h>
24: #include <IOKit/IOCommandQueue.h>
25: #include <IOKit/IOTimerEventSource.h>
26: #include <IOKit/IOWorkLoop.h>
27: #include <IOKit/IOPlatformExpert.h>
28: #include <IOKit/assert.h>
29: #include "IOKit/pwr_mgt/IOPMpmChild.h"
30: #include "IOKit/pwr_mgt/IOPMinformeeList.h"
31: #include "IOKit/pwr_mgt/IOPMchangeNoteList.h"
32: #include "IOKit/pwr_mgt/IOPMlog.h"
33:
34: static void ack_timer_expired(thread_call_param_t, thread_call_param_t);
35: static void settle_timer_expired(thread_call_param_t, thread_call_param_t);
36: void PMreceiveCmd ( OSObject *, void *, void *, void *, void * );
37: static void PM_idle_timer_expired(OSObject *, IOTimerEventSource *);
38:
39: extern const IORegistryPlane * gIOPowerPlane;
40:
41:
42: // and there's 1000 nanosecons in a microsecond:
43: #define ns_per_us 1000
44:
45:
46: // The current change note is processed by a state machine.
47: // Inputs are acks from interested parties, ack from the controlling driver,
48: // ack timeouts, settle timeout, and powerStateDidChange from the parent.
49: // These are the states:
50:
51: #define IOPMour_prechange_1 1
52: #define IOPMour_prechange_2 2
53: #define IOPMour_prechange_3 3
54: #define IOPMour_prechange_4 4
55: #define IOPMparent_prechange_down_3 5
56: #define IOPMparent_prechange_down_4 6
57: #define IOPMparent_prechange_down_5 7
58: #define IOPMparent_postchange_down_1 8
59: #define IOPMparent_postchange_down_2 9
60: #define IOPMparent_prechange_up_1 10
61: #define IOPMparent_postchange_up_1 11
62: #define IOPMparent_postchange_up_4 12
63: #define IOPMparent_postchange_up_5 13
64: #define IOPMparent_postchange_up_6 14
65: #define IOPMparent_postchange_null 15
66: #define IOPMfinished 16
67:
68: /*
69: There are two different kinds of power state changes. One is initiated by a subclassed device object which has either
70: decided to change power state, or its controlling driver has suggested it, or some other driver wants to use the
71: idle device and has asked it to become usable. The second kind of power state change is initiated by the power
72: domain parent. The two are handled slightly differently.
73:
74: There is a queue of so-called change notifications, or change notes for short. Usually the queue is empty, and when
75: 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
76: at one time, a queue is implemented. Example: the subclass device decides it's idle and initiates a change to a lower
77: power state. This causes interested parties to be notified, but they don't all acknowledge right away. This causes the
78: 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
79: wants to raise power back up again. This change can't be started, however, because the previous one isn't complete yet,
80: so the second one waits in the queue. During this time, the parent decides to lower or raise the power state of the entire
81: power domain and notifies the device, and that notification goes into the queue, too, and can't be actioned until the
82: others are.
83:
84: This is how a power change initiated by the subclass device is handled:
85: First, all interested parties are notified of the change via their powerStateWillChangeTo method. If they all don't
86: acknowledge via return code, then we have to wait. If they do, or when they finally all acknowledge via our
87: acknowledgePowerChange method, then we can continue. We call the controlling driver, instructing it to change to
88: the new state. Then we wait for power to settle. If there is no settling-time, or after it has passed, we notify
89: interested parties again, this time via their powerStateDidChangeTo methods. When they have all acked, we're done.
90: If we lowered power and don't need the power domain to be in its current power state, we suggest to the parent that
91: it lower the power domain state.
92:
93: This is how a change to a lower power domain state initiated by the parent is handled:
94: First, we figure out what power state we will be in when the new domain state is reached. Then all interested parties are
95: notified that we are moving to that new state. When they have acknowledged, we call the controlling driver to assume
96: that state and we wait for power to settle. Then we acknowledge our preparedness to our parent. When all its interested
97: parties have acknowledged, it lowers power and then notifies its interested parties again. When we get this call, we notify
98: our interested parties that the power state has changed, and when they have all acknowledged, we're done.
99:
100: This is how a change to a higher power domain state initiated by the parent is handled:
101: We figure out what power state we will be in when the new domain state is reached. If it is different from our current
102: state we notify all our interested parties. When they have all acknowledged, we acknowledge the parent. When all the
103: parent's interested parties have acknowledged, it raises power in the domain and waits for power to settle. Then it
104: notifies everyone that the new state has been reached. When we get this call, we call the controlling driver, instructing it
105: to assume the new state, and wait for power to settle. Then we notify our interested parties. When they all acknowledge
106: we are done.
107:
108: In either of the two cases above, it is possible that we will not be changing state even though the domain is. Examples:
109: A change to a lower domain state may not affect us because we are already in a low enough state, and
110: We will not take advantage of a change to a higher domain state, because we have no need of the higher power.
111: In such a case, there is nothing to do but acknowledge the parent. So when the parent calls our powerDomainWillChange
112: method, and we decide that we will not be changing state, we merely acknowledge the parent, via return code, and wait.
113: When the parent subsequently calls powerStateDidChange, we acknowledge again via return code, and the change is complete.
114:
115: Power state changes are processed in a state machine, and since there are four varieties of power state changes, there are
116: four major paths through the state machine:
117:
118: The fourth is nearly trivial. In this path, the parent is changing the domain state, but we are not changing the device state.
119: The change starts when the parent calls powerDomainWillChange. All we do is acknowledge the parent and enter the "IOPMparent_postchange" state. We wait there until the parent calls powerStateDidChange. Then we acknowledge the parent
120: again, and we're done.
121:
122: The first is fairly simple. It starts when a power domain child calls requestDomainState and we decide to change power states
123: to accomodate the child, or if our power-controlling driver calls changeStateTo, or if some other driver which is using our
124: device calls makeUsable, or if a subclassed object calls changeStateToPriv. These are all power changes initiated by us, not
125: forced upon us by the parent. We start by notifying interested parties. If they all acknowledge via return code, we can go
126: on to state "our_prechange_1". Otherwise, we start the ack timer and wait for the stragglers to acknowlege by calling
127: acknowledgePowerChange. We move on to state "our_prechange_1" when all the stragglers have acknowledged,
128: or when the ack timer expires on all those which didn't acknowledge. In "our_prechange_1" we call the power-controlling
129: driver to change the power state of the hardware. If it returns saying it has done so, we go on to state "our_prechange_2".
130: Otherwise, we have to wait for it, so we set the ack timer and wait. When it calls acknowledgeSetPowerState, or when the
131: ack timer expires, we go on. In "our_prechange_2", we look in the power state array to see if there is any settle time required
132: when changing from our current state to the new state. If not, we go right away to "our_prechange_3". Otherwise, we
133: set the settle timer and wait. When it expires, we move on. In "our_prechange_3" state, we notify all our interested parties
134: via their powerStateDidChange methods that we have finished changing power state. If they all acknowledge via return
135: code, we move on to "our_prechange_4". Otherwise we set the ack timer and wait. When they have all acknowledged, or
136: when the ack timer has expired for those that didn't, we move on to "our_prechange_4", where we remove the used
137: change note from the head of the queue and start the next one if one exists.
138:
139: Parent-initiated changes are more complex in the state machine. First, power going up and power going down are handled
140: differently, so they have different paths throught the state machine. Second, we can acknowledge the parent's notification
141: in two different ways, so each of the parent paths is really two.
142:
143: When the parent calls our powerDomainWillChange method, notifying us that it will lower power in the domain, we decide
144: what state that will put our device in. Then we embark on the state machine path "IOPMparent_prechange_down_1"
145: and "IOPMparent_prechange_down_2", in which we notify interested parties of the upcoming change,
146: instruct our driver to make the change, and check for settle time. If we get to the end of this path without
147: stalling due to an interested party which didn't acknowledge via return code, due to the controlling driver not able to change
148: state right away, or due to a non-zero settling time, then we return IOPMAckImplied to the parent and enter
149: "IOPMparent_postchange_down_1". If we do stall in any of those states, we return IOPMWillAckLater to the parent
150: and enter the parallel path "IOPMparent_prechange_down_4", "IOPMparent_prechange_down_5", and "IOPMparent_prechange_down_3", where we continue with the same processing, except that at the end we
151: acknowledge the parent explicitly via acknowledgePowerChange and enter "IOPMparent_postchange_down_1".
152: In "IOPMparent_postchange_down_1" we wait for the parent to lower power in the domain. When it calls us at
153: powerStateDidChange, we notify all our interested parties of the new power state. If they all acknowledge via return
154: code, we return to the parent, also acknowledging via return code. Otherwise we enter "parent_postchange_down_2",
155: waiting for acknowledgements. When they all arrive, or when the acknowledgement timer expires for all stragglers, we
156: explicitly acknowledge the parent via acknowledgePowerChange. In either case, we are done, and we remove the used
157: change note from the head of the queue and start on the next one.
158:
159: The case of the parent raising power in the domain is handled similarly in that there are parallel paths, one for no-stall
160: that ends in implicit acknowleging the parent, and one that has stalled at least once that ends in explicit acknowledging
161: the parent. This case is different, though in that our device changes state in the second half, after the parent calls
162: powerStateDidChange rather than before, as in the power-lowering case.
163:
164: As usual, we start by notifying our interested parties. If they all acknowledge via return code, we acknowledge the parent
165: via return code and enter "IOPMparent_postchange_up_1". If they don't, we wait in "parent_prechange_up_1" for them to
166: acknowledge or for the ack timer to expire on the stragglers. Then we acknowledge the parent via acknowledgePowerChange
167: and enter "IOPMparent_postchange_up_1", waiting for the parent to raise power and notify us. When the parent calls us
168: at powerStateDidChange, we instruct the power-controlling driver to change to the new higher state, we check for any
169: necessary settling time in "IOPMparent_postchange_up_2", and we notify all interested parties that power has changed
170: in "IOPMparent_postchange_up_3". If none of these operations stall, we acknowledge the parent via return code, release
171: the change note, and start the next, if there is one. If one of them does stall, we enter the parallel path
172: "IOPMparent_postchange_up_4", "IOPMparent_postchange_up_5", and "IOPMparent_postchange_up_6", which ends with
173: our explicit acknowledgement to the parent.
174:
175: */
176:
177:
178: const char priv_key[ ] = "Power Management private data";
179: const char prot_key[ ] = "Power Management protected data";
180:
181:
182: void IOService::PMinit ( void )
183: {
184: if ( ! initialized ) {
185:
186: pm_vars = new IOPMprot; // make space for our variables
187: priv = new IOPMpriv;
188: pm_vars->init();
189: priv->init();
190:
191: setProperty(prot_key, (OSObject *) pm_vars); // add these to the properties
192: setProperty(priv_key, (OSObject *) priv);
193:
194: initialized = true;
195: priv->owner = this;
196: pm_vars->theNumberOfPowerStates = 0; // then initialize them
197: pm_vars->myParent = NULL;
198: priv->we_are_root = false;
199: pm_vars->theControllingDriver = NULL;
200: priv->our_lock = IOLockAlloc();
201: priv->interestedDrivers = new IOPMinformeeList;
202: priv->interestedDrivers->initialize();
203: priv->children = new IOPMinformeeList;
204: priv->children->initialize();
205: priv->numberOfInformees = 0;
206: priv->changeList = new IOPMchangeNoteList;
207: priv->changeList->initialize();
208: pm_vars->aggressiveness = 0;
209: pm_vars->myCurrentState = 0;
210: priv->imminentState = 0;
211: priv->askingFor = 0;
212: priv->ourDesiredPowerState = 0;
213: pm_vars->parentCurrentPowerFlags = 0;
214: pm_vars->maxCapability = 0;
215: priv->driverDesire = 0;
216: priv->deviceDesire = 0;
217: priv->initial_change = true;
218: priv->need_to_become_usable = false;
219: priv->previousRequest = 0;
220: priv->device_overrides = false;
221: priv->machine_state = IOPMfinished;
222: pm_vars->commandQueue = NULL;
223: priv->timerEventSrc = NULL;
224: pm_vars->PMworkloop = NULL;
225: priv->activityLock = NULL;
226: pm_vars->ourName = getName();
227: pm_vars->thePlatform = getPlatform();
228: assert( pm_vars->thePlatform != 0 );
229: }
230: }
231:
232:
233: //*********************************************************************************
234: // PMstop
235: //
236: // Free up the data created in PMinit.
237: //*********************************************************************************
238: void IOService::PMstop ( void )
239: {
240: initialized = false;
241:
242: removeProperty(prot_key); // remove the properties
243: removeProperty(priv_key);
244: priv->interestedDrivers->release(); // remove lists
245: priv->children->release();
246: priv->changeList->release();
247: pm_vars->release(); // remove the instance variables
248: priv->release();
249: pm_vars = NULL;
250: priv = NULL;
251: }
252:
253:
254: //*********************************************************************************
255: // joinPMtree
256: //
257: // A policy-maker calls its nub here when initializing, to be attached into
258: // the power management hierarchy. The default function is to call the
259: // platform expert, which knows how to do it. This method is overridden
260: // by a nub subclass which may either know how to do it, or may need
261: // to take other action.
262: //
263: // This may be the only "power management" method used in a nub,
264: // meaning it may not be initialized for power management.
265: //*********************************************************************************
266: void IOService::joinPMtree ( IOService * driver )
267: {
268: IOPlatformExpert * thePlatform;
269:
270: thePlatform = getPlatform();
271: assert(thePlatform != 0 );
272: thePlatform->PMRegisterDevice(this,driver);
273: }
274:
275:
276: //*********************************************************************************
277: // youAreRoot
278: //
279: // Power Managment is informing us that we are the root power domain.
280: // The only difference between us and any other power domain is that
281: // we have no parent and therefore never call it.
282: //*********************************************************************************
283: IOReturn IOService::youAreRoot ( void )
284: {
285: priv-> we_are_root = true;
286: pm_vars->myParent = (IOService *)1; // we won't use this, but keep it non-NULL
287: return IOPMNoErr;
288: }
289:
290:
291: //*********************************************************************************
292: // setParent
293: //
294: // Power Management is informing us who our parent is.
295: // If we have a controlling driver, find out, given our newly-informed
296: // power domain state, what state it would be in, and then tell it
297: // to assume that state.
298: //*********************************************************************************
299: IOReturn IOService::setParent ( IOService * theParent, IOPMPowerFlags currentState )
300: {
301: unsigned long tempDesire;
302:
303: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogSetParent,(unsigned long)currentState,0);
304:
305: attachToParent( theParent, gIOPowerPlane);
306: pm_vars->myParent = theParent;
307: pm_vars->parentCurrentPowerFlags = currentState;
308: if ( pm_vars->theControllingDriver != NULL ) {
309: pm_vars->maxCapability = pm_vars->theControllingDriver->maxCapabilityForDomainState(pm_vars->parentCurrentPowerFlags);
310: tempDesire = priv->deviceDesire; // initially change into the state we are already in
311: priv->deviceDesire = pm_vars->theControllingDriver->initialPowerStateForDomainState(pm_vars->parentCurrentPowerFlags);
312: changeState();
313: priv->deviceDesire = tempDesire; // put this back like before
314: }
315: return IOPMNoErr;
316: }
317:
318:
319: //*********************************************************************************
320: // addChild
321: //
322: // Power Management is informing us who our children are.
323: //*********************************************************************************
324: IOReturn IOService::addChild ( IOService * theChild )
325: {
326: IOPMinformee * newChild;
327: IOPMPowerFlags capability;
328:
329: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogAddChild,0,0);
330:
331: theChild->retain();
332:
333: newChild = new IOPMpmChild;
334: newChild->initialize(theChild); // make a new child
335: priv->children->addToList(newChild); // add it to list of children
336: priv->numberOfInformees = priv->children->numberOfItems() + priv->interestedDrivers->numberOfItems();
337: if ( pm_vars->theControllingDriver == NULL ) { // tell it the current state of the power domain
338: capability = 0;
339: }
340: else {
341: capability = pm_vars->thePowerStates[pm_vars->myCurrentState].outputPowerCharacter;
342: }
343: theChild->setParent(this,capability);
344: theChild->setAggressiveness (kPMGeneralAggressiveness,pm_vars->aggressiveness); // tell it the current aggressiveness
345: add_to_active_change(newChild, true); // catch it up if change is in progress
346: return IOPMNoErr;
347: }
348:
349:
350: //*********************************************************************************
351: // removeChild
352: //
353: //*********************************************************************************
354: IOReturn IOService::removeChild ( IOService * theChild )
355: {
356: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogRemoveChild,0,0);
357:
358: priv->children->removeFromList(theChild); // remove the departing child
359: priv->numberOfInformees = priv->children->numberOfItems() + priv->interestedDrivers->numberOfItems();
360:
361: if ( (pm_vars->theControllingDriver == NULL) || // if not fully initialized
362: (pm_vars->myParent == NULL) ) {
363: return IOPMNoErr; // we can do no more
364: }
365:
366: changeState(); // change state if we can now tolerate lower power
367:
368: return IOPMNoErr;
369: }
370:
371:
372: //*********************************************************************************
373: // registerControllingDriver
374: //
375: // A driver has called us volunteering to control power to our device.
376: // If the power state array it provides is richer than the one we already
377: // know about (supplied by an earlier volunteer), then accept the offer.
378: // Notify all interested parties of our power state, which we now know.
379: //*********************************************************************************
380:
381: IOReturn IOService::registerControllingDriver ( IOService * controllingDriver, IOPMPowerState* powerStates, unsigned long numberOfStates )
382: {
383: unsigned long i;
384: unsigned long tempDesire;
385:
386: if ( (numberOfStates > pm_vars->theNumberOfPowerStates) && (numberOfStates > 1) ) {
387: if ( priv->changeList->currentChange() == -1 ) {
388: if ( controllingDriver != NULL ) {
389: if ( numberOfStates <= IOPMMaxPowerStates ) {
390: switch ( powerStates[0].version ) {
391: case 1:
392: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogControllingDriver,
393: (unsigned long)numberOfStates, (unsigned long)powerStates[0].version);
394: for ( i = 0; i < numberOfStates; i++ ) {
395: pm_vars->thePowerStates[i] = powerStates[i];
396: }
397: break;
398: case 2:
399: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogControllingDriver,
400: (unsigned long) numberOfStates,(unsigned long) powerStates[0].version);
401: for ( i = 0; i < numberOfStates; i++ ) {
402: pm_vars->thePowerStates[i].version = powerStates[i].version;
403: pm_vars->thePowerStates[i].capabilityFlags = powerStates[i].capabilityFlags;
404: pm_vars->thePowerStates[i].outputPowerCharacter = powerStates[i].outputPowerCharacter;
405: pm_vars->thePowerStates[i].inputPowerRequirement = powerStates[i].inputPowerRequirement;
406: pm_vars->thePowerStates[i].staticPower = powerStates[i].staticPower;
407: pm_vars->thePowerStates[i].unbudgetedPower = powerStates[i].unbudgetedPower;
408: pm_vars->thePowerStates[i].powerToAttain = powerStates[i].powerToAttain;
409: pm_vars->thePowerStates[i].timeToAttain = powerStates[i].timeToAttain;
410: pm_vars->thePowerStates[i].settleUpTime = powerStates[i].settleUpTime;
411: pm_vars->thePowerStates[i].timeToLower = powerStates[i].timeToLower;
412: pm_vars->thePowerStates[i].settleDownTime = powerStates[i].settleDownTime;
413: pm_vars->thePowerStates[i].powerDomainBudget = powerStates[i].powerDomainBudget;
414: }
415: break;
416: default:
417: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogControllingDriverErr1,
418: (unsigned long)powerStates[0].version,0);
419: return IOPMNoErr;
420: }
421:
422: pm_vars->theNumberOfPowerStates = numberOfStates;
423: pm_vars->theControllingDriver = controllingDriver;
424: if ( priv->interestedDrivers->findItem(controllingDriver) == NULL ) { // register it as interested
425: registerInterestedDriver (controllingDriver ); // unless already done
426: }
427: if ( priv->need_to_become_usable ) {
428: priv->need_to_become_usable = false;
429: priv->deviceDesire = pm_vars->theNumberOfPowerStates - 1;
430: }
431: if ( pm_vars->myParent != NULL ) {
432: pm_vars->maxCapability = pm_vars->theControllingDriver->maxCapabilityForDomainState(pm_vars->parentCurrentPowerFlags);
433: tempDesire = priv->deviceDesire; // initially change into the state we are already in
434: priv->deviceDesire = pm_vars->theControllingDriver->initialPowerStateForDomainState(pm_vars->parentCurrentPowerFlags);
435: changeState();
436: priv->deviceDesire = tempDesire; // put this back like before
437: }
438: }
439: else {
440: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogControllingDriverErr2,(unsigned long)numberOfStates,0);
441: }
442: }
443: else {
444: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogControllingDriverErr4,0,0);
445: }
446: }
447: }
448: else {
449: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogControllingDriverErr5,(unsigned long)numberOfStates,0);
450: }
451: return IOPMNoErr;
452: }
453:
454: //*********************************************************************************
455: // registerInterestedDriver
456: //
457: // Add the caller to our list of interested drivers and return our current
458: // power state. If we don't have a power-controlling driver yet, we will
459: // call this interested driver again later when we do get a driver and find
460: // out what the current power state of the device is.
461: //*********************************************************************************
462:
463: IOPMPowerFlags IOService::registerInterestedDriver ( IOService * theDriver )
464: {
465: IOPMinformee * newInformee;
466: IOPMPowerFlags futureCapability;
467:
468: if (theDriver == NULL ) {
469: return 0; // can't tell it a state yet
470: }
471:
472: theDriver->retain();
473:
474: newInformee = new IOPMinformee; // make new driver node
475: newInformee->initialize(theDriver);
476: priv->interestedDrivers->addToList(newInformee); // add it to list of drivers
477: priv->numberOfInformees = priv->children->numberOfItems() + priv->interestedDrivers->numberOfItems();
478:
479: if ( (pm_vars->theControllingDriver == NULL) || (pm_vars->myParent == NULL) ) {
480: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogInterestedDriver,0,0);
481: return 0; // can't tell it a state yet
482: }
483:
484: switch (priv->machine_state) { // can we notify new driver of a change in progress?
485: case IOPMour_prechange_1:
486: case IOPMour_prechange_4:
487: case IOPMparent_prechange_down_4:
488: case IOPMparent_postchange_down_2:
489: case IOPMparent_prechange_up_1:
490: case IOPMparent_postchange_up_6:
491: futureCapability = priv->head_note_capabilityFlags; // yes, remember what we tell it
492: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogInterestedDriver,(unsigned long)futureCapability,0);
493: add_to_active_change(newInformee,false); // notify it
494: return futureCapability; // and return the same thing
495: }
496: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogInterestedDriver,
497: (unsigned long) pm_vars->thePowerStates[pm_vars->myCurrentState].capabilityFlags,0);
498: return pm_vars->thePowerStates[pm_vars->myCurrentState].capabilityFlags; // no, return current capability
499: }
500:
501:
502: //*********************************************************************************
503: // deRegisterInterestedDriver
504: //
505: //*********************************************************************************
506: IOReturn IOService::deRegisterInterestedDriver ( IOService * theDriver )
507: {
508: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogRemoveDriver,0,0);
509:
510: priv->interestedDrivers->removeFromList(theDriver); // remove the departing driver
511: priv->numberOfInformees = priv->children->numberOfItems() + priv->interestedDrivers->numberOfItems();
512:
513: theDriver->release();
514:
515: return IOPMNoErr;
516: }
517:
518:
519: //*********************************************************************************
520: // acknowledgePowerChange
521: //
522: // After we notified one of the interested drivers or a power-domain child
523: // of an impending change in power, it has called to say it is now
524: // prepared for the change. If this object is the last to
525: // acknowledge this change, we take whatever action we have been waiting
526: // for.
527: // That may include acknowledging to our parent. In this case, we do it
528: // last of all to insure that this doesn't cause the parent to call us some-
529: // where else and alter data we are relying on here (like the very existance
530: // of a "current change note".)
531: //*********************************************************************************
532:
533: IOReturn IOService::acknowledgePowerChange ( IOService * whichObject )
534: {
535: IOPMinformee * ackingObject;
536:
537: ackingObject = priv->interestedDrivers->findItem(whichObject); // one of our interested drivers?
538: if ( ackingObject == NULL ) {
539: ackingObject = priv->children->findItem(whichObject); // no, one of our children?
540: if ( ackingObject == NULL ) {
541: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogAcknowledgeErr1,0,0);
542: return IOPMNoErr; // no, just return
543: }
544: else {
545: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogChildAcknowledge,0,0);
546: }
547: }
548: else {
549: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogDriverAcknowledge,0,0);
550: }
551:
552: if (! acquire_lock() ) {
553: return IOPMNoErr;
554: }
555:
556: if (priv->head_note_pendingAcks != 0 ) { // yes, make sure we're expecting acks
557: if ( ackingObject->timer != 0 ) { // make sure we're expecting this ack
558: ackingObject->timer = 0; // mark it acked
559: priv->head_note_pendingAcks -= 1; // that's one fewer to worry about
560: if ( priv->head_note_pendingAcks == 0 ) { // is that the last?
561: stop_ack_timer(); // yes, stop the timer
562: IOUnlock(priv->our_lock);
563: all_acked(); // and now we can continue
564: return IOPMNoErr;
565: }
566: }
567: else {
568: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogAcknowledgeErr2,0,0); // this object has already acked
569: }
570: }
571: else {
572: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogAcknowledgeErr3,0,0); // not expecting anybody to ack
573: }
574: IOUnlock(priv->our_lock);
575: return IOPMNoErr;
576: }
577:
578: //*********************************************************************************
579: // acknowledgeSetPowerState
580: //
581: // After we instructed our controlling driver to change power states,
582: // it has called to say it has finished doing so.
583: // We continue to process the power state change.
584: //*********************************************************************************
585:
586: IOReturn IOService::acknowledgeSetPowerState ( void )
587: {
588: if (! acquire_lock() ) {
589: return IOPMNoErr;
590: }
591: if ( priv->driver_timer == -1 ) {
592: priv->driver_timer = 0; // driver is acking instead of using return code
593: }
594: else {
595: if ( priv->driver_timer > 0 ) { // are we expecting this?
596: stop_ack_timer(); // yes, stop the timer
597: priv->driver_timer = 0;
598: IOUnlock(priv->our_lock);
599: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogDriverAcknowledgeSet,0,0);
600: driver_acked();
601: return IOPMNoErr;
602: }
603: else {
604: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogAcknowledgeErr4,0,0); // no
605: }
606: }
607: IOUnlock(priv->our_lock);
608: return IOPMNoErr;
609: }
610:
611:
612: //*********************************************************************************
613: // driver_acked
614: //
615: // Either the controlling driver has called acknowledgeSetPowerState
616: // or the acknowledgement timer has expired while waiting for that.
617: // We carry on processing the current change note.
618: //*********************************************************************************
619:
620: void IOService::driver_acked ( void )
621: {
622: switch (priv->machine_state) {
623: case IOPMour_prechange_2:
624: our_prechange_2();
625: break;
626: case IOPMparent_prechange_down_5:
627: parent_prechange_down_5();
628: break;
629: case IOPMparent_postchange_up_4:
630: parent_postchange_up_4();
631: break;
632: }
633: }
634:
635:
636: //*********************************************************************************
637: // powerDomainWillChangeTo
638: //
639: // Called by the power-hierarchy parent notifying of a new power state
640: // in the power domain.
641: // If power is going lower, we notify our interested parties that power
642: // will lower. When they have all acked, we lower the state of our device
643: // to the state appropriate for the coming domain level. Then we ack the parent.
644: // Later, when the domain has lowered, we notify everyone that power has dropped.
645: //
646: // If power is going higher and we will take advantage of this by raising our
647: // own power state, we notify our interested parties that power
648: // will raise. When they have all acked, we ack the parent. Later, when
649: // the domain has raised, we raise our power level. When power has
650: // settled, we inform our interested parties. When they have all acked,
651: // we ack the parent.
652: //*********************************************************************************
653:
654: IOReturn IOService::powerDomainWillChangeTo ( IOPMPowerFlags newPowerStateFlags )
655: {
656: unsigned long newStateNumber;
657:
658: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogWillChange,(unsigned long)newPowerStateFlags,0);
659:
660: if ( pm_vars->myParent == NULL ) {
661: return IOPMAckImplied; // somebody goofed
662: }
663:
664: if ( pm_vars->theControllingDriver == NULL ) {
665: pm_vars->parentCurrentPowerFlags = newPowerStateFlags; // we can't take any action except note the change
666: return IOPMAckImplied;
667: }
668: newStateNumber = pm_vars->theControllingDriver->maxCapabilityForDomainState(newPowerStateFlags);
669: return enqueuePowerChange(IOPMParentInitiated, newStateNumber,newPowerStateFlags); // tell interested parties about it
670: }
671:
672:
673: //*********************************************************************************
674: // powerDomainDidChangeTo
675: //
676: // Called by the power-hierarchy parent after the power state of the power domain
677: // has settled at a new level. We must notify our interested drivers and children.
678: // If they all acknowledge immediately, so do we. Otherwise, we'll acknowledge
679: // when the last of them does.
680: //*********************************************************************************
681:
682: IOReturn IOService::powerDomainDidChangeTo ( IOPMPowerFlags newPowerStateFlags )
683: {
684:
685: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogDidChange,(unsigned long)newPowerStateFlags,0);
686:
687: if ( (pm_vars->myParent == NULL) || (pm_vars->theControllingDriver == NULL) ) {
688: return IOPMAckImplied; // somebody goofed
689: }
690:
691: switch (priv->machine_state) {
692: case IOPMparent_postchange_down_1:
693: return parent_postchange_down_1(); // life-style 2 continues
694: case IOPMparent_postchange_up_1:
695: return parent_postchange_up_1(); // life-style 3 continues
696: case IOPMparent_postchange_null:
697: all_done();
698: return IOPMAckImplied; // life-style 4 done
699: }
700:
701: return IOPMAckImplied; // something wrong
702: }
703:
704:
705: //*********************************************************************************
706: // requestDomainState
707: //
708: //
709: //*********************************************************************************
710: IOReturn IOService::requestDomainState ( IOPMPowerFlags desiredState, IOService* whichChild, unsigned long specification )
711: {
712: unsigned long i;
713: IOPMinformee * nextChild;
714:
715: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogRequestDomain,
716: (unsigned long)desiredState,(unsigned long)specification);
717:
718: if ( pm_vars->theControllingDriver == NULL) {
719: return IOPMNotYetInitialized;
720: }
721:
722: switch (specification) {
723: case IOPMLowestState:
724: i = 0;
725: while ( i < pm_vars->theNumberOfPowerStates ) {
726: if ( ( pm_vars->thePowerStates[i].outputPowerCharacter & desiredState) == desiredState ) {
727: break;
728: }
729: i++;
730: }
731: if ( i >= pm_vars->theNumberOfPowerStates ) {
732: return IOPMNoSuchState;
733: }
734: break;
735:
736: case IOPMNextLowerState:
737: i = pm_vars->myCurrentState - 1;
738: while ( i >= 0 ) {
739: if ( ( pm_vars->thePowerStates[i].outputPowerCharacter & desiredState) == desiredState ) {
740: break;
741: }
742: i--;
743: }
744: if ( i < 0 ) {
745: return IOPMNoSuchState;
746: }
747: break;
748:
749: case IOPMHighestState:
750: i = pm_vars->theNumberOfPowerStates;
751: while ( i >= 0 ) {
752: i--;
753: if ( ( pm_vars->thePowerStates[i].outputPowerCharacter & desiredState) == desiredState ) {
754: break;
755: }
756: }
757: if ( i < 0 ) {
758: return IOPMNoSuchState;
759: }
760: break;
761:
762: case IOPMNextHigherState:
763: i = pm_vars->myCurrentState + 1;
764: while ( i < pm_vars->theNumberOfPowerStates ) {
765: if ( ( pm_vars->thePowerStates[i].outputPowerCharacter & desiredState) == desiredState ) {
766: break;
767: }
768: i++;
769: }
770: if ( i == pm_vars->theNumberOfPowerStates ) {
771: return IOPMNoSuchState;
772: }
773: break;
774:
775: default:
776: return IOPMBadSpecification;
777: }
778:
779: // Now loop through the children. When we encounter the calling child, save
780: // the new state as this child's desire. Then, compute a new maximum
781: // of everybody's desires.
782:
783: nextChild = priv->children->firstInList();
784:
785: if ( nextChild == NULL ) { // we're not a power domain
786: return IOPMNoErr;
787: }
788:
789: while ( nextChild != NULL ) {
790: if ( whichChild == (IOService*)nextChild->whatObject ) {
791: ((IOPMpmChild *)nextChild)->desiredDomainState = i;
792: break;
793: }
794: nextChild = priv->children->nextInList(nextChild);
795: }
796:
797: if ( pm_vars->myParent != NULL ) {
798: changeState(); // change state if all children can now tolerate lower power
799: }
800:
801: return IOPMNoErr;
802: }
803:
804:
805: //*********************************************************************************
806: // makeUsable
807: //
808: // Some client of our device is asking that we become usable. Although
809: // this has not come from a subclassed device object, treat it exactly
810: // as if it had. In this way, subsequent requests for lower power from
811: // a subclassed device object will pre-empt this request.
812: //
813: // We treat this as a subclass object request to switch to the
814: // highest power state.
815: //*********************************************************************************
816:
817: IOReturn IOService::makeUsable ( void )
818: {
819: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogMakeUsable,0,0);
820:
821: if ( pm_vars->theControllingDriver == NULL ) {
822: priv->need_to_become_usable = true;
823: return IOPMNoErr;
824: }
825: priv->deviceDesire = pm_vars->theNumberOfPowerStates - 1;
826: if ( pm_vars->myParent == NULL ) {
827: return IOPMNoErr;
828: }
829: return changeState();
830: }
831:
832:
833: //*********************************************************************************
834: // currentCapability
835: //
836: //*********************************************************************************
837:
838: IOPMPowerFlags IOService::currentCapability ( void )
839: {
840: if ( pm_vars->theControllingDriver == NULL ) {
841: return 0;
842: }
843: else {
844: return pm_vars->thePowerStates[pm_vars->myCurrentState].capabilityFlags;
845: }
846: }
847:
848:
849: //*********************************************************************************
850: // changeStateTo
851: //
852: // For some reason, our power-controlling driver has decided it needs to change
853: // power state. We enqueue the power change so that appropriate parties
854: // will be notified, and then we will instruct the driver to make the change.
855: //*********************************************************************************
856:
857: IOReturn IOService::changeStateTo ( unsigned long ordinal )
858: {
859: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogChangeStateTo,ordinal,0);
860:
861: if ( ordinal >= pm_vars->theNumberOfPowerStates ) {
862: return IOPMParameterError;
863: }
864: priv->driverDesire = ordinal;
865: if ( pm_vars->myParent == NULL ) {
866: return IOPMNoErr;
867: }
868: return changeState();
869: }
870:
871: //*********************************************************************************
872: // changeStateToPriv
873: //
874: // For some reason, a subclassed device object has decided it needs to change
875: // power state. We enqueue the power change so that appropriate parties
876: // will be notified, and then we will instruct the driver to make the change.
877: //*********************************************************************************
878:
879: IOReturn IOService::changeStateToPriv ( unsigned long ordinal )
880: {
881: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogChangeStateToPriv,ordinal,0);
882:
883: if ( pm_vars->theControllingDriver == NULL) {
884: return IOPMNotYetInitialized;
885: }
886: if ( ordinal >= pm_vars->theNumberOfPowerStates ) {
887: return IOPMParameterError;
888: }
889: priv->deviceDesire = ordinal;
890: if ( pm_vars->myParent == NULL ) {
891: return IOPMNoErr;
892: }
893: return changeState();
894: }
895:
896:
897: //*********************************************************************************
898: // changeState
899: //
900: // A subclass object, our controlling driver, or a power domain child
901: // has asked for a different power state. Here we compute what new
902: // state we should enter and enqueue the change (or start it).
903: //*********************************************************************************
904:
905: IOReturn IOService::changeState ( void )
906: {
907: unsigned long newDesiredState = 0;
908: IOPMinformee * nextChild;
909:
910: // Compute the maximum of our children's desires, our controlling driver's desire, and the subclass device's desire.
911:
912: if ( ! priv->device_overrides ) {
913: nextChild = priv->children->firstInList();
914:
915: while ( nextChild != NULL ) {
916: if ( (( IOPMpmChild *)nextChild)->desiredDomainState > newDesiredState ) {
917: newDesiredState =(( IOPMpmChild *)nextChild)->desiredDomainState;
918: }
919: nextChild = priv->children->nextInList(nextChild);
920: }
921: if ( priv->driverDesire > newDesiredState ) {
922: newDesiredState = priv->driverDesire;
923: }
924: }
925:
926: if ( priv->deviceDesire > newDesiredState ) {
927: newDesiredState = priv->deviceDesire;
928: }
929:
930: priv->ourDesiredPowerState = newDesiredState;
931:
932: return enqueuePowerChange(IOPMWeInitiated,newDesiredState,0);
933: }
934:
935:
936: //*********************************************************************************
937: // currentPowerConsumption
938: //
939: //*********************************************************************************
940:
941: unsigned long IOService::currentPowerConsumption ( void )
942: {
943: if ( pm_vars->theControllingDriver == NULL ) {
944: return 0;
945: }
946: else {
947: return pm_vars->thePowerStates[pm_vars->myCurrentState].staticPower;
948: }
949: }
950:
951: //*********************************************************************************
952: // activityTickle
953: //
954: // The activity tickle with parameter kIOPMSubclassPolicyis not handled
955: // here and should have been intercepted by the subclass.
956: // The tickle with parameter kIOPMSuperclassPolicy1 causes the activity
957: // flag to be set, and the device state checked. If the device has been
958: // powered down, it is powered up again.
959: //*********************************************************************************
960:
961: bool IOService::activityTickle ( unsigned long type, unsigned long stateNumber=0 )
962: {
963: if ( type == kIOPMSuperclassPolicy1 ) {
964: if ( (priv->activityLock == NULL) ||
965: (pm_vars->theControllingDriver == NULL) ||
966: ( pm_vars->commandQueue == NULL) ) {
967: return true;
968: }
969: IOTakeLock(priv->activityLock);
970: priv->device_active = true;
971: if ( pm_vars->myCurrentState >= stateNumber) {
972: IOUnlock(priv->activityLock);
973: return true;
974: }
975: IOUnlock(priv->activityLock); // send a message on the command queue
976: pm_vars->commandQueue->enqueueCommand(true, (void *)kPMunIdleDevice, (void *)stateNumber);
977: return false;
978: }
979: return true;
980: }
981:
982: //*********************************************************************************
983: // getPMworkloop
984: //
985: // A child is calling to get a pointer to the Power Management workloop.
986: // We got it or get it from our parent.
987: //*********************************************************************************
988:
989: IOWorkLoop * IOService::getPMworkloop ( void )
990: {
991: if ( pm_vars->myParent == NULL ) {
992: return NULL;
993: }
994: if ( pm_vars->PMworkloop == NULL ) {
995: pm_vars->PMworkloop = pm_vars->myParent->getPMworkloop();
996: }
997: return pm_vars->PMworkloop;
998: }
999:
1000:
1001: //*********************************************************************************
1002: // setIdleTimerPeriod
1003: //
1004: // A subclass policy-maker is going to use our standard idleness
1005: // detection service. Make a command queue and an idle timer and
1006: // connect them to the power management workloop. Finally,
1007: // start the timer.
1008: //*********************************************************************************
1009:
1010: IOReturn IOService::setIdleTimerPeriod ( unsigned long period )
1011: {
1012: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMsetIdleTimerPeriod,period, 0);
1013:
1014: priv->idle_timer_period = period;
1015:
1016: if ( period > 0 ) {
1017: if ( getPMworkloop() == NULL ) {
1018: return kIOReturnError;
1019: }
1020:
1021: if (pm_vars->commandQueue == NULL ) { // make the command queue
1022: pm_vars->commandQueue = IOCommandQueue::commandQueue(this, PMreceiveCmd);
1023: if (! pm_vars->commandQueue ||
1024: ( pm_vars->PMworkloop->addEventSource( pm_vars->commandQueue) != kIOReturnSuccess) ) {
1025: return kIOReturnError;
1026: }
1027: }
1028: // make the timer event
1029: if ( priv->timerEventSrc == NULL ) {
1030: priv->timerEventSrc = IOTimerEventSource::timerEventSource(this,
1031: PM_idle_timer_expired);
1032: if ( ! priv->timerEventSrc ||
1033: ( pm_vars->PMworkloop->addEventSource( priv->timerEventSrc) != kIOReturnSuccess) ) {
1034: return kIOReturnError;
1035: }
1036: }
1037:
1038: if ( priv->activityLock == NULL ) {
1039: priv->activityLock = IOLockAlloc();
1040: }
1041:
1042: start_PM_idle_timer();
1043: }
1044: return IOPMNoErr;
1045: }
1046:
1047:
1048: //*********************************************************************************
1049: // start_PM_idle_timer
1050: //
1051: // The parameter is a pointer to us. Use it to call our timeout method.
1052: //*********************************************************************************
1053: void IOService::start_PM_idle_timer ( void )
1054: {
1055: priv->timerEventSrc->setTimeout(priv->idle_timer_period, NSEC_PER_SEC);
1056: }
1057:
1058:
1059: //*********************************************************************************
1060: // PM_idle_timer_expired
1061: //
1062: // The parameter is a pointer to us. Use it to call our timeout method.
1063: //*********************************************************************************
1064:
1065: void PM_idle_timer_expired(OSObject * ourSelves, IOTimerEventSource *)
1066: {
1067: ((IOService *)ourSelves)->PM_idle_timer_expiration();
1068: }
1069:
1070:
1071: //*********************************************************************************
1072: // PM_idle_timer_expiration
1073: //
1074: // The idle timer has expired. If there has been activity since the last
1075: // expiration, just restart the timer and return. If there has not been
1076: // activity, switch to the next lower power state and restart the timer.
1077: //*********************************************************************************
1078:
1079: void IOService::PM_idle_timer_expiration ( void )
1080: {
1081: if ( priv->idle_timer_period > 0 ) {
1082: IOTakeLock(priv->activityLock);
1083: if ( priv->device_active ) {
1084: priv->device_active = false;
1085: IOUnlock(priv->activityLock);
1086: start_PM_idle_timer();
1087: return;
1088: }
1089: if (pm_vars->myCurrentState > 0 ) {
1090: IOUnlock(priv->activityLock);
1091: priv->askingFor = pm_vars->myCurrentState - 1;
1092: changeStateToPriv(pm_vars->myCurrentState - 1);
1093: start_PM_idle_timer();
1094: return;
1095: }
1096: IOUnlock(priv->activityLock);
1097: start_PM_idle_timer();
1098: }
1099: }
1100:
1101:
1102:
1103: // **********************************************************************************
1104: // PMreceiveCmd
1105: //
1106: //
1107: //
1108: // **********************************************************************************
1109: void PMreceiveCmd ( OSObject * theDriver, void * command, void * param1, void * param2, void *param3 )
1110: {
1111: ((IOService *)theDriver)->command_received(command,param1,param2,param3);
1112: }
1113:
1114:
1115: // **********************************************************************************
1116: // command_received
1117: //
1118: // We have received a command from ourselves on the command queue.
1119: // This is to prevent races with timer-expiration code.
1120: // **********************************************************************************
1121: void IOService::command_received ( void * command, void *stateNumber , void * , void *)
1122: {
1123: if ( command == (void *)kPMunIdleDevice ) {
1124: if ((pm_vars->myCurrentState < (unsigned long)stateNumber) &&
1125: (priv->imminentState < (unsigned long)stateNumber ) &&
1126: ((unsigned long)stateNumber > priv->askingFor) ) {
1127: priv->askingFor = (unsigned long)stateNumber;
1128: changeStateToPriv((unsigned long)stateNumber);
1129: }
1130: }
1131: }
1132:
1133:
1134: //*********************************************************************************
1135: // setAggressiveness
1136: //
1137: // Pass on the input parameters to all power domain children. All those which are
1138: // power domains will pass it on to their children, etc.
1139: //*********************************************************************************
1140:
1141: IOReturn IOService::setAggressiveness ( unsigned long type, unsigned long newLevel )
1142: {
1143: IOPMinformee * nextChild;
1144:
1145: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogSetAggressiveness,type, newLevel);
1146:
1147: if ( type == kPMGeneralAggressiveness ) {
1148: pm_vars->aggressiveness = newLevel;
1149: }
1150:
1151: nextChild = priv->children->firstInList();
1152:
1153: while ( nextChild != NULL ) {
1154: nextChild->whatObject->setAggressiveness(type, newLevel);
1155: nextChild = priv->children->nextInList(nextChild);
1156: }
1157:
1158: return IOPMNoErr;
1159: }
1160:
1161:
1162: //*********************************************************************************
1163: // systemWake
1164: //
1165: // Pass this to all power domain children. All those which are
1166: // power domains will pass it on to their children, etc.
1167: //*********************************************************************************
1168:
1169: IOReturn IOService::systemWake ( void )
1170: {
1171: IOPMinformee * nextChild;
1172:
1173: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogSystemWake,0, 0);
1174:
1175: nextChild = priv->children->firstInList();
1176:
1177: while ( nextChild != NULL ) {
1178: nextChild->whatObject->systemWake();
1179: nextChild = priv->children->nextInList(nextChild);
1180: }
1181:
1182: return IOPMNoErr;
1183: }
1184:
1185:
1186: //*********************************************************************************
1187: // temperatureCriticalForZone
1188: //
1189: //*********************************************************************************
1190:
1191: IOReturn IOService::temperatureCriticalForZone ( IOService * whichZone )
1192: {
1193: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogCriticalTemp,0,0);
1194:
1195: if ( (pm_vars->myParent != NULL) &&
1196: ( ! priv->we_are_root) ) {
1197: pm_vars->myParent->temperatureCriticalForZone(whichZone);
1198: }
1199: return IOPMNoErr;
1200: }
1201:
1202:
1203: //*********************************************************************************
1204: // overrideOnPriv
1205: //
1206: //*********************************************************************************
1207:
1208:
1209: IOReturn IOService::overrideOnPriv ( void )
1210: {
1211: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogOverrideOn,0,0);
1212:
1213: priv->device_overrides = true; // turn on the override
1214: return changeState(); // change state if that changed something
1215: }
1216:
1217:
1218: //*********************************************************************************
1219: // overrideOffPriv
1220: //
1221: //*********************************************************************************
1222: IOReturn IOService::overrideOffPriv ( void )
1223: {
1224: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogOverrideOff,0,0);
1225:
1226: priv->device_overrides = false; // turn off the override
1227: return changeState(); // change state if that changed something
1228: }
1229:
1230:
1231: //*********************************************************************************
1232: // enqueuePowerChange
1233: //
1234: // Allocate a new state change notification, initialize it with fields from the
1235: // caller, and add it to the tail of the list of pending power changes.
1236: //
1237: // If it is early enough in the list, and almost all the time it is the only one in
1238: // the list, start the power change.
1239: //
1240: // In rare instances, this change will preempt the previous change in the list.
1241: // If the previous change is un-actioned in any way (because we are still
1242: // processing an even earlier power change), and if both the previous change
1243: // in the list and this change are initiated by us (not the parent), then we
1244: // needn't perform the previous change, so we collapse the list a little.
1245: //*********************************************************************************
1246:
1247: IOReturn IOService::enqueuePowerChange ( unsigned long flags, unsigned long whatStateOrdinal, unsigned long domainState )
1248: {
1249: long newNote;
1250: long previousNote;
1251:
1252: // Create and initialize the new change note
1253:
1254: newNote = priv->changeList->createChangeNote();
1255: if ( newNote == -1 ) {
1256: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogEnqueueErr,0,0);
1257: return IOPMAckImplied; // uh-oh, our list is full
1258: }
1259:
1260: priv->changeList->changeNote[newNote].newStateNumber = whatStateOrdinal;
1261: priv->changeList->changeNote[newNote].outputPowerCharacter = pm_vars->thePowerStates[whatStateOrdinal].outputPowerCharacter;
1262: priv->changeList->changeNote[newNote].inputPowerRequirement = pm_vars->thePowerStates[whatStateOrdinal].inputPowerRequirement;
1263: priv->changeList->changeNote[newNote].capabilityFlags = pm_vars->thePowerStates[whatStateOrdinal].capabilityFlags;
1264: priv->changeList->changeNote[newNote].flags = flags;
1265: if (flags & IOPMParentInitiated ) {
1266: priv->changeList->changeNote[newNote].domainState = domainState;
1267: }
1268:
1269: previousNote = priv->changeList->previousChangeNote(newNote);
1270:
1271: if ( previousNote == -1 ) {
1272:
1273: // Queue is empty, we can start this change.
1274:
1275: if (flags & IOPMWeInitiated ) {
1276: start_our_change(newNote);
1277: return 0;
1278: }
1279: else {
1280: return start_parent_change(newNote);
1281: }
1282: }
1283:
1284: // The queue is not empty. Try to collapse this new change and the previous one in queue into one change.
1285: // This is possible only if both changes are initiated by us, and neither has been started yet.
1286: // Do this more than once if possible.
1287:
1288: // (A change is started iff it is at the head of the queue)
1289:
1290: while ( (previousNote != priv->head_note) && (previousNote != -1) &&
1291: (priv->changeList->changeNote[newNote].flags & priv->changeList->changeNote[previousNote].flags & IOPMWeInitiated) ) {
1292: priv->changeList->changeNote[previousNote].outputPowerCharacter = priv->changeList->changeNote[newNote].outputPowerCharacter;
1293: priv->changeList->changeNote[previousNote].inputPowerRequirement = priv->changeList->changeNote[newNote].inputPowerRequirement;
1294: priv->changeList->changeNote[previousNote].capabilityFlags =priv-> changeList->changeNote[newNote].capabilityFlags;
1295: priv->changeList->changeNote[previousNote].newStateNumber = priv->changeList->changeNote[newNote].newStateNumber;
1296: priv->changeList->releaseTailChangeNote();
1297: newNote = previousNote;
1298: previousNote = priv->changeList->previousChangeNote(newNote);
1299: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogCollapseQueue,0,0);
1300: }
1301: return IOPMWillAckLater; // in any case, we can't start yet
1302: }
1303:
1304:
1305: //*********************************************************************************
1306: // notifyAll
1307: //
1308: // Notify all interested parties either that a change is impending or that the
1309: // previously-notified change is done and power has settled.
1310: // The parameter identifies whether this is the
1311: // pre-change notification or the post-change notification.
1312: //
1313: //*********************************************************************************
1314:
1315: IOReturn IOService::notifyAll ( bool is_prechange )
1316: {
1317: IOPMinformee * nextObject;
1318: bool start_timer = false;
1319:
1320: // To prevent acknowledgePowerChange from finishing the change note and removing it from the queue if
1321: // some driver calls it, we inflate the number of pending acks so it cannot become zero. We'll fix it later.
1322:
1323: priv->head_note_pendingAcks = priv->numberOfInformees + 1;
1324:
1325: // OK, we will go through the lists of interested drivers and power domain children
1326: // and notify each one of this change.
1327:
1328: nextObject = priv->interestedDrivers->firstInList(); // notify interested drivers
1329: while ( nextObject != NULL ) {
1330: if (! notifyObject( nextObject, is_prechange, false) ) {
1331: start_timer = true;
1332: }
1333: nextObject = priv->interestedDrivers->nextInList(nextObject);
1334: }
1335: if ( start_timer ) { // start ack timer if any drivers didn't ack
1336: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogStartAckTimer,0,0);
1337: start_ack_timer();
1338: }
1339:
1340: nextObject = priv->children->firstInList(); // notify power domain children
1341: while ( nextObject != NULL ) {
1342: notifyObject(nextObject, is_prechange, true);
1343: nextObject = priv->children->nextInList(nextObject);
1344: }
1345:
1346: priv->head_note_pendingAcks -= 1; // fix this
1347: if (priv->head_note_pendingAcks == 0 ) { // is it all acked?
1348: return IOPMAckImplied; // return ack to parent
1349: }
1350: return IOPMWillAckLater;
1351: }
1352:
1353:
1354: //*********************************************************************************
1355: // notifyObject
1356: //
1357: // Notify an interested driver or a power domain child of an upcoming
1358: // power change.
1359: //
1360: // If the object acknowledges the current change, we return TRUE.
1361: //*********************************************************************************
1362:
1363: bool IOService::notifyObject ( IOPMinformee * nextObject, bool is_prechange, bool is_child )
1364: {
1365: IOReturn k = IOPMAckImplied;
1366:
1367: nextObject->timer = -1; // initialize this
1368:
1369: if ( is_prechange ) {
1370: if ( is_child ) {
1371: k =nextObject->whatObject->powerDomainWillChangeTo( priv->head_note_outputFlags);
1372: }
1373: else {
1374: pm_vars->thePlatform->PMLog (pm_vars->ourName,PMlogInformDriverPreChange,
1375: (unsigned long)priv->head_note_capabilityFlags,(unsigned long)priv->head_note_state);
1376: k = nextObject->whatObject->powerStateWillChangeTo( priv->head_note_capabilityFlags,priv->head_note_state,this);
1377: }
1378: }
1379: else {
1380: if ( is_child ) {
1381: k = nextObject->whatObject->powerDomainDidChangeTo(priv->head_note_outputFlags);
1382: }
1383: else {
1384: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogInformDriverPostChange,
1385: (unsigned long)priv->head_note_capabilityFlags,(unsigned long)priv->head_note_state);
1386: k = nextObject->whatObject->powerStateDidChangeTo(priv->head_note_capabilityFlags,priv->head_note_state,this);
1387: }
1388: }
1389:
1390: if ( nextObject->timer == 0 ) { // did it ack behind our back?
1391: return true; // yes
1392: }
1393: if ( k ==IOPMAckImplied ) { // no, did the return code ack?
1394: nextObject->timer = 0; // yes
1395: priv->head_note_pendingAcks -= 1;
1396: return true;
1397: }
1398: if ( k < 0 ) {
1399: nextObject->timer = 0; // somebody goofed
1400: priv-> head_note_pendingAcks -= 1;
1401: return true;
1402: }
1403: nextObject->timer = (k * ns_per_us / ACK_TIMER_PERIOD) + 1; // no, it's a timer
1404: return false;
1405: }
1406:
1407:
1408: //*********************************************************************************
1409: // our_prechange_1
1410: //
1411: // All parties have acknowledged our pre-change notification of a power
1412: // change we initiated. Here we instruct our controlling driver to make
1413: // the change to the hardware. If it does so, we continue processing
1414: // (waiting for settle and notifying interested parties post-change.)
1415: // If it doesn't, we have to wait for it to acknowledge and then continue.
1416: //*********************************************************************************
1417:
1418: void IOService::our_prechange_1 ( void )
1419: {
1420: if ( instruct_driver(priv->head_note_state) == IOPMAckImplied ) {
1421: our_prechange_2(); // it's done, carry on
1422: }
1423: else {
1424: priv->machine_state = IOPMour_prechange_2; // it's not, wait for it
1425: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogStartAckTimer,0,0);
1426: start_ack_timer();
1427: }
1428: }
1429:
1430:
1431: //*********************************************************************************
1432: // our_prechange_2
1433: //
1434: // Our controlling driver has changed power state on the hardware
1435: // during a power change we initiated. Here we see if we need to wait
1436: // for power to settle before continuing. If not, we continue processing
1437: // (notifying interested parties post-change). If so, we wait and
1438: // continue later.
1439: //*********************************************************************************
1440:
1441: void IOService::our_prechange_2 ( void )
1442: {
1443: priv->settle_time = compute_settle_time();
1444: if ( priv->settle_time == 0 ) {
1445: our_prechange_3();
1446: }
1447: else {
1448: priv->machine_state = IOPMour_prechange_3;
1449: startSettleTimer(priv->settle_time);
1450: }
1451: }
1452:
1453:
1454: //*********************************************************************************
1455: // our_prechange_3
1456: //
1457: // Power has settled on a power change we initiated. Here we notify
1458: // all our interested parties post-change. If they all acknowledge, we're
1459: // done with this change note, and we can start on the next one.
1460: // Otherwise we have to wait for acknowledgements and finish up later.
1461: //*********************************************************************************
1462:
1463: void IOService::our_prechange_3 ( void )
1464: {
1465: priv->machine_state = IOPMour_prechange_4; // in case they don't all ack
1466: if ( notifyAll(false) == IOPMAckImplied ) {
1467: our_prechange_4();
1468: }
1469: }
1470:
1471:
1472: //*********************************************************************************
1473: // our_prechange_4
1474: //
1475: // Power has settled on a power change we initiated, and
1476: // all our interested parties have acknowledged. We're
1477: // done with this change note, and we can start on the next one.
1478: //*********************************************************************************
1479:
1480: void IOService::our_prechange_4 ( void )
1481: {
1482: all_done();
1483: }
1484:
1485:
1486: //*********************************************************************************
1487: // parent_prechange_down_1
1488: //
1489: // All parties have acknowledged our pre-change notification of a power
1490: // lowering initiated by the parent. Here we instruct our controlling driver
1491: // to put the hardware in the state it needs to be in when the domain is
1492: // lowered. If it does so, we continue processing
1493: // (waiting for settle and acknowledging the parent.)
1494: // If it doesn't, we have to wait for it to acknowledge and then continue.
1495: //*********************************************************************************
1496:
1497: IOReturn IOService::parent_prechange_down_1 ( void )
1498: {
1499: if ( instruct_driver(priv->head_note_state) == IOPMAckImplied ) {
1500: return parent_prechange_down_2(); // it's done, carry on
1501: }
1502: priv->machine_state = IOPMparent_prechange_down_5; // it's not, wait for it
1503: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogStartAckTimer,0,0);
1504: start_ack_timer();
1505: return IOPMWillAckLater;
1506: }
1507:
1508:
1509: //*********************************************************************************
1510: // parent_prechange_down_4
1511: //
1512: // We had to wait for it, but all parties have acknowledged our pre-change
1513: // notification of a power lowering initiated by the parent.
1514: // Here we instruct our controlling driver
1515: // to put the hardware in the state it needs to be in when the domain is
1516: // lowered. If it does so, we continue processing
1517: // (waiting for settle and acknowledging the parent.)
1518: // If it doesn't, we have to wait for it to acknowledge and then continue.
1519: //*********************************************************************************
1520:
1521: void IOService::parent_prechange_down_4 ( void )
1522: {
1523: if ( instruct_driver(priv->head_note_state) == IOPMAckImplied ) {
1524: parent_prechange_down_5(); // it's done, carry on
1525: }
1526: else {
1527: priv-> machine_state = IOPMparent_prechange_down_5; // it's not, wait for it
1528: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogStartAckTimer,0,0);
1529: start_ack_timer();
1530: }
1531: }
1532:
1533:
1534: //*********************************************************************************
1535: // parent_prechange_down_2
1536: //
1537: // Our controlling driver has changed power state on the hardware
1538: // during a power change initiated by our parent. Here we see if we need
1539: // to wait for power to settle before continuing. If not, we continue
1540: // processing (acknowledging our preparedness to the parent).
1541: // If so, we wait and continue later.
1542: //*********************************************************************************
1543:
1544: IOReturn IOService::parent_prechange_down_2 ( void )
1545: {
1546: priv->settle_time = compute_settle_time();
1547: if ( priv->settle_time == 0 ) {
1548: priv->machine_state = IOPMparent_postchange_down_1;
1549: return IOPMAckImplied;
1550: }
1551: else {
1552: priv->machine_state = IOPMparent_prechange_down_3;
1553: startSettleTimer(priv->settle_time);
1554: return IOPMWillAckLater;
1555: }
1556: }
1557:
1558:
1559: //*********************************************************************************
1560: // parent_prechange_down_5
1561: //
1562: // Our controlling driver has changed power state on the hardware
1563: // during a power change initiated by our parent. We have had to wait
1564: // for acknowledgement from interested parties, or we have had to wait
1565: // for the controlling driver to change the state. Here we see if we need
1566: // to wait for power to settle before continuing. If not, we continue
1567: // processing (acknowledging our preparedness to the parent).
1568: // If so, we wait and continue later.
1569: //*********************************************************************************
1570:
1571: void IOService::parent_prechange_down_5 ( void )
1572: {
1573: priv->settle_time = compute_settle_time();
1574: if ( priv->settle_time == 0 ) {
1575: parent_prechange_down_3();
1576: }
1577: else {
1578: priv->machine_state = IOPMparent_prechange_down_3;
1579: startSettleTimer(priv->settle_time);
1580: }
1581: }
1582:
1583:
1584: //*********************************************************************************
1585: // parent_prechange_down_3
1586: //
1587: // Power has settled on a power change initiated by our parent. Here we
1588: // acknowledge the parent. There is nothing more to do until the
1589: // parent lowers power in the domain and calls us at powerStateDidChange.
1590: //*********************************************************************************
1591:
1592: void IOService::parent_prechange_down_3 ( void )
1593: {
1594: priv->machine_state = IOPMparent_postchange_down_1;
1595: pm_vars->myParent->acknowledgePowerChange(this);
1596: }
1597:
1598:
1599: //*********************************************************************************
1600: // parent_prechange_up_1
1601: //
1602: // All parties have acknowledged our pre-change notification of a power
1603: // raising initiated by the parent. Here we acknowledge the parent.
1604: // There is nothing more to do until the parent raises power in the domain
1605: // and calls us at powerStateDidChange.
1606: //*********************************************************************************
1607:
1608: void IOService::parent_prechange_up_1 ( void )
1609: {
1610: priv->machine_state = IOPMparent_postchange_up_1;
1611: pm_vars->myParent->acknowledgePowerChange(this);
1612: }
1613:
1614:
1615: //*********************************************************************************
1616: // parent_postchange_down_1
1617: //
1618: // Our parent is lowering power, and has called us at powerStateDidChange
1619: // to tell us the domain power has now settled in the new lower state.
1620: // We notify our interested parties. When they have all acked, we're done
1621: //*********************************************************************************
1622:
1623: IOReturn IOService::parent_postchange_down_1 ( void )
1624: {
1625: priv->machine_state = IOPMparent_postchange_down_2; // in case they don't all ack
1626: if ( notifyAll(false) == IOPMAckImplied ) {
1627: all_done();
1628: return IOPMAckImplied;
1629: }
1630: return IOPMWillAckLater; // they didn't
1631: }
1632:
1633:
1634: //*********************************************************************************
1635: // parent_postchange_down_2
1636: //
1637: // We had to wait for it, but all parties have acknowledged our post-change
1638: // notification of a power lowering initiated by the parent.
1639: // Here we acknowledge the parent.
1640: // We are done with this change note, and we can start on the next one.
1641: //*********************************************************************************
1642:
1643: void IOService::parent_postchange_down_2 ( void )
1644: {
1645: all_done();
1646: pm_vars->myParent->acknowledgePowerChange(this);
1647: }
1648:
1649:
1650: //*********************************************************************************
1651: // parent_postchange_up_1
1652: //
1653: // Our parent has informed us via powerStateDidChange that it has
1654: // raised the power in our power domain. Here we instruct our controlling
1655: // driver to program the hardware to take advantage of the higher domain
1656: // power. If it does so, we continue processing
1657: // (waiting for settle and notifying interested parties post-change.)
1658: // If it doesn't, we have to wait for it to acknowledge and then continue.
1659: //*********************************************************************************
1660:
1661: IOReturn IOService::parent_postchange_up_1 ( void )
1662: {
1663: if ( instruct_driver(priv->head_note_state) == IOPMAckImplied ) {
1664: return parent_postchange_up_2(); // it did it, carry on
1665: }
1666: else {
1667: priv->machine_state = IOPMparent_postchange_up_4; // it didn't, wait for it
1668: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogStartAckTimer,0,0);
1669: start_ack_timer();
1670: return IOPMWillAckLater;
1671: }
1672: }
1673:
1674:
1675: //*********************************************************************************
1676: // parent_postchange_up_2
1677: //
1678: // Our controlling driver has changed power state on the hardware
1679: // during a power raise initiated by the parent. Here we see if we need to wait
1680: // for power to settle before continuing. If not, we continue processing
1681: // (notifying interested parties post-change). If so, we wait and
1682: // continue later.
1683: //*********************************************************************************
1684:
1685: IOReturn IOService::parent_postchange_up_2 ( void )
1686: {
1687: priv->settle_time = compute_settle_time();
1688: if ( priv->settle_time == 0 ) {
1689: return parent_postchange_up_3();
1690: }
1691: else {
1692: priv->machine_state = IOPMparent_postchange_up_5;
1693: startSettleTimer(priv->settle_time);
1694: return IOPMWillAckLater;
1695: }
1696: }
1697:
1698:
1699: //*********************************************************************************
1700: // parent_postchange_up_4
1701: //
1702: // Our controlling driver has changed power state on the hardware
1703: // during a power raise initiated by the parent, but we had to wait for it.
1704: // Here we see if we need to wait for power to settle before continuing.
1705: // If not, we continue processing (notifying interested parties post-change).
1706: // If so, we wait and continue later.
1707: //*********************************************************************************
1708:
1709: void IOService::parent_postchange_up_4 ( void )
1710: {
1711: priv->settle_time = compute_settle_time();
1712: if ( priv->settle_time == 0 ) {
1713: parent_postchange_up_5();
1714: }
1715: else {
1716: priv->machine_state = IOPMparent_postchange_up_5;
1717: startSettleTimer(priv->settle_time);
1718: }
1719: }
1720:
1721:
1722: //*********************************************************************************
1723: // parent_postchange_up_3
1724: //
1725: // No power settling was required on a power raise initiated by the parent.
1726: // Here we notify all our interested parties post-change. If they all acknowledge,
1727: // we're done with this change note, and we can start on the next one.
1728: // Otherwise we have to wait for acknowledgements and finish up later.
1729: //*********************************************************************************
1730:
1731: IOReturn IOService::parent_postchange_up_3 ( void )
1732: {
1733: priv->machine_state = IOPMparent_postchange_up_6; // in case they don't all ack
1734: if ( notifyAll(false) == IOPMAckImplied ) {
1735: all_done();
1736: return IOPMAckImplied;
1737: }
1738: return IOPMWillAckLater; // they didn't
1739: }
1740:
1741:
1742: //*********************************************************************************
1743: // parent_postchange_up_5
1744: //
1745: // Power has settled on a power raise initiated by the parent.
1746: // Here we notify all our interested parties post-change. If they all acknowledge,
1747: // we're done with this change note, and we can start on the next one.
1748: // Otherwise we have to wait for acknowledgements and finish up later.
1749: //*********************************************************************************
1750:
1751: void IOService::parent_postchange_up_5 ( void )
1752: {
1753: priv->machine_state = IOPMparent_postchange_up_6; // in case they don't all ack
1754: if ( notifyAll(false) == IOPMAckImplied ) {
1755: parent_postchange_up_6();
1756: }
1757: }
1758:
1759:
1760: //*********************************************************************************
1761: // parent_postchange_up_6
1762: //
1763: // All parties have acknowledged our post-change notification of a power
1764: // raising initiated by the parent. Here we acknowledge the parent.
1765: // We are done with this change note, and we can start on the next one.
1766: //*********************************************************************************
1767:
1768: void IOService::parent_postchange_up_6 ( void )
1769: {
1770: all_done();
1771: pm_vars->myParent->acknowledgePowerChange(this);
1772: }
1773:
1774:
1775: //*********************************************************************************
1776: // all_done
1777: //
1778: // A power change is complete, and the used post-change note is at
1779: // the head of the queue. Remove it and set myCurrentState to the result
1780: // of the change. Start up the next change in queue.
1781: //*********************************************************************************
1782:
1783: void IOService::all_done ( void )
1784: {
1785: priv->machine_state = IOPMfinished;
1786:
1787: if ( priv->head_note_flags & IOPMWeInitiated ) {
1788: if ( !( priv->head_note_flags & IOPMNotDone) ) { // could our driver switch to the new state?
1789: pm_vars->myCurrentState = priv-> head_note_state; // yes
1790: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogChangeDone,(unsigned long)pm_vars->myCurrentState,0);
1791: }
1792: else { // no
1793: pm_vars->myCurrentState = pm_vars->theControllingDriver->powerStateForDomainState(pm_vars->parentCurrentPowerFlags);
1794: }
1795: }
1796: if ( priv->head_note_flags & IOPMParentInitiated ) {
1797: pm_vars->myCurrentState = priv->head_note_state;
1798: pm_vars->maxCapability = pm_vars->theControllingDriver->maxCapabilityForDomainState(priv->head_note_domainState);
1799: pm_vars->parentCurrentPowerFlags = priv->head_note_domainState;
1800: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogChangeDone,(unsigned long)pm_vars->myCurrentState,0);
1801: }
1802:
1803: priv->changeList->releaseHeadChangeNote(); // either way, we're done with this
1804:
1805: priv->head_note = priv->changeList->currentChange(); // start next one in queue
1806: if ( priv->head_note != -1 ) {
1807:
1808: if (priv->changeList->changeNote[priv->head_note].flags & IOPMWeInitiated ) {
1809: start_our_change(priv->head_note);
1810: }
1811: else {
1812: if ( start_parent_change(priv->head_note) == IOPMAckImplied ) {
1813: pm_vars->myParent->acknowledgePowerChange(this);
1814: }
1815: }
1816: }
1817: }
1818:
1819:
1820:
1821: //*********************************************************************************
1822: // all_acked
1823: //
1824: // A driver or child has acknowledged our notification of an upcoming power
1825: // change, and this acknowledgement is the last one pending
1826: // before we change power or after changing power.
1827: //
1828: //*********************************************************************************
1829:
1830: void IOService::all_acked ( void )
1831: {
1832: switch (priv->machine_state) {
1833: case IOPMour_prechange_1:
1834: our_prechange_1();
1835: break;
1836: case IOPMour_prechange_4:
1837: our_prechange_4();
1838: break;
1839: case IOPMparent_prechange_down_4:
1840: parent_prechange_down_4();
1841: break;
1842: case IOPMparent_postchange_down_2:
1843: parent_postchange_down_2();
1844: break;
1845: case IOPMparent_prechange_up_1:
1846: parent_prechange_up_1();
1847: break;
1848: case IOPMparent_postchange_up_6:
1849: parent_postchange_up_6();
1850: break;
1851: }
1852: }
1853:
1854:
1855: //*********************************************************************************
1856: // settleTimerExpired
1857: //
1858: // Power has settled after our last change. Notify interested parties that
1859: // there is a new power state.
1860: //*********************************************************************************
1861:
1862: void IOService::settleTimerExpired ( void )
1863: {
1864: switch (priv->machine_state) {
1865: case IOPMour_prechange_3:
1866: our_prechange_3();
1867: break;
1868: case IOPMparent_prechange_down_3:
1869: parent_prechange_down_3();
1870: break;
1871: case IOPMparent_postchange_up_5:
1872: parent_postchange_up_5();
1873: break;
1874: }
1875: }
1876:
1877:
1878: //*********************************************************************************
1879: // compute_settle_time
1880: //
1881: // Compute the power-settling delay in microseconds for the
1882: // change from myCurrentState to head_note_state.
1883: //*********************************************************************************
1884:
1885: unsigned long IOService::compute_settle_time ( void )
1886: {
1887: unsigned long totalTime;
1888: unsigned long i;
1889:
1890: totalTime = 0; // compute total time to attain the new state
1891: i = pm_vars->myCurrentState;
1892: if ( priv->head_note_state < pm_vars->myCurrentState ) { // we're lowering power
1893: while ( i > priv->head_note_state ) {
1894: totalTime += pm_vars->thePowerStates[i].settleDownTime;
1895: i--;
1896: }
1897: }
1898:
1899: if ( priv->head_note_state > pm_vars->myCurrentState ) { // we're raising power
1900: while ( i < priv->head_note_state ) {
1901: totalTime += pm_vars->thePowerStates[i+1].settleUpTime;
1902: i++;
1903: }
1904: }
1905:
1906: return totalTime;
1907: }
1908:
1909:
1910: //*********************************************************************************
1911: // startSettleTimer
1912: //
1913: // Enter with a power-settling delay in microseconds and start a nano-second
1914: // timer for that delay.
1915: //*********************************************************************************
1916:
1917: IOReturn IOService::startSettleTimer ( unsigned long delay )
1918: {
1919: AbsoluteTime deadline;
1920:
1921: clock_interval_to_deadline(delay, kMicrosecondScale, &deadline);
1922: thread_call_func_delayed(settle_timer_expired, (void *)this, deadline);
1923: return IOPMNoErr;
1924: }
1925:
1926: //*********************************************************************************
1927: // ack_timer_ticked
1928: //
1929: // The acknowledgement timeout periodic timer has ticked.
1930: // If we are awaiting acks for a power change notification,
1931: // we decrement the timer word of each interested driver which hasn't acked.
1932: // If a timer word becomes zero, we pretend the driver aknowledged.
1933: // If we are waiting for the controlling driver to change the power
1934: // state of the hardware, we decrement its timer word, and if it becomes
1935: // zero, we pretend the driver acknowledged.
1936: //*********************************************************************************
1937:
1938: void IOService::ack_timer_ticked ( void )
1939: {
1940: IOPMinformee * nextObject;
1941:
1942: if (! acquire_lock() ) {
1943: return;
1944: }
1945:
1946: if ( priv->driver_timer != 0 ) { // are we waiting for our driver to make its change?
1947: priv->driver_timer -= 1; // yes, tick once
1948: if ( priv->driver_timer == 0 ) { // it's tardy, we'll go on without it
1949: IOUnlock(priv->our_lock);
1950: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogCtrlDriverTardy,0,0);
1951: driver_acked();
1952: }
1953: else { // still waiting, set timer again
1954: start_ack_timer();
1955: IOUnlock(priv->our_lock);
1956: }
1957: return;
1958: }
1959:
1960: if (priv->head_note_pendingAcks != 0 ) { // are we waiting for interested parties to acknowledge?
1961: nextObject = priv->interestedDrivers->firstInList(); // yes, go through the list of interested drivers
1962: while ( nextObject != NULL ) { // and check each one
1963: if ( nextObject->timer > 0 ) {
1964: nextObject->timer -= 1;
1965: if ( nextObject->timer == 0 ) { // this one should have acked by now
1966: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogIntDriverTardy,0,0);
1967: priv->head_note_pendingAcks -= 1;
1968: }
1969: }
1970: nextObject = priv->interestedDrivers->nextInList(nextObject);
1971: }
1972: if ( priv->head_note_pendingAcks == 0 ) { // is that the last?
1973: IOUnlock(priv->our_lock);
1974: all_acked(); // yes, we can continue
1975: }
1976: else { // no, set timer again
1977: start_ack_timer();
1978: IOUnlock(priv->our_lock);
1979: }
1980: return;
1981: }
1982: IOUnlock(priv->our_lock); // not waiting for acks
1983: }
1984:
1985:
1986: //*********************************************************************************
1987: // start_ack_timer
1988: //
1989: //*********************************************************************************
1990:
1991: void IOService::start_ack_timer ( void )
1992: {
1993: AbsoluteTime deadline;
1994:
1995: clock_interval_to_deadline(ACK_TIMER_PERIOD, kNanosecondScale, &deadline);
1996: thread_call_func_delayed(ack_timer_expired, (void *)this, deadline);
1997: }
1998:
1999:
2000: //*********************************************************************************
2001: // stop_ack_timer
2002: //
2003: //*********************************************************************************
2004:
2005: void IOService::stop_ack_timer ( void )
2006: {
2007: thread_call_func_cancel(ack_timer_expired, (void *)this, true);
2008: }
2009:
2010:
2011: //*********************************************************************************
2012: // c-language timer expiration functions
2013: //
2014: //*********************************************************************************
2015:
2016: static void ack_timer_expired ( thread_call_param_t us, thread_call_param_t )
2017: {
2018: ((IOService *)us)->ack_timer_ticked();
2019: }
2020:
2021:
2022: static void settle_timer_expired ( thread_call_param_t us, thread_call_param_t )
2023: {
2024: ((IOService *)us)->settleTimerExpired();
2025: }
2026:
2027:
2028: //*********************************************************************************
2029: // add_to_active_change
2030: //
2031: // A child or interested driver has just registered with us. If there is
2032: // currently a change in progress, get the new party involved: if we
2033: // have notified all parties and are waiting for acks, notify the new
2034: // party.
2035: //*********************************************************************************
2036:
2037: IOReturn IOService::add_to_active_change ( IOPMinformee * newObject, bool is_child )
2038: {
2039: if (! acquire_lock() ) {
2040: return IOPMNoErr;
2041: }
2042:
2043: switch (priv->machine_state) {
2044: case IOPMour_prechange_1:
2045: priv->head_note_pendingAcks += 1;
2046: IOUnlock(priv->our_lock);
2047: notifyObject(newObject, true, is_child);
2048: return IOPMNoErr;
2049: case IOPMour_prechange_4:
2050: priv->head_note_pendingAcks += 1;
2051: IOUnlock(priv->our_lock);
2052: notifyObject(newObject, false, is_child);
2053: return IOPMNoErr;
2054: case IOPMparent_prechange_down_4:
2055: priv->head_note_pendingAcks += 1;
2056: IOUnlock(priv->our_lock);
2057: notifyObject(newObject, true, is_child);
2058: return IOPMNoErr;
2059: case IOPMparent_postchange_down_2:
2060: priv->head_note_pendingAcks += 1;
2061: IOUnlock(priv->our_lock);
2062: notifyObject(newObject, false, is_child);
2063: return IOPMNoErr;
2064: case IOPMparent_prechange_up_1:
2065: priv->head_note_pendingAcks += 1;
2066: IOUnlock(priv->our_lock);
2067: notifyObject(newObject, true, is_child);
2068: return IOPMNoErr;
2069: case IOPMparent_postchange_up_6:
2070: priv-> head_note_pendingAcks += 1;
2071: IOUnlock(priv->our_lock);
2072: notifyObject(newObject, false, is_child);
2073: return IOPMNoErr;
2074: }
2075: IOUnlock(priv->our_lock);
2076: return IOPMNoErr;
2077: }
2078:
2079:
2080: //*********************************************************************************
2081: // start_parent_change
2082: //
2083: // Here we begin the processing of a change note initiated by our parent
2084: // which is at the head of the queue.
2085: //
2086: // It is possible for the change to be processed to completion and removed from the queue.
2087: // There are several possible interruptions to the processing, though, and they are:
2088: // we may have to wait for interested parties to acknowledge our pre-change notification,
2089: // changes initiated by the parent will wait in the middle for powerStateDidChange,
2090: // we may have to wait for our controlling driver to change the hardware power state,
2091: // there may be a settling time after changing the hardware power state,
2092: // we may have to wait for interested parties to acknowledge our post-change notification,
2093: // we may have to wait for the acknowledgement timer expiration to substitute for the
2094: // acknowledgement from a failing driver.
2095: // We identify which of the following three possible lives the note
2096: // will have and then start the life:
2097: // 2. The parent initiated the change, and it is lowering power,
2098: // 3. The parent initiated the change, and it is raising power,
2099: // 4. The parent initiated the change, and the power state is not changing.
2100: //
2101: // In life-style 2, if all interested parties acknowledge our pre-change notification,
2102: // our controlling driver changes power states immediately without having to call us back later,
2103: // and there is no settling time required, we return IOPMAckImplied.
2104: // In life-style 3, if all interested parties acknowledge our pre-change notification, we return IOPMAckImplied.
2105: // In life-style 4, we always return IOPMAckImplied.
2106: // In any other case, we return IOPMWillAckLater.
2107: // If our caller is ultimately our powerDomainWillChange method, it will return our return code to the parent.
2108: // Otherwise, this new notification was dequeued from the queue after we finished a previous one.
2109: // In this case, an IOPMAckImplied return from here will cause the caller to explicitly acknowledge
2110: // the parent by calling its acknowledgePowerChange method.
2111: //*********************************************************************************
2112:
2113: IOReturn IOService::start_parent_change ( unsigned long queue_head )
2114: {
2115: priv->head_note = queue_head;
2116: priv-> head_note_flags = priv-> changeList->changeNote[priv->head_note].flags;
2117: priv-> head_note_state = priv->changeList->changeNote[priv->head_note].newStateNumber;
2118: priv-> head_note_outputFlags = priv->changeList->changeNote[priv->head_note].outputPowerCharacter;
2119: priv->head_note_domainState = priv->changeList->changeNote[priv->head_note].domainState;
2120: priv->head_note_capabilityFlags = priv->changeList->changeNote[priv->head_note].capabilityFlags;
2121:
2122: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogStartParentChange,(unsigned long)priv->head_note_state,0);
2123:
2124: ask_parent( priv->ourDesiredPowerState); // if we need something and haven't told the parent, do so
2125:
2126: if ( priv->head_note_state < pm_vars->myCurrentState ) {
2127: priv->initial_change = false; // life-style 2
2128: priv->machine_state = IOPMparent_prechange_down_4; // in case they don't all ack
2129: if ( notifyAll(true) == IOPMAckImplied ) {
2130: return parent_prechange_down_1();
2131: }
2132: return IOPMWillAckLater; // they didn't
2133: }
2134:
2135: if ( priv->head_note_state > pm_vars->myCurrentState ) { // if the parent is raising power, we may or may not
2136: if ( priv->ourDesiredPowerState > pm_vars->myCurrentState ) {
2137: if ( priv->ourDesiredPowerState < priv->head_note_state ) {
2138: priv->head_note_state = priv->ourDesiredPowerState; // we do, but not all the way
2139: priv->head_note_outputFlags = pm_vars->thePowerStates[priv->head_note_state].outputPowerCharacter;
2140: priv->head_note_capabilityFlags = pm_vars->thePowerStates[priv->head_note_state].capabilityFlags;
2141: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogAmendParentChange,(unsigned long)priv->head_note_state,0);
2142: }
2143: }
2144: else {
2145: priv-> head_note_state = pm_vars->myCurrentState; // we don't
2146: priv->head_note_outputFlags = pm_vars->thePowerStates[priv->head_note_state].outputPowerCharacter;
2147: priv->head_note_capabilityFlags = pm_vars->thePowerStates[priv->head_note_state].capabilityFlags;
2148: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogAmendParentChange,(unsigned long)priv->head_note_state,0);
2149: }
2150: }
2151:
2152: if ( priv->head_note_state > pm_vars->myCurrentState ) {
2153: priv->initial_change = false; // life-style 3
2154: priv->machine_state = IOPMparent_prechange_up_1; // in case they don't all ack
2155: if ( notifyAll(true) == IOPMAckImplied ) {
2156: priv->machine_state = IOPMparent_postchange_up_1;
2157: return IOPMAckImplied;
2158: }
2159: return IOPMWillAckLater; // they didn't
2160: }
2161:
2162: if ( priv->head_note_state == pm_vars->myCurrentState ) {
2163: priv->machine_state = IOPMparent_postchange_null; // life-style 4
2164: return IOPMAckImplied;
2165: }
2166: return IOPMAckImplied; // something wrong
2167: }
2168:
2169:
2170: //*********************************************************************************
2171: // start_our_change
2172: //
2173: // Here we begin the processing of a change note initiated by us
2174: // which is at the head of the queue.
2175: //
2176: // It is possible for the change to be processed to completion and removed from the queue.
2177: // There are several possible interruptions to the processing, though, and they are:
2178: // we may have to wait for interested parties to acknowledge our pre-change notification,
2179: // changes initiated by the parent will wait in the middle for powerStateDidChange,
2180: // we may have to wait for our controlling driver to change the hardware power state,
2181: // there may be a settling time after changing the hardware power state,
2182: // we may have to wait for interested parties to acknowledge our post-change notification,
2183: // we may have to wait for the acknowledgement timer expiration to substitute for the
2184: // acknowledgement from a failing driver.
2185: //*********************************************************************************
2186:
2187: void IOService::start_our_change ( unsigned long queue_head )
2188: {
2189: priv->head_note = queue_head;
2190: priv->head_note_flags = priv->changeList->changeNote[priv->head_note].flags;
2191: priv->head_note_state = priv->changeList->changeNote[priv->head_note].newStateNumber;
2192: priv->head_note_outputFlags = priv->changeList->changeNote[priv->head_note].outputPowerCharacter;
2193: priv->head_note_capabilityFlags = priv->changeList->changeNote[priv->head_note].capabilityFlags;
2194:
2195: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogStartDeviceChange,(unsigned long)priv->head_note_state,0);
2196:
2197: if ( ! priv->we_are_root ) {
2198: ask_parent(priv->head_note_state); // if this changes our power requirement, tell the parent
2199: }
2200:
2201: if ( priv->head_note_capabilityFlags & IOPMNotAttainable ) { // can our driver switch to the new state?
2202: priv-> head_note_flags |= IOPMNotDone; // no, mark the change note un-actioned
2203: all_done(); // and we're done
2204: return; // let the parent make the change for us
2205: }
2206: if ( (pm_vars->maxCapability < priv->head_note_state) && (! priv->we_are_root) ) { // is there enough power in the domain?
2207: priv->head_note_flags |= IOPMNotDone; // no, mark the change note un-actioned
2208: all_done(); // and we're done
2209: return; // till the parent raises power
2210: }
2211:
2212: if ( ! priv->initial_change ) {
2213: if ( priv->head_note_state == pm_vars->myCurrentState ) {
2214: all_done(); // we initiated a null change; forget it
2215: return;
2216: }
2217: }
2218: priv->initial_change = false;
2219:
2220: priv->machine_state = IOPMour_prechange_1; // in case they don't all ack
2221: if ( notifyAll(true) == IOPMAckImplied ) { // in life-style 1
2222: our_prechange_1();
2223: }
2224: }
2225:
2226:
2227: //*********************************************************************************
2228: // ask_parent
2229: //
2230: // Call the power domain parent to ask for a higher power state in the domain
2231: // or to suggest a lower power state.
2232: //*********************************************************************************
2233:
2234: IOReturn IOService::ask_parent ( unsigned long requestedState )
2235: {
2236: unsigned long savedPreviousRequest;
2237: IOReturn return_code;
2238:
2239: if ( priv->previousRequest == pm_vars->thePowerStates[requestedState].inputPowerRequirement ) { // is this a new desire?
2240: return IOPMNoErr; // no, the parent knows already, just return
2241: }
2242:
2243: if ( priv->we_are_root ) {
2244: return IOPMNoErr;
2245: }
2246: savedPreviousRequest = priv->previousRequest; // yes, remember our previous request for a second
2247: priv->previousRequest = pm_vars->thePowerStates[requestedState].inputPowerRequirement;
2248: return_code = pm_vars->myParent->requestDomainState( priv->previousRequest,this,IOPMLowestState);
2249:
2250: if ( return_code != IOPMNoErr ) { // if that was not ok with the parent,
2251:
2252: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogRequestDenied,(unsigned long)priv->previousRequest,0);
2253: priv->previousRequest = savedPreviousRequest; // remember our previous desire
2254: }
2255: return return_code;
2256: }
2257:
2258:
2259: //*********************************************************************************
2260: // instruct_driver
2261: //
2262: // Call the controlling driver and have it change the power state of the
2263: // hardware. If it returns IOPMAckImplied, the change is complete, and
2264: // we return IOPMAckImplied. Otherwise, it will ack when the change
2265: // is done; we return IOPMWillAckLater.
2266: //*********************************************************************************
2267:
2268: IOReturn IOService::instruct_driver ( unsigned long newState )
2269: {
2270: IOReturn return_code;
2271:
2272: if ( pm_vars->thePowerStates[newState].capabilityFlags & IOPMNotAttainable ) { // can our driver switch to the desired state?
2273: return IOPMAckImplied; // no, so don't try
2274: }
2275: priv->driver_timer = -1;
2276: pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogProgramHardware,newState,0);
2277: return_code = pm_vars->theControllingDriver->setPowerState( newState,this ); // yes, instruct it
2278: if ( return_code == IOPMAckImplied ) { // it finished
2279: priv->driver_timer = 0;
2280: return IOPMAckImplied;
2281: }
2282:
2283: if ( priv->driver_timer == 0 ) { // it acked behind our back
2284: return IOPMAckImplied;
2285: }
2286:
2287: if ( return_code < 0 ) { // somebody goofed
2288: return IOPMAckImplied;
2289: }
2290:
2291: priv->driver_timer = (return_code / 1000) + 1; // it didn't finish
2292: return IOPMWillAckLater;
2293: }
2294:
2295:
2296: //*********************************************************************************
2297: // acquire_lock
2298: //
2299: // We are acquiring the lock we use to protect our queue head from
2300: // simutaneous access by a thread which calls acknowledgePowerStateChange
2301: // or acknowledgeSetPowerState and the ack timer expiration thread.
2302: // Return TRUE if we acquire the lock, and the queue head didn't change
2303: // while we were acquiring the lock (and maybe blocked).
2304: // If there is no queue head, or it changes while we are blocked,
2305: // return FALSE with the lock unlocked.
2306: //*********************************************************************************
2307:
2308: bool IOService::acquire_lock ( void )
2309: {
2310: long current_change_note;
2311:
2312: current_change_note = priv->head_note;
2313: if ( current_change_note == -1 ) {
2314: return FALSE;
2315: }
2316:
2317: IOTakeLock(priv->our_lock);
2318: if ( current_change_note == priv->head_note ) {
2319: return TRUE;
2320: }
2321: else { // we blocked and something changed radically
2322: IOUnlock(priv->our_lock); // so there's nothing to do any more
2323: return FALSE;
2324: }
2325: }
2326:
2327:
2328: //*********************************************************************************
2329: // foundDevice
2330: //
2331: // Does nothing here. This should be implemented in a subclass driver.
2332: //*********************************************************************************
2333: #if BREAK
2334: IOReturn IOService::foundDevice ( IOService * yourDevice )
2335: {
2336: return IOPMNoErr;
2337: }
2338: #endif
2339:
2340: //*********************************************************************************
2341: // setPowerState
2342: //
2343: // Does nothing here. This should be implemented in a subclass driver.
2344: //*********************************************************************************
2345:
2346: IOReturn IOService::setPowerState ( unsigned long powerStateOrdinal, IOService* whatDevice )
2347: {
2348: return IOPMNoErr;
2349: }
2350:
2351:
2352: //*********************************************************************************
2353: // maxCapabilityForDomainState
2354: //
2355: // Finds the highest power state in the array whose input power
2356: // requirement is equal to the input parameter. Where a more intelligent
2357: // decision is possible, override this in the subclassed driver.
2358: //*********************************************************************************
2359:
2360: unsigned long IOService::maxCapabilityForDomainState ( IOPMPowerFlags domainState )
2361: {
2362: int i;
2363:
2364: if (pm_vars->theNumberOfPowerStates == 0 ) {
2365: return 0;
2366: }
2367: for ( i = (pm_vars->theNumberOfPowerStates)-1; i >= 0; i-- ) {
2368: if ( pm_vars->thePowerStates[i].inputPowerRequirement == domainState ) {
2369: return i;
2370: }
2371: }
2372: return 0;
2373: }
2374:
2375:
2376: //*********************************************************************************
2377: // initialPowerStateForDomainState
2378: //
2379: // Finds the highest power state in the array whose input power
2380: // requirement is equal to the input parameter. Where a more intelligent
2381: // decision is possible, override this in the subclassed driver.
2382: //*********************************************************************************
2383:
2384: unsigned long IOService::initialPowerStateForDomainState ( IOPMPowerFlags domainState )
2385: {
2386: int i;
2387:
2388: if (pm_vars->theNumberOfPowerStates == 0 ) {
2389: return 0;
2390: }
2391: for ( i = (pm_vars->theNumberOfPowerStates)-1; i >= 0; i-- ) {
2392: if ( pm_vars->thePowerStates[i].inputPowerRequirement == domainState ) {
2393: return i;
2394: }
2395: }
2396: return 0;
2397: }
2398:
2399:
2400: //*********************************************************************************
2401: // powerStateForDomainState
2402: //
2403: // Finds the highest power state in the array whose input power
2404: // requirement is equal to the input parameter. Where a more intelligent
2405: // decision is possible, override this in the subclassed driver.
2406: //*********************************************************************************
2407:
2408: unsigned long IOService::powerStateForDomainState ( IOPMPowerFlags domainState )
2409: {
2410: int i;
2411:
2412: if (pm_vars->theNumberOfPowerStates == 0 ) {
2413: return 0;
2414: }
2415: for ( i = (pm_vars->theNumberOfPowerStates)-1; i >= 0; i-- ) {
2416: if ( pm_vars->thePowerStates[i].inputPowerRequirement == domainState ) {
2417: return i;
2418: }
2419: }
2420: return 0;
2421: }
2422:
2423:
2424: //*********************************************************************************
2425: // powerStateWillChangeTo
2426: //
2427: // Does nothing here. This should be implemented in a subclass driver.
2428: //*********************************************************************************
2429:
2430: IOReturn IOService::powerStateWillChangeTo ( IOPMPowerFlags, unsigned long, IOService*)
2431: {
2432: return 0;
2433: }
2434:
2435:
2436: //*********************************************************************************
2437: // powerStateDidChangeTo
2438: //
2439: // Does nothing here. This should be implemented in a subclass driver.
2440: //*********************************************************************************
2441:
2442: IOReturn IOService::powerStateDidChangeTo ( IOPMPowerFlags, unsigned long, IOService*)
2443: {
2444: return 0;
2445: }
2446:
2447:
2448: //*********************************************************************************
2449: // newTemperature
2450: //
2451: // Does nothing here. This should be implemented in a subclass driver.
2452: //*********************************************************************************
2453:
2454: IOReturn IOService::newTemperature ( long currentTemp, IOService * whichZone )
2455:
2456: {
2457: return IOPMNoErr;
2458: }
2459:
2460:
2461: #undef super
2462: #define super OSObject
2463:
2464: OSDefineMetaClassAndStructors(IOPMprot, OSObject)
2465: //*********************************************************************************
2466: // serialize
2467: //
2468: // Serialize protected instance variables for debug output.
2469: //*********************************************************************************
2470: bool IOPMprot::serialize(OSSerialize *s) const
2471: {
2472: OSString * theOSString;
2473: char * buffer;
2474: char * ptr;
2475: int i;
2476: bool rtn_code;
2477:
2478: buffer = ptr = IONew(char, 2000);
2479: if(!buffer)
2480: return false;
2481:
2482: ptr += sprintf(ptr,"{ theNumberOfPowerStates = %d, ",(unsigned int)theNumberOfPowerStates);
2483:
2484: if ( theNumberOfPowerStates != 0 ) {
2485: ptr += sprintf(ptr,"version %d, ",(unsigned int)thePowerStates[0].version);
2486: }
2487:
2488: if ( theNumberOfPowerStates != 0 ) {
2489: for ( i = 0; i < (int)theNumberOfPowerStates; i++ ) {
2490: ptr += sprintf(ptr,"power state %d = { ",i);
2491: ptr += sprintf(ptr,"capabilityFlags %08x, ",(unsigned int)thePowerStates[i].capabilityFlags);
2492: ptr += sprintf(ptr,"outputPowerCharacter %08x, ",(unsigned int)thePowerStates[i].outputPowerCharacter);
2493: ptr += sprintf(ptr,"inputPowerRequirement %08x, ",(unsigned int)thePowerStates[i].inputPowerRequirement);
2494: ptr += sprintf(ptr,"staticPower %d, ",(unsigned int)thePowerStates[i].staticPower);
2495: ptr += sprintf(ptr,"unbudgetedPower %d, ",(unsigned int)thePowerStates[i].unbudgetedPower);
2496: ptr += sprintf(ptr,"powerToAttain %d, ",(unsigned int)thePowerStates[i].powerToAttain);
2497: ptr += sprintf(ptr,"timeToAttain %d, ",(unsigned int)thePowerStates[i].timeToAttain);
2498: ptr += sprintf(ptr,"settleUpTime %d, ",(unsigned int)thePowerStates[i].settleUpTime);
2499: ptr += sprintf(ptr,"timeToLower %d, ",(unsigned int)thePowerStates[i].timeToLower);
2500: ptr += sprintf(ptr,"settleDownTime %d, ",(unsigned int)thePowerStates[i].settleDownTime);
2501: ptr += sprintf(ptr,"powerDomainBudget %d }, ",(unsigned int)thePowerStates[i].powerDomainBudget);
2502: }
2503: }
2504:
2505: ptr += sprintf(ptr,"aggressiveness = %d, ",(unsigned int)aggressiveness);
2506: ptr += sprintf(ptr,"myCurrentState = %d, ",(unsigned int)myCurrentState);
2507: ptr += sprintf(ptr,"parentCurrentPowerFlags = %08x, ",(unsigned int)parentCurrentPowerFlags);
2508: ptr += sprintf(ptr,"maxCapability = %d }",(unsigned int)maxCapability);
2509:
2510: theOSString = OSString::withCString(buffer);
2511: rtn_code = theOSString->serialize(s);
2512: theOSString->release();
2513: IODelete(buffer, char, 2000);
2514:
2515: return rtn_code;
2516: }
2517:
2518:
2519: #undef super
2520: #define super OSObject
2521:
2522: OSDefineMetaClassAndStructors(IOPMpriv, OSObject)
2523: //*********************************************************************************
2524: // serialize
2525: //
2526: // Serialize private instance variables for debug output.
2527: //*********************************************************************************
2528: bool IOPMpriv::serialize(OSSerialize *s) const
2529: {
2530: OSString * theOSString;
2531: char * buffer;
2532: char * ptr;
2533: IOPMinformee * nextObject;
2534: bool rtn_code;
2535:
2536: buffer = ptr = IONew(char, 2000);
2537: if(!buffer)
2538: return false;
2539:
2540: ptr += sprintf(ptr,"{ this object = %08x",(unsigned int)owner);
2541: if ( we_are_root ) {
2542: ptr += sprintf(ptr," (root)");
2543: }
2544: ptr += sprintf(ptr,", ");
2545:
2546: nextObject = interestedDrivers->firstInList(); // display interested drivers
2547: while ( nextObject != NULL ) {
2548: ptr += sprintf(ptr,"interested driver = %08x, ",(unsigned int)nextObject->whatObject);
2549: nextObject = interestedDrivers->nextInList(nextObject);
2550: }
2551:
2552: nextObject =children->firstInList(); // display power domain children
2553: while ( nextObject != NULL ) {
2554: ptr += sprintf(ptr,"child = %08x, ",(unsigned int)nextObject->whatObject);
2555: nextObject = children->nextInList(nextObject);
2556: }
2557:
2558: ptr += sprintf(ptr,"numberOfInformees = %d, ",(unsigned int)numberOfInformees);
2559:
2560: if ( machine_state != IOPMfinished ) {
2561: ptr += sprintf(ptr,"machine_state = %d, ",(unsigned int)machine_state);
2562: ptr += sprintf(ptr,"driver_timer = %d, ",(unsigned int)driver_timer);
2563: ptr += sprintf(ptr,"settle_time = %d, ",(unsigned int)settle_time);
2564: ptr += sprintf(ptr,"head_note_flags = %08x, ",(unsigned int)head_note_flags);
2565: ptr += sprintf(ptr,"head_note_state = %d, ",(unsigned int)head_note_state);
2566: ptr += sprintf(ptr,"head_note_outputFlags = %08x, ",(unsigned int)head_note_outputFlags);
2567: ptr += sprintf(ptr,"head_note_domainState = %08x, ",(unsigned int)head_note_domainState);
2568: ptr += sprintf(ptr,"head_note_capabilityFlags = %08x, ",(unsigned int)head_note_capabilityFlags);
2569: ptr += sprintf(ptr,"head_note_pendingAcks = %d, ",(unsigned int)head_note_pendingAcks);
2570: }
2571:
2572: if ( device_overrides ) {
2573: ptr += sprintf(ptr,"device overrides, ");
2574: }
2575: ptr += sprintf(ptr,"driverDesire = %d, ",(unsigned int)driverDesire);
2576: ptr += sprintf(ptr,"deviceDesire = %d, ",(unsigned int)deviceDesire);
2577: ptr += sprintf(ptr,"ourDesiredPowerState = %d, ",(unsigned int)ourDesiredPowerState);
2578: ptr += sprintf(ptr,"previousRequest = %d }",(unsigned int)previousRequest);
2579:
2580: theOSString = OSString::withCString(buffer);
2581: rtn_code = theOSString->serialize(s);
2582: theOSString->release();
2583: IODelete(buffer, char, 2000);
2584:
2585: return rtn_code;
2586: }
2587:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.