xref: /onnv-gate/usr/src/cmd/powertop/common/battery.c (revision 11122:393b5ac48d9b)
19338Srafael.vanoni@sun.com /*
29338Srafael.vanoni@sun.com  * Copyright 2009, Intel Corporation
39338Srafael.vanoni@sun.com  * Copyright 2009, Sun Microsystems, Inc
49338Srafael.vanoni@sun.com  *
59338Srafael.vanoni@sun.com  * This file is part of PowerTOP
69338Srafael.vanoni@sun.com  *
79338Srafael.vanoni@sun.com  * This program file is free software; you can redistribute it and/or modify it
89338Srafael.vanoni@sun.com  * under the terms of the GNU General Public License as published by the
99338Srafael.vanoni@sun.com  * Free Software Foundation; version 2 of the License.
109338Srafael.vanoni@sun.com  *
119338Srafael.vanoni@sun.com  * This program is distributed in the hope that it will be useful, but WITHOUT
129338Srafael.vanoni@sun.com  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
139338Srafael.vanoni@sun.com  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
149338Srafael.vanoni@sun.com  * for more details.
159338Srafael.vanoni@sun.com  *
169338Srafael.vanoni@sun.com  * You should have received a copy of the GNU General Public License
179338Srafael.vanoni@sun.com  * along with this program in a file named COPYING; if not, write to the
189338Srafael.vanoni@sun.com  * Free Software Foundation, Inc.,
199338Srafael.vanoni@sun.com  * 51 Franklin Street, Fifth Floor,
209338Srafael.vanoni@sun.com  * Boston, MA 02110-1301 USA
219338Srafael.vanoni@sun.com  *
229338Srafael.vanoni@sun.com  * Authors:
239338Srafael.vanoni@sun.com  *	Arjan van de Ven <arjan@linux.intel.com>
249338Srafael.vanoni@sun.com  *	Eric C Saxe <eric.saxe@sun.com>
259338Srafael.vanoni@sun.com  *	Aubrey Li <aubrey.li@intel.com>
269338Srafael.vanoni@sun.com  */
279338Srafael.vanoni@sun.com 
289338Srafael.vanoni@sun.com /*
299338Srafael.vanoni@sun.com  * GPL Disclaimer
309338Srafael.vanoni@sun.com  *
319338Srafael.vanoni@sun.com  * For the avoidance of doubt, except that if any license choice other
329338Srafael.vanoni@sun.com  * than GPL or LGPL is available it will apply instead, Sun elects to
339338Srafael.vanoni@sun.com  * use only the General Public License version 2 (GPLv2) at this time
349338Srafael.vanoni@sun.com  * for any software where a choice of GPL license versions is made
359338Srafael.vanoni@sun.com  * available with the language indicating that GPLv2 or any later
369338Srafael.vanoni@sun.com  * version may be used, or where a choice of which version of the GPL
379338Srafael.vanoni@sun.com  * is applied is otherwise unspecified.
389338Srafael.vanoni@sun.com  */
399338Srafael.vanoni@sun.com 
409338Srafael.vanoni@sun.com #include <string.h>
419338Srafael.vanoni@sun.com #include <kstat.h>
429338Srafael.vanoni@sun.com #include <errno.h>
439338Srafael.vanoni@sun.com #include "powertop.h"
449338Srafael.vanoni@sun.com 
459338Srafael.vanoni@sun.com #define	mW2W(value)	((value) / 1000)
469338Srafael.vanoni@sun.com 
479338Srafael.vanoni@sun.com typedef struct battery_state {
489338Srafael.vanoni@sun.com 	uint32_t exist;
499338Srafael.vanoni@sun.com 	uint32_t power_unit;
509338Srafael.vanoni@sun.com 	uint32_t bst_state;
519338Srafael.vanoni@sun.com 	double present_rate;
529338Srafael.vanoni@sun.com 	double remain_cap;
539338Srafael.vanoni@sun.com 	double last_cap;
549338Srafael.vanoni@sun.com } battery_state_t;
559338Srafael.vanoni@sun.com 
569338Srafael.vanoni@sun.com static char		*kstat_batt_mod[3] = {NULL, "battery", "acpi_drv"};
579338Srafael.vanoni@sun.com static uint_t		kstat_batt_idx;
589338Srafael.vanoni@sun.com static battery_state_t	battery_state;
599338Srafael.vanoni@sun.com 
60*11122Srafael.vanoni@sun.com static int		pt_battery_stat_snapshot(void);
619338Srafael.vanoni@sun.com 
629338Srafael.vanoni@sun.com /*
639338Srafael.vanoni@sun.com  * Checks if the kstat module for battery information is present and
649338Srafael.vanoni@sun.com  * whether it's called 'battery' or 'acpi_drv'
659338Srafael.vanoni@sun.com  */
669338Srafael.vanoni@sun.com void
pt_battery_mod_lookup(void)67*11122Srafael.vanoni@sun.com pt_battery_mod_lookup(void)
689338Srafael.vanoni@sun.com {
699338Srafael.vanoni@sun.com 	kstat_ctl_t *kc = kstat_open();
709338Srafael.vanoni@sun.com 
719338Srafael.vanoni@sun.com 	if (kstat_lookup(kc, kstat_batt_mod[1], 0, NULL))
729338Srafael.vanoni@sun.com 		kstat_batt_idx = 1;
739338Srafael.vanoni@sun.com 	else
749338Srafael.vanoni@sun.com 		if (kstat_lookup(kc, kstat_batt_mod[2], 0, NULL))
759338Srafael.vanoni@sun.com 			kstat_batt_idx = 2;
769338Srafael.vanoni@sun.com 		else
779338Srafael.vanoni@sun.com 			kstat_batt_idx = 0;
789338Srafael.vanoni@sun.com 
799338Srafael.vanoni@sun.com 	(void) kstat_close(kc);
809338Srafael.vanoni@sun.com }
819338Srafael.vanoni@sun.com 
829338Srafael.vanoni@sun.com void
pt_battery_print(void)839908Srafael.vanoni@sun.com pt_battery_print(void)
849338Srafael.vanoni@sun.com {
859338Srafael.vanoni@sun.com 	int err;
869338Srafael.vanoni@sun.com 
879338Srafael.vanoni@sun.com 	(void) memset(&battery_state, 0, sizeof (battery_state_t));
889338Srafael.vanoni@sun.com 
899338Srafael.vanoni@sun.com 	/*
90*11122Srafael.vanoni@sun.com 	 * The return value of pt_battery_stat_snapshot() can be used for
919338Srafael.vanoni@sun.com 	 * debug or to show/hide the acpi power line. We currently don't
929338Srafael.vanoni@sun.com 	 * make the distinction of a system that runs only on AC and one
939338Srafael.vanoni@sun.com 	 * that runs on battery but has no kstat battery info.
949338Srafael.vanoni@sun.com 	 *
959338Srafael.vanoni@sun.com 	 * We still display the estimate power usage for systems
969338Srafael.vanoni@sun.com 	 * running on AC with a fully charged battery because some
979338Srafael.vanoni@sun.com 	 * batteries may still consume power.
989338Srafael.vanoni@sun.com 	 *
99*11122Srafael.vanoni@sun.com 	 * If pt_battery_mod_lookup() didn't find a kstat battery module, don't
1009338Srafael.vanoni@sun.com 	 * bother trying to take the snapshot
1019338Srafael.vanoni@sun.com 	 */
1029338Srafael.vanoni@sun.com 	if (kstat_batt_idx > 0) {
103*11122Srafael.vanoni@sun.com 		if ((err = pt_battery_stat_snapshot()) < 0)
104*11122Srafael.vanoni@sun.com 			pt_error("battery kstat not found (%d)\n", err);
1059338Srafael.vanoni@sun.com 	}
1069338Srafael.vanoni@sun.com 
1079908Srafael.vanoni@sun.com 	pt_display_acpi_power(battery_state.exist, battery_state.present_rate,
1089338Srafael.vanoni@sun.com 	    battery_state.remain_cap, battery_state.last_cap,
1099338Srafael.vanoni@sun.com 	    battery_state.bst_state);
1109338Srafael.vanoni@sun.com }
1119338Srafael.vanoni@sun.com 
1129338Srafael.vanoni@sun.com static int
pt_battery_stat_snapshot(void)113*11122Srafael.vanoni@sun.com pt_battery_stat_snapshot(void)
1149338Srafael.vanoni@sun.com {
1159338Srafael.vanoni@sun.com 	kstat_ctl_t	*kc;
1169338Srafael.vanoni@sun.com 	kstat_t		*ksp;
1179338Srafael.vanoni@sun.com 	kstat_named_t	*knp;
1189338Srafael.vanoni@sun.com 
1199338Srafael.vanoni@sun.com 	kc = kstat_open();
1209338Srafael.vanoni@sun.com 
1219338Srafael.vanoni@sun.com 	/*
1229338Srafael.vanoni@sun.com 	 * power unit:
1239338Srafael.vanoni@sun.com 	 * 	0 - Capacity information is reported in [mWh] and
1249338Srafael.vanoni@sun.com 	 *	    charge/discharge rate information in [mW]
1259338Srafael.vanoni@sun.com 	 *	1 - Capacity information is reported in [mAh] and
1269338Srafael.vanoni@sun.com 	 *	    charge/discharge rate information in [mA].
1279338Srafael.vanoni@sun.com 	 */
1289338Srafael.vanoni@sun.com 	ksp = kstat_lookup(kc, kstat_batt_mod[kstat_batt_idx], 0,
1299338Srafael.vanoni@sun.com 	    "battery BIF0");
1309338Srafael.vanoni@sun.com 
1319338Srafael.vanoni@sun.com 	if (ksp == NULL) {
1329338Srafael.vanoni@sun.com 		(void) kstat_close(kc);
1339338Srafael.vanoni@sun.com 		return (-1);
1349338Srafael.vanoni@sun.com 	}
1359338Srafael.vanoni@sun.com 
1369338Srafael.vanoni@sun.com 	(void) kstat_read(kc, ksp, NULL);
1379338Srafael.vanoni@sun.com 	knp = kstat_data_lookup(ksp, "bif_unit");
1389338Srafael.vanoni@sun.com 
1399338Srafael.vanoni@sun.com 	if (knp == NULL) {
1409338Srafael.vanoni@sun.com 		(void) kstat_close(kc);
1419338Srafael.vanoni@sun.com 		return (-1);
1429338Srafael.vanoni@sun.com 	}
1439338Srafael.vanoni@sun.com 
1449338Srafael.vanoni@sun.com 	battery_state.power_unit = knp->value.ui32;
1459338Srafael.vanoni@sun.com 
1469338Srafael.vanoni@sun.com 	/*
1479338Srafael.vanoni@sun.com 	 * Present rate:
1489338Srafael.vanoni@sun.com 	 *	the power or current being supplied or accepted
1499338Srafael.vanoni@sun.com 	 *	through the battery's terminal
1509338Srafael.vanoni@sun.com 	 */
1519338Srafael.vanoni@sun.com 	ksp = kstat_lookup(kc, kstat_batt_mod[kstat_batt_idx], 0,
1529338Srafael.vanoni@sun.com 	    "battery BST0");
1539338Srafael.vanoni@sun.com 
1549338Srafael.vanoni@sun.com 	if (ksp == NULL) {
1559338Srafael.vanoni@sun.com 		(void) kstat_close(kc);
1569338Srafael.vanoni@sun.com 		return (-1);
1579338Srafael.vanoni@sun.com 	}
1589338Srafael.vanoni@sun.com 
1599338Srafael.vanoni@sun.com 	(void) kstat_read(kc, ksp, NULL);
1609338Srafael.vanoni@sun.com 	knp = kstat_data_lookup(ksp, "bst_rate");
1619338Srafael.vanoni@sun.com 
1629338Srafael.vanoni@sun.com 	if (knp == NULL) {
1639338Srafael.vanoni@sun.com 		(void) kstat_close(kc);
1649338Srafael.vanoni@sun.com 		return (-1);
1659338Srafael.vanoni@sun.com 	}
1669338Srafael.vanoni@sun.com 
1679338Srafael.vanoni@sun.com 	if (knp->value.ui32 == 0xFFFFFFFF)
1689338Srafael.vanoni@sun.com 		battery_state.present_rate = 0;
1699338Srafael.vanoni@sun.com 	else {
1709338Srafael.vanoni@sun.com 		battery_state.exist = 1;
1719338Srafael.vanoni@sun.com 		battery_state.present_rate = mW2W((double)(knp->value.ui32));
1729338Srafael.vanoni@sun.com 	}
1739338Srafael.vanoni@sun.com 
1749338Srafael.vanoni@sun.com 	/*
1759338Srafael.vanoni@sun.com 	 * Last Full charge capacity:
1769338Srafael.vanoni@sun.com 	 *	Predicted battery capacity when fully charged.
1779338Srafael.vanoni@sun.com 	 */
1789338Srafael.vanoni@sun.com 	ksp = kstat_lookup(kc, kstat_batt_mod[kstat_batt_idx], 0,
1799338Srafael.vanoni@sun.com 	    "battery BIF0");
1809338Srafael.vanoni@sun.com 
1819338Srafael.vanoni@sun.com 	if (ksp == NULL) {
1829338Srafael.vanoni@sun.com 		(void) kstat_close(kc);
1839338Srafael.vanoni@sun.com 		return (-1);
1849338Srafael.vanoni@sun.com 	}
1859338Srafael.vanoni@sun.com 
1869338Srafael.vanoni@sun.com 	(void) kstat_read(kc, ksp, NULL);
1879338Srafael.vanoni@sun.com 	knp = kstat_data_lookup(ksp, "bif_last_cap");
1889338Srafael.vanoni@sun.com 
1899338Srafael.vanoni@sun.com 	if (knp == NULL) {
1909338Srafael.vanoni@sun.com 		(void) kstat_close(kc);
1919338Srafael.vanoni@sun.com 		return (-1);
1929338Srafael.vanoni@sun.com 	}
1939338Srafael.vanoni@sun.com 
1949338Srafael.vanoni@sun.com 	battery_state.last_cap = mW2W((double)(knp->value.ui32));
1959338Srafael.vanoni@sun.com 
1969338Srafael.vanoni@sun.com 	/*
1979338Srafael.vanoni@sun.com 	 * Remaining capacity:
1989338Srafael.vanoni@sun.com 	 *	the estimated remaining battery capacity
1999338Srafael.vanoni@sun.com 	 */
2009338Srafael.vanoni@sun.com 	ksp = kstat_lookup(kc, kstat_batt_mod[kstat_batt_idx], 0,
2019338Srafael.vanoni@sun.com 	    "battery BST0");
2029338Srafael.vanoni@sun.com 
2039338Srafael.vanoni@sun.com 	if (ksp == NULL) {
2049338Srafael.vanoni@sun.com 		(void) kstat_close(kc);
2059338Srafael.vanoni@sun.com 		return (-1);
2069338Srafael.vanoni@sun.com 	}
2079338Srafael.vanoni@sun.com 
2089338Srafael.vanoni@sun.com 	(void) kstat_read(kc, ksp, NULL);
2099338Srafael.vanoni@sun.com 	knp = kstat_data_lookup(ksp, "bst_rem_cap");
2109338Srafael.vanoni@sun.com 
2119338Srafael.vanoni@sun.com 	if (knp == NULL) {
2129338Srafael.vanoni@sun.com 		(void) kstat_close(kc);
2139338Srafael.vanoni@sun.com 		return (-1);
2149338Srafael.vanoni@sun.com 	}
2159338Srafael.vanoni@sun.com 
2169338Srafael.vanoni@sun.com 	battery_state.remain_cap = mW2W((double)(knp->value.ui32));
2179338Srafael.vanoni@sun.com 
2189338Srafael.vanoni@sun.com 	/*
2199338Srafael.vanoni@sun.com 	 * Battery State:
2209338Srafael.vanoni@sun.com 	 *	Bit0 - 1 : discharging
2219338Srafael.vanoni@sun.com 	 *	Bit1 - 1 : charging
2229338Srafael.vanoni@sun.com 	 *	Bit2 - 1 : critical energy state
2239338Srafael.vanoni@sun.com 	 */
2249338Srafael.vanoni@sun.com 	ksp = kstat_lookup(kc, kstat_batt_mod[kstat_batt_idx], 0,
2259338Srafael.vanoni@sun.com 	    "battery BST0");
2269338Srafael.vanoni@sun.com 
2279338Srafael.vanoni@sun.com 	if (ksp == NULL) {
2289338Srafael.vanoni@sun.com 		(void) kstat_close(kc);
2299338Srafael.vanoni@sun.com 		return (-1);
2309338Srafael.vanoni@sun.com 	}
2319338Srafael.vanoni@sun.com 
2329338Srafael.vanoni@sun.com 	(void) kstat_read(kc, ksp, NULL);
2339338Srafael.vanoni@sun.com 	knp = kstat_data_lookup(ksp, "bst_state");
2349338Srafael.vanoni@sun.com 
2359338Srafael.vanoni@sun.com 	if (knp == NULL) {
2369338Srafael.vanoni@sun.com 		(void) kstat_close(kc);
2379338Srafael.vanoni@sun.com 		return (-1);
2389338Srafael.vanoni@sun.com 	}
2399338Srafael.vanoni@sun.com 
2409338Srafael.vanoni@sun.com 	battery_state.bst_state = knp->value.ui32;
2419338Srafael.vanoni@sun.com 
2429338Srafael.vanoni@sun.com 	(void) kstat_close(kc);
2439338Srafael.vanoni@sun.com 
2449338Srafael.vanoni@sun.com 	return (0);
2459338Srafael.vanoni@sun.com }
246