mirror of
https://github.com/theupriser/steamify-cachyos.git
synced 2026-10-13 20:35:40 +02:00
Compare commits
3
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9924617a2d | ||
|
|
5da1833a03 | ||
|
|
62cb75d161 |
No files matched your search
@@ -1,2 +0,0 @@
|
||||
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).
|
||||
@@ -48,15 +48,11 @@ gamescope and the Plasma desktop. Primary target: the Valve Steam Machine
|
||||
`<id>_available` is checked via `component_available` (e.g. `machine`
|
||||
only on Fremont). Turn-on order is `COMPONENTS` order, turn-off reverse;
|
||||
`gaming` must stay first. Dependencies live in `toggle_component`.
|
||||
- **NVIDIA** (`lib/gamescope-nvidia.sh`, `lib/nvidia.sh`): since 2.12.0 the SteamOS conversion (`gaming` and its options) runs on
|
||||
NVIDIA PCs with a patched gamescope (GBM scan-out: gamescope#2309; Steam's UI kept at the display's size), downloaded as the
|
||||
newest release of theupriser/steamify-gamescope-nvidia, with the pinned package (`GSN_VERSION`, `GSN_SHA256`), the copy the ISO
|
||||
leaves, and a build here (`patches/gamescope-nvidia.PKGBUILD` + the two patches) as the fallback. "Gaming on NVIDIA" (`nvidia`,
|
||||
`bigpicture`, `nvsilent`) isn't offered any more (`nvidia_available`); turning the conversion on turns it off (`nvidia_swap_out`).
|
||||
Builds exist per CPU level (`gsn_cpu_variant`: znver4, v4, v3, generic; `GSN_SHA256` is a map; the installed one must pass `gsn_smoke_test`, else generic). A new pin = the release's tag + each variant's sha256 (from `SHA256SUMS`) in `lib/gamescope-nvidia.sh` and the PKGBUILD's pkgver/pkgrel, copied from the
|
||||
repository (the patches in `patches/` must stay identical to that repository's). Steam must keep running with `-steamos3`
|
||||
(without it games don't launch in gaming mode and the settings pages go): never "fix" the UI size by dropping flags or by
|
||||
`XWAYLAND_COUNT`. Tested on an RTX 5080 only; keep the branch behind `.no-release-yet` until the whole flow ran on hardware.
|
||||
- **NVIDIA** (`lib/nvidia.sh`): gamescope's session is broken on NVIDIA, so the SteamOS conversion (`gaming`, `boot`, `single`,
|
||||
`glyphs`) is hidden there (unless already on) and `nvidia` + its sub-option `bigpicture` ("Gaming on NVIDIA") replace it:
|
||||
Steam on the Plasma desktop, started at login. Never reintroduce a gamescope session for NVIDIA without re-testing on the
|
||||
hardware (notes: steamify-cachyos-dev, `nvidia/`). It can't be tested without the hardware: keep the branch behind
|
||||
`.no-release-yet` until it was.
|
||||
- **Feature versions.** Set `FEATURE_VERSION[<id>]` (`lib/menu.sh`) to the new
|
||||
`VERSION` whenever what `<id>_enable` sets up changes (a new component gets
|
||||
one too): installs recorded with an older version
|
||||
@@ -160,8 +156,9 @@ gamescope and the Plasma desktop. Primary target: the Valve Steam Machine
|
||||
a warning when `VERSION` is a version that's already released (so a
|
||||
release branch that forgot its bump shows it on every PR).
|
||||
- A release that adds, removes or renames a menu row also retakes the
|
||||
README screenshot (`assets/screenshot-menu-steam-machine.png`; NVIDIA PCs get the same menu, so there is no separate
|
||||
one): the app from the branch on a Steam Machine, every row visible and the window only as tall as its options need, the header showing the new
|
||||
README screenshots (`assets/screenshot-menu-steam-machine.png` and
|
||||
`assets/screenshot-menu-nvidia.png`, side by side in the README): the app from the branch on a Steam Machine and on a PC
|
||||
with an NVIDIA card, every row visible and each window only as tall as its options need, the header showing the new
|
||||
`VERSION`, 1600 px wide. Size the window with a KWin script (match the `steamify-ui` class exactly: a title match also hits
|
||||
Konsole and editor windows) and crop the full-screen capture to the client rectangle; mind the display scale (the Steam
|
||||
Machine runs at 1.75).
|
||||
|
||||
+1
-28
@@ -5,36 +5,9 @@ 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.12.0 - 2026-10-13
|
||||
|
||||
- **feat: the patched gamescope comes in one build per CPU level, like CachyOS's repositories (generic, x86-64-v3, v4, znver4): Steamify picks the best one this CPU can run (`gsn_cpu_variant`), falls back to generic, and starts the installed gamescope once headless (`gsn_smoke_test`): a build that doesn't start is replaced by the generic one. CI compiles each with an explicit `-march` (a `-march=native` build died with SIGILL on a Ryzen) and checks the binary for instructions beyond its level.**
|
||||
- **feat: on NVIDIA the gaming session runs on the display's own mode and Steam's interface at its size: a second gamescope patch (`gamescope-ui-native.patch`, release `3.16.31-3` of steamify-gamescope-nvidia, now the pin; built once per CPU level, see below) keeps Steam's UI X server at the output size when Steam (with `-steamos3`) asks for 1920x1080, and a wrapper (`gamescope-display-wrapper.sh`, set up by the conversion with a drop-in of `gamescope-session.service`) starts gamescope on the mode KDE has saved for the connected display, else the biggest mode at the highest refresh rate: before, gaming mode ran at the display's preferred mode (60 Hz on many monitors) with a 1080p Steam UI. Tested on an RTX 5080, 3440x1440@175: widescreen, sharp, a Proton game starts**
|
||||
|
||||
- **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**
|
||||
## 2.11.0 - 2026-10-01
|
||||
|
||||
- `2e51d1d`, `3494924`, `fbdad5a`, `079e725`, `188799e` **feat: "Start Steam silently" sub-option: under the SteamOS conversion (`silent`, opt-in now: it was always on before; an existing one is moved from its systemd unit to the autostart entry by the "update") and under Gaming on NVIDIA (`nvsilent`, opt-in, not together with Big Picture); the SteamOS one is called "Start Steam silently in desktop mode" and is always shown, also on a Steam Machine; it is Steam's own autostart entry (`~/.config/autostart/steam.desktop`), so Steam's setting "Run Steam when my computer starts" follows it**
|
||||
- `2f7b53f` **fix: the Steam Machine's serial number step no longer fails inside the ISO's installer (`/sys` is read-only in its chroot; the tmpfiles.d file applies at the next boot anyway), which made `machine` report an error and the install log end with `exit: 1`**
|
||||
- `45a23af`, `bd8f387` **feat: `STEAMIFY_NO_DOWNLOAD` (the ISO's `steamify.nodownload` kernel parameter): the installed system's first login runs the Steamify bundle of the ISO instead of downloading the newest release (to test an unreleased Steamify)**
|
||||
- `f3810a9` **fix: the SteamOS theme no longer leaves a blank Discover pin in the taskbar (Plasma's default taskbar pins Discover, which CachyOS doesn't install); the taskbar gets CachyOS's own pins (System Settings, files, browser), also on the ISO's first login**
|
||||
- `7869b47` **feat: "Steam Deck/Machine icons" (`glyphs`) is a sub-option of the SteamOS conversion, like "Start Steam silently in desktop mode": it only changes gaming mode**
|
||||
- `4d387b2` **chore: the Steamify unit tests (`controllers-test.sh`, `nvidia-test.sh`) and the NVIDIA hardware test live in steamify-cachyos-dev (`tests/`) now; `tests/` is removed here**
|
||||
- `5da1833` **feat: "Start Steam silently" sub-option: under the SteamOS conversion (`silent`, on by default, as before) and under Gaming on NVIDIA (`nvsilent`, opt-in, not together with Big Picture); on a Steam Machine only when it boots into the desktop**
|
||||
|
||||
## 2.10.0 - 2026-10-01
|
||||
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
# Steamify CachyOS
|
||||
|
||||
The Steamify app's menu, on a Steam Machine. On a PC with an NVIDIA graphics card (GTX 16 / RTX 20 series or
|
||||
newer) the same SteamOS conversion is offered; Steamify installs a patched gamescope for it.
|
||||
The Steamify app's menu. On a Steam Machine (or any PC with an AMD or Intel
|
||||
graphics card) it offers the full SteamOS conversion, on the left. On a PC with
|
||||
an NVIDIA graphics card gamescope's gaming mode shows a corrupted picture, so the
|
||||
menu offers **Gaming on NVIDIA** instead (Steam on the desktop, started at login,
|
||||
optionally in Big Picture), on the right.
|
||||
|
||||

