Hi, On Sat, Feb 28, 2026 at 03:52:58PM +0100, Hans de Goede wrote: > Elan touchscreens have a HID-battery device for the stylus which is always > there even if there is no stylus. > > This is causing upower to report an empty battery for the stylus and some > desktop-environments will show a notification about this, which is quite > annoying. > > Because of this the HID-battery is being ignored on all Elan I2c and USB > touchscreens, but this causes there to be no battery reporting for > the stylus at all. > > This adds a new HID_BATTERY_QUIRK_DYNAMIC and uses these for the Elan > touchscreens. > > This new quirks causes the present value of the battery to start at 0, > which will make userspace ignore it and only sets present to 1 after > receiving a battery input report which only happens when the stylus > gets in range. > > Reported-by: ggrundik@gmail.com > Closes: https://bugzilla.kernel.org/show_bug.cgi?id=221118 > Signed-off-by: Hans de Goede > --- Reviewed-by: Sebastian Reichel -- Sebastian > drivers/hid/hid-input.c | 14 +++++++++++--- > include/linux/hid.h | 1 + > 2 files changed, 12 insertions(+), 3 deletions(-) > > diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c > index 67ca1e88ce13..8fc20df99b97 100644 > --- a/drivers/hid/hid-input.c > +++ b/drivers/hid/hid-input.c > @@ -354,6 +354,7 @@ static enum power_supply_property hidinput_battery_props[] = { > #define HID_BATTERY_QUIRK_FEATURE (1 << 1) /* ask for feature report */ > #define HID_BATTERY_QUIRK_IGNORE (1 << 2) /* completely ignore the battery */ > #define HID_BATTERY_QUIRK_AVOID_QUERY (1 << 3) /* do not query the battery */ > +#define HID_BATTERY_QUIRK_DYNAMIC (1 << 4) /* report present only after life signs */ > > static const struct hid_device_id hid_battery_quirks[] = { > { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, > @@ -398,8 +399,8 @@ static const struct hid_device_id hid_battery_quirks[] = { > * Elan HID touchscreens seem to all report a non present battery, > * set HID_BATTERY_QUIRK_IGNORE for all Elan I2C and USB HID devices. > */ > - { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, HID_ANY_ID), HID_BATTERY_QUIRK_IGNORE }, > - { HID_USB_DEVICE(USB_VENDOR_ID_ELAN, HID_ANY_ID), HID_BATTERY_QUIRK_IGNORE }, > + { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, HID_ANY_ID), HID_BATTERY_QUIRK_DYNAMIC }, > + { HID_USB_DEVICE(USB_VENDOR_ID_ELAN, HID_ANY_ID), HID_BATTERY_QUIRK_DYNAMIC }, > {} > }; > > @@ -456,11 +457,14 @@ static int hidinput_get_battery_property(struct power_supply *psy, > int ret = 0; > > switch (prop) { > - case POWER_SUPPLY_PROP_PRESENT: > case POWER_SUPPLY_PROP_ONLINE: > val->intval = 1; > break; > > + case POWER_SUPPLY_PROP_PRESENT: > + val->intval = dev->battery_present; > + break; > + > case POWER_SUPPLY_PROP_CAPACITY: > if (dev->battery_status != HID_BATTERY_REPORTED && > !dev->battery_avoid_query) { > @@ -573,6 +577,8 @@ static int hidinput_setup_battery(struct hid_device *dev, unsigned report_type, > if (quirks & HID_BATTERY_QUIRK_AVOID_QUERY) > dev->battery_avoid_query = true; > > + dev->battery_present = (quirks & HID_BATTERY_QUIRK_DYNAMIC) ? false : true; > + > dev->battery = power_supply_register(&dev->dev, psy_desc, &psy_cfg); > if (IS_ERR(dev->battery)) { > error = PTR_ERR(dev->battery); > @@ -628,6 +634,7 @@ static void hidinput_update_battery(struct hid_device *dev, unsigned int usage, > return; > > if (hidinput_update_battery_charge_status(dev, usage, value)) { > + dev->battery_present = true; > power_supply_changed(dev->battery); > return; > } > @@ -643,6 +650,7 @@ static void hidinput_update_battery(struct hid_device *dev, unsigned int usage, > if (dev->battery_status != HID_BATTERY_REPORTED || > capacity != dev->battery_capacity || > ktime_after(ktime_get_coarse(), dev->battery_ratelimit_time)) { > + dev->battery_present = true; > dev->battery_capacity = capacity; > dev->battery_status = HID_BATTERY_REPORTED; > dev->battery_ratelimit_time = > diff --git a/include/linux/hid.h b/include/linux/hid.h > index dce862cafbbd..d9b54f0e8671 100644 > --- a/include/linux/hid.h > +++ b/include/linux/hid.h > @@ -682,6 +682,7 @@ struct hid_device { > __s32 battery_charge_status; > enum hid_battery_status battery_status; > bool battery_avoid_query; > + bool battery_present; > ktime_t battery_ratelimit_time; > #endif > > -- > 2.52.0