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