]> git.saurik.com Git - apple/xnu.git/blame - iokit/Drivers/platform/drvAppleRootDomain/RootDomain.cpp
xnu-124.13.tar.gz
[apple/xnu.git] / iokit / Drivers / platform / drvAppleRootDomain / RootDomain.cpp
CommitLineData
1c79356b
A
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
31extern "C" {
32extern void kprintf(const char *, ...);
33}
34
35extern const IORegistryPlane * gIOPowerPlane;
36
37void PMreceiveCmd ( OSObject *, void *, void *, void *, void * );
38bool 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
49static 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
55static IOPMrootDomain * gRootDomain;
56
57#define super IOService
58OSDefineMetaClassAndStructors(IOPMrootDomain,IOService)
59
60extern "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// **********************************************************************************
81bool 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//*********************************************************************************
131IOReturn 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// **********************************************************************************
144void 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
172IOReturn 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// **********************************************************************************
187IOReturn 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// **********************************************************************************
205void 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// **********************************************************************************
221IOReturn 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
249IOReturn 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
301void 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
321IOOptionBits 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
334bool 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
350bool 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
369void 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
384void 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
396bool 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
409OSDefineMetaClassAndStructors(IORootParent, IOService)
410
411#define number_of_patriarch_power_states 3
412
413static 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
424bool 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
434void IORootParent::shutDownSystem ( void )
435{
436 changePowerStateToPriv(PATRIARCH_OFF);
437}
438
439
440void IORootParent::sleepSystem ( void )
441{
442 changePowerStateToPriv(PATRIARCH_SLEEP);
443}
444
445
446void IORootParent::wakeSystem ( void )
447{
448 changePowerStateToPriv(PATRIARCH_ON);
449}
450