Skip to content

Report Descriptor

Syax89 edited this page Jul 8, 2026 · 1 revision

HID Report Descriptor

The device reports a 936-byte HID report descriptor (RPT_DESC, wire type 8) describing 8 top-level collections: a standard Digitizer Pen collection (Report ID 0x01), a standard TouchScreen collection (Report ID 0x40), and several vendor/raw collections used for the experimental raw heatmap mode (see Multi-touch Experimental).

Prefer the real device, patch only what's broken

Earlier iterations of this driver just used a hardcoded copy of the descriptor as a fallback of last resort. The current driver prefers reading it live from the device every boot — spi_hid_ll_parse() tries shid->wire_report_descriptor (populated by the RPT_DESC handling in spi_hid_seq_thread()) first, and only falls back to the hardcoded copy (driver/hardcoded_rd.h) if the live one fails hid_parse_report() — this also picks up firmware updates or descriptor differences across SKUs automatically.

Why hid_parse_report() alone isn't enough

hid_parse_report()'s return code is not a reliable validity signal — it can return success with just a non-fatal "unexpected long global item" warning even for a structurally corrupted descriptor. The real failure only surfaces later, inside hid_add_device(), when the kernel's own driver-matching machinery tries (and synchronously fails) to bind hid-generic against the malformed parsed structure — and hid_add_device() itself still returns success in that case. The actual reliable signal implemented here is checking hid->driver == NULL after a "successful" hid_add_device() call; if that's true, the driver retries once with the hardcoded descriptor.

The 64-byte page defect and its 14-byte patch

As covered in Wire Protocol, fetching the descriptor in 64-byte chunks reveals a hardware quirk: byte n·64+58 of every chunk (14 positions across the 936-byte descriptor) reads back as a spurious 0xFF, reproducibly, independent of SPI clock speed and of the host's own chunk boundaries — i.e. it's tied to the device's own internal page structure, not to anything the driver controls.

Since these are the only 14 bytes ever wrong, and always the same ones, the driver applies a targeted, minimal patch: only those 14 byte positions are overwritten from hardcoded_report_descriptor (used purely as ground truth for those positions, cross-checked against a real Windows ETW capture), while the other 922/936 bytes (98.5%) come from the live wire read on every boot.

/* driver/spi-hid-core.c, inside the RPT_DESC handling */
for (k = 55; k < len; k += 64) {
        if (shid->wire_report_descriptor[k] == 0xFF &&
            k < HARDCODED_RD_SIZE &&
            hardcoded_report_descriptor[k] != 0xFF) {
                shid->wire_report_descriptor[k] = hardcoded_report_descriptor[k];
        }
}

(The patch loop's phase is 55, not the raw 58 measured against the wire capture, because by the time the descriptor bytes reach this buffer the 3-byte [len16][ContentID] prefix has already been stripped — an off-by-3 bug that was caught and fixed during development, worth remembering if this code is touched again.)

With the patch applied, the live-read descriptor parses successfully and binds hid-generic on the first attempt essentially every time.

Clone this wiki locally