summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBastien Nocera <hadess@hadess.net>2023-06-30 10:17:33 +0200
committerBastien Nocera <hadess@hadess.net>2023-07-03 15:54:51 +0200
commitac68136b41a4d3e67b8776e7dfdb675e77e70bf6 (patch)
treef5884f69f4a9062cfd21d026ce776c9a9c046362
parentab116cda4a6e698a4f4b6128851452df38e42f2a (diff)
linux: Fix headsets type detection when hotplugged
When a UpDevice is finally created, it's possible that we've seen "add" events as well as "change" events for siblings. But as the "change" events don't create new unknown siblings to store, we have GUdevDevices from the original "add" event in that store. As the GUdevDevice documentation mentions: "By design, GUdevDevice will not react to changes for a device – it only contains a snapshot of information when the GUdevDevice object was created. To work with changes, you typically connect to the “uevent” signal on a GUdevClient and get a new GUdevDevice whenever an event happens." To avoid having to try and update the siblings store, fetch an updated GUdevDevice for the sibling we want to tell the core about, with the properties all updated. This fixes headsets plugged in after the daemon start being detected as keyboards when the sound card device is tagged with the form factor in a change event before the battery is exported. Closes: https://gitlab.freedesktop.org/upower/upower/-/issues/239
-rw-r--r--src/linux/up-enumerator-udev.c19
1 files changed, 17 insertions, 2 deletions
diff --git a/src/linux/up-enumerator-udev.c b/src/linux/up-enumerator-udev.c
index 97abaef..ef578e3 100644
--- a/src/linux/up-enumerator-udev.c
+++ b/src/linux/up-enumerator-udev.c
@@ -161,6 +161,18 @@ device_new (UpEnumeratorUdev *self, GUdevDevice *native)
}
}
+/* As GUdevDevice are static and do not update when the sysfs device
+ * changes, this helps get a GUdevDevice with updated properties */
+static GUdevDevice *
+get_latest_udev_device (UpEnumeratorUdev *self,
+ GObject *obj)
+{
+ const char *sysfs_path;
+
+ sysfs_path = g_udev_device_get_sysfs_path (G_UDEV_DEVICE (obj));
+ return g_udev_client_query_by_sysfs_path (self->udev, sysfs_path);
+}
+
static void
uevent_signal_handler_cb (UpEnumeratorUdev *self,
const gchar *action,
@@ -222,8 +234,11 @@ uevent_signal_handler_cb (UpEnumeratorUdev *self,
for (i = 0; i < devices->len; i++) {
GObject *sibling = g_ptr_array_index (devices, i);
- if (up_dev)
- up_device_sibling_discovered (up_dev, sibling);
+ if (up_dev) {
+ g_autoptr(GUdevDevice) d = get_latest_udev_device (self, sibling);
+ if (d)
+ up_device_sibling_discovered (up_dev, G_OBJECT (d));
+ }
if (UP_IS_DEVICE (sibling))
up_device_sibling_discovered (UP_DEVICE (sibling), obj);
}