Notes and tools for the Steam Controller 2 (Triton): HID input layout, firmware update protocol, feature-report routing, static analysis of the firmware blobs, and a generated per-build firmware change log.
Status: a host-side reference and learning artifact, lightly maintained. For actively-developed SC2 work (open custom firmware, a DIY replacement puck, Linux drivers) see the Related SC2 projects list under Background. Corrections here are still welcome via issues / PRs.
Most of this comes from extracting hardwareupdater.x86_64 (the PyInstaller bundle that ships with the Steam client) and verifying against an actual SC2 + Puck on a Steam Deck (SteamOS) with controller firmware bcdDevice 0.02. Hobby project with heavy AI assistance (see Disclaimer).
Covers: SC2 (USB 28DE:1302/1303), the Proteus puck (28DE:1304), and the parallel Nereid dongle (28DE:1305). Nereid is plausibly the Steam-Machine-integrated dongle, based on SDL3 commit timing and the absence of a Nereid bootloader path in Steam's user-facing updater.
| Path | Contents |
|---|---|
docs/FIRMWARE_PROTOCOL.md |
Update protocol: HDLC framing, message IDs, firmware-file format, bootloader-mode switching, live feature-report attribute queries, ARM Cortex-M static analysis. |
docs/METHODOLOGY.md |
RE notes: PyInstaller-bundle extraction, bytecode disassembly without a decompiler, the InHand-flag debunking, capture-timing pitfalls, SteamOS ACL quirks, multi-device fr_id routing. |
docs/CONTROLLER_CAPABILITIES.md |
Hardware notes: chip identification, USB topology, haptic actuator sides, components found via firmware-string analysis. |
docs/HID_REPORT_FORMAT.md |
The 54-byte Report-0x42 layout (from SDL3, verified against ~9k frames), puck USB topology, Lizard-mode timing, sub-reports 0x43 (battery) and 0x7b (the one Triton input report ID not in SDL3), SteamOS access notes. |
docs/SDL3_REFERENCE.md |
Cross-reference of what SDL3's open-source code says about Triton: report IDs, output haptic message types, settings, audio cues, charge states, IMU axis swizzle and scaling, trackpad transforms, timing constants. |
docs/HAPTICS.md |
Cross-reference of the haptic + audio output reports (0x80–0x89), reverse-engineered by iczero: actuator sides, script IDs, audio-stream formats, the 0x44 feedback channel. |
docs/CHANGELOG.md |
Per-build firmware change log: a binary diff of every version in the Ibex-Firmware archive, showing the size and which strings changed between builds. Generated by tools/fw_changelog.py. |
Python 3.10+, stdlib only. Run as the deck user on SteamOS (not sudo: root is blocked by the hidraw ACL).
Firmware analysis & extraction:
| Tool | What it does |
|---|---|
tools/extract_pyinst.py |
Minimal PyInstaller bundle extractor: MEI cookie + TOC walker. |
tools/walk_pyc.py |
Walks marshaled Python code objects, lists nested functions + constants. |
tools/analyze_fw.py |
Parses ARM Cortex-M firmware blobs (header, vector table, IRQ handlers, strings). |
tools/attr_query.py |
Sends HID Feature-Reports via ioctl to query device attributes. |
tools/fw_changelog.py |
Diffs two firmware versions (or sweeps the whole archive) into a plain "what changed" report: size, and which strings appeared or vanished. Pulls the blobs from the Ibex-Firmware archive, so no controller is needed. |
Live capture & observation:
| Tool | What it does |
|---|---|
tools/live_monitor.py |
Streams /dev/hidraw9, prints button transitions + analog deflection. |
tools/one_capture.py NAME [NAME...] |
Captures 3 s of hidraw9 traffic per named action; diffs against a baseline. |
tools/event_logger.py [seconds] |
Parallel logger across hidraw9–13; report-ID histogram per interface. |
git clone <this-repo>
cd sc2-research
# Probe puck + controller via HID Feature-Reports
python3 tools/attr_query.py
# Extract Steam's firmware updater
python3 tools/extract_pyinst.py
python3 tools/walk_pyc.py
# Analyse a firmware blob
python3 tools/analyze_fw.py ~/.local/share/Steam/bin/hardwareupdater/IBEX_FW_69FA5889.fwValve's own open releases this work builds on:
- SDL3
SDL_hidapi_steam_triton.c— driver Sam Lantinga upstreamed in commit1998b6504(Nov 12 2025) - SDL3
controller_structs.h - SDL3
controller_constants.h hardwareupdater.x86_64in~/.local/share/Steam/bin/hardwareupdater/— the PyInstaller bundle that ships with the Steam client.
Related SC2 projects (several are further along than this repo, and are cross-checked throughout the docs):
mwdmwd/sc26re— open custom firmware (Zephyr) for the controller, flashed over SWD and already playable. The authoritative source for how the hardware works; independently confirms the nRF52833 SoC, the 0x42 layout, the firmware-file header, the feature opcodes and the I2C map used here.iczero/steam-controller-stuff— Wireshark dissector + audio player; the reference for the haptic/audio output protocol (docs/HAPTICS.md).safijari/openpuck— firmware for an ~$8 nRF52840 Pro Micro that replaces the puck and emulates Xbox/Switch/PS pads; itsdocs/PROTOCOL.mdcovers the host↔puck and 2.4 GHz RF layers.OpenSteamController/Ibex-Firmware— versioned archive of every.fwblob Valve ships (source of the reproducible firmware links below). Documents the 32-byte header (CRC32 at0x08).- Use-without-Steam drivers:
Rune580/sc-evdev(Linux evdev),njanke96/steam-controller-dsu(motion/DSU), among others.
Adjacent / historical:
- SteamHapticsSinger — haptic MIDI player. "Note-On
0x83" =HAPTIC_LFO_TONE, "Note-Off0x81" =HAPTIC_PULSE. - SteamlessController — Windows tool that disables Lizard mode and bridges Report 0x42 to a virtual Xbox 360 pad.
- OpenSteamController (greggersaurus) — RE for the 2015 Steam Controller (LPC11U37F + nRF51822); architecturally unrelated to the SC2.
Hardware identification:
- iFixit Steam Controller (2nd Generation) — chip markings read as nRF52833. Confirmed: the SoC is the nRF52833 (an earlier version of this repo wrongly "corrected" this to nRF52840; see
docs/FIRMWARE_PROTOCOL.md§Hardware inference for the retraction). - PC Gamer 2026 teardown, GamersNexus review, PCGamingWiki.
Codenames that were already public before this work:
- Brad Lynch on X, Nov 19 2024 — "Ibex".
- Tom's Hardware Q4 2025 — "Ibex" + "Roy".
- NeoGAF Q4 2025 — "Triton".
- Phoronix Nov 12 2025 — "Proteus" and "Nereid".
MIT: see LICENSE. Some patterns credited inline to the BSD-3-Clause SteamHapticsSinger.
Hobby project, done with heavy AI assistance (Claude) for hypothesis-testing, cross-referencing, and drafting. The hardware testing, firmware extraction, and packet captures were on my own Steam Deck (SteamOS) with an SC2 + Puck (USB bcdDevice 0.02). Cross-checked against SDL3 source where possible; I may have missed conventions someone with deeper RE background would catch. Corrections via issues / PRs welcome.
Baseline: the firmware blobs analysed here are IBEX_FW_69FA5889 + 69FE17FF (Triton) and PROTEUS_FW_69FA587F + 69FBD45D (Proteus), all from early May 2026. Both pairs are byte-identically mirrored in OpenSteamController/Ibex-Firmware, so anyone can reproduce the analysis without their own Steam install:
curl -O https://opensteamcontroller.github.io/Ibex-Firmware/Controller/IBEX_FW_69FE17FF.fw
curl -O https://opensteamcontroller.github.io/Ibex-Firmware/Puck/PROTEUS_FW_69FBD45D.fw
python3 tools/analyze_fw.py IBEX_FW_69FE17FF.fwValve has shipped further updates since (the June 2026 release added LED dimming in settings + trigger-deadzone tweaks). The protocol layer is expected to be stable across these; static-analysis offsets are tied to the specific FW versions above.
No proprietary code or firmware blobs are redistributed here. For the blobs see OpenSteamController/Ibex-Firmware. No affiliation with Valve.