From 45a1985e78c19b072380ebad18099a2750981b93 Mon Sep 17 00:00:00 2001 From: Jonathan Ringer Date: Mon, 14 Sep 2026 14:46:20 -0700 Subject: [PATCH 01/14] ekaos/facter: extend lib.nix with SMBIOS vendor quirk framework Add device-matching helpers for hardware quirks: hasManufacturer, hasProduct, isDevice, plus common presets (isFramework, isThinkPad, isDellXps, isAsusRog, isSurface). Also add hasPciDevice, hasUsbVendor, and isConvertibleChassis utilities for broader hardware detection. --- ekaos/modules/hardware/facter/lib.nix | 109 ++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) diff --git a/ekaos/modules/hardware/facter/lib.nix b/ekaos/modules/hardware/facter/lib.nix index 5f835ef40..0335e6588 100644 --- a/ekaos/modules/hardware/facter/lib.nix +++ b/ekaos/modules/hardware/facter/lib.nix @@ -88,6 +88,93 @@ let "0${hex}" else hex; + # SMBIOS vendor/product matching for device quirks + hasManufacturer = + name: + { + smbios ? { }, + ... + }: + lib.hasInfix name ((smbios.system or { }).manufacturer or ""); + + hasProduct = + pattern: + { + smbios ? { }, + ... + }: + lib.hasInfix pattern ((smbios.system or { }).product_name or ""); + + isDevice = + { + manufacturer, + product ? null, + }: + report: hasManufacturer manufacturer report && (product == null || hasProduct product report); + + # Query if a facter report contains a PCI device with the given vendor and device IDs + hasPciDevice = + vendorId: deviceId: + { + hardware ? { }, + ... + }: + let + allPci = + (hardware.graphics_card or [ ]) + ++ (hardware.network_controller or [ ]) + ++ (hardware.storage_controller or [ ]) + ++ (hardware.multimedia_controller or [ ]); + in + builtins.any ( + { + vendor ? { }, + device ? { }, + ... + }: + (vendor.value or 0) == vendorId && (device.value or 0) == deviceId + ) allPci; + + # Query if a facter report contains a USB device with the given vendor ID + hasUsbVendor = + vendorId: + { + hardware ? { }, + ... + }: + let + allUsb = + (hardware.fingerprint_reader or [ ]) + ++ (hardware.joystick or [ ]) + ++ (hardware.scanner or [ ]) + ++ (hardware.printer or [ ]); + in + builtins.any ( + { + vendor ? { }, + ... + }: + (vendor.value or 0) == vendorId + ) allUsb; + + # Check if the facter report indicates a convertible/tablet chassis + # SMBIOS: 30=Tablet, 31=Convertible, 32=Detachable + isConvertibleChassis = + { + smbios ? { }, + ... + }: + builtins.any ( + { + chassis_type ? { }, + ... + }: + builtins.elem (chassis_type.value or 0) [ + 30 + 31 + 32 + ] + ) (smbios.chassis or [ ]); in { inherit @@ -97,6 +184,12 @@ in collectDrivers stringSet toZeroPaddedHex + hasManufacturer + hasProduct + isDevice + hasPciDevice + hasUsbVendor + isConvertibleChassis ; hasAmdCpu = hasCpu "AuthenticAMD"; @@ -106,4 +199,20 @@ in hasAmdGpu = hasGpuVendor 4098; hasIntelGpu = hasGpuVendor 32902; hasNvidiaGpu = hasGpuVendor 4318; + + # Common device checks + isFramework = hasManufacturer "Framework"; + isSurface = isDevice { + manufacturer = "Microsoft Corporation"; + product = "Surface"; + }; + isThinkPad = hasProduct "ThinkPad"; + isAsusRog = isDevice { + manufacturer = "ASUSTeK"; + product = "ROG"; + }; + isDellXps = isDevice { + manufacturer = "Dell"; + product = "XPS"; + }; } From 689d616c59f12e66aa741f9637632f855d9929ff Mon Sep 17 00:00:00 2001 From: Jonathan Ringer Date: Mon, 14 Sep 2026 14:47:04 -0700 Subject: [PATCH 02/14] ekaos/facter: add hardware detection modules Add facter auto-detection modules for audio/SOF, fingerprint readers, gaming peripherals, printers, scanners, and touchscreens. Each module detects hardware from the facter report and exposes detection flags at hardware.facter.detected.* for downstream consumers. --- ekaos/modules/hardware/facter/audio.nix | 75 +++++++++++++++++++ ekaos/modules/hardware/facter/default.nix | 6 ++ ekaos/modules/hardware/facter/fingerprint.nix | 48 ++++++++++++ ekaos/modules/hardware/facter/gaming.nix | 46 ++++++++++++ ekaos/modules/hardware/facter/printing.nix | 28 +++++++ ekaos/modules/hardware/facter/scanner.nix | 26 +++++++ ekaos/modules/hardware/facter/touchscreen.nix | 45 +++++++++++ 7 files changed, 274 insertions(+) create mode 100644 ekaos/modules/hardware/facter/audio.nix create mode 100644 ekaos/modules/hardware/facter/fingerprint.nix create mode 100644 ekaos/modules/hardware/facter/gaming.nix create mode 100644 ekaos/modules/hardware/facter/printing.nix create mode 100644 ekaos/modules/hardware/facter/scanner.nix create mode 100644 ekaos/modules/hardware/facter/touchscreen.nix diff --git a/ekaos/modules/hardware/facter/audio.nix b/ekaos/modules/hardware/facter/audio.nix new file mode 100644 index 000000000..452f30805 --- /dev/null +++ b/ekaos/modules/hardware/facter/audio.nix @@ -0,0 +1,75 @@ +# Auto-detect audio hardware and configure sound device support +{ + lib, + config, + ... +}: +let + facterLib = import ./lib.nix lib; + inherit (config.hardware.facter) report; + cfg = config.hardware.facter.detected.audio; + isBaremetal = config.hardware.facter.detected.virtualisation.none.enable; + + soundDevices = report.hardware.sound or [ ]; + driverModules = facterLib.collectDrivers soundDevices; + + # Detect Intel SOF (Sound Open Firmware) audio by driver module names + hasSofDriver = builtins.any ( + m: lib.hasPrefix "snd_sof" m || lib.hasPrefix "snd-sof" m + ) driverModules; + + # Detect Intel HDA audio + hasHdaDriver = builtins.any ( + m: lib.hasPrefix "snd_hda" m || lib.hasPrefix "snd-hda" m + ) driverModules; +in +{ + options.hardware.facter.detected.audio = { + enable = lib.mkEnableOption "Facter audio hardware detection" // { + default = builtins.length soundDevices > 0; + defaultText = "hardware dependent"; + }; + + kernelModules = lib.mkOption { + type = lib.types.listOf lib.types.str; + default = lib.unique driverModules; + defaultText = "hardware dependent"; + description = "Kernel modules for detected audio hardware."; + }; + + sof.enable = lib.mkEnableOption "Facter Intel SOF audio detection" // { + default = hasSofDriver; + defaultText = "hardware dependent"; + }; + + hda.enable = lib.mkEnableOption "Facter Intel HDA audio detection" // { + default = hasHdaDriver; + defaultText = "hardware dependent"; + }; + }; + + config = lib.mkIf config.hardware.facter.enable ( + lib.mkMerge [ + # Load audio driver modules + (lib.mkIf cfg.enable { + boot.initrd.availableKernelModules = cfg.kernelModules; + }) + + # Intel SOF audio: load additional SOF-specific modules + (lib.mkIf (cfg.enable && cfg.sof.enable) { + boot.kernelModules = [ + "snd_sof" + "snd_sof_pci" + "snd_sof_intel_hda_common" + ]; + }) + + # Intel HDA audio + (lib.mkIf (cfg.enable && cfg.hda.enable) { + boot.kernelModules = [ + "snd_hda_intel" + ]; + }) + ] + ); +} diff --git a/ekaos/modules/hardware/facter/default.nix b/ekaos/modules/hardware/facter/default.nix index 046df362d..d20610545 100644 --- a/ekaos/modules/hardware/facter/default.nix +++ b/ekaos/modules/hardware/facter/default.nix @@ -8,20 +8,26 @@ }: { imports = [ + ./audio.nix ./boot.nix ./bluetooth.nix ./bluetooth-stack.nix ./cpu.nix ./disk.nix + ./fingerprint.nix ./firmware.nix ./fwupd.nix + ./gaming.nix ./gpu.nix ./graphics.nix ./keyboard.nix ./laptop.nix ./networking.nix + ./printing.nix + ./scanner.nix ./system.nix ./thermal.nix + ./touchscreen.nix ./trackpoint.nix ./virtualisation.nix ]; diff --git a/ekaos/modules/hardware/facter/fingerprint.nix b/ekaos/modules/hardware/facter/fingerprint.nix new file mode 100644 index 000000000..92b24985a --- /dev/null +++ b/ekaos/modules/hardware/facter/fingerprint.nix @@ -0,0 +1,48 @@ +# Auto-detect fingerprint readers and enable fprintd +{ + lib, + config, + ... +}: +let + inherit (config.hardware.facter) report; + isBaremetal = config.hardware.facter.detected.virtualisation.none.enable; + + fingerprintDevices = report.hardware.fingerprint_reader or [ ]; + + # Known fingerprint reader USB vendor IDs + # Goodix (0x27c6=10182), Synaptics/WBDI (0x06cb=1739), Elan (0x04f3=1267), + # AuthenTec (0x147e=5246), Validity/Synaptics (0x138a=5002) + knownVendors = [ + 10182 + 1739 + 1267 + 5246 + 5002 + ]; + + hasFingerprint = builtins.length fingerprintDevices > 0; + + # Check if detected device is from a known vendor (for confidence) + hasKnownDevice = builtins.any ( + { + vendor ? { }, + ... + }: + builtins.elem (vendor.value or 0) knownVendors + ) fingerprintDevices; +in +{ + options.hardware.facter.detected.fingerprint.enable = + lib.mkEnableOption "Facter fingerprint reader detection" + // { + default = hasFingerprint && isBaremetal; + defaultText = "hardware dependent"; + }; + + config = + lib.mkIf (config.hardware.facter.enable && config.hardware.facter.detected.fingerprint.enable) + { + services.fprintd.enable = lib.mkDefault true; + }; +} diff --git a/ekaos/modules/hardware/facter/gaming.nix b/ekaos/modules/hardware/facter/gaming.nix new file mode 100644 index 000000000..a9a6fa776 --- /dev/null +++ b/ekaos/modules/hardware/facter/gaming.nix @@ -0,0 +1,46 @@ +# Auto-detect gaming peripherals (gamepads, joysticks) +{ + lib, + config, + ... +}: +let + facterLib = import ./lib.nix lib; + inherit (config.hardware.facter) report; + isBaremetal = config.hardware.facter.detected.virtualisation.none.enable; + + joystickDevices = report.hardware.joystick or [ ]; + hasJoystick = builtins.length joystickDevices > 0; + + driverModules = facterLib.collectDrivers joystickDevices; +in +{ + options.hardware.facter.detected.gaming = { + enable = lib.mkEnableOption "Facter gaming peripheral detection" // { + default = hasJoystick && isBaremetal; + defaultText = "hardware dependent"; + }; + + kernelModules = lib.mkOption { + type = lib.types.listOf lib.types.str; + default = lib.unique driverModules; + defaultText = "hardware dependent"; + description = "Kernel modules for detected gaming peripherals."; + }; + }; + + config = lib.mkIf (config.hardware.facter.enable && config.hardware.facter.detected.gaming.enable) { + # Load detected gamepad/joystick driver modules + boot.kernelModules = config.hardware.facter.detected.gaming.kernelModules; + + # Common gamepad kernel modules that may not be in the facter report + # but are needed for hot-plugged controllers + boot.initrd.availableKernelModules = [ + "xpad" # Xbox controllers + "hid-sony" # PlayStation controllers + "hid-nintendo" # Nintendo controllers + ]; + + # TODO(corepkgs): Port steam-hardware udev rules for controller support + }; +} diff --git a/ekaos/modules/hardware/facter/printing.nix b/ekaos/modules/hardware/facter/printing.nix new file mode 100644 index 000000000..133d83069 --- /dev/null +++ b/ekaos/modules/hardware/facter/printing.nix @@ -0,0 +1,28 @@ +# Auto-detect printer hardware for CUPS enablement +{ + lib, + config, + ... +}: +let + inherit (config.hardware.facter) report; + isBaremetal = config.hardware.facter.detected.virtualisation.none.enable; + + printerDevices = report.hardware.printer or [ ]; + hasPrinter = builtins.length printerDevices > 0; +in +{ + options.hardware.facter.detected.printing.enable = + lib.mkEnableOption "Facter printer detection" + // { + default = hasPrinter && isBaremetal; + defaultText = "hardware dependent"; + }; + + config = + lib.mkIf (config.hardware.facter.enable && config.hardware.facter.detected.printing.enable) + { + # TODO(corepkgs): Port services.printing (CUPS) module, then enable: + # services.printing.enable = lib.mkDefault true; + }; +} diff --git a/ekaos/modules/hardware/facter/scanner.nix b/ekaos/modules/hardware/facter/scanner.nix new file mode 100644 index 000000000..7f83f75dc --- /dev/null +++ b/ekaos/modules/hardware/facter/scanner.nix @@ -0,0 +1,26 @@ +# Auto-detect scanner hardware for SANE enablement +{ + lib, + config, + ... +}: +let + inherit (config.hardware.facter) report; + isBaremetal = config.hardware.facter.detected.virtualisation.none.enable; + + scannerDevices = report.hardware.scanner or [ ]; + hasScanner = builtins.length scannerDevices > 0; +in +{ + options.hardware.facter.detected.scanner.enable = lib.mkEnableOption "Facter scanner detection" // { + default = hasScanner && isBaremetal; + defaultText = "hardware dependent"; + }; + + config = + lib.mkIf (config.hardware.facter.enable && config.hardware.facter.detected.scanner.enable) + { + # TODO(corepkgs): Port hardware.sane module (sane-backends), then enable: + # hardware.sane.enable = lib.mkDefault true; + }; +} diff --git a/ekaos/modules/hardware/facter/touchscreen.nix b/ekaos/modules/hardware/facter/touchscreen.nix new file mode 100644 index 000000000..dc93b46f0 --- /dev/null +++ b/ekaos/modules/hardware/facter/touchscreen.nix @@ -0,0 +1,45 @@ +# Auto-detect touchscreen input devices +{ + lib, + config, + ... +}: +let + facterLib = import ./lib.nix lib; + inherit (config.hardware.facter) report; + cfg = config.hardware.facter.detected.touchscreen; + isBaremetal = config.hardware.facter.detected.virtualisation.none.enable; + + # Touchscreen devices appear as input hardware in facter report + # They may be in touchscreen-specific or generic input lists + touchscreenDevices = report.hardware.touchscreen or [ ]; + + # Also check for convertible/tablet chassis which implies touchscreen + isConvertible = facterLib.isConvertibleChassis report; + + driverModules = facterLib.collectDrivers touchscreenDevices; +in +{ + options.hardware.facter.detected.touchscreen = { + enable = lib.mkEnableOption "Facter touchscreen detection" // { + default = (builtins.length touchscreenDevices > 0 || isConvertible) && isBaremetal; + defaultText = "hardware dependent"; + }; + + convertible.enable = lib.mkEnableOption "Facter convertible/tablet detection" // { + default = isConvertible && isBaremetal; + defaultText = "hardware dependent"; + }; + }; + + config = lib.mkIf (config.hardware.facter.enable && cfg.enable) { + # Load touchscreen driver modules + boot.initrd.availableKernelModules = lib.unique driverModules; + + # Ensure libinput handles touch input (Wayland/Hyprland) + # libinput is typically already configured but ensure modules are loaded + boot.kernelModules = lib.mkIf cfg.convertible.enable [ + "hid-multitouch" + ]; + }; +} From 429774ae88c5bb077078020aad89a9f12ad6790b Mon Sep 17 00:00:00 2001 From: Jonathan Ringer Date: Mon, 14 Sep 2026 14:47:12 -0700 Subject: [PATCH 03/14] upower: init at 1.91.3 --- pkgs/upower/default.nix | 118 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 118 insertions(+) create mode 100644 pkgs/upower/default.nix diff --git a/pkgs/upower/default.nix b/pkgs/upower/default.nix new file mode 100644 index 000000000..558bfc5cb --- /dev/null +++ b/pkgs/upower/default.nix @@ -0,0 +1,118 @@ +{ + lib, + stdenv, + fetchFromGitLab, + makeWrapper, + pkg-config, + libxslt, + meson, + ninja, + python3, + docbook-xsl-nons, + udev, + libgudev, + libusb1, + glib, + gettext, + polkit, + gobject-introspection, + systemd, +}: + +stdenv.mkDerivation (finalAttrs: { + pname = "upower"; + version = "1.91.3"; + + outputs = [ + "out" + "dev" + ]; + + src = fetchFromGitLab { + domain = "gitlab.freedesktop.org"; + owner = "upower"; + repo = "upower"; + rev = "v${finalAttrs.version}"; + hash = "sha256-QdAJxaua43iGovQeRg+n1MypS5CS0Ro3gqF9Tv8eMBg="; + }; + + strictDeps = true; + + depsBuildBuild = [ + pkg-config + ]; + + nativeBuildInputs = [ + meson + meson.configurePhaseHook + ninja + python3 + docbook-xsl-nons + gettext + libxslt + makeWrapper + pkg-config + glib + gobject-introspection + ]; + + buildInputs = [ + libgudev + libusb1 + udev + systemd + ]; + + propagatedBuildInputs = [ + glib + polkit + ]; + + mesonFlags = [ + "--localstatedir=/var" + "--sysconfdir=/etc" + "-Dos_backend=linux" + "-Dsystemdsystemunitdir=${placeholder "out"}/etc/systemd/system" + "-Dudevrulesdir=${placeholder "out"}/lib/udev/rules.d" + "-Dudevhwdbdir=${placeholder "out"}/lib/udev/hwdb.d" + "-Dintrospection=enabled" + "-Dgtk-doc=false" + "-Didevice=disabled" + ]; + + postPatch = '' + patchShebangs src/linux/integration-test.py + patchShebangs src/linux/unittest_inspector.py + ''; + + env = { + # Install configuration files to $out/etc + # but upower reads from /etc on the running system. + # Meson does not support overriding at install time, + # so use DESTDIR and move in postInstall. + DESTDIR = "dest"; + }; + + postInstall = '' + # Move from DESTDIR to proper location + for o in $(getAllOutputNames); do + if [[ "$o" = "devdoc" ]]; then continue; fi + mv "$DESTDIR''${!o}" "$(dirname "''${!o}")" + done + + mv "$DESTDIR/var" "$out" + cp --recursive "$DESTDIR/etc" "$out" + rm --recursive "$DESTDIR/etc" + + rmdir --parents --ignore-fail-on-non-empty "$DESTDIR${builtins.storeDir}" + ! test -e "$DESTDIR" + ''; + + meta = { + homepage = "https://upower.freedesktop.org/"; + description = "D-Bus service for power management"; + mainProgram = "upower"; + platforms = lib.platforms.linux; + license = lib.licenses.gpl2Plus; + }; +}) From ab889fdd05407a11ea67efa41f42c311dec7470f Mon Sep 17 00:00:00 2001 From: Jonathan Ringer Date: Mon, 14 Sep 2026 14:47:42 -0700 Subject: [PATCH 04/14] bolt: init at 0.9.8 Add Thunderbolt 3 device management daemon, ekaos service module at services.hardware.bolt, and facter/thunderbolt.nix auto-detection that enables boltd when Thunderbolt controllers are detected. --- ekaos/modules/hardware/facter/default.nix | 1 + ekaos/modules/hardware/facter/thunderbolt.nix | 35 ++++++++ ekaos/modules/module-list.nix | 1 + ekaos/modules/services/hardware/bolt.nix | 38 +++++++++ pkgs/bolt/default.nix | 83 +++++++++++++++++++ 5 files changed, 158 insertions(+) create mode 100644 ekaos/modules/hardware/facter/thunderbolt.nix create mode 100644 ekaos/modules/services/hardware/bolt.nix create mode 100644 pkgs/bolt/default.nix diff --git a/ekaos/modules/hardware/facter/default.nix b/ekaos/modules/hardware/facter/default.nix index d20610545..d585a5d12 100644 --- a/ekaos/modules/hardware/facter/default.nix +++ b/ekaos/modules/hardware/facter/default.nix @@ -27,6 +27,7 @@ ./scanner.nix ./system.nix ./thermal.nix + ./thunderbolt.nix ./touchscreen.nix ./trackpoint.nix ./virtualisation.nix diff --git a/ekaos/modules/hardware/facter/thunderbolt.nix b/ekaos/modules/hardware/facter/thunderbolt.nix new file mode 100644 index 000000000..dd59f831b --- /dev/null +++ b/ekaos/modules/hardware/facter/thunderbolt.nix @@ -0,0 +1,35 @@ +# Auto-detect Thunderbolt/USB4 controllers +{ + lib, + config, + ... +}: +let + inherit (config.hardware.facter) report; + isBaremetal = config.hardware.facter.detected.virtualisation.none.enable; + + # Thunderbolt controllers appear as PCI devices + # Intel Thunderbolt: vendor 0x8086 (32902), various device IDs + # The facter report may list them under a dedicated category or as generic PCI + thunderboltDevices = report.hardware.thunderbolt_controller or [ ]; + + hasThunderbolt = builtins.length thunderboltDevices > 0; +in +{ + options.hardware.facter.detected.thunderbolt.enable = + lib.mkEnableOption "Facter Thunderbolt/USB4 detection" + // { + default = hasThunderbolt && isBaremetal; + defaultText = "hardware dependent"; + }; + + config = + lib.mkIf (config.hardware.facter.enable && config.hardware.facter.detected.thunderbolt.enable) + { + # Load thunderbolt kernel module for device authorization + boot.kernelModules = [ "thunderbolt" ]; + + # Enable boltd for Thunderbolt device authorization + services.hardware.bolt.enable = lib.mkDefault true; + }; +} diff --git a/ekaos/modules/module-list.nix b/ekaos/modules/module-list.nix index eafc0ef94..93a2ee9c7 100644 --- a/ekaos/modules/module-list.nix +++ b/ekaos/modules/module-list.nix @@ -161,6 +161,7 @@ ./services/databases/postgresql.nix ./services/databases/redis.nix + ./services/hardware/bolt.nix ./services/hardware/thermald.nix ./services/hardware/fwupd.nix ./services/hardware/fprintd.nix diff --git a/ekaos/modules/services/hardware/bolt.nix b/ekaos/modules/services/hardware/bolt.nix new file mode 100644 index 000000000..2fc2a0ab4 --- /dev/null +++ b/ekaos/modules/services/hardware/bolt.nix @@ -0,0 +1,38 @@ +# Thunderbolt 3 device management daemon +# Ported from nixpkgs/nixos/modules/services/hardware/bolt.nix +{ + config, + lib, + pkgs, + ... +}: +let + cfg = config.services.hardware.bolt; +in +{ + options.services.hardware.bolt = { + enable = lib.mkOption { + type = lib.types.bool; + default = false; + description = '' + Whether to enable Bolt, a userspace daemon to enable + security levels for Thunderbolt 3 on GNU/Linux. + ''; + }; + + package = lib.mkOption { + type = lib.types.package; + default = pkgs.bolt or (throw "bolt package not available"); + defaultText = lib.literalExpression "pkgs.bolt"; + description = "The bolt package to use."; + }; + }; + + config = lib.mkIf cfg.enable { + environment.systemPackages = [ cfg.package ]; + services.udev.packages = [ cfg.package ]; + + # TODO: systemd.packages not yet available in ekaOS + # systemd.packages = [ cfg.package ]; + }; +} diff --git a/pkgs/bolt/default.nix b/pkgs/bolt/default.nix new file mode 100644 index 000000000..3610e6008 --- /dev/null +++ b/pkgs/bolt/default.nix @@ -0,0 +1,83 @@ +{ + stdenv, + lib, + meson, + ninja, + pkg-config, + fetchFromGitLab, + fetchpatch, + asciidoc, + libxml2, + libxslt, + docbook_xml_dtd_45, + docbook-xsl-nons, + glib, + systemd, + polkit, +}: + +stdenv.mkDerivation (finalAttrs: { + pname = "bolt"; + version = "0.9.8"; + + src = fetchFromGitLab { + domain = "gitlab.freedesktop.org"; + owner = "bolt"; + repo = "bolt"; + tag = finalAttrs.version; + hash = "sha256-sDPipSIT2MJMdsOjOQSB+uOe6KXzVnyAqcQxPPr2NsU="; + }; + + patches = [ + # Test does not work on ZFS with atime disabled. + # Upstream issue: https://gitlab.freedesktop.org/bolt/bolt/-/issues/167 + (fetchpatch { + url = "https://gitlab.freedesktop.org/bolt/bolt/-/commit/c2f1d5c40ad71b20507e02faa11037b395fac2f8.diff"; + revert = true; + hash = "sha256-6w7ll65W/CydrWAVi/qgzhrQeDv1PWWShulLxoglF+I="; + }) + ]; + + depsBuildBuild = [ + pkg-config + ]; + + nativeBuildInputs = [ + asciidoc + docbook_xml_dtd_45 + docbook-xsl-nons + libxml2 + libxslt + meson + meson.configurePhaseHook + ninja + pkg-config + glib + ]; + + buildInputs = [ + polkit + systemd + ]; + + postPatch = '' + patchShebangs scripts tests + ''; + + mesonFlags = [ + "-Dlocalstatedir=/var" + ]; + + env = { + PKG_CONFIG_SYSTEMD_SYSTEMDSYSTEMUNITDIR = "${placeholder "out"}/lib/systemd/system"; + PKG_CONFIG_UDEV_UDEVDIR = "${placeholder "out"}/lib/udev"; + }; + + meta = { + description = "Thunderbolt 3 device management daemon"; + mainProgram = "boltctl"; + homepage = "https://gitlab.freedesktop.org/bolt/bolt"; + license = lib.licenses.lgpl21Plus; + platforms = lib.platforms.linux; + }; +}) From ce9c6caf1875b0154798e30007c061ad40122f9b Mon Sep 17 00:00:00 2001 From: Jonathan Ringer Date: Mon, 14 Sep 2026 14:47:57 -0700 Subject: [PATCH 05/14] power-profiles-daemon: init at 0.30 Add D-Bus power profile switching daemon, ekaos service module at services.power-profiles-daemon, and facter/power.nix auto-detection that enables PPD on battery-equipped bare-metal systems. --- ekaos/modules/hardware/facter/default.nix | 1 + ekaos/modules/hardware/facter/power.nix | 48 ++++++++++ ekaos/modules/module-list.nix | 1 + .../hardware/power-profiles-daemon.nix | 39 ++++++++ pkgs/power-profiles-daemon/default.nix | 92 +++++++++++++++++++ 5 files changed, 181 insertions(+) create mode 100644 ekaos/modules/hardware/facter/power.nix create mode 100644 ekaos/modules/services/hardware/power-profiles-daemon.nix create mode 100644 pkgs/power-profiles-daemon/default.nix diff --git a/ekaos/modules/hardware/facter/default.nix b/ekaos/modules/hardware/facter/default.nix index d585a5d12..459fec2f5 100644 --- a/ekaos/modules/hardware/facter/default.nix +++ b/ekaos/modules/hardware/facter/default.nix @@ -23,6 +23,7 @@ ./keyboard.nix ./laptop.nix ./networking.nix + ./power.nix ./printing.nix ./scanner.nix ./system.nix diff --git a/ekaos/modules/hardware/facter/power.nix b/ekaos/modules/hardware/facter/power.nix new file mode 100644 index 000000000..d2d27b34e --- /dev/null +++ b/ekaos/modules/hardware/facter/power.nix @@ -0,0 +1,48 @@ +# Auto-detect battery and configure extended power management +{ + lib, + config, + ... +}: +let + facterLib = import ./lib.nix lib; + inherit (config.hardware.facter) report; + cfg = config.hardware.facter.detected.power; + isBaremetal = config.hardware.facter.detected.virtualisation.none.enable; + isLaptop = config.hardware.facter.detected.laptop.enable; + + # Detect battery from facter report + batteries = report.hardware.battery or [ ]; + hasBattery = builtins.length batteries > 0; + + # Detect swap for hibernate readiness + swapDevices = report.swap or [ ]; + hasSwap = builtins.length swapDevices > 0; +in +{ + options.hardware.facter.detected.power = { + battery.enable = lib.mkEnableOption "Facter battery detection" // { + default = hasBattery || isLaptop; + defaultText = "hardware dependent"; + }; + + hibernate.enable = lib.mkEnableOption "Facter hibernate readiness" // { + default = hasBattery && hasSwap && isBaremetal; + defaultText = "hardware dependent"; + }; + }; + + config = lib.mkIf config.hardware.facter.enable ( + lib.mkMerge [ + # Battery detected: optimize for power saving + (lib.mkIf (cfg.battery.enable && isBaremetal) { + # SCSI link power management for battery life + power.scsiLinkPolicy = lib.mkDefault "med_power_with_dipm"; + + # Enable power-profiles-daemon for D-Bus power profile switching + # (used by Quickshell power profile switcher) + services.power-profiles-daemon.enable = lib.mkDefault true; + }) + ] + ); +} diff --git a/ekaos/modules/module-list.nix b/ekaos/modules/module-list.nix index 93a2ee9c7..4a71d9386 100644 --- a/ekaos/modules/module-list.nix +++ b/ekaos/modules/module-list.nix @@ -162,6 +162,7 @@ ./services/databases/redis.nix ./services/hardware/bolt.nix + ./services/hardware/power-profiles-daemon.nix ./services/hardware/thermald.nix ./services/hardware/fwupd.nix ./services/hardware/fprintd.nix diff --git a/ekaos/modules/services/hardware/power-profiles-daemon.nix b/ekaos/modules/services/hardware/power-profiles-daemon.nix new file mode 100644 index 000000000..a23e122fa --- /dev/null +++ b/ekaos/modules/services/hardware/power-profiles-daemon.nix @@ -0,0 +1,39 @@ +# Power Profiles Daemon — D-Bus daemon for user-selected power profiles +# Ported from nixpkgs/nixos/modules/services/hardware/power-profiles-daemon.nix +{ + config, + lib, + pkgs, + ... +}: +let + cfg = config.services.power-profiles-daemon; +in +{ + options.services.power-profiles-daemon = { + enable = lib.mkOption { + type = lib.types.bool; + default = false; + description = '' + Whether to enable power-profiles-daemon, a D-Bus daemon that allows + changing system behavior based upon user-selected power profiles. + ''; + }; + + package = lib.mkOption { + type = lib.types.package; + default = pkgs.power-profiles-daemon or (throw "power-profiles-daemon package not available"); + defaultText = lib.literalExpression "pkgs.power-profiles-daemon"; + description = "The power-profiles-daemon package to use."; + }; + }; + + config = lib.mkIf cfg.enable { + environment.systemPackages = [ cfg.package ]; + services.dbus.packages = [ cfg.package ]; + services.udev.packages = [ cfg.package ]; + + # TODO: systemd.packages not yet available in ekaOS + # systemd.packages = [ cfg.package ]; + }; +} diff --git a/pkgs/power-profiles-daemon/default.nix b/pkgs/power-profiles-daemon/default.nix new file mode 100644 index 000000000..4b1f27554 --- /dev/null +++ b/pkgs/power-profiles-daemon/default.nix @@ -0,0 +1,92 @@ +{ + stdenv, + lib, + pkg-config, + meson, + ninja, + fetchFromGitLab, + libgudev, + glib, + polkit, + gobject-introspection, + gettext, + gtk-doc, + docbook-xsl-nons, + docbook_xml_dtd_412, + libxml2, + libxslt, + upower, + systemd, + python3, +}: + +stdenv.mkDerivation (finalAttrs: { + pname = "power-profiles-daemon"; + version = "0.30"; + + outputs = [ + "out" + "devdoc" + ]; + + src = fetchFromGitLab { + domain = "gitlab.freedesktop.org"; + owner = "upower"; + repo = "power-profiles-daemon"; + rev = finalAttrs.version; + hash = "sha256-iQUhA46BEln8pyIBxM/MY7An8BzfiFjxZdR/tUIj4S4="; + }; + + nativeBuildInputs = [ + pkg-config + meson + meson.configurePhaseHook + ninja + gettext + gtk-doc + docbook-xsl-nons + docbook_xml_dtd_412 + libxml2 + libxslt + gobject-introspection + python3 + ]; + + buildInputs = [ + libgudev + systemd + upower + glib + polkit + ]; + + strictDeps = true; + + mesonFlags = [ + "-Dsystemdsystemunitdir=${placeholder "out"}/lib/systemd/system" + "-Dgtk_doc=true" + "-Dpylint=disabled" + "-Dtests=false" + "-Dmanpage=disabled" + "-Dbashcomp=disabled" + "-Dzshcomp=${placeholder "out"}/share/zsh/site-functions" + ]; + + env.PKG_CONFIG_POLKIT_GOBJECT_1_POLICYDIR = "${placeholder "out"}/share/polkit-1/actions"; + + postPatch = '' + patchShebangs --host \ + src/powerprofilesctl + ''; + + # TODO(corepkgs): Port pygobject3 Python package for full powerprofilesctl support. + # The CLI tool needs pygobject3 at runtime for GObject introspection bindings. + + meta = { + homepage = "https://gitlab.freedesktop.org/upower/power-profiles-daemon"; + description = "Makes user-selected power profiles handling available over D-Bus"; + mainProgram = "powerprofilesctl"; + platforms = lib.platforms.linux; + license = lib.licenses.gpl3Plus; + }; +}) From 1c6d24df2dcec5a6e8ec2d0318f6bad01e828986 Mon Sep 17 00:00:00 2001 From: Jonathan Ringer Date: Mon, 14 Sep 2026 14:48:05 -0700 Subject: [PATCH 06/14] ipu6-camera-bins, ipu6-camera-hal, ivsc-firmware: init Port Intel IPU6 camera stack: firmware binaries (ipu6-camera-bins), userspace HAL with Tiger Lake/Alder Lake/Meteor Lake variants (ipu6-camera-hal), and Vision Sensing Controller firmware (ivsc-firmware). Add ipu6ep-camera-hal and ipu6epmtl-camera-hal override entries in top-level.nix. --- pkgs/ipu6-camera-bins/default.nix | 61 ++++++++++++++++++ pkgs/ipu6-camera-hal/default.nix | 102 ++++++++++++++++++++++++++++++ pkgs/ivsc-firmware/default.nix | 47 ++++++++++++++ top-level.nix | 8 +++ 4 files changed, 218 insertions(+) create mode 100644 pkgs/ipu6-camera-bins/default.nix create mode 100644 pkgs/ipu6-camera-hal/default.nix create mode 100644 pkgs/ivsc-firmware/default.nix diff --git a/pkgs/ipu6-camera-bins/default.nix b/pkgs/ipu6-camera-bins/default.nix new file mode 100644 index 000000000..a959a8e26 --- /dev/null +++ b/pkgs/ipu6-camera-bins/default.nix @@ -0,0 +1,61 @@ +{ + lib, + stdenv, + fetchFromGitHub, + autoPatchelfHook, + expat, + zlib, +}: + +stdenv.mkDerivation (finalAttrs: { + pname = "ipu6-camera-bins"; + version = "unstable-2025-06-27"; + + src = fetchFromGitHub { + repo = "ipu6-camera-bins"; + owner = "intel"; + tag = "20250923_ov02e"; + hash = "sha256-YPPzuK13o2jnRSB3ORoMUU5E9/IifKVSetAqZHRofhw="; + }; + + nativeBuildInputs = [ + autoPatchelfHook + (lib.getLib stdenv.cc.cc) + expat + zlib + ]; + + installPhase = '' + runHook preInstall + + mkdir -p $out + cp --no-preserve=mode --recursive \ + lib \ + include \ + $out/ + + runHook postInstall + ''; + + postFixup = '' + for lib in $out/lib/lib*.so.*; do \ + lib=''${lib##*/}; \ + ln -s $lib $out/lib/''${lib%.*}; \ + done + + for pcfile in $out/lib/pkgconfig/*.pc; do + substituteInPlace $pcfile \ + --replace 'prefix=/usr' "prefix=$out" + done + ''; + + meta = { + description = "IPU firmware and proprietary image processing libraries"; + homepage = "https://github.com/intel/ipu6-camera-bins"; + license = lib.licenses.issl; + sourceProvenance = with lib.sourceTypes; [ + binaryFirmware + ]; + platforms = [ "x86_64-linux" ]; + }; +}) diff --git a/pkgs/ipu6-camera-hal/default.nix b/pkgs/ipu6-camera-hal/default.nix new file mode 100644 index 000000000..a5e7e646f --- /dev/null +++ b/pkgs/ipu6-camera-hal/default.nix @@ -0,0 +1,102 @@ +{ + lib, + stdenv, + fetchFromGitHub, + + # build + cmake, + pkg-config, + + # runtime + expat, + ipu6-camera-bins, + libtool, + gst_all_1, + libdrm, + + # Pick one of + # - ipu6 (Tiger Lake) + # - ipu6ep (Alder Lake) + # - ipu6epmtl (Meteor Lake) + ipuVersion ? "ipu6", +}: +let + ipuTarget = + { + "ipu6" = "ipu_tgl"; + "ipu6ep" = "ipu_adl"; + "ipu6epmtl" = "ipu_mtl"; + } + .${ipuVersion}; +in +stdenv.mkDerivation { + pname = "${ipuVersion}-camera-hal"; + version = "unstable-2025-06-27"; + + src = fetchFromGitHub { + owner = "intel"; + repo = "ipu6-camera-hal"; + tag = "20250923_ov02e"; + hash = "sha256-ZWwszteRmUBn0wGgN5rmzw/onfzBoPGadcmpk+93kAM="; + }; + + nativeBuildInputs = [ + cmake + cmake.configurePhaseHook + pkg-config + ]; + + cmakeFlags = [ + "-DCMAKE_BUILD_TYPE=Release" + "-DCMAKE_INSTALL_PREFIX=${placeholder "out"}" + "-DCMAKE_INSTALL_LIBDIR=lib" + "-DCMAKE_POLICY_VERSION_MINIMUM=3.5" + "-DBUILD_CAMHAL_ADAPTOR=ON" + "-DBUILD_CAMHAL_PLUGIN=ON" + "-DIPU_VERSIONS=${ipuVersion}" + "-DUSE_PG_LITE_PIPE=ON" + ]; + + env.NIX_CFLAGS_COMPILE = toString [ + "-Wno-error" + ]; + + enableParallelBuilding = true; + + buildInputs = [ + expat + ipu6-camera-bins + libtool + gst_all_1.gstreamer + gst_all_1.gst-plugins-base + libdrm + ]; + + postPatch = '' + substituteInPlace src/platformdata/PlatformData.h \ + --replace '/usr/share/' "${placeholder "out"}/share/" \ + --replace '#define CAMERA_DEFAULT_CFG_PATH "/etc/camera/"' '#define CAMERA_DEFAULT_CFG_PATH "${placeholder "out"}/etc/camera/"' + ''; + + postInstall = '' + mkdir -p $out/include/${ipuTarget}/ + cp -r $src/include $out/include/${ipuTarget}/libcamhal + ''; + + postFixup = '' + for lib in $out/lib/*.so; do + patchelf --add-rpath "${ipu6-camera-bins}/lib" $lib + done + ''; + + passthru = { + inherit ipuVersion ipuTarget; + }; + + meta = { + description = "HAL for processing of images in userspace"; + homepage = "https://github.com/intel/ipu6-camera-hal"; + license = lib.licenses.asl20; + platforms = [ "x86_64-linux" ]; + }; +} diff --git a/pkgs/ivsc-firmware/default.nix b/pkgs/ivsc-firmware/default.nix new file mode 100644 index 000000000..65015e1ee --- /dev/null +++ b/pkgs/ivsc-firmware/default.nix @@ -0,0 +1,47 @@ +{ + lib, + stdenv, + fetchFromGitHub, +}: + +stdenv.mkDerivation { + pname = "ivsc-firmware"; + version = "unstable-2024-06-14"; + + src = fetchFromGitHub { + owner = "intel"; + repo = "ivsc-firmware"; + rev = "74a01d1208a352ed85d76f959c68200af4ead918"; + hash = "sha256-kHYfeftMtoOsOtVN6+XoDMDHP7uTEztbvjQLpCnKCh0="; + }; + + dontBuild = true; + + installPhase = '' + runHook preInstall + + mkdir -p $out/lib/firmware/vsc + cp --no-preserve=mode --recursive ./firmware/* $out/lib/firmware/vsc/ + install -D ./LICENSE $out/share/doc + + mkdir -p $out/lib/firmware/vsc/soc_a1_prod + # According to Intel's documentation for prod platform the a1_prod postfix is needed + # (https://github.com/intel/ivsc-firmware) + # This fixes ipu6 webcams + for file in $out/lib/firmware/vsc/*.bin; do + ln -sf "$file" "$out/lib/firmware/vsc/soc_a1_prod/$(basename "$file" .bin)_a1_prod.bin" + done + + runHook postInstall + ''; + + meta = { + description = "Firmware binaries for the Intel Vision Sensing Controller"; + homepage = "https://github.com/intel/ivsc-firmware"; + license = lib.licenses.issl; + sourceProvenance = with lib.sourceTypes; [ + binaryFirmware + ]; + platforms = [ "x86_64-linux" ]; + }; +} diff --git a/top-level.nix b/top-level.nix index f56a7fb12..cd96a1888 100644 --- a/top-level.nix +++ b/top-level.nix @@ -1024,6 +1024,14 @@ with final; else lib.getBin prev.libiconv; + ipu6ep-camera-hal = ipu6-camera-hal.override { + ipuVersion = "ipu6ep"; + }; + + ipu6epmtl-camera-hal = ipu6-camera-hal.override { + ipuVersion = "ipu6epmtl"; + }; + openssl_legacy = openssl.override { conf = ./pkgs-many/openssl/3.0/legacy.cnf; }; From 767eb54cf1314b9cdb2f31f27a809c5de8eed48c Mon Sep 17 00:00:00 2001 From: Jonathan Ringer Date: Mon, 14 Sep 2026 14:48:30 -0700 Subject: [PATCH 07/14] ekaos/hardware: add IPU6 camera module Add hardware.ipu6 option module for Intel IPU6/MIPI camera support with platform selection (Tiger Lake, Alder Lake, Meteor Lake). Handles kernel driver loading, firmware installation, udev rules, and platform-specific camera HAL. Facter auto-detects IPU6 hardware by PCI device ID and sets the correct platform variant. --- ekaos/modules/hardware/facter/camera.nix | 77 +++++++++++++++++++++ ekaos/modules/hardware/facter/default.nix | 1 + ekaos/modules/hardware/ipu6.nix | 82 +++++++++++++++++++++++ ekaos/modules/module-list.nix | 1 + 4 files changed, 161 insertions(+) create mode 100644 ekaos/modules/hardware/facter/camera.nix create mode 100644 ekaos/modules/hardware/ipu6.nix diff --git a/ekaos/modules/hardware/facter/camera.nix b/ekaos/modules/hardware/facter/camera.nix new file mode 100644 index 000000000..d5ba430b4 --- /dev/null +++ b/ekaos/modules/hardware/facter/camera.nix @@ -0,0 +1,77 @@ +# Auto-detect Intel IPU6 camera hardware and configure platform +{ + lib, + config, + ... +}: +let + facterLib = import ./lib.nix lib; + inherit (config.hardware.facter) report; + + # Intel IPU6 PCI device IDs per CPU generation + # Vendor: Intel (0x8086 = 32902) + tigerLakeId = 39449; # 0x9a19 + alderLakeId = 18013; # 0x465d + raptorLakeId = 42845; # 0xa75d + meteorLakeId = 32025; # 0x7d19 + + allIpu6Ids = [ + tigerLakeId + alderLakeId + raptorLakeId + meteorLakeId + ]; + + multimediaDevices = report.hardware.multimedia_controller or [ ]; + + # Find the matching IPU6 device + ipu6Device = lib.findFirst ( + { + vendor ? { }, + device ? { }, + ... + }: + (vendor.value or 0) == 32902 && builtins.elem (device.value or 0) allIpu6Ids + ) null multimediaDevices; + + hasIpu6 = ipu6Device != null; + + # Determine platform from the detected device ID + detectedDeviceId = if hasIpu6 then (ipu6Device.device.value or 0) else 0; + + detectedPlatform = + if detectedDeviceId == tigerLakeId then + "ipu6" + else if detectedDeviceId == alderLakeId || detectedDeviceId == raptorLakeId then + "ipu6ep" + else if detectedDeviceId == meteorLakeId then + "ipu6epmtl" + else + "ipu6"; +in +{ + options.hardware.facter.detected.camera.ipu6 = { + enable = lib.mkEnableOption "Facter Intel IPU6 camera detection" // { + default = hasIpu6; + defaultText = "hardware dependent"; + }; + + platform = lib.mkOption { + type = lib.types.enum [ + "ipu6" + "ipu6ep" + "ipu6epmtl" + ]; + default = detectedPlatform; + defaultText = "hardware dependent"; + description = "Auto-detected IPU6 platform variant based on CPU generation."; + }; + }; + + config = + lib.mkIf (config.hardware.facter.enable && config.hardware.facter.detected.camera.ipu6.enable) + { + hardware.ipu6.enable = lib.mkDefault true; + hardware.ipu6.platform = lib.mkDefault config.hardware.facter.detected.camera.ipu6.platform; + }; +} diff --git a/ekaos/modules/hardware/facter/default.nix b/ekaos/modules/hardware/facter/default.nix index 459fec2f5..71deb12a5 100644 --- a/ekaos/modules/hardware/facter/default.nix +++ b/ekaos/modules/hardware/facter/default.nix @@ -12,6 +12,7 @@ ./boot.nix ./bluetooth.nix ./bluetooth-stack.nix + ./camera.nix ./cpu.nix ./disk.nix ./fingerprint.nix diff --git a/ekaos/modules/hardware/ipu6.nix b/ekaos/modules/hardware/ipu6.nix new file mode 100644 index 000000000..b6d2cf635 --- /dev/null +++ b/ekaos/modules/hardware/ipu6.nix @@ -0,0 +1,82 @@ +# Intel IPU6/MIPI camera hardware configuration +# Simplified from nixpkgs for ekaos +{ + config, + lib, + pkgs, + ... +}: +let + cfg = config.hardware.ipu6; +in +{ + options.hardware.ipu6 = { + enable = lib.mkEnableOption "support for Intel IPU6/MIPI cameras"; + + platform = lib.mkOption { + type = lib.types.enum [ + "ipu6" + "ipu6ep" + "ipu6epmtl" + ]; + description = '' + Choose the IPU version for your hardware platform. + + Use `ipu6` for Tiger Lake, `ipu6ep` for Alder Lake or Raptor Lake, + and `ipu6epmtl` for Meteor Lake. + ''; + }; + }; + + config = lib.mkIf cfg.enable { + # Load IPU6 kernel drivers (upstream since kernel 6.10, but still needs + # out-of-tree i2c sensors and intel-ipu6-psys kernel driver) + boot.extraModulePackages = [ config.boot.kernelPackages.ipu6-drivers ]; + + # IPU6 firmware and Intel Vision Sensing Controller firmware + hardware.firmware = [ + pkgs.ipu6-camera-bins + pkgs.ivsc-firmware + ]; + + # Restrict IPU6 raw nodes and media controller to root. + # TAG-="uaccess" blocks logind ACL grants at login. + services.udev.extraRules = '' + SUBSYSTEM=="intel-ipu6-psys", MODE="0660", GROUP="video" + SUBSYSTEM=="media", DRIVERS=="intel-ipu6", MODE="0600", GROUP="root", TAG-="uaccess" + SUBSYSTEM=="video4linux", DRIVERS=="intel-ipu6", MODE="0600", GROUP="root", TAG-="uaccess" + ''; + + # ipu6-camera-hal writes AIQ tuning data and debug logs here + tmpfiles.rules = [ + { + type = "directory"; + path = "/run/camera"; + mode = "0755"; + user = "root"; + group = "video"; + } + ]; + + # Install the platform-specific camera HAL + environment.systemPackages = + let + hal = + { + "ipu6" = pkgs.ipu6-camera-hal; + "ipu6ep" = pkgs.ipu6ep-camera-hal; + "ipu6epmtl" = pkgs.ipu6epmtl-camera-hal; + } + .${cfg.platform}; + in + [ hal ]; + + # TODO(corepkgs): Port v4l2-relayd and configure v4l2loopback relay + # for presenting IPU6 camera as a standard V4L2 device. + # The full nixpkgs module uses services.v4l2-relayd.instances.ipu6 + # with icamerasrc-{ipu6,ipu6ep,ipu6epmtl} GStreamer plugins. + + # TODO(corepkgs): Port WirePlumber configuration to disable raw IPU6 + # nodes so applications only see the v4l2loopback relay device. + }; +} diff --git a/ekaos/modules/module-list.nix b/ekaos/modules/module-list.nix index 4a71d9386..0cee84923 100644 --- a/ekaos/modules/module-list.nix +++ b/ekaos/modules/module-list.nix @@ -22,6 +22,7 @@ ./hardware/firmware.nix ./hardware/facter ./hardware/cpu.nix + ./hardware/ipu6.nix ./hardware/trackpoint.nix ./hardware/sensor/iio.nix From 860c6855afc3c32274fabc32eedb420e5d4a4871 Mon Sep 17 00:00:00 2001 From: Jonathan Ringer Date: Mon, 14 Sep 2026 14:49:02 -0700 Subject: [PATCH 08/14] ekaos/hardware: add NVIDIA GPU module Add hardware.nvidia option module for NVIDIA proprietary driver support: driver branch/package selection, open vs proprietary kernel modules, modesetting, GSP firmware, power management (suspend/resume, RTD3), PRIME hybrid GPU modes (offload/sync/reverse sync) with bus ID configuration, and nvidia-offload convenience script. Facter auto-detects NVIDIA GPUs, populates PRIME bus IDs from hardware report, and enables offload mode for hybrid GPU systems. Remove redundant nvidia-drm.modeset=1 from facter/gpu.nix as hardware.nvidia now handles it. --- ekaos/modules/hardware/facter/default.nix | 1 + ekaos/modules/hardware/facter/gpu.nix | 5 +- ekaos/modules/hardware/facter/nvidia.nix | 172 +++++++++++++ ekaos/modules/hardware/nvidia.nix | 295 ++++++++++++++++++++++ ekaos/modules/module-list.nix | 1 + 5 files changed, 471 insertions(+), 3 deletions(-) create mode 100644 ekaos/modules/hardware/facter/nvidia.nix create mode 100644 ekaos/modules/hardware/nvidia.nix diff --git a/ekaos/modules/hardware/facter/default.nix b/ekaos/modules/hardware/facter/default.nix index 71deb12a5..a011c24e1 100644 --- a/ekaos/modules/hardware/facter/default.nix +++ b/ekaos/modules/hardware/facter/default.nix @@ -24,6 +24,7 @@ ./keyboard.nix ./laptop.nix ./networking.nix + ./nvidia.nix ./power.nix ./printing.nix ./scanner.nix diff --git a/ekaos/modules/hardware/facter/gpu.nix b/ekaos/modules/hardware/facter/gpu.nix index 32ff5b030..647f500b2 100644 --- a/ekaos/modules/hardware/facter/gpu.nix +++ b/ekaos/modules/hardware/facter/gpu.nix @@ -42,11 +42,10 @@ in boot.initrd.kernelModules = [ "i915" ]; }) - # NVIDIA GPU: enable mesa side, kernel modesetting for Wayland/display - # Proprietary drivers still require user opt-in + # NVIDIA GPU: enable graphics stack + # Driver configuration is handled by hardware.nvidia (via facter/nvidia.nix) (lib.mkIf cfg.nvidia.enable { hardware.graphics.enable = lib.mkDefault true; - boot.kernelParams = [ "nvidia-drm.modeset=1" ]; }) ] ); diff --git a/ekaos/modules/hardware/facter/nvidia.nix b/ekaos/modules/hardware/facter/nvidia.nix new file mode 100644 index 000000000..fe8214176 --- /dev/null +++ b/ekaos/modules/hardware/facter/nvidia.nix @@ -0,0 +1,172 @@ +# Auto-configure NVIDIA GPU: driver options, generation detection, and PRIME +{ + lib, + config, + ... +}: +let + facterLib = import ./lib.nix lib; + inherit (config.hardware.facter) report; + cfg = config.hardware.facter.detected.nvidia; + isBaremetal = config.hardware.facter.detected.virtualisation.none.enable; + + gpus = report.hardware.graphics_card or [ ]; + + # Extract NVIDIA GPUs from facter report + nvidiaGpus = builtins.filter ( + { + vendor ? { }, + ... + }: + (vendor.value or 0) == 4318 # 0x10de + ) gpus; + + # Extract non-NVIDIA GPUs (for hybrid detection) + otherGpus = builtins.filter ( + { + vendor ? { }, + ... + }: + let + vid = vendor.value or 0; + in + vid != 4318 && (vid == 32902 || vid == 4098) # Intel or AMD + ) gpus; + + hasNvidia = builtins.length nvidiaGpus > 0; + hasOtherGpu = builtins.length otherGpus > 0; + isHybrid = hasNvidia && hasOtherGpu; + + # Extract PCI bus ID from slot field in format "PCI:X:Y:Z" + slotToBusId = + slot: + let + # slot format is typically "0000:XX:YY.Z" + parts = lib.splitString ":" slot; + hasDomain = builtins.length parts >= 3; + # Drop the domain prefix if present + busStr = if hasDomain then builtins.elemAt parts 1 else builtins.elemAt parts 0; + rest = if hasDomain then builtins.elemAt parts 2 else builtins.elemAt parts 1; + devFn = lib.splitString "." rest; + devStr = builtins.elemAt devFn 0; + fnStr = if builtins.length devFn > 1 then builtins.elemAt devFn 1 else "0"; + in + "PCI:${builtins.toString (facterLib.hexToInt busStr)}:${builtins.toString (facterLib.hexToInt devStr)}:${fnStr}"; + + # Simple hex string to int for bus IDs (handles 1-2 hex digits) + hexToInt = + s: + let + hexChars = { + "0" = 0; + "1" = 1; + "2" = 2; + "3" = 3; + "4" = 4; + "5" = 5; + "6" = 6; + "7" = 7; + "8" = 8; + "9" = 9; + "a" = 10; + "b" = 11; + "c" = 12; + "d" = 13; + "e" = 14; + "f" = 15; + }; + chars = lib.stringToCharacters (lib.toLower s); + in + lib.foldl' (acc: c: acc * 16 + (hexChars.${c} or 0)) 0 chars; + + # Extract bus ID from a GPU entry + gpuBusId = + gpu: + let + slot = gpu.slot or ""; + parts = lib.splitString ":" slot; + hasDomain = builtins.length parts >= 3; + busStr = if hasDomain then builtins.elemAt parts 1 else builtins.elemAt parts 0; + rest = if hasDomain then builtins.elemAt parts 2 else builtins.elemAt parts 1; + devFn = lib.splitString "." rest; + devStr = builtins.elemAt devFn 0; + fnStr = if builtins.length devFn > 1 then builtins.elemAt devFn 1 else "0"; + in + if slot == "" then + "" + else + "PCI:${builtins.toString (hexToInt busStr)}:${builtins.toString (hexToInt devStr)}:${fnStr}"; + + nvidiaBusId = if builtins.length nvidiaGpus > 0 then gpuBusId (builtins.head nvidiaGpus) else ""; + + # Determine iGPU bus ID and type + iGpu = if builtins.length otherGpus > 0 then builtins.head otherGpus else null; + iGpuBusId = if iGpu != null then gpuBusId iGpu else ""; + iGpuIsIntel = iGpu != null && (iGpu.vendor.value or 0) == 32902; + iGpuIsAmd = iGpu != null && (iGpu.vendor.value or 0) == 4098; +in +{ + options.hardware.facter.detected.nvidia = { + enable = lib.mkEnableOption "Facter NVIDIA GPU auto-configuration" // { + default = hasNvidia && isBaremetal; + defaultText = "hardware dependent"; + }; + + hybrid.enable = lib.mkEnableOption "Facter hybrid GPU (PRIME) detection" // { + default = isHybrid && isBaremetal; + defaultText = "hardware dependent"; + }; + + busId = lib.mkOption { + type = lib.types.str; + default = nvidiaBusId; + defaultText = "hardware dependent"; + description = "PCI bus ID of the NVIDIA GPU (auto-detected from facter report)."; + }; + + iGpuBusId = lib.mkOption { + type = lib.types.str; + default = iGpuBusId; + defaultText = "hardware dependent"; + description = "PCI bus ID of the integrated GPU (auto-detected from facter report)."; + }; + + iGpuVendor = lib.mkOption { + type = lib.types.enum [ + "intel" + "amd" + "none" + ]; + default = + if iGpuIsIntel then + "intel" + else if iGpuIsAmd then + "amd" + else + "none"; + defaultText = "hardware dependent"; + description = "Vendor of the integrated GPU."; + }; + }; + + config = lib.mkIf config.hardware.facter.enable ( + lib.mkMerge [ + # Enable the NVIDIA hardware module with auto-detected settings + (lib.mkIf cfg.enable { + hardware.nvidia.enable = lib.mkDefault true; + hardware.nvidia.prime.nvidiaBusId = lib.mkDefault cfg.busId; + }) + + # Hybrid GPU: auto-configure PRIME offload with detected bus IDs + (lib.mkIf cfg.hybrid.enable { + hardware.nvidia.prime.offload.enable = lib.mkDefault true; + hardware.nvidia.prime.intelBusId = lib.mkIf (cfg.iGpuVendor == "intel") ( + lib.mkDefault cfg.iGpuBusId + ); + hardware.nvidia.prime.amdgpuBusId = lib.mkIf (cfg.iGpuVendor == "amd") ( + lib.mkDefault cfg.iGpuBusId + ); + }) + ] + ); +} diff --git a/ekaos/modules/hardware/nvidia.nix b/ekaos/modules/hardware/nvidia.nix new file mode 100644 index 000000000..0d6d00c27 --- /dev/null +++ b/ekaos/modules/hardware/nvidia.nix @@ -0,0 +1,295 @@ +# NVIDIA GPU hardware configuration +# Simplified from nixpkgs for ekaos (Wayland-only, no X server) +{ + config, + lib, + pkgs, + ... +}: +let + cfg = config.hardware.nvidia; + nvidia_x11 = cfg.package; + + inherit (config.boot.kernelPackages) nvidiaPackages; + + useOpenModules = cfg.open == true; + + pCfg = cfg.prime; + primeEnabled = pCfg.offload.enable || pCfg.sync.enable || pCfg.reverseSync.enable; + busIDType = lib.types.strMatching "([[:print:]]+:[0-9]{1,3}(@[0-9]{1,10})?:[0-9]{1,2}:[0-9])?"; +in +{ + options.hardware.nvidia = { + enable = lib.mkEnableOption "NVIDIA proprietary driver support"; + + package = lib.mkOption { + type = lib.types.package; + default = nvidiaPackages.${cfg.branch}; + defaultText = lib.literalExpression "config.boot.kernelPackages.nvidiaPackages.\${config.hardware.nvidia.branch}"; + description = '' + The NVIDIA driver package to use. + + Prefer using {option}`hardware.nvidia.branch` when possible. + If you set this, pick a package from + `config.boot.kernelPackages.nvidiaPackages` so the driver build + matches your configured kernel. + ''; + }; + + branch = lib.mkOption { + type = + (lib.types.enum (builtins.attrNames (lib.filterAttrs (_: lib.isDerivation) nvidiaPackages))) + // { + description = "one of the available NVIDIA driver branches"; + }; + default = "stable"; + example = "production"; + description = '' + The branch of the NVIDIA driver to use. + + Common branches: stable, production, latest, beta, vulkan_beta, + legacy_535, legacy_470. + ''; + }; + + open = lib.mkOption { + type = lib.types.nullOr lib.types.bool; + default = if lib.versionOlder nvidia_x11.version "560" then false else null; + defaultText = lib.literalExpression '' + if lib.versionOlder config.hardware.nvidia.package.version "560" then false else null + ''; + example = true; + description = '' + Whether to use the open source NVIDIA kernel module. + + Recommended for Turing or later GPUs (RTX series, GTX 16xx). + Use closed source modules for older GPUs. + ''; + }; + + modesetting.enable = lib.mkEnableOption "kernel modesetting for the NVIDIA driver" // { + default = lib.versionAtLeast cfg.package.version "535"; + defaultText = lib.literalExpression '' + lib.versionAtLeast config.hardware.nvidia.package.version "535" + ''; + }; + + gsp.enable = lib.mkEnableOption "GPU System Processor (GSP) firmware" // { + default = useOpenModules || lib.versionAtLeast nvidia_x11.version "555"; + defaultText = lib.literalExpression '' + config.hardware.nvidia.open == true || lib.versionAtLeast config.hardware.nvidia.package.version "555" + ''; + }; + + powerManagement = { + enable = lib.mkEnableOption '' + NVIDIA power management through systemd (suspend/resume support) + ''; + + finegrained = lib.mkEnableOption '' + fine-grained power management (PCI-Express Runtime D3). + Requires PRIME offload to be enabled. Powers down the dGPU when idle + ''; + }; + + dynamicBoost.enable = lib.mkEnableOption '' + Dynamic Boost to balance power between CPU and GPU on supported laptops + ''; + + prime = { + nvidiaBusId = lib.mkOption { + type = busIDType; + default = ""; + example = "PCI:1:0:0"; + description = "Bus ID of the NVIDIA GPU."; + }; + + intelBusId = lib.mkOption { + type = busIDType; + default = ""; + example = "PCI:0:2:0"; + description = "Bus ID of the Intel integrated GPU."; + }; + + amdgpuBusId = lib.mkOption { + type = busIDType; + default = ""; + example = "PCI:4:0:0"; + description = "Bus ID of the AMD integrated GPU."; + }; + + offload.enable = lib.mkEnableOption '' + NVIDIA PRIME render offload. The dGPU renders only when explicitly + requested via environment variables. Battery-friendly default for laptops + ''; + + sync.enable = lib.mkEnableOption '' + NVIDIA PRIME sync mode. The dGPU is always on and handles all rendering. + Outputs through the iGPU display outputs without a MUX + ''; + + reverseSync.enable = lib.mkEnableOption '' + NVIDIA PRIME reverse sync. The iGPU handles rendering while the dGPU + provides additional display outputs + ''; + + allowExternalGpu = lib.mkEnableOption "external GPU (eGPU) support via Thunderbolt"; + }; + + nvidiaSettings = lib.mkEnableOption "nvidia-settings GUI configuration tool" // { + default = true; + }; + + nvidiaPersistenced = lib.mkEnableOption '' + nvidia-persistenced daemon to keep GPUs awake in headless mode + ''; + }; + + config = lib.mkIf cfg.enable ( + lib.mkMerge [ + # Core driver configuration + { + assertions = [ + { + assertion = cfg.open != null; + message = '' + You must set hardware.nvidia.open on NVIDIA driver versions >= 560. + Use true for Turing+ GPUs (RTX, GTX 16xx), false for older GPUs. + ''; + } + { + assertion = !useOpenModules || (nvidia_x11 ? open); + message = "The selected NVIDIA package does not provide open kernel modules."; + } + { + assertion = !useOpenModules || cfg.gsp.enable; + message = "GSP cannot be disabled when using the open source kernel driver."; + } + { + assertion = + primeEnabled -> pCfg.nvidiaBusId != "" && (pCfg.intelBusId != "" || pCfg.amdgpuBusId != ""); + message = "When NVIDIA PRIME is enabled, GPU bus IDs must be configured."; + } + { + assertion = !(pCfg.sync.enable && pCfg.offload.enable); + message = "PRIME Sync and Offload cannot both be enabled."; + } + { + assertion = !(pCfg.sync.enable && pCfg.reverseSync.enable); + message = "PRIME Sync and Reverse Sync cannot both be enabled."; + } + { + assertion = !(pCfg.sync.enable && cfg.powerManagement.finegrained); + message = "Sync mode precludes powering down the NVIDIA GPU."; + } + { + assertion = cfg.powerManagement.finegrained -> pCfg.offload.enable; + message = "Fine-grained power management requires PRIME offload."; + } + { + assertion = cfg.gsp.enable -> (nvidia_x11 ? firmware); + message = "This NVIDIA driver version does not provide GSP firmware."; + } + ]; + + # Blacklist conflicting modules + boot.blacklistedKernelModules = [ + "nouveau" + "nvidiafb" + ]; + + # Load nvidia-uvm lazily after udev rules are applied + boot.extraModprobeConfig = '' + softdep nvidia post: nvidia-uvm + ''; + + # Load nvidia-uvm eagerly for open modules (needed for CUDA) + boot.kernelModules = [ + "nvidia" + "nvidia_modeset" + "nvidia_drm" + ] + ++ lib.optionals useOpenModules [ "nvidia_uvm" ]; + + # Install the kernel module + boot.extraModulePackages = if useOpenModules then [ nvidia_x11.open ] else [ nvidia_x11 ]; + + # Kernel modesetting for Wayland + boot.kernelParams = + lib.optionals cfg.modesetting.enable [ "nvidia-drm.modeset=1" ] + ++ lib.optionals (cfg.modesetting.enable && lib.versionAtLeast nvidia_x11.version "545") [ + "nvidia-drm.fbdev=1" + ]; + + # udev rules for /dev/nvidia* device creation + services.udev.extraRules = '' + KERNEL=="nvidia", RUN+="${pkgs.runtimeShell} -c 'mknod -m 666 /dev/nvidiactl c 195 255'" + KERNEL=="nvidia", RUN+="${pkgs.runtimeShell} -c 'for i in $$(cat /proc/driver/nvidia/gpus/*/information | grep Minor | cut -d \ -f 4); do mknod -m 666 /dev/nvidia$${i} c 195 $${i}; done'" + KERNEL=="nvidia_modeset", RUN+="${pkgs.runtimeShell} -c 'mknod -m 666 /dev/nvidia-modeset c 195 254'" + KERNEL=="nvidia_uvm", RUN+="${pkgs.runtimeShell} -c 'mknod -m 666 /dev/nvidia-uvm c $$(grep nvidia-uvm /proc/devices | cut -d \ -f 1) 0'" + KERNEL=="nvidia_uvm", RUN+="${pkgs.runtimeShell} -c 'mknod -m 666 /dev/nvidia-uvm-tools c $$(grep nvidia-uvm /proc/devices | cut -d \ -f 1) 1'" + ''; + + # Graphics stack + hardware.graphics = { + enable = lib.mkDefault true; + enable32Bit = lib.mkDefault true; + extraPackages = [ nvidia_x11.out ]; + extraPackages32 = [ nvidia_x11.lib32 ]; + }; + + # GSP firmware + hardware.firmware = lib.optional cfg.gsp.enable nvidia_x11.firmware; + + # Driver binaries (nvidia-smi, etc.) + environment.systemPackages = [ + nvidia_x11.bin + ] + ++ lib.optional cfg.nvidiaSettings nvidia_x11.settings + ++ lib.optional cfg.nvidiaPersistenced nvidia_x11.persistenced; + } + + # Power management suspend/resume services + (lib.mkIf cfg.powerManagement.enable { + boot.extraModprobeConfig = '' + options nvidia NVreg_PreserveVideoMemoryAllocations=1 + ''; + }) + + # Fine-grained power management (RTD3) udev rules + (lib.mkIf cfg.powerManagement.finegrained { + boot.extraModprobeConfig = '' + options nvidia NVreg_DynamicPowerManagement=0x02 + ''; + + services.udev.extraRules = '' + # Enable runtime PM for NVIDIA VGA/3D controller devices on driver bind + ACTION=="bind", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x030000", TEST=="power/control", ATTR{power/control}="auto" + ACTION=="bind", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x030200", TEST=="power/control", ATTR{power/control}="auto" + + # Disable runtime PM for NVIDIA VGA/3D controller devices on driver unbind + ACTION=="unbind", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x030000", TEST=="power/control", ATTR{power/control}="on" + ACTION=="unbind", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x030200", TEST=="power/control", ATTR{power/control}="on" + ''; + }) + + # PRIME offload convenience script + (lib.mkIf pCfg.offload.enable { + environment.systemPackages = [ + (pkgs.writeShellScriptBin "nvidia-offload" '' + export __NV_PRIME_RENDER_OFFLOAD=1 + export __NV_PRIME_RENDER_OFFLOAD_PROVIDER=NVIDIA-G0 + export __GLX_VENDOR_LIBRARY_NAME=nvidia + export __VK_LAYER_NV_optimus=NVIDIA_only + exec "$@" + '') + ]; + }) + + # Reverse sync implies offloading + (lib.mkIf pCfg.reverseSync.enable { + hardware.nvidia.prime.offload.enable = lib.mkDefault true; + }) + ] + ); +} diff --git a/ekaos/modules/module-list.nix b/ekaos/modules/module-list.nix index 0cee84923..5b64fb159 100644 --- a/ekaos/modules/module-list.nix +++ b/ekaos/modules/module-list.nix @@ -23,6 +23,7 @@ ./hardware/facter ./hardware/cpu.nix ./hardware/ipu6.nix + ./hardware/nvidia.nix ./hardware/trackpoint.nix ./hardware/sensor/iio.nix From 71d28cc7a6c21b1d487ae401d58a16a9e9f01c75 Mon Sep 17 00:00:00 2001 From: Jonathan Ringer Date: Tue, 15 Sep 2026 07:12:51 -0700 Subject: [PATCH 09/14] bolt, power-profiles-daemon: use docbook-xml-dtd instead of aliases Replace docbook_xml_dtd_45 and docbook_xml_dtd_412 with the real attribute docbook-xml-dtd.{v4_5,v4_1_2} so callPackage can inject them without relying on stdenv/aliases.nix. --- pkgs/bolt/default.nix | 4 ++-- pkgs/power-profiles-daemon/default.nix | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pkgs/bolt/default.nix b/pkgs/bolt/default.nix index 3610e6008..d4af2cbe8 100644 --- a/pkgs/bolt/default.nix +++ b/pkgs/bolt/default.nix @@ -9,7 +9,7 @@ asciidoc, libxml2, libxslt, - docbook_xml_dtd_45, + docbook-xml-dtd, docbook-xsl-nons, glib, systemd, @@ -44,7 +44,7 @@ stdenv.mkDerivation (finalAttrs: { nativeBuildInputs = [ asciidoc - docbook_xml_dtd_45 + docbook-xml-dtd.v4_5 docbook-xsl-nons libxml2 libxslt diff --git a/pkgs/power-profiles-daemon/default.nix b/pkgs/power-profiles-daemon/default.nix index 4b1f27554..dd4920a5b 100644 --- a/pkgs/power-profiles-daemon/default.nix +++ b/pkgs/power-profiles-daemon/default.nix @@ -12,7 +12,7 @@ gettext, gtk-doc, docbook-xsl-nons, - docbook_xml_dtd_412, + docbook-xml-dtd, libxml2, libxslt, upower, @@ -45,7 +45,7 @@ stdenv.mkDerivation (finalAttrs: { gettext gtk-doc docbook-xsl-nons - docbook_xml_dtd_412 + docbook-xml-dtd.v4_1_2 libxml2 libxslt gobject-introspection From 61c71efef0cb2651821bbccf2c70b5a9a5c1d7a9 Mon Sep 17 00:00:00 2001 From: Jonathan Ringer Date: Tue, 15 Sep 2026 07:40:52 -0700 Subject: [PATCH 10/14] ipu6-camera-bins, power-profiles-daemon: fix builds Move stdenv.cc.cc lib to buildInputs so autoPatchelfHook can find libstdc++.so.6. Disable zsh/bash completions in power-profiles-daemon to avoid shtab Python module dependency. --- pkgs/ipu6-camera-bins/default.nix | 3 +++ pkgs/power-profiles-daemon/default.nix | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/pkgs/ipu6-camera-bins/default.nix b/pkgs/ipu6-camera-bins/default.nix index a959a8e26..4ec26d762 100644 --- a/pkgs/ipu6-camera-bins/default.nix +++ b/pkgs/ipu6-camera-bins/default.nix @@ -20,6 +20,9 @@ stdenv.mkDerivation (finalAttrs: { nativeBuildInputs = [ autoPatchelfHook + ]; + + buildInputs = [ (lib.getLib stdenv.cc.cc) expat zlib diff --git a/pkgs/power-profiles-daemon/default.nix b/pkgs/power-profiles-daemon/default.nix index dd4920a5b..5dc253fd8 100644 --- a/pkgs/power-profiles-daemon/default.nix +++ b/pkgs/power-profiles-daemon/default.nix @@ -69,7 +69,7 @@ stdenv.mkDerivation (finalAttrs: { "-Dtests=false" "-Dmanpage=disabled" "-Dbashcomp=disabled" - "-Dzshcomp=${placeholder "out"}/share/zsh/site-functions" + "-Dzshcomp=" ]; env.PKG_CONFIG_POLKIT_GOBJECT_1_POLICYDIR = "${placeholder "out"}/share/polkit-1/actions"; From 906b8e25bb30ac3b25ad2bf57c188dbb879abf48 Mon Sep 17 00:00:00 2001 From: Jonathan Ringer Date: Tue, 15 Sep 2026 08:02:13 -0700 Subject: [PATCH 11/14] ekaos/hardware: add IPU7 camera support Port Intel IPU7 camera stack for Lunar Lake: ipu7-camera-bins (firmware), ipu7-camera-hal (userspace HAL with ipu7x/ipu75xa variants), ipu7-drivers (kernel module), and jsoncpp dependency. Add hardware.ipu7 option module with platform selection and firmware loading. Extend facter/camera.nix to auto-detect IPU7 hardware by PCI device ID (0x645d Lunar Lake, 0xb05d Arrow Lake) alongside existing IPU6 detection. --- ekaos/modules/hardware/facter/camera.nix | 116 ++++++++++++------ ekaos/modules/hardware/ipu7.nix | 71 +++++++++++ ekaos/modules/module-list.nix | 1 + pkgs/ipu7-camera-bins/default.nix | 66 ++++++++++ pkgs/ipu7-camera-hal/default.nix | 109 ++++++++++++++++ pkgs/jsoncpp/default.nix | 56 +++++++++ pkgs/linux-support/default.nix | 2 + .../pkgs/ipu7-drivers/default.nix | 42 +++++++ top-level.nix | 4 + 9 files changed, 432 insertions(+), 35 deletions(-) create mode 100644 ekaos/modules/hardware/ipu7.nix create mode 100644 pkgs/ipu7-camera-bins/default.nix create mode 100644 pkgs/ipu7-camera-hal/default.nix create mode 100644 pkgs/jsoncpp/default.nix create mode 100644 pkgs/linux-support/pkgs/ipu7-drivers/default.nix diff --git a/ekaos/modules/hardware/facter/camera.nix b/ekaos/modules/hardware/facter/camera.nix index d5ba430b4..75e47befe 100644 --- a/ekaos/modules/hardware/facter/camera.nix +++ b/ekaos/modules/hardware/facter/camera.nix @@ -1,4 +1,4 @@ -# Auto-detect Intel IPU6 camera hardware and configure platform +# Auto-detect Intel IPU6/IPU7 camera hardware and configure platform { lib, config, @@ -8,8 +8,10 @@ let facterLib = import ./lib.nix lib; inherit (config.hardware.facter) report; - # Intel IPU6 PCI device IDs per CPU generation # Vendor: Intel (0x8086 = 32902) + intelVendorId = 32902; + + # Intel IPU6 PCI device IDs per CPU generation tigerLakeId = 39449; # 0x9a19 alderLakeId = 18013; # 0x465d raptorLakeId = 42845; # 0xa75d @@ -22,56 +24,100 @@ let meteorLakeId ]; + # Intel IPU7 PCI device IDs + lunarLakeId = 25693; # 0x645d + arrowLakeId = 45149; # 0xb05d + + allIpu7Ids = [ + lunarLakeId + arrowLakeId + ]; + multimediaDevices = report.hardware.multimedia_controller or [ ]; - # Find the matching IPU6 device - ipu6Device = lib.findFirst ( - { - vendor ? { }, - device ? { }, - ... - }: - (vendor.value or 0) == 32902 && builtins.elem (device.value or 0) allIpu6Ids - ) null multimediaDevices; + # Find Intel multimedia devices + findIntelDevice = + ids: + lib.findFirst ( + { + vendor ? { }, + device ? { }, + ... + }: + (vendor.value or 0) == intelVendorId && builtins.elem (device.value or 0) ids + ) null multimediaDevices; + # IPU6 detection + ipu6Device = findIntelDevice allIpu6Ids; hasIpu6 = ipu6Device != null; + ipu6DeviceId = if hasIpu6 then (ipu6Device.device.value or 0) else 0; - # Determine platform from the detected device ID - detectedDeviceId = if hasIpu6 then (ipu6Device.device.value or 0) else 0; - - detectedPlatform = - if detectedDeviceId == tigerLakeId then + detectedIpu6Platform = + if ipu6DeviceId == tigerLakeId then "ipu6" - else if detectedDeviceId == alderLakeId || detectedDeviceId == raptorLakeId then + else if ipu6DeviceId == alderLakeId || ipu6DeviceId == raptorLakeId then "ipu6ep" - else if detectedDeviceId == meteorLakeId then + else if ipu6DeviceId == meteorLakeId then "ipu6epmtl" else "ipu6"; + + # IPU7 detection + ipu7Device = findIntelDevice allIpu7Ids; + hasIpu7 = ipu7Device != null; + ipu7DeviceId = if hasIpu7 then (ipu7Device.device.value or 0) else 0; + + detectedIpu7Platform = if ipu7DeviceId == arrowLakeId then "ipu75xa" else "ipu7x"; in { - options.hardware.facter.detected.camera.ipu6 = { - enable = lib.mkEnableOption "Facter Intel IPU6 camera detection" // { - default = hasIpu6; - defaultText = "hardware dependent"; + options.hardware.facter.detected.camera = { + ipu6 = { + enable = lib.mkEnableOption "Facter Intel IPU6 camera detection" // { + default = hasIpu6; + defaultText = "hardware dependent"; + }; + + platform = lib.mkOption { + type = lib.types.enum [ + "ipu6" + "ipu6ep" + "ipu6epmtl" + ]; + default = detectedIpu6Platform; + defaultText = "hardware dependent"; + description = "Auto-detected IPU6 platform variant based on CPU generation."; + }; }; - platform = lib.mkOption { - type = lib.types.enum [ - "ipu6" - "ipu6ep" - "ipu6epmtl" - ]; - default = detectedPlatform; - defaultText = "hardware dependent"; - description = "Auto-detected IPU6 platform variant based on CPU generation."; + ipu7 = { + enable = lib.mkEnableOption "Facter Intel IPU7 camera detection" // { + default = hasIpu7; + defaultText = "hardware dependent"; + }; + + platform = lib.mkOption { + type = lib.types.enum [ + "ipu7x" + "ipu75xa" + ]; + default = detectedIpu7Platform; + defaultText = "hardware dependent"; + description = "Auto-detected IPU7 platform variant."; + }; }; }; - config = - lib.mkIf (config.hardware.facter.enable && config.hardware.facter.detected.camera.ipu6.enable) - { + config = lib.mkIf config.hardware.facter.enable ( + lib.mkMerge [ + (lib.mkIf config.hardware.facter.detected.camera.ipu6.enable { hardware.ipu6.enable = lib.mkDefault true; hardware.ipu6.platform = lib.mkDefault config.hardware.facter.detected.camera.ipu6.platform; - }; + }) + + (lib.mkIf config.hardware.facter.detected.camera.ipu7.enable { + hardware.ipu7.enable = lib.mkDefault true; + hardware.ipu7.platform = lib.mkDefault config.hardware.facter.detected.camera.ipu7.platform; + }) + ] + ); } diff --git a/ekaos/modules/hardware/ipu7.nix b/ekaos/modules/hardware/ipu7.nix new file mode 100644 index 000000000..fa1879433 --- /dev/null +++ b/ekaos/modules/hardware/ipu7.nix @@ -0,0 +1,71 @@ +# Intel IPU7/MIPI camera hardware configuration for Lunar Lake +{ + config, + lib, + pkgs, + ... +}: +let + cfg = config.hardware.ipu7; +in +{ + options.hardware.ipu7 = { + enable = lib.mkEnableOption "support for Intel IPU7/MIPI cameras (Lunar Lake)"; + + platform = lib.mkOption { + type = lib.types.enum [ + "ipu7x" + "ipu75xa" + ]; + default = "ipu7x"; + description = '' + Choose the IPU version for your hardware platform. + + Use `ipu7x` for Lunar Lake and `ipu75xa` for Arrow Lake. + ''; + }; + }; + + config = lib.mkIf cfg.enable { + # Load IPU7 kernel drivers + boot.extraModulePackages = [ config.boot.kernelPackages.ipu7-drivers ]; + + # IPU7 firmware (lives under lib/firmware/intel/ipu/) + hardware.firmware = [ + pkgs.ipu7-camera-bins + ]; + + # Restrict IPU7 raw nodes and media controller to root + services.udev.extraRules = '' + SUBSYSTEM=="intel-ipu7-psys", MODE="0660", GROUP="video" + SUBSYSTEM=="media", DRIVERS=="intel-ipu7", MODE="0600", GROUP="root", TAG-="uaccess" + SUBSYSTEM=="video4linux", DRIVERS=="intel-ipu7", MODE="0600", GROUP="root", TAG-="uaccess" + ''; + + # Camera HAL writes tuning data here + tmpfiles.rules = [ + { + type = "directory"; + path = "/run/camera"; + mode = "0755"; + user = "root"; + group = "video"; + } + ]; + + # Install the platform-specific camera HAL + environment.systemPackages = + let + hal = + { + "ipu7x" = pkgs.ipu7-camera-hal; + "ipu75xa" = pkgs.ipu75xa-camera-hal; + } + .${cfg.platform}; + in + [ hal ]; + + # TODO(corepkgs): Port v4l2-relayd and GStreamer icamerasrc plugin + # for IPU7 to present the camera as a standard V4L2 device. + }; +} diff --git a/ekaos/modules/module-list.nix b/ekaos/modules/module-list.nix index 5b64fb159..539d1af96 100644 --- a/ekaos/modules/module-list.nix +++ b/ekaos/modules/module-list.nix @@ -23,6 +23,7 @@ ./hardware/facter ./hardware/cpu.nix ./hardware/ipu6.nix + ./hardware/ipu7.nix ./hardware/nvidia.nix ./hardware/trackpoint.nix ./hardware/sensor/iio.nix diff --git a/pkgs/ipu7-camera-bins/default.nix b/pkgs/ipu7-camera-bins/default.nix new file mode 100644 index 000000000..f2b050727 --- /dev/null +++ b/pkgs/ipu7-camera-bins/default.nix @@ -0,0 +1,66 @@ +{ + lib, + stdenv, + fetchFromGitHub, + autoPatchelfHook, + expat, + zlib, +}: + +stdenv.mkDerivation { + pname = "ipu7-camera-bins"; + version = "unstable-2026-06-29"; + + src = fetchFromGitHub { + owner = "intel"; + repo = "ipu7-camera-bins"; + tag = "20260629_2"; + hash = "sha256-LjiqxlQKDLArgK2puxlyTpLPtL6QN6P/xWO2asPTLig="; + }; + + nativeBuildInputs = [ + autoPatchelfHook + ]; + + buildInputs = [ + (lib.getLib stdenv.cc.cc) + expat + zlib + ]; + + dontBuild = true; + + installPhase = '' + runHook preInstall + + mkdir -p $out + cp --no-preserve=mode --recursive \ + lib \ + include \ + $out/ + + runHook postInstall + ''; + + postFixup = '' + for lib in $out/lib/lib*.so.*; do \ + lib=''${lib##*/}; \ + ln -sf $lib $out/lib/''${lib%.*}; \ + done + + for pcfile in $out/lib/pkgconfig/*.pc; do + substituteInPlace $pcfile \ + --replace 'prefix=/usr' "prefix=$out" + done + ''; + + meta = { + description = "IPU7 firmware and proprietary image processing libraries for Lunar Lake"; + homepage = "https://github.com/intel/ipu7-camera-bins"; + license = lib.licenses.issl; + sourceProvenance = with lib.sourceTypes; [ + binaryFirmware + ]; + platforms = [ "x86_64-linux" ]; + }; +} diff --git a/pkgs/ipu7-camera-hal/default.nix b/pkgs/ipu7-camera-hal/default.nix new file mode 100644 index 000000000..42f274e9e --- /dev/null +++ b/pkgs/ipu7-camera-hal/default.nix @@ -0,0 +1,109 @@ +{ + lib, + stdenv, + fetchFromGitHub, + + # build + cmake, + pkg-config, + + # runtime + expat, + ipu7-camera-bins, + jsoncpp, + libtool, + gst_all_1, + libdrm, + + # Pick one of + # - ipu7x (Lunar Lake) + # - ipu75xa (Arrow Lake) + ipuVersion ? "ipu7x", +}: + +stdenv.mkDerivation { + pname = "${ipuVersion}-camera-hal"; + version = "unstable-2026-06-29"; + + src = fetchFromGitHub { + owner = "intel"; + repo = "ipu7-camera-hal"; + tag = "20260629_2"; + hash = "sha256-uiVPQBMHUBP9ZFzX0QMimIpgbmvm7JLTkD588V07iGw="; + }; + + nativeBuildInputs = [ + cmake + cmake.configurePhaseHook + pkg-config + ]; + + cmakeFlags = [ + "-DCMAKE_BUILD_TYPE=Release" + "-DCMAKE_INSTALL_PREFIX=${placeholder "out"}" + "-DCMAKE_INSTALL_LIBDIR=lib" + "-DCMAKE_POLICY_VERSION_MINIMUM=3.5" + "-DBUILD_CAMHAL_ADAPTOR=ON" + "-DBUILD_CAMHAL_PLUGIN=ON" + "-DIPU_VERSIONS=${ipuVersion}" + "-DUSE_STATIC_GRAPH=ON" + "-DUSE_STATIC_GRAPH_AUTOGEN=ON" + "-DCMAKE_INSTALL_INCLUDEDIR=include" + # jsoncpp is linked as raw library name; help cmake find it + "-Djsoncpp_DIR=${jsoncpp.dev}/lib/cmake/jsoncpp" + ]; + + env = { + NIX_CFLAGS_COMPILE = toString [ + "-Wno-error" + "-std=c++17" + ]; + NIX_LDFLAGS = toString [ "-L${jsoncpp}/lib" ]; + }; + + enableParallelBuilding = true; + + buildInputs = [ + expat + ipu7-camera-bins + jsoncpp + libtool + gst_all_1.gstreamer + gst_all_1.gst-plugins-base + libdrm + ]; + + postPatch = '' + # jsoncpp installs headers to include/json/ but source expects jsoncpp/json/ + find . -name '*.h' -o -name '*.cpp' | xargs sed -i 's|jsoncpp/json/|json/|g' + + # CMakeLists uses raw 'jsoncpp' library name; use cmake imported target instead + sed -i 's|set(TARGET_LINK_LIBS ''${TARGET_LINK_LIBS} jsoncpp)|find_package(jsoncpp REQUIRED)\nset(TARGET_LINK_LIBS ''${TARGET_LINK_LIBS} JsonCpp::JsonCpp)|' CMakeLists.txt + + substituteInPlace src/platformdata/PlatformData.h \ + --replace '/usr/share/' "${placeholder "out"}/share/" \ + --replace '#define CAMERA_DEFAULT_CFG_PATH "/etc/camera/"' '#define CAMERA_DEFAULT_CFG_PATH "${placeholder "out"}/etc/camera/"' + ''; + + postInstall = '' + mkdir -p $out/include/${ipuVersion}/ + cp -r $src/include $out/include/${ipuVersion}/libcamhal + ''; + + postFixup = '' + for lib in $out/lib/*.so; do + patchelf --add-rpath "${ipu7-camera-bins}/lib" $lib + done + ''; + + passthru = { + inherit ipuVersion; + }; + + meta = { + description = "HAL for processing of images in userspace (IPU7)"; + homepage = "https://github.com/intel/ipu7-camera-hal"; + license = lib.licenses.asl20; + platforms = [ "x86_64-linux" ]; + }; +} diff --git a/pkgs/jsoncpp/default.nix b/pkgs/jsoncpp/default.nix new file mode 100644 index 000000000..18eb49415 --- /dev/null +++ b/pkgs/jsoncpp/default.nix @@ -0,0 +1,56 @@ +{ + lib, + stdenv, + fetchFromGitHub, + cmake, + python3, + validatePkgConfig, +}: + +stdenv.mkDerivation (finalAttrs: { + pname = "jsoncpp"; + version = "1.9.7"; + + strictDeps = true; + + outputs = [ + "out" + "dev" + ]; + + src = fetchFromGitHub { + owner = "open-source-parsers"; + repo = "jsoncpp"; + rev = finalAttrs.version; + hash = "sha256-rf8d2UNTVEZhuiyChK2XnUbfGDvsfXnKADhaSp8qBwQ="; + }; + + # During darwin bootstrap, cp may not understand --reflink=auto + unpackPhase = '' + cp -a ${finalAttrs.src} ${finalAttrs.src.name} + chmod -R +w ${finalAttrs.src.name} + export sourceRoot=${finalAttrs.src.name} + ''; + + nativeBuildInputs = [ + cmake + cmake.configurePhaseHook + python3 + validatePkgConfig + ]; + + cmakeFlags = [ + "-DBUILD_SHARED_LIBS=ON" + "-DBUILD_OBJECT_LIBS=OFF" + "-DJSONCPP_WITH_CMAKE_PACKAGE=ON" + "-DBUILD_STATIC_LIBS=OFF" + ] + ++ lib.optional (stdenv.buildPlatform != stdenv.hostPlatform) "-DJSONCPP_WITH_TESTS=OFF"; + + meta = { + homepage = "https://github.com/open-source-parsers/jsoncpp"; + description = "C++ library for interacting with JSON"; + license = lib.licenses.mit; + platforms = lib.platforms.all; + }; +}) diff --git a/pkgs/linux-support/default.nix b/pkgs/linux-support/default.nix index bd0966d5e..e6ca83c6a 100644 --- a/pkgs/linux-support/default.nix +++ b/pkgs/linux-support/default.nix @@ -235,6 +235,8 @@ lib.makeScope pkgs.newScope ( ipu6-drivers = callPackage ./pkgs/ipu6-drivers { }; + ipu7-drivers = callPackage ./pkgs/ipu7-drivers { }; + ivsc-driver = callPackage ./pkgs/ivsc-driver { }; ixgbevf = callPackage ./pkgs/ixgbevf { }; diff --git a/pkgs/linux-support/pkgs/ipu7-drivers/default.nix b/pkgs/linux-support/pkgs/ipu7-drivers/default.nix new file mode 100644 index 000000000..4e7d2acb2 --- /dev/null +++ b/pkgs/linux-support/pkgs/ipu7-drivers/default.nix @@ -0,0 +1,42 @@ +{ + lib, + stdenv, + fetchFromGitHub, + kernel, + kernelModuleMakeFlags, +}: + +stdenv.mkDerivation { + pname = "ipu7-drivers"; + version = "unstable-2026-08-12"; + + src = fetchFromGitHub { + owner = "intel"; + repo = "ipu7-drivers"; + rev = "495acc90feb09d8008c0a6228fb8bb4c6415ca62"; + hash = "sha256-a2hIJ4wMCHQeDb4gp+5pjLizJ/CCfA0JivVDWeqB4vY="; + }; + + nativeBuildInputs = kernel.moduleBuildDependencies; + + makeFlags = kernelModuleMakeFlags ++ [ + "KERNELRELEASE=${kernel.modDirVersion}" + "KERNEL_SRC=${kernel.dev}/lib/modules/${kernel.modDirVersion}/build" + ]; + + preInstall = '' + sed -i -e "s,INSTALL_MOD_DIR=,INSTALL_MOD_PATH=$out INSTALL_MOD_DIR=," Makefile + ''; + + installTargets = [ + "modules_install" + ]; + + meta = { + homepage = "https://github.com/intel/ipu7-drivers"; + description = "IPU7 kernel driver for Lunar Lake cameras"; + license = lib.licenses.gpl2Only; + platforms = [ "x86_64-linux" ]; + broken = kernel.kernelOlder "6.8"; + }; +} diff --git a/top-level.nix b/top-level.nix index cd96a1888..373161d47 100644 --- a/top-level.nix +++ b/top-level.nix @@ -1032,6 +1032,10 @@ with final; ipuVersion = "ipu6epmtl"; }; + ipu75xa-camera-hal = ipu7-camera-hal.override { + ipuVersion = "ipu75xa"; + }; + openssl_legacy = openssl.override { conf = ./pkgs-many/openssl/3.0/legacy.cnf; }; From 0aa0e5c3183430eb788602ba360cb3dddd5b2d47 Mon Sep 17 00:00:00 2001 From: Jonathan Ringer Date: Wed, 16 Sep 2026 06:05:59 -0700 Subject: [PATCH 12/14] mtools, libburn, libisofs, libcdio, libcddb, libisoburn: init Port ISO image toolchain: mtools (FAT filesystem tools), libisoburn (xorriso ISO creator), and their dependency chain (libburn, libisofs, libcdio, libcddb). Required for building EkaOS installation media. --- pkgs/libburn/default.nix | 51 +++++++++++++++++++ pkgs/libcddb/default.nix | 35 +++++++++++++ pkgs/libcdio/default.nix | 98 +++++++++++++++++++++++++++++++++++++ pkgs/libisoburn/default.nix | 71 +++++++++++++++++++++++++++ pkgs/libisofs/default.nix | 54 ++++++++++++++++++++ pkgs/mtools/default.nix | 24 +++++++++ 6 files changed, 333 insertions(+) create mode 100644 pkgs/libburn/default.nix create mode 100644 pkgs/libcddb/default.nix create mode 100644 pkgs/libcdio/default.nix create mode 100644 pkgs/libisoburn/default.nix create mode 100644 pkgs/libisofs/default.nix create mode 100644 pkgs/mtools/default.nix diff --git a/pkgs/libburn/default.nix b/pkgs/libburn/default.nix new file mode 100644 index 000000000..ecd4f86d2 --- /dev/null +++ b/pkgs/libburn/default.nix @@ -0,0 +1,51 @@ +{ + lib, + stdenv, + fetchFromGitea, + fetchpatch, + autoreconfHook, + pkg-config, +}: + +stdenv.mkDerivation (finalAttrs: { + pname = "libburn"; + version = "1.5.6"; + + src = fetchFromGitea { + domain = "dev.lovelyhq.com"; + owner = "libburnia"; + repo = "libburn"; + rev = "release-${finalAttrs.version}"; + hash = "sha256-Xo45X4374FXvlrJ4Q0PahYvuWXO0k3N0ke0mbURYt54="; + }; + + patches = [ + # Fix the build against C23 compilers (like gcc-15): + (fetchpatch { + name = "c23.patch"; + url = "https://dev.lovelyhq.com/libburnia/libburn/commit/d537f9dd35282df834a311ead5f113af67d223b3.patch"; + hash = "sha256-aouU/6AchLhzMzvkVvUnFHWfebYTrkEJ6P3fF5pvE9M="; + }) + ]; + + nativeBuildInputs = [ + autoreconfHook + pkg-config + ]; + + outputs = [ + "out" + "man" + ]; + + strictDeps = true; + + meta = { + homepage = "https://dev.lovelyhq.com/libburnia/web/wiki"; + description = "Library by which preformatted data get onto optical media: CD, DVD, BD (Blu-Ray)"; + changelog = "https://dev.lovelyhq.com/libburnia/libburn/src/tag/${finalAttrs.src.rev}/ChangeLog"; + license = lib.licenses.gpl2Plus; + mainProgram = "cdrskin"; + platforms = lib.platforms.unix; + }; +}) diff --git a/pkgs/libcddb/default.nix b/pkgs/libcddb/default.nix new file mode 100644 index 000000000..268eb69f6 --- /dev/null +++ b/pkgs/libcddb/default.nix @@ -0,0 +1,35 @@ +{ + lib, + stdenv, + fetchurl, + libiconv, +}: + +stdenv.mkDerivation (finalAttrs: { + pname = "libcddb"; + version = "1.3.2"; + + src = fetchurl { + url = "mirror://sourceforge/libcddb/libcddb-${finalAttrs.version}.tar.bz2"; + sha256 = "0fr21a7vprdyy1bq6s99m0x420c9jm5fipsd63pqv8qyfkhhxkim"; + }; + + buildInputs = [ libiconv ]; + + configureFlags = lib.optionals (stdenv.hostPlatform != stdenv.buildPlatform) [ + "ac_cv_func_malloc_0_nonnull=yes" + "ac_cv_func_realloc_0_nonnull=yes" + ]; + + env = lib.optionalAttrs stdenv.cc.isGNU { + NIX_CFLAGS_COMPILE = "-Wno-error=incompatible-pointer-types"; + }; + + meta = { + description = "C library to access data on a CDDB server (freedb.org)"; + homepage = "https://libcddb.sourceforge.net/"; + license = lib.licenses.lgpl2Plus; + mainProgram = "cddb_query"; + platforms = lib.platforms.unix; + }; +}) diff --git a/pkgs/libcdio/default.nix b/pkgs/libcdio/default.nix new file mode 100644 index 000000000..3b2fb67a6 --- /dev/null +++ b/pkgs/libcdio/default.nix @@ -0,0 +1,98 @@ +{ + lib, + stdenv, + fetchFromGitHub, + autoreconfHook, + texinfo, + libcddb, + pkg-config, + ncurses, + help2man, + libiconv, + withMan ? stdenv.buildPlatform.canExecute stdenv.hostPlatform, +}: + +stdenv.mkDerivation (finalAttrs: { + pname = "libcdio"; + version = "2.3.0"; + + src = fetchFromGitHub { + owner = "libcdio"; + repo = "libcdio"; + tag = finalAttrs.version; + hash = "sha256-NZj6sMIhBORh2ZBs/WGI4BYri1REog4ovUug1t5p8Y8="; + }; + + env = lib.optionalAttrs stdenv.hostPlatform.is32bit { + NIX_CFLAGS_COMPILE = "-D_LARGEFILE64_SOURCE"; + }; + + postPatch = '' + patchShebangs . + echo " + @set UPDATED 1 January 1970 + @set UPDATED-MONTH January 1970 + @set EDITION ${finalAttrs.version} + @set VERSION ${finalAttrs.version} + " > doc/version.texi + '' + + lib.optionalString (!withMan) '' + substituteInPlace src/Makefile.am \ + --replace-fail 'man_cd_drive = cd-drive.1' "" \ + --replace-fail 'man_cd_info = cd-info.1' "" \ + --replace-fail 'man_cd_read = cd-read.1' "" \ + --replace-fail 'man_iso_info = iso-info.1' "" \ + --replace-fail 'man_iso_read = iso-read.1' "" + ''; + + configureFlags = [ + (lib.enableFeature withMan "maintainer-mode") + "CFLAGS=-std=gnu17" + ]; + + # autoconf 2.73's AM_ICONV "working iconv" runtime probe reports "no" on + # Darwin's libiconv; skip it via the cache variable. + preConfigure = '' + export am_cv_func_iconv_works=yes + ''; + + nativeBuildInputs = [ + pkg-config + autoreconfHook + texinfo + ] + ++ lib.optionals withMan [ + help2man + ]; + + buildInputs = [ + libcddb + libiconv + ncurses + ]; + + enableParallelBuilding = true; + + outputs = [ + "out" + "lib" + "dev" + "info" + ] + ++ lib.optionals withMan [ + "man" + ]; + + meta = { + description = "Library for OS-independent CD-ROM and CD image access"; + longDescription = '' + GNU libcdio is a library for OS-independent CD-ROM and + CD image access. It includes a library for working with + ISO-9660 filesystems (libiso9660), as well as utility + programs such as an audio CD player and an extractor. + ''; + homepage = "https://www.gnu.org/software/libcdio/"; + license = lib.licenses.gpl2Plus; + platforms = lib.platforms.unix; + }; +}) diff --git a/pkgs/libisoburn/default.nix b/pkgs/libisoburn/default.nix new file mode 100644 index 000000000..2268c7fd9 --- /dev/null +++ b/pkgs/libisoburn/default.nix @@ -0,0 +1,71 @@ +{ + lib, + acl, + attr, + autoreconfHook, + bzip2, + fetchFromGitea, + libburn, + libcdio, + libiconv, + libisofs, + pkg-config, + readline, + stdenv, + zlib, +}: + +stdenv.mkDerivation (finalAttrs: { + pname = "libisoburn"; + version = "1.5.6"; + + src = fetchFromGitea { + domain = "dev.lovelyhq.com"; + owner = "libburnia"; + repo = "libisoburn"; + rev = "release-${finalAttrs.version}"; + hash = "sha256-16qNVlWFVXfvbte5EgP/u193wK2GV/r22hVX0SZWr+0="; + }; + + nativeBuildInputs = [ + autoreconfHook + pkg-config + ]; + + buildInputs = [ + bzip2 + libcdio + libiconv + readline + zlib + libburn + libisofs + ] + ++ lib.optionals stdenv.hostPlatform.isLinux [ + acl + attr + ]; + + propagatedBuildInputs = lib.optionals stdenv.hostPlatform.isLinux [ + acl + ]; + + outputs = [ + "out" + "lib" + "dev" + "info" + "man" + ]; + + strictDeps = true; + + meta = { + homepage = "http://libburnia-project.org/"; + description = "Enables creation and expansion of ISO-9660 filesystems on CD/DVD/BD"; + changelog = "https://dev.lovelyhq.com/libburnia/libisoburn/src/tag/${finalAttrs.src.rev}/ChangeLog"; + license = lib.licenses.gpl2Plus; + mainProgram = "osirrox"; + inherit (libisofs.meta) platforms; + }; +}) diff --git a/pkgs/libisofs/default.nix b/pkgs/libisofs/default.nix new file mode 100644 index 000000000..3c7a08656 --- /dev/null +++ b/pkgs/libisofs/default.nix @@ -0,0 +1,54 @@ +{ + lib, + stdenv, + fetchFromGitea, + acl, + attr, + autoreconfHook, + libiconv, + zlib, +}: + +stdenv.mkDerivation (finalAttrs: { + pname = "libisofs"; + version = "1.5.8"; + + src = fetchFromGitea { + domain = "dev.lovelyhq.com"; + owner = "libburnia"; + repo = "libisofs"; + rev = "release-${finalAttrs.version}"; + hash = "sha256-tOkJfS/utUPn38rn0u5zAo1N4IIkvpejg89Oxw6Xqv4="; + }; + + nativeBuildInputs = [ + autoreconfHook + ]; + + buildInputs = + lib.optionals stdenv.hostPlatform.isLinux [ + acl + attr + ] + ++ lib.optionals stdenv.hostPlatform.isDarwin [ + libiconv + ] + ++ [ + zlib + ]; + + outputs = [ + "out" + "dev" + ]; + + enableParallelBuilding = true; + + meta = { + homepage = "https://dev.lovelyhq.com/libburnia/web/wiki"; + description = "Library to create an ISO-9660 filesystem with extensions like RockRidge or Joliet"; + changelog = "https://dev.lovelyhq.com/libburnia/libisofs/src/tag/${finalAttrs.src.rev}/ChangeLog"; + license = lib.licenses.gpl2Plus; + platforms = lib.platforms.unix; + }; +}) diff --git a/pkgs/mtools/default.nix b/pkgs/mtools/default.nix new file mode 100644 index 000000000..7f766e3e7 --- /dev/null +++ b/pkgs/mtools/default.nix @@ -0,0 +1,24 @@ +{ + lib, + stdenv, + fetchurl, +}: + +stdenv.mkDerivation (finalAttrs: { + pname = "mtools"; + version = "4.0.49"; + + src = fetchurl { + url = "mirror://gnu/mtools/mtools-${finalAttrs.version}.tar.bz2"; + hash = "sha256-b+UZNYPW58Wdp15j1yNPdsCwfK8zsQOJT0b2aocf/J8="; + }; + + enableParallelBuilding = true; + + meta = { + homepage = "https://www.gnu.org/software/mtools/"; + description = "Utilities to access MS-DOS disks"; + platforms = lib.platforms.unix; + license = lib.licenses.gpl3; + }; +}) From 0a7aa9245ea500938e94e8e068d5beb7a9ad99fe Mon Sep 17 00:00:00 2001 From: Jonathan Ringer Date: Wed, 16 Sep 2026 06:06:13 -0700 Subject: [PATCH 13/14] ekaos/initrd: fix makeInitrd and modules tree references Use pkgs.makeInitrd instead of kernelPackages.kernel.makeInitrd which no longer exists after makeInitrd was moved to the kernel variant passthru. Use kernel modules directory directly instead of the missing pkgs.aggregateModules function. --- ekaos/lib/make-initrd.nix | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/ekaos/lib/make-initrd.nix b/ekaos/lib/make-initrd.nix index d13111c15..7a7615176 100644 --- a/ekaos/lib/make-initrd.nix +++ b/ekaos/lib/make-initrd.nix @@ -193,13 +193,12 @@ let exec switch_root /mnt-root /init ''; - # Kernel modules directory — aggregateModules takes a list of module - # packages (kernel, out-of-tree drivers, etc.) and runs depmod. - modulesTree = pkgs.aggregateModules [ kernelPackages.kernel ]; + # Kernel modules directory + modulesTree = "${kernelPackages.kernel}/lib/modules"; in -kernelPackages.kernel.makeInitrd { +pkgs.makeInitrd { contents = [ { object = bootStage1; From 795f244b63af51ce5e6c5d4eaa229f09be76545b Mon Sep 17 00:00:00 2001 From: Jonathan Ringer Date: Wed, 16 Sep 2026 06:06:21 -0700 Subject: [PATCH 14/14] ekaos/installer: add hardware profile and generic ISO configuration Add a kitchen-sink hardware profile for installation media that loads drivers for all common GPUs (Intel, AMD, nouveau), audio (HDA, SOF), WiFi (iwlwifi, ath, rtw, mt7921, brcm), Ethernet, Bluetooth, input devices, Thunderbolt, and IPU6 cameras. Includes nixos-facter for post-install hardware detection. Add ekaos/configurations/iso-generic.nix for building a generic installer ISO: nix-build ekaos/configurations/iso-generic.nix --- ekaos/configurations/iso-generic.nix | 33 +++++++ ekaos/modules/installer/hardware-profile.nix | 99 ++++++++++++++++++++ 2 files changed, 132 insertions(+) create mode 100644 ekaos/configurations/iso-generic.nix create mode 100644 ekaos/modules/installer/hardware-profile.nix diff --git a/ekaos/configurations/iso-generic.nix b/ekaos/configurations/iso-generic.nix new file mode 100644 index 000000000..7703a58e1 --- /dev/null +++ b/ekaos/configurations/iso-generic.nix @@ -0,0 +1,33 @@ +# Generic EkaOS installation ISO +# +# Build with: +# nix-build -A isoImage '' -I ekaos=./ekaos/configurations/iso-generic.nix +# +# Or directly: +# nix-build ekaos/configurations/iso-generic.nix +# +# The resulting ISO is at: result/iso/ekaos-generic-*.iso +{ + system ? "x86_64-linux", + pkgs ? import ../../. { inherit system; }, +}: +let + ekaos = import ../default.nix { + inherit system pkgs; + modules = [ + ../modules/installer/installation-cd-base.nix + ../modules/installer/hardware-profile.nix + ( + { lib, ... }: + { + isoImage.edition = "generic"; + isoImage.bootMenuLabel = "EkaOS Installer"; + + system.ekaos.version = "25.05"; + boot.kernelPackages = pkgs.linux.pkgs; + } + ) + ]; + }; +in +ekaos.config.system.build.isoImage diff --git a/ekaos/modules/installer/hardware-profile.nix b/ekaos/modules/installer/hardware-profile.nix new file mode 100644 index 000000000..2711cf1fd --- /dev/null +++ b/ekaos/modules/installer/hardware-profile.nix @@ -0,0 +1,99 @@ +# Broad hardware support profile for installation media +# +# Loads a wide range of drivers, firmware, and kernel modules so the +# ISO boots on as much hardware as possible without a facter report. +# After installation, the facter-generated config takes over with +# precise per-machine settings. +# +# This module is imported by ISO configurations — it is NOT registered +# in module-list.nix. +{ + config, + lib, + pkgs, + ... +}: + +{ + # ── Firmware ────────────────────────────────────────────────────── + hardware.enableRedistributableFirmware = true; + + # ── GPU ─────────────────────────────────────────────────────────── + boot.initrd.kernelModules = [ + # Intel + "i915" + # AMD + "amdgpu" + # NVIDIA (nouveau for live boot — proprietary needs post-install opt-in) + "nouveau" + ]; + + hardware.graphics.enable = lib.mkDefault true; + + # ── Audio ───────────────────────────────────────────────────────── + boot.initrd.availableKernelModules = [ + # Intel HDA (most desktops and older laptops) + "snd_hda_intel" + # Intel SOF (Tiger Lake+ laptops) + "snd_sof_pci" + "snd_sof_pci_intel_tgl" + "snd_sof_pci_intel_mtl" + "snd_sof_intel_hda_common" + # AMD audio + "snd_hda_codec_realtek" + "snd_hda_codec_hdmi" + # USB audio + "snd_usb_audio" + + # ── Network ───────────────────────────────────────────────────── + # Intel Ethernet + "e1000e" + "igc" + "igb" + "ixgbe" + # Realtek Ethernet + "r8169" + # Broadcom + "tg3" + # Intel WiFi + "iwlwifi" + # Qualcomm/Atheros WiFi + "ath11k_pci" + "ath10k_pci" + # Realtek WiFi + "rtw89_8852be" + "rtw88_8822ce" + # MediaTek WiFi + "mt7921e" + # Broadcom WiFi + "brcmfmac" + + # ── Input ─────────────────────────────────────────────────────── + "hid_generic" + "hid_multitouch" + "i2c_hid_acpi" + "i2c_hid" + + # ── Thunderbolt ───────────────────────────────────────────────── + "thunderbolt" + + # ── Camera (IPU6/IPU7 raw kernel support) ─────────────────────── + "intel_ipu6" + "intel_ipu6_isys" + ]; + + # ── Bluetooth ───────────────────────────────────────────────────── + hardware.bluetooth.enable = lib.mkDefault true; + + # ── Gamepad / controller modules (hot-plug) ─────────────────────── + boot.kernelModules = [ + "xpad" + "hid-sony" + "hid-nintendo" + ]; + + # ── nixos-facter for post-install hardware detection ────────────── + environment.systemPackages = [ + pkgs.nixos-facter + ]; +}