From 8d811f09cc1bd2399869d2511369f9afd98d2d4c Mon Sep 17 00:00:00 2001 From: MarcelineVPQ Date: Sun, 7 Jun 2026 10:36:10 -0600 Subject: [PATCH] fix(hid): serve the controller's REAL 0x09/0x20/0x05 feature data to the host The native-recognition shortcut answered 0x09 (pairing), 0x20 (firmware) and 0x05 (calibration) with zeros + a valid crc. hid_playstation accepted that (it checks size+crc only), but games validate the actual CONTENT: Cyberpunk GET-read 0x20/0x09 ~156x in a retry storm rejecting the zeros, never completed the DualSense handshake, and showed no controller / no adaptive triggers. init_feature() already caches the real reports from the controller over BT, so serve those (via get_feature_data) for 0x09/0x20/0x05, keeping the crc-valid synthetic stub only as a fallback for the USB-enumeration probe before the BT link (so the kernel still binds then). The dongle now returns the genuine firmware string / pairing / calibration, and native adaptive triggers work in games through the dongle, 1:1 with a wired DualSense. Co-Authored-By: Claude Opus 4.8 --- src/main.cpp | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 3a50d38..bd44eef 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -257,15 +257,30 @@ uint16_t tud_hid_get_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t // only for the report DATA (reqlen = report_size - 1); usbhid prepends the // report-id byte itself. The two CRC'd reports validate crc32 over // [0xA3 feature-seed, report_id, data...] in the last 4 bytes. - if (report_id == 0x09) { // pairing info → controller MAC at [0..5] + // hid_playstation (kernel) AND the game's native DualSense detection both read + // 0x09 (pairing), 0x20 (firmware) and 0x05 (calibration). The KERNEL only checks + // size + crc, but the GAME validates the actual CONTENT — so synthesized zeros + // pass the kernel yet get rejected by the game (a ~156x GET retry storm, and no + // native adaptive triggers). Serve the REAL controller data, which init_feature() + // caches from the controller over BT (get_feature_data returns it incl. the + // report-id at [0]). Fall back to a crc-valid synthetic answer ONLY when the + // controller isn't linked yet (USB-enumeration probe before the BT link), so the + // kernel still binds at that moment. + if (report_id == 0x09 || report_id == 0x20 || report_id == 0x05) { if (reqlen == 0) return 0; + std::vector real = get_feature_data(report_id, reqlen); + if (real.size() > 1) { // real cached response present + uint16_t n = (uint16_t)(real.size() - 1); + if (n > reqlen) n = reqlen; + memcpy(buffer, real.data() + 1, n); + return n; + } memset(buffer, 0, reqlen); - if (reqlen >= 6) bt_get_addr(buffer); - return reqlen; - } - if (report_id == 0x20 || report_id == 0x05) { // firmware info / calibration (CRC-checked) - if (reqlen < 5) return 0; - memset(buffer, 0, reqlen); // zero payload; kernel validates size + CRC only + if (report_id == 0x09) { // not linked yet: MAC-only stub + if (reqlen >= 6) bt_get_addr(buffer); + return reqlen; + } + if (reqlen < 5) return 0; // 0x20 / 0x05 stub: zeros + valid crc32 uint8_t tmp[2 + 64]; tmp[0] = 0xA3; tmp[1] = report_id; memcpy(tmp + 2, buffer, reqlen - 4);