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 60b47b5b34SRafael Vanoni static int 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 67b47b5b34SRafael Vanoni 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 83*9bbf5ba1SRafael 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 /* 90b47b5b34SRafael Vanoni * The return value of 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 * 99b47b5b34SRafael Vanoni * If 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) { 103b47b5b34SRafael Vanoni if ((err = battery_stat_snapshot()) < 0) 104b47b5b34SRafael Vanoni pt_error("%s : battery kstat not found %d\n", __FILE__, 105b47b5b34SRafael Vanoni err); 106b47b5b34SRafael Vanoni } 107b47b5b34SRafael Vanoni 108*9bbf5ba1SRafael Vanoni pt_display_acpi_power(battery_state.exist, battery_state.present_rate, 109b47b5b34SRafael Vanoni battery_state.remain_cap, battery_state.last_cap, 110b47b5b34SRafael Vanoni battery_state.bst_state); 111b47b5b34SRafael Vanoni } 112b47b5b34SRafael Vanoni 113b47b5b34SRafael Vanoni static int 114b47b5b34SRafael Vanoni battery_stat_snapshot(void) 115b47b5b34SRafael Vanoni { 116b47b5b34SRafael Vanoni kstat_ctl_t *kc; 117b47b5b34SRafael Vanoni kstat_t *ksp; 118b47b5b34SRafael Vanoni kstat_named_t *knp; 119b47b5b34SRafael Vanoni 120b47b5b34SRafael Vanoni kc = kstat_open(); 121b47b5b34SRafael Vanoni 122b47b5b34SRafael Vanoni /* 123b47b5b34SRafael Vanoni * power unit: 124b47b5b34SRafael Vanoni * 0 - Capacity information is reported in [mWh] and 125b47b5b34SRafael Vanoni * charge/discharge rate information in [mW] 126b47b5b34SRafael Vanoni * 1 - Capacity information is reported in [mAh] and 127b47b5b34SRafael Vanoni * charge/discharge rate information in [mA]. 128b47b5b34SRafael Vanoni */ 129b47b5b34SRafael Vanoni ksp = kstat_lookup(kc, kstat_batt_mod[kstat_batt_idx], 0, 130b47b5b34SRafael Vanoni "battery BIF0"); 131b47b5b34SRafael Vanoni 132b47b5b34SRafael Vanoni if (ksp == NULL) { 133b47b5b34SRafael Vanoni (void) kstat_close(kc); 134b47b5b34SRafael Vanoni return (-1); 135b47b5b34SRafael Vanoni } 136b47b5b34SRafael Vanoni 137b47b5b34SRafael Vanoni (void) kstat_read(kc, ksp, NULL); 138b47b5b34SRafael Vanoni knp = kstat_data_lookup(ksp, "bif_unit"); 139b47b5b34SRafael Vanoni 140b47b5b34SRafael Vanoni if (knp == NULL) { 141b47b5b34SRafael Vanoni (void) kstat_close(kc); 142b47b5b34SRafael Vanoni return (-1); 143b47b5b34SRafael Vanoni } 144b47b5b34SRafael Vanoni 145b47b5b34SRafael Vanoni battery_state.power_unit = knp->value.ui32; 146b47b5b34SRafael Vanoni 147b47b5b34SRafael Vanoni /* 148b47b5b34SRafael Vanoni * Present rate: 149b47b5b34SRafael Vanoni * the power or current being supplied or accepted 150b47b5b34SRafael Vanoni * through the battery's terminal 151b47b5b34SRafael Vanoni */ 152b47b5b34SRafael Vanoni ksp = kstat_lookup(kc, kstat_batt_mod[kstat_batt_idx], 0, 153b47b5b34SRafael Vanoni "battery BST0"); 154b47b5b34SRafael Vanoni 155b47b5b34SRafael Vanoni if (ksp == NULL) { 156b47b5b34SRafael Vanoni (void) kstat_close(kc); 157b47b5b34SRafael Vanoni return (-1); 158b47b5b34SRafael Vanoni } 159b47b5b34SRafael Vanoni 160b47b5b34SRafael Vanoni (void) kstat_read(kc, ksp, NULL); 161b47b5b34SRafael Vanoni knp = kstat_data_lookup(ksp, "bst_rate"); 162b47b5b34SRafael Vanoni 163b47b5b34SRafael Vanoni if (knp == NULL) { 164b47b5b34SRafael Vanoni (void) kstat_close(kc); 165b47b5b34SRafael Vanoni return (-1); 166b47b5b34SRafael Vanoni } 167b47b5b34SRafael Vanoni 168b47b5b34SRafael Vanoni if (knp->value.ui32 == 0xFFFFFFFF) 169b47b5b34SRafael Vanoni battery_state.present_rate = 0; 170b47b5b34SRafael Vanoni else { 171b47b5b34SRafael Vanoni battery_state.exist = 1; 172b47b5b34SRafael Vanoni battery_state.present_rate = mW2W((double)(knp->value.ui32)); 173b47b5b34SRafael Vanoni } 174b47b5b34SRafael Vanoni 175b47b5b34SRafael Vanoni /* 176b47b5b34SRafael Vanoni * Last Full charge capacity: 177b47b5b34SRafael Vanoni * Predicted battery capacity when fully charged. 178b47b5b34SRafael Vanoni */ 179b47b5b34SRafael Vanoni ksp = kstat_lookup(kc, kstat_batt_mod[kstat_batt_idx], 0, 180b47b5b34SRafael Vanoni "battery BIF0"); 181b47b5b34SRafael Vanoni 182b47b5b34SRafael Vanoni if (ksp == NULL) { 183b47b5b34SRafael Vanoni (void) kstat_close(kc); 184b47b5b34SRafael Vanoni return (-1); 185b47b5b34SRafael Vanoni } 186b47b5b34SRafael Vanoni 187b47b5b34SRafael Vanoni (void) kstat_read(kc, ksp, NULL); 188b47b5b34SRafael Vanoni knp = kstat_data_lookup(ksp, "bif_last_cap"); 189b47b5b34SRafael Vanoni 190b47b5b34SRafael Vanoni if (knp == NULL) { 191b47b5b34SRafael Vanoni (void) kstat_close(kc); 192b47b5b34SRafael Vanoni return (-1); 193b47b5b34SRafael Vanoni } 194b47b5b34SRafael Vanoni 195b47b5b34SRafael Vanoni battery_state.last_cap = mW2W((double)(knp->value.ui32)); 196b47b5b34SRafael Vanoni 197b47b5b34SRafael Vanoni /* 198b47b5b34SRafael Vanoni * Remaining capacity: 199b47b5b34SRafael Vanoni * the estimated remaining battery capacity 200b47b5b34SRafael Vanoni */ 201b47b5b34SRafael Vanoni ksp = kstat_lookup(kc, kstat_batt_mod[kstat_batt_idx], 0, 202b47b5b34SRafael Vanoni "battery BST0"); 203b47b5b34SRafael Vanoni 204b47b5b34SRafael Vanoni if (ksp == NULL) { 205b47b5b34SRafael Vanoni (void) kstat_close(kc); 206b47b5b34SRafael Vanoni return (-1); 207b47b5b34SRafael Vanoni } 208b47b5b34SRafael Vanoni 209b47b5b34SRafael Vanoni (void) kstat_read(kc, ksp, NULL); 210b47b5b34SRafael Vanoni knp = kstat_data_lookup(ksp, "bst_rem_cap"); 211b47b5b34SRafael Vanoni 212b47b5b34SRafael Vanoni if (knp == NULL) { 213b47b5b34SRafael Vanoni (void) kstat_close(kc); 214b47b5b34SRafael Vanoni return (-1); 215b47b5b34SRafael Vanoni } 216b47b5b34SRafael Vanoni 217b47b5b34SRafael Vanoni battery_state.remain_cap = mW2W((double)(knp->value.ui32)); 218b47b5b34SRafael Vanoni 219b47b5b34SRafael Vanoni /* 220b47b5b34SRafael Vanoni * Battery State: 221b47b5b34SRafael Vanoni * Bit0 - 1 : discharging 222b47b5b34SRafael Vanoni * Bit1 - 1 : charging 223b47b5b34SRafael Vanoni * Bit2 - 1 : critical energy state 224b47b5b34SRafael Vanoni */ 225b47b5b34SRafael Vanoni ksp = kstat_lookup(kc, kstat_batt_mod[kstat_batt_idx], 0, 226b47b5b34SRafael Vanoni "battery BST0"); 227b47b5b34SRafael Vanoni 228b47b5b34SRafael Vanoni if (ksp == NULL) { 229b47b5b34SRafael Vanoni (void) kstat_close(kc); 230b47b5b34SRafael Vanoni return (-1); 231b47b5b34SRafael Vanoni } 232b47b5b34SRafael Vanoni 233b47b5b34SRafael Vanoni (void) kstat_read(kc, ksp, NULL); 234b47b5b34SRafael Vanoni knp = kstat_data_lookup(ksp, "bst_state"); 235b47b5b34SRafael Vanoni 236b47b5b34SRafael Vanoni if (knp == NULL) { 237b47b5b34SRafael Vanoni (void) kstat_close(kc); 238b47b5b34SRafael Vanoni return (-1); 239b47b5b34SRafael Vanoni } 240b47b5b34SRafael Vanoni 241b47b5b34SRafael Vanoni battery_state.bst_state = knp->value.ui32; 242b47b5b34SRafael Vanoni 243b47b5b34SRafael Vanoni (void) kstat_close(kc); 244b47b5b34SRafael Vanoni 245b47b5b34SRafael Vanoni return (0); 246b47b5b34SRafael Vanoni } 247