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		pt_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
pt_battery_mod_lookup(void)67 pt_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
pt_battery_print(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 pt_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 pt_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 = pt_battery_stat_snapshot()) < 0)
104 			pt_error("battery kstat not found (%d)\n", err);
105 	}
106 
107 	pt_display_acpi_power(battery_state.exist, battery_state.present_rate,
108 	    battery_state.remain_cap, battery_state.last_cap,
109 	    battery_state.bst_state);
110 }
111 
112 static int
pt_battery_stat_snapshot(void)113 pt_battery_stat_snapshot(void)
114 {
115 	kstat_ctl_t	*kc;
116 	kstat_t		*ksp;
117 	kstat_named_t	*knp;
118 
119 	kc = kstat_open();
120 
121 	/*
122 	 * power unit:
123 	 * 	0 - Capacity information is reported in [mWh] and
124 	 *	    charge/discharge rate information in [mW]
125 	 *	1 - Capacity information is reported in [mAh] and
126 	 *	    charge/discharge rate information in [mA].
127 	 */
128 	ksp = kstat_lookup(kc, kstat_batt_mod[kstat_batt_idx], 0,
129 	    "battery BIF0");
130 
131 	if (ksp == NULL) {
132 		(void) kstat_close(kc);
133 		return (-1);
134 	}
135 
136 	(void) kstat_read(kc, ksp, NULL);
137 	knp = kstat_data_lookup(ksp, "bif_unit");
138 
139 	if (knp == NULL) {
140 		(void) kstat_close(kc);
141 		return (-1);
142 	}
143 
144 	battery_state.power_unit = knp->value.ui32;
145 
146 	/*
147 	 * Present rate:
148 	 *	the power or current being supplied or accepted
149 	 *	through the battery's terminal
150 	 */
151 	ksp = kstat_lookup(kc, kstat_batt_mod[kstat_batt_idx], 0,
152 	    "battery BST0");
153 
154 	if (ksp == NULL) {
155 		(void) kstat_close(kc);
156 		return (-1);
157 	}
158 
159 	(void) kstat_read(kc, ksp, NULL);
160 	knp = kstat_data_lookup(ksp, "bst_rate");
161 
162 	if (knp == NULL) {
163 		(void) kstat_close(kc);
164 		return (-1);
165 	}
166 
167 	if (knp->value.ui32 == 0xFFFFFFFF)
168 		battery_state.present_rate = 0;
169 	else {
170 		battery_state.exist = 1;
171 		battery_state.present_rate = mW2W((double)(knp->value.ui32));
172 	}
173 
174 	/*
175 	 * Last Full charge capacity:
176 	 *	Predicted battery capacity when fully charged.
177 	 */
178 	ksp = kstat_lookup(kc, kstat_batt_mod[kstat_batt_idx], 0,
179 	    "battery BIF0");
180 
181 	if (ksp == NULL) {
182 		(void) kstat_close(kc);
183 		return (-1);
184 	}
185 
186 	(void) kstat_read(kc, ksp, NULL);
187 	knp = kstat_data_lookup(ksp, "bif_last_cap");
188 
189 	if (knp == NULL) {
190 		(void) kstat_close(kc);
191 		return (-1);
192 	}
193 
194 	battery_state.last_cap = mW2W((double)(knp->value.ui32));
195 
196 	/*
197 	 * Remaining capacity:
198 	 *	the estimated remaining battery capacity
199 	 */
200 	ksp = kstat_lookup(kc, kstat_batt_mod[kstat_batt_idx], 0,
201 	    "battery BST0");
202 
203 	if (ksp == NULL) {
204 		(void) kstat_close(kc);
205 		return (-1);
206 	}
207 
208 	(void) kstat_read(kc, ksp, NULL);
209 	knp = kstat_data_lookup(ksp, "bst_rem_cap");
210 
211 	if (knp == NULL) {
212 		(void) kstat_close(kc);
213 		return (-1);
214 	}
215 
216 	battery_state.remain_cap = mW2W((double)(knp->value.ui32));
217 
218 	/*
219 	 * Battery State:
220 	 *	Bit0 - 1 : discharging
221 	 *	Bit1 - 1 : charging
222 	 *	Bit2 - 1 : critical energy state
223 	 */
224 	ksp = kstat_lookup(kc, kstat_batt_mod[kstat_batt_idx], 0,
225 	    "battery BST0");
226 
227 	if (ksp == NULL) {
228 		(void) kstat_close(kc);
229 		return (-1);
230 	}
231 
232 	(void) kstat_read(kc, ksp, NULL);
233 	knp = kstat_data_lookup(ksp, "bst_state");
234 
235 	if (knp == NULL) {
236 		(void) kstat_close(kc);
237 		return (-1);
238 	}
239 
240 	battery_state.bst_state = knp->value.ui32;
241 
242 	(void) kstat_close(kc);
243 
244 	return (0);
245 }
246