]> git.saurik.com Git - apple/security.git/blob - libsecurity_utilities/lib/powerwatch.cpp
f1ab95249917aa1eb0d8560352921d2b95fcb956
[apple/security.git] / libsecurity_utilities / lib / powerwatch.cpp
1 /*
2 * Copyright (c) 2000-2004 Apple Computer, Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24
25 //
26 // powerwatch - hook into system notifications of power events
27 //
28 #include "powerwatch.h"
29 #include <IOKit/IOMessage.h>
30
31
32 namespace Security {
33 namespace MachPlusPlus {
34
35
36 //
37 // The obligatory empty virtual destructor
38 //
39 PowerWatcher::~PowerWatcher()
40 { }
41
42
43 //
44 // The default NULL implementations of the callback virtuals.
45 // We define these (rather than leaving them abstract) since
46 // many users want only one of these events.
47 //
48 void PowerWatcher::systemWillSleep()
49 { }
50
51 void PowerWatcher::systemIsWaking()
52 { }
53
54 void PowerWatcher::systemWillPowerDown()
55 { }
56
57 void PowerWatcher::systemWillPowerOn()
58 { }
59
60 //
61 // IOPowerWatchers
62 //
63
64 void
65 IOPowerWatcher::iopmcallback(void * param,
66 IOPMConnection connection,
67 IOPMConnectionMessageToken token,
68 IOPMSystemPowerStateCapabilities capabilities)
69 {
70 IOPowerWatcher *me = (IOPowerWatcher *)param;
71
72 if (SECURITY_DEBUG_LOG_ENABLED()) {
73 secdebug("powerwatch", "powerstates");
74 if (capabilities & kIOPMSystemPowerStateCapabilityDisk)
75 secdebug("powerwatch", "disk");
76 if (capabilities & kIOPMSystemPowerStateCapabilityNetwork)
77 secdebug("powerwatch", "net");
78 if (capabilities & kIOPMSystemPowerStateCapabilityAudio)
79 secdebug("powerwatch", "audio");
80 if (capabilities & kIOPMSystemPowerStateCapabilityVideo)
81 secdebug("powerwatch", "video");
82 }
83
84 /* if cpu and no display -> in DarkWake */
85 if ((capabilities & (kIOPMSystemPowerStateCapabilityCPU|kIOPMSystemPowerStateCapabilityVideo)) == kIOPMSystemPowerStateCapabilityCPU) {
86 secdebug("powerwatch", "enter DarkWake");
87 me->mInDarkWake = true;
88 } else if (me->mInDarkWake) {
89 secdebug("powerwatch", "exit DarkWake");
90 me->mInDarkWake = false;
91 }
92
93 (void)IOPMConnectionAcknowledgeEvent(connection, token);
94
95 return;
96 }
97
98
99 void
100 IOPowerWatcher::setupDarkWake()
101 {
102 IOReturn ret;
103
104 mInDarkWake = false;
105
106 mIOPMqueue = dispatch_queue_create("com.apple.security.IOPowerWatcher", NULL);
107 if (mIOPMqueue == NULL)
108 return;
109
110 ret = ::IOPMConnectionCreate(CFSTR("IOPowerWatcher"),
111 kIOPMSystemPowerStateCapabilityDisk
112 | kIOPMSystemPowerStateCapabilityNetwork
113 | kIOPMSystemPowerStateCapabilityAudio
114 | kIOPMSystemPowerStateCapabilityVideo,
115 &mIOPMconn);
116 if (ret != kIOReturnSuccess)
117 return;
118
119 ret = ::IOPMConnectionSetNotification(mIOPMconn, this,
120 (IOPMEventHandlerType)iopmcallback);
121 if (ret != kIOReturnSuccess)
122 return;
123
124 ::IOPMConnectionSetDispatchQueue(mIOPMconn, mIOPMqueue);
125 }
126
127 IOPowerWatcher::IOPowerWatcher()
128 {
129 if (!(mKernelPort = ::IORegisterForSystemPower(this, &mPortRef, ioCallback, &mHandle)))
130 UnixError::throwMe(EINVAL); // no clue
131
132 setupDarkWake();
133 }
134
135 IOPowerWatcher::~IOPowerWatcher()
136 {
137 if (mKernelPort)
138 ::IODeregisterForSystemPower(&mHandle);
139
140 if (mIOPMconn) {
141 ::IOPMConnectionSetDispatchQueue(mIOPMconn, NULL);
142 ::IOPMConnectionRelease(mIOPMconn);
143 }
144 if (mIOPMqueue)
145 ::dispatch_release(mIOPMqueue);
146 }
147
148
149 //
150 // The callback dispatcher
151 //
152 void IOPowerWatcher::ioCallback(void *refCon, io_service_t service,
153 natural_t messageType, void *argument)
154 {
155 IOPowerWatcher *me = (IOPowerWatcher *)refCon;
156 enum { allow, refuse, ignore } reaction;
157 switch (messageType) {
158 case kIOMessageSystemWillSleep:
159 secdebug("powerwatch", "system will sleep");
160 me->systemWillSleep();
161 reaction = allow;
162 break;
163 case kIOMessageSystemHasPoweredOn:
164 secdebug("powerwatch", "system has powered on");
165 me->systemIsWaking();
166 reaction = ignore;
167 break;
168 case kIOMessageSystemWillPowerOff:
169 secdebug("powerwatch", "system will power off");
170 me->systemWillPowerDown();
171 reaction = allow;
172 break;
173 case kIOMessageSystemWillNotPowerOff:
174 secdebug("powerwatch", "system will not power off");
175 reaction = ignore;
176 break;
177 case kIOMessageCanSystemSleep:
178 secdebug("powerwatch", "can system sleep");
179 reaction = allow;
180 break;
181 case kIOMessageSystemWillNotSleep:
182 secdebug("powerwatch", "system will not sleep");
183 reaction = ignore;
184 break;
185 case kIOMessageCanSystemPowerOff:
186 secdebug("powerwatch", "can system power off");
187 reaction = allow;
188 break;
189 case kIOMessageSystemWillPowerOn:
190 secdebug("powerwatch", "system will power on");
191 me->systemWillPowerOn();
192 reaction = ignore;
193 break;
194 default:
195 secdebug("powerwatch",
196 "type 0x%x message received (ignored)", messageType);
197 reaction = ignore;
198 break;
199 }
200
201 // handle acknowledgments
202 switch (reaction) {
203 case allow:
204 secdebug("powerwatch", "calling IOAllowPowerChange");
205 IOAllowPowerChange(me->mKernelPort, long(argument));
206 break;
207 case refuse:
208 secdebug("powerwatch", "calling IOCancelPowerChange");
209 IOCancelPowerChange(me->mKernelPort, long(argument));
210 break;
211 case ignore:
212 secdebug("powerwatch", "sending no response");
213 break;
214 }
215 }
216
217
218 //
219 // The MachServer hookup
220 //
221 PortPowerWatcher::PortPowerWatcher()
222 {
223 port(IONotificationPortGetMachPort(mPortRef));
224 }
225
226 boolean_t PortPowerWatcher::handle(mach_msg_header_t *in)
227 {
228 IODispatchCalloutFromMessage(NULL, in, mPortRef);
229 return TRUE;
230 }
231
232
233 } // end namespace MachPlusPlus
234
235 } // end namespace Security