fix(firmware): route 0x10/0x21 output reports to subcommand handler

The Switch sends subcommands (IMU enable, SPI reads, vibration enable,
player lights, etc.) inside 0x10 and 0x21 output reports at byte 10.
The firmware extracted rumble data from these reports but never routed
the subcommand to handle_feature_report() — it fell through the
if-else chain silently.

This caused the handshake to stall: the Switch kept retrying early
subcommands (0x00-0x0f cycling) because it never received ACK replies.
It never progressed to sending 0x40 (Toggle IMU), 0x10 (SPI Read),
0x48 (Enable Vibration), or 0x30 (Set Player Lights).

The IMU was technically sending data, but the Switch never enabled it
via subcommand 0x40, so the Switch's IMU processing was undefined.

Fix: after extracting rumble from 0x10/0x21 reports, also pass them
to handle_feature_report() so the subcommand at buffer[10] gets
processed and ACK'd. Same fix applied to both tud_hid_set_report_cb
and tud_hid_report_received_cb.
This commit is contained in:
Joey Yakimowich-Payne 2026-03-16 18:32:45 -06:00
commit e7c01d1116
No known key found for this signature in database
GPG key ID: DDF6AF5B21B407D4

View file

@ -794,13 +794,18 @@ void tud_hid_set_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_
if (switchReportID == REPORT_OUTPUT_00) {
// No-op, just acknowledge to clear any stalls.
return;
} else if (switchReportID == REPORT_OUTPUT_10 || switchReportID == REPORT_OUTPUT_21) {
// 0x10/0x21 output reports carry rumble (bytes 2-9) AND a subcommand
// at byte 10. The Switch sends IMU enable (0x40), SPI reads (0x10),
// vibration enable (0x48), player lights (0x30), etc. via these reports.
queued_report_id = report_id;
handle_feature_report(switchReportID, switchReportSubID, buffer, bufsize);
} else if (switchReportID == REPORT_FEATURE) {
queued_report_id = report_id;
handle_feature_report(switchReportID, switchReportSubID, buffer, bufsize);
} else if (switchReportID == REPORT_CONFIGURATION) {
queued_report_id = report_id;
handle_config_report(switchReportID, switchReportSubID, buffer, bufsize);
} else {
}
}
@ -817,6 +822,9 @@ void tud_hid_report_received_cb(uint8_t instance, uint8_t report_id, uint8_t con
}
if (switchReportID == REPORT_OUTPUT_00) {
return;
} else if (switchReportID == REPORT_OUTPUT_10 || switchReportID == REPORT_OUTPUT_21) {
queued_report_id = report_id;
handle_feature_report(switchReportID, switchReportSubID, buffer, bufsize);
} else if (switchReportID == REPORT_FEATURE) {
queued_report_id = report_id;
handle_feature_report(switchReportID, switchReportSubID, buffer, bufsize);