/* * Copyright 2009, Intel Corporation * Copyright 2009, Sun Microsystems, Inc * * This file is part of PowerTOP * * This program file is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; version 2 of the License. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License * along with this program in a file named COPYING; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA * * Authors: * Arjan van de Ven * Eric C Saxe * Aubrey Li */ /* * GPL Disclaimer * * For the avoidance of doubt, except that if any license choice other * than GPL or LGPL is available it will apply instead, Sun elects to * use only the General Public License version 2 (GPLv2) at this time * for any software where a choice of GPL license versions is made * available with the language indicating that GPLv2 or any later * version may be used, or where a choice of which version of the GPL * is applied is otherwise unspecified. */ #include #include #include #include "powertop.h" #define mW2W(value) ((value) / 1000) typedef struct battery_state { uint32_t exist; uint32_t power_unit; uint32_t bst_state; double present_rate; double remain_cap; double last_cap; } battery_state_t; static char *kstat_batt_mod[3] = {NULL, "battery", "acpi_drv"}; static uint_t kstat_batt_idx; static battery_state_t battery_state; static int battery_stat_snapshot(void); /* * Checks if the kstat module for battery information is present and * whether it's called 'battery' or 'acpi_drv' */ void battery_mod_lookup(void) { kstat_ctl_t *kc = kstat_open(); if (kstat_lookup(kc, kstat_batt_mod[1], 0, NULL)) kstat_batt_idx = 1; else if (kstat_lookup(kc, kstat_batt_mod[2], 0, NULL)) kstat_batt_idx = 2; else kstat_batt_idx = 0; (void) kstat_close(kc); } void pt_battery_print(void) { int err; (void) memset(&battery_state, 0, sizeof (battery_state_t)); /* * The return value of battery_stat_snapshot() can be used for * debug or to show/hide the acpi power line. We currently don't * make the distinction of a system that runs only on AC and one * that runs on battery but has no kstat battery info. * * We still display the estimate power usage for systems * running on AC with a fully charged battery because some * batteries may still consume power. * * If battery_mod_lookup() didn't find a kstat battery module, don't * bother trying to take the snapshot */ if (kstat_batt_idx > 0) { if ((err = battery_stat_snapshot()) < 0) pt_error("%s : battery kstat not found %d\n", __FILE__, err); } pt_display_acpi_power(battery_state.exist, battery_state.present_rate, battery_state.remain_cap, battery_state.last_cap, battery_state.bst_state); } static int battery_stat_snapshot(void) { kstat_ctl_t *kc; kstat_t *ksp; kstat_named_t *knp; kc = kstat_open(); /* * power unit: * 0 - Capacity information is reported in [mWh] and * charge/discharge rate information in [mW] * 1 - Capacity information is reported in [mAh] and * charge/discharge rate information in [mA]. */ ksp = kstat_lookup(kc, kstat_batt_mod[kstat_batt_idx], 0, "battery BIF0"); if (ksp == NULL) { (void) kstat_close(kc); return (-1); } (void) kstat_read(kc, ksp, NULL); knp = kstat_data_lookup(ksp, "bif_unit"); if (knp == NULL) { (void) kstat_close(kc); return (-1); } battery_state.power_unit = knp->value.ui32; /* * Present rate: * the power or current being supplied or accepted * through the battery's terminal */ ksp = kstat_lookup(kc, kstat_batt_mod[kstat_batt_idx], 0, "battery BST0"); if (ksp == NULL) { (void) kstat_close(kc); return (-1); } (void) kstat_read(kc, ksp, NULL); knp = kstat_data_lookup(ksp, "bst_rate"); if (knp == NULL) { (void) kstat_close(kc); return (-1); } if (knp->value.ui32 == 0xFFFFFFFF) battery_state.present_rate = 0; else { battery_state.exist = 1; battery_state.present_rate = mW2W((double)(knp->value.ui32)); } /* * Last Full charge capacity: * Predicted battery capacity when fully charged. */ ksp = kstat_lookup(kc, kstat_batt_mod[kstat_batt_idx], 0, "battery BIF0"); if (ksp == NULL) { (void) kstat_close(kc); return (-1); } (void) kstat_read(kc, ksp, NULL); knp = kstat_data_lookup(ksp, "bif_last_cap"); if (knp == NULL) { (void) kstat_close(kc); return (-1); } battery_state.last_cap = mW2W((double)(knp->value.ui32)); /* * Remaining capacity: * the estimated remaining battery capacity */ ksp = kstat_lookup(kc, kstat_batt_mod[kstat_batt_idx], 0, "battery BST0"); if (ksp == NULL) { (void) kstat_close(kc); return (-1); } (void) kstat_read(kc, ksp, NULL); knp = kstat_data_lookup(ksp, "bst_rem_cap"); if (knp == NULL) { (void) kstat_close(kc); return (-1); } battery_state.remain_cap = mW2W((double)(knp->value.ui32)); /* * Battery State: * Bit0 - 1 : discharging * Bit1 - 1 : charging * Bit2 - 1 : critical energy state */ ksp = kstat_lookup(kc, kstat_batt_mod[kstat_batt_idx], 0, "battery BST0"); if (ksp == NULL) { (void) kstat_close(kc); return (-1); } (void) kstat_read(kc, ksp, NULL); knp = kstat_data_lookup(ksp, "bst_state"); if (knp == NULL) { (void) kstat_close(kc); return (-1); } battery_state.bst_state = knp->value.ui32; (void) kstat_close(kc); return (0); }