Windows virtual gamepads now have zero external dependencies - ViGEmBus is removed. - DualShock 4: Windows UMDF backend (inject/dualshock4_windows.rs + dualshock4_proto.rs), reusing the DualSense SwDeviceCreate game-detection identity fix. The one UMDF driver serves the DS5 or DS4 identity/descriptor/features/strings per a device_type byte the host stamps into shared memory. Driver also gains IOCTL_HID_GET_STRING and a 41-byte calibration feature. - Xbox 360: a new UMDF2 XUSB companion driver (packaging/windows/xusb-driver/) that registers GUID_DEVINTERFACE_XUSB and answers the buffered XInput IOCTLs from a shared section, so classic XInputGetState/SetState work with no kernel bus driver. inject/gamepad_windows.rs is rewritten to drive it and the vigem-client dependency is removed. Xbox One folds to the 360 XInput path. - Installer: vendor + pnputil-install the three UMDF drivers (packaging/windows/gamepad-drivers/ + install-gamepad-drivers.ps1, wired into pack-host-installer.ps1 + punktfunk-host.iss). - Multi-pad: the host stamps each pad index into the device Location (pszDeviceLocation); the driver reads it via WdfDeviceAllocAndQueryProperty to map its own *-shm-<index>, with UmdfHostProcessSharing=ProcessSharingDisabled giving each pad its own host (per-pad statics). Validated live on the Windows host: Cyberpunk native DualSense detection, DS4 identity + descriptor, XInputGetState + rumble round-trip, two pads -> two distinct XInput slots, and a full installer build. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Packaging punktfunk for Fedora / Bazzite
The punktfunk host is Linux-only and links system FFmpeg (NVENC), PipeWire, Opus and the NVIDIA driver. This directory packages it for the Fedora Atomic / Bazzite world (rpm-ostree + bootc), where most of those deps are already present.
👉 Ubuntu/Debian hosts install via
aptfrom Gitea's package registry — seedebian/README.md(apt update && apt upgradefor new builds).
👉 End-to-end Bazzite setup walkthrough (install → udev/group →
host.env→ service → firewall → verify → troubleshooting):bazzite/README.md. This file is the higher-level packaging rationale.
packaging/
rpm/punktfunk.spec # the RPM (builds punktfunk-host from source with cargo)
bazzite/host.env # gamescope-default config for a Bazzite appliance
bazzite/README.md # step-by-step Bazzite setup guide
bootc/Containerfile # bake punktfunk into a Bazzite-based atomic image
copr/ # COPR build-from-SCM settings
What's needed beyond base Fedora
| Dependency | Where it comes from |
|---|---|
ffmpeg-libs with NVENC |
RPM Fusion nonfree (ffmpeg, not ffmpeg-free) |
NVIDIA driver (libnvidia-encode, libEGL_nvidia) |
Bazzite -nvidia images ship it; plain Fedora: akmod-nvidia + xorg-x11-drv-nvidia-cuda |
| gamescope, PipeWire, wireplumber | Bazzite ships these; plain Fedora: dnf install gamescope pipewire wireplumber |
opus, libei |
Fedora base / updates |
On Bazzite the only genuinely new runtime bits are ffmpeg-libs (RPM Fusion) + opus +
libei — the rest of the stack is already there. The default backend is gamescope
(packaging/bazzite/host.env), which the host spawns headless per session — no desktop login.
Option A — Gitea RPM registry (recommended; per-host, rpm-ostree)
The host's RPM is published to unom's self-hosted Gitea RPM registry (CI builds it on every
push), mirroring the Debian/apt setup. Add one repo file, install, and track
updates with rpm-ostree upgrade — no COPR account needed. Full guide: rpm/README.md.
# GPG-signed pkgs + Gitea-signed metadata → gpgcheck=1, repo_gpgcheck=1 (see rpm/README.md)
sudo tee /etc/yum.repos.d/punktfunk.repo >/dev/null <<'REPO'
[gitea-unom-bazzite]
name=punktfunk (unom, Bazzite)
baseurl=https://git.unom.io/api/packages/unom/rpm/bazzite
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://git.unom.io/api/packages/unom/rpm/repository.key
https://git.unom.io/api/packages/unom/generic/punktfunk-keys/1/RPM-GPG-KEY-punktfunk
REPO
rpm-ostree install punktfunk && systemctl reboot
# updates: rpm-ostree upgrade && systemctl reboot
Option B — COPR (per-host, rpm-ostree install)
- Create a COPR project, enable build-from-SCM pointing at this repo, spec path
packaging/rpm/punktfunk.spec(seecopr/README.md). Under External Repositories add RPM Fusion nonfree soffmpeg-develresolves at build time. - On the Bazzite host:
# RPM Fusion (for the NVENC ffmpeg) — usually already enabled on Bazzite rpm-ostree install \ https://mirrors.rpmfusion.org/free/fedora/rpmfusion-free-release-$(rpm -E %fedora).noarch.rpm \ https://mirrors.rpmfusion.org/nonfree/fedora/rpmfusion-nonfree-release-$(rpm -E %fedora).noarch.rpm # enable the COPR + install punktfunk sudo wget -O /etc/yum.repos.d/_copr_punktfunk.repo \ https://copr.fedorainfracloud.org/coprs/enricobuehler/punktfunk/repo/fedora-$(rpm -E %fedora)/ rpm-ostree install punktfunk systemctl reboot
Option B — bootc (image-based, atomic)
Layer punktfunk into a Bazzite image once, then rebase any number of hosts onto it — no
per-host drift. See bootc/Containerfile:
podman build -t ghcr.io/<you>/bazzite-punktfunk -f packaging/bootc/Containerfile .
podman push ghcr.io/<you>/bazzite-punktfunk
# on the target:
sudo bootc switch ghcr.io/<you>/bazzite-punktfunk && systemctl reboot
First-run setup (either option)
ujust add-user-to-input-group # virtual gamepads need /dev/uinput (then re-login).
# On Bazzite use ujust, NOT `usermod -aG input` (atomic OS — it won't stick).
mkdir -p ~/.config/punktfunk
cp /usr/share/punktfunk/host.env.bazzite ~/.config/punktfunk/host.env # edit (gamescope app, etc.)
systemctl --user enable --now punktfunk-host
# Management web console (pairing + status) — pulled in by default (the host RPM Recommends it;
# `--no-install-recommends` / headless-only boxes can skip it). Enable it and read the login password:
systemctl --user enable --now punktfunk-web
journalctl --user -u punktfunk-web-init | sed -n 's/.*password generated: //p' # then open http://<host-ip>:3000
Pair a stock Moonlight client (mDNS-discovered), or connect the native punktfunk/1 client — via the
web console at http://<host-ip>:3000 or directly.
⚠️ COPR caveat: COPR's mock chroot has no
bun, so a COPR build produces onlypunktfunk+punktfunk-client— notpunktfunk-web. For the console on a COPR/bootc host, install from the Gitea RPM registry (Option A — it carriespunktfunk-web), which is also whybootc/Containerfileinstalls from there rather than COPR.
Why not Flatpak (for the HOST)?
The host needs unsandboxed access the zero-copy NVENC path, /dev/uinput, the PipeWire
graph and the compositor's privileged protocols — a Flatpak sandbox fights all of these.
An RPM (or the bootc layer) installs into the host system where those just work.
👉 The client is a different story — it IS shipped as a Flatpak (the only viable Steam Deck install path: SteamOS
/usris read-only and lackslibadwaita/libSDL3). Seeflatpak/README.md. The client sandbox only needs the GPU render node, Wayland, PipeWire audio, the network and hidraw — all expressible as finish-args.
Building the SRPM/RPM locally (Fedora only)
git archive --format=tar.gz --prefix=punktfunk-0.0.1/ -o ~/rpmbuild/SOURCES/punktfunk-0.0.1.tar.gz HEAD
rpmbuild -ba packaging/rpm/punktfunk.spec # needs the BuildRequires from the spec
(Not buildable on Debian/Ubuntu — use a Fedora toolbox/container or COPR.)