Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions .github/workflows/nix-flake.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: nix-flake

on:
pull_request:
paths:
- 'flake.nix'
- 'flake.lock'
- 'nix/**'
- 'vds/**'
- '.github/workflows/nix-flake.yml'
push:
branches: [dev, main]
paths:
- 'flake.nix'
- 'flake.lock'
- 'nix/**'
- 'vds/**'
- '.github/workflows/nix-flake.yml'
workflow_dispatch:

jobs:
flake:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: cachix/install-nix-action@v27
- name: flake evaluates
run: nix flake check --no-build
- name: build userspace (vdsd, vdsctl)
run: nix build .#vds --print-build-logs
- name: build kernel module
run: nix build .#vds-module --print-build-logs
71 changes: 70 additions & 1 deletion docs/INSTALLER.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ stream; used by the wizard).
| Debian / Ubuntu | apt: dkms + `linux-headers-$(uname -r)` |
| openSUSE | zypper: dkms + `kernel-default-devel` |
| Bazzite / Silverblue | `rpm-ostree install --idempotent dkms kernel-devel`; requires one reboot, then re-run the installer |
| NixOS | No system changes: writes `./opends5-vds.nix` + `./opends5-vds-src/` for `boot.extraModulePackages`; apply with `nixos-rebuild switch` |
| NixOS | Nothing to run: use the flake (see "NixOS" below). The installer's fallback writes `./opends5-vds.nix` + `./opends5-vds-src/` for non-flake configs |
| Anything else | Clean "unsupported" message; see docs/PORTING.md for manual steps |

On all dkms-based platforms it then stages the module source to
Expand Down Expand Up @@ -67,6 +67,75 @@ checkout) the step is skipped.
The binaries are built in CI on Ubuntu 22.04 (glibc 2.35 baseline), so one
build runs on every 2022-or-newer distribution.

## NixOS

NixOS is configured declaratively, so the installer never escalates and never
modifies the system there. The repo ships a **flake** that replaces the whole
installer — kernel module *and* userspace — with one import.

### Flake (recommended)

Add the input and enable the service in your flake-based configuration:

```nix
{
inputs.opends5.url = "github:LordVicky/OpenDS5";

# in your nixosConfigurations.<host>:
modules = [
inputs.opends5.nixosModules.default
{
services.opends5 = {
enable = true;
users = [ "YOURNAME" ]; # members of the vds group (/dev/vds* access)
};
}
];
}
```

Then `sudo nixos-rebuild switch`. This is the declarative equivalent of
everything the installer does on other distributions:

- builds the `vds_hcd` kernel module from source against *your* configured
kernel (`boot.extraModulePackages`) and autoloads it — no DKMS, no MOK
signing; kernel bumps rebuild it automatically,
- builds `vdsd`/`vdsctl` from the `vds/` source tree (no glibc-prebuilt
binaries, no nix-ld),
- installs the udev rules, the system-wide wireplumber config, the `vds`
group, and the `vdsd` systemd unit.

To run the companion app itself, enable AppImage support
(`programs.appimage = { enable = true; binfmt = true; };`) and run the
release AppImage; the setup wizard will detect a working system and skip
installation.

**Updates**: the AppImage swap updates the app normally, but the driver is
pinned by your flake lock — after an app update, run
`nix flake update opends5 && sudo nixos-rebuild switch` to match. Until then
the running module is the locked version.

Smoke-test the packages without a NixOS machine (any box with Nix):
`nix build .#vds` and `nix build .#vds-module`.

### Generator fallback (non-flake configs)

`--install-system` on NixOS runs entirely unprivileged and writes two things
to the current directory: `opends5-vds.nix` (a module that builds `vds_hcd`
via `boot.extraModulePackages`) and `opends5-vds-src/` (the module source).
Move both next to `configuration.nix`, add
`imports = [ ./opends5-vds.nix ];`, and `sudo nixos-rebuild switch`.

The fallback covers the kernel module only. For userspace, mirror the flake
module by hand: create the `vds` group, add your user, install the udev rules
(`vds-bin/99-vds-dualsense-udev.rules`) via `services.udev.extraRules`, and
run `vdsd` as a systemd service built from the `vds/` source (the prebuilt
Ubuntu binaries need `programs.nix-ld.enable`). Re-run the generator and
rebuild after driver updates.

Verify either path with `lsmod | grep vds_hcd` and `ls /dev/vds*` after the
rebuild (reboot if the kernel changed).

## Setup wizard

On Linux, the app checks at launch whether `vds_hcd` is loaded and
Expand Down
43 changes: 43 additions & 0 deletions flake.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
{
description = "OpenDS5 — virtual DualSense stack (vds_hcd kernel module + vdsd userspace)";

inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";

outputs = { self, nixpkgs }:
let
version =
(builtins.fromJSON
(builtins.readFile ./ds5-bridge/companion/package.json)).version;
systems = [ "x86_64-linux" "aarch64-linux" ];
forAllSystems = f: nixpkgs.lib.genAttrs systems
(system: f nixpkgs.legacyPackages.${system});
in
{
# Single source of truth for the module/package version (the app
# version; matches what DKMS stamps on other distros).
opends5Version = version;

packages = forAllSystems (pkgs: rec {
vds = pkgs.callPackage ./nix/vds.nix { inherit version; };
# Standalone module build against the default nixpkgs kernel, mainly
# for `nix build .#vds-module` smoke tests. The NixOS module builds
# against the host's configured kernel instead.
vds-module = pkgs.callPackage ./nix/vds-module.nix {
kernel = pkgs.linuxPackages.kernel;
inherit version;
};
default = vds;
});

nixosModules = rec {
opends5 = import ./nix/nixos-module.nix self;
default = opends5;
};

devShells = forAllSystems (pkgs: {
default = pkgs.mkShell {
inputsFrom = [ self.packages.${pkgs.stdenv.hostPlatform.system}.vds ];
};
});
};
}
65 changes: 65 additions & 0 deletions nix/nixos-module.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# NixOS module for OpenDS5: kernel module + userspace daemon + udev rules
# + wireplumber config. The declarative equivalent of everything
# installer/opends5-install does on other distributions.
self:
{ config, lib, pkgs, ... }:

