From 1c735e5ddba814acc57a9d268ed7852bd4aa5887 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 8 Sep 2025 22:55:12 +0200 Subject: [PATCH] HID: hid-lg-g15: Add hw_brightness_changed support for the G510 keyboard Add hw_brightness_changed support for the G510 keyboard, so that e.g. GNOME will show an OSD notification when toggling the backlight on/off with the button the keyboard. Note that it is not possible to turn the backlight back on by writing /sys/class/leds/.../brightness it can only be turned on by pressing the button on the keyboard. To reflect this /sys/class/leds/.../brightness will always report the last brightness value independent of the on/off toggle built into the keyboard. Signed-off-by: Hans de Goede --- drivers/hid/hid-lg-g15.c | 37 ++++++++++++++++++++++++++++++++++--- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/drivers/hid/hid-lg-g15.c b/drivers/hid/hid-lg-g15.c index f8605656257b..e5be2a5dfa67 100644 --- a/drivers/hid/hid-lg-g15.c +++ b/drivers/hid/hid-lg-g15.c @@ -26,6 +26,9 @@ #define LG_G510_FEATURE_BACKLIGHT_RGB 0x05 #define LG_G510_FEATURE_POWER_ON_RGB 0x06 +#define LG_G510_INPUT_MACRO_KEYS 0x03 +#define LG_G510_INPUT_KBD_BACKLIGHT 0x04 + enum lg_g15_model { LG_G15, LG_G15_V2, @@ -67,6 +70,7 @@ struct lg_g15_data { enum lg_g15_model model; struct lg_g15_led leds[LG_G15_LED_MAX]; bool game_mode_enabled; + bool backlight_disabled; }; /******** G15 and G15 v2 LED functions ********/ @@ -227,6 +231,20 @@ static int lg_g510_get_initial_led_brightness(struct lg_g15_data *g15, int i) g15->leds[i].brightness = 0; } + if (i) + return 0; + + ret = hid_hw_raw_request(g15->hdev, LG_G510_INPUT_KBD_BACKLIGHT, + g15->transfer_buf, 2, + HID_INPUT_REPORT, HID_REQ_GET_REPORT); + if (ret != 2) { + /* This can happen when a KVM switch is used, so only warn. */ + hid_warn(g15->hdev, "Error getting backlight state: %d\n", ret); + return 0; + } + + g15->backlight_disabled = g15->transfer_buf[1] & 0x04; + return 0; } @@ -549,14 +567,24 @@ static int lg_g510_event(struct lg_g15_data *g15, u8 *data) static int lg_g510_leds_event(struct lg_g15_data *g15, u8 *data) { + struct lg_g15_led *g15_led = &g15->leds[LG_G15_KBD_BRIGHTNESS]; bool backlight_disabled; + backlight_disabled = data[1] & 0x04; + if (backlight_disabled == g15->backlight_disabled) + return 0; + + led_classdev_notify_brightness_hw_changed( + &g15_led->mcdev.led_cdev, + backlight_disabled ? 0 : g15_led->brightness); + + g15->backlight_disabled = backlight_disabled; + /* * The G510 ignores backlight updates when the backlight is turned off * through the light toggle button on the keyboard, to work around this * we queue a workitem to sync values when the backlight is turned on. */ - backlight_disabled = data[1] & 0x04; if (!backlight_disabled) schedule_work(&g15->work); @@ -588,9 +616,9 @@ static int lg_g15_raw_event(struct hid_device *hdev, struct hid_report *report, break; case LG_G510: case LG_G510_USB_AUDIO: - if (data[0] == 0x03 && size == 5) + if (data[0] == LG_G510_INPUT_MACRO_KEYS && size == 5) return lg_g510_event(g15, data); - if (data[0] == 0x04 && size == 2) + if (data[0] == LG_G510_INPUT_KBD_BACKLIGHT && size == 2) return lg_g510_leds_event(g15, data); break; } @@ -624,6 +652,9 @@ static void lg_g15_setup_led_rgb(struct lg_g15_data *g15, int index) g15->leds[index].mcdev.led_cdev.max_brightness = 255; g15->leds[index].mcdev.num_colors = 3; + if (index == LG_G15_KBD_BRIGHTNESS) + g15->leds[index].mcdev.led_cdev.flags = LED_BRIGHT_HW_CHANGED; + subled_info = devm_kcalloc(&g15->hdev->dev, 3, sizeof(*subled_info), GFP_KERNEL); if (!subled_info) return; -- 2.51.0