All of lore.kernel.org
 help / color / mirror / Atom feed
From: Denis Benato <denis.benato@linux.dev>
To: Antheas Kapenekakis <lkml@antheas.dev>,
	Denis Benato <benato.denis96@gmail.com>
Cc: linux-kernel@vger.kernel.org, linux-input@vger.kernel.org,
	Benjamin Tissoires <bentiss@kernel.org>,
	Jiri Kosina <jikos@kernel.org>,
	"Luke D . Jones" <luke@ljones.dev>,
	Mateusz Schyboll <dragonn@op.pl>
Subject: Re: [PATCH v2 3/4] HID: asus: add support for xgm led
Date: Sat, 13 Jun 2026 16:01:02 +0200	[thread overview]
Message-ID: <7e851a3f-b595-468f-b3b1-a4ffbb03f85d@linux.dev> (raw)
In-Reply-To: <CAGwozwE-EOdbJgKwUXth3S5Tzw4AcxJaMCjP=r0YUP5+TNnOkQ@mail.gmail.com>


On 6/13/26 02:30, Antheas Kapenekakis wrote:
> On Fri, 12 Jun 2026 at 17:56, Denis Benato <benato.denis96@gmail.com> wrote:
>>
>> On 6/12/26 16:39, Antheas Kapenekakis wrote:
>>> On Fri, 12 Jun 2026 at 16:23, Denis Benato <denis.benato@linux.dev> wrote:
>>>> XG mobile stations have very bright leds behind the fan that can be
>>>> turned either ON or OFF: add a cled interface to allow controlling the
>>>> brightness of those red leds.
>>>>
>>>> Signed-off-by: Denis Benato <denis.benato@linux.dev>
>>>> ---
>>>>  drivers/hid/hid-asus.c | 70 ++++++++++++++++++++++++++++++++++++++++++
>>>>  1 file changed, 70 insertions(+)
>>>>
>>>> diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c
>>>> index 323dc0b7f3ff..21c4a60d224e 100644
>>>> --- a/drivers/hid/hid-asus.c
>>>> +++ b/drivers/hid/hid-asus.c
>>>> @@ -51,6 +51,8 @@ MODULE_DESCRIPTION("Asus HID Keyboard and TouchPad");
>>>>  #define FEATURE_KBD_LED_REPORT_ID1 0x5d
>>>>  #define FEATURE_KBD_LED_REPORT_ID2 0x5e
>>>>
>>>> +#define ROG_XGM_REPORT_SIZE 300
>>>> +
>>>>  #define ROG_ALLY_REPORT_SIZE 64
>>>>  #define ROG_ALLY_X_MIN_MCU 313
>>>>  #define ROG_ALLY_MIN_MCU 319
>>>> @@ -118,6 +120,11 @@ struct asus_kbd_leds {
>>>>         bool removed;
>>>>  };
>>>>
>>>> +struct asus_xgm_led {
>>>> +       struct led_classdev cdev;
>>>> +       struct hid_device *hdev;
>>>> +};
>>>> +
>>>>  struct asus_touchpad_info {
>>>>         int max_x;
>>>>         int max_y;
>>>> @@ -143,6 +150,7 @@ struct asus_drvdata {
>>>>         unsigned long battery_next_query;
>>>>         struct work_struct fn_lock_sync_work;
>>>>         bool fn_lock;
>>>> +       struct asus_xgm_led *xgm_led;
>>>>  };
>>>>
>>>>  static int asus_report_battery(struct asus_drvdata *, u8 *, int);
>>>> @@ -941,6 +949,23 @@ static int asus_battery_probe(struct hid_device *hdev)
>>>>         return ret;
>>>>  }
>>>>
>>>> +static int asus_xgm_led_set(struct led_classdev *led_cdev, enum led_brightness value)
>>>> +{
>>>> +       const u8 buf[ROG_XGM_REPORT_SIZE] = {
>>>> +               FEATURE_KBD_LED_REPORT_ID2, 0xC5, (value) ? 0x50 : 0x00
>>>> +       };
>>>> +       struct asus_xgm_led *xgm = container_of(led_cdev, struct asus_xgm_led, cdev);
>>>> +       int ret;
>>>> +
>>>> +       ret = asus_kbd_set_report(xgm->hdev, buf, ROG_XGM_REPORT_SIZE);
>>>> +       if (ret != ROG_XGM_REPORT_SIZE) {
>>>> +               hid_err(xgm->hdev, "Unable to set XG mobile led state: %d\n", ret);
>>>> +               return ret;
>>>> +       }
>>>> +
>>>> +       return 0;
>>>> +}
>>>> +
>>>>  static int asus_input_configured(struct hid_device *hdev, struct hid_input *hi)
>>>>  {
>>>>         struct input_dev *input = hi->input;
>>>> @@ -1184,6 +1209,14 @@ static int __maybe_unused asus_resume(struct hid_device *hdev)
> I might have confused the hunk here and you are right, input
> configured is above.
>
>>>>                 }
>>>>         }
>>>>
>>>> +       if (drvdata->xgm_led) {
>>>> +               ret = asus_xgm_led_set(&drvdata->xgm_led->cdev, drvdata->xgm_led->cdev.brightness);
>>>> +               if (ret) {
>>>> +                       hid_err(hdev, "Asus failed to restore xgm brightness: %d\n", ret);
>>>> +                       goto asus_resume_err;
>>>> +               }
>>>> +       }
>>>> +
>>>>  asus_resume_err:
>>>>         return ret;
>>>>  }
>>>> @@ -1310,6 +1343,40 @@ static int asus_probe(struct hid_device *hdev, const struct hid_device_id *id)
>>>>                 }
>>>>         }
>>>>
>>>> +       if (asus_has_report_id(hdev, FEATURE_KBD_REPORT_ID) &&
>>>> +           ((hdev->product == USB_DEVICE_ID_ASUSTEK_XGM_2022) ||
>>>> +            (hdev->product == USB_DEVICE_ID_ASUSTEK_XGM_2023))) {
>>>> +               drvdata->xgm_led = devm_kzalloc(&hdev->dev, sizeof(*drvdata->xgm_led), GFP_KERNEL);
>>>> +               if (drvdata->xgm_led == NULL) {
>>>> +                       ret = -ENOMEM;
>>>> +                       goto err_stop_hw;
>>>> +               }
>>>> +               drvdata->xgm_led->hdev = hdev;
>>>> +               drvdata->xgm_led->cdev.name = devm_kasprintf(&hdev->dev, GFP_KERNEL,
>>>> +                                       "asus:xgm-%s:led",
>>>> +                                       strlen(hdev->uniq) ?
>>>> +                                       hdev->uniq : dev_name(&hdev->dev));
>>>> +               drvdata->xgm_led->cdev.brightness = 1;
>>>> +               drvdata->xgm_led->cdev.max_brightness = 1;
>>>> +               drvdata->xgm_led->cdev.brightness_set_blocking = asus_xgm_led_set;
>>>> +
>>>> +               /*
>>>> +                * Sometimes after a reboot LEDs are ON, sometimes are OFF: set them to
>>>> +                * what the default brightness resets when doing a cold boot.
>>>> +                */
>>> I think this is set by the driver, so you should reformat the comment
>>> above, so you should trim the comment.
>>>
>>> Perhaps, "The LED state is arbitrary on boot, therefore default to the
>>> initial brightness set above". This way it does not become outdated if
>>> cdev.brightness changes.
>> yeah better spelling. I agree.
>>>> +               ret = asus_xgm_led_set(&drvdata->xgm_led->cdev, drvdata->xgm_led->cdev.brightness);
>>>> +               if (ret) {
>>>> +                       hid_err(hdev, "Asus failed to set xgm led: %d\n", ret);
>>>> +                       goto err_stop_hw;
>>>> +               }
>>> You already do this in asus_input_configured so you do it twice?
>>> Perhaps skip one if you end up keeping them? I think that it's better
>>> to keep this block.
>> In asus_input_configured? Will take a look in the next days. I tought
>> the other was in asus_resume since at resume they resets back...
>>> Or even better return an error in _get so that on boot it is
>>> ambiguous? I assume the leds remain to the state they had prior to the
>>> reboot? With this change, imagine a user that turned off the leds in
>>> windows, permabooted into Linux, and now has the lights always turn on
>>> during boot.
>> Cold boot sets them to ON, while rebooting keep them at what they were.
>>
>> After exiting from sleep they are always ON, but this is on an ally,
>> I don't know if on an old rog flow it's the same.
>>> Moreover, can systemd restore this or is it out of scope for its led
>>> handler? Perhaps it is an ambitious idea though, and better skipped.
>> I don't see realistic for this to fail if it was successful at probe so it
>> shouldn't matter. As for systemd restoring them it would have to
>> be informed that they changed (but there is no read-back) so either
>> way something has to happen at resume, but doing this means no
>> additional software is necessary and user preference is being
>> respected regardless of anything else.
> Ok, so xg mobile is the first generation gpu dock with the wide
> connector, which is why it is i2c. It's probably from the side port.
You are correct in the connector: it is a pci-e custom connector with
an usb-c on the side.

That's not i2c: it's usb-c and it is basically a usb-c hub with others
usb connectors on the dock, a 2.5Gbps ethernet and the controller
device.
> So, when it initializes in general it enables the leds. And it
> initializes on boot and on wake. And it has no memory.
From what I can see I can say I have no idea, if this was 100% correct
I wouldn't see leds staying OFF after a reboot since the driver
does a reinit of the device.

These devices have leds entering a blinking pattern while the main device
is in s2idle and the ACPI has specific code for these devices.

It's what egpu_enable enables: the pci-e part of the device (usb-c
part is always enabled).

