diff --git a/maintainers/maintainer-list.nix b/maintainers/maintainer-list.nix index b1246893c90b6..b142a90bf2a1d 100644 --- a/maintainers/maintainer-list.nix +++ b/maintainers/maintainer-list.nix @@ -3756,6 +3756,12 @@ matrix = "@cedric:cbarrete.com"; name = "Cédric Barreteau"; }; + cbingman = { + name = "Christian Bingman"; + email = "maintainer@christianbingman.com"; + github = "ChristianBingman"; + githubId = 42191425; + }; cbleslie = { email = "cameronleslie@gmail.com"; github = "cbleslie"; diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index 2bfb963c19dfc..4da5052b7f9e3 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -643,6 +643,7 @@ ./services/hardware/udisks2.nix ./services/hardware/undervolt.nix ./services/hardware/upower.nix + ./services/hardware/usbipd.nix ./services/hardware/usbmuxd.nix ./services/hardware/usbrelayd.nix ./services/hardware/vdr.nix diff --git a/nixos/modules/services/hardware/usbipd.nix b/nixos/modules/services/hardware/usbipd.nix new file mode 100755 index 0000000000000..843d8c3c4aace --- /dev/null +++ b/nixos/modules/services/hardware/usbipd.nix @@ -0,0 +1,99 @@ +{ + lib, + pkgs, + config, + ... +}: +let + cfg = config.services.usbipd; + device = lib.types.submodule { + options = { + productid = lib.mkOption { + type = lib.types.str; + description = "The product id of the device"; + }; + vendorid = lib.mkOption { + type = lib.types.str; + description = "The vendor id of the device"; + }; + }; + }; +in +{ + options.services.usbipd = { + enable = lib.mkEnableOption "usbip server"; + kernelPackage = lib.mkPackageOption pkgs.linuxPackages_latest "usbip" { }; + devices = lib.mkOption { + type = lib.types.listOf device; + default = [ ]; + description = "List of USB devices to watch and automatically export."; + example = [ + { + productid = "xxxx"; + vendorid = "xxxx"; + } + ]; + }; + openFirewall = lib.mkOption { + type = lib.types.bool; + default = true; + description = "Open port 3240 for usbipd"; + example = false; + }; + }; + + config = lib.mkIf cfg.enable { + boot.extraModulePackages = [ cfg.kernelPackage ]; + boot.kernelModules = [ + "usbip-core" + "usbip-host" + ]; + networking.firewall.allowedTCPPorts = lib.mkIf cfg.openFirewall [ 3240 ]; + services.udev.extraRules = lib.strings.concatLines ( + (map ( + dev: + "ACTION==\"add\", SUBSYSTEM==\"usb\", ATTRS{idProduct}==\"${dev.productid}\", ATTRS{idVendor}==\"${dev.vendorid}\", RUN+=\"${pkgs.systemd}/bin/systemctl restart usbip-${dev.vendorid}:${dev.productid}.service\"" + ) cfg.devices) + ); + + systemd.services = + (builtins.listToAttrs ( + map (dev: { + name = "usbip-${dev.vendorid}:${dev.productid}"; + value = { + after = [ "usbipd.service" ]; + script = '' + set +e + devices=$(${cfg.kernelPackage}/bin/usbip list -l | grep -E "^.*- busid.*(${dev.vendorid}:${dev.productid})" ) + echo $devices | while read device; do + output=$(${cfg.kernelPackage}/bin/usbip -d bind -b $(echo $device | ${pkgs.gawk}/bin/awk '{ print $3 }') 2>&1) + code=$? + + echo $output + if [[ $output =~ "already bound" ]] || [ $code -eq 0 ]; then + continue + else + exit $code + fi + done + ''; + serviceConfig.Type = "oneshot"; + serviceConfig.RemainAfterExit = true; + restartTriggers = [ "usbipd.service" ]; + }; + }) cfg.devices + )) + // { + usbipd = { + wantedBy = [ "multi-user.target" ]; + script = '' + ${lib.getExe' pkgs.kmod "modprobe"} usbip-host usbip-core + exec ${lib.getExe' cfg.kernelPackage "usbipd"} -D + ''; + serviceConfig.Type = "forking"; + }; + }; + }; + meta.maintainers = with lib.maintainers; [ cbingman ]; + meta.buildDocsInSandbox = false; +}