]> git.saurik.com Git - apple/xnu.git/blob - iokit/Kernel/IOPMPagingPlexus.cpp
187e0a1b711ba3142aae6578d11e161db0ae9c16
[apple/xnu.git] / iokit / Kernel / IOPMPagingPlexus.cpp
1 /*
2 * Copyright (c) 1998-2001 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22 /*
23 * Copyright (c) 1998 Apple Computer, Inc. All rights reserved.
24 *
25 * HISTORY
26 * 9 May 01 suurballe.
27 */
28
29 #include <IOKit/pwr_mgt/IOPMPagingPlexus.h>
30 #include <IOKit/pwr_mgt/IOPM.h>
31 #include <IOKit/pwr_mgt/RootDomain.h>
32 #include <IOKit/pwr_mgt/IOPowerConnection.h>
33 #include <IOKit/IOLib.h>
34
35 extern char rootdevice[];
36
37 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
38
39 #define super IOService
40 OSDefineMetaClassAndStructors(IOPMPagingPlexus,IOService)
41
42
43 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
44
45 // stub driver has two power states, off and on
46
47 enum { kIOPlexusPowerStateCount = 2 };
48
49 static const IOPMPowerState powerStates[ kIOPlexusPowerStateCount ] = {
50 { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
51 { 1, 0, IOPMPagingAvailable, IOPMPowerOn, 0, 0, 0, 0, 0, 0, 0, 0 }
52 };
53
54 //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
55 // initialize
56 //
57 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
58
59 bool IOPMPagingPlexus::start ( IOService * provider )
60 {
61 super::start(provider);
62
63 ourLock = IOLockAlloc();
64 systemBooting = true;
65
66 PMinit(); // initialize superclass variables
67
68 registerPowerDriver(this,(IOPMPowerState *)powerStates,kIOPlexusPowerStateCount);
69
70 return true;
71 }
72
73
74 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
75 // setAggressiveness
76 //
77 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
78
79 IOReturn IOPMPagingPlexus::setAggressiveness ( unsigned long type, unsigned long )
80 {
81 OSDictionary * dict;
82 OSIterator * iter;
83 OSObject * next;
84 IOService * candidate = 0;
85 IOService * pagingProvider;
86
87 if( type != kPMMinutesToSleep)
88 return IOPMNoErr;
89
90 IOLockLock(ourLock);
91 if ( systemBooting ) {
92 systemBooting = false;
93 IOLockUnlock(ourLock);
94 dict = IOBSDNameMatching(rootdevice);
95 if ( dict ) {
96 iter = getMatchingServices(dict);
97 if ( iter ) {
98 while ( (next = iter->getNextObject()) ) {
99 if ( (candidate = OSDynamicCast(IOService,next)) ) {
100 break;
101 }
102 }
103 iter->release();
104 }
105 }
106 if ( candidate ) {
107 pagingProvider = findProvider(candidate);
108 if ( pagingProvider ) {
109 processSiblings(pagingProvider);
110 pagingProvider->addPowerChild(this);
111 getPMRootDomain()->removePowerChild(((IOPowerConnection *)getParentEntry(gIOPowerPlane)));
112 processChildren();
113 }
114 }
115 }
116 else {
117 IOLockUnlock(ourLock);
118 }
119 return IOPMNoErr;
120 }
121
122
123 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
124 // findProvider
125 //
126 // Climb upward in the power tree from the node pointed to by the parameter.
127 // Return a pointer to the first power-managed entity encountered.
128 // This is the provider of paging services (the root device disk driver).
129 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
130
131 IOService * IOPMPagingPlexus::findProvider ( IOService * mediaObject )
132 {
133 IORegistryEntry * node = mediaObject;
134
135 if ( mediaObject == NULL ) {
136 return NULL;
137 }
138
139 while ( node ) {
140 if ( node->inPlane(gIOPowerPlane) ) {
141 return (IOService *)node;
142 }
143 node = node->getParentEntry(gIOServicePlane);
144 }
145 return NULL;
146 }
147
148 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
149 // processSiblings
150 //
151 // Climb upward in the power tree from the node pointed to by the parameter.
152 // "Other" children of each ancestor (not the nodes in our upward path) are
153 // made children of this plexus, so they get paging services from here.
154 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
155
156 void IOPMPagingPlexus::processSiblings ( IOService * aNode )
157 {
158 OSIterator * parentIterator;
159 IORegistryEntry * nextNub;
160 IORegistryEntry * nextParent;
161 OSIterator * siblingIterator;
162 IORegistryEntry * nextSibling;
163
164 parentIterator = aNode->getParentIterator(gIOPowerPlane); // iterate parents of this node
165
166 if ( parentIterator ) {
167 while ( true ) {
168 if ( ! (nextNub = (IORegistryEntry *)(parentIterator->getNextObject())) ) {
169 parentIterator->release();
170 break;
171 }
172 if ( OSDynamicCast(IOPowerConnection,nextNub) ) {
173 nextParent = nextNub->getParentEntry(gIOPowerPlane);
174 if ( nextParent == getPMRootDomain() ) {
175 continue; // plexus already has root's children
176 }
177 if ( nextParent == this ) {
178 parentIterator->release();
179 removePowerChild((IOPowerConnection *)nextNub);
180 break;
181 }
182 siblingIterator = nextParent->getChildIterator(gIOPowerPlane);
183 // iterate children of this parent
184 if ( siblingIterator ) {
185 while ( (nextSibling = (IORegistryEntry *)(siblingIterator->getNextObject())) ) {
186 if ( OSDynamicCast(IOPowerConnection,nextSibling) ) {
187 nextSibling = nextSibling->getChildEntry(gIOPowerPlane);
188 if ( nextSibling != aNode ) { // non-ancestor of driver gets
189 addPowerChild((IOService *)nextSibling); // plexus as parent
190 }
191 }
192 }
193 siblingIterator->release();
194 }
195 processSiblings((IOService *)nextParent); // do the same thing to this parent
196 }
197 }
198 }
199 }
200
201
202 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
203 // processChildren
204 //
205 // Now invent the need for paging services: alter our children's arrays
206 // to show that they need paging.
207 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
208
209 void IOPMPagingPlexus::processChildren ( void )
210 {
211 OSIterator * childIterator;
212 IOPowerConnection * nextChildNub;
213 IORegistryEntry * nextChild;
214 IOService * child;
215 unsigned int i;
216
217 childIterator = getChildIterator(gIOPowerPlane);
218
219 if ( childIterator ) {
220 while ( (nextChild = (IORegistryEntry *)(childIterator->getNextObject())) ) {
221 if ( (nextChildNub = OSDynamicCast(IOPowerConnection,nextChild)) ) {
222 child = (IOService *)nextChild->getChildEntry(gIOPowerPlane);
223 if ( child->pm_vars->theControllingDriver ) {
224 for ( i = 1; i < child->pm_vars->theNumberOfPowerStates; i++ ) {
225 child->pm_vars->thePowerStates[i].inputPowerRequirement |= IOPMPagingAvailable;
226 }
227 }
228 if ( child->pm_vars->myCurrentState ) {
229 nextChildNub->setDesiredDomainState(kIOPlexusPowerStateCount-1);
230 }
231 }
232 }
233 childIterator->release();
234 }
235 }