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