summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBastien Nocera <hadess@hadess.net>2017-03-23 18:38:33 +0100
committerBastien Nocera <hadess@hadess.net>2017-04-06 14:18:10 +0200
commit6b147982817ad9180e594bcfdb0db94bbfcb4869 (patch)
tree71f4fd96578f4139d20a57647ad44680d4df9e5f /src
parent27a3eea5e5a5a39acd22f67994a4ba4027faf201 (diff)
linux: Add support for "capacity_level" attribute
Some devices, such as a number of wireless Logitech unifying devices don't have a precise battery level reporting, and use the Linux POWER_SUPPLY_CAPACITY_LEVEL_* values. This minimal fix matches the levels against approximate percentage values. This is good enough to make the Logitech T650 report battery again when using the kernel HID++ battery support. https://bugs.freedesktop.org/show_bug.cgi?id=100359
Diffstat (limited to 'src')
-rwxr-xr-xsrc/linux/integration-test67
-rw-r--r--src/linux/up-device-supply.c36
2 files changed, 102 insertions, 1 deletions
diff --git a/src/linux/integration-test b/src/linux/integration-test
index 65f141d..1769e26 100755
--- a/src/linux/integration-test
+++ b/src/linux/integration-test
@@ -952,6 +952,73 @@ class Tests(dbusmock.DBusTestCase):
self.assertEqual(self.get_dbus_display_property('WarningLevel'), UP_DEVICE_LEVEL_NONE)
self.stop_daemon()
+ def test_hidpp_touchpad(self):
+ '''HID++ touchpad battery with 5 capacity levels'''
+
+ dev = self.testbed.add_device('hid',
+ '/devices/pci0000:00/0000:00:14.0/usb3/3-10/3-10:1.2/0003:046D:C52B.0009/0003:046D:4101.000A',
+ None,
+ [], [])
+
+ parent = dev
+ self.testbed.add_device(
+ 'input',
+ '/devices/pci0000:00/0000:00:14.0/usb3/3-10/3-10:1.2/0003:046D:C52B.0009/0003:046D:4101.000A/input/input22',
+ parent,
+ [], ['DEVNAME', 'input/mouse3', 'ID_INPUT_TOUCHPAD', '1'])
+
+ dev = self.testbed.add_device(
+ 'power_supply',
+ '/devices/pci0000:00/0000:00:14.0/usb3/3-10/3-10:1.2/0003:046D:C52B.0009/0003:046D:4101.000A/power_supply/hidpp_battery_3',
+ parent,
+ ['type', 'Battery',
+ 'scope', 'Device',
+ 'present', '1',
+ 'online', '1',
+ 'status', 'Discharging',
+ 'capacity_level', 'Full\n',
+ 'serial_number', '123456',
+ 'model_name', 'Logitech T650'],
+ [])
+
+ self.start_daemon()
+ devs = self.proxy.EnumerateDevices()
+ self.assertEqual(len(devs), 1)
+ mousebat0_up = devs[0]
+
+ self.assertEqual(self.get_dbus_dev_property(mousebat0_up, 'Model'), 'Logitech T650')
+ self.assertEqual(self.get_dbus_dev_property(mousebat0_up, 'PowerSupply'), False)
+ # 5 == mouse
+ self.assertEqual(self.get_dbus_dev_property(mousebat0_up, 'Type'), 5)
+ self.assertEqual(self.get_dbus_dev_property(mousebat0_up, 'Serial'), '123456')
+ self.assertEqual(self.get_dbus_property('OnBattery'), False)
+ self.assertEqual(self.get_dbus_display_property('WarningLevel'), UP_DEVICE_LEVEL_NONE)
+
+ # Now test all the levels
+ self.assertEqual(self.get_dbus_dev_property(mousebat0_up, 'Percentage'), 100)
+
+ self.testbed.set_attribute(dev, 'capacity_level', 'Critical\n')
+ self.testbed.uevent(dev, 'change')
+ time.sleep(0.5)
+ self.assertEqual(self.get_dbus_dev_property(mousebat0_up, 'Percentage'), 5)
+
+ self.testbed.set_attribute(dev, 'capacity_level', 'Low\n')
+ self.testbed.uevent(dev, 'change')
+ time.sleep(0.5)
+ self.assertEqual(self.get_dbus_dev_property(mousebat0_up, 'Percentage'), 10)
+
+ self.testbed.set_attribute(dev, 'capacity_level', 'High\n')
+ self.testbed.uevent(dev, 'change')
+ time.sleep(0.5)
+ self.assertEqual(self.get_dbus_dev_property(mousebat0_up, 'Percentage'), 70)
+
+ self.testbed.set_attribute(dev, 'capacity_level', 'Normal\n')
+ self.testbed.uevent(dev, 'change')
+ time.sleep(0.5)
+ self.assertEqual(self.get_dbus_dev_property(mousebat0_up, 'Percentage'), 55)
+
+ self.stop_daemon()
+
def test_bluetooth_hid_mouse(self):
'''bluetooth HID mouse battery'''
diff --git a/src/linux/up-device-supply.c b/src/linux/up-device-supply.c
index 5659bca..44c2f79 100644
--- a/src/linux/up-device-supply.c
+++ b/src/linux/up-device-supply.c
@@ -476,6 +476,36 @@ up_device_supply_get_state (const gchar *native_path)
return state;
}
+static gdouble
+sysfs_get_capacity_level (const char *native_path)
+{
+ char *level;
+ gdouble ret = -1.0;
+ guint i;
+ struct {
+ const char *level;
+ gdouble percentage;
+ } levels[] = {
+ /* In order of most likely to least likely */
+ { "Normal", 55.0 },
+ { "High", 70.0 },
+ { "Low", 20.0 },
+ { "Critical", 5.0 },
+ { "Full", 100.0 }
+ };
+
+ level = sysfs_get_string (native_path, "capacity_level");
+ for (i = 0; i < G_N_ELEMENTS(levels); i++) {
+ if (g_ascii_strncasecmp (levels[i].level, level, strlen (levels[i].level)) == 0) {
+ ret = levels[i].percentage;
+ break;
+ }
+ }
+
+ g_free (level);
+ return ret;
+}
+
/**
* up_device_supply_refresh_battery:
*
@@ -858,6 +888,9 @@ up_device_supply_refresh_device (UpDeviceSupply *supply,
/* get a precise percentage */
percentage = sysfs_get_double_with_error (native_path, "capacity");
+ if (percentage < 0.0)
+ percentage = sysfs_get_capacity_level (native_path);
+
if (percentage < 0.0) {
/* Probably talking to the device over Bluetooth */
state = UP_DEVICE_STATE_UNKNOWN;
@@ -1036,7 +1069,8 @@ up_device_supply_coldplug (UpDevice *device)
/* we don't use separate ACs for devices */
if (supply->priv->is_power_supply == FALSE &&
- !sysfs_file_exists (native_path, "capacity")) {
+ !sysfs_file_exists (native_path, "capacity") &&
+ !sysfs_file_exists (native_path, "capacity_level")) {
g_debug ("Ignoring device AC, we'll monitor the device battery");
return FALSE;
}