1 /*
2  * Copyright (c) 1998-2005 Apple Computer, Inc. All rights reserved.
3  *
4  * @APPLE_OSREFERENCE_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. The rights granted to you under the License
10  * may not be used to create, or enable the creation or redistribution of,
11  * unlawful or unlicensed copies of an Apple operating system, or to
12  * circumvent, violate, or enable the circumvention or violation of, any
13  * terms of an Apple operating system software license agreement.
14  *
15  * Please obtain a copy of the License at
16  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17  *
18  * The Original Code and all software distributed under the License are
19  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23  * Please see the License for the specific language governing rights and
24  * limitations under the License.
25  *
26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27  */
28 
29 #include <IOKit/pwr_mgt/IOPMPowerSource.h>
30 #include <IOKit/pwr_mgt/IOPM.h>
31 #include <IOKit/IOMessage.h>
32 #include <IOKit/IOLib.h>
33 
34 #define super IOService
35 
36 OSDefineMetaClassAndStructors(IOPMPowerSource, IOService)
37 
38 // *****************************************************************************
39 // powerSource
40 //
41 // Static initializer for IOPMPowerSource. Returns a new instance of the class
42 // which the caller must attach to the power plane.
43 // *****************************************************************************
44 
45 IOPMPowerSource *IOPMPowerSource::powerSource(void)
46 {
47     IOPMPowerSource *ps = new IOPMPowerSource;
48 
49     if(ps) {
50         ps->init();
51         return ps;
52     }
53     return NULL;
54 }
55 
56 // *****************************************************************************
57 // init
58 //
59 // *****************************************************************************
60 bool IOPMPowerSource::init (void)
61 {
62     if (!super::init()) {
63         return false;
64     }
65 
66     nextInList = NULL;
67 
68     properties = OSDictionary::withCapacity(10);
69     if(!properties) return false;
70     properties->setCapacityIncrement(1);
71 
72     externalConnectedKey = OSSymbol::withCString(kIOPMPSExternalConnectedKey);
73     externalChargeCapableKey = OSSymbol::withCString(kIOPMPSExternalChargeCapableKey);
74     batteryInstalledKey = OSSymbol::withCString(kIOPMPSBatteryInstalledKey);
75     chargingKey = OSSymbol::withCString(kIOPMPSIsChargingKey);
76     warnLevelKey = OSSymbol::withCString(kIOPMPSAtWarnLevelKey);
77     criticalLevelKey = OSSymbol::withCString(kIOPMPSAtCriticalLevelKey);
78     currentCapacityKey = OSSymbol::withCString(kIOPMPSCurrentCapacityKey);
79     maxCapacityKey = OSSymbol::withCString(kIOPMPSMaxCapacityKey);
80     timeRemainingKey = OSSymbol::withCString(kIOPMPSTimeRemainingKey);
81     amperageKey = OSSymbol::withCString(kIOPMPSAmperageKey);
82     voltageKey = OSSymbol::withCString(kIOPMPSVoltageKey);
83     cycleCountKey = OSSymbol::withCString(kIOPMPSCycleCountKey);
84     adapterInfoKey = OSSymbol::withCString(kIOPMPSAdapterInfoKey);
85     locationKey = OSSymbol::withCString(kIOPMPSLocationKey);
86     errorConditionKey = OSSymbol::withCString(kIOPMPSErrorConditionKey);
87     manufacturerKey = OSSymbol::withCString(kIOPMPSManufacturerKey);
88     modelKey = OSSymbol::withCString(kIOPMPSModelKey);
89     serialKey = OSSymbol::withCString(kIOPMPSSerialKey);
90     batteryInfoKey = OSSymbol::withCString(kIOPMPSLegacyBatteryInfoKey);
91 
92     return true;
93 }
94 
95 // *****************************************************************************
96 // free
97 //
98 // *****************************************************************************
99 void IOPMPowerSource::free(void)
100 {
101     if(properties) properties->release();
102     if(externalConnectedKey) externalConnectedKey->release();
103     if(externalChargeCapableKey) externalChargeCapableKey->release();
104     if(batteryInstalledKey) batteryInstalledKey->release();
105     if(chargingKey) chargingKey->release();
106     if(warnLevelKey) warnLevelKey->release();
107     if(criticalLevelKey) criticalLevelKey->release();
108     if(currentCapacityKey) currentCapacityKey->release();
109     if(maxCapacityKey) maxCapacityKey->release();
110     if(timeRemainingKey) timeRemainingKey->release();
111     if(amperageKey) amperageKey->release();
112     if(voltageKey) voltageKey->release();
113     if(cycleCountKey) cycleCountKey->release();
114     if(adapterInfoKey) adapterInfoKey->release();
115     if(errorConditionKey) errorConditionKey->release();
116     if(manufacturerKey) manufacturerKey->release();
117     if(modelKey) modelKey->release();
118     if(serialKey) serialKey->release();
119     if(locationKey) locationKey->release();
120     if(batteryInfoKey) batteryInfoKey->release();
121 }
122 
123 // *****************************************************************************
124 // updateStatus
125 //
126 // Update power source state in IORegistry and message interested clients
127 // notifying them of our change.
128 // *****************************************************************************
129 void IOPMPowerSource::updateStatus (void)
130 {
131     OSCollectionIterator            *iterator;
132     OSObject                        *iteratorKey;
133     OSObject                        *obj;
134 
135     // do nothing if settings haven't changed
136     if(!settingsChangedSinceUpdate) return;
137 
138     iterator = OSCollectionIterator::withCollection(properties);
139     if(!iterator) return;
140 
141     while ((iteratorKey = iterator->getNextObject())) {
142         OSSymbol *key;
143 
144         key = OSDynamicCast(OSSymbol, iteratorKey);
145         if (!key) continue;
146         obj = properties->getObject(key);
147         if(!obj) continue;
148         setProperty(key, obj);
149     }
150     iterator->release();
151 
152     settingsChangedSinceUpdate = false;
153 
154     // And up goes the flare
155     messageClients(kIOPMMessageBatteryStatusHasChanged);
156 }
157 
158 
159 /*******************************************************************************
160  *
161  * PROTECTED Accessors. All the setters! Yay!
162  *
163  ******************************************************************************/
164 
165 void IOPMPowerSource::setPSProperty(const OSSymbol *key, OSObject *val)
166 {
167     OSObject    *lastVal;
168     OSNumber    *newNumVal;
169 
170     if(!key || !val) return;
171 
172     // Compare new setting with existing setting; update
173     // 'settingsChangedSinceUpdate' if the setting has changed.
174     // If values are OSNumbers, do equality comparison.
175     // Otherwise, just compare pointers.
176 
177     if( (lastVal = properties->getObject(key)) ) {
178         newNumVal = OSDynamicCast(OSNumber, val);
179         if(newNumVal) {
180             if(newNumVal->isEqualTo(lastVal)) {
181                 // settings didn't change
182             } else {
183                 // num val is not equal to last val
184                 settingsChangedSinceUpdate = true;
185             }
186         } else {
187             // pointer compare as last resort
188             if(lastVal != val)
189                 settingsChangedSinceUpdate = true;
190         }
191     } else {
192         // new setting; no last value
193         settingsChangedSinceUpdate = true;
194     }
195 
196     // here's the part where we go crazy.
197     properties->setObject(key, val);
198 }
199 
200 
201 
202 void IOPMPowerSource::setExternalConnected(bool b) {
203     setPSProperty(externalConnectedKey,
204             b ? kOSBooleanTrue : kOSBooleanFalse);
205 }
206 
207 void IOPMPowerSource::setExternalChargeCapable(bool b) {
208     setPSProperty(externalChargeCapableKey,
209             b ? kOSBooleanTrue : kOSBooleanFalse);
210 }
211 
212 void IOPMPowerSource::setBatteryInstalled(bool b) {
213     setPSProperty(batteryInstalledKey,
214             b ? kOSBooleanTrue : kOSBooleanFalse);
215 }
216 
217 void IOPMPowerSource::setIsCharging(bool b) {
218     setPSProperty(chargingKey,
219             b ? kOSBooleanTrue : kOSBooleanFalse);
220 }
221 
222 void IOPMPowerSource::setAtWarnLevel(bool b) {
223     setPSProperty(warnLevelKey,
224             b ? kOSBooleanTrue : kOSBooleanFalse);
225 }
226 
227 void IOPMPowerSource::setAtCriticalLevel(bool b) {
228     setPSProperty(criticalLevelKey,
229             b ? kOSBooleanTrue : kOSBooleanFalse);
230 }
231 
232 
233 void IOPMPowerSource::setCurrentCapacity(unsigned int val) {
234     OSNumber *n = OSNumber::withNumber(val, 32);
235     setPSProperty(currentCapacityKey, n);
236     n->release();
237 }
238 
239 void IOPMPowerSource::setMaxCapacity(unsigned int val) {
240     OSNumber *n = OSNumber::withNumber(val, 32);
241     setPSProperty(maxCapacityKey, n);
242     n->release();
243 }
244 
245 void IOPMPowerSource::setTimeRemaining(int val) {
246     OSNumber *n = OSNumber::withNumber(val, 32);
247     setPSProperty(timeRemainingKey, n);
248     n->release();
249 }
250 
251 void IOPMPowerSource::setAmperage(int val) {
252     OSNumber *n = OSNumber::withNumber(val, 32);
253     setPSProperty(amperageKey, n);
254     n->release();
255 }
256 
257 void IOPMPowerSource::setVoltage(unsigned int val) {
258     OSNumber *n = OSNumber::withNumber(val, 32);
259     setPSProperty(voltageKey, n);
260     n->release();
261 }
262 
263 void IOPMPowerSource::setCycleCount(unsigned int val) {
264     OSNumber *n = OSNumber::withNumber(val, 32);
265     setPSProperty(cycleCountKey, n);
266     n->release();
267 }
268 
269 void IOPMPowerSource::setAdapterInfo(int val) {
270     OSNumber *n = OSNumber::withNumber(val, 32);
271     setPSProperty(adapterInfoKey, n);
272     n->release();
273 }
274 
275 void IOPMPowerSource::setLocation(int val) {
276     OSNumber *n = OSNumber::withNumber(val, 32);
277     setPSProperty(locationKey, n);
278     n->release();
279 }
280 
281 void IOPMPowerSource::setErrorCondition(OSSymbol *s) {
282     setPSProperty(errorConditionKey, s);
283 }
284 
285 void IOPMPowerSource::setManufacturer(OSSymbol *s) {
286     setPSProperty(manufacturerKey, s);
287 }
288 
289 void IOPMPowerSource::setModel(OSSymbol *s) {
290     setPSProperty(modelKey, s);
291 }
292 
293 void IOPMPowerSource::setSerial(OSSymbol *s) {
294     setPSProperty(serialKey, s);
295 }
296 
297 void IOPMPowerSource::setLegacyIOBatteryInfo(OSDictionary *d) {
298     setPSProperty(batteryInfoKey, d);
299 }
300 
301 
302 
303 
304 /*******************************************************************************
305  *
306  * PUBLIC Accessors. All the getters! Boo!
307  *
308  ******************************************************************************/
309 
310 OSObject *IOPMPowerSource::getPSProperty(const OSSymbol *symmie) {
311     if(!symmie) return NULL;
312     return properties->getObject(symmie);
313 }
314 
315 bool IOPMPowerSource::externalConnected(void) {
316     return (kOSBooleanTrue == properties->getObject(externalConnectedKey));
317 }
318 
319 bool IOPMPowerSource::externalChargeCapable(void) {
320     return (kOSBooleanTrue == properties->getObject(externalChargeCapableKey));
321 }
322 
323 bool IOPMPowerSource::batteryInstalled(void) {
324     return (kOSBooleanTrue == properties->getObject(batteryInstalledKey));
325 }
326 
327 bool IOPMPowerSource::isCharging(void) {
328     return (kOSBooleanTrue == properties->getObject(chargingKey));
329 }
330 
331 bool IOPMPowerSource::atWarnLevel(void) {
332     return (kOSBooleanTrue == properties->getObject(warnLevelKey));
333 }
334 
335 bool IOPMPowerSource::atCriticalLevel(void) {
336     return (kOSBooleanTrue == properties->getObject(criticalLevelKey));
337 }
338 
339 unsigned int IOPMPowerSource::currentCapacity(void) {
340     OSNumber        *n;
341     n = OSDynamicCast(OSNumber, properties->getObject(currentCapacityKey));
342     if(!n) return 0;
343     else return (unsigned int)n->unsigned32BitValue();
344 }
345 
346 unsigned int IOPMPowerSource::maxCapacity(void) {
347     OSNumber        *n;
348     n = OSDynamicCast(OSNumber, properties->getObject(maxCapacityKey));
349     if(!n) return 0;
350     else return (unsigned int)n->unsigned32BitValue();
351 }
352 
353 unsigned int IOPMPowerSource::capacityPercentRemaining(void)
354 {
355     unsigned int _currentCapacity = currentCapacity();
356     unsigned int _maxCapacity = maxCapacity();
357     if(0 == _maxCapacity) {
358         return 0;
359     } else {
360         return ((100*_currentCapacity) / _maxCapacity);
361     }
362 }
363 
364 int IOPMPowerSource::timeRemaining(void) {
365     OSNumber        *n;
366     n = OSDynamicCast(OSNumber, properties->getObject(timeRemainingKey));
367     if(!n) return 0;
368     else return (int)n->unsigned32BitValue();
369 }
370 
371 int IOPMPowerSource::amperage(void) {
372     OSNumber        *n;
373     n = OSDynamicCast(OSNumber, properties->getObject(amperageKey));
374     if(!n) return 0;
375     else return (int)n->unsigned32BitValue();
376 }
377 
378 unsigned int IOPMPowerSource::voltage(void) {
379     OSNumber        *n;
380     n = OSDynamicCast(OSNumber, properties->getObject(voltageKey));
381     if(!n) return 0;
382     else return (unsigned int)n->unsigned32BitValue();
383 }
384 
385 unsigned int IOPMPowerSource::cycleCount(void) {
386     OSNumber        *n;
387     n = OSDynamicCast(OSNumber, properties->getObject(cycleCountKey));
388     if(!n) return 0;
389     else return (unsigned int)n->unsigned32BitValue();
390 }
391 
392 int IOPMPowerSource::adapterInfo(void) {
393     OSNumber        *n;
394     n = OSDynamicCast(OSNumber, properties->getObject(adapterInfoKey));
395     if(!n) return 0;
396     else return (int)n->unsigned32BitValue();
397 }
398 
399 int IOPMPowerSource::location(void) {
400     OSNumber        *n;
401     n = OSDynamicCast(OSNumber, properties->getObject(locationKey));
402     if(!n) return 0;
403     else return (unsigned int)n->unsigned32BitValue();
404 }
405 
406 OSSymbol *IOPMPowerSource::errorCondition(void) {
407     return OSDynamicCast(OSSymbol, properties->getObject(errorConditionKey));
408 }
409 
410 OSSymbol *IOPMPowerSource::manufacturer(void) {
411     return OSDynamicCast(OSSymbol, properties->getObject(manufacturerKey));
412 }
413 
414 OSSymbol *IOPMPowerSource::model(void) {
415     return OSDynamicCast(OSSymbol, properties->getObject(modelKey));
416 }
417 
418 OSSymbol *IOPMPowerSource::serial(void) {
419     return OSDynamicCast(OSSymbol, properties->getObject(serialKey));
420 }
421 
422 OSDictionary *IOPMPowerSource::legacyIOBatteryInfo(void) {
423     return OSDynamicCast(OSDictionary, properties->getObject(batteryInfoKey));
424 }
425