linux: up-enumerator-udev: Process add, change, and remove udev events for keyboard backlight device

Add, update, and remove the keyboard backlight LED device when receiving
add, change, and remove udev events.
This commit is contained in:
Kate Hsuan 2025-03-11 17:18:50 +08:00
parent e01aa7c903
commit fd6eebb397

View file

@ -31,6 +31,7 @@
#include "up-device-supply-battery.h" #include "up-device-supply-battery.h"
#include "up-device-hid.h" #include "up-device-hid.h"
#include "up-device-wup.h" #include "up-device-wup.h"
#include "up-kbd-backlight-led.h"
#ifdef HAVE_IDEVICE #ifdef HAVE_IDEVICE
#include "up-device-idevice.h" #include "up-device-idevice.h"
#endif /* HAVE_IDEVICE */ #endif /* HAVE_IDEVICE */
@ -217,39 +218,13 @@ emit_changes_for_siblings (UpEnumeratorUdev *self,
} }
static void static void
uevent_signal_handler_cb (UpEnumeratorUdev *self, power_supply_add_helper (UpEnumeratorUdev *self,
const gchar *action, const gchar *action,
GUdevDevice *device, GUdevDevice *device,
GUdevClient *client) GUdevClient *client,
GObject *obj,
const gchar *device_key)
{ {
const char *device_key = g_udev_device_get_sysfs_path (device);
g_debug ("Received uevent %s on device %s", action, device_key);
/* Work around the fact that we don't get a REMOVE event in some cases. */
if (g_strcmp0 (g_udev_device_get_subsystem (device), "power_supply") == 0)
device_key = g_udev_device_get_name (device);
/* It appears that we may not always receive an "add" event. As such,
* treat "add"/"change" in the same way, by first checking if we have
* seen the device.
* Even worse, we may not get a "remove" event in some odd cases, so
* if there is an "add" but we find the device (as the power_supply
* node has the same name), then remove it first before adding the
* new one.
*/
if (g_strcmp0 (action, "change") == 0 || g_strcmp0 (action, "add") == 0) {
GObject *obj;
obj = g_hash_table_lookup (self->known, device_key);
if (UP_IS_DEVICE (obj) && g_strcmp0 (action, "add") == 0 &&
g_strcmp0 (g_udev_device_get_sysfs_path (device),
g_udev_device_get_sysfs_path (G_UDEV_DEVICE (up_device_get_native (UP_DEVICE (obj))))) != 0) {
uevent_signal_handler_cb (self, "remove", device, client);
obj = NULL;
}
if (!obj) {
g_autoptr(UpDevice) up_dev = NULL; g_autoptr(UpDevice) up_dev = NULL;
g_autofree char *parent_id = NULL; g_autofree char *parent_id = NULL;
@ -300,6 +275,83 @@ uevent_signal_handler_cb (UpEnumeratorUdev *self,
if (up_dev) if (up_dev)
g_signal_emit_by_name (self, "device-added", up_dev); g_signal_emit_by_name (self, "device-added", up_dev);
}
static void
kbd_backlight_add_helper (UpEnumeratorUdev *self,
const gchar *action,
GUdevDevice *device,
GUdevClient *client,
GObject *obj,
const char *device_key)
{
UpDaemon *daemon;
g_autoptr(UpDeviceKbdBacklight) up_kbd = NULL;
g_autofree char *parent_id = NULL;
daemon = up_enumerator_get_daemon (UP_ENUMERATOR (self));
up_kbd = g_initable_new (UP_TYPE_KBD_BACKLIGHT_LED, NULL, NULL,
"daemon", daemon,
"native", device,
NULL);
if (up_kbd)
obj = G_OBJECT (up_kbd);
else
obj = G_OBJECT (device);
g_hash_table_insert (self->known, (char*) device_key, g_object_ref (obj));
if (up_kbd)
g_signal_emit_by_name (self, "device-added", G_OBJECT (up_kbd));
}
static void
uevent_signal_handler_cb (UpEnumeratorUdev *self,
const gchar *action,
GUdevDevice *device,
GUdevClient *client)
{
const char *device_key = g_udev_device_get_sysfs_path (device);
gboolean is_kbd_backlight = FALSE;
g_debug ("Received uevent %s on device %s", action, device_key);
/* Work around the fact that we don't get a REMOVE event in some cases. */
if (g_strcmp0 (g_udev_device_get_subsystem (device), "power_supply") == 0)
device_key = g_udev_device_get_name (device);
if (g_strcmp0 (g_udev_device_get_subsystem (device), "leds") == 0) {
if (g_strrstr (device_key, "kbd_backlight") == NULL)
return;
is_kbd_backlight = TRUE;
}
g_debug ("uevent subsystem %s", g_udev_device_get_subsystem (device));
/* It appears that we may not always receive an "add" event. As such,
* treat "add"/"change" in the same way, by first checking if we have
* seen the device.
* Even worse, we may not get a "remove" event in some odd cases, so
* if there is an "add" but we find the device (as the power_supply
* node has the same name), then remove it first before adding the
* new one.
*/
if (g_strcmp0 (action, "change") == 0 || g_strcmp0 (action, "add") == 0) {
GObject *obj;
obj = g_hash_table_lookup (self->known, device_key);
if (UP_IS_DEVICE (obj) && g_strcmp0 (action, "add") == 0 &&
g_strcmp0 (g_udev_device_get_sysfs_path (device),
g_udev_device_get_sysfs_path (G_UDEV_DEVICE (up_device_get_native (UP_DEVICE (obj))))) != 0) {
uevent_signal_handler_cb (self, "remove", device, client);
obj = NULL;
}
if (!obj) {
if (is_kbd_backlight)
kbd_backlight_add_helper (self, action, device, client, obj, device_key);
else
power_supply_add_helper (self, action, device, client, obj, device_key);
} else { } else {
if (!UP_IS_DEVICE (obj)) { if (!UP_IS_DEVICE (obj)) {
@ -326,6 +378,11 @@ uevent_signal_handler_cb (UpEnumeratorUdev *self,
g_debug ("removing device for path %s", g_udev_device_get_sysfs_path (device)); g_debug ("removing device for path %s", g_udev_device_get_sysfs_path (device));
if (is_kbd_backlight) {
g_signal_emit_by_name (self, "device-removed", obj);
return;
}
parent_id = g_object_get_data (obj, "udev-parent-id"); parent_id = g_object_get_data (obj, "udev-parent-id");
/* Remove from siblings table. */ /* Remove from siblings table. */