From bb22c84e70a4ace843acdc3b84a120372a827bd0 Mon Sep 17 00:00:00 2001 From: Christoph Honal Date: Sat, 18 Apr 2026 02:41:11 +0200 Subject: [PATCH 1/2] nixos/ipu6: Fix device persistence and pipewire integration --- nixos/modules/hardware/video/webcam/ipu6.nix | 54 ++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/nixos/modules/hardware/video/webcam/ipu6.nix b/nixos/modules/hardware/video/webcam/ipu6.nix index aab986251d75..d00c1a6e0952 100644 --- a/nixos/modules/hardware/video/webcam/ipu6.nix +++ b/nixos/modules/hardware/video/webcam/ipu6.nix @@ -9,6 +9,7 @@ let inherit (lib) mkDefault mkEnableOption + mkForce mkIf mkOption optional @@ -38,6 +39,19 @@ in ''; }; + videoDeviceNumber = mkOption { + type = types.int; + default = 50; + description = '' + v4l2loopback device number for the relay output (`/dev/videoN`). + + Must be fixed so application camera permission grants, which are keyed to + the PipeWire node name (derived from the sysfs device path), survive + reboots. Choose a number above the IPU6 raw node range (typically 3-34) + and any other v4l2loopback devices on the system. + ''; + }; + }; config = mkIf cfg.enable { @@ -51,10 +65,32 @@ in ivsc-firmware ]; + # Restrict IPU6 raw nodes and media controller to root. DRIVERS== matches the + # parent PCI device. 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. + systemd.tmpfiles.rules = [ "d /run/camera 0755 root video -" ]; + + # Disable raw IPU6 nodes in WirePlumber. Matched via udev ID_V4L_PRODUCT=ipu6, + # set by the kernel at device registration without requiring a device open. + services.pipewire.wireplumber.extraConfig."ipu6-v4l2-rules" = { + "monitor.v4l2.rules" = [ + { + matches = [ { "device.product.name" = "ipu6"; } ]; + actions = { + "update-props" = { + "device.disabled" = true; + }; + }; + } + ]; + }; + services.v4l2-relayd.instances.ipu6 = { enable = mkDefault true; @@ -72,5 +108,23 @@ in format = mkIf (cfg.platform != "ipu6") (mkDefault "NV12"); }; }; + + # Override preStart/postStop from the v4l2-relayd module: + # - Use a fixed device number so PipeWire node names (and application permission + # grants) are stable across reboots. Exit 17 (EEXIST) is success. + # - Keep the device alive on stop so apps survive relay restarts via + # VIDIOC_DQBUF blocking rather than receiving errors. + systemd.services.v4l2-relayd-ipu6 = { + preStart = mkForce '' + mkdir -p "$(dirname "$V4L2_DEVICE_FILE")" + ${config.boot.kernelPackages.v4l2loopback.bin}/bin/v4l2loopback-ctl \ + add --name "Intel MIPI Camera" --exclusive-caps=1 ${toString cfg.videoDeviceNumber} || [ $? -eq 17 ] + echo /dev/video${toString cfg.videoDeviceNumber} > "$V4L2_DEVICE_FILE" + ''; + postStop = mkForce '' + rm -rf "$(dirname "$V4L2_DEVICE_FILE")" + ''; + }; + }; } From 6fa956a7308306f370d3d9184f1baf34e96468ca Mon Sep 17 00:00:00 2001 From: Christoph Honal Date: Sat, 18 Apr 2026 03:29:57 +0200 Subject: [PATCH 2/2] nixos/v4l2-relayd: Don't create dummy video device --- nixos/modules/services/video/v4l2-relayd.nix | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/nixos/modules/services/video/v4l2-relayd.nix b/nixos/modules/services/video/v4l2-relayd.nix index bcf8725c845b..654c4a0aa272 100644 --- a/nixos/modules/services/video/v4l2-relayd.nix +++ b/nixos/modules/services/video/v4l2-relayd.nix @@ -221,6 +221,11 @@ in boot = mkIf ((length enabledInstances) > 0) { extraModulePackages = [ kernelPackages.v4l2loopback ]; kernelModules = [ "v4l2loopback" ]; + # Prevent v4l2loopback from auto-creating a device at load time. An + # unconfigured device has a degenerate framerate range that breaks + # GStreamer caps negotiation. All devices are created at runtime via + # v4l2loopback-ctl add in each instance's preStart instead. + extraModprobeConfig = "options v4l2loopback devices=0"; }; systemd.services = mkInstanceServices enabledInstances;