Subject: upower: bluetooth HID keyboard shows up as laptop battery Package: upower Version: 0.99.1-3.1 Severity: normal
Dear Maintainer, The UPower battery detection system incorrectly assumes that Bluetooth keyboards have an "input" node immediately underneath the "bluetooth" node. With HID devices, the "input" node exists under a subsequent "hid" node. Because of this, Bluetooth HID batteries will appear as full laptop batteries, and upower will incorrectly assume main power is dying when the laptop keyboard runs low on power. This bug has been reported upstream, but no action has been taken: https://bugs.freedesktop.org/show_bug.cgi?id=86510 The attached patch solves the problem. -- System Information: Debian Release: jessie/sid APT prefers testing APT policy: (500, 'testing') Architecture: armhf (armv7l) Kernel: Linux 3.17.0-rc5-00226-gdcb0c37 (SMP w/4 CPU cores; PREEMPT) Locale: LANG=en_SG.UTF-8, LC_CTYPE=en_SG.UTF-8 (charmap=UTF-8) Shell: /bin/sh linked to /bin/dash Versions of packages upower depends on: ii dbus 1.8.12-1 ii libc6 2.19-13 ii libdbus-1-3 1.8.12-1 ii libdbus-glib-1-2 0.102-1 ii libglib2.0-0 2.42.0-2 ii libgudev-1.0-0 215-7 ii libimobiledevice4 1.1.6+dfsg-3.1 ii libplist2 1.11-3 ii libupower-glib3 0.99.1-3.1 ii libusb-1.0-0 2:1.0.19-1 ii udev 215-7 Versions of packages upower recommends: ii policykit-1 0.105-8 upower suggests no packages. -- no debconf information
Description: Add support for batteries on HID devices HID keyboards can be attached via Bluetooth or USB, but are in a separate class from both. Upower will reach too far up the ownership chain, and won't be able to detect the input device. As a result, keyboards will show up as the main battery. . This patch adds support for creating a chain of classes to look for input data, and places "hid" in front of "bluetooth". . upower (0.99.1-3.1) unstable; urgency=medium . * Non-maintainer upload. * Add support for HID keyboards Author: Sean Cross <x...@kosagi.com> --- upower-0.99.1.orig/src/linux/up-device-supply.c +++ upower-0.99.1/src/linux/up-device-supply.c @@ -902,6 +902,39 @@ up_device_supply_poll_unknown_battery (U return FALSE; } +static gchar * +up_device_get_input_path (GUdevDevice *native, const gchar *type) +{ + GUdevDevice *dev; + gchar *input_path = NULL; + const gchar *device_path = NULL; + GError *error = NULL; + GDir *dir = NULL; + const gchar *file; + + /* Detect if the battery comes from bluetooth keyboard or mouse. */ + dev = g_udev_device_get_parent_with_subsystem (native, type, NULL); + if (dev != NULL) { + device_path = g_udev_device_get_sysfs_path (dev); + if ((dir = g_dir_open (device_path, 0, &error))) { + while ((file = g_dir_read_name (dir))) { + /* Check if it is an input device. */ + if (g_str_has_prefix (file, "input")) { + input_path = g_build_filename (device_path, file, NULL); + break; + } + } + g_dir_close (dir); + } else { + g_warning ("Can not open folder %s: %s", device_path, error->message); + g_error_free (error); + } + g_object_unref (dev); + } + + return input_path; +} + /** * up_device_supply_coldplug: * @@ -912,10 +945,8 @@ up_device_supply_coldplug (UpDevice *dev { UpDeviceSupply *supply = UP_DEVICE_SUPPLY (device); gboolean ret = FALSE; - GUdevDevice *bluetooth; GUdevDevice *native; const gchar *file; - const gchar *device_path = NULL; const gchar *native_path; const gchar *scope; gchar *device_type = NULL; @@ -959,43 +990,32 @@ up_device_supply_coldplug (UpDevice *dev type = UP_DEVICE_KIND_LINE_POWER; } else if (g_ascii_strcasecmp (device_type, "battery") == 0) { - /* Detect if the battery comes from bluetooth keyboard or mouse. */ - bluetooth = g_udev_device_get_parent_with_subsystem (native, "bluetooth", NULL); - if (bluetooth != NULL) { - device_path = g_udev_device_get_sysfs_path (bluetooth); - if ((dir = g_dir_open (device_path, 0, &error))) { - while ((file = g_dir_read_name (dir))) { - /* Check if it is an input device. */ - if (g_str_has_prefix (file, "input")) { - input_path = g_build_filename (device_path, file, NULL); - break; + int i; + const char *classes[] = {"hid", "bluetooth"}; + int num_classes = sizeof(classes) / sizeof(*classes); + + for (i = 0; i < num_classes && type == UP_DEVICE_KIND_UNKNOWN; i++) { + + input_path = up_device_get_input_path (native, classes[i]); + + if (input_path != NULL) { + if ((dir = g_dir_open (input_path, 0, &error))) { + while ((file = g_dir_read_name (dir))) { + /* Check if it is a mouse device. */ + if (g_str_has_prefix (file, "mouse")) { + type = UP_DEVICE_KIND_MOUSE; + break; + } } + g_dir_close (dir); + } else { + g_warning ("Can not open folder %s: %s", input_path, error->message); + g_error_free (error); } - g_dir_close (dir); - } else { - g_warning ("Can not open folder %s: %s", device_path, error->message); - g_error_free (error); - } - g_object_unref (bluetooth); - } - - if (input_path != NULL) { - if ((dir = g_dir_open (input_path, 0, &error))) { - while ((file = g_dir_read_name (dir))) { - /* Check if it is a mouse device. */ - if (g_str_has_prefix (file, "mouse")) { - type = UP_DEVICE_KIND_MOUSE; - break; - } + g_free (input_path); + if (type == UP_DEVICE_KIND_UNKNOWN) { + type = UP_DEVICE_KIND_KEYBOARD; } - g_dir_close (dir); - } else { - g_warning ("Can not open folder %s: %s", input_path, error->message); - g_error_free (error); - } - g_free (input_path); - if (type == UP_DEVICE_KIND_UNKNOWN) { - type = UP_DEVICE_KIND_KEYBOARD; } }