let
cfg = config.services.opends5;
in
{
options.services.opends5 = {
enable = lib.mkEnableOption "OpenDS5 virtual DualSense stack";

package = lib.mkOption {
type = lib.types.package;
default = self.packages.${pkgs.stdenv.hostPlatform.system}.vds;
defaultText = lib.literalExpression "opends5.packages.<system>.vds";
description = "The vds userspace package (vdsd, vdsctl, rules).";
};

users = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [ ];
example = [ "alice" ];
description = "Users added to the vds group (access to /dev/vds*).";
};
};

config = lib.mkIf cfg.enable {
boot.extraModulePackages = [
(pkgs.callPackage ./vds-module.nix {
kernel = config.boot.kernelPackages.kernel;
version = self.opends5Version;
})
];
boot.kernelModules = [ "vds_hcd" ];

users.groups.vds = { };
users.users = lib.genAttrs cfg.users (_: {
extraGroups = [ "vds" ];
});

services.udev.packages = [ cfg.package ];

environment.systemPackages = [ cfg.package ];

# Session-manager config for the controller's audio path; the system-wide
# conf.d is merged by wireplumber alongside any per-user config.
environment.etc."wireplumber/wireplumber.conf.d/99-vds-dualsense.conf".source =
"${cfg.package}/share/wireplumber/wireplumber.conf.d/99-vds-dualsense.conf";

systemd.services.vdsd = {
description = "vDS userspace daemon (OpenDS5)";
after = [ "bluetooth.service" ];
wants = [ "bluetooth.service" ];
wantedBy = [ "multi-user.target" ];
serviceConfig = {
Type = "simple";
ExecStart = "${cfg.package}/bin/vdsd";
Restart = "on-failure";
RestartSec = "1s";
};
};
};
}
40 changes: 40 additions & 0 deletions nix/vds-module.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# vds_hcd kernel module, built out-of-tree against the given kernel.
# Instantiated by the NixOS module with config.boot.kernelPackages.kernel,
# so it always matches the configured kernel and rebuilds on kernel bumps.
{ lib
, stdenv
, kernel
, version
}:

stdenv.mkDerivation {
pname = "vds_hcd";
inherit version;

# Kbuild references ../include, so the source root is the whole vds tree.
src = ../vds;

hardeningDisable = [ "pic" ];
nativeBuildInputs = kernel.moduleBuildDependencies;

makeFlags = [
"-C" "module"
"KERNELRELEASE=${kernel.modDirVersion}"
"KDIR=${kernel.dev}/lib/modules/${kernel.modDirVersion}/build"
"VDS_VERSION=${version}"
];

installPhase = ''
runHook preInstall
install -D module/vds_hcd.ko \
$out/lib/modules/${kernel.modDirVersion}/extra/vds_hcd.ko
runHook postInstall
'';

meta = with lib; {
description = "vDS virtual USB host controller kernel module (OpenDS5)";
homepage = "https://github.com/LordVicky/OpenDS5";
license = licenses.mit;
platforms = platforms.linux;
};
}
54 changes: 54 additions & 0 deletions nix/vds.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# Userspace stack: the vdsd daemon and vdsctl CLI, built from the in-tree
# vds/ source. Also installs the udev rules and wireplumber config so the
# NixOS module can reference them from one package.
{ lib
, stdenv
, cmake
, pkg-config
, bluez
, dbus
, libopus
, udev
, version
}:

stdenv.mkDerivation {
pname = "vds";
inherit version;

src = ../vds;

nativeBuildInputs = [ cmake pkg-config ];
buildInputs = [ bluez dbus libopus udev ];

# generate-version.sh needs the git repo (absent in the sandbox); the build
# falls back to "unknown" without this.
postPatch = ''
cat > generate-version.sh <<EOF
#!/bin/sh
echo ${version}
EOF
chmod +x generate-version.sh
'';

# Upstream install() also runs service-registration hooks; install the
# binaries and support files directly instead.
installPhase = ''
runHook preInstall
install -Dm755 vdsd $out/bin/vdsd
install -Dm755 vdsctl $out/bin/vdsctl
install -Dm644 ../99-vds-dualsense-udev.rules \
$out/lib/udev/rules.d/99-vds-dualsense.rules
install -Dm644 ../99-vds-dualsense-wireplumber.conf \
$out/share/wireplumber/wireplumber.conf.d/99-vds-dualsense.conf
runHook postInstall
'';

meta = with lib; {
description = "vDS virtual DualSense userspace daemon (OpenDS5)";
homepage = "https://github.com/LordVicky/OpenDS5";
license = licenses.mit;
platforms = platforms.linux;
mainProgram = "vdsd";
};
}
Loading