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