public inbox for linux-bluetooth@vger.kernel.org
 help / color / mirror / Atom feed
* [Bug 221263] New: HID: Apple Magic Mouse 2 (BT 0x004C:0x0323) reports wrong battery percentage -- hidinput_query_battery_capacity() reads buf[1]    (status byte) instead of buf[2] (AbsoluteStateOfCharge)
@ 2026-03-19 23:50 bugzilla-daemon
  2026-03-19 23:52 ` [Bug 221263] " bugzilla-daemon
  2026-03-20  9:06 ` bugzilla-daemon
  0 siblings, 2 replies; 3+ messages in thread
From: bugzilla-daemon @ 2026-03-19 23:50 UTC (permalink / raw)
  To: linux-bluetooth

https://bugzilla.kernel.org/show_bug.cgi?id=221263

            Bug ID: 221263
           Summary: HID: Apple Magic Mouse 2 (BT 0x004C:0x0323) reports
                    wrong battery percentage --
                    hidinput_query_battery_capacity() reads buf[1]
                    (status byte) instead of buf[2]
                    (AbsoluteStateOfCharge)
           Product: Drivers
           Version: 2.5
          Hardware: ARM
                OS: Linux
            Status: NEW
          Severity: normal
          Priority: P3
         Component: Bluetooth
          Assignee: linux-bluetooth@vger.kernel.org
          Reporter: wh6cyy@gmail.com
        Regression: No

Hi,

  I am reporting a confirmed bug in the HID battery subsystem that causes the
  Apple Magic Mouse 2 to permanently show 4% battery at boot when connected via
  Bluetooth.  The root cause has been isolated to a hardcoded byte-index
  assumption in hidinput_query_battery_capacity() (drivers/hid/hid-input.c)
  that is incompatible with the Magic Mouse 2's multi-field report 0x90