These devices heavily rely on ACPI, even if they are external so I'm
trying to reduce assumptions here.
> For not setting the led, you could return an error on reads if the
> brightness has not been written yet and if it has return a cached
> value / restore on awake. You can store the brightness in the struct
> below xgm_led, e.g., xgm_led_val, and initialize it to -1. If it is
> -1, get would return the same error you did for battery capacity in
> asus-wmi
Yes, I could do that, but considering this is just a simple ON/OFF switch,
where the device has no memory (even sleeping changes the status),
three times (even on windows):
sleep enter: whatever -> blinking
sleep exit: blinking -> ON
after some milliseconds: ON -> whatever was set before

I don't see anything to be gained by not setting it in _probe:
no memory write to spare, no delayed effect.

The cost of additional code that would be the same as the default _get
implementation just to throw an error is one I can't justify.
> In that case, you would remove the init from probe. Otherwise, the
> current patch with a small tweak to the comment if you do a revision
> is fine by me
>
> Reviewed by: Antheas Kapenekakis <lkml@antheas.dev>
Alright, thank you
>>>> +
>>>> +               ret = led_classdev_register(&hdev->dev, &drvdata->xgm_led->cdev);
>>>> +               if (ret) {
>>>> +                       hid_err(hdev, "Asus failed to register xgm led: %d\n", ret);
>>>> +                       goto err_stop_hw;
>>>> +               }
>>>> +       }
>>>> +
>>>>         /* Laptops keyboard backlight is always at 0x5a */
>>>>         if (is_vendor && (drvdata->quirks & QUIRK_USE_KBD_BACKLIGHT) &&
>>>>             (asus_has_report_id(hdev, FEATURE_KBD_REPORT_ID)) &&
>>>> @@ -1366,6 +1433,9 @@ static void asus_remove(struct hid_device *hdev)
>>>>         if (drvdata->quirks & QUIRK_HID_FN_LOCK)
>>>>                 cancel_work_sync(&drvdata->fn_lock_sync_work);
>>>>
>>>> +       if (drvdata->xgm_led)
>>>> +               led_classdev_unregister(&drvdata->xgm_led->cdev);
>>>> +
>>>>         hid_hw_stop(hdev);
>>>>  }
>>>>
>>>> --
>>>> 2.47.3
>>>>
>>>>
>> Thanks,
>> Denis
>>

  reply	other threads:[~2026-06-13 14:02 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-06-12 14:23 [PATCH v2 0/4] HID: asus: security fixes and more hardware support Denis Benato
2026-06-12 14:23 ` [PATCH v2 1/4] HID: asus: mitigate possible use-after-free Denis Benato
2026-06-12 14:44   ` Antheas Kapenekakis
2026-06-12 14:23 ` [PATCH v2 2/4] HID: asus: prevent wrong pointer cast Denis Benato
2026-06-12 14:38   ` sashiko-bot
2026-06-12 14:48   ` Antheas Kapenekakis
2026-06-12 14:23 ` [PATCH v2 3/4] HID: asus: add support for xgm led Denis Benato
2026-06-12 14:37   ` sashiko-bot
2026-06-12 14:39   ` Antheas Kapenekakis
2026-06-12 15:56     ` Denis Benato
2026-06-13  0:30       ` Antheas Kapenekakis
2026-06-13 14:01         ` Denis Benato [this message]
2026-06-12 14:23 ` [PATCH v2 4/4] HID: asus: add i2c entry for FA808UM and other TUFs Denis Benato
2026-06-12 14:37   ` sashiko-bot
2026-06-13 13:22     ` Denis Benato

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=7e851a3f-b595-468f-b3b1-a4ffbb03f85d@linux.dev \
    --to=denis.benato@linux.dev \
    --cc=benato.denis96@gmail.com \
    --cc=bentiss@kernel.org \
    --cc=dragonn@op.pl \
    --cc=jikos@kernel.org \
    --cc=linux-input@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=lkml@antheas.dev \
    --cc=luke@ljones.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.