Compare commits

..
11 Commits
Author SHA1 Message Date
theupriser 852205317a Merge pull request #8 from theupriser/fix/use-cachyos-vapor
Fix/use cachyos vapor
2026-09-24 10:57:03 +02:00
theupriser 77b94c29a2 fix: Merge remote-tracking branch 'origin/main' into fix/use-cachyos-vapor 2026-09-24 10:55:55 +02:00
theupriser c0014ee623 docs: 0.7.0 was released on its own (#6, #7) 2026-09-24 10:55:55 +02:00
theupriser d39731a8b9 docs: Last commit hash in the changelog 2026-09-24 10:55:27 +02:00
theupriser 99a95abf1f fix: Kernel legend only mentions the LEDs on a Steam Machine 2026-09-24 10:54:33 +02:00
theupriser 429e840a9f fix: Shorter BIOS labels so the menu fits 80 columns 2026-09-24 10:51:53 +02:00
theupriser 45a8757f58 fix: BIOS dry run also walks through the restart choices
A dry run counts as staged, so [m]/[r] and the restart question on q show up; restarting only prints in dry-run mode.
2026-09-24 10:48:39 +02:00
theupriser 54fc9e362b feat: Menu comes back after each run, BIOS dry run, version 0.8.0
- After a run the menu returns; [m] back to the menu or [r] restart now when a restart is needed; q quits.
- A staged BIOS update greys the item out until the restart.
- WIZARD_BIOS_DRY_RUN=1: whole BIOS flow without the device check, never flashes.
- VERSION 0.8.0; CHANGELOG: BIOS work moved to 0.8.0; README: BIOS update step by step.
2026-09-24 10:40:16 +02:00
theupriser b70c9d614f fix: shellcheck in the bundle, and the docs for the BIOS checks
- Rename a variable in lib/bios.sh that clashed with lib/state.sh's array in the bundle.
- README, AGENTS.md and CHANGELOG.md for the greyed-out item, the device check and the aligned warning box.
2026-09-24 10:30:24 +02:00
theupriser 40c9ee638b fix: BIOS update only when newer, device check first, aligned warnings
- Greyed out and not tickable unless Valve has a newer BIOS (component_selectable).
- Download, SHA-256 and a fwupd device check (get-details) before the warnings.
- Warning box with a solid block frame (a coloured row of # renders narrower in Konsole); menu Now column aligned.
2026-09-24 10:29:46 +02:00
theupriser 2f9b2a54e1 feat: Opt-in BIOS update for the Steam Machine
- Menu item (Fremont only, never preselected) with the current and newest BIOS version.
- Two warnings and two confirmations (y/N, then typing UPDATE); checksum-verified download
  of Valve's fremont-hw-support; installed with fwupd, written at the next restart.
- Menu actions: one-off items that are never preselected, re-applied or listed as on/off.
2026-09-24 10:22:15 +02:00
8 changed files with 433 additions and 37 deletions

No files matched your search

+22
View File
@@ -132,11 +132,33 @@ gamescope and the Plasma desktop. Primary target: the Valve Steam Machine
and `ensure-kernel-headers.service` installs missing ones at boot (a and `ensure-kernel-headers.service` installs missing ones at boot (a
pacman hook can't run pacman), which triggers DKMS's install hook. The module creates pacman hook can't run pacman), which triggers DKMS's install hook. The module creates
`/sys/class/leds/valve-leds*`. `/sys/class/leds/valve-leds*`.
- `bios` is an *action* (`ACTIONS` in `lib/menu.sh`), not an on/off
component: never preselected (not even on a first run), never re-applied
by `a`, not listed in the state overview, and `bios_status` is always off.
Only selectable when Valve's version differs from the installed one
(`component_selectable`, greyed out otherwise). Download, SHA-256 and the
fwupd device check (`get-details --json`: no `UpdateError`) come before the
warnings. The warning box uses `█` for its frame: Konsole draws a long
coloured row of `#` narrower, so the right edge wouldn't line up.
Keep both confirmations (y/N, then typing `UPDATE`) and the warnings; the
firmware comes from the newest `holo-X.Y` repo (`.files` db names the
`.cab`, `.db` gives the SHA-256), and fwupd itself refuses non-Fremont
hardware. In the VM, test it with `WIZARD_BIOS_DRY_RUN=1` (skips only the
device check, never flashes) and a faked version (dev-env
`BIOS_VERSION=F7F0107 ./run.sh --fremont`).
- The entry point loops: menu, run, "back to the menu" (or `[m]`/`[r]` when a
restart is needed), until `q`; the restart question is asked once at the
end. Scripted input that runs out ends the loop like `q`.
- `Relogin=true` means a gamescope that fails to start is relaunched in a - `Relogin=true` means a gamescope that fails to start is relaunched in a
tight loop; keep that in mind when changing session handling. tight loop; keep that in mind when changing session handling.
## Checking changes ## Checking changes
The bundle puts every module in one file, so shellcheck sees all their
`local` variables together: don't reuse a name another module uses as an
array (e.g. `g` in `lib/state.sh`), or CI's shellcheck on the bundle fails.
There is no test suite. At minimum: There is no test suite. At minimum:
```bash ```bash
+39 -2
View File
@@ -5,7 +5,44 @@ All notable changes, per version and per commit. Versions follow
`setup-gamescope-boot.sh`. Versions before 0.7.0 were numbered afterwards, `setup-gamescope-boot.sh`. Versions before 0.7.0 were numbered afterwards,
one per merged pull request. one per merged pull request.
## 0.7.0 - 2026-09-24 ## 0.8.0 - 2026-09-24
An opt-in BIOS update for the Steam Machine, and a menu that comes back after
every run.
- `2f9b2a5` **feat: Opt-in BIOS update for the Steam Machine**
- New menu item (Steam Machine only, never ticked by default) showing the
current BIOS version and the newest from Valve's `fremont-hw-support`.
- Two large warnings and two confirmations (y/N, then typing `UPDATE`),
checksum-verified download, installed with fwupd; the wizard then offers
the restart that writes it, with a warning to keep the power on.
- `40c9ee6` **fix: BIOS update only when newer, device check first, aligned warnings**
- The item is greyed out and can't be ticked unless Valve has a newer BIOS.
- Before any warning: SHA-256 of Valve's package, then fwupd confirms the
firmware fits this machine's hardware; otherwise it stops.
- Warning box drawn with a solid red frame whose edges line up, and the
menu's "Now" column aligned.
- `b70c9d6` **fix: shellcheck in the bundle, and the docs for the BIOS checks**
- A variable name in `lib/bios.sh` clashed with `lib/state.sh` in the bundle
(CI's shellcheck would fail); README, AGENTS.md and this changelog updated.
- `54fc9e3` **feat: Menu comes back after each run, BIOS dry run, version 0.8.0**
- After a run the menu returns with the new state; quit with `q`. When
something needs a restart, choose between back to the menu (`m`) and
restart now (`r`); quitting asks once more.
- A staged BIOS update greys the item out until the restart.
- `WIZARD_BIOS_DRY_RUN=1` walks through the whole BIOS update (download,
checksum, both warnings) but only prints the install and never flashes.
- README: the menu loop and the BIOS update step by step.
- `45a8757` **fix: BIOS dry run also walks through the restart choices**
- A dry run counts as staged, so `[m]`/`[r]` and the restart question on `q`
show up; in dry-run mode restarting only prints what it would do.
- `429e840` **fix: Shorter BIOS labels so the menu fits 80 columns**
- "now F7F0107, newest F7F0108 (own risk)", "F7F0108 waits for a restart",
"F7F0107 is up to date"; shorter dry-run line.
- `99a95ab` **fix: Kernel legend only mentions the LEDs on a Steam Machine**
- **docs: Last commit hash in the changelog; 0.7.0 was released on its own (#6, #7)**
## 0.7.0 - 2026-09-24 (#6, #7)
The SteamOS theme comes from CachyOS's `cachyos-vapor` package, applied with The SteamOS theme comes from CachyOS's `cachyos-vapor` package, applied with
Vapor's own desktop layout, and gains the SteamOS desktop extras. The Steam Vapor's own desktop layout, and gains the SteamOS desktop extras. The Steam
@@ -52,7 +89,7 @@ Machine LED driver works on every installed kernel and survives kernel updates.
- Install with `.../releases/latest/download/setup-gamescope-boot.sh`, which - Install with `.../releases/latest/download/setup-gamescope-boot.sh`, which
always points to the newest release. always points to the newest release.
- `1604ed1` **docs: Versioning and release rules in AGENTS.md** - `1604ed1` **docs: Versioning and release rules in AGENTS.md**
- **ci: The latest tag follows the newest version tag** - `6afef78` **ci: The latest tag follows the newest version tag**
- When a new version is released, the `latest` tag and release move to it - When a new version is released, the `latest` tag and release move to it
(bundle replaced), so the older `.../releases/download/latest/...` URL (bundle replaced), so the older `.../releases/download/latest/...` URL
also always gives the newest version. also always gives the newest version.
+41 -9
View File
@@ -27,6 +27,9 @@ Everything you turn off is put back the way it was.
5. **Steam Machine support** - only shown on a Valve Steam Machine: the 5. **Steam Machine support** - only shown on a Valve Steam Machine: the
driver for the front LED bar, and the hardware settings in Steam (fan, driver for the front LED bar, and the hardware settings in Steam (fan,
TV control over HDMI-CEC). TV control over HDMI-CEC).
6. **Update BIOS** - only on a Steam Machine, opt-in and at your own risk:
installs the newest Steam Machine BIOS from Valve (see
[BIOS updates](#bios-updates-steam-machine)).
## Requirements ## Requirements
@@ -74,6 +77,10 @@ it's loaded right now, so a kernel update is easy to check. The wizard then
shows what it will change, asks your password once, and at the end offers shows what it will change, asks your password once, and at the end offers
to restart (needed for changes to how the PC starts). to restart (needed for changes to how the PC starts).
After each run the menu comes back with the new state, so you can change more
in one go; quit with **q**. When something needs a restart, you choose
between going back to the menu and restarting now; quitting asks once more.
Run it again whenever you like - to change your choices, to turn things off Run it again whenever you like - to change your choices, to turn things off
again, or after a CachyOS update (press `a` in the menu to re-apply again, or after a CachyOS update (press `a` in the menu to re-apply
everything that's on). everything that's on).
@@ -283,17 +290,41 @@ cat /var/lib/dkms/leds-valve-dkms/0.1/build/make.log
journalctl --user -b | grep -i led journalctl --user -b | grep -i led
``` ```
**BIOS updates** are not part of the wizard. Valve ships the Steam Machine ### BIOS updates (Steam Machine)
BIOS as `F7F0108.cab` in its `fremont-hw-support` package for fwupd. To
install it by hand (keep the machine on mains power and don't interrupt it): The **Update BIOS** item is only shown on a Steam Machine and is never ticked
by default. It shows the BIOS version you have now and the newest one Valve
ships (the `.cab` file in its `fremont-hw-support` package, looked up on
Valve's SteamOS mirror):
```bash
sudo dmidecode -s bios-version # current version
sudo pacman -S fwupd
curl -LO https://steamdeck-packages.steamos.cloud/archlinux-mirror/holo-3.9/os/x86_64/fremont-hw-support-20260807.1-1-any.pkg.tar.zst
mkdir fhw && tar -I zstd -xf fremont-hw-support-*.pkg.tar.zst -C fhw
sudo fwupdmgr install fhw/usr/share/fwupd/remotes.d/fremont/firmware/F7F0108.cab
``` ```
[ ] Update BIOS: now F7F0107, newest F7F0108 (own risk) (opt-in, runs once)
```
It can only be ticked when Valve has a newer BIOS than yours; when you're up
to date, when the newest version can't be looked up (offline), or when an
update is already waiting for a restart, it's greyed out.
When you run it, the wizard:
1. downloads Valve's package and checks its **SHA-256** against Valve's
repository, so it's exactly Valve's file;
2. asks **fwupd** whether the firmware is for this very machine (fwupd compares
the firmware's hardware IDs with the device) and stops if it isn't;
3. shows a large red **warning** with the current and the new version, and asks
whether you understand the risks (default: no);
4. shows the warning **again** and only continues when you type `UPDATE`;
5. hands the firmware to fwupd, which writes it during the **next restart**:
choose "restart now" or restart later yourself.
**At your own risk:** a failed or interrupted BIOS update can leave the machine
unable to start. Keep it on mains power, and never turn off the power, unplug
it or press the power button while it updates, including during the restart;
the screen can stay black for several minutes.
To walk through it without flashing anything, run the wizard with
`WIZARD_BIOS_DRY_RUN=1`: it downloads and checks the package and shows both
warnings, skips fwupd's device check, and only prints the install command.
### Manual session control ### Manual session control
@@ -328,6 +359,7 @@ gamescope-session, ...) stay installed.
| `lib/vapor-theme.sh` | SteamOS theme: installs and switches to `cachyos-vapor` | | `lib/vapor-theme.sh` | SteamOS theme: installs and switches to `cachyos-vapor` |
| `lib/steamos-extras.sh` | SteamOS desktop extras from Valve's package (Add to Steam, Nested Desktop, icon, keyboard rule, KWallet) | | `lib/steamos-extras.sh` | SteamOS desktop extras from Valve's package (Add to Steam, Nested Desktop, icon, keyboard rule, KWallet) |
| `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/bios.sh` | Update BIOS (Steam Machine, opt-in): current/newest version, double confirmation, fwupd |
| `lib/steam-machine.sh` | Steam Machine support: LED driver, LED access, steamos-manager | | `lib/steam-machine.sh` | Steam Machine support: LED driver, LED access, steamos-manager |
| `.github/tools/bundle.sh` | Builds the single-file version (`dist/setup-gamescope-boot.sh`) | | `.github/tools/bundle.sh` | Builds the single-file version (`dist/setup-gamescope-boot.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` |
+203
View File
@@ -0,0 +1,203 @@
#!/bin/bash
# "Update BIOS" menu item, only on a Steam Machine and always opt-in: flashes
# the newest Steam Machine BIOS from Valve's fremont-hw-support package with
# fwupd. It's an action, not an on/off component: never preselected, never
# re-applied, and there is nothing to turn off afterwards.
# Sourced by setup-gamescope-boot.sh; not meant to be run on its own.
BIOS_REPO_PREFIX=holo
# WIZARD_BIOS_DRY_RUN=1 walks through the whole BIOS update (download,
# checksum, both warnings) but never flashes: fwupd's device check is
# skipped and the install is only printed. For testing, e.g. in a VM.
BIOS_DRY_RUN="${WIZARD_BIOS_DRY_RUN:-}"
bios_available() { detect_valve_fremont; }
bios_status() { return 1; }
bios_disable() { return 0; }
bios_current() {
cat /sys/class/dmi/id/bios_version 2>/dev/null || echo unknown
}
bios_lookup_newest() {
# Sets BIOS_REPO, BIOS_PKG, BIOS_SHA256 and BIOS_NEWEST (e.g. F7F0108)
# from the newest holo-X.Y repository on Valve's mirror: its .files
# database names the firmware file, its .db gives the package checksum.
# Only once per run, and with short timeouts so an offline machine
# doesn't hold up the menu.
[[ -n "${BIOS_LOOKED_UP:-}" ]] && return 0
BIOS_LOOKED_UP=1; BIOS_NEWEST=""
local tmp desc
BIOS_REPO="$(curl -fsL --max-time 10 "$VALVE_MIRROR/" | grep -oE "$BIOS_REPO_PREFIX-[0-9]+\.[0-9]+/" | tr -d / | sort -uV | tail -n 1)"
[[ -n "$BIOS_REPO" ]] || return 1
tmp="$(mktemp -d)"
if curl -fsL --max-time 30 "$VALVE_MIRROR/$BIOS_REPO/os/x86_64/$BIOS_REPO.files" -o "$tmp/files" &&
curl -fsL --max-time 30 "$VALVE_MIRROR/$BIOS_REPO/os/x86_64/$BIOS_REPO.db" -o "$tmp/db"; then
desc="$(tar -tf "$tmp/files" 2>/dev/null | grep -E '^fremont-hw-support-[0-9][^/]*/files$' | head -n 1)"
[[ -n "$desc" ]] && BIOS_CAB="$(tar -xOf "$tmp/files" "$desc" | grep -E '^usr/share/fwupd/.*\.cab$' | head -n 1)"
desc="${desc%/files}/desc"
BIOS_PKG="$(tar -xOf "$tmp/db" "$desc" 2>/dev/null | awk '/^%FILENAME%$/ { getline; print }')"
BIOS_SHA256="$(tar -xOf "$tmp/db" "$desc" 2>/dev/null | awk '/^%SHA256SUM%$/ { getline; print }')"
[[ -n "${BIOS_CAB:-}" && -n "$BIOS_PKG" && -n "$BIOS_SHA256" ]] && BIOS_NEWEST="$(basename "$BIOS_CAB" .cab)"
fi
rm -rf "$tmp"
[[ -n "$BIOS_NEWEST" ]]
}
bios_selectable() {
# Only when Valve has a newer BIOS than the one installed; the menu
# greys the item out otherwise (up to date, or newest unknown/offline).
[[ -z "${BIOS_NEEDS_RESTART:-}" && -n "${BIOS_NEWEST:-}" && "$BIOS_NEWEST" != "$(bios_current)" ]]
}
bios_label() {
# Menu label with the current and the newest version; kept short so the
# row (with "(not available)" when greyed out) fits 80 columns.
local current
current="$(bios_current)"
if [[ -n "${BIOS_NEEDS_RESTART:-}" ]]; then
echo "Update BIOS: $BIOS_NEWEST waits for a restart"
elif [[ -z "${BIOS_NEWEST:-}" ]]; then
echo "Update BIOS: now $current, newest unknown (offline?)"
elif [[ "$BIOS_NEWEST" == "$current" ]]; then
echo "Update BIOS: $current is up to date"
else
echo "Update BIOS: now $current, newest $BIOS_NEWEST (own risk)"
fi
}
BIOS_BOX_WIDTH=68
bios_box_line() {
# bios_box_line [text]: one line of the warning box, padded to the same
# visible width (colour codes don't count) so the right edge lines up.
local text="${1:-}" plain pad
plain="$(printf '%b' "$text" | sed 's/\x1b\[[0-9;]*m//g')"
pad=$(( BIOS_BOX_WIDTH - 6 - ${#plain} ))
(( pad < 0 )) && pad=0
printf ' %b██%b %b%*s%b██%b\n' "$c_red" "$c_reset" "$text" "$pad" "" "$c_red" "$c_reset"
}
bios_box_border() {
# Block characters: Konsole draws a long coloured row of # narrower
# than the box's other lines, so its right edge wouldn't line up.
printf ' %b%s%b\n' "$c_red" "$(printf '█%.0s' $(seq "$BIOS_BOX_WIDTH"))" "$c_reset"
}
bios_disclaimer() {
# bios_disclaimer <title> [line...]: the warning box; extra lines are
# shown above the fixed risks.
local title="$1" line b="$c_bold" n="$c_reset"
shift
echo
bios_box_border
bios_box_line
bios_box_line "$c_red$b$title$n"
bios_box_line
bios_box_border
for line in "$@"; do bios_box_line "$line"; done
bios_box_line
bios_box_line "- A failed or interrupted BIOS update can leave the machine"
bios_box_line " unable to start (bricked). This wizard, CachyOS and Valve"
bios_box_line " take no responsibility for that."
bios_box_line "- ${b}NEVER turn off the power, unplug the machine or press${n}"
bios_box_line " ${b}the power button while the update runs${n}, including the"
bios_box_line " restart(s) afterwards, when the firmware is written."
bios_box_line "- The screen can stay black for several minutes. Wait."
bios_box_line "- Only on mains power, with all other programs closed."
bios_box_line
bios_box_border
echo
}
bios_fits_device() {
# bios_fits_device <cab>: does fwupd match this firmware to a device in
# this machine? It compares the file's hardware IDs (GUIDs) with the
# hardware; for a file that doesn't fit it reports an UpdateError.
local details
details="$(sudo fwupdmgr get-details --json "$1" 2>/dev/null)" || return 1
grep -q '"Guid"' <<< "$details" && ! grep -q '"UpdateError"' <<< "$details"
}
bios_enable() {
if ! bios_lookup_newest; then
err "Couldn't find the newest Steam Machine BIOS on Valve's mirror ($VALVE_MIRROR)."
return 1
fi
local current tmp compatible
current="$(bios_current)"
[[ -n "$BIOS_DRY_RUN" ]] && warn "DRY RUN (WIZARD_BIOS_DRY_RUN): nothing will be flashed."
if [[ "$current" == "$BIOS_NEWEST" ]]; then
ok "The BIOS is already the newest version ($current); nothing to do."
return 0
fi
# Download and check everything before asking: the warnings only come
# when the file is Valve's (SHA-256 from Valve's repo database) and fwupd
# confirms it's firmware for this very machine.
pacman -Q fwupd >/dev/null 2>&1 || sudo pacman -S --needed --noconfirm fwupd ||
{ err "Installing fwupd failed."; return 1; }
tmp="$(mktemp -d)"
info "Downloading $BIOS_PKG ($BIOS_REPO)..."
if ! curl -fsSL "$VALVE_MIRROR/$BIOS_REPO/os/x86_64/$BIOS_PKG" -o "$tmp/pkg.tar.zst" ||
! echo "$BIOS_SHA256 $tmp/pkg.tar.zst" | sha256sum -c --quiet - ||
! tar -I unzstd -xf "$tmp/pkg.tar.zst" -C "$tmp" "$BIOS_CAB"; then
err "Downloading or verifying $BIOS_PKG failed; the BIOS was not touched."
rm -rf "$tmp"
return 1
fi
ok "Checksum OK: this is Valve's $BIOS_PKG."
local yes="$c_green$c_bold" b="$c_bold" n="$c_reset"
if [[ -n "$BIOS_DRY_RUN" ]]; then
warn "Dry run: skipping fwupd's check that the firmware fits this machine."
compatible="${c_yellow}${b}not checked${n} (dry run)"
elif bios_fits_device "$tmp/$BIOS_CAB"; then
ok "fwupd confirms BIOS $BIOS_NEWEST is firmware for this machine."
compatible="${yes}yes${n} (checked by fwupd)"
else
err "fwupd says BIOS $BIOS_NEWEST is not for this machine's hardware; not installing it."
rm -rf "$tmp"
return 1
fi
bios_disclaimer "WARNING: BIOS UPDATE - ENTIRELY AT YOUR OWN RISK" \
"Current BIOS: ${b}$current${n}" \
"New BIOS: ${b}$BIOS_NEWEST${n}" \
"Checksum: ${yes}OK${n} (Valve's package)" \
"Compatible: $compatible"
if ! ask_yn "Do you understand the risks and want to continue?" n; then
info "BIOS update cancelled; nothing was changed."; rm -rf "$tmp"; return 0
fi
bios_disclaimer "LAST CHANCE: THIS FLASHES BIOS $BIOS_NEWEST" \
"After this, keep the power on until the machine has fully" \
"started again. Don't touch it, even if the screen is black."
local reply
read -rp "$(echo -e "${c_red}${c_bold}Type UPDATE (in capitals) to flash the BIOS, anything else cancels:${c_reset} ")" reply
if [[ "$reply" != UPDATE ]]; then
info "BIOS update cancelled; nothing was changed."; rm -rf "$tmp"; return 0
fi
if [[ -n "$BIOS_DRY_RUN" ]]; then
ok "Dry run: would run: fwupdmgr install -y --no-reboot-check $(basename "$BIOS_CAB")"
ok "Dry run finished; nothing was flashed."
# Treated as staged, so the restart choices that follow a real
# update show up too; restarting only prints (see restart_now).
BIOS_NEEDS_RESTART=1
rm -rf "$tmp"
return 0
fi
info "Handing BIOS $BIOS_NEWEST to fwupd. Do NOT turn off the power from now on."
# -y: we already asked twice; --no-reboot-check: the wizard's own
# restart question comes at the end.
if ! sudo fwupdmgr install -y --no-reboot-check "$tmp/$BIOS_CAB"; then
err "fwupd could not install the BIOS update (see above); the BIOS was not changed."
rm -rf "$tmp"
return 1
fi
rm -rf "$tmp"
BIOS_NEEDS_RESTART=1
ok "BIOS $BIOS_NEWEST is staged. It is written during the next restart:"
warn "keep the power on and don't touch the machine until it has fully started again."
}
+1 -1
View File
@@ -2,7 +2,7 @@
# Output helpers, prompts and small shared utilities. # Output helpers, prompts and small shared utilities.
# Sourced by setup-gamescope-boot.sh; not meant to be run on its own. # Sourced by setup-gamescope-boot.sh; not meant to be run on its own.
c_reset="\033[0m"; c_bold="\033[1m"; c_green="\033[32m"; c_yellow="\033[33m"; c_red="\033[31m"; c_cyan="\033[36m" c_reset="\033[0m"; c_bold="\033[1m"; c_green="\033[32m"; c_yellow="\033[33m"; c_red="\033[31m"; c_cyan="\033[36m"; c_dim="\033[2m"
info() { echo -e "${c_cyan}[INFO]${c_reset} $*"; } info() { echo -e "${c_cyan}[INFO]${c_reset} $*"; }
ok() { echo -e "${c_green}[OK]${c_reset} $*"; } ok() { echo -e "${c_green}[OK]${c_reset} $*"; }
+47 -12
View File
@@ -5,7 +5,10 @@
# 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 theme glyphs single machine) COMPONENTS=(gaming theme glyphs single machine bios)
# One-off actions rather than on/off components: never preselected, never
# re-applied, not listed as on or off.
ACTIONS=(bios)
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"
@@ -13,11 +16,24 @@ 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)"
[machine]="Steam Machine support: LED bar driver, hardware settings in Steam" [machine]="Steam Machine support: LED bar driver, hardware settings in Steam"
[bios]="Update BIOS"
) )
declare -A CURRENT WANTED declare -A CURRENT WANTED
component_available() { component_available() {
[[ "$1" != machine ]] || machine_available case "$1" in
machine) machine_available ;;
bios) bios_available ;;
esac
}
is_action() { [[ " ${ACTIONS[*]} " == *" $1 "* ]]; }
component_selectable() {
# Greyed out and not tickable when it has nothing to do.
case "$1" in
bios) bios_selectable ;;
esac
} }
detect_components() { detect_components() {
@@ -27,16 +43,19 @@ detect_components() {
if "${c}_status"; then CURRENT[$c]=1; any=true; else CURRENT[$c]=0; fi if "${c}_status"; then CURRENT[$c]=1; any=true; else CURRENT[$c]=0; fi
WANTED[$c]=${CURRENT[$c]} WANTED[$c]=${CURRENT[$c]}
done done
# First run: preselect the full SteamOS experience. # Shows the current and newest BIOS version.
bios_available && { bios_lookup_newest; LABEL[bios]="$(bios_label)"; }
# First run: preselect the full SteamOS experience (never an action).
if [[ "$any" == false ]]; then if [[ "$any" == false ]]; then
for c in "${COMPONENTS[@]}"; do for c in "${COMPONENTS[@]}"; do
component_available "$c" && WANTED[$c]=1 component_available "$c" && ! is_action "$c" && WANTED[$c]=1
done done
fi fi
} }
toggle_component() { toggle_component() {
local c="$1" local c="$1"
component_selectable "$c" || return 1
WANTED[$c]=$(( 1 - WANTED[$c] )) WANTED[$c]=$(( 1 - WANTED[$c] ))
# Single user mode only makes sense on top of the SteamOS conversion. # Single user mode only makes sense on top of the SteamOS conversion.
if [[ "$c" == single && "${WANTED[single]}" == 1 ]]; then WANTED[gaming]=1; fi if [[ "$c" == single && "${WANTED[single]}" == 1 ]]; then WANTED[gaming]=1; fi
@@ -51,9 +70,17 @@ show_menu() {
for c in "${COMPONENTS[@]}"; do for c in "${COMPONENTS[@]}"; do
component_available "$c" || continue component_available "$c" || continue
i=$((i + 1)); MENU_ITEMS[$i]=$c i=$((i + 1)); MENU_ITEMS[$i]=$c
now="off"; [[ "${CURRENT[$c]}" == 1 ]] && now="${c_green}on${c_reset} " # Pad the plain word, then colour it: colour codes would count as width.
now="off"; [[ "${CURRENT[$c]}" == 1 ]] && now="on"
is_action "$c" && now="-"
now="$(printf '%-6s' "$now")"
[[ "${CURRENT[$c]}" == 1 ]] && now="${now/on/${c_green}on${c_reset}}"
want="[ ]"; [[ "${WANTED[$c]}" == 1 ]] && want="[x]" want="[ ]"; [[ "${WANTED[$c]}" == 1 ]] && want="[x]"
printf " %-3s %-6b %-6s %s\n" "$i" "$now " "$want" "${LABEL[$c]}" if component_selectable "$c"; then
printf " %-3s %b %-6s %s\n" "$i" "$now" "$want" "${LABEL[$c]}"
else
printf " %b%-3s %-6s %-6s %s (not available)%b\n" "$c_dim" "$i" "$now" "$want" "${LABEL[$c]}" "$c_reset"
fi
done done
echo echo
echo -e "$KERNEL_OVERVIEW" echo -e "$KERNEL_OVERVIEW"
@@ -84,13 +111,18 @@ draw_menu_tui() {
component_available "$c" || continue component_available "$c" || continue
MENU_ITEMS[$i]=$c MENU_ITEMS[$i]=$c
box="[ ]"; [[ "${WANTED[$c]}" == 1 ]] && box="[${c_green}x${c_reset}]" box="[ ]"; [[ "${WANTED[$c]}" == 1 ]] && box="[${c_green}x${c_reset}]"
state="off"; [[ "${CURRENT[$c]}" == 1 ]] && state="${c_green}on${c_reset}" state=" (now: off)"; [[ "${CURRENT[$c]}" == 1 ]] && state=" (now: ${c_green}on${c_reset})"
is_action "$c" && state=" (opt-in, runs once)"
line="$box ${LABEL[$c]}" line="$box ${LABEL[$c]}"
if (( i == cursor )); then if ! component_selectable "$c"; then
# Greyed out: nothing to do (e.g. BIOS already up to date).
local mark=" "; (( i == cursor )) && mark=" ${c_cyan}>${c_reset} "
echo -e "${mark}${c_dim}[ ] ${LABEL[$c]} (not available)${c_reset}"
elif (( i == cursor )); then
# The green x's reset would end the bold too: re-enable it after. # The green x's reset would end the bold too: re-enable it after.
echo -e " ${c_cyan}>${c_reset} ${c_bold}${line//"$c_reset"/"$c_reset$c_bold"}${c_reset} (now: ${state})" echo -e " ${c_cyan}>${c_reset} ${c_bold}${line//"$c_reset"/"$c_reset$c_bold"}${c_reset}${state}"
else else
echo -e " ${line} (now: ${state})" echo -e " ${line}${state}"
fi fi
i=$((i + 1)) i=$((i + 1))
done done
@@ -137,7 +169,8 @@ run_menu_lines() {
q|Q) return 1 ;; q|Q) return 1 ;;
*) *)
if [[ "$reply" =~ ^[0-9]+$ && -n "${MENU_ITEMS[$reply]:-}" ]]; then if [[ "$reply" =~ ^[0-9]+$ && -n "${MENU_ITEMS[$reply]:-}" ]]; then
toggle_component "${MENU_ITEMS[$reply]}" toggle_component "${MENU_ITEMS[$reply]}" ||
warn "Not available: ${LABEL[${MENU_ITEMS[$reply]}]}"
else else
warn "Unknown choice: $reply" warn "Unknown choice: $reply"
fi fi
@@ -160,6 +193,7 @@ plan_changes() {
for c in "${COMPONENTS[@]}"; do for c in "${COMPONENTS[@]}"; do
component_available "$c" || continue component_available "$c" || continue
[[ "${WANTED[$c]}" == 1 ]] || continue [[ "${WANTED[$c]}" == 1 ]] || continue
if is_action "$c"; then TO_ENABLE+=("$c"); continue; fi
if [[ "${CURRENT[$c]}" == 0 || "$REAPPLY" == true ]] || if [[ "${CURRENT[$c]}" == 0 || "$REAPPLY" == true ]] ||
[[ "$c" == gaming && "${CURRENT[single]}" != "${WANTED[single]}" ]]; then [[ "$c" == gaming && "${CURRENT[single]}" != "${WANTED[single]}" ]]; then
TO_ENABLE+=("$c") TO_ENABLE+=("$c")
@@ -177,7 +211,8 @@ apply_changes() {
"${c}_disable" || failed+=("$c") "${c}_disable" || failed+=("$c")
done done
for c in "${TO_ENABLE[@]}"; do for c in "${TO_ENABLE[@]}"; do
echo; echo -e "${c_bold}Turning on: ${LABEL[$c]}${c_reset}" if is_action "$c"; then echo; echo -e "${c_bold}Running: ${LABEL[$c]%%:*}${c_reset}"
else echo; echo -e "${c_bold}Turning on: ${LABEL[$c]}${c_reset}"; fi
"${c}_enable" || failed+=("$c") "${c}_enable" || failed+=("$c")
done done
FAILED=("${failed[@]}") FAILED=("${failed[@]}")
+3 -1
View File
@@ -163,7 +163,9 @@ kernel_overview() {
local mark="${c_green}yes${c_reset}" miss="${c_red}no ${c_reset}" leds=false local mark="${c_green}yes${c_reset}" miss="${c_red}no ${c_reset}" leds=false
detect_valve_fremont && command -v dkms >/dev/null 2>&1 && leds=true detect_valve_fremont && command -v dkms >/dev/null 2>&1 && leds=true
local kdir k pkg headers hid led running line local kdir k pkg headers hid led running line
echo -e " ${c_bold}Kernels${c_reset} (> = running; controller = Steam controller driver, LEDs = LED bar driver built)" local legend="> = running; controller = Steam controller driver"
[[ "$leds" == true ]] && legend+=", LEDs = LED bar driver built"
echo -e " ${c_bold}Kernels${c_reset} ($legend)"
for kdir in /usr/lib/modules/*/; do for kdir in /usr/lib/modules/*/; do
k="$(basename "$kdir")" k="$(basename "$kdir")"
[[ -f "$kdir/pkgbase" ]] || continue [[ -f "$kdir/pkgbase" ]] || continue
+77 -12
View File
@@ -15,11 +15,11 @@
set -uo pipefail set -uo pipefail
# Release version, see CHANGELOG.md. # Release version, see CHANGELOG.md.
VERSION=0.7.0 VERSION=0.8.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 vapor-theme steamos-extras desktop-shortcut menu; do for lib in common state packages login-manager single-user steam-desktop steam-machine vapor-theme steamos-extras bios desktop-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
@@ -39,47 +39,112 @@ fi
# user running the script. # user running the script.
TARGET_USER="$(id -un)" TARGET_USER="$(id -un)"
restart_needed() { [[ -n "${BIOS_NEEDS_RESTART:-}" || "$RESTART_FOR_LOGIN" == true ]]; }
restart_now() {
if [[ -n "${BIOS_NEEDS_RESTART:-}" ]]; then
warn "The BIOS update is written during this restart. Keep the power on and don't"
warn "touch the machine until it has fully started again, even if the screen stays black."
fi
if [[ -n "${BIOS_DRY_RUN:-}" ]]; then
ok "Dry run: would restart now (sudo reboot); not restarting."
exit 0
fi
info "Restarting..."
sudo reboot
exit 0
}
after_run() {
# After a run: back to the menu, or restart right away when something
# that just ran needs it. Returns 1 when input has ended (scripted runs).
local reply
if ! restart_needed; then
read -rp "Press Enter to go back to the menu... " _ || return 1
return 0
fi
if [[ -n "${BIOS_NEEDS_RESTART:-}" ]]; then
warn "The BIOS update is installed at the next restart."
else
info "The login changes take effect after a restart."
fi
while true; do
read -rp "$(echo -e "${c_bold}[m]${c_reset} back to the menu ${c_bold}[r]${c_reset} restart now: ")" reply || return 1
case "$reply" in
m|M|"") return 0 ;;
r|R) restart_now ;;
*) warn "Type m or r." ;;
esac
done
}
# Menu loop: after each run the menu comes back with the new state, until
# the user quits; the restart question comes then, once, for everything.
RESTART_FOR_LOGIN=false
SUDO_KEEPALIVE=false
while true; do
detect_components detect_components
run_menu || { info "Nothing changed."; exit 0; } run_menu || break
plan_changes plan_changes
if [[ ${#TO_DISABLE[@]} -eq 0 && ${#TO_ENABLE[@]} -eq 0 ]]; then if [[ ${#TO_DISABLE[@]} -eq 0 && ${#TO_ENABLE[@]} -eq 0 ]]; then
ok "Everything is already the way you want it." ok "Everything is already the way you want it."
exit 0 read -rp "Press Enter to go back to the menu... " _ || break
continue
fi fi
echo echo
echo -e "${c_bold}This will:${c_reset}" echo -e "${c_bold}This will:${c_reset}"
for c in "${TO_DISABLE[@]}"; do echo " - turn off: ${LABEL[$c]}"; done for c in "${TO_DISABLE[@]}"; do echo " - turn off: ${LABEL[$c]}"; done
for c in "${TO_ENABLE[@]}"; do for c in "${TO_ENABLE[@]}"; do
if [[ "${CURRENT[$c]}" == 1 ]]; then echo " - re-apply: ${LABEL[$c]}"; else echo " - turn on: ${LABEL[$c]}"; fi if is_action "$c"; then echo " - run: ${LABEL[$c]%%:*} at your own risk (checks, then asks twice more)"
elif [[ "${CURRENT[$c]}" == 1 ]]; then echo " - re-apply: ${LABEL[$c]}"; else echo " - turn on: ${LABEL[$c]}"; fi
done done
ask_yn "Go ahead?" y || { info "Nothing changed."; exit 0; } ask_yn "Go ahead?" y || { info "Nothing changed."; continue; }
# Ask for the sudo password once and keep it fresh, instead of prompting at # Ask for the sudo password once and keep it fresh, instead of prompting
# random points during the run. # at random points during the run.
sudo -n true 2>/dev/null || sudo -v || exit 1 sudo -n true 2>/dev/null || sudo -v || exit 1
if [[ "$SUDO_KEEPALIVE" == false ]]; then
SUDO_KEEPALIVE=true
while true; do sudo -n true; sleep 50; kill -0 "$$" 2>/dev/null || exit; done 2>/dev/null & while true; do sudo -n true; sleep 50; kill -0 "$$" 2>/dev/null || exit; done 2>/dev/null &
fi
apply_changes apply_changes
# Login manager changes only take effect after a restart.
[[ " ${TO_DISABLE[*]} ${TO_ENABLE[*]} " == *" gaming "* || " ${TO_DISABLE[*]} ${TO_ENABLE[*]} " == *" single "* ]] &&
RESTART_FOR_LOGIN=true
echo echo
detect_components detect_components
echo -e "${c_bold}Done. Current state:${c_reset}" echo -e "${c_bold}Done. Current state:${c_reset}"
for c in "${COMPONENTS[@]}"; do for c in "${COMPONENTS[@]}"; do
component_available "$c" || continue component_available "$c" && ! is_action "$c" || continue
if [[ "${CURRENT[$c]}" == 1 ]]; then echo -e " ${c_green}on ${c_reset} ${LABEL[$c]}"; else echo " off ${LABEL[$c]}"; fi if [[ "${CURRENT[$c]}" == 1 ]]; then echo -e " ${c_green}on ${c_reset} ${LABEL[$c]}"; else echo " off ${LABEL[$c]}"; fi
done done
if [[ ${#FAILED[@]} -gt 0 ]]; then if [[ ${#FAILED[@]} -gt 0 ]]; then
warn "These had problems (see above): ${FAILED[*]}" warn "These had problems (see above): ${FAILED[*]}"
fi fi
echo echo
after_run || break
done
echo
# Login manager changes only take effect after a restart. # A staged BIOS update is written during the restart.
if [[ " ${TO_DISABLE[*]} ${TO_ENABLE[*]} " == *" gaming "* || " ${TO_DISABLE[*]} ${TO_ENABLE[*]} " == *" single "* ]]; then if [[ -n "${BIOS_NEEDS_RESTART:-}" ]]; then
warn "The BIOS update is written during the next restart. Keep the power on and"
warn "don't touch the machine until it has fully started again, even if the screen stays black."
if ask_yn "Restart now to install the BIOS update?" n; then
restart_now
else
info "The BIOS update installs at your next restart."
fi
elif [[ "$RESTART_FOR_LOGIN" == true ]]; then
if ask_yn "Restart now so the changes take effect?" n; then if ask_yn "Restart now so the changes take effect?" n; then
sudo reboot restart_now
else else
info "Restart whenever you're ready." info "Restart whenever you're ready."
fi fi
else
info "Bye."
fi fi