structure.


  --- System information ---

    Kernel:   6.18.15-400.asahi.fc43.aarch64+16k (Asahi Linux on Apple Silicon)
    Device:   Apple Magic Mouse 2, "William's Magic Mouse #2"
    BT MAC:   D0:C0:50:CF:DF:F1
    HID IDs:  Bus=0x0005 (Bluetooth), Vendor=0x004C (Apple BT),
              Product=0x0323
    Driver:   hid-magicmouse (BT path)


  --- Observed vs. expected behaviour ---

    /sys/class/power_supply/hid-d0:c0:50:cf:df:f1-battery/capacity
    reports: 4

    macOS reports 94% for the same mouse simultaneously (confirmed ground
truth).
    Occasional spontaneous correct readings (~95%) are observed at boot before
    the first sysfs read (see Race Condition section below), confirming the
    device transmits the correct value.

    UPower sysfs snapshot:

      POWER_SUPPLY_NAME=hid-d0:c0:50:cf:df:f1-battery
      POWER_SUPPLY_TYPE=Battery
      POWER_SUPPLY_STATUS=Discharging
      POWER_SUPPLY_CAPACITY=4
      POWER_SUPPLY_SCOPE=Device
      POWER_SUPPLY_MODEL_NAME=William's Magic Mouse #2


  --- HID Report Descriptor (battery collection) ---

  Full raw descriptor (from hid-recorder):
    R: 135 05 01 09 02 a1 01 85 12 05 09 19 01 29 02 15 00 25 01 95 02 75 01
    81 02 95 01 75 06 81 03 05 01 09 01 a1 00 16 01 f8 26 ff 07 36 01 fb 46
    ff 04 65 13 55 0d 09 30 09 31 75 10 95 02 81 06 75 08 95 02 81 01 c0 06
    02 ff 09 55 85 55 15 00 26 ff 00 75 08 95 40 b1 a2 c0 06 00 ff 09 14 a1
    01 85 90 05 84 75 01 95 03 15 00 25 01 09 61 05 85 09 44 09 46 81 02 95
    05 81 01 75 08 95 01 15 00 26 ff 00 09 65 81 02 c0

  Battery Application Collection (report 0x90):

    85 90          -- Report ID 0x90
    05 84          -- Usage Page: Power Device (0x84)
    75 01 95 03    -- Report Size 1, Count 3
    15 00 25 01    -- Logical Min 0, Max 1
    09 61          -- Usage: PresentStatus (0x61)          [bit 0]
    05 85          -- Usage Page: Battery System (0x85)
    09 44          -- Usage: Charging (0x44)               [bit 1]
    09 46          -- Usage: Discharging (0x46)            [bit 2]
    81 02          -- Input (FIELD 0: 3 x 1-bit status)
    95 05 81 01    -- 5-bit padding
    75 08 95 01    -- Report Size 8, Count 1
    15 00 26 ff 00 -- Logical Min 0, Max 255
    09 65          -- Usage: AbsoluteStateOfCharge (0x65)
    81 02          -- Input (FIELD 1: 8-bit charge)
    c0             -- End Collection

  Raw buffer layout for report 0x90 (as seen by the kernel):

    buf[0] = 0x90  -- report ID
    buf[1] = 0x04  -- FIELD 0: status byte (bit2=Discharging=1, rest=0)
    buf[2] = 0x5F  -- FIELD 1: AbsoluteStateOfCharge = 95 decimal


  --- Bluetooth traffic capture (btmon) ---

  The kernel queries:  41 90  (GET_REPORT, INPUT type, report ID 0x90)

  The mouse consistently responds:  a1 90 04 5f

    a1 = BT HID DATA INPUT header
    90 = report ID
    04 = status byte = 0b00000100 (bit2=Discharging)
    5f = AbsoluteStateOfCharge = 95 decimal  ← matches macOS 94%

  The value 0x5f=95 is stable across every captured report.


  --- Root cause ---

  hidinput_query_battery_capacity() in drivers/hid/hid-input.c:

    ret = hidinput_scale_battery_capacity(dev, buf[1]);   /* BUG */

  It hardcodes buf[1] as the battery byte.  For reports where the battery
  field is the first (and only) data field, buf[1] is correct.  For report
  0x90 on the Magic Mouse 2, buf[1] is the status byte (0x04 = 4) and the
  AbsoluteStateOfCharge is at buf[2] (0x5F = 95).

  Arithmetic confirming the bug:

    Observed: buf[1] = 0x04 = 4 → scale(4, 0, 100) = 4%  ✓ matches sysfs
    Correct:  buf[2] = 0x5F = 95 → scale(95, 0, 100) = 95%  ✓ matches macOS

  The correct byte offset is deterministic from the descriptor:
    1 + (field->report_offset / 8) = 1 + (8/8) = 2  →  buf[2]

  The leading 1 accounts for the report-ID byte prepended by
hid_hw_raw_request().


  --- Race condition / intermittent correct readings ---

  hidinput_get_battery_property() has two paths:

    A. Query path (buggy): when battery_status != HID_BATTERY_REPORTED, calls
       hidinput_query_battery_capacity() → reads buf[1] = 4 → returns 4%.

    B. Event-driven path (correct): after the first spontaneous HID INPUT
       event for report 0x90 processes the AbsoluteStateOfCharge usage via
       hid_input_var_field() (which correctly bit-extracts each usage's value
       per the descriptor), hidinput_update_battery() caches 95 in
       dev->battery_capacity and sets battery_status = HID_BATTERY_REPORTED.
       Subsequent sysfs reads return 95%.

  The race: if UPower reads sysfs before the first mouse input event (which is
  typical at boot), path A fires → 4%.  If the user moves the mouse before
  UPower reads → path B fires first → 95%.

  This explains the "sometimes correct at boot" behaviour: it is a genuine
  race between UPower's enumeration and the first spontaneous HID report.


  --- Why magicmouse_fetch_battery() does not apply ---

  magicmouse_fetch_battery() checks is_usb_magicmouse2() which tests:
    vendor == USB_VENDOR_ID_APPLE  /* 0x05AC */

  A BT-connected Magic Mouse 2 presents vendor=0x004C (Apple BT vendor ID),
  not 0x05AC.  is_usb_magicmouse2() returns false; the battery timer is never
  armed; all battery handling falls through to hid-input.c where the bug lives.


  --- Proposed fix direction ---

  Option A (general fix): Store the AbsoluteStateOfCharge field's byte offset
  at hidinput_configure_usage() time (e.g., in a new hdev->battery_field_offset
  member) and use it in hidinput_query_battery_capacity() instead of the
  hardcoded 1.

  Option B (device-specific): Extend is_usb_magicmouse2() to also accept
  BT_VENDOR_ID_APPLE (0x004C), arming the existing battery timer for BT-path
  devices so magicmouse_fetch_battery() runs and primes battery_status before
  the first sysfs read, bypassing the hid-input.c query path entirely.

  I do not have a tested patch yet.  I am happy to test patches.

  Regards,
  Will

  --
  Kernel: 6.18.15-400.asahi.fc43.aarch64+16k
  Platform: Apple Silicon (Asahi Linux / Fedora 43)

