ACPI battery status in /proc/acpi/battery is deprecated in recent Linux
kernels, and missing when CONFIG_ACPI_PROCFS_POWER is disabled.

Add support for getting the battery readout from
/sys/class/power_supply and use it instead of /proc/acpi when available.

Signed-off-by: Anssi Hannula <anssi.hann...@iki.fi>
---
 Makefile                    |    2 +-
 measurement/measurement.cpp |   22 ++++++-
 measurement/sysfs.cpp       |  158 +++++++++++++++++++++++++++++++++++++++++++
 measurement/sysfs.h         |   55 +++++++++++++++
 4 files changed, 234 insertions(+), 3 deletions(-)
 create mode 100644 measurement/sysfs.cpp
 create mode 100644 measurement/sysfs.h

diff --git a/Makefile b/Makefile
index b0b6cb7..36b39e8 100644
--- a/Makefile
+++ b/Makefile
@@ -13,7 +13,7 @@ OBJS += perf/perf.o perf/perf_bundle.o
 OBJS += process/process.o process/do_process.o process/interrupt.o 
process/timer.o process/work.o process/powerconsumer.o process/device.o
 DEVS += devices/device.o devices/backlight.o devices/usb.o devices/ahci.o 
devices/alsa.o devices/rfkill.o devices/i915-gpu.o devices/thinkpad-fan.o 
devices/network.o devices/thinkpad-light.o
 DEVS += devices/runtime_pm.o
-DEVS += measurement/measurement.o measurement/acpi.o measurement/extech.o
+DEVS += measurement/measurement.o measurement/acpi.o measurement/extech.o 
measurement/sysfs.o
 OBJS += $(DEVS)
 OBJS += parameters/parameters.o parameters/learn.o parameters/persistent.o
 OBJS += calibrate/calibrate.o
diff --git a/measurement/measurement.cpp b/measurement/measurement.cpp
index 3dbaab9..f16cd32 100644
--- a/measurement/measurement.cpp
+++ b/measurement/measurement.cpp
@@ -25,9 +25,11 @@
 #include "measurement.h"
 #include "acpi.h"
 #include "extech.h"
+#include "sysfs.h"
 #include "../parameters/parameters.h"
 #include "../lib.h"
 
+#include <string>
 #include <sys/types.h>
 #include <dirent.h>
 
@@ -103,7 +105,20 @@ double global_time_left(void)
        return total;
 }
 
