DEV Community

Cover image for Reverse-engineering the Steam Machine's RGB LEDs — and controlling them on Windows
Szarow Łukasz
Szarow Łukasz

Posted on

Reverse-engineering the Steam Machine's RGB LEDs — and controlling them on Windows

Intro
The Steam Machine's front panel has 17 addressable RGB LEDs. On SteamOS you get a slick
control UI; on Windows — nothing. I wanted my lights back, so I reverse-engineered how
they work and rebuilt control from scratch. Here's the whole trail.

1. How SteamOS drives it
ls /sys/class/leds/ shows valve-leds[0..16] — 17 multicolour LEDs exposed by the
kernel module leds_valve (drivers/leds/rgb, by Collabora, GPL, in-tree in Valve's
neptune kernel). It's a platform driver bound by DMI match (svn*Valve*:pn*Fremont*),
and it talks to the board over x86 I/O ports, not USB or WMI.

2. Finding the ports
/proc/ioports (as root) shows a valve-leds region at 0x0DE8–0x0E7A plus a single
byte at 0x6C. The driver even exposes a regmap in debugfs. To map the registers I set a
known gradient through sysfs (LED i → R=0x10+i, G=0x30+i, B=0x50+i) and dumped the
whole window via /dev/port. The ascending pattern gave away the layout instantly.

3. The register layout
Two parallel 17×(R,G,B) blocks:

  • Block B (offset 0x51): the raw colour you set.
  • Block A (offset 0x1B): the driven PWM — the EC computes it from B. Plus effect/params registers near the end, and startup (boot) colour at 0x01.

4. Confirming it
Writing colours straight to the ports via /dev/port — with the kernel driver bypassed
— changed the physical LEDs. That's the whole ballgame: the same writes work from any
ring0 code, including Windows.

5. Porting to Windows
User-mode Windows can't run IN/OUT, so I call a signed ring0 helper (inpoutx64 /
WinRing0) to poke the exact same ports — the technique OpenRGB uses for EC/SMBus gear.
The ports are decoded by the machine's EC, so it "just works" once you're on the box.

6. Bonus: temps and fan
The EC mirrors a ChromeOS-EC memory-mapped region at I/O port 0x900: temperatures
(one byte each, °C) and fan RPM (16-bit LE). Reading those gives a live system monitor right in the lighting app.

7. The fan-control rabbit hole
Setting fan RPM needs writing an MMIO register at 0xFE700B92 (that's how Steam Deck Tools
does it). inpoutx64 can't map that MMIO on current Windows 11 — even as SYSTEM — because
the OS restricts \Device\PhysicalMemory for MMIO. So control stays off; monitoring works.

The result
SteamLEDs: per-LED colour, effects, an animation builder, national-flag "stadium wave"
animations, reactive modes (temp/CPU/screen/mouse), 7 languages, tray + autostart.
Free & open-source: github.com/eviance/steamleds

How works

Top comments (0)