19338Srafael.vanoni@sun.com /*
29338Srafael.vanoni@sun.com * Copyright 2009, Intel Corporation
39338Srafael.vanoni@sun.com * Copyright 2009, Sun Microsystems, Inc
49338Srafael.vanoni@sun.com *
59338Srafael.vanoni@sun.com * This file is part of PowerTOP
69338Srafael.vanoni@sun.com *
79338Srafael.vanoni@sun.com * This program file is free software; you can redistribute it and/or modify it
89338Srafael.vanoni@sun.com * under the terms of the GNU General Public License as published by the
99338Srafael.vanoni@sun.com * Free Software Foundation; version 2 of the License.
109338Srafael.vanoni@sun.com *
119338Srafael.vanoni@sun.com * This program is distributed in the hope that it will be useful, but WITHOUT
129338Srafael.vanoni@sun.com * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
139338Srafael.vanoni@sun.com * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
149338Srafael.vanoni@sun.com * for more details.
159338Srafael.vanoni@sun.com *
169338Srafael.vanoni@sun.com * You should have received a copy of the GNU General Public License
179338Srafael.vanoni@sun.com * along with this program in a file named COPYING; if not, write to the
189338Srafael.vanoni@sun.com * Free Software Foundation, Inc.,
199338Srafael.vanoni@sun.com * 51 Franklin Street, Fifth Floor,
209338Srafael.vanoni@sun.com * Boston, MA 02110-1301 USA
219338Srafael.vanoni@sun.com *
229338Srafael.vanoni@sun.com * Authors:
239338Srafael.vanoni@sun.com * Arjan van de Ven <arjan@linux.intel.com>
249338Srafael.vanoni@sun.com * Eric C Saxe <eric.saxe@sun.com>
259338Srafael.vanoni@sun.com * Aubrey Li <aubrey.li@intel.com>
269338Srafael.vanoni@sun.com */
279338Srafael.vanoni@sun.com
289338Srafael.vanoni@sun.com /*
299338Srafael.vanoni@sun.com * GPL Disclaimer
309338Srafael.vanoni@sun.com *
319338Srafael.vanoni@sun.com * For the avoidance of doubt, except that if any license choice other
329338Srafael.vanoni@sun.com * than GPL or LGPL is available it will apply instead, Sun elects to
339338Srafael.vanoni@sun.com * use only the General Public License version 2 (GPLv2) at this time
349338Srafael.vanoni@sun.com * for any software where a choice of GPL license versions is made
359338Srafael.vanoni@sun.com * available with the language indicating that GPLv2 or any later
369338Srafael.vanoni@sun.com * version may be used, or where a choice of which version of the GPL
379338Srafael.vanoni@sun.com * is applied is otherwise unspecified.
389338Srafael.vanoni@sun.com */
399338Srafael.vanoni@sun.com
409338Srafael.vanoni@sun.com #include <string.h>
419338Srafael.vanoni@sun.com #include <kstat.h>
429338Srafael.vanoni@sun.com #include <errno.h>
439338Srafael.vanoni@sun.com #include "powertop.h"
449338Srafael.vanoni@sun.com
459338Srafael.vanoni@sun.com #define mW2W(value) ((value) / 1000)
469338Srafael.vanoni@sun.com
479338Srafael.vanoni@sun.com typedef struct battery_state {
489338Srafael.vanoni@sun.com uint32_t exist;
499338Srafael.vanoni@sun.com uint32_t power_unit;
509338Srafael.vanoni@sun.com uint32_t bst_state;
519338Srafael.vanoni@sun.com double present_rate;
529338Srafael.vanoni@sun.com double remain_cap;
539338Srafael.vanoni@sun.com double last_cap;
549338Srafael.vanoni@sun.com } battery_state_t;
559338Srafael.vanoni@sun.com
569338Srafael.vanoni@sun.com static char *kstat_batt_mod[3] = {NULL, "battery", "acpi_drv"};
579338Srafael.vanoni@sun.com static uint_t kstat_batt_idx;
589338Srafael.vanoni@sun.com static battery_state_t battery_state;
599338Srafael.vanoni@sun.com
60*11122Srafael.vanoni@sun.com static int pt_battery_stat_snapshot(void);
619338Srafael.vanoni@sun.com
629338Srafael.vanoni@sun.com /*
639338Srafael.vanoni@sun.com * Checks if the kstat module for battery information is present and
649338Srafael.vanoni@sun.com * whether it's called 'battery' or 'acpi_drv'
659338Srafael.vanoni@sun.com */
669338Srafael.vanoni@sun.com void
pt_battery_mod_lookup(void)67*11122Srafael.vanoni@sun.com pt_battery_mod_lookup(void)
689338Srafael.vanoni@sun.com {
699338Srafael.vanoni@sun.com kstat_ctl_t *kc = kstat_open();
709338Srafael.vanoni@sun.com
719338Srafael.vanoni@sun.com if (kstat_lookup(kc, kstat_batt_mod[1], 0, NULL))
729338Srafael.vanoni@sun.com kstat_batt_idx = 1;
739338Srafael.vanoni@sun.com else
749338Srafael.vanoni@sun.com if (kstat_lookup(kc, kstat_batt_mod[2], 0, NULL))
759338Srafael.vanoni@sun.com kstat_batt_idx = 2;
769338Srafael.vanoni@sun.com else
779338Srafael.vanoni@sun.com kstat_batt_idx = 0;
789338Srafael.vanoni@sun.com
799338Srafael.vanoni@sun.com (void) kstat_close(kc);
809338Srafael.vanoni@sun.com }
819338Srafael.vanoni@sun.com
829338Srafael.vanoni@sun.com void
pt_battery_print(void)839908Srafael.vanoni@sun.com pt_battery_print(void)
849338Srafael.vanoni@sun.com {
859338Srafael.vanoni@sun.com int err;
869338Srafael.vanoni@sun.com
879338Srafael.vanoni@sun.com (void) memset(&battery_state, 0, sizeof (battery_state_t));
889338Srafael.vanoni@sun.com
899338Srafael.vanoni@sun.com /*
90*11122Srafael.vanoni@sun.com * The return value of pt_battery_stat_snapshot() can be used for
919338Srafael.vanoni@sun.com * debug or to show/hide the acpi power line. We currently don't
929338Srafael.vanoni@sun.com * make the distinction of a system that runs only on AC and one
939338Srafael.vanoni@sun.com * that runs on battery but has no kstat battery info.
949338Srafael.vanoni@sun.com *
959338Srafael.vanoni@sun.com * We still display the estimate power usage for systems
969338Srafael.vanoni@sun.com * running on AC with a fully charged battery because some
979338Srafael.vanoni@sun.com * batteries may still consume power.
989338Srafael.vanoni@sun.com *
99*11122Srafael.vanoni@sun.com * If pt_battery_mod_lookup() didn't find a kstat battery module, don't
1009338Srafael.vanoni@sun.com * bother trying to take the snapshot
1019338Srafael.vanoni@sun.com */
1029338Srafael.vanoni@sun.com if (kstat_batt_idx > 0) {
103*11122Srafael.vanoni@sun.com if ((err = pt_battery_stat_snapshot()) < 0)
104*11122Srafael.vanoni@sun.com pt_error("battery kstat not found (%d)\n", err);
1059338Srafael.vanoni@sun.com }
1069338Srafael.vanoni@sun.com
1079908Srafael.vanoni@sun.com pt_display_acpi_power(battery_state.exist, battery_state.present_rate,
1089338Srafael.vanoni@sun.com battery_state.remain_cap, battery_state.last_cap,
1099338Srafael.vanoni@sun.com battery_state.bst_state);
1109338Srafael.vanoni@sun.com }
1119338Srafael.vanoni@sun.com
1129338Srafael.vanoni@sun.com static int
pt_battery_stat_snapshot(void)113*11122Srafael.vanoni@sun.com pt_battery_stat_snapshot(void)
1149338Srafael.vanoni@sun.com {
1159338Srafael.vanoni@sun.com kstat_ctl_t *kc;
1169338Srafael.vanoni@sun.com kstat_t *ksp;
1179338Srafael.vanoni@sun.com kstat_named_t *knp;
1189338Srafael.vanoni@sun.com
1199338Srafael.vanoni@sun.com kc = kstat_open();
1209338Srafael.vanoni@sun.com
1219338Srafael.vanoni@sun.com /*
1229338Srafael.vanoni@sun.com * power unit:
1239338Srafael.vanoni@sun.com * 0 - Capacity information is reported in [mWh] and
1249338Srafael.vanoni@sun.com * charge/discharge rate information in [mW]
1259338Srafael.vanoni@sun.com * 1 - Capacity information is reported in [mAh] and
1269338Srafael.vanoni@sun.com * charge/discharge rate information in [mA].
1279338Srafael.vanoni@sun.com */
1289338Srafael.vanoni@sun.com ksp = kstat_lookup(kc, kstat_batt_mod[kstat_batt_idx], 0,
1299338Srafael.vanoni@sun.com "battery BIF0");
1309338Srafael.vanoni@sun.com
1319338Srafael.vanoni@sun.com if (ksp == NULL) {
1329338Srafael.vanoni@sun.com (void) kstat_close(kc);
1339338Srafael.vanoni@sun.com return (-1);
1349338Srafael.vanoni@sun.com }
1359338Srafael.vanoni@sun.com
1369338Srafael.vanoni@sun.com (void) kstat_read(kc, ksp, NULL);
1379338Srafael.vanoni@sun.com knp = kstat_data_lookup(ksp, "bif_unit");
1389338Srafael.vanoni@sun.com
1399338Srafael.vanoni@sun.com if (knp == NULL) {
1409338Srafael.vanoni@sun.com (void) kstat_close(kc);
1419338Srafael.vanoni@sun.com return (-1);
1429338Srafael.vanoni@sun.com }
1439338Srafael.vanoni@sun.com
1449338Srafael.vanoni@sun.com battery_state.power_unit = knp->value.ui32;
1459338Srafael.vanoni@sun.com
1469338Srafael.vanoni@sun.com /*
1479338Srafael.vanoni@sun.com * Present rate:
1489338Srafael.vanoni@sun.com * the power or current being supplied or accepted
1499338Srafael.vanoni@sun.com * through the battery's terminal
1509338Srafael.vanoni@sun.com */
1519338Srafael.vanoni@sun.com ksp = kstat_lookup(kc, kstat_batt_mod[kstat_batt_idx], 0,
1529338Srafael.vanoni@sun.com "battery BST0");
1539338Srafael.vanoni@sun.com
1549338Srafael.vanoni@sun.com if (ksp == NULL) {
1559338Srafael.vanoni@sun.com (void) kstat_close(kc);
1569338Srafael.vanoni@sun.com return (-1);
1579338Srafael.vanoni@sun.com }
1589338Srafael.vanoni@sun.com
1599338Srafael.vanoni@sun.com (void) kstat_read(kc, ksp, NULL);
1609338Srafael.vanoni@sun.com knp = kstat_data_lookup(ksp, "bst_rate");
1619338Srafael.vanoni@sun.com
1629338Srafael.vanoni@sun.com if (knp == NULL) {
1639338Srafael.vanoni@sun.com (void) kstat_close(kc);
1649338Srafael.vanoni@sun.com return (-1);
1659338Srafael.vanoni@sun.com }
1669338Srafael.vanoni@sun.com
1679338Srafael.vanoni@sun.com if (knp->value.ui32 == 0xFFFFFFFF)
1689338Srafael.vanoni@sun.com battery_state.present_rate = 0;
1699338Srafael.vanoni@sun.com else {
1709338Srafael.vanoni@sun.com battery_state.exist = 1;
1719338Srafael.vanoni@sun.com battery_state.present_rate = mW2W((double)(knp->value.ui32));
1729338Srafael.vanoni@sun.com }
1739338Srafael.vanoni@sun.com
1749338Srafael.vanoni@sun.com /*
1759338Srafael.vanoni@sun.com * Last Full charge capacity:
1769338Srafael.vanoni@sun.com * Predicted battery capacity when fully charged.
1779338Srafael.vanoni@sun.com */
1789338Srafael.vanoni@sun.com ksp = kstat_lookup(kc, kstat_batt_mod[kstat_batt_idx], 0,
1799338Srafael.vanoni@sun.com "battery BIF0");
1809338Srafael.vanoni@sun.com
1819338Srafael.vanoni@sun.com if (ksp == NULL) {
1829338Srafael.vanoni@sun.com (void) kstat_close(kc);
1839338Srafael.vanoni@sun.com return (-1);
1849338Srafael.vanoni@sun.com }
1859338Srafael.vanoni@sun.com
1869338Srafael.vanoni@sun.com (void) kstat_read(kc, ksp, NULL);
1879338Srafael.vanoni@sun.com knp = kstat_data_lookup(ksp, "bif_last_cap");
1889338Srafael.vanoni@sun.com
1899338Srafael.vanoni@sun.com if (knp == NULL) {
1909338Srafael.vanoni@sun.com (void) kstat_close(kc);
1919338Srafael.vanoni@sun.com return (-1);
1929338Srafael.vanoni@sun.com }
1939338Srafael.vanoni@sun.com
1949338Srafael.vanoni@sun.com battery_state.last_cap = mW2W((double)(knp->value.ui32));
1959338Srafael.vanoni@sun.com
1969338Srafael.vanoni@sun.com /*
1979338Srafael.vanoni@sun.com * Remaining capacity:
1989338Srafael.vanoni@sun.com * the estimated remaining battery capacity
1999338Srafael.vanoni@sun.com */
2009338Srafael.vanoni@sun.com ksp = kstat_lookup(kc, kstat_batt_mod[kstat_batt_idx], 0,
2019338Srafael.vanoni@sun.com "battery BST0");
2029338Srafael.vanoni@sun.com
2039338Srafael.vanoni@sun.com if (ksp == NULL) {
2049338Srafael.vanoni@sun.com (void) kstat_close(kc);
2059338Srafael.vanoni@sun.com return (-1);
2069338Srafael.vanoni@sun.com }
2079338Srafael.vanoni@sun.com
2089338Srafael.vanoni@sun.com (void) kstat_read(kc, ksp, NULL);
2099338Srafael.vanoni@sun.com knp = kstat_data_lookup(ksp, "bst_rem_cap");
2109338Srafael.vanoni@sun.com
2119338Srafael.vanoni@sun.com if (knp == NULL) {
2129338Srafael.vanoni@sun.com (void) kstat_close(kc);
2139338Srafael.vanoni@sun.com return (-1);
2149338Srafael.vanoni@sun.com }
2159338Srafael.vanoni@sun.com
2169338Srafael.vanoni@sun.com battery_state.remain_cap = mW2W((double)(knp->value.ui32));
2179338Srafael.vanoni@sun.com
2189338Srafael.vanoni@sun.com /*
2199338Srafael.vanoni@sun.com * Battery State:
2209338Srafael.vanoni@sun.com * Bit0 - 1 : discharging
2219338Srafael.vanoni@sun.com * Bit1 - 1 : charging
2229338Srafael.vanoni@sun.com * Bit2 - 1 : critical energy state
2239338Srafael.vanoni@sun.com */
2249338Srafael.vanoni@sun.com ksp = kstat_lookup(kc, kstat_batt_mod[kstat_batt_idx], 0,
2259338Srafael.vanoni@sun.com "battery BST0");
2269338Srafael.vanoni@sun.com
2279338Srafael.vanoni@sun.com if (ksp == NULL) {
2289338Srafael.vanoni@sun.com (void) kstat_close(kc);
2299338Srafael.vanoni@sun.com return (-1);
2309338Srafael.vanoni@sun.com }
2319338Srafael.vanoni@sun.com
2329338Srafael.vanoni@sun.com (void) kstat_read(kc, ksp, NULL);
2339338Srafael.vanoni@sun.com knp = kstat_data_lookup(ksp, "bst_state");
2349338Srafael.vanoni@sun.com
2359338Srafael.vanoni@sun.com if (knp == NULL) {
2369338Srafael.vanoni@sun.com (void) kstat_close(kc);
2379338Srafael.vanoni@sun.com return (-1);
2389338Srafael.vanoni@sun.com }
2399338Srafael.vanoni@sun.com
2409338Srafael.vanoni@sun.com battery_state.bst_state = knp->value.ui32;
2419338Srafael.vanoni@sun.com
2429338Srafael.vanoni@sun.com (void) kstat_close(kc);
2439338Srafael.vanoni@sun.com
2449338Srafael.vanoni@sun.com return (0);
2459338Srafael.vanoni@sun.com }
246