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