From 820012785e6296209ce73f35f451142ff21d2fb9 Mon Sep 17 00:00:00 2001 From: derped Date: Sat, 19 Jul 2025 11:46:29 +0200 Subject: [PATCH] services/hhhd: init handheld-daemon with tdp --- pkgs/adjustor/default.nix | 65 +++++++++++++ pkgs/hhd/0001-remove-selinux-fixes.patch | 37 ++++++++ pkgs/hhd/default.nix | 111 +++++++++++++++++++++++ pkgs/nixpkgs.nix | 2 + services/handheld-daemon.nix | 17 ++++ 5 files changed, 232 insertions(+) create mode 100644 pkgs/adjustor/default.nix create mode 100644 pkgs/hhd/0001-remove-selinux-fixes.patch create mode 100644 pkgs/hhd/default.nix create mode 100644 services/handheld-daemon.nix diff --git a/pkgs/adjustor/default.nix b/pkgs/adjustor/default.nix new file mode 100644 index 0000000..acb2042 --- /dev/null +++ b/pkgs/adjustor/default.nix @@ -0,0 +1,65 @@ +{ + fetchFromGitHub, + lib, + + buildPythonPackage, + setuptools, + rich, + pyroute2, + fuse, + pygobject3, + dbus-python, + + # Dependencies + kmod, + util-linux, +}: + +buildPythonPackage rec { + pname = "adjustor"; + version = "3.6.1"; + pyproject = true; + + src = fetchFromGitHub { + owner = "hhd-dev"; + repo = "adjustor"; + rev = "refs/tags/v${version}"; + hash = "sha256-A5IdwuhsK9umMtsUR7CpREGxbTYuJNPV4MT+6wqcWT8="; + }; + + # This package relies on several programs expected to be on the user's PATH. + # We take a more reproducible approach by patching the absolute path to each of these required + # binaries. + postPatch = '' + substituteInPlace src/adjustor/core/acpi.py \ + --replace-fail '"modprobe"' '"${lib.getExe' kmod "modprobe"}"' + + substituteInPlace src/adjustor/fuse/utils.py \ + --replace-fail 'f"mount' 'f"${lib.getExe' util-linux "mount"}' + ''; + + build-system = [ + setuptools + ]; + + dependencies = [ + rich + pyroute2 + fuse + pygobject3 + dbus-python + kmod + ]; + + # This package doesn't have upstream tests. + doCheck = false; + + meta = with lib; { + homepage = "https://github.com/hhd-dev/adjustor/"; + description = "Adjustor TDP plugin for Handheld Daemon"; + platforms = platforms.linux; + license = licenses.gpl3Only; + maintainers = with maintainers; [ toast ]; + mainProgram = "hhd"; + }; +} diff --git a/pkgs/hhd/0001-remove-selinux-fixes.patch b/pkgs/hhd/0001-remove-selinux-fixes.patch new file mode 100644 index 0000000..2fe3ae7 --- /dev/null +++ b/pkgs/hhd/0001-remove-selinux-fixes.patch @@ -0,0 +1,37 @@ +diff --git a/src/hhd/plugins/power/power.py b/src/hhd/plugins/power/power.py +index 5ece857..be41542 100644 +--- a/src/hhd/plugins/power/power.py ++++ b/src/hhd/plugins/power/power.py +@@ -79,12 +79,6 @@ def create_subvol(): + ) + return + +- # Fixup selinux for swap +- subprocess.run( +- ["semanage", "fcontext", "-a", "-t", "var_t", HHD_SWAP_SUBVOL], +- ) +- subprocess.run(["restorecon", HHD_SWAP_SUBVOL]) +- + logger.info(f"Creating swap subvolume {HHD_SWAP_SUBVOL}") + os.system(f"btrfs subvolume create {HHD_SWAP_SUBVOL}") + +@@ -153,19 +147,6 @@ def create_temporary_swap(): + subprocess.run(["chmod", "600", HHD_SWAP_FILE], check=True) + subprocess.run(["mkswap", HHD_SWAP_FILE], check=True) + +- # Fixup selinux for swap +- subprocess.run( +- [ +- "semanage", +- "fcontext", +- "-a", +- "-t", +- "swapfile_t", +- HHD_SWAP_FILE, +- ], +- ) +- subprocess.run(["restorecon", HHD_SWAP_FILE]) +- + # Enable swap + subprocess.run(["swapon", HHD_SWAP_FILE], check=True) + diff --git a/pkgs/hhd/default.nix b/pkgs/hhd/default.nix new file mode 100644 index 0000000..c44e06d --- /dev/null +++ b/pkgs/hhd/default.nix @@ -0,0 +1,111 @@ +{ + lib, + python3Packages, + fetchFromGitHub, + + # dependencies + adjustor, + systemd, + hidapi, + coreutils, + kmod, + efibootmgr, + dbus, + lsof, + btrfs-progs, + util-linux, +}: + +python3Packages.buildPythonApplication rec { + pname = "handheld-daemon"; + version = "3.15.10"; + pyproject = true; + + src = fetchFromGitHub { + owner = "hhd-dev"; + repo = "hhd"; + tag = "v${version}"; + hash = "sha256-VlFcozpW6JQs1jsit6cE3pOZLqJR4IS6nmNDqeTygKo="; + }; + + # Handheld-daemon runs some selinux-related utils which are not in nixpkgs. + # NixOS doesn't support selinux so we can safely remove them + patches = [ ./0001-remove-selinux-fixes.patch ]; + + # This package relies on several programs expected to be on the user's PATH. + # We take a more reproducible approach by patching the absolute path to each of these required + # binaries. + postPatch = '' + substituteInPlace src/hhd/controller/lib/hid.py \ + --replace-fail "libhidapi" "${lib.getLib hidapi}/lib/libhidapi" + + substituteInPlace src/hhd/controller/lib/hide.py \ + --replace-fail "/bin/chmod" "${lib.getExe' coreutils "chmod"}" \ + --replace-fail "udevadm" "${lib.getExe' systemd "udevadm"}" + + substituteInPlace src/hhd/controller/physical/evdev.py \ + --replace-fail "udevadm" "${lib.getExe' systemd "udevadm"}" + + substituteInPlace src/hhd/controller/physical/imu.py \ + --replace-fail '"modprobe' '"${lib.getExe' kmod "modprobe"}' + + substituteInPlace src/hhd/plugins/power/power.py \ + --replace-fail '"efibootmgr"' '"${lib.getExe' efibootmgr "id"}"' \ + --replace-fail '"systemctl"' '"${lib.getExe' systemd "systemctl"}"' \ + --replace-fail '"stat"' '"${lib.getExe' coreutils "stat"}"' \ + --replace-fail '"swapon"' '"${lib.getExe' util-linux "swapon"}"' \ + --replace-fail '"swapoff"' '"${lib.getExe' util-linux "swapoff"}"' \ + --replace-fail '"fallocate"' '"${lib.getExe' util-linux "fallocate"}"' \ + --replace-fail '"chmod"' '"${lib.getExe' coreutils "chmod"}"' \ + --replace-fail '"mkswap"' '"${lib.getExe' util-linux "mkswap"}"' \ + --replace-fail '"btrfs",' '"${lib.getExe' btrfs-progs "btrfs"}",' + + substituteInPlace src/hhd/device/oxp/serial.py \ + --replace-fail "udevadm" "${lib.getExe' systemd "udevadm"}" + + substituteInPlace src/hhd/plugins/overlay/systemd.py \ + --replace-fail "dbus-monitor" "${lib.getExe' dbus "dbus-monitor"}" \ + --replace-fail "systemd-inhibit" "${lib.getExe' systemd "systemd-inhibit"}" + + substituteInPlace src/hhd/plugins/overlay/x11.py \ + --replace-fail "lsof" "${lib.getExe lsof}" + + substituteInPlace src/hhd/plugins/plugin.py \ + --replace-fail '"id"' '"${lib.getExe' coreutils "id"}"' + ''; + + build-system = with python3Packages; [ + setuptools + ]; + + dependencies = with python3Packages; [ + adjustor + evdev + pyserial + pyyaml + rich + setuptools + xlib + ]; + + # This package doesn't have upstream tests. + doCheck = false; + + postInstall = '' + install -Dm644 $src/usr/lib/udev/rules.d/83-hhd.rules -t $out/lib/udev/rules.d/ + install -Dm644 $src/usr/lib/udev/hwdb.d/83-hhd.hwdb -t $out/lib/udev/hwdb.d/ + ''; + + meta = { + homepage = "https://github.com/hhd-dev/hhd/"; + description = "Linux support for handheld gaming devices like the Legion Go, ROG Ally, and GPD Win"; + platforms = lib.platforms.linux; + changelog = "https://github.com/hhd-dev/hhd/releases/tag/${src.tag}"; + license = lib.licenses.gpl3Only; + maintainers = with lib.maintainers; [ + appsforartists + toast + ]; + mainProgram = "hhd"; + }; +} diff --git a/pkgs/nixpkgs.nix b/pkgs/nixpkgs.nix index 56ce7b5..eb54d64 100644 --- a/pkgs/nixpkgs.nix +++ b/pkgs/nixpkgs.nix @@ -22,6 +22,8 @@ in theme_sddm_midnight = callPackage ./sddm_midnight { }; xdiskusage = callPackage ./xdiskusage { }; kanagawa = callPackage ./kanagawa { }; + adjustor = pkgs.python3Packages.callPackage ./adjustor { }; + hhd = callPackage ./hhd { }; } // import ./scripts { inherit pkgs; }; }; overlays = [ diff --git a/services/handheld-daemon.nix b/services/handheld-daemon.nix new file mode 100644 index 0000000..ee39bca --- /dev/null +++ b/services/handheld-daemon.nix @@ -0,0 +1,17 @@ +{ + config, + lib, + pkgs, + ... +}: + +with lib; + +mkIf (elem "handheld-daemon" config.machine.services) { + services.handheld-daemon = { + enable = true; + package = pkgs.hhd; + user = (lib.elemAt config.machine.users 0).name; + ui.enable = true; + }; +}