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
36OSDefineMetaClassAndStructors(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
45IOPMPowerSource *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// *****************************************************************************
60bool 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// *****************************************************************************
99void 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// *****************************************************************************
129void 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
165void IOPMPowerSource::setPSProperty(const OSSymbol *key, OSObject *val)
166{
167    OSObject    *lastVal;
168
169    if(!key || !val) return;
170
171    // Compare new setting with existing setting; update
172    // 'settingsChangedSinceUpdate' if the setting has changed.
173    // If values are OSNumbers, do equality comparison.
174    // Otherwise, just compare pointers.
175
176    if( (lastVal = properties->getObject(key)) ) {
177	if(val->isEqualTo(lastVal)) {
178	    // settings didn't change
179	} else {
180	    // num val is not equal to last val
181	    settingsChangedSinceUpdate = true;
182	}
183    } else {
184        // new setting; no last value
185        settingsChangedSinceUpdate = true;
186    }
187
188    // here's the part where we go crazy.
189    properties->setObject(key, val);
190}
191
192
193
194void IOPMPowerSource::setExternalConnected(bool b) {
195    setPSProperty(externalConnectedKey,
196            b ? kOSBooleanTrue : kOSBooleanFalse);
197}
198
199void IOPMPowerSource::setExternalChargeCapable(bool b) {
200    setPSProperty(externalChargeCapableKey,
201            b ? kOSBooleanTrue : kOSBooleanFalse);
202}
203
204void IOPMPowerSource::setBatteryInstalled(bool b) {
205    setPSProperty(batteryInstalledKey,
206            b ? kOSBooleanTrue : kOSBooleanFalse);
207}
208
209void IOPMPowerSource::setIsCharging(bool b) {
210    setPSProperty(chargingKey,
211            b ? kOSBooleanTrue : kOSBooleanFalse);
212}
213
214void IOPMPowerSource::setAtWarnLevel(bool b) {
215    setPSProperty(warnLevelKey,
216            b ? kOSBooleanTrue : kOSBooleanFalse);
217}
218
219void IOPMPowerSource::setAtCriticalLevel(bool b) {
220    setPSProperty(criticalLevelKey,
221            b ? kOSBooleanTrue : kOSBooleanFalse);
222}
223
224
225void IOPMPowerSource::setCurrentCapacity(unsigned int val) {
226    OSNumber *n = OSNumber::withNumber(val, 32);
227    setPSProperty(currentCapacityKey, n);
228    n->release();
229}
230
231void IOPMPowerSource::setMaxCapacity(unsigned int val) {
232    OSNumber *n = OSNumber::withNumber(val, 32);
233    setPSProperty(maxCapacityKey, n);
234    n->release();
235}
236
237void IOPMPowerSource::setTimeRemaining(int val) {
238    OSNumber *n = OSNumber::withNumber(val, 32);
239    setPSProperty(timeRemainingKey, n);
240    n->release();
241}
242
243void IOPMPowerSource::setAmperage(int val) {
244    OSNumber *n = OSNumber::withNumber(val, 32);
245    setPSProperty(amperageKey, n);
246    n->release();
247}
248
249void IOPMPowerSource::setVoltage(unsigned int val) {
250    OSNumber *n = OSNumber::withNumber(val, 32);
251    setPSProperty(voltageKey, n);
252    n->release();
253}
254
255void IOPMPowerSource::setCycleCount(unsigned int val) {
256    OSNumber *n = OSNumber::withNumber(val, 32);
257    setPSProperty(cycleCountKey, n);
258    n->release();
259}
260
261void IOPMPowerSource::setAdapterInfo(int val) {
262    OSNumber *n = OSNumber::withNumber(val, 32);
263    setPSProperty(adapterInfoKey, n);
264    n->release();
265}
266
267void IOPMPowerSource::setLocation(int val) {
268    OSNumber *n = OSNumber::withNumber(val, 32);
269    setPSProperty(locationKey, n);
270    n->release();
271}
272
273void IOPMPowerSource::setErrorCondition(OSSymbol *s) {
274    setPSProperty(errorConditionKey, s);
275}
276
277void IOPMPowerSource::setManufacturer(OSSymbol *s) {
278    setPSProperty(manufacturerKey, s);
279}
280
281void IOPMPowerSource::setModel(OSSymbol *s) {
282    setPSProperty(modelKey, s);
283}
284
285void IOPMPowerSource::setSerial(OSSymbol *s) {
286    setPSProperty(serialKey, s);
287}
288
289void IOPMPowerSource::setLegacyIOBatteryInfo(OSDictionary *d) {
290    setPSProperty(batteryInfoKey, d);
291}
292
293
294
295
296/*******************************************************************************
297 *
298 * PUBLIC Accessors. All the getters! Boo!
299 *
300 ******************************************************************************/
301
302OSObject *IOPMPowerSource::getPSProperty(const OSSymbol *symmie) {
303    if(!symmie) return NULL;
304    return properties->getObject(symmie);
305}
306
307bool IOPMPowerSource::externalConnected(void) {
308    return (kOSBooleanTrue == properties->getObject(externalConnectedKey));
309}
310
311bool IOPMPowerSource::externalChargeCapable(void) {
312    return (kOSBooleanTrue == properties->getObject(externalChargeCapableKey));
313}
314
315bool IOPMPowerSource::batteryInstalled(void) {
316    return (kOSBooleanTrue == properties->getObject(batteryInstalledKey));
317}
318
319bool IOPMPowerSource::isCharging(void) {
320    return (kOSBooleanTrue == properties->getObject(chargingKey));
321}
322
323bool IOPMPowerSource::atWarnLevel(void) {
324    return (kOSBooleanTrue == properties->getObject(warnLevelKey));
325}
326
327bool IOPMPowerSource::atCriticalLevel(void) {
328    return (kOSBooleanTrue == properties->getObject(criticalLevelKey));
329}
330
331unsigned int IOPMPowerSource::currentCapacity(void) {
332    OSNumber        *n;
333    n = OSDynamicCast(OSNumber, properties->getObject(currentCapacityKey));
334    if(!n) return 0;
335    else return (unsigned int)n->unsigned32BitValue();
336}
337
338unsigned int IOPMPowerSource::maxCapacity(void) {
339    OSNumber        *n;
340    n = OSDynamicCast(OSNumber, properties->getObject(maxCapacityKey));
341    if(!n) return 0;
342    else return (unsigned int)n->unsigned32BitValue();
343}
344
345unsigned int IOPMPowerSource::capacityPercentRemaining(void)
346{
347    unsigned int _currentCapacity = currentCapacity();
348    unsigned int _maxCapacity = maxCapacity();
349    if(0 == _maxCapacity) {
350        return 0;
351    } else {
352        return ((100*_currentCapacity) / _maxCapacity);
353    }
354}
355
356int IOPMPowerSource::timeRemaining(void) {
357    OSNumber        *n;
358    n = OSDynamicCast(OSNumber, properties->getObject(timeRemainingKey));
359    if(!n) return 0;
360    else return (int)n->unsigned32BitValue();
361}
362
363int IOPMPowerSource::amperage(void) {
364    OSNumber        *n;
365    n = OSDynamicCast(OSNumber, properties->getObject(amperageKey));
366    if(!n) return 0;
367    else return (int)n->unsigned32BitValue();
368}
369
370unsigned int IOPMPowerSource::voltage(void) {
371    OSNumber        *n;
372    n = OSDynamicCast(OSNumber, properties->getObject(voltageKey));
373    if(!n) return 0;
374    else return (unsigned int)n->unsigned32BitValue();
375}
376
377unsigned int IOPMPowerSource::cycleCount(void) {
378    OSNumber        *n;
379    n = OSDynamicCast(OSNumber, properties->getObject(cycleCountKey));
380    if(!n) return 0;
381    else return (unsigned int)n->unsigned32BitValue();
382}
383
384int IOPMPowerSource::adapterInfo(void) {
385    OSNumber        *n;
386    n = OSDynamicCast(OSNumber, properties->getObject(adapterInfoKey));
387    if(!n) return 0;
388    else return (int)n->unsigned32BitValue();
389}
390
391int IOPMPowerSource::location(void) {
392    OSNumber        *n;
393    n = OSDynamicCast(OSNumber, properties->getObject(locationKey));
394    if(!n) return 0;
395    else return (unsigned int)n->unsigned32BitValue();
396}
397
398OSSymbol *IOPMPowerSource::errorCondition(void) {
399    return OSDynamicCast(OSSymbol, properties->getObject(errorConditionKey));
400}
401
402OSSymbol *IOPMPowerSource::manufacturer(void) {
403    return OSDynamicCast(OSSymbol, properties->getObject(manufacturerKey));
404}
405
406OSSymbol *IOPMPowerSource::model(void) {
407    return OSDynamicCast(OSSymbol, properties->getObject(modelKey));
408}
409
410OSSymbol *IOPMPowerSource::serial(void) {
411    return OSDynamicCast(OSSymbol, properties->getObject(serialKey));
412}
413
414OSDictionary *IOPMPowerSource::legacyIOBatteryInfo(void) {
415    return OSDynamicCast(OSDictionary, properties->getObject(batteryInfoKey));
416}
417