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