feat: HDMI-CEC with Valve's cecd, on any PC

Opt-in menu item: cecd, cec-audio-control and inputattach-cec-units from
Valve's holo repository (SHA-256 checked). Works with any /dev/cec*.
This commit is contained in:
theupriser committed 2026-09-25 09:11:44 +02:00
1 parent ebbc70b213
commit 72a18232a5
8 files changed
+163 -8

No files matched your search

+11
View File
@@ -5,6 +5,17 @@ All notable changes, per version and per commit. Versions follow
`steamify.sh`. Versions before 0.7.0 were numbered afterwards, `steamify.sh`. Versions before 0.7.0 were numbered afterwards,
one per merged pull request. one per merged pull request.
## 1.1.0 - 2026-09-25
- **feat: HDMI-CEC** (experimental, never ticked by default, on every PC)
- Valve's `cecd`, `cec-audio-control` and `inputattach-cec-units` from its
SteamOS repository (SHA-256 checked): use Steam with the TV remote, and
the TV turns on and off with the PC. On a Steam Machine, steamos-manager
configures it from Steam's settings.
- Works with any `/dev/cec*` (GPU or USB adapter); the menu lists them.
- The README no longer says Steam Machine support alone gives HDMI-CEC:
`cecd` wasn't installed, so it didn't.
## 1.0.0 - 2026-09-25 ## 1.0.0 - 2026-09-25
- **feat: Pin the kernel to 7.1.6-1 on a Steam Machine** - **feat: Pin the kernel to 7.1.6-1 on a Steam Machine**
+5 -1
View File
@@ -27,13 +27,17 @@ Steam Machine.
([details](TECHNICAL.md#single-user-mode-sddm-no-locking)). ([details](TECHNICAL.md#single-user-mode-sddm-no-locking)).
5. **Steamify shortcut** - an icon on the desktop and in the launcher that 5. **Steamify shortcut** - an icon on the desktop and in the launcher that
opens the newest Steamify, so you don't need the install command again. opens the newest Steamify, so you don't need the install command again.
6. **HDMI-CEC** (experimental, off by default) - use Steam with your TV's
remote, and the TV turns on and off with the PC. Needs a GPU with CEC (like
the Steam Machine) or a USB CEC adapter
([details](TECHNICAL.md#hdmi-cec)).
## Steam Machine ## Steam Machine
On a Valve Steam Machine the menu has two more items: On a Valve Steam Machine the menu has two more items:
- **Steam Machine support** - the front **LED bar** works, Steam's - **Steam Machine support** - the front **LED bar** works, Steam's
**hardware settings** (fan, TV control over HDMI-CEC) work, and the power **hardware settings** (fan, performance) work, and the power
button puts it to sleep like a console. button puts it to sleep like a console.
- **Pin the kernel to 7.1.6-1** - on by default: with newer CachyOS kernels - **Pin the kernel to 7.1.6-1** - on by default: with newer CachyOS kernels
the Steam Machine reboots instead of shutting down. Untick it once CachyOS the Steam Machine reboots instead of shutting down. Untick it once CachyOS
+33 -2
View File
@@ -154,8 +154,9 @@ The **Steam Machine support** component, only shown on Fremont hardware
- console-like power button: it puts the machine to sleep, and it never - console-like power button: it puts the machine to sleep, and it never
suspends by itself on mains power (the launcher's Shut Down still shuts down); suspends by itself on mains power (the launcher's Shut Down still shuts down);
- installs and enables `steamos-manager`, the service Steam in gaming mode - installs and enables `steamos-manager`, the service Steam in gaming mode
uses for hardware settings (fan, HDMI-CEC, performance); it recognises the uses for hardware settings (fan, performance, and the HDMI-CEC settings
Steam Machine from its DMI data. when [HDMI-CEC](#hdmi-cec) is on); it recognises the Steam Machine from its
DMI data.
Turning it off removes all of that again (the AUR helper is kept). Turning it off removes all of that again (the AUR helper is kept).
@@ -168,6 +169,35 @@ or upgraded. A newly added kernel doesn't come with its headers, so
`ensure-kernel-headers.service` checks at every boot and installs any `ensure-kernel-headers.service` checks at every boot and installs any
missing `-headers` package, which makes DKMS build the driver for it. missing `-headers` package, which makes DKMS build the driver for it.
## HDMI-CEC
The **HDMI-CEC** item (on every PC, never ticked by default) installs
Valve's CEC stack from its SteamOS `holo` repository, the newest `holo-X.Y`
on `steamdeck-packages.steamos.cloud`, each package checked against the
SHA-256 in Valve's package index:
- `cecd`, Valve's CEC daemon (a user service started with the desktop and
gaming mode): TV remote keys become normal key presses (arrows, Enter,
Back), and it turns the TV on and off with the PC;
- `cec-audio-control`: volume of the TV or receiver;
- `inputattach-cec-units` (with `linuxconsole` from CachyOS for
`inputattach`): attaches USB CEC adapters (Pulse-Eight, RainShadow).
It works with any `/dev/cec*`: a GPU that has CEC on its HDMI port (the
Steam Machine; the CachyOS kernel has DisplayPort CEC built in) or a USB
adapter. The menu lists the CEC devices found. Also turn on CEC on the TV
(Sony: BRAVIA Sync, Samsung: Anynet+, LG: SimpLink). On a Steam Machine
`steamos-manager` writes cecd's settings from Steam's (wake the TV, put it to
sleep), in `~/.config/cecd/config.d/`.
It's experimental: on SteamOS itself CEC can wake the Steam Machine right
after it goes to sleep (Samsung TVs,
[SteamOS#2626](https://github.com/ValveSoftware/SteamOS/issues/2626)) and
upset CEC for the TV's other devices
([SteamOS#2817](https://github.com/ValveSoftware/SteamOS/issues/2817)).
Turning it off removes the packages again (`linuxconsole` only if the
wizard installed it).
## Kernel pin (Steam Machine) ## Kernel pin (Steam Machine)
With CachyOS kernels newer than 7.1.6 a Steam Machine reboots instead of With CachyOS kernels newer than 7.1.6 a Steam Machine reboots instead of
@@ -256,6 +286,7 @@ immediately, which can turn into a loop - see
| `lib/single-user.sh` | Single user mode: no lock screen, user switching or log out | | `lib/single-user.sh` | Single user mode: no lock screen, user switching or log out |
| `lib/wizard-shortcut.sh` | Steamify shortcut: desktop icon and launcher entry that run the newest release | | `lib/wizard-shortcut.sh` | Steamify shortcut: desktop icon and launcher entry that run the newest release |
| `lib/bios.sh` | Update BIOS (Steam Machine, opt-in): current/newest version, double confirmation, fwupd | | `lib/bios.sh` | Update BIOS (Steam Machine, opt-in): current/newest version, double confirmation, fwupd |
| `lib/cec.sh` | HDMI-CEC: Valve's `cecd` and friends from its `holo` repository |
| `lib/steam-machine.sh` | Steam Machine support: LED driver, LED access, steamos-manager; kernel pin | | `lib/steam-machine.sh` | Steam Machine support: LED driver, LED access, steamos-manager; kernel pin |
| `.github/tools/bundle.sh` | Builds the single-file version (`dist/steamify.sh`) | | `.github/tools/bundle.sh` | Builds the single-file version (`dist/steamify.sh`) |
| `.github/workflows/bundle.yml` | Builds and checks it on every push; publishes it on `main` | | `.github/workflows/bundle.yml` | Builds and checks it on every push; publishes it on `main` |
+18
View File
@@ -32,6 +32,24 @@ cat /var/lib/dkms/leds-valve-dkms/0.1/build/make.log
journalctl --user -b | grep -i led journalctl --user -b | grep -i led
``` ```
## The TV remote does nothing (HDMI-CEC)
- Turn on CEC in the TV's settings (Sony: BRAVIA Sync, Samsung: Anynet+, LG:
SimpLink) and, if it has one, allow the PC to control it.
- Check that the PC has a CEC device, and that `cecd` runs:
```bash
ls /dev/cec*
systemctl --user status cecd
journalctl --user -u cecd -b
cec-ctl -d /dev/cec0 -S # the devices on the TV's CEC bus (v4l-utils)
```
No `/dev/cec*`: your GPU's HDMI port has no CEC; a USB CEC adapter
(e.g. Pulse-Eight) works. The Steam Machine wakes up again right after going
to sleep, or other devices lose CEC? That happens on SteamOS too; turn
HDMI-CEC off in the wizard.
## The Steam Machine still reboots when I shut it down ## The Steam Machine still reboots when I shut it down
Check that the pinned kernel is installed and running: Check that the pinned kernel is installed and running:
+88
View File
@@ -0,0 +1,88 @@
#!/bin/bash
# "HDMI-CEC" menu item, on any PC: Valve's CEC daemon (cecd), TV/receiver
# volume control (cec-audio-control) and the units that attach USB CEC
# adapters (Pulse-Eight, RainShadow) with inputattach. They're only in
# Valve's SteamOS (holo) repository, not in CachyOS or the AUR. Works with
# any /dev/cec*: a GPU with CEC (e.g. the Steam Machine) or a USB adapter.
# On a Steam Machine, steamos-manager configures cecd from Steam's settings.
# Sourced by steamify.sh; not meant to be run on its own.
CEC_PKGS=(cecd cec-audio-control inputattach-cec-units)
cec_status() { pacman -Q "${CEC_PKGS[@]}" >/dev/null 2>&1; }
fetch_holo_pkg() {
# fetch_holo_pkg <dir> <package>: download the newest <package> from
# Valve's newest holo repository into <dir> and print its path. The
# SHA-256 comes from Valve's package index and is verified.
local dir="$1" name="$2" repo desc file_name sha256
repo="$(curl -fsL "$VALVE_MIRROR/" | grep -oE 'holo-[0-9]+\.[0-9]+/' | tr -d / | sort -V | tail -n 1)"
if [[ ! -f "$dir/holo.db" ]]; then
[[ -n "$repo" ]] && curl -fsL "$VALVE_MIRROR/$repo/os/x86_64/$repo.db" -o "$dir/holo.db" ||
{ err "Couldn't read Valve's SteamOS package index ($VALVE_MIRROR)."; return 1; }
fi
desc="$(tar -tf "$dir/holo.db" 2>/dev/null | grep -E "^$name-[0-9][^/]*/desc$" | head -n 1)"
[[ -n "$desc" ]] || { err "No $name in Valve's $repo repository."; return 1; }
file_name="$(tar -xOf "$dir/holo.db" "$desc" | awk '/^%FILENAME%$/ { getline; print }')"
sha256="$(tar -xOf "$dir/holo.db" "$desc" | awk '/^%SHA256SUM%$/ { getline; print }')"
info "Downloading $file_name ($repo)..." >&2
curl -fsL "$VALVE_MIRROR/$repo/os/x86_64/$file_name" -o "$dir/$file_name" ||
{ err "Downloading $file_name failed."; return 1; }
echo "$sha256 $dir/$file_name" | sha256sum -c --quiet - >&2 ||
{ err "Checksum mismatch for $file_name; not using it."; return 1; }
echo "$dir/$file_name"
}
cec_enable() {
local tmp p f files=()
# inputattach, needed by inputattach-cec-units.
if ! pacman -Q linuxconsole >/dev/null 2>&1; then
sudo pacman -S --needed --noconfirm linuxconsole || { err "Installing linuxconsole failed."; return 1; }
state_set cec installed_linuxconsole 1
fi
tmp="$(mktemp -d)"
for p in "${CEC_PKGS[@]}"; do
f="$(fetch_holo_pkg "$tmp" "$p")" || { rm -rf "$tmp"; return 1; }
files+=("$f")
done
info "Installing Valve's CEC daemon..."
if ! sudo pacman -U --needed --noconfirm "${files[@]}"; then
rm -rf "$tmp"
err "Installing ${CEC_PKGS[*]} failed."
return 1
fi
rm -rf "$tmp"
# Its udev rule gives the user /dev/cec*; cecd starts with the graphical
# session, after steamos-manager wrote its config from Steam's settings.
sudo udevadm control --reload
sudo udevadm trigger --subsystem-match=cec --action=add
systemctl --user daemon-reload
systemctl --user enable steamos-manager-configure-cecd.service 2>/dev/null
if compgen -G "/dev/cec*" >/dev/null; then
systemctl --user restart cecd.service 2>/dev/null
ok "HDMI-CEC on ($(cd /dev && echo cec*)). Turn on CEC on your TV too (e.g. Sony: BRAVIA Sync, Samsung: Anynet+, LG: SimpLink)."
else
warn "No CEC device (/dev/cec*) found: your GPU may not support CEC. A USB CEC adapter"
warn "(e.g. Pulse-Eight) works too. Check again after a restart with: ls /dev/cec*"
fi
}
cec_disable() {
info "Removing HDMI-CEC..."
systemctl --user disable --now cecd.service cec-audio-control.socket cec-audio-control.service 2>/dev/null
systemctl --user disable steamos-manager-configure-cecd.service 2>/dev/null
sudo pacman -Rns --noconfirm "${CEC_PKGS[@]}" 2>/dev/null
if [[ -n "$(state_get cec installed_linuxconsole)" ]]; then
sudo pacman -Rns --noconfirm linuxconsole 2>/dev/null
state_clear cec
fi
sudo udevadm control --reload
ok "HDMI-CEC removed."
}
cec_overview() {
# For the menu's kernel overview.
local dev="none"
compgen -G "/dev/cec*" >/dev/null && dev="$(cd /dev && echo cec*)"
echo "CEC devices: $dev cecd: $(systemctl --user is-active cecd 2>/dev/null)"
}
+5 -3
View File
@@ -5,15 +5,16 @@
# Menu order. Components are turned on in this order and off in reverse; # Menu order. Components are turned on in this order and off in reverse;
# gaming must come first (single user builds on it). # gaming must come first (single user builds on it).
COMPONENTS=(gaming boot theme glyphs single launcher machine kpin bios) COMPONENTS=(gaming boot theme glyphs single launcher cec machine kpin bios)
# One-off actions rather than on/off components: never preselected, never # One-off actions rather than on/off components: never preselected, never
# re-applied, not listed as on or off. # re-applied, not listed as on or off.
ACTIONS=(bios) ACTIONS=(bios)
# Sub-options, shown indented under their parent and only while it's ticked. # Sub-options, shown indented under their parent and only while it's ticked.
declare -A PARENT=([boot]=gaming [kpin]=machine) declare -A PARENT=([boot]=gaming [kpin]=machine)
# Never preselected on a first run: booting into the desktop is a choice, # Never preselected on a first run: booting into the desktop is a choice,
# gamescope is the default. # gamescope is the default; HDMI-CEC is opt-in (it can wake the machine or
NO_PRESELECT=(boot) # upset other devices on the TV, even on SteamOS).
NO_PRESELECT=(boot cec)
declare -A LABEL=( declare -A LABEL=(
[gaming]="SteamOS conversion: boot into gaming mode, Steam on the desktop" [gaming]="SteamOS conversion: boot into gaming mode, Steam on the desktop"
@@ -22,6 +23,7 @@ declare -A LABEL=(
[glyphs]="Install Steam Deck/Machine icons: Deck button icons in gaming mode" [glyphs]="Install Steam Deck/Machine icons: Deck button icons in gaming mode"
[single]="Single user mode: no password, lock screen or log out (SDDM)" [single]="Single user mode: no password, lock screen or log out (SDDM)"
[launcher]="Steamify shortcut: desktop icon to run this again" [launcher]="Steamify shortcut: desktop icon to run this again"
[cec]="HDMI-CEC: use Steam with the TV remote, TV on/off with the PC (experimental)"
[machine]="Steam Machine support: LED bar driver, hardware settings in Steam" [machine]="Steam Machine support: LED bar driver, hardware settings in Steam"
[kpin]="Pin the kernel to $PINNED_KERNEL_VER (fixes rebooting after shutdown)" [kpin]="Pin the kernel to $PINNED_KERNEL_VER (fixes rebooting after shutdown)"
[bios]="Update BIOS" [bios]="Update BIOS"
+1
View File
@@ -344,6 +344,7 @@ kernel_overview() {
fi fi
echo -e " ${running}${line}" echo -e " ${running}${line}"
done done
cec_status && { echo; echo -e " $(cec_overview)"; }
if [[ "$leds" == true ]]; then if [[ "$leds" == true ]]; then
local loaded="$miss" nodes local loaded="$miss" nodes
lsmod | grep -q '^leds_valve' && loaded="$mark" lsmod | grep -q '^leds_valve' && loaded="$mark"
+2 -2
View File
@@ -15,11 +15,11 @@
set -uo pipefail set -uo pipefail
# Release version, see CHANGELOG.md. # Release version, see CHANGELOG.md.
VERSION=1.0.0 VERSION=1.1.0
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
for lib in common state packages login-manager single-user steam-desktop steam-machine boot-session vapor-theme steamos-extras bios desktop-shortcut wizard-shortcut menu; do for lib in common state packages login-manager single-user steam-desktop steam-machine cec boot-session vapor-theme steamos-extras bios desktop-shortcut wizard-shortcut menu; do
# shellcheck source=/dev/null # shellcheck source=/dev/null
source "$SCRIPT_DIR/lib/$lib.sh" source "$SCRIPT_DIR/lib/$lib.sh"
done done