From 72a18232a5f44ccb63faa7b419b9877eceba6ccf Mon Sep 17 00:00:00 2001 From: Rick Peters Date: Fri, 25 Sep 2026 09:11:44 +0200 Subject: [PATCH] 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*. --- CHANGELOG.md | 11 ++++++ README.md | 6 ++- TECHNICAL.md | 35 +++++++++++++++++- TROUBLESHOOTING.md | 18 +++++++++ lib/cec.sh | 88 ++++++++++++++++++++++++++++++++++++++++++++ lib/menu.sh | 8 ++-- lib/steam-machine.sh | 1 + steamify.sh | 4 +- 8 files changed, 163 insertions(+), 8 deletions(-) create mode 100644 lib/cec.sh diff --git a/CHANGELOG.md b/CHANGELOG.md index eb2302c..c645efe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,17 @@ All notable changes, per version and per commit. Versions follow `steamify.sh`. Versions before 0.7.0 were numbered afterwards, 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 - **feat: Pin the kernel to 7.1.6-1 on a Steam Machine** diff --git a/README.md b/README.md index a312908..335df1e 100644 --- a/README.md +++ b/README.md @@ -27,13 +27,17 @@ Steam Machine. ([details](TECHNICAL.md#single-user-mode-sddm-no-locking)). 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. +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 On a Valve Steam Machine the menu has two more items: - **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. - **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 diff --git a/TECHNICAL.md b/TECHNICAL.md index 918ac16..0e6333a 100644 --- a/TECHNICAL.md +++ b/TECHNICAL.md @@ -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 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 - uses for hardware settings (fan, HDMI-CEC, performance); it recognises the - Steam Machine from its DMI data. + uses for hardware settings (fan, performance, and the HDMI-CEC settings + 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). @@ -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 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) 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/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/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 | | `.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` | diff --git a/TROUBLESHOOTING.md b/TROUBLESHOOTING.md index 5e5cf37..a201b9a 100644 --- a/TROUBLESHOOTING.md +++ b/TROUBLESHOOTING.md @@ -32,6 +32,24 @@ cat /var/lib/dkms/leds-valve-dkms/0.1/build/make.log 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 Check that the pinned kernel is installed and running: diff --git a/lib/cec.sh b/lib/cec.sh new file mode 100644 index 0000000..59ecb9a --- /dev/null +++ b/lib/cec.sh @@ -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 : download the newest from + # Valve's newest holo repository into 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)" +} diff --git a/lib/menu.sh b/lib/menu.sh index 372495b..a7d524d 100644 --- a/lib/menu.sh +++ b/lib/menu.sh @@ -5,15 +5,16 @@ # Menu order. Components are turned on in this order and off in reverse; # 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 # re-applied, not listed as on or off. ACTIONS=(bios) # Sub-options, shown indented under their parent and only while it's ticked. declare -A PARENT=([boot]=gaming [kpin]=machine) # Never preselected on a first run: booting into the desktop is a choice, -# gamescope is the default. -NO_PRESELECT=(boot) +# gamescope is the default; HDMI-CEC is opt-in (it can wake the machine or +# upset other devices on the TV, even on SteamOS). +NO_PRESELECT=(boot cec) declare -A LABEL=( [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" [single]="Single user mode: no password, lock screen or log out (SDDM)" [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" [kpin]="Pin the kernel to $PINNED_KERNEL_VER (fixes rebooting after shutdown)" [bios]="Update BIOS" diff --git a/lib/steam-machine.sh b/lib/steam-machine.sh index b650d9e..717bb2e 100644 --- a/lib/steam-machine.sh +++ b/lib/steam-machine.sh @@ -344,6 +344,7 @@ kernel_overview() { fi echo -e " ${running}${line}" done + cec_status && { echo; echo -e " $(cec_overview)"; } if [[ "$leds" == true ]]; then local loaded="$miss" nodes lsmod | grep -q '^leds_valve' && loaded="$mark" diff --git a/steamify.sh b/steamify.sh index 2215dfc..cefea11 100755 --- a/steamify.sh +++ b/steamify.sh @@ -15,11 +15,11 @@ set -uo pipefail # Release version, see CHANGELOG.md. -VERSION=1.0.0 +VERSION=1.1.0 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 source "$SCRIPT_DIR/lib/$lib.sh" done