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 #include <os/log.h>
34 
35 #define super IOService
36 
OSDefineMetaClassAndStructors(IOPMPowerSource,IOService)37 OSDefineMetaClassAndStructors(IOPMPowerSource, IOService)
38 
39 // *****************************************************************************
40 // powerSource
41 //
42 // Static initializer for IOPMPowerSource. Returns a new instance of the class
43 // which the caller must attach to the power plane.
44 // *****************************************************************************
45 
46 IOPMPowerSource *IOPMPowerSource::powerSource(void)
47 {
48 	IOPMPowerSource *ps = new IOPMPowerSource;
49 
50 	if (ps) {
51 		ps->init();
52 		return ps;
53 	}
54 	return NULL;
55 }
56 
57 // *****************************************************************************
58 // init
59 //
60 // *****************************************************************************
61 bool
init(void)62 IOPMPowerSource::init(void)
63 {
64 	if (!super::init()) {
65 		return false;
66 	}
67 
68 	nextInList = NULL;
69 
70 	properties = OSDictionary::withCapacity(10);
71 	if (!properties) {
72 		return false;
73 	}
74 	properties->setCapacityIncrement(1);
75 
76 	externalConnectedKey = OSSymbol::withCString(kIOPMPSExternalConnectedKey);
77 	externalChargeCapableKey = OSSymbol::withCString(kIOPMPSExternalChargeCapableKey);
78 	batteryInstalledKey = OSSymbol::withCString(kIOPMPSBatteryInstalledKey);
79 	chargingKey = OSSymbol::withCString(kIOPMPSIsChargingKey);
80 	warnLevelKey = OSSymbol::withCString(kIOPMPSAtWarnLevelKey);
81 	criticalLevelKey = OSSymbol::withCString(kIOPMPSAtCriticalLevelKey);
82 	currentCapacityKey = OSSymbol::withCString(kIOPMPSCurrentCapacityKey);
83 	maxCapacityKey = OSSymbol::withCString(kIOPMPSMaxCapacityKey);
84 	timeRemainingKey = OSSymbol::withCString(kIOPMPSTimeRemainingKey);
85 	amperageKey = OSSymbol::withCString(kIOPMPSAmperageKey);
86 	voltageKey = OSSymbol::withCString(kIOPMPSVoltageKey);
87 	cycleCountKey = OSSymbol::withCString(kIOPMPSCycleCountKey);
88 	adapterInfoKey = OSSymbol::withCString(kIOPMPSAdapterInfoKey);
89 	locationKey = OSSymbol::withCString(kIOPMPSLocationKey);
90 	errorConditionKey = OSSymbol::withCString(kIOPMPSErrorConditionKey);
91 	manufacturerKey = OSSymbol::withCString(kIOPMPSManufacturerKey);
92 	modelKey = OSSymbol::withCString(kIOPMPSModelKey);
93 	serialKey = OSSymbol::withCString(kIOPMPSSerialKey);
94 	batteryInfoKey = OSSymbol::withCString(kIOPMPSLegacyBatteryInfoKey);
95 
96 	return true;
97 }
98 
99 // *****************************************************************************
100 // free
101 //
102 // *****************************************************************************
103 void
free(void)104 IOPMPowerSource::free(void)
105 {
106 	if (properties) {
107 		properties->release();
108 	}
109 	if (externalConnectedKey) {
110 		externalConnectedKey->release();
111 	}
112 	if (externalChargeCapableKey) {
113 		externalChargeCapableKey->release();
114 	}
115 	if (batteryInstalledKey) {
116 		batteryInstalledKey->release();
117 	}
118 	if (chargingKey) {
119 		chargingKey->release();
120 	}
121 	if (warnLevelKey) {
122 		warnLevelKey->release();
123 	}
124 	if (criticalLevelKey) {
125 		criticalLevelKey->release();
126 	}
127 	if (currentCapacityKey) {
128 		currentCapacityKey->release();
129 	}
130 	if (maxCapacityKey) {
131 		maxCapacityKey->release();
132 	}
133 	if (timeRemainingKey) {
134 		timeRemainingKey->release();
135 	}
136 	if (amperageKey) {
137 		amperageKey->release();
138 	}
139 	if (voltageKey) {
140 		voltageKey->release();
141 	}
142 	if (cycleCountKey) {
143 		cycleCountKey->release();
144 	}
145 	if (adapterInfoKey) {
146 		adapterInfoKey->release();
147 	}
148 	if (errorConditionKey) {
149 		errorConditionKey->release();
150 	}
151 	if (manufacturerKey) {
152 		manufacturerKey->release();
153 	}
154 	if (modelKey) {
155 		modelKey->release();
156 	}
157 	if (serialKey) {
158 		serialKey->release();
159 	}
160 	if (locationKey) {
161 		locationKey->release();
162 	}
163 	if (batteryInfoKey) {
164 		batteryInfoKey->release();
165 	}
166 
167 	super::free();
168 }
169 
170 // *****************************************************************************
171 // updateStatus
172 //
173 // Update power source state in IORegistry and message interested clients
174 // notifying them of our change.
175 // *****************************************************************************
176 void
updateStatus(void)177 IOPMPowerSource::updateStatus(void)
178 {
179 	OSCollectionIterator            *iterator;
180 	OSObject                        *iteratorKey;
181 	OSObject                        *obj;
182 
183 	// do nothing if settings haven't changed
184 	if (!settingsChangedSinceUpdate) {
185 		return;
186 	}
187 
188 	iterator = OSCollectionIterator::withCollection(properties);
189 	if (!iterator) {
190 		return;
191 	}
192 
193 	while ((iteratorKey = iterator->getNextObject())) {
194 		OSSymbol *key;
195 
196 		key = OSDynamicCast(OSSymbol, iteratorKey);
197 		if (!key) {
198 			continue;
199 		}
200 		obj = properties->getObject(key);
201 		if (!obj) {
202 			continue;
203 		}
204 		setProperty(key, obj);
205 	}
206 	iterator->release();
207 
208 	settingsChangedSinceUpdate = false;
209 
210 	// And up goes the flare
211 	IOMessage notifyMessage = kIOPMMessageBatteryStatusHasChanged;
212 #if DEVELOPMENT || DEBUG
213 	os_log(OS_LOG_DEFAULT, "notify clients '%u'\n", (unsigned int)notifyMessage);
214 #endif
215 	messageClients(notifyMessage);
216 }
217 
218 
219 /*******************************************************************************
220  *
221  * PROTECTED Accessors. All the setters! Yay!
222  *
223  ******************************************************************************/
224 
225 void
setPSProperty(const OSSymbol * key,OSObject * val)226 IOPMPowerSource::setPSProperty(const OSSymbol *key, OSObject *val)
227 {
228 	OSObject    *lastVal;
229 
230 	if (!key || !val) {
231 		return;
232 	}
233 
234 	// Compare new setting with existing setting; update
235 	// 'settingsChangedSinceUpdate' if the setting has changed.
236 	// If values are OSNumbers, do equality comparison.
237 	// Otherwise, just compare pointers.
238 
239 	if ((lastVal = properties->getObject(key))) {
240 		if (val->isEqualTo(lastVal)) {
241 			// settings didn't change
242 		} else {
243 			// num val is not equal to last val
244 			settingsChangedSinceUpdate = true;
245 		}
246 	} else {
247 		// new setting; no last value
248 		settingsChangedSinceUpdate = true;
249 	}
250 
251 	// here's the part where we go crazy.
252 	properties->setObject(key, val);
253 }
254 
255 
256 
257 void
setExternalConnected(bool b)258 IOPMPowerSource::setExternalConnected(bool b)
259 {
260 	setPSProperty(externalConnectedKey,
261 	    b ? kOSBooleanTrue : kOSBooleanFalse);
262 }
263 
264 void
setExternalChargeCapable(bool b)265 IOPMPowerSource::setExternalChargeCapable(bool b)
266 {
267 	setPSProperty(externalChargeCapableKey,
268 	    b ? kOSBooleanTrue : kOSBooleanFalse);
269 }
270 
271 void
setBatteryInstalled(bool b)272 IOPMPowerSource::setBatteryInstalled(bool b)
273 {
274 	setPSProperty(batteryInstalledKey,
275 	    b ? kOSBooleanTrue : kOSBooleanFalse);
276 }
277 
278 void
setIsCharging(bool b)279 IOPMPowerSource::setIsCharging(bool b)
280 {
281 	setPSProperty(chargingKey,
282 	    b ? kOSBooleanTrue : kOSBooleanFalse);
283 }
284 
285 void
setAtWarnLevel(bool b)286 IOPMPowerSource::setAtWarnLevel(bool b)
287 {
288 	setPSProperty(warnLevelKey,
289 	    b ? kOSBooleanTrue : kOSBooleanFalse);
290 }
291 
292 void
setAtCriticalLevel(bool b)293 IOPMPowerSource::setAtCriticalLevel(bool b)
294 {
295 	setPSProperty(criticalLevelKey,
296 	    b ? kOSBooleanTrue : kOSBooleanFalse);
297 }
298 
299 
300 void
setCurrentCapacity(unsigned int val)301 IOPMPowerSource::setCurrentCapacity(unsigned int val)
302 {
303 	OSNumber *n = OSNumber::withNumber(val, 32);
304 	setPSProperty(currentCapacityKey, n);
305 	n->release();
306 }
307 
308 void
setMaxCapacity(unsigned int val)309 IOPMPowerSource::setMaxCapacity(unsigned int val)
310 {
311 	OSNumber *n = OSNumber::withNumber(val, 32);
312 	setPSProperty(maxCapacityKey, n);
313 	n->release();
314 }
315 
316 void
setTimeRemaining(int val)317 IOPMPowerSource::setTimeRemaining(int val)
318 {
319 	OSNumber *n = OSNumber::withNumber(val, 32);
320 	setPSProperty(timeRemainingKey, n);
321 	n->release();
322 }
323 
324 void
setAmperage(int val)325 IOPMPowerSource::setAmperage(int val)
326 {
327 	OSNumber *n = OSNumber::withNumber(val, 32);
328 	setPSProperty(amperageKey, n);
329 	n->release();
330 }
331 
332 void
setVoltage(unsigned int val)333 IOPMPowerSource::setVoltage(unsigned int val)
334 {
335 	OSNumber *n = OSNumber::withNumber(val, 32);
336 	setPSProperty(voltageKey, n);
337 	n->release();
338 }
339 
340 void
setCycleCount(unsigned int val)341 IOPMPowerSource::setCycleCount(unsigned int val)
342 {
343 	OSNumber *n = OSNumber::withNumber(val, 32);
344 	setPSProperty(cycleCountKey, n);
345 	n->release();
346 }
347 
348 void
setAdapterInfo(int val)349 IOPMPowerSource::setAdapterInfo(int val)
350 {
351 	OSNumber *n = OSNumber::withNumber(val, 32);
352 	setPSProperty(adapterInfoKey, n);
353 	n->release();
354 }
355 
356 void
setLocation(int val)357 IOPMPowerSource::setLocation(int val)
358 {
359 	OSNumber *n = OSNumber::withNumber(val, 32);
360 	setPSProperty(locationKey, n);
361 	n->release();
362 }
363 
364 void
setErrorCondition(OSSymbol * s)365 IOPMPowerSource::setErrorCondition(OSSymbol *s)
366 {
367 	setPSProperty(errorConditionKey, s);
368 }
369 
370 void
setManufacturer(OSSymbol * s)371 IOPMPowerSource::setManufacturer(OSSymbol *s)
372 {
373 	setPSProperty(manufacturerKey, s);
374 }
375 
376 void
setModel(OSSymbol * s)377 IOPMPowerSource::setModel(OSSymbol *s)
378 {
379 	setPSProperty(modelKey, s);
380 }
381 
382 void
setSerial(OSSymbol * s)383 IOPMPowerSource::setSerial(OSSymbol *s)
384 {
385 	setPSProperty(serialKey, s);
386 }
387 
388 void
setLegacyIOBatteryInfo(OSDictionary * d)389 IOPMPowerSource::setLegacyIOBatteryInfo(OSDictionary *d)
390 {
391 	setPSProperty(batteryInfoKey, d);
392 }
393 
394 
395 
396 
397 /*******************************************************************************
398  *
399  * PUBLIC Accessors. All the getters! Boo!
400  *
401  ******************************************************************************/
402 
403 OSObject *
getPSProperty(const OSSymbol * symmie)404 IOPMPowerSource::getPSProperty(const OSSymbol *symmie)
405 {
406 	if (!symmie) {
407 		return NULL;
408 	}
409 	return properties->getObject(symmie);
410 }
411 
412 bool
externalConnected(void)413 IOPMPowerSource::externalConnected(void)
414 {
415 	return kOSBooleanTrue == properties->getObject(externalConnectedKey);
416 }
417 
418 bool
externalChargeCapable(void)419 IOPMPowerSource::externalChargeCapable(void)
420 {
421 	return kOSBooleanTrue == properties->getObject(externalChargeCapableKey);
422 }
423 
424 bool
batteryInstalled(void)425 IOPMPowerSource::batteryInstalled(void)
426 {
427 	return kOSBooleanTrue == properties->getObject(batteryInstalledKey);
428 }
429 
430 bool
isCharging(void)431 IOPMPowerSource::isCharging(void)
432 {
433 	return kOSBooleanTrue == properties->getObject(chargingKey);
434 }
435 
436 bool
atWarnLevel(void)437 IOPMPowerSource::atWarnLevel(void)
438 {
439 	return kOSBooleanTrue == properties->getObject(warnLevelKey);
440 }
441 
442 bool
atCriticalLevel(void)443 IOPMPowerSource::atCriticalLevel(void)
444 {
445 	return kOSBooleanTrue == properties->getObject(criticalLevelKey);
446 }
447 
448 unsigned int
currentCapacity(void)449 IOPMPowerSource::currentCapacity(void)
450 {
451 	OSNumber        *n;
452 	n = OSDynamicCast(OSNumber, properties->getObject(currentCapacityKey));
453 	if (!n) {
454 		return 0;
455 	} else {
456 		return (unsigned int)n->unsigned32BitValue();
457 	}
458 }
459 
460 unsigned int
maxCapacity(void)461 IOPMPowerSource::maxCapacity(void)
462 {
463 	OSNumber        *n;
464 	n = OSDynamicCast(OSNumber, properties->getObject(maxCapacityKey));
465 	if (!n) {
466 		return 0;
467 	} else {
468 		return (unsigned int)n->unsigned32BitValue();
469 	}
470 }
471 
472 unsigned int
capacityPercentRemaining(void)473 IOPMPowerSource::capacityPercentRemaining(void)
474 {
475 	unsigned int _currentCapacity = currentCapacity();
476 	unsigned int _maxCapacity = maxCapacity();
477 	if (0 == _maxCapacity) {
478 		return 0;
479 	} else {
480 		return (100 * _currentCapacity) / _maxCapacity;
481 	}
482 }
483 
484 int
timeRemaining(void)485 IOPMPowerSource::timeRemaining(void)
486 {
487 	OSNumber        *n;
488 	n = OSDynamicCast(OSNumber, properties->getObject(timeRemainingKey));
489 	if (!n) {
490 		return 0;
491 	} else {
492 		return (int)n->unsigned32BitValue();
493 	}
494 }
495 
496 int
amperage(void)497 IOPMPowerSource::amperage(void)
498 {
499 	OSNumber        *n;
500 	n = OSDynamicCast(OSNumber, properties->getObject(amperageKey));
501 	if (!n) {
502 		return 0;
503 	} else {
504 		return (int)n->unsigned32BitValue();
505 	}
506 }
507 
508 unsigned int
voltage(void)509 IOPMPowerSource::voltage(void)
510 {
511 	OSNumber        *n;
512 	n = OSDynamicCast(OSNumber, properties->getObject(voltageKey));
513 	if (!n) {
514 		return 0;
515 	} else {
516 		return (unsigned int)n->unsigned32BitValue();
517 	}
518 }
519 
520 unsigned int
cycleCount(void)521 IOPMPowerSource::cycleCount(void)
522 {
523 	OSNumber        *n;
524 	n = OSDynamicCast(OSNumber, properties->getObject(cycleCountKey));
525 	if (!n) {
526 		return 0;
527 	} else {
528 		return (unsigned int)n->unsigned32BitValue();
529 	}
530 }
531 
532 int
adapterInfo(void)533 IOPMPowerSource::adapterInfo(void)
534 {
535 	OSNumber        *n;
536 	n = OSDynamicCast(OSNumber, properties->getObject(adapterInfoKey));
537 	if (!n) {
538 		return 0;
539 	} else {
540 		return (int)n->unsigned32BitValue();
541 	}
542 }
543 
544 int
location(void)545 IOPMPowerSource::location(void)
546 {
547 	OSNumber        *n;
548 	n = OSDynamicCast(OSNumber, properties->getObject(locationKey));
549 	if (!n) {
550 		return 0;
551 	} else {
552 		return (unsigned int)n->unsigned32BitValue();
553 	}
554 }
555 
556 OSSymbol *
errorCondition(void)557 IOPMPowerSource::errorCondition(void)
558 {
559 	return OSDynamicCast(OSSymbol, properties->getObject(errorConditionKey));
560 }
561 
562 OSSymbol *
manufacturer(void)563 IOPMPowerSource::manufacturer(void)
564 {
565 	return OSDynamicCast(OSSymbol, properties->getObject(manufacturerKey));
566 }
567 
568 OSSymbol *
model(void)569 IOPMPowerSource::model(void)
570 {
571 	return OSDynamicCast(OSSymbol, properties->getObject(modelKey));
572 }
573 
574 OSSymbol *
serial(void)575 IOPMPowerSource::serial(void)
576 {
577 	return OSDynamicCast(OSSymbol, properties->getObject(serialKey));
578 }
579 
580 OSDictionary *
legacyIOBatteryInfo(void)581 IOPMPowerSource::legacyIOBatteryInfo(void)
582 {
583 	return OSDynamicCast(OSDictionary, properties->getObject(batteryInfoKey));
584 }
585