]> git.saurik.com Git - apple/xnu.git/blob - iokit/Drivers/platform/drvAppleRootDomain/RootDomain.cpp
xnu-123.5.tar.gz
[apple/xnu.git] / iokit / Drivers / platform / drvAppleRootDomain / RootDomain.cpp
1 /*
2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22 #include <IOKit/IOWorkLoop.h>
23 #include <IOKit/IOCommandQueue.h>
24 #include <IOKit/IOTimerEventSource.h>
25 #include <IOKit/IOPlatformExpert.h>
26 #include <IOKit/pwr_mgt/RootDomain.h>
27 #include <IOKit/pwr_mgt/IOPM.h>
28 #include <IOKit/IOMessage.h>
29 #include "RootDomainUserClient.h"
30
31 extern "C" {
32 extern void kprintf(const char *, ...);
33 }
34
35 extern const IORegistryPlane * gIOPowerPlane;
36
37 void PMreceiveCmd ( OSObject *, void *, void *, void *, void * );
38 bool rootHasPMU( OSObject * us, void *, IOService * yourDevice );
39
40
41 #define number_of_power_states 3
42 #define OFF_STATE 0
43 #define SLEEP_STATE 1
44 #define ON_STATE 2
45
46 #define ON_POWER IOPMPowerOn
47 #define SLEEP_POWER IOPMAuxPowerOn
48
49 static IOPMPowerState ourPowerStates[number_of_power_states] = {
50 {1,0,0,0,0,0,0,0,0,0,0,0},
51 {1,0,0,SLEEP_POWER,0,0,0,0,0,0,0,0},
52 {1,IOPMPowerOn,IOPMPowerOn,ON_POWER,0,0,0,0,0,0,0,0},
53 };
54
55 static IOPMrootDomain * gRootDomain;
56
57 #define super IOService
58 OSDefineMetaClassAndStructors(IOPMrootDomain,IOService)
59
60 extern "C"
61 {
62 IONotifier * registerSleepWakeInterest(IOServiceInterestHandler handler, void * self, void * ref = 0)
63 {
64 return gRootDomain->registerInterest( gIOGeneralInterest, handler, self, ref );
65 }
66
67 IOReturn acknowledgeSleepWakeNotification(void * PMrefcon)
68 {
69 return gRootDomain->allowPowerChange ( (unsigned long)PMrefcon );
70 }
71
72 }
73
74
75 // **********************************************************************************
76 // start
77 //
78 // We don't do much here. The real initialization occurs when the platform
79 // expert informs us we are the root.
80 // **********************************************************************************
81 bool IOPMrootDomain::start ( IOService * nub )
82 {
83 super::start(nub);
84
85 gRootDomain = this;
86
87 PMinit();
88 allowSleep = true;
89 sleepIsSupported = false;
90 idlePeriod = 0;
91 systemBooting = true;
92 // systemBooting = false; // temporary work-around for 2589847
93 ignoringClamshell = false;
94
95 pm_vars->PMworkloop = IOWorkLoop::workLoop(); // make the workloop
96 pm_vars->commandQueue = IOCommandQueue::commandQueue(this, PMreceiveCmd); // make a command queue
97 if (! pm_vars->commandQueue ||
98 ( pm_vars->PMworkloop->addEventSource( pm_vars->commandQueue) != kIOReturnSuccess) ) {
99 return IOPMNoErr;
100 }
101
102 patriarch = new IORootParent; // create our parent
103 patriarch->init();
104 patriarch->attach(this);
105 patriarch->start(this);
106 patriarch->youAreRoot();
107 patriarch->wakeSystem();
108 patriarch->addPowerChild(this);
109
110 registerPowerDriver(this,ourPowerStates,number_of_power_states);
111
112 // Clamp power on. We will revisit this decision when the login window is displayed
113 // and we receive preferences via SetAggressiveness.
114 changePowerStateToPriv(ON_STATE); // clamp power on
115 powerOverrideOnPriv();
116
117 registerService(); // let clients find us
118
119 return true;
120 }
121
122
123 //*********************************************************************************
124 // youAreRoot
125 //
126 // Power Managment is informing us that we are the root power domain.
127 // We know we are not the root however, since we have just instantiated a parent
128 // for ourselves and made it the root. We override this method so it will have
129 // no effect
130 //*********************************************************************************
131 IOReturn IOPMrootDomain::youAreRoot ( void )
132 {
133 return IOPMNoErr;
134 }
135
136
137 // **********************************************************************************
138 // command_received
139 //
140 // We have received a command from ourselves on the command queue.
141 // If it is to send a recently-received aggressiveness factor, do so.
142 // Otherwise, it's something the superclass enqueued.
143 // **********************************************************************************
144 void IOPMrootDomain::command_received ( void * command, void * x, void * y, void * z )
145 {
146 switch ( (int)command ) {
147 case kPMbroadcastAggressiveness:
148 if ( (int)x == kPMMinutesToSleep ) {
149 idlePeriod = (int)y*60;
150 if ( allowSleep && sleepIsSupported ) {
151 setIdleTimerPeriod(idlePeriod); // set new timeout
152 }
153 }
154 break;
155 default:
156 super::command_received(command,x,y,z);
157 break;
158 }
159 }
160
161
162 //*********************************************************************************
163 // setAggressiveness
164 //
165 // Some aggressiveness factor has changed. We put this change on our
166 // command queue so that we can broadcast it to the hierarchy while on
167 // the Power Mangement workloop thread. This enables objects in the
168 // hierarchy to successfully alter their idle timers, which are all on the
169 // same thread.
170 //*********************************************************************************
171
172 IOReturn IOPMrootDomain::setAggressiveness ( unsigned long type, unsigned long newLevel )
173 {
174 systemBooting = false; // when the finder launches, this method gets called -- system booting is done.
175
176 pm_vars->commandQueue->enqueueCommand(true, (void *)kPMbroadcastAggressiveness, (void *) type, (void *) newLevel );
177 super::setAggressiveness(type,newLevel);
178
179 return kIOReturnSuccess;
180 }
181
182
183 // **********************************************************************************
184 // sleepSystem
185 //
186 // **********************************************************************************
187 IOReturn IOPMrootDomain::sleepSystem ( void )
188 {
189 kprintf("sleep demand received\n");
190 if ( !systemBooting && allowSleep && sleepIsSupported ) {
191 patriarch->sleepSystem();
192 }
193 return kIOReturnSuccess;
194 }
195
196
197 // **********************************************************************************
198 // powerChangeDone
199 //
200 // This overrides powerChangeDone in IOService.
201 // If we just finished switching to state zero, call the platform expert to
202 // sleep the kernel.
203 // Then later, when we awake, the kernel returns here and we wake the system.
204 // **********************************************************************************
205 void IOPMrootDomain::powerChangeDone ( unsigned long powerStateOrdinal )
206 {
207 if ( powerStateOrdinal == SLEEP_STATE ) {
208 pm_vars->thePlatform->sleepKernel();
209 activityTickle(kIOPMSubclassPolicy); // reset idle sleep
210 systemWake(); // tell the tree we're waking
211 patriarch->wakeSystem(); // make sure we have power
212 changePowerStateToPriv(ON_STATE); // and wake
213 }
214 }
215
216
217 // **********************************************************************************
218 // newUserClient
219 //
220 // **********************************************************************************
221 IOReturn IOPMrootDomain::newUserClient( task_t owningTask, void * /* security_id */, UInt32 type, IOUserClient ** handler )
222 {
223 IOReturn err = kIOReturnSuccess;
224 RootDomainUserClient * client;
225
226 client = RootDomainUserClient::withTask(owningTask);
227
228 if( !client || (false == client->attach( this )) ||
229 (false == client->start( this )) ) {
230 if(client) {
231 client->detach( this );
232 client->release();
233 client = NULL;
234 }
235 err = kIOReturnNoMemory;
236 }
237 *handler = client;
238 return err;
239 }
240
241 //*********************************************************************************
242 // receivePowerNotification
243 //
244 // The power controller is notifying us of a hardware-related power management
245 // event that we must handle. This is a result of an 'environment' interrupt from
246 // the power mgt micro.
247 //*********************************************************************************
248
249 IOReturn IOPMrootDomain::receivePowerNotification (UInt32 msg)
250 {
251 if (msg & kIOPMSleepNow) {
252 (void) sleepSystem ();
253 }
254
255 if (msg & kIOPMPowerButton) {
256 (void) sleepSystem ();
257 }
258
259 if (msg & kIOPMPowerEmergency) {
260 (void) sleepSystem ();
261 }
262
263 if (msg & kIOPMClamshellClosed) {
264 if ( ! ignoringClamshell ) {
265 (void) sleepSystem ();
266 }
267 }
268
269 if (msg & kIOPMIgnoreClamshell) {
270 ignoringClamshell = true;
271 }
272
273 if (msg & kIOPMAllowSleep) {
274 if ( sleepIsSupported ) {
275 setIdleTimerPeriod(idlePeriod);
276 }
277 allowSleep = true;
278 changePowerStateTo (0);
279 }
280
281 // if the case is open on some machines, we must now
282 // allow the machine to be put to sleep or to idle sleep
283
284 if (msg & kIOPMPreventSleep) {
285 if ( sleepIsSupported ) {
286 setIdleTimerPeriod(0);
287 }
288 allowSleep = false;
289 changePowerStateTo (number_of_power_states-1);
290 }
291
292 return 0;
293 }
294
295
296 //*********************************************************************************
297 // sleepSupported
298 //
299 //*********************************************************************************
300
301 void IOPMrootDomain::setSleepSupported( IOOptionBits flags )
302 {
303 platformSleepSupport = flags;
304 if ( flags & kRootDomainSleepSupported ) {
305 sleepIsSupported = true;
306 setProperty("IOSleepSupported","");
307 }
308 else
309 {
310 sleepIsSupported = false;
311 removeProperty("IOSleepSupported");
312 }
313
314 }
315
316 //*********************************************************************************
317 // getSleepSupported
318 //
319 //*********************************************************************************
320
321 IOOptionBits IOPMrootDomain::getSleepSupported( void )
322 {
323 return( platformSleepSupport );
324 }
325
326
327 //*********************************************************************************
328 // tellChangeDown
329 //
330 // We override the superclass implementation so we can send a different message
331 // type to the client or application being notified.
332 //*********************************************************************************
333
334 bool IOPMrootDomain::tellChangeDown ( unsigned long stateNum )
335 {
336 if ( stateNum == SLEEP_STATE ) {
337 return super::tellClientsWithResponse(kIOMessageSystemWillSleep);
338 }
339 return super::tellChangeDown(stateNum);
340 }
341
342
343 //*********************************************************************************
344 // askChangeDown
345 //
346 // We override the superclass implementation so we can send a different message
347 // type to the client or application being notified.
348 //*********************************************************************************
349
350 bool IOPMrootDomain::askChangeDown (unsigned long stateNum)
351 {
352 if ( stateNum == SLEEP_STATE ) {
353 return super::tellClientsWithResponse(kIOMessageCanSystemSleep);
354 }
355 return super::askChangeDown(stateNum);
356 }
357
358
359 //*********************************************************************************
360 // tellNoChangeDown
361 //
362 // Notify registered applications and kernel clients that we are not
363 // dropping power.
364 //
365 // We override the superclass implementation so we can send a different message
366 // type to the client or application being notified.
367 //*********************************************************************************
368
369 void IOPMrootDomain::tellNoChangeDown ( unsigned long )
370 {
371 return tellClients(kIOMessageSystemWillNotSleep);
372 }
373
374
375 //*********************************************************************************
376 // tellChangeUp
377 //
378 // Notify registered applications and kernel clients that we are raising power.
379 //
380 // We override the superclass implementation so we can send a different message
381 // type to the client or application being notified.
382 //*********************************************************************************
383
384 void IOPMrootDomain::tellChangeUp ( unsigned long )
385 {
386 return tellClients(kIOMessageSystemHasPoweredOn);
387 }
388
389
390 // **********************************************************************************
391 // activityTickle
392 //
393 // This is called by the HID system and calls the superclass in turn.
394 // **********************************************************************************
395
396 bool IOPMrootDomain::activityTickle ( unsigned long, unsigned long x=0 )
397 {
398 return super::activityTickle (kIOPMSuperclassPolicy1,ON_STATE);
399 }
400
401
402
403
404 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
405
406 #undef super
407 #define super IOService
408
409 OSDefineMetaClassAndStructors(IORootParent, IOService)
410
411 #define number_of_patriarch_power_states 3
412
413 static IOPMPowerState patriarchPowerStates[number_of_patriarch_power_states] = {
414 {1,0,0,0,0,0,0,0,0,0,0,0}, // off
415 {1,0,SLEEP_POWER,0,0,0,0,0,0,0,0,0}, // sleep
416 {1,0,ON_POWER,0,0,0,0,0,0,0,0,0} // running
417 };
418
419 #define PATRIARCH_OFF 0
420 #define PATRIARCH_SLEEP 1
421 #define PATRIARCH_ON 2
422
423
424 bool IORootParent::start ( IOService * nub )
425 {
426 super::start(nub);
427 PMinit();
428 registerPowerDriver(this,patriarchPowerStates,number_of_patriarch_power_states);
429 powerOverrideOnPriv();
430 return true;
431 }
432
433
434 void IORootParent::shutDownSystem ( void )
435 {
436 changePowerStateToPriv(PATRIARCH_OFF);
437 }
438
439
440 void IORootParent::sleepSystem ( void )
441 {
442 changePowerStateToPriv(PATRIARCH_SLEEP);
443 }
444
445
446 void IORootParent::wakeSystem ( void )
447 {
448 changePowerStateToPriv(PATRIARCH_ON);
449 }
450