-void power_meters_callback(const char *d_name)
+void sysfs_power_meters_callback(const char *d_name)
+{
+       std::string type = read_sysfs_string("/sys/class/power_supply/%s/type", 
d_name);
+
+       if (type != "Battery" && type != "UPS")
+               return;
+
+       class sysfs_power_meter *meter;
+       meter = new(std::nothrow) class sysfs_power_meter(d_name);
+       if (meter)
+               power_meters.push_back(meter);
+}
+
+void acpi_power_meters_callback(const char *d_name)
 {
        class acpi_power_meter *meter;
        meter = new(std::nothrow) class acpi_power_meter(d_name);
@@ -113,7 +128,10 @@ void power_meters_callback(const char *d_name)
 
 void detect_power_meters(void)
 {
-       process_directory("/proc/acpi/battery", power_meters_callback);
+       process_directory("/sys/class/power_supply", 
sysfs_power_meters_callback);
+       if (power_meters.size() == 0) {
+               process_directory("/proc/acpi/battery", 
acpi_power_meters_callback);
+       }
 }
 
 void extech_power_meter(const char *devnode)
diff --git a/measurement/sysfs.cpp b/measurement/sysfs.cpp
new file mode 100644
index 0000000..66cb1cd
--- /dev/null
+++ b/measurement/sysfs.cpp
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2011 Anssi Hannula
+ *
+ * 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
+ * or just google for it.
+ *
+ * Authors:
+ *     Anssi Hannula <anssi.hann...@iki.fi>
+ */
+#include "measurement.h"
+#include "sysfs.h"
+#include "../lib.h"
+#include <string.h>
+#include <stdio.h>
+
+sysfs_power_meter::sysfs_power_meter(const char *power_supply_name)
+{
+       rate = 0.0;
+       capacity = 0.0;
+       strncpy(name, power_supply_name, sizeof(name));
+}
+
+bool sysfs_power_meter::get_sysfs_attr(const char *attribute, int *value)
+{
+       char filename[4096];
+       bool ok;
+
+       snprintf(filename, sizeof(filename), "/sys/class/power_supply/%s/%s", 
name, attribute);
+       *value = read_sysfs(filename, &ok);
+
+       return ok;
+}
+
+bool sysfs_power_meter::is_present()
+{
+       int present = 0;
+
+       if (!get_sysfs_attr("present", &present))
+               return true; /* assume always present */
+
+       return present;
+}
+
+double sysfs_power_meter::get_voltage()
+{
+       int voltage;
+
+       if (!get_sysfs_attr("voltage_now", &voltage))
+               return -1.0;
+
+       /* µV to V */
+       return voltage / 1000000.0;
+}
+
+bool sysfs_power_meter::set_rate_from_power()
+{
+       int power;
+
+       if (!get_sysfs_attr("power_now", &power))
+               return false;
+
+       /* µW to W */
+       rate = power / 1000000.0;
+       return true;
+}
+
+bool sysfs_power_meter::set_rate_from_current(double voltage)
+{
+       int current;
+
+       if (!get_sysfs_attr("current_now", &current))
+               return false;
+
+       /* current: µA
+        * voltage: V
+        * rate: W */
+       rate = (current / 1000000.0) * voltage;
+       return true;
+}
+
+bool sysfs_power_meter::set_capacity_from_energy()
+{
+       int energy;
+
+       if (!get_sysfs_attr("energy_now", &energy))
+               return false;
+
+       /* µWh to J */
+       capacity = energy / 1000000.0 * 3600.0;
+       return true;
+}
+
+bool sysfs_power_meter::set_capacity_from_charge(double voltage)
+{
+       int charge;
+
+       if (!get_sysfs_attr("charge_now", &charge))
+               return false;
+
+       /* charge: µAh
+        * voltage: V
+        * capacity: J */
+       capacity = (charge / 1000000.0) * voltage * 3600.0;
+       return true;
+}
+
+void sysfs_power_meter::measure()
+{
+       bool got_rate = false;
+       bool got_capacity = false;
+
+       rate = 0.0;
+       capacity = 0.0;
+
+       if (!is_present())
+               return;
+       if (read_sysfs_string("/sys/class/power_supply/%s/status", name) != 
"Discharging")
+               return;
+
+       got_rate = set_rate_from_power();
+       got_capacity = set_capacity_from_energy();
+
+       if (!got_rate || !got_capacity) {
+               double voltage = get_voltage();
+               if (voltage < 0.0)
+                       return;
+               if (!got_rate)
+                       set_rate_from_current(voltage);
+               if (!got_capacity)
+                       set_capacity_from_charge(voltage);
+       }
+}
+
+
+void sysfs_power_meter::end_measurement(void)
+{
+       measure();
+}
+
+void sysfs_power_meter::start_measurement(void)
+{
+       /* Battery state is generally a lagging indication, lets only measure 
at the end */
+}
diff --git a/measurement/sysfs.h b/measurement/sysfs.h
new file mode 100644
index 0000000..b7efa3d
--- /dev/null
+++ b/measurement/sysfs.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2011 Anssi Hannula
+ *
+ * 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
+ * or just google for it.
+ *
+ * Authors:
+ *     Anssi Hannula <anssi.hann...@iki.fi>
+ */
+#ifndef INCLUDE_GUARD_SYSFS_H
+#define INCLUDE_GUARD_SYSFS_H
+
+#include "measurement.h"
+
+class sysfs_power_meter: public power_meter {
+       char name[256];
+
+       double capacity;
+       double rate;
+
+       bool get_sysfs_attr(const char *attribute, int *value);
+       bool is_present();
+       double get_voltage();
+
+       bool set_rate_from_power();
+       bool set_rate_from_current(double voltage);
+       bool set_capacity_from_energy();
+       bool set_capacity_from_charge(double voltage);
+
+       void measure();
+public:
+       sysfs_power_meter(const char *power_supply_name);
+       virtual void start_measurement(void);
+       virtual void end_measurement(void);
+
+       virtual double joules_consumed(void) { return rate; }
+       virtual double dev_capacity(void) { return capacity; }
+};
+
+#endif
-- 
1.7.7.2

_______________________________________________
Power mailing list
Power@bughost.org
https://bughost.org/mailman/listinfo/power

Reply via email to