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