From nobody Mon Feb 9 11:47:31 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 033F0319615 for ; Fri, 26 Dec 2025 11:10:35 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1766747437; cv=none; b=ZZF8nCZSwvYX0+Leo1UTXKIn258/Yo2bewqjsqcjWz7ZNANhlyEuaTvdrvZLrHywq9XgqbRLmMUAfj3FItj9Ft7fjrNwiIFQBco+Y53MTfhGzVS9N7SKLBwM//hTqXVatr09YllmEWq08BzxpOuHHy6dqMBlqpF2iVDj2fM7lNM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1766747437; c=relaxed/simple; bh=Rn1+K+oDKCqxE1iwfPRSHgU9Q3fMkg2TcTCaOkKZL0U=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Mi+jnrjkr2PgHo59DF3Tr6/zygKvBc/vr9qmo6IQwikZOqvVnlfT5f6BTcXSzWdeduVSTYLZbxh3/ELQMeNLBwHk3MtSV7OeYMuylHUY55y+I+0hBZ4vrIaXR/gRxEBFLGXHPUTAuJWLvkdRIHCnoMkAy34cC6KRNox2oXiGGo0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=NJ3NyBpq; dkim=pass (2048-bit key) header.d=redhat.com header.i=@redhat.com header.b=pqZ6lj/O; arc=none smtp.client-ip=170.10.129.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="NJ3NyBpq"; dkim=pass (2048-bit key) header.d=redhat.com header.i=@redhat.com header.b="pqZ6lj/O" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1766747434; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=QoSNpVz84k6O+emje+qv97k+nCpKT4dVeE4/DACkgMQ=; b=NJ3NyBpqNfPxEfxccRStz4x3qV1nNXxpXNIs3yI5w4bRUf76LpF5TfqpdaPNwGpCAKM/PK UG4OUhTcXbVI2JAhjcATQA3hE0OBaakac7xQPB2A+Htidh8oaaxXjfHcTzEeTv7iRVt8hd CAEp7D0kO1xL5JhI5KO1rnttg25+HMM= Received: from mail-wm1-f72.google.com (mail-wm1-f72.google.com [209.85.128.72]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-553-cOEB67ofOEiUAkQfuC0ZEA-1; Fri, 26 Dec 2025 06:10:33 -0500 X-MC-Unique: cOEB67ofOEiUAkQfuC0ZEA-1 X-Mimecast-MFC-AGG-ID: cOEB67ofOEiUAkQfuC0ZEA_1766747432 Received: by mail-wm1-f72.google.com with SMTP id 5b1f17b1804b1-477563e531cso47912935e9.1 for ; Fri, 26 Dec 2025 03:10:33 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=google; t=1766747432; x=1767352232; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=QoSNpVz84k6O+emje+qv97k+nCpKT4dVeE4/DACkgMQ=; b=pqZ6lj/OLoFocslTEH3kAF4ZhfNDyN00yUtJx10C9HMQCHsupBs5S4t0yEzfW4rhf8 RFtTU8pxptMlZcp5PuvbbWHLm7KBLCmUYEGm3DdwAKGdTJGjTNztiXUlP3b+8jGSpZq5 4jQ1xSW5Sev/tntqLdmPh1OwM7va0eYgTgvDpG5LO2tWUJlrXaYffw7rZ1FvWH56u8N0 cv4CVqXmv27uIpvaz9QFPNq7pu0jXP6YtzhM15b9vCWkWSWcV2u2tBXT9dnRl/KaSu6Y /6HavkpePZbx5/87Y+MdWlF5Xl51DFULNl0KoMBQlvGGJ4LRqPuoIlMWMfRct2v76diP 14Kw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1766747432; x=1767352232; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=QoSNpVz84k6O+emje+qv97k+nCpKT4dVeE4/DACkgMQ=; b=sqxZkT99HMpd8mQ+YyzFZCDlhF3kzDxwwjmB1OLs/jK30Npcb0JggoTI0sEqRU5kzS uWUsQnjRiix65ZEMwh+ilWiCmyn/WU6M1TzJuNYue3wcGntneYle00pNa+6Q4RMdzQLZ qZQgz7A/DQOHnVj+k0UNP2xB5gKpQgTm5WN5gPVHF63YtwiV1+XdjX2s9VrllkCLz1G4 NhiMA95JNKKVy8/LqqrB8kY4XsHwdw0bFA/VPHzey8FPsnBlZAWH5rXZQpaQeQKigtLC FiCD3DsbxUAQhPx34ZUusQFBQeBN3zNJ46VGIXKJmlPCZRXycg2COnmOrvb2iaf6GwXu NgpA== X-Forwarded-Encrypted: i=1; AJvYcCWsI2EarkvSTI82JbmGnrCWcrMHEh2Mfp9m4lZepebIJqfJSefkTPII5kkrUi4lSVijw8ICHMj7mvLAiVU=@vger.kernel.org X-Gm-Message-State: AOJu0YzRv0cgpS6FKu3wBpVcIKRtRqOLEeReVt0XHpEAOmYE+naL7fxc 96UMPIY+CprB8lZDXEOfD/0w2Bm98gFBcPCibw22a1arlHa7nX5EKZ+zvb5MmkHKhhLnEMl6Hla tGE9KIaZ9fC7+zLzx1clfWmykKpeHTETk38SOf6bOWI14l5x5/gola5BHk1ausyjE7w== X-Gm-Gg: AY/fxX5FhYF3CElIznvhIkYTcFGQk7M9ty6bJsnSGLKsFMjYYypI8gQG49eqPFHqiDW psORVrVUxOCBqQK0uM1cwqR09F/t6MG/cLHYvu6d1gvKGNV5NA3uNPwKn+raU6iqILwHuftaWpy dnkbUTzhB/fip1sme6orJI0DxwciQhpi+ieXtibmXDgNB/oFRLZcmkAeflT0hVVZO1P9yklDj8/ dY9jLw8qH3KT1n7wD3VA/Ufxipakze9N+DHn4mPKiNOhXMM+9FY7grMBQ+XJx6SN+fUZqaF4iJ+ VjCivxP/nCS5eB5umnLdlZGwL+ufSxMXxRwwl+hIwsoDJ4/M54YeMRrIK0sX7ZCAmicIz8vxjLK 0/eGkoqVeXKycuZ9OCzYYKV+Fnb9dKfkhoYAy5I+3426GnRujH7NqS9RvyGfzUJSJ/fTSN0UAdc +qaTqn9ZTmdQ== X-Received: by 2002:a05:600c:4fd4:b0:46e:4a13:e6c6 with SMTP id 5b1f17b1804b1-47d1958a43fmr220086635e9.19.1766747432468; Fri, 26 Dec 2025 03:10:32 -0800 (PST) X-Google-Smtp-Source: AGHT+IEU4MGJHqxBEWn5UWS0CJv1A2i60wxgLqqXa5EqtmhmRyIjWHos23C9iDTSKsLczNxqr/tUVQ== X-Received: by 2002:a05:600c:4fd4:b0:46e:4a13:e6c6 with SMTP id 5b1f17b1804b1-47d1958a43fmr220083225e9.19.1766747427304; Fri, 26 Dec 2025 03:10:27 -0800 (PST) Received: from sissix.lzampier.com ([2a06:5900:814a:ab00:3725:2991:6cf3:b3aa]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-47d193d4e91sm375653855e9.13.2025.12.26.03.10.26 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 26 Dec 2025 03:10:26 -0800 (PST) From: Lucas Zampieri To: linux-input@vger.kernel.org Cc: Lucas Zampieri , linux-kernel@vger.kernel.org, Jiri Kosina , Benjamin Tissoires , Sebastian Reichel , Bastien Nocera , linux-pm@vger.kernel.org, lcasmz54@gmail.com Subject: [PATCH v6 3/3] HID: input: Add support for multiple batteries per device Date: Fri, 26 Dec 2025 11:10:16 +0000 Message-ID: <20251226111019.31243-4-lzampier@redhat.com> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20251226111019.31243-1-lzampier@redhat.com> References: <20251226111019.31243-1-lzampier@redhat.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add support for HID devices that report multiple batteries, each identified by its report ID. The hid_device->battery pointer is replaced with a batteries list. Batteries are named using the pattern hid-{uniq}-battery-{report_id}. The hid_get_battery() helper returns the first battery in the list for backwards compatibility with single-battery drivers. Signed-off-by: Lucas Zampieri --- drivers/hid/hid-core.c | 4 ++++ drivers/hid/hid-input.c | 44 ++++++++++++++++++++++++++++------------- include/linux/hid.h | 11 ++++++++--- 3 files changed, 42 insertions(+), 17 deletions(-) diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index a5b3a8ca2fcb..76d628547e9a 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -2990,6 +2990,10 @@ struct hid_device *hid_allocate_device(void) mutex_init(&hdev->ll_open_lock); kref_init(&hdev->ref); =20 +#ifdef CONFIG_HID_BATTERY_STRENGTH + INIT_LIST_HEAD(&hdev->batteries); +#endif + ret =3D hid_bpf_device_init(hdev); if (ret) goto out_err; diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index c2d16236c638..445d6f160be8 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -511,6 +511,18 @@ static int hidinput_get_battery_property(struct power_= supply *psy, return ret; } =20 +static struct hid_battery *hidinput_find_battery(struct hid_device *dev, + int report_id) +{ + struct hid_battery *bat; + + list_for_each_entry(bat, &dev->batteries, list) { + if (bat->report_id =3D=3D report_id) + return bat; + } + return NULL; +} + static int hidinput_setup_battery(struct hid_device *dev, unsigned report_= type, struct hid_field *field, bool is_percentage) { @@ -521,13 +533,15 @@ static int hidinput_setup_battery(struct hid_device *= dev, unsigned report_type, s32 min, max; int error; =20 - if (dev->battery) - return 0; /* already initialized? */ + /* Check if battery for this report ID already exists */ + if (hidinput_find_battery(dev, field->report->id)) + return 0; =20 quirks =3D find_battery_quirk(dev); =20 - hid_dbg(dev, "device %x:%x:%x %d quirks %d\n", - dev->bus, dev->vendor, dev->product, dev->version, quirks); + hid_dbg(dev, "device %x:%x:%x %d quirks %d report_id %d\n", + dev->bus, dev->vendor, dev->product, dev->version, quirks, + field->report->id); =20 if (quirks & HID_BATTERY_QUIRK_IGNORE) return 0; @@ -542,9 +556,11 @@ static int hidinput_setup_battery(struct hid_device *d= ev, unsigned report_type, goto err_free_bat; } =20 - psy_desc->name =3D devm_kasprintf(&dev->dev, GFP_KERNEL, "hid-%s-battery", + psy_desc->name =3D devm_kasprintf(&dev->dev, GFP_KERNEL, + "hid-%s-battery-%d", strlen(dev->uniq) ? - dev->uniq : dev_name(&dev->dev)); + dev->uniq : dev_name(&dev->dev), + field->report->id); if (!psy_desc->name) { error =3D -ENOMEM; goto err_free_desc; @@ -595,7 +611,7 @@ static int hidinput_setup_battery(struct hid_device *de= v, unsigned report_type, } =20 power_supply_powers(bat->ps, &dev->dev); - dev->battery =3D bat; + list_add_tail(&bat->list, &dev->batteries); return 0; =20 err_free_name: @@ -604,7 +620,6 @@ static int hidinput_setup_battery(struct hid_device *de= v, unsigned report_type, devm_kfree(&dev->dev, psy_desc); err_free_bat: devm_kfree(&dev->dev, bat); - dev->battery =3D NULL; return error; } =20 @@ -622,12 +637,13 @@ static bool hidinput_update_battery_charge_status(str= uct hid_battery *bat, return false; } =20 -static void hidinput_update_battery(struct hid_device *dev, unsigned int u= sage, - int value) +static void hidinput_update_battery(struct hid_device *dev, int report_id, + unsigned int usage, int value) { - struct hid_battery *bat =3D dev->battery; + struct hid_battery *bat; int capacity; =20 + bat =3D hidinput_find_battery(dev, report_id); if (!bat) return; =20 @@ -661,8 +677,8 @@ static int hidinput_setup_battery(struct hid_device *de= v, unsigned report_type, return 0; } =20 -static void hidinput_update_battery(struct hid_device *dev, unsigned int u= sage, - int value) +static void hidinput_update_battery(struct hid_device *dev, int report_id, + unsigned int usage, int value) { } #endif /* CONFIG_HID_BATTERY_STRENGTH */ @@ -1530,7 +1546,7 @@ void hidinput_hid_event(struct hid_device *hid, struc= t hid_field *field, struct return; =20 if (usage->type =3D=3D EV_PWR) { - hidinput_update_battery(hid, usage->hid, value); + hidinput_update_battery(hid, report->id, usage->hid, value); return; } =20 diff --git a/include/linux/hid.h b/include/linux/hid.h index d14b867299c8..5069ef90cf7b 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -647,6 +647,7 @@ enum hid_battery_status { * @capacity: current battery capacity (0-100) * @avoid_query: if true, avoid querying battery (e.g., for stylus) * @ratelimit_time: rate limiting for battery reports + * @list: list node for linking into hid_device's battery list */ struct hid_battery { struct hid_device *dev; @@ -660,6 +661,7 @@ struct hid_battery { __s32 capacity; bool avoid_query; ktime_t ratelimit_time; + struct list_head list; }; =20 struct hid_driver; @@ -698,9 +700,10 @@ struct hid_device { #ifdef CONFIG_HID_BATTERY_STRENGTH /* * Power supply information for HID devices which report - * battery strength. battery is non-NULL if successfully registered. + * battery strength. Each battery is tracked separately in the + * batteries list. */ - struct hid_battery *battery; + struct list_head batteries; #endif =20 unsigned long status; /* see STAT flags above */ @@ -764,7 +767,9 @@ static inline void hid_set_drvdata(struct hid_device *h= dev, void *data) #ifdef CONFIG_HID_BATTERY_STRENGTH static inline struct hid_battery *hid_get_battery(struct hid_device *hdev) { - return hdev->battery; + if (list_empty(&hdev->batteries)) + return NULL; + return list_first_entry(&hdev->batteries, struct hid_battery, list); } #endif =20 --=20 2.52.0