* [PATCH v7 0/3] HID: Add support for multiple batteries per device
@ 2026-03-14 1:05 Lucas Zampieri
2026-03-14 1:05 ` [PATCH v7 1/3] HID: input: Convert battery code to devm_* Lucas Zampieri
` (3 more replies)
0 siblings, 4 replies; 6+ messages in thread
From: Lucas Zampieri @ 2026-03-14 1:05 UTC (permalink / raw)
To: linux-input
Cc: Lucas Zampieri, linux-kernel, Jiri Kosina, Benjamin Tissoires,
Sebastian Reichel, Bastien Nocera, linux-pm
This series adds support for HID devices with multiple batteries.
Currently, the HID battery reporting subsystem only supports one battery per
device. There are several devices with multiple batteries that would benefit
from this support:
- Gaming headsets with batteries in both the headset and charging dock
- Wireless earbuds with per-earbud batteries plus charging case
- Split keyboards with per-side batteries
## Proposed Solution
This series introduces struct hid_battery to encapsulate individual battery
state, replaces the old battery fields with a list-based approach, and adds
support for multiple batteries tracked within struct hid_device. Batteries
are identified by report ID and named as hid-{uniq}-battery-{id}. The
implementation is fully backwards compatible with single-battery devices
through a helper function. The series first converts the battery code to
devm_* as preparatory cleanup, which simplifies the subsequent refactoring
and reduces risk of memory management bugs.
## Testing
Tested with split keyboard hardware (Dactyl 5x6) using custom ZMK firmware
that implements per-side HID battery reporting. Each battery (left and right
keyboard halves) reports independently through the power supply interface with
distinct report IDs (0x05 and 0x06).
Test firmware available on my personal fork at:
https://github.com/zampierilucas/zmk/tree/feat/individual-hid-battery-reporting
If this series gets merged, these changes will be proposed to upstream ZMK.
HID descriptor and recording captured with hid-recorder:
D: 0
R: 162 05 01 09 06 a1 01 85 01 05 07 19 e0 29 e7 15 00 25 01 75 01 95 08 81 02 05 07 75 08 95 01 81 03 05 07 15 00 25 01 19 00 29 67 75 01 95 68 81 02 c0 05 0c 09 01 a1 01 85 02 05 0c 15 00 26 ff 0f 19 00 2a ff 0f 75 10 95 06 81 00 c0 05 84 09 05 a1 01 05 85 85 05 09 44 15 00 25 01 35 00 45 01 75 08 95 01 81 02 09 65 15 00 25 64 35 00 45 64 75 08 95 01 81 02 c0 05 84 09 05 a1 01 05 85 85 06 09 44 15 00 25 01 35 00 45 01 75 08 95 01 81 02 09 65 15 00 25 64 35 00 45 64 75 08 95 01 81 02 c0
N: ZMK Project Dactyl 5x6
P: usb-0000:2d:00.3-4.2/input2
I: 3 1d50 615e
D: 0
E: 0.000000 3 05 00 56
E: 0.000977 3 05 00 56
E: 1.490974 3 06 00 52
E: 1.491958 3 06 00 52
E: 6.492979 3 06 00 53
E: 6.493962 3 06 00 53
The recording shows both batteries reporting with different charge levels
(Report ID 05: 86%, Report ID 06: 82%-83%), demonstrating the multi-battery
functionality. This can be used to verify UPower compatibility.
## Future Work: Userspace Integration
As suggested by Bastien, semantic battery differentiation (e.g., "left
earbud" vs "right earbud") requires userspace coordination, as HID
reports typically lack role metadata.
This will require:
1. systemd/hwdb entries for device-specific battery role mappings
2. UPower updates to enumerate and group multi-battery devices
3. Desktop environment changes to display batteries with meaningful labels
This kernel infrastructure is a prerequisite for that userspace work.
Lucas Zampieri (3):
HID: input: Convert battery code to devm_*
HID: input: Introduce struct hid_battery and refactor battery code
HID: input: Add support for multiple batteries per device
Signed-off-by: Lucas Zampieri <lcasmz54@gmail.com>
Changes in v7:
- Rebased on top of hid.git for-next branch as requested by Jiri
- Adapted to new battery_present field and HID_BATTERY_QUIRK_DYNAMIC
quirk introduced upstream
- Adapted to kzalloc_obj() -> devm_kzalloc() and __free(kfree) cleanup
guard changes in upstream
Changes in v6:
- Split v5 patch 2/2 into two separate patches as suggested by Benjamin:
- Patch 2/3: Introduce struct hid_battery and convert existing code
(no functional change for single-battery devices)
- Patch 3/3: Add multi-battery list support
- Renamed hid_get_first_battery() to hid_get_battery() as suggested by
Benjamin
- Added devm_kfree() calls in error path of hidinput_setup_battery() for
proper cleanup if devm_power_supply_register() fails
Changes in v5:
- Split the monolithic v4 patch into two logical patches as suggested by
Benjamin, devm_* conversion, then struct refactor and multi-battery support
combined
Changes in v4:
- Added missing hidinput_update_battery() stub in #else block for
CONFIG_HID_BATTERY_STRENGTH=n builds
- Reported-by: kernel test robot <lkp@intel.com>
- Closes: https://lore.kernel.org/oe-kbuild-all/202511201624.yUv4VtBv-lkp@intel.com/
Changes in v3:
- Squashed the three v2 patches into a single patch as suggested by
Benjamin
- Removed all legacy dev->battery_* fields, using list-based storage only
- Changed battery naming to include report ID: hid-{uniq}-battery-{report_id}
- Converted battery memory management to devm_* for automatic cleanup
- Updated hidinput_update_battery() to take struct hid_battery directly
- Added hid_get_first_battery() helper for external driver compatibility
- Updated hid-apple.c and hid-magicmouse.c to use new battery API
- Simplified cover letter based on feedback
Changes in v2:
- Split the monolithic v1 patch into three logical patches for easier review:
1. Introduce struct hid_battery (pure structure addition)
2. Refactor existing code to use the new structure (internal changes)
3. Add multi-battery support (new functionality)
- Added detailed testing section with hardware specifics
- Added hid-recorder output (dactyl-hid-recording.txt) demonstrating two-battery
HID descriptor for UPower validation
- Added "Future Work: Userspace Integration" section addressing Bastien's feedback
about semantic battery differentiation
- Added hardware examples with product links to commit messages (per Bastien's
suggestion)
- No functional changes from v1, only improved patch organization and documentation
drivers/hid/hid-apple.c | 10 +-
drivers/hid/hid-core.c | 4 +
drivers/hid/hid-input-test.c | 39 ++++---
drivers/hid/hid-input.c | 197 ++++++++++++++++++-----------------
drivers/hid/hid-magicmouse.c | 10 +-
include/linux/hid.h | 57 +++++++---
6 files changed, 186 insertions(+), 131 deletions(-)
base-commit: 73965d0aefc8ef6504552e5805f645d58a8727b0
--
2.53.0
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v7 1/3] HID: input: Convert battery code to devm_*
2026-03-14 1:05 [PATCH v7 0/3] HID: Add support for multiple batteries per device Lucas Zampieri
@ 2026-03-14 1:05 ` Lucas Zampieri
2026-03-14 1:05 ` [PATCH v7 2/3] HID: input: Introduce struct hid_battery and refactor battery code Lucas Zampieri
` (2 subsequent siblings)
3 siblings, 0 replies; 6+ messages in thread
From: Lucas Zampieri @ 2026-03-14 1:05 UTC (permalink / raw)
To: linux-input
Cc: Lucas Zampieri, linux-kernel, Jiri Kosina, Benjamin Tissoires,
Sebastian Reichel, Bastien Nocera, linux-pm
Convert the HID battery code to use devm_* managed resource APIs for
the power_supply_desc allocation, battery name string, and power supply
registration.
The error path uses devm_kfree() to clean up allocated memory if
devm_power_supply_register() fails, preventing memory waste on repeated
setup attempts. The hidinput_cleanup_battery() function is removed as
devm handles cleanup automatically.
Signed-off-by: Lucas Zampieri <lcasmz54@gmail.com>
---
drivers/hid/hid-input.c | 34 +++++++---------------------------
1 file changed, 7 insertions(+), 27 deletions(-)
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index 395138372..7e0f971ef 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -526,13 +526,13 @@ static int hidinput_setup_battery(struct hid_device *dev, unsigned report_type,
if (quirks & HID_BATTERY_QUIRK_IGNORE)
return 0;
- psy_desc = kzalloc_obj(*psy_desc);
+ psy_desc = devm_kzalloc(&dev->dev, sizeof(*psy_desc), GFP_KERNEL);
if (!psy_desc)
return -ENOMEM;
- psy_desc->name = kasprintf(GFP_KERNEL, "hid-%s-battery",
- strlen(dev->uniq) ?
- dev->uniq : dev_name(&dev->dev));
+ psy_desc->name = devm_kasprintf(&dev->dev, GFP_KERNEL, "hid-%s-battery",
+ strlen(dev->uniq) ?
+ dev->uniq : dev_name(&dev->dev));
if (!psy_desc->name) {
error = -ENOMEM;
goto err_free_mem;
@@ -574,7 +574,7 @@ static int hidinput_setup_battery(struct hid_device *dev, unsigned report_type,
dev->battery_present = (quirks & HID_BATTERY_QUIRK_DYNAMIC) ? false : true;
- dev->battery = power_supply_register(&dev->dev, psy_desc, &psy_cfg);
+ dev->battery = devm_power_supply_register(&dev->dev, psy_desc, &psy_cfg);
if (IS_ERR(dev->battery)) {
error = PTR_ERR(dev->battery);
hid_warn(dev, "can't register power supply: %d\n", error);
@@ -585,27 +585,13 @@ static int hidinput_setup_battery(struct hid_device *dev, unsigned report_type,
return 0;
err_free_name:
- kfree(psy_desc->name);
+ devm_kfree(&dev->dev, psy_desc->name);
err_free_mem:
- kfree(psy_desc);
+ devm_kfree(&dev->dev, psy_desc);
dev->battery = NULL;
return error;
}
-static void hidinput_cleanup_battery(struct hid_device *dev)
-{
- const struct power_supply_desc *psy_desc;
-
- if (!dev->battery)
- return;
-
- psy_desc = dev->battery->desc;
- power_supply_unregister(dev->battery);
- kfree(psy_desc->name);
- kfree(psy_desc);
- dev->battery = NULL;
-}
-
static bool hidinput_update_battery_charge_status(struct hid_device *dev,
unsigned int usage, int value)
{
@@ -660,10 +646,6 @@ static int hidinput_setup_battery(struct hid_device *dev, unsigned report_type,
return 0;
}
-static void hidinput_cleanup_battery(struct hid_device *dev)
-{
-}
-
static void hidinput_update_battery(struct hid_device *dev, unsigned int usage,
int value)
{
@@ -2393,8 +2375,6 @@ void hidinput_disconnect(struct hid_device *hid)
{
struct hid_input *hidinput, *next;
- hidinput_cleanup_battery(hid);
-
list_for_each_entry_safe(hidinput, next, &hid->inputs, list) {
list_del(&hidinput->list);
if (hidinput->registered)
--
2.53.0
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v7 2/3] HID: input: Introduce struct hid_battery and refactor battery code
2026-03-14 1:05 [PATCH v7 0/3] HID: Add support for multiple batteries per device Lucas Zampieri
2026-03-14 1:05 ` [PATCH v7 1/3] HID: input: Convert battery code to devm_* Lucas Zampieri
@ 2026-03-14 1:05 ` Lucas Zampieri
2026-03-14 1:05 ` [PATCH v7 3/3] HID: input: Add support for multiple batteries per device Lucas Zampieri
2026-03-19 15:01 ` [PATCH v7 0/3] HID: " Benjamin Tissoires
3 siblings, 0 replies; 6+ messages in thread
From: Lucas Zampieri @ 2026-03-14 1:05 UTC (permalink / raw)
To: linux-input
Cc: Lucas Zampieri, linux-kernel, Jiri Kosina, Benjamin Tissoires,
Sebastian Reichel, Bastien Nocera, linux-pm
Introduce struct hid_battery to encapsulate individual battery state,
preparing for future multi-battery support.
The new structure contains all battery-related fields previously stored
directly in hid_device (capacity, min, max, report_type, report_id,
charge_status, etc.). The hid_device->battery pointer type changes from
struct power_supply* to struct hid_battery*, and all battery functions
are refactored accordingly.
A hid_get_battery() helper is added for external drivers, with
hid-apple.c and hid-magicmouse.c updated to use the new API. The
hid-input-test.c KUnit tests are also updated for the new structure.
No functional changes for single-battery devices.
Signed-off-by: Lucas Zampieri <lcasmz54@gmail.com>
---
drivers/hid/hid-apple.c | 10 +--
drivers/hid/hid-input-test.c | 39 ++++++-----
drivers/hid/hid-input.c | 131 +++++++++++++++++++----------------
drivers/hid/hid-magicmouse.c | 10 +--
include/linux/hid.h | 52 ++++++++++----
5 files changed, 146 insertions(+), 96 deletions(-)
diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c
index fc5897a6b..8b8b05c8a 100644
--- a/drivers/hid/hid-apple.c
+++ b/drivers/hid/hid-apple.c
@@ -623,17 +623,19 @@ static int apple_fetch_battery(struct hid_device *hdev)
struct apple_sc *asc = hid_get_drvdata(hdev);
struct hid_report_enum *report_enum;
struct hid_report *report;
+ struct hid_battery *bat;
- if (!(asc->quirks & APPLE_RDESC_BATTERY) || !hdev->battery)
+ bat = hid_get_battery(hdev);
+ if (!(asc->quirks & APPLE_RDESC_BATTERY) || !bat)
return -1;
- report_enum = &hdev->report_enum[hdev->battery_report_type];
- report = report_enum->report_id_hash[hdev->battery_report_id];
+ report_enum = &hdev->report_enum[bat->report_type];
+ report = report_enum->report_id_hash[bat->report_id];
if (!report || report->maxfield < 1)
return -1;
- if (hdev->battery_capacity == hdev->battery_max)
+ if (bat->capacity == bat->max)
return -1;
hid_hw_request(hdev, report, HID_REQ_GET_REPORT);
diff --git a/drivers/hid/hid-input-test.c b/drivers/hid/hid-input-test.c
index 6f5c71660..c92008daf 100644
--- a/drivers/hid/hid-input-test.c
+++ b/drivers/hid/hid-input-test.c
@@ -9,54 +9,59 @@
static void hid_test_input_update_battery_charge_status(struct kunit *test)
{
- struct hid_device *dev;
+ struct hid_battery *bat;
bool handled;
- dev = kunit_kzalloc(test, sizeof(*dev), GFP_KERNEL);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev);
+ bat = kunit_kzalloc(test, sizeof(*bat), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, bat);
- handled = hidinput_update_battery_charge_status(dev, HID_DG_HEIGHT, 0);
+ handled = hidinput_update_battery_charge_status(bat, HID_DG_HEIGHT, 0);
KUNIT_EXPECT_FALSE(test, handled);
- KUNIT_EXPECT_EQ(test, dev->battery_charge_status, POWER_SUPPLY_STATUS_UNKNOWN);
+ KUNIT_EXPECT_EQ(test, bat->charge_status, POWER_SUPPLY_STATUS_UNKNOWN);
- handled = hidinput_update_battery_charge_status(dev, HID_BAT_CHARGING, 0);
+ handled = hidinput_update_battery_charge_status(bat, HID_BAT_CHARGING, 0);
KUNIT_EXPECT_TRUE(test, handled);
- KUNIT_EXPECT_EQ(test, dev->battery_charge_status, POWER_SUPPLY_STATUS_DISCHARGING);
+ KUNIT_EXPECT_EQ(test, bat->charge_status, POWER_SUPPLY_STATUS_DISCHARGING);
- handled = hidinput_update_battery_charge_status(dev, HID_BAT_CHARGING, 1);
+ handled = hidinput_update_battery_charge_status(bat, HID_BAT_CHARGING, 1);
KUNIT_EXPECT_TRUE(test, handled);
- KUNIT_EXPECT_EQ(test, dev->battery_charge_status, POWER_SUPPLY_STATUS_CHARGING);
+ KUNIT_EXPECT_EQ(test, bat->charge_status, POWER_SUPPLY_STATUS_CHARGING);
}
static void hid_test_input_get_battery_property(struct kunit *test)
{
struct power_supply *psy;
+ struct hid_battery *bat;
struct hid_device *dev;
union power_supply_propval val;
int ret;
dev = kunit_kzalloc(test, sizeof(*dev), GFP_KERNEL);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev);
- dev->battery_avoid_query = true;
+
+ bat = kunit_kzalloc(test, sizeof(*bat), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, bat);
+ bat->dev = dev;
+ bat->avoid_query = true;
psy = kunit_kzalloc(test, sizeof(*psy), GFP_KERNEL);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, psy);
- psy->drv_data = dev;
+ psy->drv_data = bat;
- dev->battery_status = HID_BATTERY_UNKNOWN;
- dev->battery_charge_status = POWER_SUPPLY_STATUS_CHARGING;
+ bat->status = HID_BATTERY_UNKNOWN;
+ bat->charge_status = POWER_SUPPLY_STATUS_CHARGING;
ret = hidinput_get_battery_property(psy, POWER_SUPPLY_PROP_STATUS, &val);
KUNIT_EXPECT_EQ(test, ret, 0);
KUNIT_EXPECT_EQ(test, val.intval, POWER_SUPPLY_STATUS_UNKNOWN);
- dev->battery_status = HID_BATTERY_REPORTED;
- dev->battery_charge_status = POWER_SUPPLY_STATUS_CHARGING;
+ bat->status = HID_BATTERY_REPORTED;
+ bat->charge_status = POWER_SUPPLY_STATUS_CHARGING;
ret = hidinput_get_battery_property(psy, POWER_SUPPLY_PROP_STATUS, &val);
KUNIT_EXPECT_EQ(test, ret, 0);
KUNIT_EXPECT_EQ(test, val.intval, POWER_SUPPLY_STATUS_CHARGING);
- dev->battery_status = HID_BATTERY_REPORTED;
- dev->battery_charge_status = POWER_SUPPLY_STATUS_DISCHARGING;
+ bat->status = HID_BATTERY_REPORTED;
+ bat->charge_status = POWER_SUPPLY_STATUS_DISCHARGING;
ret = hidinput_get_battery_property(psy, POWER_SUPPLY_PROP_STATUS, &val);
KUNIT_EXPECT_EQ(test, ret, 0);
KUNIT_EXPECT_EQ(test, val.intval, POWER_SUPPLY_STATUS_DISCHARGING);
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index 7e0f971ef..b5d34658b 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -416,18 +416,18 @@ static unsigned find_battery_quirk(struct hid_device *hdev)
return quirks;
}
-static int hidinput_scale_battery_capacity(struct hid_device *dev,
+static int hidinput_scale_battery_capacity(struct hid_battery *bat,
int value)
{
- if (dev->battery_min < dev->battery_max &&
- value >= dev->battery_min && value <= dev->battery_max)
- value = ((value - dev->battery_min) * 100) /
- (dev->battery_max - dev->battery_min);
+ if (bat->min < bat->max &&
+ value >= bat->min && value <= bat->max)
+ value = ((value - bat->min) * 100) /
+ (bat->max - bat->min);
return value;
}
-static int hidinput_query_battery_capacity(struct hid_device *dev)
+static int hidinput_query_battery_capacity(struct hid_battery *bat)
{
int ret;
@@ -435,19 +435,20 @@ static int hidinput_query_battery_capacity(struct hid_device *dev)
if (!buf)
return -ENOMEM;
- ret = hid_hw_raw_request(dev, dev->battery_report_id, buf, 4,
- dev->battery_report_type, HID_REQ_GET_REPORT);
+ ret = hid_hw_raw_request(bat->dev, bat->report_id, buf, 4,
+ bat->report_type, HID_REQ_GET_REPORT);
if (ret < 2)
return -ENODATA;
- return hidinput_scale_battery_capacity(dev, buf[1]);
+ return hidinput_scale_battery_capacity(bat, buf[1]);
}
static int hidinput_get_battery_property(struct power_supply *psy,
enum power_supply_property prop,
union power_supply_propval *val)
{
- struct hid_device *dev = power_supply_get_drvdata(psy);
+ struct hid_battery *bat = power_supply_get_drvdata(psy);
+ struct hid_device *dev = bat->dev;
int value;
int ret = 0;
@@ -457,17 +458,17 @@ static int hidinput_get_battery_property(struct power_supply *psy,
break;
case POWER_SUPPLY_PROP_PRESENT:
- val->intval = dev->battery_present;
+ val->intval = bat->present;
break;
case POWER_SUPPLY_PROP_CAPACITY:
- if (dev->battery_status != HID_BATTERY_REPORTED &&
- !dev->battery_avoid_query) {
- value = hidinput_query_battery_capacity(dev);
+ if (bat->status != HID_BATTERY_REPORTED &&
+ !bat->avoid_query) {
+ value = hidinput_query_battery_capacity(bat);
if (value < 0)
return value;
} else {
- value = dev->battery_capacity;
+ value = bat->capacity;
}
val->intval = value;
@@ -478,20 +479,20 @@ static int hidinput_get_battery_property(struct power_supply *psy,
break;
case POWER_SUPPLY_PROP_STATUS:
- if (dev->battery_status != HID_BATTERY_REPORTED &&
- !dev->battery_avoid_query) {
- value = hidinput_query_battery_capacity(dev);
+ if (bat->status != HID_BATTERY_REPORTED &&
+ !bat->avoid_query) {
+ value = hidinput_query_battery_capacity(bat);
if (value < 0)
return value;
- dev->battery_capacity = value;
- dev->battery_status = HID_BATTERY_QUERIED;
+ bat->capacity = value;
+ bat->status = HID_BATTERY_QUERIED;
}
- if (dev->battery_status == HID_BATTERY_UNKNOWN)
+ if (bat->status == HID_BATTERY_UNKNOWN)
val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
else
- val->intval = dev->battery_charge_status;
+ val->intval = bat->charge_status;
break;
case POWER_SUPPLY_PROP_SCOPE:
@@ -509,8 +510,9 @@ static int hidinput_get_battery_property(struct power_supply *psy,
static int hidinput_setup_battery(struct hid_device *dev, unsigned report_type,
struct hid_field *field, bool is_percentage)
{
+ struct hid_battery *bat;
struct power_supply_desc *psy_desc;
- struct power_supply_config psy_cfg = { .drv_data = dev, };
+ struct power_supply_config psy_cfg = { 0 };
unsigned quirks;
s32 min, max;
int error;
@@ -526,16 +528,22 @@ static int hidinput_setup_battery(struct hid_device *dev, unsigned report_type,
if (quirks & HID_BATTERY_QUIRK_IGNORE)
return 0;
- psy_desc = devm_kzalloc(&dev->dev, sizeof(*psy_desc), GFP_KERNEL);
- if (!psy_desc)
+ bat = devm_kzalloc(&dev->dev, sizeof(*bat), GFP_KERNEL);
+ if (!bat)
return -ENOMEM;
+ psy_desc = devm_kzalloc(&dev->dev, sizeof(*psy_desc), GFP_KERNEL);
+ if (!psy_desc) {
+ error = -ENOMEM;
+ goto err_free_bat;
+ }
+
psy_desc->name = devm_kasprintf(&dev->dev, GFP_KERNEL, "hid-%s-battery",
strlen(dev->uniq) ?
dev->uniq : dev_name(&dev->dev));
if (!psy_desc->name) {
error = -ENOMEM;
- goto err_free_mem;
+ goto err_free_desc;
}
psy_desc->type = POWER_SUPPLY_TYPE_BATTERY;
@@ -555,51 +563,57 @@ static int hidinput_setup_battery(struct hid_device *dev, unsigned report_type,
if (quirks & HID_BATTERY_QUIRK_FEATURE)
report_type = HID_FEATURE_REPORT;
- dev->battery_min = min;
- dev->battery_max = max;
- dev->battery_report_type = report_type;
- dev->battery_report_id = field->report->id;
- dev->battery_charge_status = POWER_SUPPLY_STATUS_DISCHARGING;
+ bat->dev = dev;
+ bat->min = min;
+ bat->max = max;
+ bat->report_type = report_type;
+ bat->report_id = field->report->id;
+ bat->charge_status = POWER_SUPPLY_STATUS_DISCHARGING;
+ bat->status = HID_BATTERY_UNKNOWN;
/*
* Stylus is normally not connected to the device and thus we
* can't query the device and get meaningful battery strength.
* We have to wait for the device to report it on its own.
*/
- dev->battery_avoid_query = report_type == HID_INPUT_REPORT &&
- field->physical == HID_DG_STYLUS;
+ bat->avoid_query = report_type == HID_INPUT_REPORT &&
+ field->physical == HID_DG_STYLUS;
if (quirks & HID_BATTERY_QUIRK_AVOID_QUERY)
- dev->battery_avoid_query = true;
+ bat->avoid_query = true;
- dev->battery_present = (quirks & HID_BATTERY_QUIRK_DYNAMIC) ? false : true;
+ bat->present = (quirks & HID_BATTERY_QUIRK_DYNAMIC) ? false : true;
- dev->battery = devm_power_supply_register(&dev->dev, psy_desc, &psy_cfg);
- if (IS_ERR(dev->battery)) {
- error = PTR_ERR(dev->battery);
+ psy_cfg.drv_data = bat;
+ bat->ps = devm_power_supply_register(&dev->dev, psy_desc, &psy_cfg);
+ if (IS_ERR(bat->ps)) {
+ error = PTR_ERR(bat->ps);
hid_warn(dev, "can't register power supply: %d\n", error);
goto err_free_name;
}
- power_supply_powers(dev->battery, &dev->dev);
+ power_supply_powers(bat->ps, &dev->dev);
+ dev->battery = bat;
return 0;
err_free_name:
devm_kfree(&dev->dev, psy_desc->name);
-err_free_mem:
+err_free_desc:
devm_kfree(&dev->dev, psy_desc);
+err_free_bat:
+ devm_kfree(&dev->dev, bat);
dev->battery = NULL;
return error;
}
-static bool hidinput_update_battery_charge_status(struct hid_device *dev,
+static bool hidinput_update_battery_charge_status(struct hid_battery *bat,
unsigned int usage, int value)
{
switch (usage) {
case HID_BAT_CHARGING:
- dev->battery_charge_status = value ?
- POWER_SUPPLY_STATUS_CHARGING :
- POWER_SUPPLY_STATUS_DISCHARGING;
+ bat->charge_status = value ?
+ POWER_SUPPLY_STATUS_CHARGING :
+ POWER_SUPPLY_STATUS_DISCHARGING;
return true;
}
@@ -609,34 +623,35 @@ static bool hidinput_update_battery_charge_status(struct hid_device *dev,
static void hidinput_update_battery(struct hid_device *dev, unsigned int usage,
int value)
{
+ struct hid_battery *bat = dev->battery;
int capacity;
- if (!dev->battery)
+ if (!bat)
return;
- if (hidinput_update_battery_charge_status(dev, usage, value)) {
- dev->battery_present = true;
- power_supply_changed(dev->battery);
+ if (hidinput_update_battery_charge_status(bat, usage, value)) {
+ bat->present = true;
+ power_supply_changed(bat->ps);
return;
}
if ((usage & HID_USAGE_PAGE) == HID_UP_DIGITIZER && value == 0)
return;
- if (value < dev->battery_min || value > dev->battery_max)
+ if (value < bat->min || value > bat->max)
return;
- capacity = hidinput_scale_battery_capacity(dev, value);
+ capacity = hidinput_scale_battery_capacity(bat, value);
- 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 =
+ if (bat->status != HID_BATTERY_REPORTED ||
+ capacity != bat->capacity ||
+ ktime_after(ktime_get_coarse(), bat->ratelimit_time)) {
+ bat->present = true;
+ bat->capacity = capacity;
+ bat->status = HID_BATTERY_REPORTED;
+ bat->ratelimit_time =
ktime_add_ms(ktime_get_coarse(), 30 * 1000);
- power_supply_changed(dev->battery);
+ power_supply_changed(bat->ps);
}
}
#else /* !CONFIG_HID_BATTERY_STRENGTH */
diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c
index 9eadf3252..e70bd3dc0 100644
--- a/drivers/hid/hid-magicmouse.c
+++ b/drivers/hid/hid-magicmouse.c
@@ -817,19 +817,21 @@ static int magicmouse_fetch_battery(struct hid_device *hdev)
#ifdef CONFIG_HID_BATTERY_STRENGTH
struct hid_report_enum *report_enum;
struct hid_report *report;
+ struct hid_battery *bat;
- if (!hdev->battery ||
+ bat = hid_get_battery(hdev);
+ if (!bat ||
(!is_usb_magicmouse2(hdev->vendor, hdev->product) &&
!is_usb_magictrackpad2(hdev->vendor, hdev->product)))
return -1;
- report_enum = &hdev->report_enum[hdev->battery_report_type];
- report = report_enum->report_id_hash[hdev->battery_report_id];
+ report_enum = &hdev->report_enum[bat->report_type];
+ report = report_enum->report_id_hash[bat->report_id];
if (!report || report->maxfield < 1)
return -1;
- if (hdev->battery_capacity == hdev->battery_max)
+ if (bat->capacity == bat->max)
return -1;
hid_hw_request(hdev, report, HID_REQ_GET_REPORT);
diff --git a/include/linux/hid.h b/include/linux/hid.h
index 44357295b..71beff003 100644
--- a/include/linux/hid.h
+++ b/include/linux/hid.h
@@ -634,6 +634,36 @@ enum hid_battery_status {
HID_BATTERY_REPORTED, /* Device sent unsolicited battery strength report */
};
+/**
+ * struct hid_battery - represents a single battery power supply
+ * @dev: pointer to the parent hid_device
+ * @ps: the power supply instance
+ * @min: minimum battery value from HID descriptor
+ * @max: maximum battery value from HID descriptor
+ * @report_type: HID report type (input/feature)
+ * @report_id: HID report ID for this battery
+ * @charge_status: current charging status
+ * @status: battery reporting status
+ * @capacity: current battery capacity (0-100)
+ * @avoid_query: if true, avoid querying battery (e.g., for stylus)
+ * @present: if true, battery is present (may be dynamic)
+ * @ratelimit_time: rate limiting for battery reports
+ */
+struct hid_battery {
+ struct hid_device *dev;
+ struct power_supply *ps;
+ __s32 min;
+ __s32 max;
+ __s32 report_type;
+ __s32 report_id;
+ __s32 charge_status;
+ enum hid_battery_status status;
+ __s32 capacity;
+ bool avoid_query;
+ bool present;
+ ktime_t ratelimit_time;
+};
+
struct hid_driver;
struct hid_ll_driver;
@@ -670,20 +700,9 @@ struct hid_device {
#ifdef CONFIG_HID_BATTERY_STRENGTH
/*
* Power supply information for HID devices which report
- * battery strength. power_supply was successfully registered if
- * battery is non-NULL.
+ * battery strength. battery is non-NULL if successfully registered.
*/
- struct power_supply *battery;
- __s32 battery_capacity;
- __s32 battery_min;
- __s32 battery_max;
- __s32 battery_report_type;
- __s32 battery_report_id;
- __s32 battery_charge_status;
- enum hid_battery_status battery_status;
- bool battery_avoid_query;
- bool battery_present;
- ktime_t battery_ratelimit_time;
+ struct hid_battery *battery;
#endif
unsigned long status; /* see STAT flags above */
@@ -745,6 +764,13 @@ static inline void hid_set_drvdata(struct hid_device *hdev, void *data)
dev_set_drvdata(&hdev->dev, data);
}
+#ifdef CONFIG_HID_BATTERY_STRENGTH
+static inline struct hid_battery *hid_get_battery(struct hid_device *hdev)
+{
+ return hdev->battery;
+}
+#endif
+
#define HID_GLOBAL_STACK_SIZE 4
#define HID_COLLECTION_STACK_SIZE 4
--
2.53.0
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v7 3/3] HID: input: Add support for multiple batteries per device
2026-03-14 1:05 [PATCH v7 0/3] HID: Add support for multiple batteries per device Lucas Zampieri
2026-03-14 1:05 ` [PATCH v7 1/3] HID: input: Convert battery code to devm_* Lucas Zampieri
2026-03-14 1:05 ` [PATCH v7 2/3] HID: input: Introduce struct hid_battery and refactor battery code Lucas Zampieri
@ 2026-03-14 1:05 ` Lucas Zampieri
2026-06-02 1:19 ` Bug report in " Rafael Passos
2026-03-19 15:01 ` [PATCH v7 0/3] HID: " Benjamin Tissoires
3 siblings, 1 reply; 6+ messages in thread
From: Lucas Zampieri @ 2026-03-14 1:05 UTC (permalink / raw)
To: linux-input
Cc: Lucas Zampieri, linux-kernel, Jiri Kosina, Benjamin Tissoires,
Sebastian Reichel, Bastien Nocera, linux-pm
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 <lcasmz54@gmail.com>
---
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 da57cbf0a..58a31ee07 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -2995,6 +2995,10 @@ struct hid_device *hid_allocate_device(void)
mutex_init(&hdev->ll_open_lock);
kref_init(&hdev->ref);
+#ifdef CONFIG_HID_BATTERY_STRENGTH
+ INIT_LIST_HEAD(&hdev->batteries);
+#endif
+
ret = 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 b5d34658b..8fff185fe 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -507,6 +507,18 @@ static int hidinput_get_battery_property(struct power_supply *psy,
return ret;
}
+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 == 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)
{
@@ -517,13 +529,15 @@ static int hidinput_setup_battery(struct hid_device *dev, unsigned report_type,
s32 min, max;
int error;
- 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;
quirks = find_battery_quirk(dev);
- 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);
if (quirks & HID_BATTERY_QUIRK_IGNORE)
return 0;
@@ -538,9 +552,11 @@ static int hidinput_setup_battery(struct hid_device *dev, unsigned report_type,
goto err_free_bat;
}
- psy_desc->name = devm_kasprintf(&dev->dev, GFP_KERNEL, "hid-%s-battery",
+ psy_desc->name = 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 = -ENOMEM;
goto err_free_desc;
@@ -593,7 +609,7 @@ static int hidinput_setup_battery(struct hid_device *dev, unsigned report_type,
}
power_supply_powers(bat->ps, &dev->dev);
- dev->battery = bat;
+ list_add_tail(&bat->list, &dev->batteries);
return 0;
err_free_name:
@@ -602,7 +618,6 @@ static int hidinput_setup_battery(struct hid_device *dev, unsigned report_type,
devm_kfree(&dev->dev, psy_desc);
err_free_bat:
devm_kfree(&dev->dev, bat);
- dev->battery = NULL;
return error;
}
@@ -620,12 +635,13 @@ static bool hidinput_update_battery_charge_status(struct hid_battery *bat,
return false;
}
-static void hidinput_update_battery(struct hid_device *dev, unsigned int usage,
- int value)
+static void hidinput_update_battery(struct hid_device *dev, int report_id,
+ unsigned int usage, int value)
{
- struct hid_battery *bat = dev->battery;
+ struct hid_battery *bat;
int capacity;
+ bat = hidinput_find_battery(dev, report_id);
if (!bat)
return;
@@ -661,8 +677,8 @@ static int hidinput_setup_battery(struct hid_device *dev, unsigned report_type,
return 0;
}
-static void hidinput_update_battery(struct hid_device *dev, unsigned int usage,
- int value)
+static void hidinput_update_battery(struct hid_device *dev, int report_id,
+ unsigned int usage, int value)
{
}
#endif /* CONFIG_HID_BATTERY_STRENGTH */
@@ -1546,7 +1562,7 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct
return;
if (usage->type == EV_PWR) {
- hidinput_update_battery(hid, usage->hid, value);
+ hidinput_update_battery(hid, report->id, usage->hid, value);
return;
}
diff --git a/include/linux/hid.h b/include/linux/hid.h
index 71beff003..442a80d79 100644
--- a/include/linux/hid.h
+++ b/include/linux/hid.h
@@ -648,6 +648,7 @@ enum hid_battery_status {
* @avoid_query: if true, avoid querying battery (e.g., for stylus)
* @present: if true, battery is present (may be dynamic)
* @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;
@@ -662,6 +663,7 @@ struct hid_battery {
bool avoid_query;
bool present;
ktime_t ratelimit_time;
+ struct list_head list;
};
struct hid_driver;
@@ -700,9 +702,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
unsigned long status; /* see STAT flags above */
@@ -767,7 +770,9 @@ static inline void hid_set_drvdata(struct hid_device *hdev, 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
--
2.53.0
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v7 0/3] HID: Add support for multiple batteries per device
2026-03-14 1:05 [PATCH v7 0/3] HID: Add support for multiple batteries per device Lucas Zampieri
` (2 preceding siblings ...)
2026-03-14 1:05 ` [PATCH v7 3/3] HID: input: Add support for multiple batteries per device Lucas Zampieri
@ 2026-03-19 15:01 ` Benjamin Tissoires
3 siblings, 0 replies; 6+ messages in thread
From: Benjamin Tissoires @ 2026-03-19 15:01 UTC (permalink / raw)
To: linux-input, Lucas Zampieri
Cc: linux-kernel, Jiri Kosina, Sebastian Reichel, Bastien Nocera, linux-pm
On Sat, 14 Mar 2026 01:05:27 +0000, Lucas Zampieri wrote:
> This series adds support for HID devices with multiple batteries.
>
> Currently, the HID battery reporting subsystem only supports one battery per
> device. There are several devices with multiple batteries that would benefit
> from this support:
> - Gaming headsets with batteries in both the headset and charging dock
> - Wireless earbuds with per-earbud batteries plus charging case
> - Split keyboards with per-side batteries
>
> [...]
Applied to https://git.kernel.org/pub/scm/linux/kernel/git/hid/hid.git (for-7.1/core-v2), thanks!
[1/3] HID: input: Convert battery code to devm_*
https://git.kernel.org/hid/hid/c/5a9df498581a
[2/3] HID: input: Introduce struct hid_battery and refactor battery code
https://git.kernel.org/hid/hid/c/7a3ac62473f2
[3/3] HID: input: Add support for multiple batteries per device
https://git.kernel.org/hid/hid/c/4a58ae85c3f9
Cheers,
--
Benjamin Tissoires <bentiss@kernel.org>
^ permalink raw reply [flat|nested] 6+ messages in thread
* Bug report in HID: input: Add support for multiple batteries per device
2026-03-14 1:05 ` [PATCH v7 3/3] HID: input: Add support for multiple batteries per device Lucas Zampieri
@ 2026-06-02 1:19 ` Rafael Passos
0 siblings, 0 replies; 6+ messages in thread
From: Rafael Passos @ 2026-06-02 1:19 UTC (permalink / raw)
To: lcasmz54; +Cc: bentiss, hadess, jikos, linux-input, linux-kernel, linux-pm, sre
Hi, I found a bug preventing preventing my laptop from booting
the mainline, and my bisection led me to this patch.
I believe I found the issue already, and will send a patch
following this report.
Decoded trace:
```
jun 01 20:03:15 debbook kernel: Oops: Oops: 0000 [#1] SMP NOPTI
jun 01 20:03:15 debbook kernel: CPU: 4 UID: 0 PID: 257 Comm: (udev-worker) Not tainted 7.1.0-rc6rcpassos #85 PREEMPT(lazy)
jun 01 20:03:15 debbook kernel: Hardware name: HP HP ProBook x360 435 G7/8735, BIOS S80 Ver. 01.17.02 06/07/2024
jun 01 20:03:15 debbook kernel: RIP: 0010:hidinput_setup_battery.isra.0 (/media/wd/code/kernel-dev/linux/drivers/hid/hid-input.c:412 /media/wd/code/kernel-dev/linux/drivers/hid/hid-input.c:523) hid
jun 01 20:03:15 debbook kernel: Code: f3 48 ab 48 8b 85 18 1c 00 00 48 39 c3 74 4b 48 8b 52 68 48 83 e8 38 8b 4a 30 eb 0e 90 48 8b 50 38 48 8d 42 c8 48 39 d3 74 30 <3b> >
All code
========
0: f3 48 ab rep stos %rax,(%rdi)
3: 48 8b 85 18 1c 00 00 mov 0x1c18(%rbp),%rax
a: 48 39 c3 cmp %rax,%rbx
d: 74 4b je 0x5a
f: 48 8b 52 68 mov 0x68(%rdx),%rdx
13: 48 83 e8 38 sub $0x38,%rax
17: 8b 4a 30 mov 0x30(%rdx),%ecx
1a: eb 0e jmp 0x2a
1c: 90 nop
1d: 48 8b 50 38 mov 0x38(%rax),%rdx
21: 48 8d 42 c8 lea -0x38(%rdx),%rax
25: 48 39 d3 cmp %rdx,%rbx
28: 74 30 je 0x5a
2a:* 3b 00 cmp (%rax),%eax <-- trapping instruction
Code starting with the faulting instruction
===========================================
0: 3b 00 cmp (%rax),%eax
jun 01 20:03:15 debbook kernel: RSP: 0018:ffffce87407c76c0 EFLAGS: 00010286
jun 01 20:03:15 debbook kernel: RAX: ffffffffffffffc8 RBX: ffff8db823bb7c18 RCX: 0000000000000007
jun 01 20:03:15 debbook kernel: RDX: 0000000000000000 RSI: 0000000000000000 RDI: ffffce87407c7718
jun 01 20:03:15 debbook kernel: RBP: ffff8db823bb6000 R08: ffffce87407c77c0 R09: ffffce87407c77bc
jun 01 20:03:15 debbook kernel: R10: ffff8db80df756c0 R11: ffff8db81f7b3000 R12: ffffce87407c76e8
jun 01 20:03:15 debbook kernel: R13: ffff8db80df756c0 R14: ffff8db823bb6000 R15: ffff8db823119600
jun 01 20:03:15 debbook kernel: FS: 00007fe5afebfd80(0000) GS:ffff8dbf6807b000(0000) knlGS:0000000000000000
jun 01 20:03:15 debbook kernel: CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
jun 01 20:03:15 debbook kernel: CR2: ffffffffffffffe4 CR3: 000000011ffe4000 CR4: 0000000000350ef0
jun 01 20:03:15 debbook kernel: Call Trace:
jun 01 20:03:15 debbook kernel: <TASK>
jun 01 20:03:15 debbook kernel: ? input_alloc_absinfo (./include/linux/slab.h:950 ./include/linux/slab.h:1188 drivers/input/input.c:442)
jun 01 20:03:15 debbook kernel: hidinput_connect (/media/wd/code/kernel-dev/linux/drivers/hid/hid-input.c:1294 /media/wd/code/kernel-dev/linux/drivers/hid/hid-input.c:2278 /media/wd/code/kernel-dev/linux/drivers/hid/hid-input.c:2345) hid
jun 01 20:03:15 debbook kernel: hid_connect (/media/wd/code/kernel-dev/linux/drivers/hid/hid-core.c:2308 (discriminator 1)) hid
jun 01 20:03:15 debbook kernel: ? vfree.part.0 (mm/vmalloc.c:3475)
jun 01 20:03:15 debbook kernel: hid_hw_start (/media/wd/code/kernel-dev/linux/drivers/hid/hid-core.c:2426 /media/wd/code/kernel-dev/linux/drivers/hid/hid-core.c:2417) hid
jun 01 20:03:15 debbook kernel: mt_probe (/media/wd/code/kernel-dev/linux/drivers/hid/hid-multitouch.c:2028) hid_multitouch
jun 01 20:03:15 debbook kernel: ? devres_open_group (./include/linux/spinlock.h:408 ./include/linux/spinlock.h:619 drivers/base/devres.c:263 drivers/base/devres.c:617)
jun 01 20:03:15 debbook kernel: hid_device_probe (/media/wd/code/kernel-dev/linux/drivers/hid/hid-core.c:2822 /media/wd/code/kernel-dev/linux/drivers/hid/hid-core.c:2859) hid
jun 01 20:03:15 debbook kernel: really_probe (drivers/base/dd.c:631 drivers/base/dd.c:709)
jun 01 20:03:15 debbook kernel: ? __pfx___device_attach_driver (drivers/base/dd.c:908 (discriminator 1))
jun 01 20:03:15 debbook kernel: __driver_probe_device (drivers/base/dd.c:871)
jun 01 20:03:15 debbook kernel: driver_probe_device (drivers/base/dd.c:901)
jun 01 20:03:15 debbook kernel: __device_attach_driver (drivers/base/dd.c:1029)
jun 01 20:03:15 debbook kernel: bus_for_each_drv (drivers/base/bus.c:500)
jun 01 20:03:15 debbook kernel: __device_attach (drivers/base/dd.c:1101)
jun 01 20:03:15 debbook kernel: ? __pfx___hid_bus_reprobe_drivers (/media/wd/code/kernel-dev/linux/drivers/hid/hid-core.c:3111) hid
jun 01 20:03:15 debbook kernel: device_reprobe (drivers/base/bus.c:847 drivers/base/bus.c:881)
jun 01 20:03:15 debbook kernel: ? __hid_bus_reprobe_drivers (/media/wd/code/kernel-dev/linux/drivers/hid/hid-core.c:3094) hid
jun 01 20:03:15 debbook kernel: bus_for_each_dev (drivers/base/bus.c:383)
jun 01 20:03:15 debbook kernel: ? __pfx___hid_bus_driver_added (/media/wd/code/kernel-dev/linux/drivers/hid/hid-core.c:2900) hid
jun 01 20:03:15 debbook kernel: __hid_bus_driver_added (/media/wd/code/kernel-dev/linux/drivers/hid/hid-core.c:3106) hid
jun 01 20:03:15 debbook kernel: bus_for_each_drv (drivers/base/bus.c:500)
jun 01 20:03:15 debbook kernel: ? __pfx_sensor_hub_driver_init (hid-sensor-hub.mod.c:?) hid_sensor_hub
jun 01 20:03:15 debbook kernel: __hid_register_driver (/media/wd/code/kernel-dev/linux/drivers/hid/hid-core.c:3134 /media/wd/code/kernel-dev/linux/drivers/hid/hid-core.c:3118) hid
jun 01 20:03:15 debbook kernel: do_one_initcall (init/main.c:1392)
jun 01 20:03:15 debbook kernel: do_init_module (kernel/module/main.c:3106)
jun 01 20:03:15 debbook kernel: init_module_from_file (kernel/module/main.c:3777)
jun 01 20:03:15 debbook kernel: idempotent_init_module (kernel/module/main.c:3789)
jun 01 20:03:15 debbook kernel: __x64_sys_finit_module (kernel/module/main.c:3815 kernel/module/main.c:3799 kernel/module/main.c:3799)
jun 01 20:03:15 debbook kernel: do_syscall_64 (arch/x86/entry/syscall_64.c:63 arch/x86/entry/syscall_64.c:94)
jun 01 20:03:15 debbook kernel: ? do_sys_openat2 (./include/linux/fs.h:2553 fs/open.c:1363)
jun 01 20:03:15 debbook kernel: ? __x64_sys_openat (fs/open.c:1370 fs/open.c:1386 fs/open.c:1381 fs/open.c:1381)
jun 01 20:03:15 debbook kernel: ? do_syscall_64 (./arch/x86/include/asm/entry-common.h:63 ./include/linux/irq-entry-common.h:210 ./include/linux/irq-entry-common.h:230 ./include/linux/entry-common.h:318 arch/x86/entry/syscall_64.c:100)
jun 01 20:03:15 debbook kernel: ? do_syscall_64 (./arch/x86/include/asm/entry-common.h:63 ./include/linux/irq-entry-common.h:210 ./include/linux/irq-entry-common.h:230 ./include/linux/entry-common.h:318 arch/x86/entry/syscall_64.c:100)
jun 01 20:03:15 debbook kernel: ? do_syscall_64 (./arch/x86/include/asm/entry-common.h:63 ./include/linux/irq-entry-common.h:210 ./include/linux/irq-entry-common.h:230 ./include/linux/entry-common.h:318 arch/x86/entry/syscall_64.c:100)
jun 01 20:03:15 debbook kernel: ? __x64_sys_openat (fs/open.c:1370 fs/open.c:1386 fs/open.c:1381 fs/open.c:1381)
jun 01 20:03:15 debbook kernel: ? __fput (./include/linux/percpu_counter.h:71 ./include/linux/percpu_counter.h:272 fs/file_table.c:99 fs/file_table.c:523)
jun 01 20:03:15 debbook kernel: ? __x64_sys_close (fs/open.c:1507 fs/open.c:1492 fs/open.c:1492)
jun 01 20:03:15 debbook kernel: ? do_syscall_64 (./arch/x86/include/asm/entry-common.h:63 ./include/linux/irq-entry-common.h:210 ./include/linux/irq-entry-common.h:230 ./include/linux/entry-common.h:318 arch/x86/entry/syscall_64.c:100)
jun 01 20:03:15 debbook kernel: ? from_kgid_munged (kernel/user_namespace.c:406 kernel/user_namespace.c:512 kernel/user_namespace.c:536)
jun 01 20:03:15 debbook kernel: ? __do_sys_getgid (kernel/sys.c:1042 (discriminator 2))
jun 01 20:03:15 debbook kernel: ? do_syscall_64 (./arch/x86/include/asm/entry-common.h:63 ./include/linux/irq-entry-common.h:210 ./include/linux/irq-entry-common.h:230 ./include/linux/entry-common.h:318 arch/x86/entry/syscall_64.c:100)
jun 01 20:03:15 debbook kernel: ? do_syscall_64 (./include/linux/randomize_kstack.h:57 arch/x86/entry/syscall_64.c:92)
jun 01 20:03:15 debbook kernel: entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:121)
jun 01 20:03:15 debbook kernel: RIP: 0033:0x7fe5affd3c69
jun 01 20:03:15 debbook kernel: Code: ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> >
All code
========
0: ff c3 inc %ebx
2: 66 2e 0f 1f 84 00 00 cs nopw 0x0(%rax,%rax,1)
9: 00 00 00
c: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)
11: 48 89 f8 mov %rdi,%rax
14: 48 89 f7 mov %rsi,%rdi
17: 48 89 d6 mov %rdx,%rsi
1a: 48 89 ca mov %rcx,%rdx
1d: 4d 89 c2 mov %r8,%r10
20: 4d 89 c8 mov %r9,%r8
23: 4c 8b 4c 24 08 mov 0x8(%rsp),%r9
28: 0f 05 syscall
2a:* 48 rex.W <-- trapping instruction
...
Code starting with the faulting instruction
===========================================
0: 48 rex.W
...
jun 01 20:03:15 debbook kernel: RSP: 002b:00007ffc4716a3d8 EFLAGS: 00000246 ORIG_RAX: 0000000000000139
jun 01 20:03:15 debbook kernel: RAX: ffffffffffffffda RBX: 0000555df96b8430 RCX: 00007fe5affd3c69
jun 01 20:03:15 debbook kernel: RDX: 0000000000000004 RSI: 00007fe5afd7344d RDI: 0000000000000050
jun 01 20:03:15 debbook kernel: RBP: 0000000000000004 R08: 0000000000000000 R09: 0000555df962b170
jun 01 20:03:15 debbook kernel: R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000020000
jun 01 20:03:15 debbook kernel: R13: 00007fe5afd7344d R14: 0000555df96bb2e0 R15: 0000000000000000
jun 01 20:03:15 debbook kernel: </TASK>
jun 01 20:03:15 debbook kernel: Modules linked in: hid_sensor_hub(+) drm_buddy amdxcp drm_panel_backlight_quirks gpu_sched drm_ttm_helper ttm drm_exec i2c_algo_bit drm_s>
```
Thanks,
Rafael Passos
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2026-06-02 1:20 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-03-14 1:05 [PATCH v7 0/3] HID: Add support for multiple batteries per device Lucas Zampieri
2026-03-14 1:05 ` [PATCH v7 1/3] HID: input: Convert battery code to devm_* Lucas Zampieri
2026-03-14 1:05 ` [PATCH v7 2/3] HID: input: Introduce struct hid_battery and refactor battery code Lucas Zampieri
2026-03-14 1:05 ` [PATCH v7 3/3] HID: input: Add support for multiple batteries per device Lucas Zampieri
2026-06-02 1:19 ` Bug report in " Rafael Passos
2026-03-19 15:01 ` [PATCH v7 0/3] HID: " Benjamin Tissoires
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®