xref: /illumos-gate/usr/src/cmd/powertop/common/battery.c (revision b47b5b34b42fa8056577c43496cdb99a4c99f8d7)
1*b47b5b34SRafael Vanoni /*
2*b47b5b34SRafael Vanoni  * Copyright 2009, Intel Corporation
3*b47b5b34SRafael Vanoni  * Copyright 2009, Sun Microsystems, Inc
4*b47b5b34SRafael Vanoni  *
5*b47b5b34SRafael Vanoni  * This file is part of PowerTOP
6*b47b5b34SRafael Vanoni  *
7*b47b5b34SRafael Vanoni  * This program file is free software; you can redistribute it and/or modify it
8*b47b5b34SRafael Vanoni  * under the terms of the GNU General Public License as published by the
9*b47b5b34SRafael Vanoni  * Free Software Foundation; version 2 of the License.
10*b47b5b34SRafael Vanoni  *
11*b47b5b34SRafael Vanoni  * This program is distributed in the hope that it will be useful, but WITHOUT
12*b47b5b34SRafael Vanoni  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13*b47b5b34SRafael Vanoni  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14*b47b5b34SRafael Vanoni  * for more details.
15*b47b5b34SRafael Vanoni  *
16*b47b5b34SRafael Vanoni  * You should have received a copy of the GNU General Public License
17*b47b5b34SRafael Vanoni  * along with this program in a file named COPYING; if not, write to the
18*b47b5b34SRafael Vanoni  * Free Software Foundation, Inc.,
19*b47b5b34SRafael Vanoni  * 51 Franklin Street, Fifth Floor,
20*b47b5b34SRafael Vanoni  * Boston, MA 02110-1301 USA
21*b47b5b34SRafael Vanoni  *
22*b47b5b34SRafael Vanoni  * Authors:
23*b47b5b34SRafael Vanoni  *	Arjan van de Ven <arjan@linux.intel.com>
24*b47b5b34SRafael Vanoni  *	Eric C Saxe <eric.saxe@sun.com>
25*b47b5b34SRafael Vanoni  *	Aubrey Li <aubrey.li@intel.com>
26*b47b5b34SRafael Vanoni  */
27*b47b5b34SRafael Vanoni 
28*b47b5b34SRafael Vanoni /*
29*b47b5b34SRafael Vanoni  * GPL Disclaimer
30*b47b5b34SRafael Vanoni  *
31*b47b5b34SRafael Vanoni  * For the avoidance of doubt, except that if any license choice other
32*b47b5b34SRafael Vanoni  * than GPL or LGPL is available it will apply instead, Sun elects to
33*b47b5b34SRafael Vanoni  * use only the General Public License version 2 (GPLv2) at this time
34*b47b5b34SRafael Vanoni  * for any software where a choice of GPL license versions is made
35*b47b5b34SRafael Vanoni  * available with the language indicating that GPLv2 or any later
36*b47b5b34SRafael Vanoni  * version may be used, or where a choice of which version of the GPL
37*b47b5b34SRafael Vanoni  * is applied is otherwise unspecified.
38*b47b5b34SRafael Vanoni  */
39*b47b5b34SRafael Vanoni 
40*b47b5b34SRafael Vanoni #include <string.h>
41*b47b5b34SRafael Vanoni #include <kstat.h>
42*b47b5b34SRafael Vanoni #include <errno.h>
43*b47b5b34SRafael Vanoni #include "powertop.h"
44*b47b5b34SRafael Vanoni 
45*b47b5b34SRafael Vanoni #define	mW2W(value)	((value) / 1000)
46*b47b5b34SRafael Vanoni 
47*b47b5b34SRafael Vanoni typedef struct battery_state {
48*b47b5b34SRafael Vanoni 	uint32_t exist;
49*b47b5b34SRafael Vanoni 	uint32_t power_unit;
50*b47b5b34SRafael Vanoni 	uint32_t bst_state;
51*b47b5b34SRafael Vanoni 	double present_rate;
52*b47b5b34SRafael Vanoni 	double remain_cap;
53*b47b5b34SRafael Vanoni 	double last_cap;
54*b47b5b34SRafael Vanoni } battery_state_t;
55*b47b5b34SRafael Vanoni 
56*b47b5b34SRafael Vanoni static char		*kstat_batt_mod[3] = {NULL, "battery", "acpi_drv"};
57*b47b5b34SRafael Vanoni static uint_t		kstat_batt_idx;
58*b47b5b34SRafael Vanoni static battery_state_t	battery_state;
59*b47b5b34SRafael Vanoni 
60*b47b5b34SRafael Vanoni static int		battery_stat_snapshot(void);
61*b47b5b34SRafael Vanoni 
62*b47b5b34SRafael Vanoni /*
63*b47b5b34SRafael Vanoni  * Checks if the kstat module for battery information is present and
64*b47b5b34SRafael Vanoni  * whether it's called 'battery' or 'acpi_drv'
65*b47b5b34SRafael Vanoni  */
66*b47b5b34SRafael Vanoni void
67*b47b5b34SRafael Vanoni battery_mod_lookup(void)
68*b47b5b34SRafael Vanoni {
69*b47b5b34SRafael Vanoni 	kstat_ctl_t *kc = kstat_open();
70*b47b5b34SRafael Vanoni 
71*b47b5b34SRafael Vanoni 	if (kstat_lookup(kc, kstat_batt_mod[1], 0, NULL))
72*b47b5b34SRafael Vanoni 		kstat_batt_idx = 1;
73*b47b5b34SRafael Vanoni 	else
74*b47b5b34SRafael Vanoni 		if (kstat_lookup(kc, kstat_batt_mod[2], 0, NULL))
75*b47b5b34SRafael Vanoni 			kstat_batt_idx = 2;
76*b47b5b34SRafael Vanoni 		else
77*b47b5b34SRafael Vanoni 			kstat_batt_idx = 0;
78*b47b5b34SRafael Vanoni 
79*b47b5b34SRafael Vanoni 	(void) kstat_close(kc);
80*b47b5b34SRafael Vanoni }
81*b47b5b34SRafael Vanoni 
82*b47b5b34SRafael Vanoni void
83*b47b5b34SRafael Vanoni print_battery(void)
84*b47b5b34SRafael Vanoni {
85*b47b5b34SRafael Vanoni 	int err;
86*b47b5b34SRafael Vanoni 
87*b47b5b34SRafael Vanoni 	(void) memset(&battery_state, 0, sizeof (battery_state_t));
88*b47b5b34SRafael Vanoni 
89*b47b5b34SRafael Vanoni 	/*
90*b47b5b34SRafael Vanoni 	 * The return value of battery_stat_snapshot() can be used for
91*b47b5b34SRafael Vanoni 	 * debug or to show/hide the acpi power line. We currently don't
92*b47b5b34SRafael Vanoni 	 * make the distinction of a system that runs only on AC and one
93*b47b5b34SRafael Vanoni 	 * that runs on battery but has no kstat battery info.
94*b47b5b34SRafael Vanoni 	 *
95*b47b5b34SRafael Vanoni 	 * We still display the estimate power usage for systems
96*b47b5b34SRafael Vanoni 	 * running on AC with a fully charged battery because some
97*b47b5b34SRafael Vanoni 	 * batteries may still consume power.
98*b47b5b34SRafael Vanoni 	 *
99*b47b5b34SRafael Vanoni 	 * If battery_mod_lookup() didn't find a kstat battery module, don't
100*b47b5b34SRafael Vanoni 	 * bother trying to take the snapshot
101*b47b5b34SRafael Vanoni 	 */
102*b47b5b34SRafael Vanoni 	if (kstat_batt_idx > 0) {
103*b47b5b34SRafael Vanoni 		if ((err = battery_stat_snapshot()) < 0)
104*b47b5b34SRafael Vanoni 			pt_error("%s : battery kstat not found %d\n", __FILE__,
105*b47b5b34SRafael Vanoni 			    err);
106*b47b5b34SRafael Vanoni 	}
107*b47b5b34SRafael Vanoni 
108*b47b5b34SRafael Vanoni 	show_acpi_power_line(battery_state.exist, battery_state.present_rate,
109*b47b5b34SRafael Vanoni 	    battery_state.remain_cap, battery_state.last_cap,
110*b47b5b34SRafael Vanoni 	    battery_state.bst_state);
111*b47b5b34SRafael Vanoni }
112*b47b5b34SRafael Vanoni 
113*b47b5b34SRafael Vanoni static int
114*b47b5b34SRafael Vanoni battery_stat_snapshot(void)
115*b47b5b34SRafael Vanoni {
116*b47b5b34SRafael Vanoni 	kstat_ctl_t	*kc;
117*b47b5b34SRafael Vanoni 	kstat_t		*ksp;
118*b47b5b34SRafael Vanoni 	kstat_named_t	*knp;
119*b47b5b34SRafael Vanoni 
120*b47b5b34SRafael Vanoni 	kc = kstat_open();
121*b47b5b34SRafael Vanoni 
122*b47b5b34SRafael Vanoni 	/*
123*b47b5b34SRafael Vanoni 	 * power unit:
124*b47b5b34SRafael Vanoni 	 * 	0 - Capacity information is reported in [mWh] and
125*b47b5b34SRafael Vanoni 	 *	    charge/discharge rate information in [mW]
126*b47b5b34SRafael Vanoni 	 *	1 - Capacity information is reported in [mAh] and
127*b47b5b34SRafael Vanoni 	 *	    charge/discharge rate information in [mA].
128*b47b5b34SRafael Vanoni 	 */
129*b47b5b34SRafael Vanoni 	ksp = kstat_lookup(kc, kstat_batt_mod[kstat_batt_idx], 0,
130*b47b5b34SRafael Vanoni 	    "battery BIF0");
131*b47b5b34SRafael Vanoni 
132*b47b5b34SRafael Vanoni 	if (ksp == NULL) {
133*b47b5b34SRafael Vanoni 		(void) kstat_close(kc);
134*b47b5b34SRafael Vanoni 		return (-1);
135*b47b5b34SRafael Vanoni 	}
136*b47b5b34SRafael Vanoni 
137*b47b5b34SRafael Vanoni 	(void) kstat_read(kc, ksp, NULL);
138*b47b5b34SRafael Vanoni 	knp = kstat_data_lookup(ksp, "bif_unit");
139*b47b5b34SRafael Vanoni 
140*b47b5b34SRafael Vanoni 	if (knp == NULL) {
141*b47b5b34SRafael Vanoni 		(void) kstat_close(kc);
142*b47b5b34SRafael Vanoni 		return (-1);
143*b47b5b34SRafael Vanoni 	}
144*b47b5b34SRafael Vanoni 
145*b47b5b34SRafael Vanoni 	battery_state.power_unit = knp->value.ui32;
146*b47b5b34SRafael Vanoni 
147*b47b5b34SRafael Vanoni 	/*
148*b47b5b34SRafael Vanoni 	 * Present rate:
149*b47b5b34SRafael Vanoni 	 *	the power or current being supplied or accepted
150*b47b5b34SRafael Vanoni 	 *	through the battery's terminal
151*b47b5b34SRafael Vanoni 	 */
152*b47b5b34SRafael Vanoni 	ksp = kstat_lookup(kc, kstat_batt_mod[kstat_batt_idx], 0,
153*b47b5b34SRafael Vanoni 	    "battery BST0");
154*b47b5b34SRafael Vanoni 
155*b47b5b34SRafael Vanoni 	if (ksp == NULL) {
156*b47b5b34SRafael Vanoni 		(void) kstat_close(kc);
157*b47b5b34SRafael Vanoni 		return (-1);
158*b47b5b34SRafael Vanoni 	}
159*b47b5b34SRafael Vanoni 
160*b47b5b34SRafael Vanoni 	(void) kstat_read(kc, ksp, NULL);
161*b47b5b34SRafael Vanoni 	knp = kstat_data_lookup(ksp, "bst_rate");
162*b47b5b34SRafael Vanoni 
163*b47b5b34SRafael Vanoni 	if (knp == NULL) {
164*b47b5b34SRafael Vanoni 		(void) kstat_close(kc);
165*b47b5b34SRafael Vanoni 		return (-1);
166*b47b5b34SRafael Vanoni 	}
167*b47b5b34SRafael Vanoni 
168*b47b5b34SRafael Vanoni 	if (knp->value.ui32 == 0xFFFFFFFF)
169*b47b5b34SRafael Vanoni 		battery_state.present_rate = 0;
170*b47b5b34SRafael Vanoni 	else {
171*b47b5b34SRafael Vanoni 		battery_state.exist = 1;
172*b47b5b34SRafael Vanoni 		battery_state.present_rate = mW2W((double)(knp->value.ui32));
173*b47b5b34SRafael Vanoni 	}
174*b47b5b34SRafael Vanoni 
175*b47b5b34SRafael Vanoni 	/*
176*b47b5b34SRafael Vanoni 	 * Last Full charge capacity:
177*b47b5b34SRafael Vanoni 	 *	Predicted battery capacity when fully charged.
178*b47b5b34SRafael Vanoni 	 */
179*b47b5b34SRafael Vanoni 	ksp = kstat_lookup(kc, kstat_batt_mod[kstat_batt_idx], 0,
180*b47b5b34SRafael Vanoni 	    "battery BIF0");
181*b47b5b34SRafael Vanoni 
182*b47b5b34SRafael Vanoni 	if (ksp == NULL) {
183*b47b5b34SRafael Vanoni 		(void) kstat_close(kc);
184*b47b5b34SRafael Vanoni 		return (-1);
185*b47b5b34SRafael Vanoni 	}
186*b47b5b34SRafael Vanoni 
187*b47b5b34SRafael Vanoni 	(void) kstat_read(kc, ksp, NULL);
188*b47b5b34SRafael Vanoni 	knp = kstat_data_lookup(ksp, "bif_last_cap");
189*b47b5b34SRafael Vanoni 
190*b47b5b34SRafael Vanoni 	if (knp == NULL) {
191*b47b5b34SRafael Vanoni 		(void) kstat_close(kc);
192*b47b5b34SRafael Vanoni 		return (-1);
193*b47b5b34SRafael Vanoni 	}
194*b47b5b34SRafael Vanoni 
195*b47b5b34SRafael Vanoni 	battery_state.last_cap = mW2W((double)(knp->value.ui32));
196*b47b5b34SRafael Vanoni 
197*b47b5b34SRafael Vanoni 	/*
198*b47b5b34SRafael Vanoni 	 * Remaining capacity:
199*b47b5b34SRafael Vanoni 	 *	the estimated remaining battery capacity
200*b47b5b34SRafael Vanoni 	 */
201*b47b5b34SRafael Vanoni 	ksp = kstat_lookup(kc, kstat_batt_mod[kstat_batt_idx], 0,
202*b47b5b34SRafael Vanoni 	    "battery BST0");
203*b47b5b34SRafael Vanoni 
204*b47b5b34SRafael Vanoni 	if (ksp == NULL) {
205*b47b5b34SRafael Vanoni 		(void) kstat_close(kc);
206*b47b5b34SRafael Vanoni 		return (-1);
207*b47b5b34SRafael Vanoni 	}
208*b47b5b34SRafael Vanoni 
209*b47b5b34SRafael Vanoni 	(void) kstat_read(kc, ksp, NULL);
210*b47b5b34SRafael Vanoni 	knp = kstat_data_lookup(ksp, "bst_rem_cap");
211*b47b5b34SRafael Vanoni 
212*b47b5b34SRafael Vanoni 	if (knp == NULL) {
213*b47b5b34SRafael Vanoni 		(void) kstat_close(kc);
214*b47b5b34SRafael Vanoni 		return (-1);
215*b47b5b34SRafael Vanoni 	}
216*b47b5b34SRafael Vanoni 
217*b47b5b34SRafael Vanoni 	battery_state.remain_cap = mW2W((double)(knp->value.ui32));
218*b47b5b34SRafael Vanoni 
219*b47b5b34SRafael Vanoni 	/*
220*b47b5b34SRafael Vanoni 	 * Battery State:
221*b47b5b34SRafael Vanoni 	 *	Bit0 - 1 : discharging
222*b47b5b34SRafael Vanoni 	 *	Bit1 - 1 : charging
223*b47b5b34SRafael Vanoni 	 *	Bit2 - 1 : critical energy state
224*b47b5b34SRafael Vanoni 	 */
225*b47b5b34SRafael Vanoni 	ksp = kstat_lookup(kc, kstat_batt_mod[kstat_batt_idx], 0,
226*b47b5b34SRafael Vanoni 	    "battery BST0");
227*b47b5b34SRafael Vanoni 
228*b47b5b34SRafael Vanoni 	if (ksp == NULL) {
229*b47b5b34SRafael Vanoni 		(void) kstat_close(kc);
230*b47b5b34SRafael Vanoni 		return (-1);
231*b47b5b34SRafael Vanoni 	}
232*b47b5b34SRafael Vanoni 
233*b47b5b34SRafael Vanoni 	(void) kstat_read(kc, ksp, NULL);
234*b47b5b34SRafael Vanoni 	knp = kstat_data_lookup(ksp, "bst_state");
235*b47b5b34SRafael Vanoni 
236*b47b5b34SRafael Vanoni 	if (knp == NULL) {
237*b47b5b34SRafael Vanoni 		(void) kstat_close(kc);
238*b47b5b34SRafael Vanoni 		return (-1);
239*b47b5b34SRafael Vanoni 	}
240*b47b5b34SRafael Vanoni 
241*b47b5b34SRafael Vanoni 	battery_state.bst_state = knp->value.ui32;
242*b47b5b34SRafael Vanoni 
243*b47b5b34SRafael Vanoni 	(void) kstat_close(kc);
244*b47b5b34SRafael Vanoni 
245*b47b5b34SRafael Vanoni 	return (0);
246*b47b5b34SRafael Vanoni }
247