-- 
You may reply to this email to add a comment.

You are receiving this mail because:
You are the assignee for the bug.

^ permalink raw reply	[flat|nested] 3+ messages in thread

* [Bug 221263] HID: Apple Magic Mouse 2 (BT 0x004C:0x0323) reports wrong battery percentage -- hidinput_query_battery_capacity() reads buf[1]    (status byte) instead of buf[2] (AbsoluteStateOfCharge)
  2026-03-19 23:50 [Bug 221263] New: HID: Apple Magic Mouse 2 (BT 0x004C:0x0323) reports wrong battery percentage -- hidinput_query_battery_capacity() reads buf[1] (status byte) instead of buf[2] (AbsoluteStateOfCharge) bugzilla-daemon
@ 2026-03-19 23:52 ` bugzilla-daemon
  2026-03-20  9:06 ` bugzilla-daemon
  1 sibling, 0 replies; 3+ messages in thread
From: bugzilla-daemon @ 2026-03-19 23:52 UTC (permalink / raw)
  To: linux-bluetooth

https://bugzilla.kernel.org/show_bug.cgi?id=221263

--- Comment #1 from will (wh6cyy@gmail.com) ---
The bug also existed on Fedora Asahi 42.

-- 
You may reply to this email to add a comment.

You are receiving this mail because:
You are the assignee for the bug.

^ permalink raw reply	[flat|nested] 3+ messages in thread

* [Bug 221263] HID: Apple Magic Mouse 2 (BT 0x004C:0x0323) reports wrong battery percentage -- hidinput_query_battery_capacity() reads buf[1]    (status byte) instead of buf[2] (AbsoluteStateOfCharge)
  2026-03-19 23:50 [Bug 221263] New: HID: Apple Magic Mouse 2 (BT 0x004C:0x0323) reports wrong battery percentage -- hidinput_query_battery_capacity() reads buf[1] (status byte) instead of buf[2] (AbsoluteStateOfCharge) bugzilla-daemon
  2026-03-19 23:52 ` [Bug 221263] " bugzilla-daemon
@ 2026-03-20  9:06 ` bugzilla-daemon
  1 sibling, 0 replies; 3+ messages in thread
From: bugzilla-daemon @ 2026-03-20  9:06 UTC (permalink / raw)
  To: linux-bluetooth

https://bugzilla.kernel.org/show_bug.cgi?id=221263

Bastien Nocera (bugzilla@hadess.net) changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |bugzilla@hadess.net
          Component|Bluetooth                   |Input Devices
           Assignee|linux-bluetooth@vger.kernel |drivers_input-devices@kerne
                   |.org                        |l-bugs.osdl.org

--- Comment #2 from Bastien Nocera (bugzilla@hadess.net) ---
This isn't a Bluetooth issue, the problem is in the HID drivers, reassigning.

-- 
You may reply to this email to add a comment.

You are receiving this mail because:
You are the assignee for the bug.

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2026-03-20  9:06 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-19 23:50 [Bug 221263] New: HID: Apple Magic Mouse 2 (BT 0x004C:0x0323) reports wrong battery percentage -- hidinput_query_battery_capacity() reads buf[1] (status byte) instead of buf[2] (AbsoluteStateOfCharge) bugzilla-daemon
2026-03-19 23:52 ` [Bug 221263] " bugzilla-daemon
2026-03-20  9:06 ` bugzilla-daemon

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox