mirror of
https://github.com/theupriser/steamify-cachyos.git
synced 2026-10-13 19:09:38 +02:00
Compare commits
19
Commits
No files matched your search
@@ -0,0 +1,2 @@
|
||||
Not tested on hardware yet: the whole Steamify flow for the patched gamescope on NVIDIA (apply, reboot, session).
|
||||
Delete this file when it was, after asking the user (AGENTS.md).
|
||||
@@ -5,6 +5,22 @@ 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.
|
||||
|
||||
## 2.11.2 - 2026-10-13
|
||||
|
||||
- **fix: on an NVIDIA PC that had single user mode on before the SteamOS conversion, "Return to Gaming Mode" and the boot choice work again: single user mode's desktop autologin (`zzz-steamify-autologin.conf`, read last) pinned the Plasma session; the conversion removes it, and turning the conversion off sets it up again**
|
||||
|
||||
- **fix: when an option fails, its sub-options are not applied any more (a failed conversion used to leave its "Boot into the desktop", silent start and icons on without it)**
|
||||
|
||||
- **fix: a PC that keeps `python-hidapi` (liquidctl needs it) can use the SteamOS conversion: jupiter-hw-support, which gamescope-session-cachyos depends on, wants `python-hid`, which conflicts with it and stopped the package install. Steamify builds and installs an empty placeholder package that provides `python-hid` first (`patches/python-hid-shim.PKGBUILD`); only the Steam Deck controller firmware updater uses it**
|
||||
|
||||
- **feat: the patched gamescope is downloaded as the newest release of steamify-gamescope-nvidia (checked against that release's `.sha256`), a newer one than the installed package shows the SteamOS conversion as an update, and what this Steamify was tested with is the fallback: the pinned package (sha256 in Steamify), the copy the ISO leaves, a build here; the repository's workflow builds each release in CachyOS's container**
|
||||
|
||||
- `124b424`, `f234c72` **fix: HDMI-CEC on the Steam Machine no longer needs GitHub: when downloading Valve's CEC driver fails, Steamify uses the copy it carries (`patches/cros-ec-cec.c`), checked against the same pinned sha256**
|
||||
|
||||
- `127b8cf`, `2811ecc`, `f3cd053`, `4325d80`, `03f9e87`, `5b5181f`, `06ffc8b`, `4d60dd2`, `0ba94b2` **feat: the SteamOS conversion is offered on NVIDIA PCs again (GTX 16 / RTX 20 series or newer: Turing and later, the cards NVIDIA's open kernel driver supports): it builds and installs a patched gamescope from the recipe and patch Steamify carries (`patches/`, prepared in [steamify-gamescope-nvidia](https://github.com/theupriser/steamify-gamescope-nvidia); gamescope 3.16.31, so a Steamify release builds the version it was tested with) (GBM-allocated scan-out buffers, NVIDIA's corrupted gaming-mode picture, gamescope#2309; a few minutes to build) and sets `gamescope_drm_gbm_scanout=1` for the session (`lib/gamescope-nvidia.sh`). It replaces "Gaming on NVIDIA", which is not offered any more (the kernel parameters, early modules, suspend memory and the 32-bit libraries come with the conversion on a supported card; a PC that had "Gaming on NVIDIA" on has it turned off when the conversion is turned on). Tested on an RTX 5080 (driver 615.78.08): Steam's gaming UI is clean with it and shows artifacts without. The package is pinned to one gamescope release: updating it is not automatic yet**
|
||||
|
||||
- `ce4bc67` **feat: "Gaming on NVIDIA" also keeps video memory over suspend (`NVreg_PreserveVideoMemoryAllocations=1` in `/etc/modprobe.d/90-steamify-nvidia.conf`, the initramfs is rebuilt), enables `nvidia-suspend`/`nvidia-resume`/`nvidia-hibernate`, and installs `lib32-nvidia-utils` and `lib32-libxkbcommon` (32-bit games, the 32-bit MangoHud preload) on a supported card; off removes only what Steamify added. Untested on hardware yet**
|
||||
|
||||
## 2.11.1 - 2026-10-02
|
||||
|
||||
- `d70aeb8` **docs: new README screenshots of the app (2.11 menu) on a Steam Machine and on an NVIDIA PC, and the README names the opt-in "Start Steam silently in desktop mode" and the icons as an option of the conversion**
|
||||
|
||||
@@ -187,6 +187,16 @@ Contributing (or an AI agent)? Read [AGENTS.md](AGENTS.md).
|
||||
|
||||
MIT - do whatever you want with it. See [LICENSE.md](LICENSE.md).
|
||||
|
||||
### Code from other projects
|
||||
|
||||
Some files in `patches/` are not MIT. They keep their own license, and each file says where it comes from:
|
||||
|
||||
| File | What | License and source |
|
||||
|---|---|---|
|
||||
| `steamify-fremont-poweroff.c` | Kernel module for the Steam Machine's power-off fix. It does what Valve's Steam Machine kernel does for this (clears the S4 wake bit of GPIO pin 18 at probe), but at power-off, for kernels without Valve's change. Valve's kernel: [evlaV/linux-integration](https://github.com/evlaV/linux-integration). | GPL-2.0, like the Linux kernel it is built into |
|
||||
| `cros-ec-cec.c` | Valve's Steam Machine HDMI-CEC driver (ChromeOS EC CEC, Copyright BayLibre; Valve's version of it), at a pinned commit of [evlaV/linux-integration](https://github.com/evlaV/linux-integration). Used when it can't be downloaded. | GPL-2.0+, unmodified (Steamify's `cros-ec-cec-single-port.patch` is applied when it is built) |
|
||||
| `gamescope-gbm-scanout.patch` | GBM scan-out for gamescope on NVIDIA: nine commits of [farnoy/gamescope](https://github.com/farnoy/gamescope) on [ValveSoftware/gamescope](https://github.com/ValveSoftware/gamescope). | gamescope's license (BSD-2-Clause) |
|
||||
|
||||
## Disclaimer
|
||||
|
||||
Steamify CachyOS is an unofficial community project. It is not affiliated
|
||||
|
||||
+25
-4
@@ -238,10 +238,30 @@ no fix known). The kernel parameters `nvidia-drm.modeset=1`/`fbdev=1` and loadin
|
||||
window straight to the display. What does work on an RTX 5080: Steam's Big Picture (`steam -gamepadui`) as a normal window of
|
||||
the Plasma desktop session, smooth and clean.
|
||||
|
||||
So with an NVIDIA GPU (PCI vendor 0x10de, display class, its driver providing `nvidia_drm`: `nvidia_present`) the SteamOS
|
||||
conversion (`gaming`, and its options `boot`, `single`, `glyphs`) isn't offered, unless it is already on (so it can be turned
|
||||
off). `nvidia` ("Gaming on NVIDIA", `lib/nvidia.sh`) takes its place, hidden while the conversion is on (both would start
|
||||
Steam at login): it installs `steam` when missing (recorded in state `nvidia`, removed again only then) and enables the user
|
||||
Since 2.11.2 there is a second way: gamescope with GBM-allocated scan-out buffers (`lib/gamescope-nvidia.sh`). On an RTX 5080
|
||||
(driver 615.78.08, 3440x1440@175) Steam's gaming UI in gamescope's DRM session is clean with it and shows artifacts everywhere
|
||||
without. The patch is nine commits of [farnoy/gamescope](https://github.com/farnoy/gamescope) (`nvidia-gbm-wayland`), carried in
|
||||
`patches/` (`gamescope-gbm-scanout.patch` and the recipe `gamescope-nvidia.PKGBUILD`, kept in sync with
|
||||
[steamify-gamescope-nvidia](https://github.com/theupriser/steamify-gamescope-nvidia), where new gamescope versions are
|
||||
prepared). gamescope changes every few weeks, so the package is downloaded, not carried: `gsn_install_package` takes the
|
||||
**newest release** of that repository (CI builds it in CachyOS's container; a person merges the version bump), checked against the
|
||||
`.sha256` of the same release, and installs it with `pacman -U --ask 4` (the package provides and conflicts with `gamescope`). What
|
||||
this Steamify release was tested with is the fallback, in this order: the pinned package (`GSN_VERSION`, `GSN_SHA256`: from GitHub, the
|
||||
cache, or the copy the ISO leaves in `/usr/local/share/steamify/gamescope`), then a build here from the recipe and patch in `patches/`
|
||||
(`makepkg -sf` as the user, in `~/.cache/steamify`; no checksums on gamescope's own sources). A package that downloaded fine but
|
||||
doesn't install goes on to the next step; nothing changes before one of them is installed. A newer release than the installed package
|
||||
shows the conversion as an update (`gsn_update_pending`, looked up at most every six hours, quiet offline). Simple files that don't
|
||||
change (the power-off module, small patches) stay in `patches/` as they are. It is opt-in inside gamescope: `gamescope_drm_gbm_scanout=1` in
|
||||
`~/.config/gamescope-session/environment` and `~/.config/environment.d/99-steamify-gamescope-nvidia.conf`. The SteamOS conversion
|
||||
(`gaming_enable`) does this on every NVIDIA PC (`nvidia_present`: PCI vendor 0x10de, display class, its driver providing
|
||||
`nvidia_drm`), together with what "Gaming on NVIDIA" set up (on a supported card, `nvidia_supported`: GTX 16 / RTX 20 series or
|
||||
newer, Turing and later): the kernel parameters, the early modules, suspend memory, the 32-bit libraries (`nvidia_kernel_enable`,
|
||||
`nvidia_extras_enable`). So the SteamOS conversion is the one gaming option on NVIDIA now, and "Gaming on NVIDIA" (below) is not
|
||||
offered any more (`nvidia_available`); a PC that had it on keeps it until the conversion is turned on, which turns it off
|
||||
(`nvidia_swap_out`). Turning the conversion off removes the setting and those settings, and keeps the packages. Tested on an RTX 5080 only.
|
||||
|
||||
Before 2.11.2, with an NVIDIA GPU the SteamOS conversion (`gaming`, and its options `boot`, `single`, `glyphs`) wasn't offered, unless
|
||||
it was already on. `nvidia` ("Gaming on NVIDIA", `lib/nvidia.sh`) took its place (both would start Steam at login): it installs `steam` when missing (recorded in state `nvidia`, removed again only then) and enables the user
|
||||
unit `steamify-steam-autostart.service` (`services/`, `ExecStart=/usr/bin/steam @ARGS@`, Plasma only). Its sub-option
|
||||
`bigpicture` ("Steam starts in Big Picture", ticked along with it) rewrites the unit with `-gamepadui` and sets
|
||||
`ksmserverrc [General] loginMode=emptySession` (`kset`, undone with `krevert bigpicture`), so windows of the last session
|
||||
@@ -572,6 +592,7 @@ immediately, which can turn into a loop - see
|
||||
| `lib/update-notifier.sh` | Update notifications: the notifier from `patches/` and its user timer |
|
||||
| `lib/first-login.sh` | `--defaults` without a session (the Steam Machine ISO's installer): the one-time first-login step that sets up single user's launcher on Plasma's new layout and opens the app |
|
||||
| `lib/controllers.sh` | Extended controller support: Xbox wireless dongle (xone) and Xbox Bluetooth (xpadneo) from the CachyOS repo |
|
||||
| `lib/gamescope-nvidia.sh` | gamescope on NVIDIA: builds and installs the patched gamescope (GBM scan-out) from steamify-gamescope-nvidia and sets `gamescope_drm_gbm_scanout=1` for the SteamOS conversion |
|
||||
| `lib/nvidia.sh` | Gaming on NVIDIA: Steam on the desktop, started at login, optionally in Big Picture (replaces the SteamOS conversion there) |
|
||||
| `lib/vram-booster.sh` | VRAM booster (`dmemcg-booster`, `plasma-foreground-booster`) |
|
||||
| `services/` | The systemd units the scripts install (`service_file`, `@KEY@` placeholders); see its README |
|
||||
|
||||
+6
-1
@@ -147,7 +147,6 @@ backend_apply() {
|
||||
for id in "${want[@]}"; do [[ "$id" == "$c" ]] && WANTED[$c]=1; done
|
||||
done
|
||||
# The same rules as the menu's toggles.
|
||||
# (Single user mode only needs the conversion where it is offered: not on NVIDIA PCs.)
|
||||
[[ "${WANTED[single]:-0}" == 1 ]] && component_available gaming && WANTED[gaming]=1
|
||||
if component_available gaming; then
|
||||
[[ "${WANTED[gaming]:-0}" == 0 ]] && { WANTED[single]=0; WANTED[boot]=0; }
|
||||
@@ -186,6 +185,12 @@ backend_apply() {
|
||||
if backend_run_component "$c" disable; then feature_record "$c" disable; else failed+=("$c"); fi
|
||||
done
|
||||
for c in "${TO_ENABLE[@]}"; do
|
||||
# A sub-option of something that just failed isn't applied: it would be left on without its parent.
|
||||
if [[ -n "${PARENT[$c]:-}" && " ${failed[*]:-} " == *" ${PARENT[$c]} "* ]]; then
|
||||
backend_event log "\"id\":$(json_str "$c"),\"line\":$(json_str "Skipped: ${LABEL[${PARENT[$c]}]%%:*} didn't work.")"
|
||||
failed+=("$c")
|
||||
continue
|
||||
fi
|
||||
if backend_run_component "$c" enable; then is_action "$c" || feature_record "$c" enable; else failed+=("$c"); fi
|
||||
done
|
||||
feature_record_unticked
|
||||
|
||||
+9
-4
@@ -73,11 +73,16 @@ cec_driver_enable() {
|
||||
cp "$CEC_DRIVER_CACHE" "$tmp/cros-ec-cec.c"
|
||||
else
|
||||
info "Downloading Valve's Steam Machine CEC driver..."
|
||||
if ! curl -fsL --retry 2 "$CEC_DRIVER_URL" -o "$tmp/cros-ec-cec.c" ||
|
||||
if ! curl -fsL --retry 2 --max-time 60 "$CEC_DRIVER_URL" -o "$tmp/cros-ec-cec.c" ||
|
||||
! echo "$CEC_DRIVER_SHA256 $tmp/cros-ec-cec.c" | sha256sum -c --quiet -; then
|
||||
rm -rf "$tmp"
|
||||
err "Downloading Valve's CEC driver failed (or its checksum didn't match)."
|
||||
return 1
|
||||
# GitHub is down, rate-limits us, or sent something else: Steamify carries the same file (checked the same way).
|
||||
warn "Downloading Valve's CEC driver failed (or its checksum didn't match): using the copy Steamify carries."
|
||||
patch_file cros-ec-cec.c > "$tmp/cros-ec-cec.c"
|
||||
if ! echo "$CEC_DRIVER_SHA256 $tmp/cros-ec-cec.c" | sha256sum -c --quiet -; then
|
||||
rm -rf "$tmp"
|
||||
err "Steamify's own copy of Valve's CEC driver doesn't match the pinned checksum (a new pin needs a new copy in patches/)."
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
# The name carries the checksum: a newer pin gets its own file, the old one goes.
|
||||
sudo find "${CEC_DRIVER_CACHE%/*}" -maxdepth 1 -name 'cros-ec-cec-*.c' ! -name "${CEC_DRIVER_CACHE##*/}" -delete 2>/dev/null
|
||||
|
||||
@@ -0,0 +1,204 @@
|
||||
#!/bin/bash
|
||||
# gamescope's own gaming mode on NVIDIA: a patched gamescope that allocates its scan-out buffers with GBM, which cures
|
||||
# the corrupted picture (https://github.com/ValveSoftware/gamescope/issues/2309). The patch is opt-in: gamescope reads
|
||||
# `gamescope_drm_gbm_scanout=1` from its environment, which is set for the gaming session (gamescope-session's
|
||||
# environment file, and environment.d).
|
||||
#
|
||||
# gamescope changes every few weeks, so the package is not carried but downloaded: the newest release of
|
||||
# https://github.com/theupriser/steamify-gamescope-nvidia (CI builds it in CachyOS's container, a person merges the
|
||||
# version bump), and a newer one than the installed package shows as an update of the SteamOS conversion
|
||||
# (`gsn_update_pending`). What this Steamify release was tested with is the fallback: the pinned package (sha256 below),
|
||||
# a copy that came with the ISO, and last a build here from the recipe and patch in patches/. Simple files that don't change
|
||||
# stay in patches/ and are used as they are.
|
||||
#
|
||||
# Used by the SteamOS conversion (`gaming_enable`/`gaming_disable`) on every NVIDIA PC (`nvidia_present`); the kernel
|
||||
# parameters and the rest of lib/nvidia.sh's setup only on a supported card (`nvidia_supported`): GTX 16 / RTX 20 series or
|
||||
# newer (Turing and later, what NVIDIA's open kernel driver supports). Tested on an RTX 5080 only.
|
||||
# Sourced by steamify.sh; not meant to be run on its own.
|
||||
|
||||
GSN_PKG=steamify-gamescope-nvidia
|
||||
GSN_RELEASES="${GSN_RELEASES:-https://github.com/theupriser/steamify-gamescope-nvidia/releases}"
|
||||
# The package this Steamify release was tested with (patches/gamescope-nvidia.PKGBUILD names the same version): the
|
||||
# fallback. A new pin: the release's tag, the package's sha256, and the PKGBUILD's pkgver/pkgrel.
|
||||
GSN_VERSION=3.16.31-1
|
||||
GSN_SHA256=9f20e5243866d1ddeb9ba0c6828bc7be1945f623f9a5d8094391f0df043002e1
|
||||
# Where the ISO leaves a copy of the pinned package, for installs without GitHub.
|
||||
GSN_BACKUP_DIR="${GSN_BACKUP_DIR:-/usr/local/share/steamify/gamescope}"
|
||||
# How long a look at GitHub for a newer release counts (seconds), so opening the menu doesn't ask every time.
|
||||
GSN_CHECK_EVERY="${GSN_CHECK_EVERY:-21600}"
|
||||
GSN_ENV_LINE='gamescope_drm_gbm_scanout=1'
|
||||
GSN_ENV_D="${GSN_ENV_D:-$HOME/.config/environment.d/99-steamify-gamescope-nvidia.conf}"
|
||||
GSN_SESSION_ENV="${GSN_SESSION_ENV:-$HOME/.config/gamescope-session/environment}"
|
||||
|
||||
gsn_package_installed() { pacman -Q "$GSN_PKG" >/dev/null 2>&1; }
|
||||
|
||||
gsn_installed_version() { pacman -Q "$GSN_PKG" 2>/dev/null | awk '{print $2}'; }
|
||||
|
||||
gsn_env_set() { [[ -f "$GSN_ENV_D" ]] && grep -qsx "$GSN_ENV_LINE" "$GSN_SESSION_ENV"; }
|
||||
|
||||
gsn_status() { gsn_package_installed && gsn_env_set; }
|
||||
|
||||
gsn_newer() {
|
||||
# gsn_newer <a> <b>: version a is newer than b (pacman's own comparison).
|
||||
[[ "$(vercmp "$1" "$2" 2>/dev/null)" == 1 ]]
|
||||
}
|
||||
|
||||
gsn_latest_tag() {
|
||||
# The newest release's tag (<gamescope version>-<package release>), from GitHub; nothing when it can't be reached or
|
||||
# there is no release. Follows the redirect of /releases/latest: no API, no rate limit, no JSON. gsn_latest_tag [seconds]
|
||||
local url
|
||||
url="$(curl -fsL --connect-timeout 4 --max-time "${1:-10}" -o /dev/null -w '%{url_effective}' "$GSN_RELEASES/latest" 2>/dev/null)" || return 1
|
||||
url="${url##*/}"
|
||||
[[ "$url" =~ ^[0-9][0-9A-Za-z._]*-[0-9]+$ ]] || return 1
|
||||
echo "$url"
|
||||
}
|
||||
|
||||
gsn_update_pending() {
|
||||
# The patched gamescope is installed and GitHub has a newer release: the menu shows the conversion as an update.
|
||||
# Looked up at most every GSN_CHECK_EVERY seconds (the answer is kept in the state), quickly, and silently when
|
||||
# offline: no network is never a reason to show or hide anything.
|
||||
gsn_package_installed || return 1
|
||||
local now checked latest
|
||||
now="$(date +%s)"; checked="$(state_get gamescope_nvidia checked 0)"
|
||||
if (( now - ${checked:-0} > GSN_CHECK_EVERY )); then
|
||||
state_set gamescope_nvidia checked "$now"
|
||||
latest="$(gsn_latest_tag 5)" && state_set gamescope_nvidia latest "$latest"
|
||||
fi
|
||||
latest="$(state_get gamescope_nvidia latest)"
|
||||
[[ -n "$latest" ]] && gsn_newer "$latest" "$(gsn_installed_version)"
|
||||
}
|
||||
|
||||
gsn_sha_of() {
|
||||
# The hash a release file is expected to have: the pinned one for the pinned version, else the .sha256 next to the
|
||||
# package in the same release (it shows the download wasn't damaged, not who made it).
|
||||
local tag="$1" file="$2"
|
||||
if [[ "$tag" == "$GSN_VERSION" ]]; then echo "$GSN_SHA256"; return 0; fi
|
||||
curl -fsL --connect-timeout 10 --max-time 30 "$GSN_RELEASES/download/$tag/$file.sha256" 2>/dev/null | awk 'NR==1 {print $1}'
|
||||
}
|
||||
|
||||
gsn_download() {
|
||||
# gsn_download <tag>: the release's package, verified, in the cache; prints its path.
|
||||
local tag="$1" cache="${XDG_CACHE_HOME:-$HOME/.cache}/steamify" file want got
|
||||
file="$GSN_PKG-$tag-x86_64.pkg.tar.zst"
|
||||
mkdir -p "$cache" || return 1
|
||||
want="$(gsn_sha_of "$tag" "$file")"
|
||||
[[ "$want" =~ ^[0-9a-f]{64}$ ]] || return 1
|
||||
if [[ -f "$cache/$file" ]] && [[ "$(sha256sum "$cache/$file" | awk '{print $1}')" == "$want" ]]; then echo "$cache/$file"; return 0; fi
|
||||
curl -fsL --retry 2 --connect-timeout 15 --max-time 300 -o "$cache/$file.part" "$GSN_RELEASES/download/$tag/$file" || { rm -f "$cache/$file.part"; return 1; }
|
||||
got="$(sha256sum "$cache/$file.part" | awk '{print $1}')"
|
||||
if [[ "$got" != "$want" ]]; then rm -f "$cache/$file.part"; return 1; fi
|
||||
mv -f "$cache/$file.part" "$cache/$file"
|
||||
echo "$cache/$file"
|
||||
}
|
||||
|
||||
gsn_fetch_package() {
|
||||
# The package to install, as a path, newest first: the newest release on GitHub (not older than the pinned one), else
|
||||
# the pinned package (GitHub, the cache, or the copy that came with the ISO). Only files with the expected sha256 count.
|
||||
local tag pkg cache="${XDG_CACHE_HOME:-$HOME/.cache}/steamify" file="$GSN_PKG-$GSN_VERSION-x86_64.pkg.tar.zst" copy
|
||||
tag="$(gsn_latest_tag)" || tag=""
|
||||
if [[ -n "$tag" && "$tag" != "$GSN_VERSION" ]] && gsn_newer "$tag" "$GSN_VERSION"; then
|
||||
info "Downloading the newest patched gamescope ($tag)..." >&2
|
||||
if pkg="$(gsn_download "$tag")"; then echo "$pkg"; return 0; fi
|
||||
warn "Downloading the newest patched gamescope ($tag) failed: using the version this Steamify was tested with ($GSN_VERSION)." >&2
|
||||
fi
|
||||
info "Downloading the patched gamescope ($GSN_VERSION)..." >&2
|
||||
if pkg="$(gsn_download "$GSN_VERSION")"; then echo "$pkg"; return 0; fi
|
||||
warn "Downloading the patched gamescope failed (or its checksum didn't match)." >&2
|
||||
for copy in "$GSN_BACKUP_DIR/$file" "$cache/$file"; do
|
||||
if [[ -f "$copy" ]] && [[ "$(sha256sum "$copy" | awk '{print $1}')" == "$GSN_SHA256" ]]; then
|
||||
info "Using the copy that came with Steamify: $copy" >&2
|
||||
echo "$copy"; return 0
|
||||
fi
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
gsn_build_package() {
|
||||
# Last resort: builds the pinned package from the recipe and patch Steamify carries (patches/), as the user. It
|
||||
# downloads gamescope's sources (Valve's repository at the PKGBUILD's pkgver, and its submodules) and compiles them: a
|
||||
# few minutes. Prints the package's path.
|
||||
local dir cache="${XDG_CACHE_HOME:-$HOME/.cache}/steamify"
|
||||
info "Building the patched gamescope here instead (a few minutes)..." >&2
|
||||
sudo pacman -S --needed --noconfirm base-devel git >&2 || { err "Installing the build tools failed." >&2; return 1; }
|
||||
# On disk, not /tmp: the installer's chroot has a tmpfs there (RAM), and the build is 1-2 GB.
|
||||
mkdir -p "$cache" && dir="$(mktemp -d -p "$cache" gamescope-build.XXXXXX)" || return 1
|
||||
patch_file gamescope-nvidia.PKGBUILD > "$dir/PKGBUILD" &&
|
||||
patch_file gamescope-gbm-scanout.patch > "$dir/gamescope-gbm-scanout.patch" || {
|
||||
err "Couldn't write the build files." >&2
|
||||
rm -rf "$dir"; return 1
|
||||
}
|
||||
if ! (cd "$dir" && makepkg -sf --noconfirm --nocheck >&2); then
|
||||
err "Building the patched gamescope failed (see above)." >&2
|
||||
rm -rf "$dir"; return 1
|
||||
fi
|
||||
# Moved out, so the build folder can go.
|
||||
mv "$(ls "$dir"/"$GSN_PKG"-*.pkg.tar.* 2>/dev/null | grep -v -- '-debug-' | head -1)" "$cache/gamescope-local-build.pkg.tar.zst" ||
|
||||
{ rm -rf "$dir"; return 1; }
|
||||
rm -rf "$dir"
|
||||
echo "$cache/gamescope-local-build.pkg.tar.zst"
|
||||
}
|
||||
|
||||
gsn_install_package() {
|
||||
# The patched gamescope, newest first, each step only when the one before failed: the newest release from GitHub, the
|
||||
# pinned package (GitHub, cache or the copy that came with the ISO), a build here. A package that downloaded fine but
|
||||
# doesn't install (its libraries differ from this PC's) goes on to the next step too. Nothing else changes before one of
|
||||
# them is installed, so a failure leaves the PC as it was, with what it had. --ask 4 lets pacman replace the stock
|
||||
# gamescope it conflicts with, and an older patched one.
|
||||
local pkg latest have
|
||||
have="$(gsn_installed_version)"
|
||||
latest="$(gsn_latest_tag)" || latest=""
|
||||
# Already the newest (or, offline, the pinned version or newer): nothing to do.
|
||||
if [[ -n "$have" ]]; then
|
||||
if [[ -n "$latest" ]] && ! gsn_newer "$latest" "$have"; then return 0; fi
|
||||
if [[ -z "$latest" ]] && ! gsn_newer "$GSN_VERSION" "$have"; then return 0; fi
|
||||
fi
|
||||
if pkg="$(gsn_fetch_package)" && sudo pacman -U --noconfirm --ask 4 "$pkg"; then
|
||||
ok "Patched gamescope installed."
|
||||
return 0
|
||||
fi
|
||||
warn "The ready-made patched gamescope couldn't be installed."
|
||||
[[ -n "$have" ]] && { warn "The installed one ($have) stays."; return 0; }
|
||||
if pkg="$(gsn_build_package)" && sudo pacman -U --noconfirm --ask 4 "$pkg"; then
|
||||
ok "Patched gamescope built and installed."
|
||||
return 0
|
||||
fi
|
||||
err "The patched gamescope couldn't be installed. The stock gamescope stays."
|
||||
return 1
|
||||
}
|
||||
|
||||
gsn_env_enable() {
|
||||
mkdir -p "$(dirname "$GSN_ENV_D")" "$(dirname "$GSN_SESSION_ENV")"
|
||||
echo "$GSN_ENV_LINE" > "$GSN_ENV_D"
|
||||
touch "$GSN_SESSION_ENV"
|
||||
grep -qsx "$GSN_ENV_LINE" "$GSN_SESSION_ENV" || echo "$GSN_ENV_LINE" >> "$GSN_SESSION_ENV"
|
||||
}
|
||||
|
||||
gsn_env_disable() {
|
||||
rm -f "$GSN_ENV_D"
|
||||
[[ -f "$GSN_SESSION_ENV" ]] && sed -i "/^${GSN_ENV_LINE}\$/d" "$GSN_SESSION_ENV"
|
||||
return 0
|
||||
}
|
||||
|
||||
gsn_enable() {
|
||||
# Only on a supported NVIDIA card; elsewhere the stock gamescope is right.
|
||||
nvidia_present || return 0
|
||||
# A PC that had "Gaming on NVIDIA" on: Steam must not also start on the desktop.
|
||||
nvidia_swap_out
|
||||
# What NVIDIA's DRM stack wants (lib/nvidia.sh; a supported card only, the functions check): modeset/fbdev on the
|
||||
# kernel command line, the modules in the initramfs, video memory kept over suspend, the 32-bit libraries. Takes
|
||||
# effect at the next boot, like the session.
|
||||
nvidia_kernel_enable || return 1
|
||||
nvidia_extras_enable || return 1
|
||||
gsn_install_package || return 1
|
||||
gsn_env_enable
|
||||
ok "gamescope draws NVIDIA's picture through GBM (gamescope_drm_gbm_scanout=1) from the next gaming mode start."
|
||||
}
|
||||
|
||||
gsn_disable() {
|
||||
# The setting goes, and what nvidia_*_enable added; the packages stay (patched gamescope, 32-bit libraries), like
|
||||
# the other packages of the conversion (steam, gamescope-session-cachyos).
|
||||
gsn_env_disable
|
||||
nvidia_present || return 0
|
||||
nvidia_extras_disable
|
||||
nvidia_kernel_disable
|
||||
}
|
||||
@@ -94,6 +94,8 @@ gaming_enable() {
|
||||
# LOGIN_MANAGER (sddm with single user, else plasmalogin) is set by the
|
||||
# menu. Re-running with the other value switches over cleanly.
|
||||
install_required_packages || return 1
|
||||
# NVIDIA: gamescope's picture is corrupted unless it is the patched one (no-op elsewhere).
|
||||
gsn_enable || return 1
|
||||
case "$LOGIN_MANAGER" in
|
||||
sddm)
|
||||
switch_to_sddm || return 1
|
||||
@@ -107,6 +109,8 @@ gaming_enable() {
|
||||
install_session_sync
|
||||
;;
|
||||
esac
|
||||
# (NVIDIA with single user mode from before the conversion: its desktop autologin would pin the Plasma session.)
|
||||
single_login_release
|
||||
create_desktop_shortcut
|
||||
steam_enable
|
||||
os_name_enable || return 1
|
||||
@@ -122,8 +126,11 @@ gaming_disable() {
|
||||
switch_to_plasmalogin
|
||||
remove_desktop_shortcut
|
||||
steam_disable
|
||||
gsn_disable
|
||||
krevert gaming
|
||||
os_name_disable
|
||||
# NVIDIA with single user mode still on: nothing else logs in by itself any more.
|
||||
nvidia_present && single_status && single_login_enable
|
||||
ok "The PC boots to the normal login screen again (from the next boot)."
|
||||
}
|
||||
|
||||
|
||||
+24
-7
@@ -26,7 +26,7 @@ NO_PRESELECT=(boot silent nvsilent cec kpin hdmi extended_controller_support)
|
||||
# FEATURE_BASELINE.
|
||||
FEATURE_BASELINE=2.1.0
|
||||
declare -A FEATURE_VERSION=(
|
||||
[gaming]=2.9.0 [boot]=2.1.0 [silent]=2.11.0 [nvidia]=2.10.0 [bigpicture]=2.10.0 [nvsilent]=2.11.0 [theme]=2.1.0 [glyphs]=2.1.0 [single]=2.1.0
|
||||
[gaming]=2.9.0 [boot]=2.1.0 [silent]=2.11.0 [nvidia]=2.11.2 [bigpicture]=2.10.0 [nvsilent]=2.11.0 [theme]=2.1.0 [glyphs]=2.1.0 [single]=2.1.0
|
||||
[launcher]=2.1.0 [cec]=2.7.0 [machine]=2.9.0 [poweroff]=2.2.0 [vram]=2.3.0 [notify]=2.5.0 [steamgame]=2.5.1 [extended_controller_support]=2.10.0
|
||||
[kpin]=2.1.0 [hdmi]=2.1.0
|
||||
)
|
||||
@@ -57,11 +57,9 @@ declare -A CURRENT WANTED
|
||||
|
||||
component_available() {
|
||||
case "$1" in
|
||||
# gamescope's own session is broken on NVIDIA: the conversion is replaced by "Gaming on NVIDIA" there (shown
|
||||
# anyway when it's already on, so it can be turned off).
|
||||
gaming|boot|silent|glyphs) ! nvidia_present || gaming_status ;;
|
||||
nvidia) nvidia_available ;;
|
||||
bigpicture|nvsilent) bigpicture_available ;;
|
||||
# The SteamOS conversion is offered on NVIDIA PCs too: it installs the patched gamescope there (lib/gamescope-nvidia.sh)
|
||||
# and turns off "Gaming on NVIDIA" (lib/nvidia.sh), which is not offered any more (nvidia_available).
|
||||
nvidia|bigpicture|nvsilent) nvidia_available ;;
|
||||
machine|poweroff) machine_available ;;
|
||||
vram) vram_available ;;
|
||||
# Steamify in the Steam library is for gaming mode's controller: not needed for Big Picture on the desktop (NVIDIA PCs;
|
||||
@@ -115,7 +113,11 @@ feature_outdated() {
|
||||
# On, but set up by an older version of that feature (compared as
|
||||
# versions: 2.10.0 is newer than 2.9.0).
|
||||
local have want
|
||||
# "Gaming on NVIDIA" is on: the SteamOS conversion replaces it, as an update of what the PC has (lib/nvidia.sh).
|
||||
[[ "$1" == gaming ]] && nvidia_migration_pending && return 0
|
||||
[[ "${CURRENT[$1]:-0}" == 1 ]] || return 1
|
||||
# NVIDIA: a newer patched gamescope is out (lib/gamescope-nvidia.sh): a normal run installs it.
|
||||
[[ "$1" == gaming ]] && nvidia_present && gsn_update_pending && return 0
|
||||
have="$(state_get features "$1" "$FEATURE_BASELINE")"
|
||||
[[ "$have" == off ]] && have="$FEATURE_BASELINE"
|
||||
want="${FEATURE_VERSION[$1]:-$FEATURE_BASELINE}"
|
||||
@@ -184,6 +186,17 @@ detect_components() {
|
||||
component_available "$c" || continue
|
||||
{ feature_outdated "$c" || feature_new "$c"; } && WANTED[$c]=1
|
||||
done
|
||||
# "Gaming on NVIDIA" was on: its replacement, the SteamOS conversion, comes with the defaults of a first run, and the
|
||||
# PC starts the way it did: Steam in Big Picture at login becomes booting into gaming mode, any other Steam start
|
||||
# (a normal window, or silent in the tray) becomes booting into the desktop, with the silent start kept.
|
||||
if nvidia_migration_pending; then
|
||||
WANTED[glyphs]=1
|
||||
if bigpicture_status; then WANTED[boot]=0
|
||||
else
|
||||
WANTED[boot]=1
|
||||
nvsilent_status && WANTED[silent]=1
|
||||
fi
|
||||
fi
|
||||
# The kernel pin is no longer needed (the power-off fix), and HDMI
|
||||
# refresh boost needed the pin: whatever is left of either is unticked,
|
||||
# so a normal run removes it.
|
||||
@@ -296,7 +309,6 @@ toggle_component() {
|
||||
component_selectable "$c" || return 1
|
||||
WANTED[$c]=$(( 1 - WANTED[$c] ))
|
||||
# Single user mode only makes sense on top of the SteamOS conversion.
|
||||
# (On NVIDIA the conversion isn't offered: single user mode logs in by itself, see lib/single-user.sh.)
|
||||
if [[ "$c" == single && "${WANTED[single]}" == 1 ]] && component_available gaming; then WANTED[gaming]=1; fi
|
||||
if [[ "$c" == gaming && "${WANTED[gaming]}" == 0 ]]; then WANTED[single]=0; WANTED[boot]=0; fi
|
||||
# Where to boot to is part of the conversion, too.
|
||||
@@ -499,6 +511,11 @@ apply_changes() {
|
||||
if "${c}_disable"; then feature_record "$c" disable; else failed+=("$c"); fi
|
||||
done
|
||||
for c in "${TO_ENABLE[@]}"; do
|
||||
# A sub-option of something that just failed isn't applied: it would be left on without its parent.
|
||||
if [[ -n "${PARENT[$c]:-}" && " ${failed[*]:-} " == *" ${PARENT[$c]} "* ]]; then
|
||||
warn "Skipping ${LABEL[$c]%%:*}: ${LABEL[${PARENT[$c]}]%%:*} didn't work."
|
||||
continue
|
||||
fi
|
||||
if [[ "$c" == boot ]]; then echo; echo -e "${c_bold}Boot into: desktop${c_reset}"
|
||||
elif 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
|
||||
|
||||
+77
-5
@@ -13,6 +13,11 @@ NVIDIA_INITRAMFS_CONF=${NVIDIA_INITRAMFS_CONF:-/etc/mkinitcpio.conf.d/90-steamif
|
||||
# The script and pacman hook that keep the initramfs file right at every kernel change.
|
||||
NVIDIA_SCRIPT=${NVIDIA_SCRIPT:-/usr/local/libexec/steamify-nvidia-initramfs}
|
||||
NVIDIA_HOOK=${NVIDIA_HOOK:-/etc/pacman.d/hooks/85-steamify-nvidia-initramfs.hook}
|
||||
# Keeps video memory over suspend (with the nvidia-suspend/resume services).
|
||||
NVIDIA_MODPROBE=${NVIDIA_MODPROBE:-/etc/modprobe.d/90-steamify-nvidia.conf}
|
||||
NVIDIA_SLEEP_UNITS="nvidia-suspend.service nvidia-resume.service nvidia-hibernate.service"
|
||||
# 32-bit parts Steam games and the 32-bit MangoHud preload need.
|
||||
NVIDIA_LIB32_PKGS="lib32-nvidia-utils lib32-libxkbcommon"
|
||||
# The running kernel's command line; the tests point this at a file.
|
||||
NVIDIA_CMDLINE=${NVIDIA_CMDLINE:-/proc/cmdline}
|
||||
# The DRM devices in sysfs; the tests point this at a fake tree.
|
||||
@@ -32,9 +37,27 @@ nvidia_present() {
|
||||
return 1
|
||||
}
|
||||
|
||||
# Shown on NVIDIA PCs, unless the SteamOS conversion is already on there (it
|
||||
# has to be turned off first: both would start Steam at login).
|
||||
nvidia_available() { nvidia_present && ! gaming_status 2>/dev/null; }
|
||||
# Not offered any more (2.11.2): the SteamOS conversion with the patched gamescope (lib/gamescope-nvidia.sh) covers NVIDIA PCs.
|
||||
# A PC that has this on keeps it until the conversion is turned on, which calls nvidia_swap_out.
|
||||
nvidia_available() { return 1; }
|
||||
|
||||
nvidia_migration_pending() {
|
||||
# "Gaming on NVIDIA" is on (set up before 2.11.2) and the SteamOS conversion that replaces it isn't: the menu ticks the
|
||||
# conversion and shows it as an update, so a normal run moves the PC over (nvidia_swap_out in gsn_enable).
|
||||
nvidia_present && nvidia_status && ! gaming_status 2>/dev/null
|
||||
}
|
||||
|
||||
nvidia_swap_out() {
|
||||
# The conversion takes over: Steam no longer starts by itself on the desktop at login (both would start it). Steam, the
|
||||
# packages and the NVIDIA settings stay: the conversion needs them too. The state stays for the conversion's own disable.
|
||||
nvidia_status || return 0
|
||||
info "Gaming on NVIDIA is replaced by the SteamOS conversion: Steam no longer starts on the desktop at login."
|
||||
user_systemctl disable --now "$NVIDIA_UNIT" >/dev/null 2>&1
|
||||
rm -f "$(nvidia_unit_file)"
|
||||
user_systemctl daemon-reload
|
||||
krevert bigpicture
|
||||
return 0
|
||||
}
|
||||
bigpicture_available() { nvidia_available; }
|
||||
|
||||
nvidia_status() {
|
||||
@@ -62,6 +85,7 @@ nvidia_enable() {
|
||||
nvidia_write_unit "$unit_args" || return 1
|
||||
user_systemctl enable "$NVIDIA_UNIT" >/dev/null 2>&1 || { err "Enabling $NVIDIA_UNIT failed."; return 1; }
|
||||
nvidia_kernel_enable || return 1
|
||||
nvidia_extras_enable || return 1
|
||||
ok "Steam starts at your next login."
|
||||
}
|
||||
|
||||
@@ -70,13 +94,19 @@ nvidia_disable() {
|
||||
user_systemctl disable --now "$NVIDIA_UNIT" >/dev/null 2>&1
|
||||
rm -f "$unit"
|
||||
user_systemctl daemon-reload
|
||||
# Swapped for the SteamOS conversion (turned on first, in the same run): it needs the same settings, they stay.
|
||||
gaming_status 2>/dev/null || nvidia_extras_disable
|
||||
pkgs="$(state_get nvidia installed_pkgs)"
|
||||
if gaming_status 2>/dev/null; then
|
||||
local p; pkgs=" $pkgs "
|
||||
for p in $NVIDIA_LIB32_PKGS; do pkgs="${pkgs// $p / }"; done
|
||||
fi
|
||||
# Only what Steamify installed; games and the Steam folder stay.
|
||||
# shellcheck disable=SC2086 # a list of package names
|
||||
[[ -n "$pkgs" ]] && sudo pacman -Rns --noconfirm $pkgs >/dev/null 2>&1
|
||||
state_clear nvidia
|
||||
krevert bigpicture
|
||||
nvidia_kernel_disable
|
||||
gaming_status 2>/dev/null || nvidia_kernel_disable
|
||||
ok "Steam no longer starts at login."
|
||||
}
|
||||
|
||||
@@ -118,7 +148,7 @@ nvsilent_disable() {
|
||||
|
||||
nvidia_supported() {
|
||||
# A supported NVIDIA GPU: PCI vendor 0x10de, display class, its kernel
|
||||
# driver installed, and not older than the RTX 20 series, decided like the
|
||||
# driver installed, and not older than Turing (GTX 16 / RTX 20 series: the cards NVIDIA's open kernel driver supports), decided like the
|
||||
# VRAM booster does (vram_nvidia_legacy_id: chwd's legacy card lists, every
|
||||
# other card runs NVIDIA's open modules). Older cards are left alone.
|
||||
local d
|
||||
@@ -254,6 +284,48 @@ nvidia_kernel_enable() {
|
||||
return 0
|
||||
}
|
||||
|
||||
nvidia_extras_enable() {
|
||||
# Video memory kept over sleep, the matching services and the 32-bit libraries (a supported card only).
|
||||
nvidia_supported || return 0
|
||||
local pkg u units="" prev missing=()
|
||||
if [[ ! -f "$NVIDIA_MODPROBE" ]]; then
|
||||
info "Keeping video memory over suspend (NVreg_PreserveVideoMemoryAllocations=1)..."
|
||||
printf '%s\n' '# Added by Steamify (Gaming on NVIDIA)' 'options nvidia NVreg_PreserveVideoMemoryAllocations=1' |
|
||||
sudo tee "$NVIDIA_MODPROBE" >/dev/null || { err "Writing $NVIDIA_MODPROBE failed."; return 1; }
|
||||
# The NVIDIA modules load from the initramfs, which carries modprobe.d.
|
||||
nvidia_rebuild_boot || warn "Rebuilding the initramfs failed: the suspend setting applies once it is rebuilt."
|
||||
fi
|
||||
for u in $NVIDIA_SLEEP_UNITS; do
|
||||
systemctl is-enabled -q "$u" 2>/dev/null && continue
|
||||
sudo systemctl enable "$u" >/dev/null 2>&1 && units+="${units:+ }$u"
|
||||
done
|
||||
if [[ -n "$units" ]]; then
|
||||
prev="$(state_get nvidia enabled_units)"
|
||||
state_set nvidia enabled_units "${prev:+$prev }$units"
|
||||
fi
|
||||
for pkg in $NVIDIA_LIB32_PKGS; do pacman -Q "$pkg" >/dev/null 2>&1 || missing+=("$pkg"); done
|
||||
if [[ ${#missing[@]} -gt 0 ]]; then
|
||||
info "Installing the 32-bit libraries games need: ${missing[*]}"
|
||||
if sudo pacman -S --needed --noconfirm "${missing[@]}"; then
|
||||
prev="$(state_get nvidia installed_pkgs)"
|
||||
state_set nvidia installed_pkgs "${prev:+$prev }${missing[*]}"
|
||||
else
|
||||
warn "Installing ${missing[*]} failed (is [multilib] enabled in /etc/pacman.conf?): 32-bit games may not start."
|
||||
fi
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
nvidia_extras_disable() {
|
||||
# Only what Steamify enabled; the 32-bit packages go with installed_pkgs.
|
||||
local u
|
||||
for u in $(state_get nvidia enabled_units); do sudo systemctl disable "$u" >/dev/null 2>&1; done
|
||||
if [[ -f "$NVIDIA_MODPROBE" ]]; then
|
||||
sudo rm -f "$NVIDIA_MODPROBE"
|
||||
nvidia_rebuild_boot || true
|
||||
fi
|
||||
}
|
||||
|
||||
nvidia_kernel_disable() {
|
||||
local f changed=0; f="$(nvidia_boot_file)"
|
||||
if [[ -n "$f" ]] && grep -q "$NVIDIA_PARAMS" "$f" 2>/dev/null; then
|
||||
|
||||
@@ -58,6 +58,30 @@ bootstrap_yay() {
|
||||
fi
|
||||
}
|
||||
|
||||
python_hid_shim_ensure() {
|
||||
# jupiter-hw-support (a dependency of gamescope-session-cachyos) wants python-hid, which conflicts with python-hidapi, and
|
||||
# a PC can need python-hidapi (liquidctl does). Only Valve's Steam Deck controller firmware updater uses python-hid, which
|
||||
# a PC doesn't run: so a placeholder package that provides python-hid keeps python-hidapi and satisfies the dependency
|
||||
# (also at later updates, which a one-time --assume-installed wouldn't). It stays when the conversion goes off:
|
||||
# jupiter-hw-support, which stays, depends on it.
|
||||
pacman -Q python-hidapi >/dev/null 2>&1 || return 0
|
||||
pacman -Q python-hid steamify-python-hid-shim >/dev/null 2>&1 && return 0
|
||||
local dir pkg cache="${XDG_CACHE_HOME:-$HOME/.cache}/steamify"
|
||||
warn "python-hidapi is installed (liquidctl and others need it) and conflicts with python-hid, which Steam Deck's tools ask for: keeping python-hidapi, with a small placeholder package for python-hid."
|
||||
sudo pacman -S --needed --noconfirm base-devel >/dev/null || { err "Installing the build tools failed."; return 1; }
|
||||
mkdir -p "$cache" && dir="$(mktemp -d -p "$cache" hid-shim.XXXXXX)" || return 1
|
||||
patch_file python-hid-shim.PKGBUILD > "$dir/PKGBUILD" || { rm -rf "$dir"; return 1; }
|
||||
if ! (cd "$dir" && makepkg -f --noconfirm >/dev/null) ||
|
||||
! pkg="$(ls "$dir"/steamify-python-hid-shim-*.pkg.tar.* 2>/dev/null | head -1)" ||
|
||||
! sudo pacman -U --noconfirm "$pkg"; then
|
||||
rm -rf "$dir"
|
||||
err "Couldn't set up the python-hid placeholder: python-hidapi and python-hid conflict, so the packages can't be installed."
|
||||
return 1
|
||||
fi
|
||||
rm -rf "$dir"
|
||||
ok "python-hidapi kept; python-hid is covered by a placeholder."
|
||||
}
|
||||
|
||||
install_required_packages() {
|
||||
# Step 2: gamescope/Steam and the desktop helpers the rest of the setup uses.
|
||||
local -a MISSING
|
||||
@@ -65,6 +89,7 @@ install_required_packages() {
|
||||
mapfile -t MISSING < <(pacman -T gamescope-session-cachyos steam mangohud xterm ttf-liberation wqy-zenhei plasma-keyboard)
|
||||
|
||||
if [[ ${#MISSING[@]} -gt 0 ]]; then
|
||||
python_hid_shim_ensure || return 1
|
||||
info "Installing missing packages: ${MISSING[*]}"
|
||||
sudo pacman -S --needed --noconfirm "${MISSING[@]}" || { err "Package installation failed."; return 1; }
|
||||
else
|
||||
|
||||
@@ -140,6 +140,15 @@ EOF
|
||||
remove_sddm_base_autologin
|
||||
}
|
||||
|
||||
single_login_release() {
|
||||
# The SteamOS conversion logs in by itself, and picks the session (gamescope, or the desktop with "Boot into"): the
|
||||
# desktop autologin above, which sorts last, would pin the Plasma session and "Return to Gaming Mode" would open KDE
|
||||
# again. Called when the conversion is turned on; turning it off sets it up again (gaming_disable).
|
||||
[[ -f "$SINGLE_AUTOLOGIN" ]] || return 0
|
||||
info "The SteamOS conversion logs in by itself: removing the desktop autologin of single user mode."
|
||||
sudo rm -f "$SINGLE_AUTOLOGIN"
|
||||
}
|
||||
|
||||
single_login_disable() {
|
||||
[[ -f "$SINGLE_AUTOLOGIN" ]] || return 0
|
||||
sudo rm -f "$SINGLE_AUTOLOGIN"
|
||||
|
||||
@@ -16,3 +16,7 @@ read and reviewed on their own. `lib/*.sh` reads them with `patch_file
|
||||
| `steamify-os-release.sh`, `steamify-os-release.hook` | `lib/login-manager.sh` (SteamOS conversion) | What Steam's System settings show besides the OS name (which stays CachyOS's): `VERSION_ID=steamos-X.Y`, `VERSION_CODENAME=steam-machine`, `VARIANT`/`VARIANT_ID` Steamify with its version, in `/etc/os-release`; the pacman hook runs it again after cachyos-hooks (`fill SCRIPT=... VERSION=... STEAMOS=...`) |
|
||||
| `steamify-nvidia-initramfs.sh`, `steamify-nvidia-initramfs.hook` | `lib/nvidia.sh` (SteamOS conversion, NVIDIA fix) | The pacman hook (before the initramfs is built, after DKMS) and its script: the NVIDIA modules go into the initramfs only while every installed kernel has them, decided again at every kernel or driver change (`fill SCRIPT=...`) |
|
||||
| `cros-ec-cec-single-port.patch` | `lib/cec.sh` (HDMI-CEC) | Makes Valve's Steam Machine CEC driver find amdgpu's HDMI port |
|
||||
| `gamescope-gbm-scanout.patch` | `lib/gamescope-nvidia.sh` (gamescope on NVIDIA) | gamescope 3.16.31 patch: scan-out buffers allocated with GBM (opt-in, `gamescope_drm_gbm_scanout=1`), which cures the corrupted picture on NVIDIA; from farnoy/gamescope, see the header of the file |
|
||||
| `gamescope-nvidia.PKGBUILD` | `lib/gamescope-nvidia.sh` (gamescope on NVIDIA) | The recipe for the patched gamescope package (`steamify-gamescope-nvidia`, provides and conflicts with `gamescope`): Valve's gamescope at `pkgver` plus `gamescope-gbm-scanout.patch`; written with the patch to a temporary folder and built with `makepkg` |
|
||||
| `cros-ec-cec.c` | `lib/cec.sh` (HDMI-CEC) | Valve's Steam Machine CEC driver (GPL-2.0+, from evlaV/linux-integration at the pinned commit): the backup when downloading it from GitHub fails; used only if its sha256 equals `CEC_DRIVER_SHA256` (a new pin needs a new copy) |
|
||||
| `python-hid-shim.PKGBUILD` | `lib/packages.sh` (required packages) | An empty package that provides `python-hid`, for PCs that keep `python-hidapi` (they conflict; jupiter-hw-support, a dependency of gamescope-session-cachyos, wants python-hid, only the Steam Deck controller updater uses it): built with `makepkg` and installed before the conversion's packages |
|
||||
@@ -0,0 +1,621 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* CEC driver for ChromeOS Embedded Controller
|
||||
*
|
||||
* Copyright (c) 2018 BayLibre, SAS
|
||||
* Author: Neil Armstrong <narmstrong@baylibre.com>
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/dmi.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/cec.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/platform_data/cros_ec_commands.h>
|
||||
#include <linux/platform_data/cros_ec_proto.h>
|
||||
#include <media/cec.h>
|
||||
#include <media/cec-notifier.h>
|
||||
|
||||
#define DRV_NAME "cros-ec-cec"
|
||||
|
||||
/**
|
||||
* struct cros_ec_cec_port - Driver data for a single EC CEC port
|
||||
*
|
||||
* @port_num: port number
|
||||
* @adap: CEC adapter
|
||||
* @notify: CEC notifier pointer
|
||||
* @rx_msg: storage for a received message
|
||||
* @cros_ec_cec: pointer to the parent struct
|
||||
*/
|
||||
struct cros_ec_cec_port {
|
||||
int port_num;
|
||||
struct cec_adapter *adap;
|
||||
struct cec_notifier *notify;
|
||||
struct cec_msg rx_msg;
|
||||
struct cros_ec_cec *cros_ec_cec;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct cros_ec_cec - Driver data for EC CEC
|
||||
*
|
||||
* @cros_ec: Pointer to EC device
|
||||
* @notifier: Notifier info for responding to EC events
|
||||
* @write_cmd_version: Highest supported version of EC_CMD_CEC_WRITE_MSG.
|
||||
* @num_ports: Number of CEC ports
|
||||
* @ports: Array of ports
|
||||
*/
|
||||
struct cros_ec_cec {
|
||||
struct cros_ec_device *cros_ec;
|
||||
struct notifier_block notifier;
|
||||
int write_cmd_version;
|
||||
int num_ports;
|
||||
struct cros_ec_cec_port *ports[EC_CEC_MAX_PORTS];
|
||||
};
|
||||
|
||||
static void cros_ec_cec_received_message(struct cros_ec_cec_port *port,
|
||||
uint8_t *msg, uint8_t len)
|
||||
{
|
||||
if (len > CEC_MAX_MSG_SIZE)
|
||||
len = CEC_MAX_MSG_SIZE;
|
||||
|
||||
port->rx_msg.len = len;
|
||||
memcpy(port->rx_msg.msg, msg, len);
|
||||
|
||||
cec_received_msg(port->adap, &port->rx_msg);
|
||||
}
|
||||
|
||||
static void handle_cec_message(struct cros_ec_cec *cros_ec_cec)
|
||||
{
|
||||
struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec;
|
||||
uint8_t *cec_message = cros_ec->event_data.data.cec_message;
|
||||
unsigned int len = cros_ec->event_size;
|
||||
struct cros_ec_cec_port *port;
|
||||
/*
|
||||
* There are two ways of receiving CEC messages:
|
||||
* 1. Old EC firmware which only supports one port sends the data in a
|
||||
* cec_message MKBP event.
|
||||
* 2. New EC firmware which supports multiple ports uses
|
||||
* EC_MKBP_CEC_HAVE_DATA to notify that data is ready and
|
||||
* EC_CMD_CEC_READ_MSG to read it.
|
||||
* Check that the EC only has one CEC port, and then we can assume the
|
||||
* message is from port 0.
|
||||
*/
|
||||
if (cros_ec_cec->num_ports != 1) {
|
||||
dev_err(cros_ec->dev,
|
||||
"received cec_message on device with %d ports\n",
|
||||
cros_ec_cec->num_ports);
|
||||
return;
|
||||
}
|
||||
port = cros_ec_cec->ports[0];
|
||||
|
||||
cros_ec_cec_received_message(port, cec_message, len);
|
||||
}
|
||||
|
||||
static void cros_ec_cec_read_message(struct cros_ec_cec_port *port)
|
||||
{
|
||||
struct cros_ec_device *cros_ec = port->cros_ec_cec->cros_ec;
|
||||
struct ec_params_cec_read params = {
|
||||
.port = port->port_num,
|
||||
};
|
||||
struct ec_response_cec_read response;
|
||||
int ret = 0;
|
||||
int count = 0;
|
||||
|
||||
/* NOTE read as many messages as we can, return value from cros_ec_cmd
|
||||
* here should either equal to the bytes transferred or a negative
|
||||
* error code, so as long as we get positive integers we are
|
||||
* reading messages!
|
||||
*/
|
||||
do {
|
||||
ret = cros_ec_cmd(cros_ec, 0, EC_CMD_CEC_READ_MSG, ¶ms,
|
||||
sizeof(params), &response, sizeof(response));
|
||||
if (ret > 0) {
|
||||
++count;
|
||||
cros_ec_cec_received_message(port, response.msg, response.msg_len);
|
||||
}
|
||||
}
|
||||
while (ret > 0);
|
||||
|
||||
if (ret < 0 && count == 0) {
|
||||
dev_err(cros_ec->dev,
|
||||
"error reading CEC message on EC: %d\n", ret);
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_cec_event(struct cros_ec_cec *cros_ec_cec)
|
||||
{
|
||||
struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec;
|
||||
uint32_t cec_events = cros_ec->event_data.data.cec_events;
|
||||
uint32_t port_num = EC_MKBP_EVENT_CEC_GET_PORT(cec_events);
|
||||
uint32_t events = EC_MKBP_EVENT_CEC_GET_EVENTS(cec_events);
|
||||
struct cros_ec_cec_port *port;
|
||||
|
||||
if (port_num >= cros_ec_cec->num_ports) {
|
||||
dev_err(cros_ec->dev,
|
||||
"received CEC event for invalid port %d\n", port_num);
|
||||
return;
|
||||
}
|
||||
port = cros_ec_cec->ports[port_num];
|
||||
|
||||
if (events & EC_MKBP_CEC_SEND_OK)
|
||||
cec_transmit_attempt_done(port->adap, CEC_TX_STATUS_OK);
|
||||
|
||||
/* FW takes care of all retries, tell core to avoid more retries */
|
||||
if (events & EC_MKBP_CEC_SEND_FAILED)
|
||||
cec_transmit_attempt_done(port->adap,
|
||||
CEC_TX_STATUS_MAX_RETRIES |
|
||||
CEC_TX_STATUS_NACK);
|
||||
|
||||
if (events & EC_MKBP_CEC_HAVE_DATA)
|
||||
cros_ec_cec_read_message(port);
|
||||
}
|
||||
|
||||
static int cros_ec_cec_event(struct notifier_block *nb,
|
||||
unsigned long queued_during_suspend,
|
||||
void *_notify)
|
||||
{
|
||||
struct cros_ec_cec *cros_ec_cec;
|
||||
struct cros_ec_device *cros_ec;
|
||||
|
||||
cros_ec_cec = container_of(nb, struct cros_ec_cec, notifier);
|
||||
cros_ec = cros_ec_cec->cros_ec;
|
||||
|
||||
if (cros_ec->event_data.event_type == EC_MKBP_EVENT_CEC_EVENT) {
|
||||
handle_cec_event(cros_ec_cec);
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
if (cros_ec->event_data.event_type == EC_MKBP_EVENT_CEC_MESSAGE) {
|
||||
handle_cec_message(cros_ec_cec);
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
static int cros_ec_cec_set_log_addr(struct cec_adapter *adap, u8 logical_addr)
|
||||
{
|
||||
struct cros_ec_cec_port *port = adap->priv;
|
||||
struct cros_ec_cec *cros_ec_cec = port->cros_ec_cec;
|
||||
struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec;
|
||||
struct ec_params_cec_set params = {
|
||||
.cmd = CEC_CMD_LOGICAL_ADDRESS,
|
||||
.port = port->port_num,
|
||||
.val = logical_addr,
|
||||
};
|
||||
int ret;
|
||||
|
||||
ret = cros_ec_cmd(cros_ec, 0, EC_CMD_CEC_SET, ¶ms, sizeof(params),
|
||||
NULL, 0);
|
||||
if (ret < 0) {
|
||||
dev_err(cros_ec->dev,
|
||||
"error setting CEC logical address on EC: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cros_ec_cec_transmit(struct cec_adapter *adap, u8 attempts,
|
||||
u32 signal_free_time, struct cec_msg *cec_msg)
|
||||
{
|
||||
struct cros_ec_cec_port *port = adap->priv;
|
||||
struct cros_ec_cec *cros_ec_cec = port->cros_ec_cec;
|
||||
struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec;
|
||||
struct ec_params_cec_write params;
|
||||
struct ec_params_cec_write_v1 params_v1;
|
||||
int ret;
|
||||
|
||||
if (cros_ec_cec->write_cmd_version == 0) {
|
||||
memcpy(params.msg, cec_msg->msg, cec_msg->len);
|
||||
ret = cros_ec_cmd(cros_ec, 0, EC_CMD_CEC_WRITE_MSG, ¶ms,
|
||||
cec_msg->len, NULL, 0);
|
||||
} else {
|
||||
params_v1.port = port->port_num;
|
||||
params_v1.msg_len = cec_msg->len;
|
||||
memcpy(params_v1.msg, cec_msg->msg, cec_msg->len);
|
||||
ret = cros_ec_cmd(cros_ec, cros_ec_cec->write_cmd_version,
|
||||
EC_CMD_CEC_WRITE_MSG, ¶ms_v1,
|
||||
sizeof(params_v1), NULL, 0);
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
dev_err(cros_ec->dev,
|
||||
"error writing CEC msg on EC: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cros_ec_cec_adap_enable(struct cec_adapter *adap, bool enable)
|
||||
{
|
||||
struct cros_ec_cec_port *port = adap->priv;
|
||||
struct cros_ec_cec *cros_ec_cec = port->cros_ec_cec;
|
||||
struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec;
|
||||
struct ec_params_cec_set params = {
|
||||
.cmd = CEC_CMD_ENABLE,
|
||||
.port = port->port_num,
|
||||
.val = enable,
|
||||
};
|
||||
int ret;
|
||||
|
||||
ret = cros_ec_cmd(cros_ec, 0, EC_CMD_CEC_SET, ¶ms, sizeof(params),
|
||||
NULL, 0);
|
||||
if (ret < 0) {
|
||||
dev_err(cros_ec->dev,
|
||||
"error %sabling CEC on EC: %d\n",
|
||||
(enable ? "en" : "dis"), ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct cec_adap_ops cros_ec_cec_ops = {
|
||||
.adap_enable = cros_ec_cec_adap_enable,
|
||||
.adap_log_addr = cros_ec_cec_set_log_addr,
|
||||
.adap_transmit = cros_ec_cec_transmit,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int cros_ec_cec_suspend(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct cros_ec_cec *cros_ec_cec = dev_get_drvdata(&pdev->dev);
|
||||
|
||||
if (device_may_wakeup(dev))
|
||||
enable_irq_wake(cros_ec_cec->cros_ec->irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cros_ec_cec_resume(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct cros_ec_cec *cros_ec_cec = dev_get_drvdata(&pdev->dev);
|
||||
|
||||
if (device_may_wakeup(dev))
|
||||
disable_irq_wake(cros_ec_cec->cros_ec->irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(cros_ec_cec_pm_ops,
|
||||
cros_ec_cec_suspend, cros_ec_cec_resume);
|
||||
|
||||
#if IS_ENABLED(CONFIG_PCI) && IS_ENABLED(CONFIG_DMI)
|
||||
|
||||
/*
|
||||
* Specify the DRM device name handling the HDMI output and the HDMI connector
|
||||
* corresponding to each CEC port. The order of connectors must match the order
|
||||
* in the EC (first connector is EC port 0, ...), and the number of connectors
|
||||
* must match the number of ports in the EC (which can be queried using the
|
||||
* EC_CMD_CEC_PORT_COUNT host command).
|
||||
*/
|
||||
|
||||
struct cec_dmi_match {
|
||||
const char *sys_vendor;
|
||||
const char *product_name;
|
||||
const char *devname;
|
||||
const char *const *conns;
|
||||
};
|
||||
|
||||
static const char *const port_b_conns[] = { "Port B", NULL };
|
||||
static const char *const port_c_conns[] = { "Port C", NULL };
|
||||
static const char *const port_db_conns[] = { "Port D", "Port B", NULL };
|
||||
static const char *const port_ba_conns[] = { "Port B", "Port A", NULL };
|
||||
static const char *const port_ab_conns[] = { "Port A", "Port B", NULL };
|
||||
static const char *const port_d_conns[] = { "Port D", NULL };
|
||||
|
||||
static const struct cec_dmi_match cec_dmi_match_table[] = {
|
||||
/* AMD Lilac */
|
||||
{ "AMD", "Lilac", "0000:03:00.0", port_c_conns },
|
||||
/* Valve Fremont */
|
||||
{ "OEM", "F7F", "0000:03:00.0", port_c_conns },
|
||||
{ "Valve", "Fremont", "0000:03:00.0", port_c_conns },
|
||||
/* Google Fizz */
|
||||
{ "Google", "Fizz", "0000:00:02.0", port_b_conns },
|
||||
/* Google Brask */
|
||||
{ "Google", "Brask", "0000:00:02.0", port_b_conns },
|
||||
/* Google Moli */
|
||||
{ "Google", "Moli", "0000:00:02.0", port_b_conns },
|
||||
/* Google Kinox */
|
||||
{ "Google", "Kinox", "0000:00:02.0", port_b_conns },
|
||||
/* Google Kuldax */
|
||||
{ "Google", "Kuldax", "0000:00:02.0", port_b_conns },
|
||||
/* Google Aurash */
|
||||
{ "Google", "Aurash", "0000:00:02.0", port_b_conns },
|
||||
/* Google Gladios */
|
||||
{ "Google", "Gladios", "0000:00:02.0", port_b_conns },
|
||||
/* Google Lisbon */
|
||||
{ "Google", "Lisbon", "0000:00:02.0", port_b_conns },
|
||||
/* Google Dibbi */
|
||||
{ "Google", "Dibbi", "0000:00:02.0", port_db_conns },
|
||||
/* Google Constitution */
|
||||
{ "Google", "Constitution", "0000:00:02.0", port_ba_conns },
|
||||
/* Google Boxy */
|
||||
{ "Google", "Boxy", "0000:00:02.0", port_d_conns },
|
||||
/* Google Taranza */
|
||||
{ "Google", "Taranza", "0000:00:02.0", port_db_conns },
|
||||
/* Google Dexi */
|
||||
{ "Google", "Dexi", "0000:00:02.0", port_db_conns },
|
||||
/* Google Dita */
|
||||
{ "Google", "Dita", "0000:00:02.0", port_db_conns },
|
||||
/* Google Dirks */
|
||||
{ "Google", "Dirks", "0000:00:02.0", port_ab_conns },
|
||||
/* Google Moxie */
|
||||
{ "Google", "Moxie", "0000:00:02.0", port_b_conns },
|
||||
/* AMD Lilac */
|
||||
{ "AMD", "Lilac", "0000:06:00.0", port_c_conns },
|
||||
};
|
||||
|
||||
static struct device *cros_ec_cec_find_hdmi_dev(struct device *dev,
|
||||
const char * const **conns)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0 ; i < ARRAY_SIZE(cec_dmi_match_table) ; ++i) {
|
||||
const struct cec_dmi_match *m = &cec_dmi_match_table[i];
|
||||
|
||||
if (dmi_match(DMI_SYS_VENDOR, m->sys_vendor) &&
|
||||
dmi_match(DMI_PRODUCT_NAME, m->product_name)) {
|
||||
struct device *d;
|
||||
|
||||
/* Find the device, bail out if not yet registered */
|
||||
d = bus_find_device_by_name(&pci_bus_type, NULL,
|
||||
m->devname);
|
||||
if (!d)
|
||||
return ERR_PTR(-EPROBE_DEFER);
|
||||
put_device(d);
|
||||
*conns = m->conns;
|
||||
return d;
|
||||
}
|
||||
}
|
||||
|
||||
/* Hardware support must be added in the cec_dmi_match_table */
|
||||
dev_warn(dev, "CEC notifier not configured for this hardware\n");
|
||||
|
||||
return ERR_PTR(-ENODEV);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static struct device *cros_ec_cec_find_hdmi_dev(struct device *dev,
|
||||
const char * const **conns)
|
||||
{
|
||||
return ERR_PTR(-ENODEV);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static int cros_ec_cec_get_num_ports(struct cros_ec_cec *cros_ec_cec)
|
||||
{
|
||||
struct ec_response_cec_port_count response;
|
||||
int ret;
|
||||
|
||||
ret = cros_ec_cmd(cros_ec_cec->cros_ec, 0, EC_CMD_CEC_PORT_COUNT, NULL,
|
||||
0, &response, sizeof(response));
|
||||
if (ret < 0) {
|
||||
/*
|
||||
* Old EC firmware only supports one port and does not support
|
||||
* the port count command, so fall back to assuming one port.
|
||||
*/
|
||||
cros_ec_cec->num_ports = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (response.port_count == 0) {
|
||||
dev_err(cros_ec_cec->cros_ec->dev,
|
||||
"EC reports 0 CEC ports\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (response.port_count > EC_CEC_MAX_PORTS) {
|
||||
dev_err(cros_ec_cec->cros_ec->dev,
|
||||
"EC reports too many ports: %d\n", response.port_count);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
cros_ec_cec->num_ports = response.port_count;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cros_ec_cec_get_write_cmd_version(struct cros_ec_cec *cros_ec_cec)
|
||||
{
|
||||
struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec;
|
||||
struct ec_params_get_cmd_versions_v1 params = {
|
||||
.cmd = EC_CMD_CEC_WRITE_MSG,
|
||||
};
|
||||
struct ec_response_get_cmd_versions response;
|
||||
int ret;
|
||||
|
||||
ret = cros_ec_cmd(cros_ec, 1, EC_CMD_GET_CMD_VERSIONS, ¶ms,
|
||||
sizeof(params), &response, sizeof(response));
|
||||
if (ret < 0) {
|
||||
dev_err(cros_ec->dev,
|
||||
"error getting CEC write command version: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (response.version_mask & EC_VER_MASK(1)) {
|
||||
cros_ec_cec->write_cmd_version = 1;
|
||||
} else {
|
||||
if (cros_ec_cec->num_ports != 1) {
|
||||
dev_err(cros_ec->dev,
|
||||
"v0 write command only supports 1 port, %d reported\n",
|
||||
cros_ec_cec->num_ports);
|
||||
return -EINVAL;
|
||||
}
|
||||
cros_ec_cec->write_cmd_version = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cros_ec_cec_init_port(struct device *dev,
|
||||
struct cros_ec_cec *cros_ec_cec,
|
||||
int port_num, struct device *hdmi_dev,
|
||||
const char * const *conns)
|
||||
{
|
||||
struct cros_ec_cec_port *port;
|
||||
int ret;
|
||||
|
||||
port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL);
|
||||
if (!port)
|
||||
return -ENOMEM;
|
||||
|
||||
port->cros_ec_cec = cros_ec_cec;
|
||||
port->port_num = port_num;
|
||||
|
||||
port->adap = cec_allocate_adapter(&cros_ec_cec_ops, port, DRV_NAME,
|
||||
CEC_CAP_DEFAULTS |
|
||||
CEC_CAP_CONNECTOR_INFO, 1);
|
||||
if (IS_ERR(port->adap))
|
||||
return PTR_ERR(port->adap);
|
||||
|
||||
if (!conns[port_num]) {
|
||||
dev_err(dev, "no conn for port %d\n", port_num);
|
||||
ret = -ENODEV;
|
||||
goto out_probe_adapter;
|
||||
}
|
||||
|
||||
port->notify = cec_notifier_cec_adap_register(hdmi_dev, conns[port_num],
|
||||
port->adap);
|
||||
if (!port->notify) {
|
||||
ret = -ENOMEM;
|
||||
goto out_probe_adapter;
|
||||
}
|
||||
|
||||
ret = cec_register_adapter(port->adap, dev);
|
||||
if (ret < 0)
|
||||
goto out_probe_notify;
|
||||
|
||||
cros_ec_cec->ports[port_num] = port;
|
||||
|
||||
return 0;
|
||||
|
||||
out_probe_notify:
|
||||
cec_notifier_cec_adap_unregister(port->notify, port->adap);
|
||||
out_probe_adapter:
|
||||
cec_delete_adapter(port->adap);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cros_ec_cec_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct cros_ec_dev *ec_dev = dev_get_drvdata(pdev->dev.parent);
|
||||
struct cros_ec_device *cros_ec = ec_dev->ec_dev;
|
||||
struct cros_ec_cec *cros_ec_cec;
|
||||
struct cros_ec_cec_port *port;
|
||||
struct device *hdmi_dev;
|
||||
const char * const *conns = NULL;
|
||||
int ret;
|
||||
|
||||
hdmi_dev = cros_ec_cec_find_hdmi_dev(&pdev->dev, &conns);
|
||||
if (IS_ERR(hdmi_dev))
|
||||
return PTR_ERR(hdmi_dev);
|
||||
|
||||
cros_ec_cec = devm_kzalloc(&pdev->dev, sizeof(*cros_ec_cec),
|
||||
GFP_KERNEL);
|
||||
if (!cros_ec_cec)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(pdev, cros_ec_cec);
|
||||
cros_ec_cec->cros_ec = cros_ec;
|
||||
|
||||
device_init_wakeup(&pdev->dev, 1);
|
||||
|
||||
ret = cros_ec_cec_get_num_ports(cros_ec_cec);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = cros_ec_cec_get_write_cmd_version(cros_ec_cec);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
for (int i = 0; i < cros_ec_cec->num_ports; i++) {
|
||||
ret = cros_ec_cec_init_port(&pdev->dev, cros_ec_cec, i,
|
||||
hdmi_dev, conns);
|
||||
if (ret)
|
||||
goto unregister_ports;
|
||||
}
|
||||
|
||||
/* Get CEC events from the EC. */
|
||||
cros_ec_cec->notifier.notifier_call = cros_ec_cec_event;
|
||||
ret = blocking_notifier_chain_register(&cros_ec->event_notifier,
|
||||
&cros_ec_cec->notifier);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to register notifier\n");
|
||||
goto unregister_ports;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
unregister_ports:
|
||||
/*
|
||||
* Unregister any adapters which have been registered. We don't add the
|
||||
* port to the array until the adapter has been registered successfully,
|
||||
* so any non-NULL ports must have been registered.
|
||||
*/
|
||||
for (int i = 0; i < cros_ec_cec->num_ports; i++) {
|
||||
port = cros_ec_cec->ports[i];
|
||||
if (!port)
|
||||
break;
|
||||
cec_notifier_cec_adap_unregister(port->notify, port->adap);
|
||||
cec_unregister_adapter(port->adap);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void cros_ec_cec_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct cros_ec_cec *cros_ec_cec = platform_get_drvdata(pdev);
|
||||
struct device *dev = &pdev->dev;
|
||||
struct cros_ec_cec_port *port;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* blocking_notifier_chain_unregister() only fails if the notifier isn't
|
||||
* in the list. We know it was added to it by .probe(), so there should
|
||||
* be no need for error checking. Be cautious and still check.
|
||||
*/
|
||||
ret = blocking_notifier_chain_unregister(
|
||||
&cros_ec_cec->cros_ec->event_notifier,
|
||||
&cros_ec_cec->notifier);
|
||||
if (ret)
|
||||
dev_err(dev, "failed to unregister notifier\n");
|
||||
|
||||
for (int i = 0; i < cros_ec_cec->num_ports; i++) {
|
||||
port = cros_ec_cec->ports[i];
|
||||
cec_notifier_cec_adap_unregister(port->notify, port->adap);
|
||||
cec_unregister_adapter(port->adap);
|
||||
}
|
||||
}
|
||||
|
||||
static const struct platform_device_id cros_ec_cec_id[] = {
|
||||
{ DRV_NAME, 0 },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, cros_ec_cec_id);
|
||||
|
||||
static struct platform_driver cros_ec_cec_driver = {
|
||||
.probe = cros_ec_cec_probe,
|
||||
.remove = cros_ec_cec_remove,
|
||||
.driver = {
|
||||
.name = DRV_NAME,
|
||||
.pm = &cros_ec_cec_pm_ops,
|
||||
},
|
||||
.id_table = cros_ec_cec_id,
|
||||
};
|
||||
|
||||
module_platform_driver(cros_ec_cec_driver);
|
||||
|
||||
MODULE_DESCRIPTION("CEC driver for ChromeOS ECs");
|
||||
MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
|
||||
MODULE_LICENSE("GPL");
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,124 @@
|
||||
# Maintainer: theupriser
|
||||
# Based on Arch Linux's gamescope PKGBUILD (Maxime Gauduin, Giancarlo Razzolini, Sven-Hendrik Haase and contributors).
|
||||
#
|
||||
# gamescope with GBM-allocated scan-out buffers for NVIDIA (opt-in: gamescope_drm_gbm_scanout=1).
|
||||
# The patch is gamescope-gbm-scanout.patch (next to this file; see its header for where it comes from). pkgver is the gamescope
|
||||
# release the patch was made for and tested with. Kept in sync with https://github.com/theupriser/steamify-gamescope-nvidia;
|
||||
# Steamify (lib/gamescope-nvidia.sh) writes both files into a temporary folder and runs makepkg there.
|
||||
|
||||
pkgname=steamify-gamescope-nvidia
|
||||
_srcname=gamescope
|
||||
pkgver=3.16.31
|
||||
pkgrel=1
|
||||
pkgdesc='SteamOS session compositing window manager, with GBM scan-out for NVIDIA (opt-in: gamescope_drm_gbm_scanout=1)'
|
||||
arch=(x86_64)
|
||||
url=https://github.com/theupriser/steamify-gamescope-nvidia
|
||||
license=(
|
||||
BSD-2-Clause
|
||||
BSD-3-Clause
|
||||
LicenseRef-Reshade
|
||||
)
|
||||
provides=("gamescope=$pkgver")
|
||||
conflicts=(gamescope gamescope-nvidia-gbm)
|
||||
replaces=(gamescope-nvidia-gbm)
|
||||
depends=(
|
||||
glibc
|
||||
mesa
|
||||
libstdc++
|
||||
libgcc
|
||||
lcms2
|
||||
libavif
|
||||
libcap.so
|
||||
libdecor
|
||||
libdrm
|
||||
libei
|
||||
libinput
|
||||
libpipewire-0.3.so
|
||||
libx11
|
||||
libxcb
|
||||
libxcomposite
|
||||
libxcursor
|
||||
libxdamage
|
||||
libxext
|
||||
libxfixes
|
||||
libxi
|
||||
libxkbcommon.so
|
||||
libxmu
|
||||
libxrender
|
||||
libxres
|
||||
libxtst
|
||||
libxxf86vm
|
||||
luajit
|
||||
pixman
|
||||
sdl2
|
||||
seatd
|
||||
systemd-libs
|
||||
vulkan-icd-loader
|
||||
wayland
|
||||
xcb-util-errors
|
||||
xcb-util-wm
|
||||
xorg-server-xwayland
|
||||
)
|
||||
makedepends=(
|
||||
benchmark
|
||||
cmake
|
||||
git
|
||||
glslang
|
||||
meson
|
||||
ninja
|
||||
vulkan-headers
|
||||
wayland-protocols
|
||||
catch2
|
||||
)
|
||||
source=(
|
||||
gamescope::git+https://github.com/ValveSoftware/gamescope.git#commit=${pkgver}
|
||||
gamescope-gbm-scanout.patch
|
||||
git+https://gitlab.freedesktop.org/emersion/libdisplay-info.git
|
||||
git+https://gitlab.freedesktop.org/emersion/libliftoff.git
|
||||
git+https://github.com/ValveSoftware/openvr.git
|
||||
git+https://github.com/Joshua-Ashton/reshade.git
|
||||
git+https://github.com/KhronosGroup/SPIRV-Headers.git
|
||||
git+https://github.com/Joshua-Ashton/vkroots.git
|
||||
git+https://gitlab.freedesktop.org/wlroots/wlroots.git
|
||||
)
|
||||
b2sums=('SKIP'
|
||||
'SKIP'
|
||||
'SKIP'
|
||||
'SKIP'
|
||||
'SKIP'
|
||||
'SKIP'
|
||||
'SKIP'
|
||||
'SKIP'
|
||||
'SKIP')
|
||||
|
||||
prepare() {
|
||||
cd gamescope
|
||||
|
||||
# GBM scan-out for NVIDIA. If it no longer applies to this gamescope version, stop here: the build must not
|
||||
# silently produce an unpatched gamescope under this package's name.
|
||||
git apply --check ../gamescope-gbm-scanout.patch || { echo "gbm patch does not apply to gamescope ${pkgver}" >&2; return 1; }
|
||||
git apply ../gamescope-gbm-scanout.patch
|
||||
|
||||
meson subprojects download
|
||||
|
||||
for submodule in src/reshade subprojects/{libdisplay-info,libliftoff,openvr,vkroots,wlroots} thirdparty/SPIRV-Headers; do
|
||||
git submodule init ${submodule}
|
||||
git config submodule.${submodule}.url ../${submodule##*/}
|
||||
done
|
||||
git -c protocol.file.allow=always submodule update
|
||||
}
|
||||
|
||||
build() {
|
||||
arch-meson gamescope build \
|
||||
-Dforce_fallback_for=glm,stb,libdisplay-info,libliftoff,vkroots \
|
||||
-Dpipewire=enabled
|
||||
meson compile -C build
|
||||
}
|
||||
|
||||
package() {
|
||||
DESTDIR="${pkgdir}" meson install -C build \
|
||||
--skip-subprojects
|
||||
install -Dm 644 gamescope/LICENSE -t "${pkgdir}"/usr/share/licenses/${pkgname}/
|
||||
}
|
||||
|
||||
# vim: ts=2 sw=2 et:
|
||||
@@ -0,0 +1,17 @@
|
||||
# Maintainer: theupriser
|
||||
# An empty package that only tells pacman "python-hid is there". For a PC that keeps python-hidapi (liquidctl needs it):
|
||||
# the real python-hid conflicts with it, and jupiter-hw-support (a dependency of gamescope-session-cachyos) wants python-hid.
|
||||
# Only Valve's Steam Deck controller firmware updater in jupiter-hw-support uses it, which a PC doesn't run.
|
||||
# Steamify (lib/packages.sh) builds it with makepkg and installs it before the conversion's packages.
|
||||
pkgname=steamify-python-hid-shim
|
||||
pkgver=1
|
||||
pkgrel=1
|
||||
pkgdesc='Placeholder: python-hid for PCs that keep python-hidapi (they conflict)'
|
||||
arch=(any)
|
||||
license=(MIT)
|
||||
depends=(python-hidapi)
|
||||
provides=('python-hid=99')
|
||||
|
||||
package() {
|
||||
:
|
||||
}
|
||||
@@ -7,6 +7,11 @@
|
||||
* leaves set on GPIO pin 18 (_SB.PCI0.GPP6) stays set, and the machine starts again right after powering off.
|
||||
* Valve's kernel clears that bit at probe on Fremont (not for upstream);
|
||||
* this does the same right before power-off, for kernels without it.
|
||||
*
|
||||
* What it does follows Valve's Steam Machine kernel
|
||||
* (https://github.com/evlaV/linux-integration, GPL-2.0 like the rest of the
|
||||
* Linux kernel); this module is Steamify's own implementation of it, also
|
||||
* GPL-2.0. Not affiliated with or endorsed by Valve Corporation.
|
||||
*/
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/bits.h>
|
||||
|
||||
+2
-2
@@ -15,11 +15,11 @@
|
||||
set -uo pipefail
|
||||
|
||||
# Release version, see CHANGELOG.md.
|
||||
VERSION=2.11.1
|
||||
VERSION=2.11.2
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
for lib in common state packages login-manager single-user steam-desktop steam-machine fremont-poweroff vram-booster hdmi-refresh nvidia controllers cec boot-session vapor-theme steamos-extras bios desktop-shortcut wizard-shortcut steam-game update-notifier first-login menu backend; do
|
||||
for lib in common state packages login-manager single-user steam-desktop steam-machine fremont-poweroff vram-booster hdmi-refresh nvidia gamescope-nvidia controllers cec boot-session vapor-theme steamos-extras bios desktop-shortcut wizard-shortcut steam-game update-notifier first-login menu backend; do
|
||||
# shellcheck source=/dev/null
|
||||
source "$SCRIPT_DIR/lib/$lib.sh"
|
||||
done
|
||||
|
||||
+4
-2
@@ -65,7 +65,8 @@ Item {
|
||||
var w = {};
|
||||
for (var i = 0; i < items.length; i++) w[items[i].id] = items[i].kind === "action" ? false : items[i].wanted;
|
||||
want = w;
|
||||
boot = nowOn("boot") ? "desktop" : "gamescope";
|
||||
// (What the PC has, or what the backend ticked: "Gaming on NVIDIA" moving to the conversion keeps how Steam started.)
|
||||
boot = want.boot ? "desktop" : "gamescope";
|
||||
if (sel > rows.length) sel = 0;
|
||||
}
|
||||
Connections { target: backend; function onStatusChanged() { if (app.screen === "menu" || app.screen === "done") app.syncFromStatus(); } }
|
||||
@@ -101,7 +102,8 @@ Item {
|
||||
if (it.kind !== "toggle") continue;
|
||||
if (hidden(it)) { if (it.on) p.push({ id: it.id, action: "off" }); continue; }
|
||||
if (it.parent && !want[it.parent]) { if (it.on) p.push({ id: it.id, action: "off" }); continue; }
|
||||
if (want[it.id] && !it.on) p.push({ id: it.id, action: "on", isNew: !!it["new"] });
|
||||
// (An item that is off but flagged "update" replaces what the PC has: the conversion for "Gaming on NVIDIA".)
|
||||
if (want[it.id] && !it.on) p.push({ id: it.id, action: it.update ? "update" : "on", isNew: !!it["new"] });
|
||||
else if (!want[it.id] && it.on) p.push({ id: it.id, action: "off" });
|
||||
else if (want[it.id] && (reapply || it.update)) p.push({ id: it.id, action: reapply ? "again" : "update" });
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user