|
||||
| On a Steam Machine | On a PC with an NVIDIA graphics card |
|
||||
|---|---|
|
||||
|  |  |
|
||||
|
||||
Turn a CachyOS desktop PC into a SteamOS-style console: it boots straight
|
||||
into Steam's Big Picture (gamescope), and you can switch to the KDE Plasma
|
||||
@@ -22,10 +27,6 @@ Steam Machine.
|
||||
on the desktop too.
|
||||
- **Boot into: gamescope / desktop** - where the PC starts. Gaming mode is
|
||||
the default.
|
||||
- **Start Steam silently in desktop mode** (off by default) - Steam starts
|
||||
at login on the desktop, in the tray without a window. It is Steam's own
|
||||
autostart entry, so Steam's setting "Run Steam when my computer starts"
|
||||
follows it (the Linux Steam client has no silent option of its own).
|
||||
- Steam's **System** settings show the SteamOS release Steamify follows
|
||||
as OS Version (e.g. `steamos-3.9`), `steam-machine` as OS Codename and
|
||||
Steamify's version as OS Variant. The OS name stays CachyOS
|
||||
@@ -39,7 +40,7 @@ Steam Machine.
|
||||
2. **SteamOS theme** - the Vapor look of SteamOS for the desktop, with
|
||||
**Add to Steam** in right-click menus
|
||||
([details](TECHNICAL.md#steamos-desktop-look)).
|
||||
3. **Steam Deck/Machine icons** - Steam Deck button icons in gaming mode (an option of the SteamOS conversion).
|
||||
3. **Steam Deck/Machine icons** - Steam Deck button icons in gaming mode.
|
||||
4. **Single user mode** - like SteamOS: never a login or lock screen, and no
|
||||
KDE wallet password prompts (e.g. from Brave). Typing a password with a
|
||||
controller is no fun
|
||||
@@ -182,16 +183,6 @@ 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
|
||||
|
||||
+13
-39
@@ -109,10 +109,8 @@ tools write to the conf.d fragment into the base config.
|
||||
installs `/usr/local/bin/sync-steamos-session.sh` plus
|
||||
`sync-steamos-session.path`/`.service`;
|
||||
- `KWIN_IM_SHOW_ALWAYS=1` for the virtual keyboard; the sub-option `silent`
|
||||
("Start Steam silently in desktop mode", opt-in, always shown) writes
|
||||
`~/.config/autostart/steam.desktop` (the system steam.desktop with `-silent` in its Exec line). That is the
|
||||
file Steam's own setting "Run Steam when my computer starts" creates and removes, so the setting shows it. An older
|
||||
`steam-desktop-autostart` user unit is removed;
|
||||
("Start Steam silently", on by default) adds a `steam-desktop-autostart`
|
||||
systemd user service that starts Steam silently in Plasma only;
|
||||
- the **Return to Gaming Mode** shortcut; on plasma-login-manager with a
|
||||
narrow sudoers rule (`/etc/sudoers.d/gamescope-session-switch`) so it can
|
||||
restart the login manager without a password prompt.
|
||||
@@ -126,8 +124,7 @@ The conversion also sets what Steam's System settings show, see
|
||||
|
||||
**Steam Deck/Machine icons:** `STEAM_GAMEPADUI_ARGS="-gamepadui -steamos3"`
|
||||
in `~/.config/environment.d/` (and gamescope-session's own environment
|
||||
file), which makes Steam show Steam Deck button glyphs in gaming mode. It is a sub-option of the SteamOS conversion (`gaming`):
|
||||
it does nothing without gaming mode, ticking it ticks the conversion and turning the conversion off turns it off.
|
||||
file), which makes Steam show Steam Deck button glyphs in gaming mode.
|
||||
|
||||
## SteamOS desktop look
|
||||
|
||||
@@ -227,7 +224,7 @@ DKMS modules, built for every installed kernel, so `install_kernel_headers` (`li
|
||||
headers first. A PC that already has the AUR's `xone-dkms-git` keeps it: it provides the same driver and conflicts with the repo's
|
||||
`xone-dkms`. Status is the three packages being installed. Off removes only what Steamify installed (state
|
||||
`extended_controller_support`, `installed_pkgs`); the headers stay. The drivers load when the device shows up: the dongle is
|
||||
plugged in again, or the controller reconnected. Its test is in steamify-cachyos-dev (`tests/controllers-test.sh`).
|
||||
plugged in again, or the controller reconnected. `tests/controllers-test.sh` tests it with a stub `pacman`.
|
||||
|
||||
## Gaming on NVIDIA
|
||||
|
||||
@@ -238,30 +235,10 @@ 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.
|
||||
|
||||
Since 2.12.0 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, once per CPU level: generic, v3, v4, znver4, each checked for instructions beyond its level; a person merges the version bump). `gsn_cpu_variant` picks the build for this CPU (the dynamic loader's x86-64 level; AMD with `avx512_bf16` is znver4), generic is the fallback, and `gsn_smoke_test` runs the installed gamescope headless and swaps in generic when it doesn't start. The package is checked against the pinned hash
|
||||
or the release's `.sha256`, and installed 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.12.0, 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
|
||||
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
|
||||
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
|
||||
@@ -279,7 +256,7 @@ and boot entries are rebuilt and checked for the parameters. The early-load drop
|
||||
has the NVIDIA modules (mkinitcpio fails on a missing module, and `limine-mkinitcpio` then skips that kernel's boot entry):
|
||||
a pacman hook (`/etc/pacman.d/hooks/85-steamify-nvidia-initramfs.hook`, after DKMS, before the initramfs is built) runs
|
||||
`/usr/local/libexec/steamify-nvidia-initramfs` at every kernel or driver change and decides again. Turning it off removes
|
||||
all of it. The tests are in steamify-cachyos-dev: `tests/nvidia-test.sh` (a fake GPU, a stub `pacman` and `systemctl`, a temp home) and `tests/nvidia-hardware-test.sh` (a real NVIDIA PC).
|
||||
all of it. `tests/nvidia-hardware-test.sh check|apply|visual` is for a real NVIDIA PC (writes `~/steamify-nvidia-report.txt`). `tests/nvidia-test.sh` tests it against a fake GPU, a stub `pacman` and `systemctl`, and a temp home.
|
||||
|
||||
Tried and dropped (notes in steamify-cachyos-dev, `nvidia/HARDWARE-RESULTS.md`): a gamescope session that opens Big Picture in Plasma (it needed the `start-gamescope-session`
|
||||
command shadowed in `/usr/local/bin`, and showed the desktop for a few seconds, then a Steam window with a black border);
|
||||
@@ -367,7 +344,8 @@ desktop through its desktop layout (A = Enter, B = Esc, Y = Space, X =
|
||||
Steam's keyboard), in gaming mode as a gamepad.
|
||||
|
||||
Steam reads the list only at startup and writes it back on exit, so Steam is
|
||||
closed (`steam -shutdown`) for the edit and started again (`steam -silent`). That's refused in gaming
|
||||
closed (`steam -shutdown`) for the edit and started again (through
|
||||
`steam-desktop-autostart.service` when it's there). That's refused in gaming
|
||||
mode and when Steamify itself was started from Steam (`SteamGameId`), since
|
||||
closing Steam would end it. An entry for the start script that's already
|
||||
there (added by hand, or with the path from before 2.5.0) is updated, not
|
||||
@@ -512,8 +490,7 @@ In the home folder, everything is under `steamify`:
|
||||
| `~/.local/share/steamify/bin/` | The shortcut's start scripts (`run-app`, `run-wizard`) and `steamify-notifier` |
|
||||
| `~/.local/share/icons/hicolor/scalable/apps/steamify.svg` | The shortcut's icon |
|
||||
| `~/.local/share/applications/steamify-*.desktop` | The launcher entries |
|
||||
| `~/.config/autostart/steam.desktop` | the `silent` option (Steam's "Run Steam when my computer starts") |
|
||||
| `~/.config/systemd/user/` | `steamify-update-check.*` |
|
||||
| `~/.config/systemd/user/` | `steamify-update-check.*`, `steam-desktop-autostart.service` |
|
||||
|
||||
System-wide: `/usr/local/lib/steamify/` (kernel headers script),
|
||||
`/usr/src/steamify-*` (DKMS modules), `/var/cache/steamify/kernel` (the old
|
||||
@@ -559,9 +536,7 @@ steamify.sh --defaults --list # what --defaults can se
|
||||
item this PC can't use (e.g. `vram` without a VRAM region) is left off with
|
||||
a warning. `--boot desktop` needs `gaming`. Unknown options, ids, `boot` or
|
||||
`bios` in the list: exit code 1 before anything changes. What needs a
|
||||
Plasma session waits for the first login (`lib/first-login.sh`). The same step (and the online theme path) replaces Plasma's default taskbar pins, which include Discover
|
||||
(not installed on CachyOS: a blank icon), by CachyOS's own (`taskbar_drop_discover` in `lib/vapor-theme.sh`; skipped when Discover is
|
||||
installed or the taskbar already has its own `launchers`).
|
||||
Plasma session waits for the first login (`lib/first-login.sh`).
|
||||
|
||||
With `Relogin=true`, a gamescope session that fails to start is restarted
|
||||
immediately, which can turn into a loop - see
|
||||
@@ -592,7 +567,6 @@ 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 |
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 225 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 322 KiB After Width: | Height: | Size: 465 KiB |
+5
-9
@@ -50,7 +50,7 @@ backend_status() {
|
||||
items+="${items:+,}{\"id\":$(json_str "$c"),\"label\":$(json_str "${LABEL[$c]%%:*}")"
|
||||
items+=",\"hint\":$(json_str "$( [[ "${LABEL[$c]}" == *:* ]] && echo "${LABEL[$c]#*: }")")"
|
||||
items+=",\"kind\":\"$kind\",\"parent\":$(json_str "$parent")"
|
||||
items+=",\"needs\":\"\""
|
||||
items+=",\"needs\":$(json_str "$([[ "$c" == silent ]] && silent_needs_boot && echo boot)")"
|
||||
items+=",\"on\":$( [[ "$now" == 1 ]] && echo true || echo false)"
|
||||
items+=",\"wanted\":$( [[ "${WANTED[$c]:-0}" == 1 ]] && echo true || echo false)"
|
||||
items+=",\"update\":$(feature_outdated "$c" && echo true || echo false)"
|
||||
@@ -147,6 +147,7 @@ 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; }
|
||||
@@ -157,8 +158,8 @@ backend_apply() {
|
||||
[[ "${WANTED[nvsilent]:-0}" == 1 ]] && WANTED[nvidia]=1
|
||||
[[ "${WANTED[bigpicture]:-0}" == 1 ]] && WANTED[nvsilent]=0
|
||||
[[ "${WANTED[nvidia]:-0}" == 0 ]] && { WANTED[bigpicture]=0; WANTED[nvsilent]=0; }
|
||||
[[ "${WANTED[silent]:-0}" == 1 || "${WANTED[glyphs]:-0}" == 1 ]] && component_available gaming && WANTED[gaming]=1
|
||||
[[ "${WANTED[gaming]:-0}" == 0 ]] && { WANTED[silent]=0; WANTED[glyphs]=0; }
|
||||
[[ "${WANTED[silent]:-0}" == 1 ]] && component_available gaming && WANTED[gaming]=1
|
||||
[[ "${WANTED[gaming]:-0}" == 0 ]] && WANTED[silent]=0
|
||||
[[ "${WANTED[poweroff]:-0}" == 1 ]] && WANTED[machine]=1
|
||||
[[ "${WANTED[machine]:-0}" == 0 ]] && WANTED[poweroff]=0
|
||||
[[ "${WANTED[kpin]:-0}" == 1 ]] && WANTED[machine]=1
|
||||
@@ -166,6 +167,7 @@ backend_apply() {
|
||||
# Retired: only ever removed.
|
||||
WANTED[hdmi]=0
|
||||
case "$boot" in desktop) WANTED[boot]=1; WANTED[gaming]=1 ;; gamescope) WANTED[boot]=0 ;; esac
|
||||
silent_normalize
|
||||
|
||||
REAPPLY=$reapply
|
||||
plan_changes
|
||||
@@ -185,12 +187,6 @@ 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
|
||||
|
||||
+2
-7
@@ -73,17 +73,12 @@ 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 --max-time 60 "$CEC_DRIVER_URL" -o "$tmp/cros-ec-cec.c" ||
|
||||
if ! curl -fsL --retry 2 "$CEC_DRIVER_URL" -o "$tmp/cros-ec-cec.c" ||
|
||||
! echo "$CEC_DRIVER_SHA256 $tmp/cros-ec-cec.c" | sha256sum -c --quiet -; then
|
||||
# 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/)."
|
||||
err "Downloading Valve's CEC driver failed (or its checksum didn't match)."
|
||||
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
|
||||
sudo install -Dm644 "$tmp/cros-ec-cec.c" "$CEC_DRIVER_CACHE"
|
||||
|
||||
+4
-15
@@ -7,25 +7,13 @@
|
||||
|
||||
FIRST_LOGIN_ENTRY="${XDG_CONFIG_HOME:-$HOME/.config}/autostart/steamify-first-login.desktop"
|
||||
FIRST_LOGIN_SCRIPT="$STEAMIFY_BIN/first-login"
|
||||
FIRST_LOGIN_BUNDLE="$STEAMIFY_BIN/first-login-steamify.sh"
|
||||
|
||||
first_login_schedule() {
|
||||
# The newest release's Steamify runs at the first login. STEAMIFY_NO_DOWNLOAD (the ISO was started with
|
||||
# steamify.nodownload, to test an unreleased Steamify): this very bundle runs instead.
|
||||
# (Only a single-file bundle can be copied; SCRIPT_DIR doesn't exist in one.)
|
||||
local run self="${BASH_SOURCE[0]:-}"
|
||||
if [[ -n "${STEAMIFY_NO_DOWNLOAD:-}" && -f "$self" ]] && grep -q '^# Single-file build' "$self"; then
|
||||
install_executable "$FIRST_LOGIN_BUNDLE" 755 < "$self"
|
||||
run="bash \"$FIRST_LOGIN_BUNDLE\" --first-login; rm -f \"$FIRST_LOGIN_BUNDLE\""
|
||||
else
|
||||
run="curl -fsSL --max-time 30 \"$WIZARD_URL\" | bash -s -- --first-login"
|
||||
fi
|
||||
install_executable "$FIRST_LOGIN_SCRIPT" 755 << EOF2
|
||||
#!/bin/bash
|
||||
# Installed by Steamify CachyOS: runs once, at the first desktop login.
|
||||
set -o pipefail
|
||||
mkdir -p ~/.cache
|
||||
{ $run; } > ~/.cache/steamify-first-login.log 2>&1
|
||||
curl -fsSL --max-time 30 "$WIZARD_URL" | bash -s -- --first-login
|
||||
rm -f "$FIRST_LOGIN_ENTRY" "\$0"
|
||||
[[ -x "$WIZARD_APP_LAUNCHER" ]] && exec "$WIZARD_APP_LAUNCHER"
|
||||
EOF2
|
||||
@@ -43,9 +31,10 @@ first_login_run() {
|
||||
[[ -n "$(plasma_applets org.kde.plasma.kickoff)" ]] && break
|
||||
sleep 2
|
||||
done
|
||||
if single_status; then
|
||||
stop_plasmashell_for_edit
|
||||
taskbar_drop_discover
|
||||
single_status && single_launcher
|
||||
single_launcher
|
||||
restart_plasmashell_if_stopped
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
@@ -1,308 +0,0 @@
|
||||
#!/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-3
|
||||
# One build per CPU level, like CachyOS's repositories: generic is the one every x86-64 PC can run.
|
||||
declare -A GSN_SHA256=(
|
||||
[generic]=4c7995694d2726c356785d9aec12a11c98419b4d2e139617f03bb46c758ced56
|
||||
[v3]=43c6928ca9fa67c063c4e1b993b686145e94e68de1bd46645782d3186779fa2d
|
||||
[v4]=b6d4621e4b98d9aa5c600fe9a5a1cae164fef6bbf93d259fb8a6af666b098f9f
|
||||
[znver4]=60f45da74a0b96d776219f6e6aa22c5d23e48b08233b3fa12b6c4d7aa6812dd9
|
||||
)
|
||||
# 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_cpu_variant() {
|
||||
# The best build this CPU can run: znver4 (Ryzen 7000/9000: AMD with AVX-512 BF16), v4, v3, else generic. The
|
||||
# dynamic loader knows the CPU level best ("x86-64-v4 (supported, searched)").
|
||||
local help; help="$(/lib64/ld-linux-x86-64.so.2 --help 2>/dev/null)"
|
||||
if grep -q 'x86-64-v4 (supported' <<< "$help"; then
|
||||
if grep -q AuthenticAMD /proc/cpuinfo && grep -qw avx512_bf16 /proc/cpuinfo; then echo znver4; else echo v4; fi
|
||||
elif grep -q 'x86-64-v3 (supported' <<< "$help"; then echo v3
|
||||
else echo generic; fi
|
||||
}
|
||||
|
||||
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). gsn_sha_of <tag> <file> <variant>
|
||||
local tag="$1" file="$2" variant="$3"
|
||||
if [[ "$tag" == "$GSN_VERSION" ]]; then echo "${GSN_SHA256[$variant]}"; 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> <variant>: the release's package, verified, in the cache; prints its path.
|
||||
local tag="$1" variant="$2" cache="${XDG_CACHE_HOME:-$HOME/.cache}/steamify" file want got
|
||||
file="$GSN_PKG-$tag-$variant.pkg.tar.zst"
|
||||
mkdir -p "$cache" || return 1
|
||||
want="$(gsn_sha_of "$tag" "$file" "$variant")"
|
||||
[[ "$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: the build for this CPU, then the generic one, each from the newest release on
|
||||
# GitHub (not older than the pinned one), else the pinned release (GitHub, the cache, or the copy that came with the
|
||||
# ISO). Only files with the expected sha256 count. gsn_fetch_package [variant]
|
||||
local tag pkg v cache="${XDG_CACHE_HOME:-$HOME/.cache}/steamify" file copy
|
||||
local -a variants=("${1:-$(gsn_cpu_variant)}"); [[ "${variants[0]}" == generic ]] || variants+=(generic)
|
||||
tag="$(gsn_latest_tag)" || tag=""
|
||||
for v in "${variants[@]}"; do
|
||||
if [[ -n "$tag" && "$tag" != "$GSN_VERSION" ]] && gsn_newer "$tag" "$GSN_VERSION"; then
|
||||
info "Downloading the newest patched gamescope ($tag, $v)..." >&2
|
||||
if pkg="$(gsn_download "$tag" "$v")"; then echo "$pkg"; return 0; fi
|
||||
warn "Downloading the newest patched gamescope ($tag, $v) failed: trying the version this Steamify was tested with ($GSN_VERSION)." >&2
|
||||
fi
|
||||
info "Downloading the patched gamescope ($GSN_VERSION, $v)..." >&2
|
||||
if pkg="$(gsn_download "$GSN_VERSION" "$v")"; then echo "$pkg"; return 0; fi
|
||||
file="$GSN_PKG-$GSN_VERSION-$v.pkg.tar.zst"
|
||||
for copy in "$GSN_BACKUP_DIR/$file" "$cache/$file"; do
|
||||
if [[ -f "$copy" ]] && [[ "$(sha256sum "$copy" | awk '{print $1}')" == "${GSN_SHA256[$v]}" ]]; then
|
||||
info "Using the copy that came with Steamify: $copy" >&2
|
||||
echo "$copy"; return 0
|
||||
fi
|
||||
done
|
||||
done
|
||||
warn "Downloading the patched gamescope failed (or its checksum didn't match)." >&2
|
||||
return 1
|
||||
}
|
||||
|
||||
gsn_smoke_test() {
|
||||
# The installed gamescope must start (headless, no screen needed): a build that crashes would leave gaming mode in a loop.
|
||||
# It segfaults while shutting down headless (also unpatched builds), so what counts is that it ran the program.
|
||||
timeout 25 gamescope --backend headless -W 640 -H 360 -r 60 -- true 2>&1 | grep -q 'Primary child shut down'
|
||||
}
|
||||
|
||||
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" &&
|
||||
patch_file gamescope-ui-native.patch > "$dir/gamescope-ui-native.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.
|
||||
local f built=""
|
||||
for f in "$dir"/"$GSN_PKG"-*.pkg.tar.*; do
|
||||
[[ -e "$f" && "$f" != *-debug-* ]] && { built="$f"; break; }
|
||||
done
|
||||
[[ -n "$built" ]] && mv "$built" "$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
|
||||
if ! gsn_smoke_test; then
|
||||
warn "The patched gamescope for this CPU doesn't start: installing the generic build instead."
|
||||
pkg="$(gsn_fetch_package generic)" && sudo pacman -U --noconfirm --ask 4 "$pkg" && gsn_smoke_test ||
|
||||
{ err "The patched gamescope doesn't start on this PC."; return 1; }
|
||||
fi
|
||||
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
|
||||
}
|
||||
|
||||
# --- The session starts gamescope on the display's own mode
|
||||
#
|
||||
# gamescope-session starts gamescope without a size or a refresh rate, so it takes the display's *preferred* mode, which
|
||||
# many monitors declare as 60 Hz while the desktop runs them at their highest. patches/gamescope-display-wrapper.sh (put
|
||||
# first in the gaming session's PATH by a drop-in of gamescope-session.service) starts it on the mode KDE has saved for
|
||||
# the connected display, else the biggest mode at the highest refresh rate, read at every session start.
|
||||
GSN_DISPLAY_WRAPPER="${GSN_DISPLAY_WRAPPER:-$STEAMIFY_BIN/gamescope}"
|
||||
GSN_DISPLAY_DROPIN="${GSN_DISPLAY_DROPIN:-$HOME/.config/systemd/user/gamescope-session.service.d/steamify-display.conf}"
|
||||
|
||||
gsn_display_status() { [[ -x "$GSN_DISPLAY_WRAPPER" && -f "$GSN_DISPLAY_DROPIN" ]]; }
|
||||
|
||||
gsn_display_pending() {
|
||||
# The patched gamescope is in use but the session still starts it on the display's preferred mode: a normal run sets it up.
|
||||
gsn_package_installed && gsn_env_set && ! gsn_display_status
|
||||
}
|
||||
|
||||
gsn_display_enable() {
|
||||
patch_file gamescope-display-wrapper.sh | install_executable "$GSN_DISPLAY_WRAPPER" 755 || return 1
|
||||
mkdir -p "$(dirname "$GSN_DISPLAY_DROPIN")"
|
||||
cat > "$GSN_DISPLAY_DROPIN" << EOF
|
||||
# Steamify: the gaming session starts gamescope on the display's own mode (see lib/gamescope-nvidia.sh). Turning the
|
||||
# SteamOS conversion off removes this file.
|
||||
[Service]
|
||||
ExecStart=
|
||||
ExecStart=/usr/bin/bash -c 'PATH="$(dirname "$GSN_DISPLAY_WRAPPER"):\$PATH" exec /usr/lib/steamos/gamescope-session'
|
||||
EOF
|
||||
user_systemctl daemon-reload
|
||||
}
|
||||
|
||||
gsn_display_disable() {
|
||||
# Only our own files: the wrapper is recognised by its first comment line.
|
||||
grep -qs "^# Steamify: gamescope-session starts gamescope" "$GSN_DISPLAY_WRAPPER" && rm -f "$GSN_DISPLAY_WRAPPER"
|
||||
[[ -f "$GSN_DISPLAY_DROPIN" ]] && rm -f "$GSN_DISPLAY_DROPIN" && rmdir "$(dirname "$GSN_DISPLAY_DROPIN")" 2>/dev/null
|
||||
user_systemctl daemon-reload
|
||||
return 0
|
||||
}
|
||||
|
||||
gsn_preflight() {
|
||||
# Before anything changes: what would make the install fail half way. Prints the reason and fails, or passes.
|
||||
if [[ -e /var/lib/pacman/db.lck ]]; then
|
||||
echo "another package manager is running (/var/lib/pacman/db.lck): finish or close it and try again"; return 1
|
||||
fi
|
||||
local free; free="$(df --output=avail -BM / 2>/dev/null | tail -1 | tr -dc 0-9)"
|
||||
if [[ -n "$free" ]] && (( free < 1500 )); then
|
||||
echo "less than 1.5 GB free on /: free some space and try again"; return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
gsn_fail_mark() {
|
||||
# Remember a failed setup so the menu says so on the next start, and tell the user now (desktop notification).
|
||||
state_set gamescope_nvidia failed "$(date '+%Y-%m-%d %H:%M'): $1"
|
||||
command -v notify-send >/dev/null 2>&1 &&
|
||||
notify-send -a Steamify -i dialog-warning "Steamify: gaming mode setup failed" "$1. Open Steamify and apply again." 2>/dev/null || true
|
||||
}
|
||||
|
||||
gsn_fail_note() {
|
||||
# The menu's reminder of a failed setup (nothing when the last one worked).
|
||||
local f; f="$(state_get gamescope_nvidia failed)"
|
||||
[[ -n "$f" ]] && warn "The last gaming mode setup for NVIDIA failed ($f). Apply the conversion again to retry."
|
||||
return 0
|
||||
}
|
||||
|
||||
gsn_enable() {
|
||||
# Only on a supported NVIDIA card; elsewhere the stock gamescope is right.
|
||||
nvidia_present || return 0
|
||||
local why
|
||||
if ! why="$(gsn_preflight)"; then err "Gaming mode for NVIDIA can't be set up: $why."; gsn_fail_mark "$why"; return 1; fi
|
||||
# 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 || { gsn_fail_mark "the patched gamescope couldn't be installed"; return 1; }
|
||||
state_set gamescope_nvidia failed ""
|
||||
gsn_env_enable
|
||||
gsn_display_enable || warn "Couldn't set up the display mode for gaming mode: gamescope takes the display's preferred mode."
|
||||
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
|
||||
gsn_display_disable
|
||||
nvidia_present || return 0
|
||||
nvidia_extras_disable
|
||||
nvidia_kernel_disable
|
||||
}
|
||||
@@ -94,8 +94,6 @@ 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
|
||||
@@ -109,8 +107,6 @@ 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
|
||||
@@ -126,11 +122,8 @@ 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)."
|
||||
}
|
||||
|
||||
|
||||
+29
-32
@@ -5,19 +5,19 @@
|
||||
|
||||
# Menu order. Components are turned on in this order and off in reverse;
|
||||
# gaming must come first (single user builds on it).
|
||||
COMPONENTS=(gaming boot silent glyphs nvidia bigpicture nvsilent theme single launcher steamgame notify extended_controller_support vram cec machine poweroff kpin hdmi bios)
|
||||
COMPONENTS=(gaming boot silent nvidia bigpicture nvsilent theme glyphs single launcher steamgame notify extended_controller_support vram cec machine poweroff kpin hdmi bios)
|
||||
# One-off actions rather than on/off components: never preselected, never
|
||||
# re-applied, not listed as on or off.
|
||||
ACTIONS=(bios)
|
||||
# Sub-options, shown indented under their parent and only while it's ticked.
|
||||
declare -A PARENT=([boot]=gaming [silent]=gaming [glyphs]=gaming [bigpicture]=nvidia [nvsilent]=nvidia [steamgame]=launcher [poweroff]=machine [kpin]=machine [hdmi]=machine [bios]=machine)
|
||||
declare -A PARENT=([boot]=gaming [silent]=gaming [bigpicture]=nvidia [nvsilent]=nvidia [steamgame]=launcher [poweroff]=machine [kpin]=machine [hdmi]=machine [bios]=machine)
|
||||
# Never preselected on a first run: booting into the desktop is a choice,
|
||||
# gamescope is the default; HDMI-CEC is opt-in (it can wake the machine or
|
||||
# upset other devices on the TV, even on SteamOS), except on a Steam Machine,
|
||||
# which has CEC like on SteamOS. HDMI refresh boost needs someone at the
|
||||
# screen to confirm each step. Extended controller support builds kernel modules for
|
||||
# every installed kernel: opt-in.
|
||||
NO_PRESELECT=(boot silent nvsilent cec kpin hdmi extended_controller_support)
|
||||
NO_PRESELECT=(boot nvsilent cec kpin hdmi extended_controller_support)
|
||||
# Feature versions: the Steamify version in which what a component's enable
|
||||
# sets up last changed; set it to the new VERSION whenever you change one.
|
||||
# Each successful run records it (state "features"); a component that's on
|
||||
@@ -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.12.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.1.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
|
||||
[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
|
||||
)
|
||||
@@ -35,7 +35,7 @@ declare -A LABEL=(
|
||||
[gaming]="SteamOS conversion: boot into gaming mode, Steam on the desktop"
|
||||
[boot]="Boot into the desktop instead of gaming mode"
|
||||
[nvidia]="Gaming on NVIDIA: Steam on the desktop, started at login"
|
||||
[silent]="Start Steam silently in desktop mode: in the tray at login on the desktop, no window"
|
||||
[silent]="Start Steam silently: in the tray at login on the desktop, no window"
|
||||
[nvsilent]="Start Steam silently: in the tray at login, no window (untick: Steam's normal window)"
|
||||
[bigpicture]="Steam starts in Big Picture: the controller-friendly Steam (untick: Steam's normal window)"
|
||||
[theme]="Install SteamOS theme: Vapor look (cachyos-vapor)"
|
||||
@@ -57,9 +57,11 @@ declare -A CURRENT WANTED
|
||||
|
||||
component_available() {
|
||||
case "$1" in
|
||||
# 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 ;;
|
||||
# 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 ;;
|
||||
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;
|
||||
@@ -79,12 +81,25 @@ boot_mode() {
|
||||
if [[ "$1" == 1 ]]; then echo desktop; else echo gamescope; fi
|
||||
}
|
||||
|
||||
silent_needs_boot() {
|
||||
# On a Steam Machine, silent start only makes sense when it boots into
|
||||
# the desktop (gaming mode starts its own Steam): the option is hidden,
|
||||
# and off, while "Boot into" is gaming mode.
|
||||
machine_available
|
||||
}
|
||||
|
||||
silent_normalize() {
|
||||
silent_needs_boot && [[ "${WANTED[boot]:-0}" != 1 ]] && WANTED[silent]=0
|
||||
return 0
|
||||
}
|
||||
|
||||
menu_visible() {
|
||||
# Shown in the menu. A sub-option ("Boot into", the kernel pin) only
|
||||
# while its parent is ticked.
|
||||
component_available "$1" || return 1
|
||||
# Silent start is hidden while Steam starts in Big Picture.
|
||||
[[ "$1" == nvsilent && "${WANTED[bigpicture]:-0}" == 1 ]] && return 1
|
||||
[[ "$1" == silent ]] && silent_needs_boot && [[ "${WANTED[boot]:-0}" != 1 ]] && return 1
|
||||
[[ -z "${PARENT[$1]:-}" || "${WANTED[${PARENT[$1]}]:-0}" == 1 ]]
|
||||
}
|
||||
|
||||
@@ -113,11 +128,7 @@ 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 || gsn_display_pending; } && return 0
|
||||
have="$(state_get features "$1" "$FEATURE_BASELINE")"
|
||||
[[ "$have" == off ]] && have="$FEATURE_BASELINE"
|
||||
want="${FEATURE_VERSION[$1]:-$FEATURE_BASELINE}"
|
||||
@@ -186,17 +197,6 @@ 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.
|
||||
@@ -220,6 +220,7 @@ detect_components() {
|
||||
done
|
||||
machine_available && WANTED[cec]=1
|
||||
fi
|
||||
silent_normalize
|
||||
}
|
||||
|
||||
defaults_options() {
|
||||
@@ -276,6 +277,7 @@ defaults_options() {
|
||||
WANTED[boot]=1 ;;
|
||||
gamescope) WANTED[boot]=0 ;;
|
||||
esac
|
||||
silent_normalize
|
||||
return 0
|
||||
}
|
||||
|
||||
@@ -299,7 +301,7 @@ defaults_list() {
|
||||
[[ "$c" == cec ]] && machine_available && on=true
|
||||
items+="${items:+,}{\"id\":$(json_str "$c"),\"label\":$(json_str "${LABEL[$c]%%:*}")"
|
||||
items+=",\"hint\":$(json_str "$( [[ "${LABEL[$c]}" == *:* ]] && echo "${LABEL[$c]#*: }")")"
|
||||
items+=",\"kind\":\"$kind\",\"parent\":$(json_str "${PARENT[$c]:-}"),\"needs\":\"\",\"hideWhen\":$(json_str "$([[ "$c" == nvsilent ]] && echo bigpicture)"),\"on\":$on,\"selectable\":$sel}"
|
||||
items+=",\"kind\":\"$kind\",\"parent\":$(json_str "${PARENT[$c]:-}"),\"needs\":$(json_str "$([[ "$c" == silent ]] && silent_needs_boot && echo boot)"),\"hideWhen\":$(json_str "$([[ "$c" == nvsilent ]] && echo bigpicture)"),\"on\":$on,\"selectable\":$sel}"
|
||||
done
|
||||
printf '[%s]\n' "$items"
|
||||
}
|
||||
@@ -309,6 +311,7 @@ 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.
|
||||
@@ -319,9 +322,9 @@ toggle_component() {
|
||||
# Silent and Big Picture exclude each other.
|
||||
if [[ "$c" == nvsilent && "${WANTED[nvsilent]}" == 1 ]]; then WANTED[nvidia]=1; WANTED[bigpicture]=0; fi
|
||||
if [[ "$c" == nvidia && "${WANTED[nvidia]}" == 0 ]]; then WANTED[nvsilent]=0; fi
|
||||
if [[ "$c" == gaming && "${WANTED[gaming]}" == 0 ]]; then WANTED[silent]=0; WANTED[glyphs]=0; fi
|
||||
if [[ "$c" == gaming && "${WANTED[gaming]}" == 0 ]]; then WANTED[silent]=0; fi
|
||||
if [[ "$c" == silent && "${WANTED[silent]}" == 1 ]]; then WANTED[gaming]=1; fi
|
||||
if [[ "$c" == glyphs && "${WANTED[glyphs]}" == 1 ]]; then WANTED[gaming]=1; fi
|
||||
silent_normalize
|
||||
# The power-off fix is opt-out: ticked along with Steam Machine support.
|
||||
if [[ "$c" == machine ]]; then WANTED[poweroff]=${WANTED[machine]}; fi
|
||||
if [[ "$c" == poweroff && "${WANTED[poweroff]}" == 1 ]]; then WANTED[machine]=1; fi
|
||||
@@ -337,7 +340,6 @@ toggle_component() {
|
||||
show_menu() {
|
||||
local i=0 c now want
|
||||
echo
|
||||
gsn_fail_note
|
||||
printf " ${c_bold}%-3s %-6s %-6s %s${c_reset}\n" "#" "Now" "Want" "Component"
|
||||
MENU_ITEMS=()
|
||||
for c in "${COMPONENTS[@]}"; do
|
||||
@@ -512,11 +514,6 @@ 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
|
||||
|
||||
+5
-77
@@ -13,11 +13,6 @@ 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.
|
||||
@@ -37,27 +32,9 @@ nvidia_present() {
|
||||
return 1
|
||||
}
|
||||
|
||||
# Not offered any more (2.12.0): 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.12.0) 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
|
||||
}
|
||||
# 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; }
|
||||
bigpicture_available() { nvidia_available; }
|
||||
|
||||
nvidia_status() {
|
||||
@@ -85,7 +62,6 @@ 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."
|
||||
}
|
||||
|
||||
@@ -94,19 +70,13 @@ 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
|
||||
gaming_status 2>/dev/null || nvidia_kernel_disable
|
||||
nvidia_kernel_disable
|
||||
ok "Steam no longer starts at login."
|
||||
}
|
||||
|
||||
@@ -148,7 +118,7 @@ nvsilent_disable() {
|
||||
|
||||
nvidia_supported() {
|
||||
# A supported NVIDIA GPU: PCI vendor 0x10de, display class, its kernel
|
||||
# driver installed, and not older than Turing (GTX 16 / RTX 20 series: the cards NVIDIA's open kernel driver supports), decided like the
|
||||
# driver installed, and not older than the RTX 20 series, 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
|
||||
@@ -284,48 +254,6 @@ 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,30 +58,6 @@ 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
|
||||
@@ -89,7 +65,6 @@ 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,15 +140,6 @@ 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"
|
||||
|
||||
+13
-30
@@ -16,51 +16,34 @@ steam_enable() {
|
||||
}
|
||||
|
||||
# Sub-option of the SteamOS conversion: Steam starts silently (in the tray,
|
||||
# no window) on the Plasma desktop. It is Steam's own autostart entry, the file
|
||||
# Steam's setting "Run Steam when my computer starts" creates and removes, so
|
||||
# that setting shows what Steamify did (and the other way around). Steam's copy
|
||||
# is the system steam.desktop; ours has -silent in its Exec line.
|
||||
STEAM_AUTOSTART="${XDG_CONFIG_HOME:-$HOME/.config}/autostart/steam.desktop"
|
||||
STEAM_SYSTEM_DESKTOP=/usr/share/applications/steam.desktop
|
||||
|
||||
# no window) on the Plasma desktop.
|
||||
silent_status() {
|
||||
# The old systemd unit counts as on too (until it is migrated by an update of this option).
|
||||
grep -qs '^Exec=.*-silent' "$STEAM_AUTOSTART" ||
|
||||
[[ -f "$HOME/.config/systemd/user/steam-desktop-autostart.service" ]]
|
||||
}
|
||||
|
||||
silent_old_unit_remove() {
|
||||
# Before 2.11.0 the option was a systemd user unit: it would start Steam a second time.
|
||||
local unit="$HOME/.config/systemd/user/steam-desktop-autostart.service"
|
||||
[[ -f "$unit" ]] || return 0
|
||||
user_systemctl disable --now steam-desktop-autostart.service 2>/dev/null
|
||||
rm -f "$unit"
|
||||
user_systemctl daemon-reload
|
||||
}
|
||||
|
||||
silent_enable() {
|
||||
silent_old_unit_remove
|
||||
mkdir -p "$(dirname "$STEAM_AUTOSTART")"
|
||||
if [[ -f "$STEAM_SYSTEM_DESKTOP" ]]; then
|
||||
sed 's|^Exec=/usr/bin/steam %U$|Exec=/usr/bin/steam -silent %U|' "$STEAM_SYSTEM_DESKTOP" > "$STEAM_AUTOSTART"
|
||||
fi
|
||||
silent_status || printf '%s\n' '[Desktop Entry]' 'Name=Steam' 'Exec=/usr/bin/steam -silent %U' \
|
||||
'Icon=steam' 'Terminal=false' 'Type=Application' 'Categories=Network;FileTransfer;Game;' > "$STEAM_AUTOSTART"
|
||||
ok "Steam starts silently on the desktop from the next login."
|
||||
local systemd_user_dir="$HOME/.config/systemd/user"
|
||||
mkdir -p "$systemd_user_dir"
|
||||
service_file steam-desktop-autostart.service > "$systemd_user_dir/steam-desktop-autostart.service"
|
||||
# Clean out old .desktop shortcut so they don't fight
|
||||
rm -f "$HOME/.config/autostart/steam.desktop"
|
||||
user_systemctl daemon-reload
|
||||
user_systemctl enable --now steam-desktop-autostart.service
|
||||
ok "Steam starts silently on the desktop."
|
||||
}
|
||||
|
||||
silent_disable() {
|
||||
silent_old_unit_remove
|
||||
silent_status && rm -f "$STEAM_AUTOSTART"
|
||||
user_systemctl disable --now steam-desktop-autostart.service 2>/dev/null
|
||||
rm -f "$HOME/.config/systemd/user/steam-desktop-autostart.service"
|
||||
user_systemctl daemon-reload
|
||||
ok "Steam no longer starts by itself on the desktop."
|
||||
}
|
||||
|
||||
steam_disable() {
|
||||
info "Removing Steam desktop settings..."
|
||||
# The autostart entry is the `silent` option's: removed with it, and here
|
||||
# The autostart unit is the `silent` option's: removed with it, and here
|
||||
# too for when the conversion goes off by itself.
|
||||
silent_status && silent_disable
|
||||
silent_old_unit_remove
|
||||
rm -f "$HOME/.config/environment.d/99-kde-virtual-keyboard.conf"
|
||||
ok "Steam desktop settings removed (takes full effect at next login)."
|
||||
}
|
||||
|
||||
+5
-1
@@ -56,7 +56,7 @@ steamgame_steam_busy() {
|
||||
|
||||
steamgame_edit() {
|
||||
# steamgame_edit <function>: runs it with Steam closed, then starts Steam
|
||||
# again if it was running (silently, in the tray).
|
||||
# again if it was running (through our autostart unit when that's there).
|
||||
local was_running=false i
|
||||
if pgrep -x steam >/dev/null; then
|
||||
steamgame_steam_busy && return 1
|
||||
@@ -72,7 +72,11 @@ steamgame_edit() {
|
||||
fi
|
||||
"$1"; local rc=$?
|
||||
if [[ "$was_running" == true ]]; then
|
||||
if user_systemctl is-enabled -q steam-desktop-autostart.service 2>/dev/null; then
|
||||
user_systemctl start steam-desktop-autostart.service
|
||||
else
|
||||
systemd-run --user --collect -q steam -silent >/dev/null 2>&1
|
||||
fi
|
||||
info "Steam is starting again."
|
||||
fi
|
||||
return "$rc"
|
||||
|
||||
@@ -407,12 +407,9 @@ wifi_backend_disable() {
|
||||
|
||||
serial_enable() {
|
||||
printf '%s\n' "# Written by Steamify: Steam shows the serial number, like on SteamOS." \
|
||||
'z /sys/class/dmi/id/product_serial 0444 - - -' | sudo tee "$SERIAL_TMPFILES" > /dev/null ||
|
||||
'z /sys/class/dmi/id/product_serial 0444 - - -' | sudo tee "$SERIAL_TMPFILES" > /dev/null &&
|
||||
sudo systemd-tmpfiles --create "$SERIAL_TMPFILES" ||
|
||||
{ err "Making the serial number readable for Steam failed."; return 1; }
|
||||
# The file applies at every boot; now too, unless /sys is read-only (the ISO's installer runs in a chroot).
|
||||
sudo systemd-tmpfiles --create "$SERIAL_TMPFILES" 2>/dev/null ||
|
||||
info "The serial number becomes readable for Steam at the next boot."
|
||||
return 0
|
||||
}
|
||||
|
||||
serial_disable() {
|
||||
|
||||
+4
-19
@@ -106,32 +106,17 @@ theme_enable() {
|
||||
# SteamOS panel, launcher icon and wallpaper. It needs plasmashell up.
|
||||
lookandfeeltool -a "$VAPOR_LOOKANDFEEL" --resetLayout >/dev/null 2>&1 ||
|
||||
{ err "lookandfeeltool failed."; return 1; }
|
||||
# The new layout has a new launcher, without single user's settings, and the default taskbar pins.
|
||||
# The new layout has a new launcher, without single user's settings.
|
||||
if single_status; then
|
||||
sleep 3
|
||||
stop_plasmashell_for_edit
|
||||
taskbar_drop_discover
|
||||
single_status && single_launcher
|
||||
single_launcher
|
||||
restart_plasmashell_if_stopped
|
||||
fi
|
||||
extras_enable || warn "SteamOS desktop extras not installed (see above); the theme itself is on."
|
||||
ok "Vapor theme active."
|
||||
}
|
||||
|
||||
taskbar_drop_discover() {
|
||||
# Plasma's default taskbar pins Discover, which CachyOS doesn't install: the pin shows as a
|
||||
# blank icon. Pin what CachyOS's own layout pins (/etc/skel) instead. Not when Discover is
|
||||
# installed, and only on a taskbar that still has the default pins (no launchers key).
|
||||
# Edit only while plasmashell is stopped.
|
||||
[[ -e /usr/share/applications/org.kde.discover.desktop ]] && return 0
|
||||
local applet grp
|
||||
for applet in $(plasma_applets org.kde.plasma.icontasks); do
|
||||
grp="Containments|${applet%%:*}|Applets|${applet#*:}|Configuration|General"
|
||||
[[ -n "$(kreadconfig6 --file plasma-org.kde.plasma.desktop-appletsrc --group Containments --group "${applet%%:*}" \
|
||||
--group Applets --group "${applet#*:}" --group Configuration --group General --key launchers)" ]] && continue
|
||||
kset theme plasma-org.kde.plasma.desktop-appletsrc "$grp" launchers \
|
||||
'applications:systemsettings.desktop,preferred://filemanager,preferred://browser'
|
||||
done
|
||||
}
|
||||
|
||||
theme_disable() {
|
||||
extras_disable
|
||||
info "Restoring the previous desktop look and layout..."
|
||||
|
||||
@@ -16,9 +16,3 @@ 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 (CI builds it per CPU level; here it is only the local-build fallback) (`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 |
|
||||
| `gamescope-ui-native.patch` | `lib/gamescope-nvidia.sh` (gamescope on NVIDIA) | Small patch after the GBM one: keeps Steam's UI X server at the display's size when Steam (with `-steamos3`) asks for 1920x1080; `gamescope_xwayland_ui_native=0` turns it off |
|
||||
| `gamescope-display-wrapper.sh` | `lib/gamescope-nvidia.sh` (gamescope on NVIDIA) | Installed as `gamescope` in Steamify's bin folder and put first in the gaming session's PATH: starts gamescope on the mode KDE has saved for the connected display, else the biggest mode at the highest refresh rate (modetest + `kwinoutputconfig.json`) |
|
||||
@@ -1,621 +0,0 @@
|
||||
// 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");
|
||||
@@ -1,51 +0,0 @@
|
||||
#!/bin/bash
|
||||
# Steamify: gamescope-session starts gamescope without a size or a refresh rate, so it takes the display's *preferred* mode,
|
||||
# which many monitors declare as 60 Hz (the faster modes sit in an extension block of the EDID). This starts it the way the
|
||||
# desktop runs that display: the mode KDE has saved for the connected display (System Settings > Display), when the display
|
||||
# still has it, else its biggest mode at the highest refresh rate.
|
||||
# Read at every session start (modetest, part of libdrm which gamescope needs, and KDE's ~/.config/kwinoutputconfig.json), so
|
||||
# changing the resolution in KDE, another monitor or a TV just works. Anything unclear (no modetest output, no modes, more than
|
||||
# one display connected: gamescope chooses which one it uses) leaves gamescope's own choice alone.
|
||||
real=/usr/bin/gamescope
|
||||
|
||||
modes() {
|
||||
# One line per mode of every connected connector: "<connector> <width> <height> <refresh>"
|
||||
local m
|
||||
for m in nvidia-drm amdgpu i915 xe nouveau radeon; do
|
||||
timeout 10 modetest -M "$m" -c 2>/dev/null | awk '
|
||||
/^[0-9]+[ \t]+[0-9]+[ \t]+(connected|disconnected|unknown)/ { conn = ($3 == "connected") ? $4 : ""; next }
|
||||
conn != "" && /^[ \t]+#[0-9]+ [0-9]+x[0-9]+ [0-9.]+ / && !/interlace/ {
|
||||
split($2, wh, "x"); printf "%s %d %d %.0f\n", conn, wh[1], wh[2], $3
|
||||
}'
|
||||
done
|
||||
}
|
||||
|
||||
kde_mode() {
|
||||
# kde_mode <connector>: "<width> <height> <refresh>" as KDE has it saved for that connector, or nothing.
|
||||
python3 -I - "$1" "${XDG_CONFIG_HOME:-$HOME/.config}/kwinoutputconfig.json" 2>/dev/null << 'EOF'
|
||||
import json, sys
|
||||
try:
|
||||
for block in json.load(open(sys.argv[2])):
|
||||
if block.get("name") == "outputs":
|
||||
for o in block.get("data", []):
|
||||
m = o.get("mode")
|
||||
if o.get("connectorName") == sys.argv[1] and m:
|
||||
print(m["width"], m["height"], round(m["refreshRate"] / 1000))
|
||||
except Exception:
|
||||
pass
|
||||
EOF
|
||||
}
|
||||
|
||||
args=()
|
||||
all="$(modes)"
|
||||
conn="$(awk '{print $1}' <<< "$all" | sort -u)"
|
||||
if [[ -n "$conn" && "$(wc -l <<< "$conn")" == 1 ]]; then
|
||||
read -r w h r <<< "$(kde_mode "$conn")"
|
||||
# KDE's mode only counts when the display really has it (a refresh rate within 1 Hz).
|
||||
if [[ -z "${w:-}" ]] || ! awk -v w="$w" -v h="${h:-0}" -v r="${r:-0}" '$2 == w && $3 == h && ($4 - r < 2 && r - $4 < 2) {f = 1} END {exit !f}' <<< "$all"; then
|
||||
read -r _ w h r < <(awk '{print $2 * $3, $2, $3, $4}' <<< "$all" | sort -k1,1nr -k4,4nr | head -1 | awk '{print "x", $2, $3, $4}')
|
||||
fi
|
||||
[[ "${w:-0}" -gt 0 && "${h:-0}" -gt 0 && "${r:-0}" -gt 0 ]] && args=(-W "$w" -H "$h" -r "$r")
|
||||
fi
|
||||
if [[ "${1:-}" == --print-args ]]; then echo "${args[*]}"; exit 0; fi
|
||||
exec "$real" "${args[@]}" "$@"
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,128 +0,0 @@
|
||||
# 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 patches are gamescope-gbm-scanout.patch and gamescope-ui-native.patch (next to this file, applied in this order); see the
|
||||
# README for where they come from.
|
||||
# UPSTREAM_VERSION (next to this file) names the gamescope tag the patches are made for.
|
||||
|
||||
pkgname=steamify-gamescope-nvidia
|
||||
_srcname=gamescope
|
||||
pkgver=3.16.31
|
||||
pkgrel=3
|
||||
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
|
||||
gamescope-ui-native.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'
|
||||
'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
|
||||
git apply --check ../gamescope-ui-native.patch || { echo "ui-native patch does not apply to gamescope ${pkgver}" >&2; return 1; }
|
||||
git apply ../gamescope-ui-native.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:
|
||||
@@ -1,39 +0,0 @@
|
||||
Keeps Steam's UI X server (server 0) at the output size when Steam asks for a smaller one.
|
||||
|
||||
With -steamos3 (what gamescope-session-cachyos passes) Steam sets its UI to 1920x1080 right after it starts
|
||||
(GAMESCOPE_XWAYLAND_MODE_CONTROL), so on a bigger display, and on one that isn't 16:9, the whole interface is a scaled-up
|
||||
1080p picture. Games already run at the display's size. With this the server stays at the output size and Steam draws its
|
||||
window to match; Steam's SteamOS features (settings pages, game launching) keep working. Written for Steamify on an NVIDIA
|
||||
PC (RTX 5080, 3440x1440@175, tested with Steam's UI and a Proton game); not part of the farnoy patch. On by default; the
|
||||
setting gamescope_xwayland_ui_native=0 (in gamescope's environment) turns it off.
|
||||
Applies with `git apply` after gamescope-gbm-scanout.patch (it ignores these lines).
|
||||
|
||||
diff --git a/src/steamcompmgr.cpp b/src/steamcompmgr.cpp
|
||||
index 2cb5eb5..ce14c8d 100644
|
||||
--- a/src/steamcompmgr.cpp
|
||||
+++ b/src/steamcompmgr.cpp
|
||||
@@ -129,6 +129,8 @@ LogScope g_WaitableLog("waitable");
|
||||
|
||||
gamescope::ConVar<bool> cv_overlay_unmultiplied_alpha{ "overlay_unmultiplied_alpha", false };
|
||||
|
||||
+gamescope::ConVar<bool> cv_xwayland_ui_native( "xwayland_ui_native", true, "Keep the Steam UI X server (server 0) at the output size when Steam asks for a smaller one." );
|
||||
+
|
||||
gamescope::ConVar<bool> cv_vr_show_forwarded_overlays{ "vr_show_forwarded_overlays", false };
|
||||
|
||||
std::string *g_pVROverlayKey = nullptr;
|
||||
@@ -7240,6 +7242,15 @@ handle_property_notify(xwayland_ctx_t *ctx, XPropertyEvent *ev)
|
||||
height = std::min<int>(height, currentOutputHeight);
|
||||
}
|
||||
|
||||
+ // Steam asks for a smaller size for its own UI (server 0, 1920x1080 with -steamos3), which makes the whole
|
||||
+ // interface a scaled-up picture on a bigger display, and on one that isn't 16:9 as well. The UI server
|
||||
+ // stays at the output size: Steam sizes its window to the server.
|
||||
+ if ( server_idx == 0 && cv_xwayland_ui_native )
|
||||
+ {
|
||||
+ width = currentOutputWidth;
|
||||
+ height = currentOutputHeight;
|
||||
+ }
|
||||
+
|
||||
gamescope_xwayland_server_t *server = wlserver_get_xwayland_server( server_idx );
|
||||
if ( server )
|
||||
{
|
||||
@@ -1,17 +0,0 @@
|
||||
# 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,11 +7,6 @@
|
||||
* 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>
|
||||
|
||||
@@ -12,5 +12,6 @@ in the shell code.
|
||||
| `steamify-boot-desktop.service` | `lib/boot-session.sh` (Boot into: desktop) | Sets the Plasma session before the login manager starts |
|
||||
| `sync-steamos-session.path`, `.service` | `lib/login-manager.sh` (SteamOS conversion, plasma-login-manager) | The sync bridge: copies Steam's session choice into `plasmalogin.conf` |
|
||||
| `steamify-steam-autostart.service` | `lib/nvidia.sh` (Gaming on NVIDIA) | Steam at login on the Plasma desktop, normal or in Big Picture (user unit) |
|
||||
| `steam-desktop-autostart.service` | `lib/steam-desktop.sh` (SteamOS conversion) | Steam in the background on the Plasma desktop (user unit) |
|
||||
| `ensure-kernel-headers.service` | `lib/steam-machine.sh` (Steam Machine support) | Installs missing kernel headers at boot, so DKMS builds for every kernel |
|
||||
| `steamify-update-check.service`, `.timer` | `lib/update-notifier.sh` (Update notifications) | The daily and login check for a new release (user units) |
|
||||
@@ -0,0 +1,15 @@
|
||||
[Unit]
|
||||
Description=Steam Background Autostart for Virtual Keyboard
|
||||
After=graphical-session.target
|
||||
PartOf=graphical-session.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
# Only in the Plasma desktop session; gamescope-session starts its own Steam.
|
||||
ExecCondition=/bin/sh -c '[ "$XDG_CURRENT_DESKTOP" = KDE ]'
|
||||
ExecStart=/usr/bin/steam -silent
|
||||
Restart=on-failure
|
||||
RestartSec=5
|
||||
|
||||
[Install]
|
||||
WantedBy=graphical-session.target
|
||||
+2
-2
@@ -15,11 +15,11 @@
|
||||
set -uo pipefail
|
||||
|
||||
# Release version, see CHANGELOG.md.
|
||||
VERSION=2.12.0
|
||||
VERSION=2.11.0
|
||||
|
||||
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 gamescope-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 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
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
#!/bin/bash
|
||||
# Tests lib/controllers.sh (extended controller support: xone, the Xbox wireless dongle, and xpadneo, Xbox Bluetooth) with a stub pacman
|
||||
# and a temp home. No root, VM or hardware needed: bash tests/controllers-test.sh
|
||||
cd "$(dirname "$0")/.." || exit 1
|
||||
T="$(mktemp -d)"; trap 'rm -rf "$T"' EXIT
|
||||
fail=0
|
||||
check() { if eval "$2"; then echo "ok $1"; else echo "FAIL $1"; fail=1; fi; }
|
||||
|
||||
SCRIPT_DIR="$PWD"; HOME="$T/home"; mkdir -p "$HOME"
|
||||
source lib/common.sh; source lib/state.sh; source lib/controllers.sh; source lib/menu.sh
|
||||
# Runs as the user, and refuses anything under the real system folders: a test must never touch them.
|
||||
sudo() { local a; for a in "$@"; do case "$a" in /etc/*|/usr/*|/boot/*|/var/*) echo "REFUSED sudo $*" >&2; return 1 ;; esac; done; "$@"; }
|
||||
info() { :; }; ok() { :; }; warn() { :; }; err() { echo "ERR $*"; }
|
||||
kwriteconfig6() { local f="" k="" v=""; while [[ $# -gt 0 ]]; do case "$1" in --file) f="$2"; shift ;; --key) k="$2"; shift ;; --group) shift ;; *) v="$1" ;; esac; shift; done; mkdir -p "$(dirname "$f")"; sed -i "/^$k=/d" "$f" 2>/dev/null; printf '%s=%s\n' "$k" "$v" >> "$f"; }
|
||||
kreadconfig6() { local f="" k=""; while [[ $# -gt 0 ]]; do case "$1" in --file) f="$2"; shift ;; --key) k="$2"; shift ;; --group|--default) shift ;; esac; shift; done; sed -n "s/^$k=//p" "$f" 2>/dev/null; }
|
||||
# A pretend package database.
|
||||
PKGS=""; PACMAN_LOG="$T/pacman.log"; : > "$PACMAN_LOG"; PACMAN_FAIL=0
|
||||
pacman() {
|
||||
case "$1" in
|
||||
-Q) local p; for p in "${@:2}"; do [[ " $PKGS " == *" $p "* ]] || return 1; done ;;
|
||||
-S) [[ $PACMAN_FAIL == 1 ]] && return 1; echo "S ${*:4}" >> "$PACMAN_LOG"; PKGS+=" ${*:4}" ;;
|
||||
-Rns) echo "R ${*:3}" >> "$PACMAN_LOG"; local p; for p in ${*:3}; do PKGS=" ${PKGS// $p / } "; done ;;
|
||||
esac
|
||||
}
|
||||
HEADERS=0; install_kernel_headers() { HEADERS=$((HEADERS + 1)); }
|
||||
|
||||
check "off to begin with" '! extended_controller_support_status'
|
||||
extended_controller_support_enable
|
||||
check "installs the repo's xpadneo-dkms, xone-dkms and the dongle firmware" 'pacman -Q xpadneo-dkms xone-dkms xone-dongle-firmware'
|
||||
check "kernel headers are made sure of first" '[[ $HEADERS == 1 ]]'
|
||||
check "what we installed is recorded" '[[ "$(state_get extended_controller_support installed_pkgs)" == "xpadneo-dkms xone-dkms xone-dongle-firmware" ]]'
|
||||
check "it is on" extended_controller_support_status
|
||||
n="$(wc -l < "$PACMAN_LOG")"; extended_controller_support_enable
|
||||
check "a second run installs nothing again" '[[ "$(wc -l < "$PACMAN_LOG")" == "$n" ]]'
|
||||
extended_controller_support_disable
|
||||
check "off: the three packages are removed again" '! pacman -Q xpadneo-dkms 2>/dev/null && ! pacman -Q xone-dkms 2>/dev/null && ! pacman -Q xone-dongle-firmware 2>/dev/null && [[ -z "$(state_get extended_controller_support installed_pkgs)" ]]'
|
||||
|
||||
# The AUR's xone-dkms-git conflicts with the repo's xone-dkms: it counts, and is kept.
|
||||
PKGS=" xone-dkms-git xone-dongle-firmware xpadneo-dkms"; : > "$PACMAN_LOG"
|
||||
check "xone-dkms-git counts as xone: already on" extended_controller_support_status
|
||||
extended_controller_support_enable; extended_controller_support_disable
|
||||
check "with xone-dkms-git: nothing installed and nothing removed" '[[ ! -s "$PACMAN_LOG" ]] && pacman -Q xone-dkms-git xpadneo-dkms xone-dongle-firmware'
|
||||
PKGS=" xone-dkms-git"
|
||||
extended_controller_support_enable
|
||||
check "xone-dkms-git present: only the missing ones are installed, never xone-dkms" 'grep -q "^S xpadneo-dkms xone-dongle-firmware$" "$PACMAN_LOG" && ! pacman -Q xone-dkms 2>/dev/null'
|
||||
extended_controller_support_disable
|
||||
check "and off removes only those two, xone-dkms-git stays" 'pacman -Q xone-dkms-git && ! pacman -Q xpadneo-dkms 2>/dev/null'
|
||||
|
||||
# A failed install is an error and records nothing.
|
||||
PKGS=""; PACMAN_FAIL=1
|
||||
check "a failed pacman is an error" '! extended_controller_support_enable >/dev/null'
|
||||
check "...and records nothing" '[[ -z "$(state_get extended_controller_support installed_pkgs)" ]]'
|
||||
PACMAN_FAIL=0
|
||||
|
||||
# Packages that were already there are never removed by turning it off.
|
||||
PKGS=" xpadneo-dkms xone-dkms xone-dongle-firmware"; : > "$PACMAN_LOG"
|
||||
extended_controller_support_enable; extended_controller_support_disable
|
||||
check "packages you had before stay" 'pacman -Q xpadneo-dkms xone-dkms xone-dongle-firmware && [[ ! -s "$PACMAN_LOG" ]]'
|
||||
|
||||
# The menu.
|
||||
check "offered on every PC" 'component_available extended_controller_support'
|
||||
check "not preselected: it builds kernel modules for every kernel" '[[ " ${NO_PRESELECT[*]} " == *" extended_controller_support "* ]]'
|
||||
check "a top-level item with a label" '[[ -z "${PARENT[extended_controller_support]:-}" && -n "${LABEL[extended_controller_support]}" ]]'
|
||||
|
||||
# The "new" badge: an opt-in option added after setup shows it, but is never ticked for you.
|
||||
component_selectable() { return 0; }
|
||||
declare -A CURRENT=([gaming]=1 [nvidia]=0 [extended_controller_support]=0 [vram]=0 [boot]=0)
|
||||
rm -f "$STATE_DIR/features.state"
|
||||
check "new opt-in option (conversion on, no record): the new badge" 'feature_new_optin extended_controller_support'
|
||||
check "...but it is not ticked for you (not a new default option)" '! feature_new extended_controller_support'
|
||||
check "...and the menu label says (new)" '[[ "$(menu_label extended_controller_support)" == *"(new)"* ]]'
|
||||
check "a new default option is still ticked for you, and is not the opt-in kind" 'feature_new vram && ! feature_new_optin vram'
|
||||
check "Boot into never gets the badge (it is a choice row)" '! feature_new_optin boot'
|
||||
state_set_features() { kwriteconfig6 --file "$STATE_DIR/features.state" --group State --key "$1" "$2"; }
|
||||
state_set_features extended_controller_support off
|
||||
check "once a run recorded it as off, the badge is gone" '! feature_new_optin extended_controller_support'
|
||||
rm -f "$STATE_DIR/features.state"
|
||||
CURRENT[gaming]=0; CURRENT[nvidia]=1
|
||||
check "on an NVIDIA PC (Gaming on NVIDIA on, no conversion) it shows too" 'feature_new_optin extended_controller_support'
|
||||
CURRENT[nvidia]=0
|
||||
check "with neither the conversion nor Gaming on NVIDIA on (a fresh PC) nothing is new" '! feature_new_optin extended_controller_support && ! feature_new vram'
|
||||
CURRENT[gaming]=1; CURRENT[extended_controller_support]=1
|
||||
check "already on: not new" '! feature_new_optin extended_controller_support'
|
||||
exit $fail
|
||||
@@ -0,0 +1,95 @@
|
||||
#!/bin/bash
|
||||
# Test of the NVIDIA fix on a real PC with an NVIDIA GPU (the unit test fakes
|
||||
# one: tests/nvidia-test.sh). Run from the Steamify checkout:
|
||||
# bash tests/nvidia-hardware-test.sh check read-only: what is detected, what the live kernel uses, what apply would change
|
||||
# bash tests/nvidia-hardware-test.sh apply really applies the fix (sudo), then reboot and run check again
|
||||
# bash tests/nvidia-hardware-test.sh visual after trying gaming mode: was the picture clean? (asks you)
|
||||
# Every run appends to ~/steamify-nvidia-report.txt: paste that file when asking for help.
|
||||
cd "$(dirname "$0")/.." || exit 1
|
||||
# patch_file (lib/common.sh) reads the hook script from $SCRIPT_DIR/patches.
|
||||
SCRIPT_DIR="$PWD"
|
||||
REPORT="${NVIDIA_REPORT:-$HOME/steamify-nvidia-report.txt}"
|
||||
source lib/common.sh; source lib/hdmi-refresh.sh; source lib/vram-booster.sh; source lib/nvidia.sh
|
||||
mode="${1:-check}"
|
||||
fail=0
|
||||
say() { echo "$*" | tee -a "$REPORT"; }
|
||||
pass() { say "PASS $*"; }
|
||||
bad() { say "FAIL $*"; fail=1; }
|
||||
note() { say " $*"; }
|
||||
root_cat() { cat "$1" 2>/dev/null || sudo cat "$1" 2>/dev/null || echo "(unreadable)"; }
|
||||
|
||||
say ""; say "===== $(date '+%F %T') mode=$mode kernel=$(uname -r)"
|
||||
|
||||
report_system() {
|
||||
say "-- GPU and software"
|
||||
lspci -nn 2>/dev/null | grep -iE 'vga|3d|display' | while read -r l; do note "$l"; done
|
||||
command -v nvidia-smi >/dev/null && note "driver: $(nvidia-smi --query-gpu=name,driver_version --format=csv,noheader 2>&1 | head -n 1)"
|
||||
for p in nvidia-open nvidia-utils nvidia-dkms gamescope gamescope-session-cachyos linux-cachyos-nvidia-open; do
|
||||
v="$(pacman -Q "$p" 2>/dev/null)" && note "$v"
|
||||
done
|
||||
note "boot loader file: $(nvidia_boot_file || true)"
|
||||
note "cmdline: $(cat /proc/cmdline)"
|
||||
}
|
||||
|
||||
check_state() {
|
||||
say "-- Steamify's view"
|
||||
if nvidia_present; then pass "a supported NVIDIA GPU (RTX 20 series or newer) with its driver is detected"
|
||||
elif nvidia_legacy_gpu; then bad "the NVIDIA GPU is older than RTX 20 (on chwd's legacy lists in $VRAM_CHWD_IDS): the fix is not applied"
|
||||
else bad "no NVIDIA GPU with its driver detected: the fix does nothing here"; fi
|
||||
for c in /sys/class/drm/card[0-9]*/device; do
|
||||
[[ "$(cat "$c/vendor" 2>/dev/null)" == 0x10de ]] && note "NVIDIA PCI device id $(cat "$c/device") $(vram_nvidia_legacy_id "$(cat "$c/device")" && echo '(on a chwd legacy list)' || echo '(not on a legacy list: RTX 20 or newer)')"
|
||||
done
|
||||
ls "$VRAM_CHWD_IDS"/nvidia-*.ids >/dev/null 2>&1 || note "no chwd legacy lists found: every NVIDIA card counts as supported"
|
||||
local p
|
||||
for p in $NVIDIA_PARAMS; do
|
||||
if grep -qw -- "$p" /proc/cmdline; then pass "$p is on the running kernel's command line"
|
||||
elif nvidia_param_set "$p"; then bad "$p is in the boot loader's file but not booted yet: reboot"
|
||||
else bad "$p is missing (run: bash tests/nvidia-hardware-test.sh apply)"; fi
|
||||
done
|
||||
say "-- the live NVIDIA driver"
|
||||
local m
|
||||
for m in modeset fbdev; do
|
||||
v="$(root_cat /sys/module/nvidia_drm/parameters/$m)"
|
||||
if [[ "$v" == Y ]]; then pass "nvidia_drm $m = Y"; else bad "nvidia_drm $m = $v (want Y)"; fi
|
||||
done
|
||||
lsmod | grep -q '^nvidia_drm' && pass "nvidia_drm is loaded" || bad "nvidia_drm is not loaded"
|
||||
local c found=0
|
||||
for c in /sys/class/drm/card[0-9]*/device; do
|
||||
[[ "$(cat "$c/vendor" 2>/dev/null)" == 0x10de ]] || continue
|
||||
found=1; note "NVIDIA card: ${c%/device} driver=$(basename "$(readlink -f "$c/driver" 2>/dev/null)")"
|
||||
for s in "${c%/device}"/card*-*/status; do [[ -f "$s" ]] && note " $(basename "$(dirname "$s")"): $(cat "$s")"; done
|
||||
done
|
||||
[[ $found == 1 ]] || bad "no NVIDIA card in /sys/class/drm"
|
||||
say "-- initramfs"
|
||||
if nvidia_modules_everywhere; then note "every installed kernel has nvidia_drm: the early-load drop-in is used"
|
||||
else note "not every installed kernel has nvidia_drm: the early-load drop-in is skipped (parameters still apply)"; fi
|
||||
nvidia_initramfs_ok && note "NVIDIA modules are in the initramfs config" || note "NVIDIA modules are not in the initramfs config"
|
||||
say "-- what apply would change"
|
||||
if nvidia_params_missing; then note "adds $NVIDIA_PARAMS to $(nvidia_boot_file)"; else note "kernel parameters: nothing to change"; fi
|
||||
if ! nvidia_initramfs_ok && nvidia_modules_everywhere; then note "writes $NVIDIA_INITRAMFS_CONF"; fi
|
||||
}
|
||||
|
||||
case "$mode" in
|
||||
check)
|
||||
report_system; check_state ;;
|
||||
apply)
|
||||
report_system
|
||||
say "-- applying"
|
||||
if nvidia_enable 2>&1 | tee -a "$REPORT"; [[ ${PIPESTATUS[0]} == 0 ]]; then pass "nvidia_enable finished"
|
||||
else bad "nvidia_enable failed (output above)"; fi
|
||||
say "Now reboot, then run: bash tests/nvidia-hardware-test.sh check" ;;
|
||||
visual)
|
||||
report_system
|
||||
say "-- try gaming mode now (log in to it or reboot into it), look at the screen, then answer"
|
||||
read -rp "Is the gaming mode picture clean (no corruption, no flicker)? [y/n/partly] " a
|
||||
read -rp "What did you see (one line, e.g. 'garbled colours at start, fine after login')? " what
|
||||
say "visual result: $a: $what"
|
||||
[[ "$a" == y ]] && pass "picture clean" || bad "picture not clean ($a)"
|
||||
say "-- gamescope and NVIDIA lines from this boot's log"
|
||||
{ journalctl -b --no-pager 2>/dev/null || sudo journalctl -b --no-pager 2>/dev/null; } |
|
||||
grep -iE 'gamescope|nvidia|drm|nvrm|wlserver|vulkan' | tail -n 80 | tee -a "$REPORT" | tail -n 5
|
||||
note "(more in $REPORT)" ;;
|
||||
*) echo "usage: $0 check|apply|visual"; exit 2 ;;
|
||||
esac
|
||||
say ""; say "Report: $REPORT"
|
||||
exit $fail
|
||||
@@ -0,0 +1,206 @@
|
||||
#!/bin/bash
|
||||
# Tests lib/nvidia.sh ("Gaming on NVIDIA" and its Big Picture option) and the menu rules around it, against a fake RTX 5080
|
||||
# (PCI 10de:2c02) beside an Intel iGPU, a stub modinfo, pacman and systemctl, and a temp home. No root, VM or NVIDIA
|
||||
# hardware needed: bash tests/nvidia-test.sh
|
||||
cd "$(dirname "$0")/.." || exit 1
|
||||
T="$(mktemp -d)"; trap 'rm -rf "$T"' EXIT
|
||||
fail=0
|
||||
check() { if eval "$2"; then echo "ok $1"; else echo "FAIL $1"; fail=1; fi; }
|
||||
|
||||
SCRIPT_DIR="$PWD"; HOME="$T/home"; mkdir -p "$HOME"
|
||||
source lib/common.sh; source lib/state.sh; source lib/login-manager.sh; source lib/single-user.sh; source lib/hdmi-refresh.sh; source lib/vram-booster.sh; source lib/nvidia.sh; source lib/menu.sh
|
||||
# Runs as the user, and refuses anything under the real system folders: a test must never touch them.
|
||||
sudo() { local a; for a in "$@"; do case "$a" in /etc/*|/usr/*|/boot/*|/var/*) echo "REFUSED sudo $*" >&2; return 1 ;; esac; done; "$@"; }
|
||||
info() { :; }; ok() { :; }; warn() { :; }; err() { echo "ERR $*"; }
|
||||
# KDE's config tools on plain files under the temp home (a relative file name is relative to ~/.config, as in KDE).
|
||||
kwriteconfig6() {
|
||||
local f="" k="" v="" del=0
|
||||
while [[ $# -gt 0 ]]; do case "$1" in --file) f="$2"; shift ;; --key) k="$2"; shift ;; --group) shift ;; --delete) del=1 ;; *) v="$1" ;; esac; shift; done
|
||||
[[ "$f" == /* ]] || f="$HOME/.config/$f"; mkdir -p "$(dirname "$f")"
|
||||
if [[ $del == 1 ]]; then sed -i "/^$k=/d" "$f" 2>/dev/null; else sed -i "/^$k=/d" "$f" 2>/dev/null; printf '%s=%s\n' "$k" "$v" >> "$f"; fi
|
||||
}
|
||||
kreadconfig6() {
|
||||
local f="" k="" d="" r
|
||||
while [[ $# -gt 0 ]]; do case "$1" in --file) f="$2"; shift ;; --key) k="$2"; shift ;; --default) d="$2"; shift ;; --group) shift ;; esac; shift; done
|
||||
[[ "$f" == /* ]] || f="$HOME/.config/$f"
|
||||
r="$(sed -n "s/^$k=//p" "$f" 2>/dev/null)"; printf '%s\n' "${r:-$d}"
|
||||
}
|
||||
# A pretend package database and systemd: what the tests assert on.
|
||||
PKGS=""; PACMAN_LOG="$T/pacman.log"; : > "$PACMAN_LOG"; ENABLED=0
|
||||
pacman() {
|
||||
case "$1" in
|
||||
-Q) [[ " $PKGS " == *" $2 "* ]] ;;
|
||||
-S) echo "S $*" >> "$PACMAN_LOG"; PKGS+=" ${*: -1}" ;;
|
||||
-Rns) echo "R $*" >> "$PACMAN_LOG"; PKGS=" ${PKGS//${*: -1}/} " ;;
|
||||
esac
|
||||
}
|
||||
user_systemctl() {
|
||||
case "$1" in
|
||||
enable) ENABLED=1 ;;
|
||||
disable) ENABLED=0 ;;
|
||||
is-enabled) [[ $ENABLED == 1 ]] ;;
|
||||
esac
|
||||
return 0
|
||||
}
|
||||
FAKE_DRIVER=1; modinfo() { [[ "$FAKE_DRIVER" == 1 ]]; }
|
||||
GAMING_ON=0; gaming_status() { [[ "$GAMING_ON" == 1 ]]; }
|
||||
UNIT="$HOME/.config/systemd/user/$NVIDIA_UNIT"
|
||||
|
||||
mkdir -p "$T/drm/card0/device" "$T/drm/card1/device"
|
||||
echo 0x8086 > "$T/drm/card0/device/vendor"; echo 0x030000 > "$T/drm/card0/device/class"
|
||||
echo 0x10de > "$T/drm/card1/device/vendor"; echo 0x030000 > "$T/drm/card1/device/class"
|
||||
echo 0x2c02 > "$T/drm/card1/device/device"
|
||||
NVIDIA_DRM_DIR="$T/drm"
|
||||
backup_file() { [[ -f "$1.bak" ]] || cp "$1" "$1.bak"; }
|
||||
REBUILDS=0; nvidia_rebuild_boot() { REBUILDS=$((REBUILDS + 1)); }
|
||||
: > "$T/cmdline"; NVIDIA_CMDLINE="$T/cmdline" # the running kernel's command line: without the parameters
|
||||
NVIDIA_INITRAMFS_CONF="$T/90-steamify-nvidia.conf"
|
||||
NVIDIA_SCRIPT="$T/libexec/steamify-nvidia-initramfs"; NVIDIA_HOOK="$T/hooks/85-steamify-nvidia-initramfs.hook"
|
||||
mkdir -p "$T/mods/6.1.0-cachyos/kernel"; : > "$T/mods/6.1.0-cachyos/kernel/nvidia-drm.ko.zst"; : > "$T/mods/6.1.0-cachyos/pkgbase"
|
||||
NVIDIA_MODULES_DIR="$T/mods"
|
||||
NVIDIA_LIMINE_CONF="$T/none/limine.conf"; NVIDIA_SDBOOT_DIR="$T/none/entries"; NVIDIA_GRUB_CFG="$T/none/grub.cfg" # not generated here: not checked
|
||||
mkdir -p "$T/chwd"; VRAM_CHWD_IDS="$T/chwd"
|
||||
# The component's kernel step edits this boot loader file (systemd-boot's) in the tests, never a real one.
|
||||
printf 'LINUX_OPTIONS="quiet"\n' > "$T/sdboot-manage.conf"; nvidia_boot_file() { echo "$T/sdboot-manage.conf"; }
|
||||
|
||||
# --- detection
|
||||
check "finds the NVIDIA card as card1 beside an iGPU" nvidia_present
|
||||
FAKE_DRIVER=0; check "no nvidia_drm module (nouveau): not an NVIDIA PC" '! nvidia_present'
|
||||
FAKE_DRIVER=1; NVIDIA_DRM_DIR="$T/none"; check "no NVIDIA GPU: not an NVIDIA PC" '! nvidia_present'
|
||||
NVIDIA_DRM_DIR="$T/drm"
|
||||
|
||||
# --- which items the menu shows
|
||||
check "NVIDIA PC: the SteamOS conversion and its gamescope options are hidden" '! component_available gaming && ! component_available boot && ! component_available glyphs'
|
||||
check "NVIDIA PC: Gaming on NVIDIA and Big Picture are shown" 'component_available nvidia && component_available bigpicture'
|
||||
GAMING_ON=1
|
||||
check "NVIDIA PC with the conversion already on: it is shown, so it can be turned off" 'component_available gaming && component_available boot'
|
||||
check "...and Gaming on NVIDIA is hidden (both would start Steam)" '! component_available nvidia && ! component_available bigpicture'
|
||||
GAMING_ON=0; NVIDIA_DRM_DIR="$T/none"
|
||||
check "no NVIDIA: the conversion is shown as before" 'component_available gaming && component_available boot'
|
||||
check "...and Gaming on NVIDIA is hidden" '! component_available nvidia && ! component_available bigpicture'
|
||||
NVIDIA_DRM_DIR="$T/drm"
|
||||
|
||||
# --- "Add as non-Steam game" is for gaming mode's controller: not offered on an NVIDIA PC (unless already on)
|
||||
steamgame_available() { return 0; }; STEAMGAME_ON=0; steamgame_status() { [[ "$STEAMGAME_ON" == 1 ]]; }
|
||||
check "NVIDIA PC: Add as non-Steam game is hidden" '! component_available steamgame'
|
||||
STEAMGAME_ON=1; check "...unless it is already on (so it can be turned off)" 'component_available steamgame'; STEAMGAME_ON=0
|
||||
NVIDIA_DRM_DIR="$T/none"; check "no NVIDIA: it is offered as before" 'component_available steamgame'
|
||||
steamgame_available() { return 1; }; check "no NVIDIA, no Steam account yet: still not offered" '! component_available steamgame'
|
||||
steamgame_available() { return 0; }; NVIDIA_DRM_DIR="$T/drm"
|
||||
|
||||
# --- turning it on
|
||||
check "off to begin with" '! nvidia_status && ! bigpicture_status'
|
||||
nvidia_enable
|
||||
check "Steam is installed when missing, and recorded as ours" 'grep -q "^S " "$PACMAN_LOG" && [[ "$(state_get nvidia installed_pkgs)" == steam ]]'
|
||||
check "the autostart unit is written: Steam without arguments" 'grep -q "^ExecStart=/usr/bin/steam $" "$UNIT"'
|
||||
check "it is on" 'nvidia_status && ! bigpicture_status'
|
||||
n="$(wc -l < "$PACMAN_LOG")"; nvidia_enable
|
||||
check "a second run installs nothing again" '[[ "$(wc -l < "$PACMAN_LOG")" == "$n" ]]'
|
||||
|
||||
# --- Big Picture
|
||||
bigpicture_enable
|
||||
check "Big Picture: Steam starts with -gamepadui" 'grep -q "^ExecStart=/usr/bin/steam -gamepadui$" "$UNIT" && bigpicture_status'
|
||||
nvidia_enable
|
||||
check "turning Gaming on NVIDIA on again keeps Big Picture" 'bigpicture_status'
|
||||
check "Big Picture: Plasma starts with an empty session" '[[ "$(kreadconfig6 --file ksmserverrc --group General --key loginMode)" == emptySession ]]'
|
||||
bigpicture_disable
|
||||
check "Big Picture off: Steam's normal window again" '! bigpicture_status && nvidia_status'
|
||||
check "...and the session setting is back as it was (not set)" '[[ -z "$(kreadconfig6 --file ksmserverrc --group General --key loginMode)" ]]'
|
||||
|
||||
# --- turning it off
|
||||
bigpicture_enable; nvidia_disable
|
||||
check "off: the unit is gone and Steam, which we installed, is removed" '! nvidia_status && [[ ! -e "$UNIT" ]] && ! pacman -Q steam && [[ -z "$(state_get nvidia installed_pkgs)" ]]'
|
||||
check "Big Picture without the unit does nothing" 'bigpicture_enable && bigpicture_disable && [[ ! -e "$UNIT" ]]'
|
||||
|
||||
# --- Steam that was there already is never removed
|
||||
PKGS=" steam"; : > "$PACMAN_LOG"
|
||||
nvidia_enable; nvidia_disable
|
||||
check "Steam installed before is kept, and not installed again" '[[ ! -s "$PACMAN_LOG" ]] && pacman -Q steam'
|
||||
|
||||
# --- kernel parameters and early modules (a supported card only: RTX 20 series or newer)
|
||||
check "RTX 5080 (2c02) is supported: no chwd legacy lists" nvidia_supported
|
||||
printf '1c03\n1b80\n' > "$T/chwd/nvidia-580.ids" # a GTX 1060 and a GTX 1080: chwd's 580xx legacy list
|
||||
check "RTX 5080 is not on a legacy list" 'nvidia_supported && ! nvidia_legacy_gpu'
|
||||
echo 0x1c03 > "$T/drm/card1/device/device"
|
||||
check "GTX 1060 (older than RTX 20): no kernel setup, but still an NVIDIA PC" '! nvidia_supported && nvidia_legacy_gpu && nvidia_present'
|
||||
echo 0x2c02 > "$T/drm/card1/device/device"
|
||||
|
||||
for loader in limine limineplus sdboot grub; do
|
||||
case $loader in
|
||||
limine) F="$T/limine"; printf 'KERNEL_CMDLINE[default]="quiet splash"\n' > "$F" ;;
|
||||
# CachyOS writes its line as "+=" and may already have nvidia_drm.modeset=1 in it.
|
||||
limineplus) F="$T/limine"; printf 'KERNEL_CMDLINE[default]+="quiet splash nvidia_drm.modeset=1"\n' > "$F" ;;
|
||||
sdboot) F="$T/sdboot-manage.conf"; printf 'LINUX_OPTIONS="quiet splash"\n' > "$F" ;;
|
||||
grub) F="$T/grub"; printf 'GRUB_CMDLINE_LINUX_DEFAULT="quiet splash"\n' > "$F" ;;
|
||||
esac
|
||||
nvidia_boot_file() { echo "$F"; }
|
||||
rm -f "$NVIDIA_INITRAMFS_CONF"; REBUILDS=0; ORIG="$(cat "$F")"
|
||||
nvidia_kernel_enable
|
||||
check "$loader: parameters added" 'grep -q "nvidia-drm.modeset=1" "$F" && grep -q "nvidia-drm.fbdev=1" "$F"'
|
||||
check "$loader: initramfs drop-in written" 'grep -q nvidia_drm "$NVIDIA_INITRAMFS_CONF"'
|
||||
check "$loader: script and pacman hook installed" '[[ -x "$NVIDIA_SCRIPT" ]] && grep -q "^Exec = $NVIDIA_SCRIPT sync" "$NVIDIA_HOOK"'
|
||||
check "$loader: backup made, rebuilt once" '[[ -f "$F.bak" && $REBUILDS == 1 ]]'
|
||||
SUM="$(cat "$F")"; nvidia_kernel_enable
|
||||
check "$loader: second run changes nothing" '[[ "$(cat "$F")" == "$SUM" && $REBUILDS == 1 ]]'
|
||||
nvidia_kernel_disable
|
||||
check "$loader: disable restores the file, drops the drop-in, script and hook" '[[ "$(cat "$F")" == "$ORIG" && ! -f "$NVIDIA_INITRAMFS_CONF" && ! -e "$NVIDIA_SCRIPT" && ! -e "$NVIDIA_HOOK" ]]'
|
||||
done
|
||||
|
||||
# A missing patches/ file must be an error, never an empty script or hook.
|
||||
( SCRIPT_DIR="$T/no-patches"; NVIDIA_SCRIPT="$T/empty/script"; NVIDIA_HOOK="$T/empty/hook"; ! nvidia_hook_install 2>/dev/null && [[ ! -s "$T/empty/script" ]] ) && echo "ok a missing patch file is an error, nothing empty installed" || { echo "FAIL a missing patch file is an error, nothing empty installed"; fail=1; }
|
||||
# The pacman hook's script decides again at every kernel change.
|
||||
syncit() { NVIDIA_INITRAMFS_CONF="$NVIDIA_INITRAMFS_CONF" NVIDIA_MODULES_DIR="$NVIDIA_MODULES_DIR" bash "$NVIDIA_SCRIPT" sync; }
|
||||
nvidia_hook_install; rm -f "$NVIDIA_INITRAMFS_CONF"
|
||||
syncit; check "hook script: every kernel has the modules -> drop-in written" '[[ -f "$NVIDIA_INITRAMFS_CONF" ]]'
|
||||
mkdir -p "$T/mods/6.6.0-lts/kernel"; : > "$T/mods/6.6.0-lts/pkgbase"
|
||||
syncit; check "hook script: a new kernel without modules -> drop-in removed" '[[ ! -f "$NVIDIA_INITRAMFS_CONF" ]]'
|
||||
: > "$T/mods/6.6.0-lts/kernel/nvidia-drm.ko.zst"
|
||||
syncit; check "hook script: the modules arrive (DKMS built) -> drop-in back" '[[ -f "$NVIDIA_INITRAMFS_CONF" ]]'
|
||||
rm -rf "$T/mods/6.6.0-lts"; mkdir -p "$T/mods/5.0.0-leftover"; : > "$T/mods/5.0.0-leftover/modules.dep"
|
||||
syncit; check "hook script: a leftover folder of a removed kernel is ignored" '[[ -f "$NVIDIA_INITRAMFS_CONF" ]]'
|
||||
rm -rf "$T/mods/5.0.0-leftover"; nvidia_kernel_disable
|
||||
# A second kernel without the NVIDIA modules: no early-load drop-in, parameters still set.
|
||||
mkdir -p "$T/mods/6.6.0-lts/kernel"; : > "$T/mods/6.6.0-lts/pkgbase"; F="$T/sdboot-manage.conf"; printf 'LINUX_OPTIONS="quiet"\n' > "$F"
|
||||
nvidia_boot_file() { echo "$F"; }; rm -f "$NVIDIA_INITRAMFS_CONF"; REBUILDS=0; nvidia_kernel_enable
|
||||
check "kernel without nvidia modules: no drop-in, parameters set" '[[ ! -f "$NVIDIA_INITRAMFS_CONF" ]] && grep -q "nvidia-drm.fbdev=1" "$F"'
|
||||
rm -rf "$T/mods/6.6.0-lts"
|
||||
# Generated boot entries without the parameters (the initramfs build failed): an error.
|
||||
printf 'linux /vmlinuz root=/dev/sda1\n' > "$T/grub.cfg"; NVIDIA_GRUB_CFG="$T/grub.cfg"
|
||||
F="$T/grub"; printf 'GRUB_CMDLINE_LINUX_DEFAULT="quiet"\n' > "$F"; nvidia_boot_file() { echo "$F"; }; rm -f "$NVIDIA_INITRAMFS_CONF"
|
||||
check "boot entries without the parameters: error" '! nvidia_kernel_enable >/dev/null'
|
||||
NVIDIA_GRUB_CFG="$T/none/grub.cfg"
|
||||
# A config file without the setting to edit: an error, not "applied".
|
||||
F="$T/sdboot-manage.conf"; printf '#LINUX_OPTIONS=""\n' > "$F"; nvidia_boot_file() { echo "$F"; }; REBUILDS=0
|
||||
check "no setting to edit: error, nothing rebuilt" '! nvidia_kernel_enable >/dev/null && [[ $REBUILDS == 0 ]]'
|
||||
FAKE_DRIVER=0; NVIDIA_DRM_DIR="$T/drm"; printf 'LINUX_OPTIONS="quiet"\n' > "$T/sdboot"; F="$T/sdboot"; REBUILDS=0; nvidia_kernel_enable
|
||||
check "no NVIDIA driver: nothing touched" '[[ "$(cat "$F")" == "LINUX_OPTIONS=\"quiet\"" && $REBUILDS == 0 ]]'
|
||||
|
||||
# --- single user mode on NVIDIA: its own login step (SDDM, autologin into Plasma) without the conversion
|
||||
FAKE_DRIVER=1; NVIDIA_DRM_DIR="$T/drm" # an earlier section ended without the driver
|
||||
SW="$T/switches.log"; : > "$SW"; TARGET_USER=tester; SINGLE_AUTOLOGIN="$T/sddm.conf.d/zzz-steamify-autologin.conf"
|
||||
switch_to_sddm() { echo sddm >> "$SW"; }; switch_to_plasmalogin() { echo plasmalogin >> "$SW"; }
|
||||
remove_sddm_base_autologin() { :; } # would look at the real /etc/sddm.conf
|
||||
GAMING_ON=0
|
||||
check "single user mode is offered on NVIDIA without the conversion..." 'component_available single'
|
||||
GAMING_ON=1; check "...and with it" 'component_available single'; GAMING_ON=0
|
||||
single_login_enable
|
||||
check "single user: SDDM, autologin of the user into the Plasma session" 'grep -qx "User=tester" "$SINGLE_AUTOLOGIN" && grep -qx "Session=plasma.desktop" "$SINGLE_AUTOLOGIN" && grep -qx "Relogin=true" "$SINGLE_AUTOLOGIN" && grep -qx sddm "$SW"'
|
||||
c1="$(cat "$SINGLE_AUTOLOGIN")"; single_login_enable
|
||||
check "single user login: a second run changes nothing" '[[ "$(cat "$SINGLE_AUTOLOGIN")" == "$c1" ]]'
|
||||
single_login_disable
|
||||
check "single user off: the file is gone and plasma-login-manager is the login manager again" '[[ ! -e "$SINGLE_AUTOLOGIN" ]] && grep -qx plasmalogin "$SW"'
|
||||
: > "$SW"; GAMING_ON=1; single_login_enable
|
||||
check "with the conversion on, single user mode leaves the login to it" '[[ ! -e "$SINGLE_AUTOLOGIN" && ! -s "$SW" ]]'
|
||||
GAMING_ON=0
|
||||
# --- the menu rules
|
||||
declare -A WANTED=([nvidia]=1 [bigpicture]=1 [gaming]=0 [boot]=0 [single]=0 [machine]=0 [poweroff]=0 [launcher]=0 [steamgame]=0)
|
||||
component_selectable() { return 0; }
|
||||
toggle_component nvidia
|
||||
check "unticking Gaming on NVIDIA unticks Big Picture" '[[ "${WANTED[nvidia]}" == 0 && "${WANTED[bigpicture]}" == 0 ]]'
|
||||
toggle_component bigpicture
|
||||
check "ticking Big Picture ticks Gaming on NVIDIA" '[[ "${WANTED[nvidia]}" == 1 && "${WANTED[bigpicture]}" == 1 ]]'
|
||||
WANTED[single]=0; WANTED[gaming]=0; toggle_component single
|
||||
check "ticking single user mode does not tick the conversion where it isn't offered" '[[ "${WANTED[single]}" == 1 && "${WANTED[gaming]}" == 0 ]]'
|
||||
check "Big Picture follows Gaming on NVIDIA in the menu" '[[ " ${COMPONENTS[*]} " == *" nvidia bigpicture "* && "${PARENT[bigpicture]}" == nvidia ]]'
|
||||
|
||||
exit $fail
|
||||
+5
-8
@@ -38,8 +38,8 @@ Item {
|
||||
|
||||
readonly property var status: backend.status || ({})
|
||||
readonly property var items: status.items || []
|
||||
// Hidden: Big Picture excludes a silent start.
|
||||
function hidden(i) { return i.id === "nvsilent" && want.bigpicture; }
|
||||
// Hidden: Big Picture excludes a silent start; on a Steam Machine a silent start needs "Boot into" desktop.
|
||||
function hidden(i) { return (i.id === "nvsilent" && want.bigpicture) || (i.needs === "boot" && boot !== "desktop"); }
|
||||
readonly property var rows: items.filter(function (i) { return (!i.parent || want[i.parent]) && !hidden(i); })
|
||||
readonly property var bios: status.bios || null
|
||||
|
||||
@@ -65,8 +65,7 @@ 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;
|
||||
// (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";
|
||||
boot = nowOn("boot") ? "desktop" : "gamescope";
|
||||
if (sel > rows.length) sel = 0;
|
||||
}
|
||||
Connections { target: backend; function onStatusChanged() { if (app.screen === "menu" || app.screen === "done") app.syncFromStatus(); } }
|
||||
@@ -79,14 +78,13 @@ Item {
|
||||
w[id] = !w[id];
|
||||
// The same rules as the terminal menu (toggle_component).
|
||||
var hasGaming = items.some(function (i) { return i.id === "gaming"; });
|
||||
if (id === "gaming" && !w.gaming) { w.single = false; w.silent = false; w.glyphs = false; }
|
||||
if (id === "gaming" && !w.gaming) { w.single = false; w.silent = false; }
|
||||
if (id === "single" && w.single && hasGaming) w.gaming = true;
|
||||
if (id === "nvidia") w.bigpicture = w.nvidia;
|
||||
if (id === "bigpicture" && w.bigpicture) { w.nvidia = true; w.nvsilent = false; }
|
||||
if (id === "nvsilent" && w.nvsilent) { w.nvidia = true; w.bigpicture = false; }
|
||||
if (id === "nvidia" && !w.nvidia) w.nvsilent = false;
|
||||
if (id === "silent" && w.silent) w.gaming = true;
|
||||
if (id === "glyphs" && w.glyphs) w.gaming = true;
|
||||
if (id === "machine") w.poweroff = w.machine;
|
||||
if (id === "poweroff" && w.poweroff) w.machine = true;
|
||||
if (id === "machine" && !w.machine) w.kpin = false;
|
||||
@@ -102,8 +100,7 @@ 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; }
|
||||
// (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"] });
|
||||
if (want[it.id] && !it.on) p.push({ id: it.id, action: "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" });
|
||||
}
|
||||
|
||||
+2
-2
@@ -6,11 +6,11 @@ QtObject {
|
||||
readonly property var items: ({
|
||||
gaming: { label: "SteamOS conversion", hint: "Boot into gaming mode, Steam on the desktop",
|
||||
body: "Boots straight into gaming mode. Switch to Desktop in Steam works, and Return to Gaming Mode on the desktop brings you back.",
|
||||
changes: ["Autologin into gamescope", "Return to Gaming Mode shortcut"] },
|
||||
changes: ["Autologin into gamescope", "Return to Gaming Mode shortcut", "Steam starts silently on the desktop"] },
|
||||
boot: { label: "Boot into", hint: "Where the PC starts",
|
||||
body: "Where the PC starts after a restart. Switching back and forth works the same either way.",
|
||||
changes: ["Desktop: the Plasma session is set before login", "Gaming: the SteamOS default"] },
|
||||
silent: { label: "Start Steam silently in desktop mode", hint: "In the tray at login on the desktop, no window",
|
||||
silent: { label: "Start Steam silently", hint: "In the tray at login on the desktop, no window",
|
||||
body: "Steam starts by itself when you log in to the Plasma desktop, in the tray without a window. Gaming mode starts its own Steam.",
|
||||
changes: ["Steam is started with -silent (a systemd user service, desktop only)", "Off: the service is removed again"] },
|
||||
nvidia: { label: "Gaming on NVIDIA", hint: "Steam on the desktop, started at login",
|
||||
|
||||
Reference in new issue
Block a user