[RFC] HID: battery support design for Fractal Scape USB dongle (36bc:0001)

From: Andreas Kotiagin <hidden>
Date: 2026-09-15 17:08:50

Hello,

I am investigating battery reporting for the Fractal Scape wireless headset
through its USB dongle, with the intention of exposing a peripheral battery
through power_supply. Before building a substantial driver, I would appreciate
feedback on the integration and coexistence approach below.

Descriptor observations from an attached 36bc:0001 dongle (bcdDevice 3.21):

- Interfaces 0-2 are USB audio. Interface 3 is the only HID interface.
- That HID interface contains consumer controls, telephony, and vendor
  collections. The final collection is usage page 0xff00, usage 1, with
  report ID 2 and 63 payload bytes for both input and output.
- It has an interrupt IN endpoint 0x84, max packet 64, and no interrupt OUT
  endpoint. The complete HID report descriptor is 177 bytes.
- There is no advertised standard battery usage. The whole HID interface
  currently binds to hid-generic.

Source inspection of ScapeCtl at commit
b5ec62ccbbb090dec24c614c5580fd1b2bf6fdbb indicates a status output request
consisting of report ID 02 followed by f1 21 and 61 zero bytes. Its parser
uses payload byte 14 for percentage and payload byte 18 == 1 for connection
(raw report offsets 15 and 19, respectively). Replies echo f1 21. It uses a
500 ms response deadline, a default 1.5 second polling interval, and also
sends a separate keepalive. Its README reports unsolicited 11 21 messages
but warns that their presence byte is unreliable.

These response semantics are source-derived, not yet confirmed on the attached
headset. Captures across power-off, range loss, docking and cable charging,
comparison with Fractal Adjust, and the need for keepalive at slower polling
rates are still pending. No charging field has been established. ScapeCtl's
root license is GPLv3; the planned kernel implementation will be independently
written from protocol facts and hardware measurements, without copying or
translating its code.

Proposed design:

- A small dedicated hid-scape driver matching only USB 36bc:0001, interface 3,
  with input/output report-size and vendor-usage checks. No hub or unverified
  wired-headset IDs.
- Normal hid_parse / hid_hw_start(HID_CONNECT_DEFAULT) / hid_hw_open, with
  raw_event returning 0 so media controls and hidraw continue to receive
  reports. Audio interfaces remain with snd-usb-audio.
- Cached power_supply data parented to the HID device, SCOPE_DEVICE,
  CAPACITY 0-100 after validated input, STATUS_UNKNOWN until charging is
  established, and no invented voltage, current or energy properties.
  Connection and stale-data semantics must be settled by measurements;
  a timeout must not be exposed as zero percent.
- Initial 60 second polling from scheduled work using an output SET_REPORT,
  with a bounded response deadline, conservative backoff, and synchronous
  work cancellation on removal/suspend. No USB I/O in property callbacks.
- A way to pause polling and drain outstanding driver requests before
  Adjust/ScapeCtl configuration sessions. There is no known transaction ID;
  separate hidraw readers and ScapeCtl's process-local mutex do not establish
  safe simultaneous device access. Passive reception can still cache valid
  status while preserving all incoming reports.

The v6.18 SteelSeries headset driver is a useful integration reference, but
the opaque vendor protocol appears to need more than a generic HID battery
quirk. Does a dedicated HID driver fit here? Is there an existing preferred
mechanism for coordinating such polling with hidraw configuration clients,
or a recommended precedent for a per-device polling pause control?

I will provide raw captures, lifecycle/coexistence results and a tested patch
once those outstanding hardware questions are resolved. This is a design
inquiry, not a request to merge unverified protocol support.

ScapeCtl source inspected:
https://github.com/charlietran/scapectl/tree/b5ec62ccbbb090dec24c614c5580fd1b2bf6fdbb

Thanks,
Andreas Kotiagin
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help