From: Damiano Gragnaniello <damianogragnaniello@gmail.com>
To: jikos@kernel.org
Cc: bentiss@kernel.org, linux-input@vger.kernel.org,
Damiano Gragnaniello <damianogragnaniello@gmail.com>
Subject: [PATCH v5] HID: magicmouse: add battery reporting for Magic Trackpad v1
Date: Thu, 16 Apr 2026 14:53:15 +0200 [thread overview]
Message-ID: <20260416125317.172576-1-damianogragnaniello@gmail.com> (raw)
In-Reply-To: <20260415155548.927385-1-damianogragnaniello@gmail.com>
The Magic Trackpad v1 (A1339) reports battery level via Bluetooth using
Report ID 0x47. This patch adds support for parsing this report and
registering a power_supply interface so that userspace (upower) can
correctly display the battery percentage for this legacy device.
Signed-off-by: Damiano Gragnaniello <damianogragnaniello@gmail.com>
---
v5:
- Rebased on current upstream hid-magicmouse.c (post-timer_container_of
refactor). Previous versions failed to apply due to context drift.
- Removed spurious TRACKPAD_V1_BATTERY_TIMEOUT_SEC define (unused).
- Removed space-aligned assignments in probe() in favor of plain
single-tab assignments to satisfy checkpatch.pl --strict.
- Added kernel-doc comment entries for new struct fields.
- Preserved all original driver logic and comments without modification.
v4:
- Fixed patch formatting and spacing issues to ensure clean application.
- Removed local path references and non-technical notes.
- Corrected diff headers.
v3:
- Fixed changelog language (translated from Italian to English).
- Standardized patch naming for upstream submission.
v2:
- Rename macros to TRACKPAD_V1_BATTERY_REPORT_ID for clarity.
- Add clamp_val() to ensure battery capacity stays within 0-100 range.
- Restore original driver comments.
drivers/hid/hid-magicmouse.c | 82 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 82 insertions(+)
diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c
--- a/drivers/hid/hid-magicmouse.c
+++ b/drivers/hid/hid-magicmouse.c
@@ -15,6 +15,7 @@
#include <linux/hid.h>
#include <linux/input/mt.h>
#include <linux/module.h>
+#include <linux/power_supply.h>
#include <linux/slab.h>
#include <linux/workqueue.h>
@@ -60,6 +61,7 @@
#define MOUSE_REPORT_ID 0x29
#define MOUSE2_REPORT_ID 0x12
#define DOUBLE_REPORT_ID 0xf7
+#define TRACKPAD_V1_BATTERY_REPORT_ID 0x47
#define USB_BATTERY_TIMEOUT_SEC 60
/* These definitions are not precise, but they're close enough. (Bits
@@ -124,6 +126,10 @@
* @hdev: Pointer to the underlying HID device.
* @work: Workqueue to handle initialization retry for quirky devices.
* @battery_timer: Timer for obtaining battery level information.
+ * @battery: Power supply instance for Magic Trackpad v1 AA battery reporting.
+ * @battery_desc: Descriptor for the power_supply registration.
+ * @battery_name: Name buffer for the power_supply instance.
+ * @battery_capacity: Last known battery level (0-100%) for Magic Trackpad v1.
*/
struct magicmouse_sc {
struct input_dev *input;
@@ -149,8 +155,46 @@
struct hid_device *hdev;
struct delayed_work work;
struct timer_list battery_timer;
+
+ /* Magic Trackpad v1 (AA battery) power_supply support */
+ struct power_supply *battery;
+ struct power_supply_desc battery_desc;
+ char battery_name[64];
+ int battery_capacity;
+};
+
+static const enum power_supply_property magicmouse_v1_battery_props[] = {
+ POWER_SUPPLY_PROP_PRESENT,
+ POWER_SUPPLY_PROP_CAPACITY,
+ POWER_SUPPLY_PROP_SCOPE,
+ POWER_SUPPLY_PROP_STATUS,
+};
+
+static int magicmouse_v1_battery_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct magicmouse_sc *msc = power_supply_get_drvdata(psy);
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_PRESENT:
+ val->intval = 1;
+ break;
+ case POWER_SUPPLY_PROP_CAPACITY:
+ val->intval = msc->battery_capacity;
+ break;
+ case POWER_SUPPLY_PROP_SCOPE:
+ val->intval = POWER_SUPPLY_SCOPE_DEVICE;
+ break;
+ case POWER_SUPPLY_PROP_STATUS:
+ val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
}
static int magicmouse_firm_touch(struct magicmouse_sc *msc)
@@ -391,6 +435,19 @@
int x = 0, y = 0, ii, clicks = 0, npoints;
switch (data[0]) {
+ case TRACKPAD_V1_BATTERY_REPORT_ID:
+ /*
+ * Magic Trackpad v1 (A1339, BT) sends battery level in byte 1,
+ * already expressed as a percentage (0-100) by the firmware.
+ * Clamp defensively and notify the power_supply framework.
+ */
+ if (size < 2)
+ return 0;
+ if (msc->battery) {
+ msc->battery_capacity = clamp_val((int)data[1], 0, 100);
+ power_supply_changed(msc->battery);
+ }
+ return 0;
case TRACKPAD_REPORT_ID:
case TRACKPAD2_BT_REPORT_ID:
/* Expect four bytes of prefix, and N*9 bytes of touch data. */
@@ -890,6 +947,31 @@
magicmouse_fetch_battery(hdev);
}
+ /* Register power_supply for Magic Trackpad v1 (AA battery, BT only) */
+ if (id->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD &&
+ id->vendor == USB_VENDOR_ID_APPLE) {
+ struct power_supply_config psy_cfg = {};
+
+ psy_cfg.drv_data = msc;
+ msc->battery_capacity = 0;
+ snprintf(msc->battery_name, sizeof(msc->battery_name),
+ "hid-magictrackpad-v1-%s", dev_name(&hdev->dev));
+
+ msc->battery_desc.name = msc->battery_name;
+ msc->battery_desc.type = POWER_SUPPLY_TYPE_BATTERY;
+ msc->battery_desc.properties = magicmouse_v1_battery_props;
+ msc->battery_desc.num_properties = ARRAY_SIZE(magicmouse_v1_battery_props);
+ msc->battery_desc.get_property = magicmouse_v1_battery_get_property;
+
+ msc->battery = devm_power_supply_register(&hdev->dev,
+ &msc->battery_desc,
+ &psy_cfg);
+ if (IS_ERR(msc->battery)) {
+ hid_err(hdev, "can't register battery device\n");
+ msc->battery = NULL;
+ }
+ }
+
if (is_usb_magicmouse2(id->vendor, id->product) ||
(is_usb_magictrackpad2(id->vendor, id->product) &&
hdev->type != HID_TYPE_USBMOUSE))
next prev parent reply other threads:[~2026-04-16 12:53 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-04-15 15:55 [PATCH] HID: magicmouse: add battery reporting for Magic Trackpad v1 Damiano Gragnaniello
2026-04-15 20:41 ` [PATCH v2] " Damiano Gragnaniello
2026-04-15 21:31 ` [PATCH v3] " Damiano Gragnaniello
2026-04-15 21:53 ` [PATCH v4] " Damiano Gragnaniello
2026-04-16 12:53 ` Damiano Gragnaniello [this message]
2026-04-16 14:33 ` [PATCH v6] " Damiano Gragnaniello
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=20260416125317.172576-1-damianogragnaniello@gmail.com \
--to=damianogragnaniello@gmail.com \
--cc=bentiss@kernel.org \
--cc=jikos@kernel.org \
--cc=linux-input@vger.kernel.org \
/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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox