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