about summary refs log tree commit diff
path: root/nixpkgs/nixos/modules/services/hardware
diff options
context:
space:
mode:
Diffstat (limited to 'nixpkgs/nixos/modules/services/hardware')
-rw-r--r--nixpkgs/nixos/modules/services/hardware/80-net-setup-link.rules13
-rw-r--r--nixpkgs/nixos/modules/services/hardware/acpid.nix156
-rw-r--r--nixpkgs/nixos/modules/services/hardware/actkbd.nix133
-rw-r--r--nixpkgs/nixos/modules/services/hardware/bluetooth.nix89
-rw-r--r--nixpkgs/nixos/modules/services/hardware/bolt.nix34
-rw-r--r--nixpkgs/nixos/modules/services/hardware/brltty.nix50
-rw-r--r--nixpkgs/nixos/modules/services/hardware/evscript.nix49
-rw-r--r--nixpkgs/nixos/modules/services/hardware/freefall.nix64
-rw-r--r--nixpkgs/nixos/modules/services/hardware/fwupd.nix119
-rw-r--r--nixpkgs/nixos/modules/services/hardware/illum.nix35
-rw-r--r--nixpkgs/nixos/modules/services/hardware/interception-tools.nix61
-rw-r--r--nixpkgs/nixos/modules/services/hardware/irqbalance.nix30
-rw-r--r--nixpkgs/nixos/modules/services/hardware/lcd.nix172
-rw-r--r--nixpkgs/nixos/modules/services/hardware/lirc.nix100
-rw-r--r--nixpkgs/nixos/modules/services/hardware/nvidia-optimus.nix43
-rw-r--r--nixpkgs/nixos/modules/services/hardware/pcscd.nix69
-rw-r--r--nixpkgs/nixos/modules/services/hardware/pommed.nix50
-rw-r--r--nixpkgs/nixos/modules/services/hardware/ratbagd.nix32
-rw-r--r--nixpkgs/nixos/modules/services/hardware/sane.nix162
-rw-r--r--nixpkgs/nixos/modules/services/hardware/sane_extra_backends/brscan4.nix115
-rw-r--r--nixpkgs/nixos/modules/services/hardware/sane_extra_backends/brscan4_etc_files.nix71
-rw-r--r--nixpkgs/nixos/modules/services/hardware/sane_extra_backends/dsseries.nix26
-rw-r--r--nixpkgs/nixos/modules/services/hardware/tcsd.nix151
-rw-r--r--nixpkgs/nixos/modules/services/hardware/thermald.nix52
-rw-r--r--nixpkgs/nixos/modules/services/hardware/thinkfan.nix152
-rw-r--r--nixpkgs/nixos/modules/services/hardware/tlp.nix120
-rw-r--r--nixpkgs/nixos/modules/services/hardware/trezord.nix60
-rw-r--r--nixpkgs/nixos/modules/services/hardware/triggerhappy.nix123
-rw-r--r--nixpkgs/nixos/modules/services/hardware/u2f.nix23
-rw-r--r--nixpkgs/nixos/modules/services/hardware/udev.nix320
-rw-r--r--nixpkgs/nixos/modules/services/hardware/udisks2.nix47
-rw-r--r--nixpkgs/nixos/modules/services/hardware/undervolt.nix134
-rw-r--r--nixpkgs/nixos/modules/services/hardware/upower.nix104
-rw-r--r--nixpkgs/nixos/modules/services/hardware/usbmuxd.nix74
-rw-r--r--nixpkgs/nixos/modules/services/hardware/vdr.nix81
35 files changed, 3114 insertions, 0 deletions
diff --git a/nixpkgs/nixos/modules/services/hardware/80-net-setup-link.rules b/nixpkgs/nixos/modules/services/hardware/80-net-setup-link.rules
new file mode 100644
index 000000000000..18547f170a3f
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/hardware/80-net-setup-link.rules
@@ -0,0 +1,13 @@
+# Copied from systemd 203.
+ACTION=="remove", GOTO="net_name_slot_end"
+SUBSYSTEM!="net", GOTO="net_name_slot_end"
+NAME!="", GOTO="net_name_slot_end"
+
+IMPORT{cmdline}="net.ifnames"
+ENV{net.ifnames}=="0", GOTO="net_name_slot_end"
+
+NAME=="", ENV{ID_NET_NAME_ONBOARD}!="", NAME="$env{ID_NET_NAME_ONBOARD}"
+NAME=="", ENV{ID_NET_NAME_SLOT}!="", NAME="$env{ID_NET_NAME_SLOT}"
+NAME=="", ENV{ID_NET_NAME_PATH}!="", NAME="$env{ID_NET_NAME_PATH}"
+
+LABEL="net_name_slot_end"
diff --git a/nixpkgs/nixos/modules/services/hardware/acpid.nix b/nixpkgs/nixos/modules/services/hardware/acpid.nix
new file mode 100644
index 000000000000..4c97485d9726
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/hardware/acpid.nix
@@ -0,0 +1,156 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  canonicalHandlers = {
+    powerEvent = {
+      event = "button/power.*";
+      action = config.services.acpid.powerEventCommands;
+    };
+
+    lidEvent = {
+      event = "button/lid.*";
+      action = config.services.acpid.lidEventCommands;
+    };
+
+    acEvent = {
+      event = "ac_adapter.*";
+      action = config.services.acpid.acEventCommands;
+    };
+  };
+
+  acpiConfDir = pkgs.runCommand "acpi-events" { preferLocalBuild = true; }
+    ''
+      mkdir -p $out
+      ${
+        # Generate a configuration file for each event. (You can't have
+        # multiple events in one config file...)
+        let f = name: handler:
+          ''
+            fn=$out/${name}
+            echo "event=${handler.event}" > $fn
+            echo "action=${pkgs.writeShellScriptBin "${name}.sh" handler.action }/bin/${name}.sh '%e'" >> $fn
+          '';
+        in concatStringsSep "\n" (mapAttrsToList f (canonicalHandlers // config.services.acpid.handlers))
+      }
+    '';
+
+in
+
+{
+
+  ###### interface
+
+  options = {
+
+    services.acpid = {
+
+      enable = mkOption {
+        type = types.bool;
+        default = false;
+        description = "Whether to enable the ACPI daemon.";
+      };
+
+      logEvents = mkOption {
+        type = types.bool;
+        default = false;
+        description = "Log all event activity.";
+      };
+
+      handlers = mkOption {
+        type = types.attrsOf (types.submodule {
+          options = {
+            event = mkOption {
+              type = types.str;
+              example = [ "button/power.*" "button/lid.*" "ac_adapter.*" "button/mute.*" "button/volumedown.*" "cd/play.*" "cd/next.*" ];
+              description = "Event type.";
+            };
+
+            action = mkOption {
+              type = types.lines;
+              description = "Shell commands to execute when the event is triggered.";
+            };
+          };
+        });
+
+        description = ''
+          Event handlers.
+
+          <note><para>
+            Handler can be a single command.
+          </para></note>
+        '';
+        default = {};
+        example = {
+          ac-power = {
+            event = "ac_adapter/*";
+            action = ''
+              vals=($1)  # space separated string to array of multiple values
+              case ''${vals[3]} in
+                  00000000)
+                      echo unplugged >> /tmp/acpi.log
+                      ;;
+                  00000001)
+                      echo plugged in >> /tmp/acpi.log
+                      ;;
+                  *)
+                      echo unknown >> /tmp/acpi.log
+                      ;;
+              esac
+            '';
+          };
+        };
+      };
+
+      powerEventCommands = mkOption {
+        type = types.lines;
+        default = "";
+        description = "Shell commands to execute on a button/power.* event.";
+      };
+
+      lidEventCommands = mkOption {
+        type = types.lines;
+        default = "";
+        description = "Shell commands to execute on a button/lid.* event.";
+      };
+
+      acEventCommands = mkOption {
+        type = types.lines;
+        default = "";
+        description = "Shell commands to execute on an ac_adapter.* event.";
+      };
+
+    };
+
+  };
+
+
+  ###### implementation
+
+  config = mkIf config.services.acpid.enable {
+
+    systemd.services.acpid = {
+      description = "ACPI Daemon";
+
+      wantedBy = [ "multi-user.target" ];
+      after = [ "systemd-udev-settle.service" ];
+
+      path = [ pkgs.acpid ];
+
+      serviceConfig = {
+        Type = "forking";
+      };
+
+      unitConfig = {
+        ConditionVirtualization = "!systemd-nspawn";
+        ConditionPathExists = [ "/proc/acpi" ];
+      };
+
+      script = "acpid ${optionalString config.services.acpid.logEvents "--logevents"} --confdir ${acpiConfDir}";
+    };
+
+  };
+
+}
diff --git a/nixpkgs/nixos/modules/services/hardware/actkbd.nix b/nixpkgs/nixos/modules/services/hardware/actkbd.nix
new file mode 100644
index 000000000000..4168140b287a
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/hardware/actkbd.nix
@@ -0,0 +1,133 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  cfg = config.services.actkbd;
+
+  configFile = pkgs.writeText "actkbd.conf" ''
+    ${concatMapStringsSep "\n"
+      ({ keys, events, attributes, command, ... }:
+        ''${concatMapStringsSep "+" toString keys}:${concatStringsSep "," events}:${concatStringsSep "," attributes}:${command}''
+      )
+      cfg.bindings}
+    ${cfg.extraConfig}
+  '';
+
+  bindingCfg = { ... }: {
+    options = {
+
+      keys = mkOption {
+        type = types.listOf types.int;
+        description = "List of keycodes to match.";
+      };
+
+      events = mkOption {
+        type = types.listOf (types.enum ["key" "rep" "rel"]);
+        default = [ "key" ];
+        description = "List of events to match.";
+      };
+
+      attributes = mkOption {
+        type = types.listOf types.str;
+        default = [ "exec" ];
+        description = "List of attributes.";
+      };
+
+      command = mkOption {
+        type = types.str;
+        default = "";
+        description = "What to run.";
+      };
+
+    };
+  };
+
+in
+
+{
+
+  ###### interface
+
+  options = {
+
+    services.actkbd = {
+
+      enable = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Whether to enable the <command>actkbd</command> key mapping daemon.
+
+          Turning this on will start an <command>actkbd</command>
+          instance for every evdev input that has at least one key
+          (which is okay even for systems with tiny memory footprint,
+          since actkbd normally uses &lt;100 bytes of memory per
+          instance).
+
+          This allows binding keys globally without the need for e.g.
+          X11.
+        '';
+      };
+
+      bindings = mkOption {
+        type = types.listOf (types.submodule bindingCfg);
+        default = [];
+        example = lib.literalExample ''
+          [ { keys = [ 113 ]; events = [ "key" ]; command = "''${pkgs.alsaUtils}/bin/amixer -q set Master toggle"; }
+          ]
+        '';
+        description = ''
+          Key bindings for <command>actkbd</command>.
+
+          See <command>actkbd</command> <filename>README</filename> for documentation.
+
+          The example shows a piece of what <option>sound.enableMediaKeys</option> does when enabled.
+        '';
+      };
+
+      extraConfig = mkOption {
+        type = types.lines;
+        default = "";
+        description = ''
+          Literal contents to append to the end of actkbd configuration file.
+        '';
+      };
+
+    };
+
+  };
+
+
+  ###### implementation
+
+  config = mkIf cfg.enable {
+
+    services.udev.packages = lib.singleton (pkgs.writeTextFile {
+      name = "actkbd-udev-rules";
+      destination = "/etc/udev/rules.d/61-actkbd.rules";
+      text = ''
+        ACTION=="add", SUBSYSTEM=="input", KERNEL=="event[0-9]*", ENV{ID_INPUT_KEY}=="1", TAG+="systemd", ENV{SYSTEMD_WANTS}+="actkbd@$env{DEVNAME}.service"
+      '';
+    });
+
+    systemd.services."actkbd@" = {
+      enable = true;
+      restartIfChanged = true;
+      unitConfig = {
+        Description = "actkbd on %I";
+        ConditionPathExists = "%I";
+      };
+      serviceConfig = {
+        Type = "forking";
+        ExecStart = "${pkgs.actkbd}/bin/actkbd -D -c ${configFile} -d %I";
+      };
+    };
+
+    # For testing
+    environment.systemPackages = [ pkgs.actkbd ];
+
+  };
+
+}
diff --git a/nixpkgs/nixos/modules/services/hardware/bluetooth.nix b/nixpkgs/nixos/modules/services/hardware/bluetooth.nix
new file mode 100644
index 000000000000..c5f9d1f9b725
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/hardware/bluetooth.nix
@@ -0,0 +1,89 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.hardware.bluetooth;
+  bluez-bluetooth = cfg.package;
+
+in {
+
+  ###### interface
+
+  options = {
+
+    hardware.bluetooth = {
+      enable = mkEnableOption "support for Bluetooth";
+
+      powerOnBoot = mkOption {
+        type    = types.bool;
+        default = true;
+        description = "Whether to power up the default Bluetooth controller on boot.";
+      };
+
+      package = mkOption {
+        type = types.package;
+        default = pkgs.bluez;
+        defaultText = "pkgs.bluez";
+        example = "pkgs.bluezFull";
+        description = ''
+          Which BlueZ package to use.
+
+          <note><para>
+            Use the <literal>pkgs.bluezFull</literal> package to enable all
+            bluez plugins.
+          </para></note>
+        '';
+      };
+
+      extraConfig = mkOption {
+        type = types.lines;
+        default = "";
+        example = ''
+          [General]
+          ControllerMode = bredr
+        '';
+        description = ''
+          Set additional configuration for system-wide bluetooth (/etc/bluetooth/main.conf).
+
+          NOTE: We already include [Policy], so any configuration under the Policy group should come first.
+        '';
+      };
+    };
+
+  };
+
+  ###### implementation
+
+  config = mkIf cfg.enable {
+
+    environment.systemPackages = [ bluez-bluetooth pkgs.openobex pkgs.obexftp ];
+
+    environment.etc = singleton {
+      source = pkgs.writeText "main.conf" ''
+        [Policy]
+        AutoEnable=${lib.boolToString cfg.powerOnBoot}
+
+        ${cfg.extraConfig}
+      '';
+      target = "bluetooth/main.conf";
+    };
+
+    services.udev.packages = [ bluez-bluetooth ];
+    services.dbus.packages = [ bluez-bluetooth ];
+    systemd.packages       = [ bluez-bluetooth ];
+
+    systemd.services = {
+      bluetooth = {
+        wantedBy = [ "bluetooth.target" ];
+        aliases  = [ "dbus-org.bluez.service" ];
+      };
+    };
+
+    systemd.user.services = {
+      obex.aliases = [ "dbus-org.bluez.obex.service" ];
+    };
+
+  };
+
+}
diff --git a/nixpkgs/nixos/modules/services/hardware/bolt.nix b/nixpkgs/nixos/modules/services/hardware/bolt.nix
new file mode 100644
index 000000000000..32b60af06037
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/hardware/bolt.nix
@@ -0,0 +1,34 @@
+# Thunderbolt 3 device manager
+
+{ config, lib, pkgs, ...}:
+
+with lib;
+
+{
+  options = {
+
+    services.hardware.bolt = {
+
+      enable = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Whether to enable Bolt, a userspace daemon to enable
+          security levels for Thunderbolt 3 on GNU/Linux.
+
+          Bolt is used by GNOME 3 to handle Thunderbolt settings.
+        '';
+      };
+
+    };
+
+  };
+
+  config = mkIf config.services.hardware.bolt.enable {
+
+    environment.systemPackages = [ pkgs.bolt ];
+    services.udev.packages = [ pkgs.bolt ];
+    systemd.packages = [ pkgs.bolt ];
+
+  };
+}
diff --git a/nixpkgs/nixos/modules/services/hardware/brltty.nix b/nixpkgs/nixos/modules/services/hardware/brltty.nix
new file mode 100644
index 000000000000..1266e8f81e5b
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/hardware/brltty.nix
@@ -0,0 +1,50 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.services.brltty;
+
+in {
+
+  options = {
+
+    services.brltty.enable = mkOption {
+      type = types.bool;
+      default = false;
+      description = "Whether to enable the BRLTTY daemon.";
+    };
+
+  };
+
+  config = mkIf cfg.enable {
+
+    systemd.services.brltty = {
+      description = "Braille Device Support";
+      unitConfig = {
+        Documentation = "http://mielke.cc/brltty/";
+        DefaultDependencies = "no";
+        RequiresMountsFor = "${pkgs.brltty}/var/lib/brltty";
+      };
+      serviceConfig = {
+        ExecStart = "${pkgs.brltty}/bin/brltty --no-daemon";
+        Type = "notify";
+        TimeoutStartSec = 5;
+        TimeoutStopSec = 10;
+        Restart = "always";
+        RestartSec = 30;
+        Nice = -10;
+        OOMScoreAdjust = -900;
+        ProtectHome = "read-only";
+        ProtectSystem = "full";
+        SystemCallArchitectures = "native";
+      };
+      wants = [ "systemd-udev-settle.service" ];
+      after = [ "local-fs.target" "systemd-udev-settle.service" ];
+      before = [ "sysinit.target" ];
+      wantedBy = [ "sysinit.target" ];
+    };
+
+  };
+
+}
diff --git a/nixpkgs/nixos/modules/services/hardware/evscript.nix b/nixpkgs/nixos/modules/services/hardware/evscript.nix
new file mode 100644
index 000000000000..2d45ec513f49
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/hardware/evscript.nix
@@ -0,0 +1,49 @@
+{ pkgs, lib, config, ... }:
+
+let
+  cfg = config.services.evscript;
+
+in
+{
+  options = with lib; {
+    services.evscript = {
+      enable = mkEnableOption "the evscript service";
+
+      package = mkOption {
+        description = "evscript package to use for the evscript service";
+        type = types.package;
+        default = pkgs.evscript;
+      };
+
+      devices = mkOption {
+        description = "evdev devices for evscript to listen to";
+        type = types.listOf types.path;
+        example = [ "/dev/input/by-path/pci-0000:00:1d.0-usb-0:1.1:1.0-event-kbd" ];
+      };
+
+      script = mkOption {
+        description = "Dyon script for evscript service to run";
+        type = types.path;
+      };
+    };
+  };
+
+  config = lib.mkIf cfg.enable {
+    boot.kernelModules = [ "uinput" ];
+
+    services.udev.extraRules = ''
+      KERNEL=="uinput", MODE="0660", GROUP="input"
+    '';
+
+    systemd.services.evscript = {
+      wantedBy = [ "multi-user.target" ];
+      serviceConfig.DynamicUser = true;
+      serviceConfig.SupplementaryGroups = [ "input" ];
+      script = ''
+        ${cfg.package}/bin/evscript \
+            ${lib.concatMapStringsSep " " (d: "-d ${d}") cfg.devices} \
+            -f ${cfg.script}
+      '';
+    };
+  };
+}
diff --git a/nixpkgs/nixos/modules/services/hardware/freefall.nix b/nixpkgs/nixos/modules/services/hardware/freefall.nix
new file mode 100644
index 000000000000..066ccaa4d7cf
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/hardware/freefall.nix
@@ -0,0 +1,64 @@
+{ config, lib, pkgs, utils, ... }:
+
+with lib;
+
+let
+
+  cfg = config.services.freefall;
+
+in {
+
+  options.services.freefall = {
+
+    enable = mkOption {
+      type = types.bool;
+      default = false;
+      description = ''
+        Whether to protect HP/Dell laptop hard drives (not SSDs) in free fall.
+      '';
+    };
+
+    package = mkOption {
+      type = types.package;
+      default = pkgs.freefall;
+      defaultText = "pkgs.freefall";
+      description = ''
+        freefall derivation to use.
+      '';
+    };
+
+    devices = mkOption {
+      type = types.listOf types.string;
+      default = [ "/dev/sda" ];
+      description = ''
+        Device paths to all internal spinning hard drives.
+      '';
+    };
+
+  };
+
+  config = let
+
+    mkService = dev:
+      assert dev != "";
+      let dev' = utils.escapeSystemdPath dev; in
+      nameValuePair "freefall-${dev'}" {
+        description = "Free-fall protection for ${dev}";
+        after = [ "${dev'}.device" ];
+        wantedBy = [ "${dev'}.device" ];
+        serviceConfig = {
+          ExecStart = "${cfg.package}/bin/freefall ${dev}";
+          Restart = "on-failure";
+          Type = "forking";
+        };
+      };
+
+  in mkIf cfg.enable {
+
+    environment.systemPackages = [ cfg.package ];
+
+    systemd.services = builtins.listToAttrs (map mkService cfg.devices);
+
+  };
+
+}
diff --git a/nixpkgs/nixos/modules/services/hardware/fwupd.nix b/nixpkgs/nixos/modules/services/hardware/fwupd.nix
new file mode 100644
index 000000000000..cad9fa20de0f
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/hardware/fwupd.nix
@@ -0,0 +1,119 @@
+# fwupd daemon.
+
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.services.fwupd;
+  originalEtc =
+    let
+      mkEtcFile = n: nameValuePair n { source = "${pkgs.fwupd}/etc/${n}"; };
+    in listToAttrs (map mkEtcFile pkgs.fwupd.filesInstalledToEtc);
+  extraTrustedKeys =
+    let
+      mkName = p: "pki/fwupd/${baseNameOf (toString p)}";
+      mkEtcFile = p: nameValuePair (mkName p) { source = p; };
+    in listToAttrs (map mkEtcFile cfg.extraTrustedKeys);
+
+  # We cannot include the file in $out and rely on filesInstalledToEtc
+  # to install it because it would create a cyclic dependency between
+  # the outputs. We also need to enable the remote,
+  # which should not be done by default.
+  testRemote = if cfg.enableTestRemote then {
+    "fwupd/remotes.d/fwupd-tests.conf" = {
+      source = pkgs.runCommand "fwupd-tests-enabled.conf" {} ''
+        sed "s,^Enabled=false,Enabled=true," \
+        "${pkgs.fwupd.installedTests}/etc/fwupd/remotes.d/fwupd-tests.conf" > "$out"
+      '';
+    };
+  } else {};
+in {
+
+  ###### interface
+  options = {
+    services.fwupd = {
+      enable = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Whether to enable fwupd, a DBus service that allows
+          applications to update firmware.
+        '';
+      };
+
+      blacklistDevices = mkOption {
+        type = types.listOf types.string;
+        default = [];
+        example = [ "2082b5e0-7a64-478a-b1b2-e3404fab6dad" ];
+        description = ''
+          Allow blacklisting specific devices by their GUID
+        '';
+      };
+
+      blacklistPlugins = mkOption {
+        type = types.listOf types.string;
+        default = [ "test" ];
+        example = [ "udev" ];
+        description = ''
+          Allow blacklisting specific plugins
+        '';
+      };
+
+      extraTrustedKeys = mkOption {
+        type = types.listOf types.path;
+        default = [];
+        example = literalExample "[ /etc/nixos/fwupd/myfirmware.pem ]";
+        description = ''
+          Installing a public key allows firmware signed with a matching private key to be recognized as trusted, which may require less authentication to install than for untrusted files. By default trusted firmware can be upgraded (but not downgraded) without the user or administrator password. Only very few keys are installed by default.
+        '';
+      };
+
+      enableTestRemote = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Whether to enable test remote. This is used by
+          <link xlink:href="https://github.com/hughsie/fwupd/blob/master/data/installed-tests/README.md">installed tests</link>.
+        '';
+      };
+    };
+  };
+
+
+  ###### implementation
+  config = mkIf cfg.enable {
+    environment.systemPackages = [ pkgs.fwupd ];
+
+    environment.etc = {
+      "fwupd/daemon.conf" = {
+        source = pkgs.writeText "daemon.conf" ''
+          [fwupd]
+          BlacklistDevices=${lib.concatStringsSep ";" cfg.blacklistDevices}
+          BlacklistPlugins=${lib.concatStringsSep ";" cfg.blacklistPlugins}
+        '';
+      };
+      "fwupd/uefi.conf" = {
+        source = pkgs.writeText "uefi.conf" ''
+          [uefi]
+          OverrideESPMountPoint=${config.boot.loader.efi.efiSysMountPoint}
+        '';
+      };
+
+    } // originalEtc // extraTrustedKeys // testRemote;
+
+    services.dbus.packages = [ pkgs.fwupd ];
+
+    services.udev.packages = [ pkgs.fwupd ];
+
+    systemd.packages = [ pkgs.fwupd ];
+
+    systemd.tmpfiles.rules = [
+      "d /var/lib/fwupd 0755 root root -"
+    ];
+  };
+
+  meta = {
+    maintainers = pkgs.fwupd.meta.maintainers;
+  };
+}
diff --git a/nixpkgs/nixos/modules/services/hardware/illum.nix b/nixpkgs/nixos/modules/services/hardware/illum.nix
new file mode 100644
index 000000000000..ff73c99a6537
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/hardware/illum.nix
@@ -0,0 +1,35 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.services.illum;
+in {
+
+  options = {
+
+    services.illum = {
+
+      enable = mkOption {
+        default = false;
+        type = types.bool;
+        description = ''
+          Enable illum, a daemon for controlling screen brightness with brightness buttons.
+        '';
+      };
+
+    };
+
+  };
+
+  config = mkIf cfg.enable {
+
+    systemd.services.illum = {
+      description = "Backlight Adjustment Service";
+      wantedBy = [ "multi-user.target" ];
+      serviceConfig.ExecStart = "${pkgs.illum}/bin/illum-d";
+    };
+
+  };
+
+}
diff --git a/nixpkgs/nixos/modules/services/hardware/interception-tools.nix b/nixpkgs/nixos/modules/services/hardware/interception-tools.nix
new file mode 100644
index 000000000000..fadcb19a016f
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/hardware/interception-tools.nix
@@ -0,0 +1,61 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.services.interception-tools;
+in {
+  options.services.interception-tools = {
+    enable = mkOption {
+      type = types.bool;
+      default = false;
+      description = "Whether to enable the interception tools service.";
+    };
+
+    plugins = mkOption {
+      type = types.listOf types.package;
+      default = [ pkgs.interception-tools-plugins.caps2esc ];
+      description = ''
+        A list of interception tools plugins that will be made available to use
+        inside the udevmon configuration.
+      '';
+    };
+
+    udevmonConfig = mkOption {
+      type = types.either types.str types.path;
+      default = ''
+        - JOB: "intercept -g $DEVNODE | caps2esc | uinput -d $DEVNODE"
+          DEVICE:
+            EVENTS:
+              EV_KEY: [KEY_CAPSLOCK, KEY_ESC]
+      '';
+      example = ''
+        - JOB: "intercept -g $DEVNODE | y2z | x2y | uinput -d $DEVNODE"
+          DEVICE:
+            EVENTS:
+              EV_KEY: [KEY_X, KEY_Y]
+      '';
+      description = ''
+        String of udevmon YAML configuration, or path to a udevmon YAML
+        configuration file.
+      '';
+    };
+  };
+
+  config = mkIf cfg.enable {
+    systemd.services.interception-tools = {
+      description = "Interception tools";
+      path = [ pkgs.bash pkgs.interception-tools ] ++ cfg.plugins;
+      serviceConfig = {
+        ExecStart = ''
+          ${pkgs.interception-tools}/bin/udevmon -c \
+          ${if builtins.typeOf cfg.udevmonConfig == "path"
+          then cfg.udevmonConfig
+          else pkgs.writeText "udevmon.yaml" cfg.udevmonConfig}
+        '';
+        Nice = -20;
+      };
+      wantedBy = [ "multi-user.target" ];
+    };
+  };
+}
diff --git a/nixpkgs/nixos/modules/services/hardware/irqbalance.nix b/nixpkgs/nixos/modules/services/hardware/irqbalance.nix
new file mode 100644
index 000000000000..b139154432cf
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/hardware/irqbalance.nix
@@ -0,0 +1,30 @@
+#
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  cfg = config.services.irqbalance;
+
+in
+{
+  options.services.irqbalance.enable = mkEnableOption "irqbalance daemon";
+
+  config = mkIf cfg.enable {
+
+    systemd.services = {
+      irqbalance = {
+        description = "irqbalance daemon";
+        path = [ pkgs.irqbalance ];
+        serviceConfig =
+          { ExecStart = "${pkgs.irqbalance}/bin/irqbalance --foreground"; };
+        wantedBy = [ "multi-user.target" ];
+      };
+    };
+
+    environment.systemPackages = [ pkgs.irqbalance ];
+
+  };
+
+}
diff --git a/nixpkgs/nixos/modules/services/hardware/lcd.nix b/nixpkgs/nixos/modules/services/hardware/lcd.nix
new file mode 100644
index 000000000000..d78d742cd318
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/hardware/lcd.nix
@@ -0,0 +1,172 @@
+{ config, lib, pkgs, ... }:
+
+let
+  cfg = config.services.hardware.lcd;
+  pkg = lib.getBin pkgs.lcdproc;
+
+  serverCfg = pkgs.writeText "lcdd.conf" ''
+    [server]
+    DriverPath=${pkg}/lib/lcdproc/
+    ReportToSyslog=false
+    Bind=${cfg.serverHost}
+    Port=${toString cfg.serverPort}
+    ${cfg.server.extraConfig}
+  '';
+
+  clientCfg = pkgs.writeText "lcdproc.conf" ''
+    [lcdproc]
+    Server=${cfg.serverHost}
+    Port=${toString cfg.serverPort}
+    ReportToSyslog=false
+    ${cfg.client.extraConfig}
+  '';
+
+  serviceCfg = {
+    DynamicUser = true;
+    Restart = "on-failure";
+    Slice = "lcd.slice";
+  };
+
+in with lib; {
+
+  meta.maintainers = with maintainers; [ peterhoeg ];
+
+  options = with types; {
+    services.hardware.lcd = {
+      serverHost = mkOption {
+        type = str;
+        default = "localhost";
+        description = "Host on which LCDd is listening.";
+      };
+
+      serverPort = mkOption {
+        type = int;
+        default = 13666;
+        description = "Port on which LCDd is listening.";
+      };
+
+      server = {
+        enable = mkOption {
+          type = bool;
+          default = false;
+          description = "Enable the LCD panel server (LCDd)";
+        };
+
+        openPorts = mkOption {
+          type = bool;
+          default = false;
+          description = "Open the ports in the firewall";
+        };
+
+        usbPermissions = mkOption {
+          type = bool;
+          default = false;
+          description = ''
+            Set group-write permissions on a USB device.
+            </para>
+            <para>
+            A USB connected LCD panel will most likely require having its
+            permissions modified for lcdd to write to it. Enabling this option
+            sets group-write permissions on the device identified by
+            <option>services.hardware.lcd.usbVid</option> and
+            <option>services.hardware.lcd.usbPid</option>. In order to find the
+            values, you can run the <command>lsusb</command> command. Example
+            output:
+            </para>
+            <para>
+            <literal>
+            Bus 005 Device 002: ID 0403:c630 Future Technology Devices International, Ltd lcd2usb interface
+            </literal>
+            </para>
+            <para>
+            In this case the vendor id is 0403 and the product id is c630.
+          '';
+        };
+
+        usbVid = mkOption {
+          type = str;
+          default = "";
+          description = "The vendor ID of the USB device to claim.";
+        };
+
+        usbPid = mkOption {
+          type = str;
+          default = "";
+          description = "The product ID of the USB device to claim.";
+        };
+
+        usbGroup = mkOption {
+          type = str;
+          default = "dialout";
+          description = "The group to use for settings permissions. This group must exist or you will have to create it.";
+        };
+
+        extraConfig = mkOption {
+          type = lines;
+          default = "";
+          description = "Additional configuration added verbatim to the server config.";
+        };
+      };
+
+      client = {
+        enable = mkOption {
+          type = bool;
+          default = false;
+          description = "Enable the LCD panel client (LCDproc)";
+        };
+
+        extraConfig = mkOption {
+          type = lines;
+          default = "";
+          description = "Additional configuration added verbatim to the client config.";
+        };
+
+        restartForever = mkOption {
+          type = bool;
+          default = true;
+          description = "Try restarting the client forever.";
+        };
+      };
+    };
+  };
+
+  config = mkIf (cfg.server.enable || cfg.client.enable) {
+    networking.firewall.allowedTCPPorts = mkIf (cfg.server.enable && cfg.server.openPorts) [ cfg.serverPort ];
+
+    services.udev.extraRules = mkIf (cfg.server.enable && cfg.server.usbPermissions) ''
+      ACTION=="add", SUBSYSTEMS=="usb", ATTRS{idVendor}=="${cfg.server.usbVid}", ATTRS{idProduct}=="${cfg.server.usbPid}", MODE="660", GROUP="${cfg.server.usbGroup}"
+    '';
+
+    systemd.services = {
+      lcdd = mkIf cfg.server.enable {
+        description = "LCDproc - server";
+        wantedBy = [ "lcd.target" ];
+        serviceConfig = serviceCfg // {
+          ExecStart = "${pkg}/bin/LCDd -f -c ${serverCfg}";
+          SupplementaryGroups = cfg.server.usbGroup;
+        };
+      };
+
+      lcdproc = mkIf cfg.client.enable {
+        description = "LCDproc - client";
+        after = [ "lcdd.service" ];
+        wantedBy = [ "lcd.target" ];
+        serviceConfig = serviceCfg // {
+          ExecStart = "${pkg}/bin/lcdproc -f -c ${clientCfg}";
+          # If the server is being restarted at the same time, the client will
+          # fail as it cannot connect, so space it out a bit.
+          RestartSec = "5";
+          # Allow restarting for eternity
+          StartLimitIntervalSec = lib.mkIf cfg.client.restartForever "0";
+          StartLimitBurst = lib.mkIf cfg.client.restartForever "0";
+        };
+      };
+    };
+
+    systemd.targets.lcd = {
+      description = "LCD client/server";
+      after = [ "lcdd.service" "lcdproc.service" ];
+      wantedBy = [ "multi-user.target" ];
+    };
+  };
+}
diff --git a/nixpkgs/nixos/modules/services/hardware/lirc.nix b/nixpkgs/nixos/modules/services/hardware/lirc.nix
new file mode 100644
index 000000000000..826e512c75d1
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/hardware/lirc.nix
@@ -0,0 +1,100 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.services.lirc;
+in {
+
+  ###### interface
+
+  options = {
+    services.lirc = {
+
+      enable = mkEnableOption "LIRC daemon";
+
+      options = mkOption {
+        type = types.lines;
+        example = ''
+          [lircd]
+          nodaemon = False
+        '';
+        description = "LIRC default options descriped in man:lircd(8) (<filename>lirc_options.conf</filename>)";
+      };
+
+      configs = mkOption {
+        type = types.listOf types.lines;
+        description = "Configurations for lircd to load, see man:lircd.conf(5) for details (<filename>lircd.conf</filename>)";
+      };
+
+      extraArguments = mkOption {
+        type = types.listOf types.str;
+        default = [];
+        description = "Extra arguments to lircd.";
+      };
+    };
+  };
+
+  ###### implementation
+
+  config = mkIf cfg.enable {
+
+    # Note: LIRC executables raises a warning, if lirc_options.conf do not exists
+    environment.etc."lirc/lirc_options.conf".text = cfg.options;
+
+    passthru.lirc.socket = "/run/lirc/lircd";
+
+    environment.systemPackages = [ pkgs.lirc ];
+
+    systemd.sockets.lircd = {
+      description = "LIRC daemon socket";
+      wantedBy = [ "sockets.target" ];
+      socketConfig = {
+        ListenStream = config.passthru.lirc.socket;
+        SocketUser = "lirc";
+        SocketMode = "0660";
+      };
+    };
+
+    systemd.services.lircd = let
+      configFile = pkgs.writeText "lircd.conf" (builtins.concatStringsSep "\n" cfg.configs);
+    in {
+      description = "LIRC daemon service";
+      after = [ "network.target" ];
+
+      unitConfig.Documentation = [ "man:lircd(8)" ];
+
+      serviceConfig = {
+        RuntimeDirectory = "lirc";
+
+        # Service runtime directory and socket share same folder.
+        # Following hacks are necessary to get everything right:
+
+        # 1. prevent socket deletion during stop and restart
+        RuntimeDirectoryPreserve = true;
+
+        # 2. fix runtime folder owner-ship, happens when socket activation
+        #    creates the folder
+        PermissionsStartOnly = true;
+        ExecStartPre = [
+          "${pkgs.coreutils}/bin/chown lirc /run/lirc/"
+        ];
+
+        ExecStart = ''
+          ${pkgs.lirc}/bin/lircd --nodaemon \
+            ${escapeShellArgs cfg.extraArguments} \
+            ${configFile}
+        '';
+        User = "lirc";
+      };
+    };
+
+    users.users.lirc = {
+      uid = config.ids.uids.lirc;
+      group = "lirc";
+      description = "LIRC user for lircd";
+    };
+
+    users.groups.lirc.gid = config.ids.gids.lirc;
+  };
+}
diff --git a/nixpkgs/nixos/modules/services/hardware/nvidia-optimus.nix b/nixpkgs/nixos/modules/services/hardware/nvidia-optimus.nix
new file mode 100644
index 000000000000..d53175052c74
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/hardware/nvidia-optimus.nix
@@ -0,0 +1,43 @@
+{ config, lib, ... }:
+
+let kernel = config.boot.kernelPackages; in
+
+{
+
+  ###### interface
+
+  options = {
+
+    hardware.nvidiaOptimus.disable = lib.mkOption {
+      default = false;
+      type = lib.types.bool;
+      description = ''
+        Completely disable the NVIDIA graphics card and use the
+        integrated graphics processor instead.
+      '';
+    };
+
+  };
+
+
+  ###### implementation
+
+  config = lib.mkIf config.hardware.nvidiaOptimus.disable {
+    boot.blacklistedKernelModules = ["nouveau" "nvidia" "nvidiafb" "nvidia-drm"];
+    boot.kernelModules = [ "bbswitch" ];
+    boot.extraModulePackages = [ kernel.bbswitch ];
+
+    systemd.services.bbswitch = {
+      description = "Disable NVIDIA Card";
+      wantedBy = [ "multi-user.target" ];
+      serviceConfig = {
+        Type = "oneshot";
+        RemainAfterExit = true;
+        ExecStart = "${kernel.bbswitch}/bin/discrete_vga_poweroff";
+        ExecStop = "${kernel.bbswitch}/bin/discrete_vga_poweron";
+      };
+      path = [ kernel.bbswitch ];
+    };
+  };
+
+}
diff --git a/nixpkgs/nixos/modules/services/hardware/pcscd.nix b/nixpkgs/nixos/modules/services/hardware/pcscd.nix
new file mode 100644
index 000000000000..f3fc4c3cc79e
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/hardware/pcscd.nix
@@ -0,0 +1,69 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfgFile = pkgs.writeText "reader.conf" config.services.pcscd.readerConfig;
+
+  pluginEnv = pkgs.buildEnv {
+    name = "pcscd-plugins";
+    paths = map (p: "${p}/pcsc/drivers") config.services.pcscd.plugins;
+  };
+
+in {
+
+  ###### interface
+
+  options = {
+
+    services.pcscd = {
+      enable = mkEnableOption "PCSC-Lite daemon";
+
+      plugins = mkOption {
+        type = types.listOf types.package;
+        default = [ pkgs.ccid ];
+        defaultText = "[ pkgs.ccid ]";
+        example = literalExample "[ pkgs.pcsc-cyberjack ]";
+        description = "Plugin packages to be used for PCSC-Lite.";
+      };
+
+      readerConfig = mkOption {
+        type = types.lines;
+        default = "";
+        example = ''
+          FRIENDLYNAME      "Some serial reader"
+          DEVICENAME        /dev/ttyS0
+          LIBPATH           /path/to/serial_reader.so
+          CHANNELID         1
+        '';
+        description = ''
+          Configuration for devices that aren't hotpluggable.
+
+          See <citerefentry><refentrytitle>reader.conf</refentrytitle>
+          <manvolnum>5</manvolnum></citerefentry> for valid options.
+        '';
+      };
+    };
+  };
+
+  ###### implementation
+
+  config = mkIf config.services.pcscd.enable {
+
+    systemd.sockets.pcscd = {
+      description = "PCSC-Lite Socket";
+      wantedBy = [ "sockets.target" ];
+      before = [ "multi-user.target" ];
+      socketConfig.ListenStream = "/run/pcscd/pcscd.comm";
+    };
+
+    systemd.services.pcscd = {
+      description = "PCSC-Lite daemon";
+      environment.PCSCLITE_HP_DROPDIR = pluginEnv;
+      serviceConfig = {
+        ExecStart = "${getBin pkgs.pcsclite}/sbin/pcscd -f -x -c ${cfgFile}";
+        ExecReload = "${getBin pkgs.pcsclite}/sbin/pcscd -H";
+      };
+    };
+  };
+}
diff --git a/nixpkgs/nixos/modules/services/hardware/pommed.nix b/nixpkgs/nixos/modules/services/hardware/pommed.nix
new file mode 100644
index 000000000000..bf7d6a46a293
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/hardware/pommed.nix
@@ -0,0 +1,50 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let cfg = config.services.hardware.pommed;
+    defaultConf = "${pkgs.pommed_light}/etc/pommed.conf.mactel";
+in {
+
+  options = {
+
+    services.hardware.pommed = {
+
+      enable = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Whether to use the pommed tool to handle Apple laptop
+          keyboard hotkeys.
+        '';
+      };
+
+      configFile = mkOption {
+        type = types.nullOr types.path;
+        default = null;
+        description = ''
+          The path to the <filename>pommed.conf</filename> file. Leave
+          to null to use the default config file
+          (<filename>/etc/pommed.conf.mactel</filename>). See the
+          files <filename>/etc/pommed.conf.mactel</filename> and
+          <filename>/etc/pommed.conf.pmac</filename> for examples to
+          build on.
+        '';
+      };
+    };
+
+  };
+
+  config = mkIf cfg.enable {
+    environment.systemPackages = [ pkgs.polkit pkgs.pommed_light ];
+
+    environment.etc."pommed.conf".source =
+      if cfg.configFile == null then defaultConf else cfg.configFile;
+
+    systemd.services.pommed = {
+      description = "Pommed Apple Hotkeys Daemon";
+      wantedBy = [ "multi-user.target" ];
+      script = "${pkgs.pommed_light}/bin/pommed -f";
+    };
+  };
+}
diff --git a/nixpkgs/nixos/modules/services/hardware/ratbagd.nix b/nixpkgs/nixos/modules/services/hardware/ratbagd.nix
new file mode 100644
index 000000000000..103e1d2315ae
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/hardware/ratbagd.nix
@@ -0,0 +1,32 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.services.ratbagd;
+in
+{
+  ###### interface
+
+  options = {
+    services.ratbagd = {
+      enable = mkOption {
+        default = false;
+        description = ''
+          Whether to enable ratbagd for configuring gaming mice.
+        '';
+      };
+    };
+  };
+
+  ###### implementation
+
+  config = mkIf cfg.enable {
+    # Give users access to the "ratbagctl" tool
+    environment.systemPackages = [ pkgs.libratbag ];
+
+    services.dbus.packages = [ pkgs.libratbag ];
+
+    systemd.packages = [ pkgs.libratbag ];
+  };
+}
diff --git a/nixpkgs/nixos/modules/services/hardware/sane.nix b/nixpkgs/nixos/modules/services/hardware/sane.nix
new file mode 100644
index 000000000000..fe05c5a5c06f
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/hardware/sane.nix
@@ -0,0 +1,162 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  pkg = if config.hardware.sane.snapshot
+    then pkgs.sane-backends-git
+    else pkgs.sane-backends;
+
+  sanedConf = pkgs.writeTextFile {
+    name = "saned.conf";
+    destination = "/etc/sane.d/saned.conf";
+    text = ''
+      localhost
+      ${config.services.saned.extraConfig}
+    '';
+  };
+
+  netConf = pkgs.writeTextFile {
+    name = "net.conf";
+    destination = "/etc/sane.d/net.conf";
+    text = ''
+      ${lib.optionalString config.services.saned.enable "localhost"}
+      ${config.hardware.sane.netConf}
+    '';
+  };
+
+  env = {
+    SANE_CONFIG_DIR = config.hardware.sane.configDir;
+    LD_LIBRARY_PATH = [ "${saneConfig}/lib/sane" ];
+  };
+
+  backends = [ pkg netConf ] ++ optional config.services.saned.enable sanedConf ++ config.hardware.sane.extraBackends;
+  saneConfig = pkgs.mkSaneConfig { paths = backends; };
+
+  enabled = config.hardware.sane.enable || config.services.saned.enable;
+
+in
+
+{
+
+  ###### interface
+
+  options = {
+
+    hardware.sane.enable = mkOption {
+      type = types.bool;
+      default = false;
+      description = ''
+        Enable support for SANE scanners.
+
+        <note><para>
+          Users in the "scanner" group will gain access to the scanner, or the "lp" group if it's also a printer.
+        </para></note>
+      '';
+    };
+
+    hardware.sane.snapshot = mkOption {
+      type = types.bool;
+      default = false;
+      description = "Use a development snapshot of SANE scanner drivers.";
+    };
+
+    hardware.sane.extraBackends = mkOption {
+      type = types.listOf types.path;
+      default = [];
+      description = ''
+        Packages providing extra SANE backends to enable.
+
+        <note><para>
+          The example contains the package for HP scanners.
+        </para></note>
+      '';
+      example = literalExample "[ pkgs.hplipWithPlugin ]";
+    };
+
+    hardware.sane.configDir = mkOption {
+      type = types.string;
+      internal = true;
+      description = "The value of SANE_CONFIG_DIR.";
+    };
+
+    hardware.sane.netConf = mkOption {
+      type = types.lines;
+      default = "";
+      example = "192.168.0.16";
+      description = ''
+        Network hosts that should be probed for remote scanners.
+      '';
+    };
+
+    services.saned.enable = mkOption {
+      type = types.bool;
+      default = false;
+      description = ''
+        Enable saned network daemon for remote connection to scanners.
+
+        saned would be runned from <literal>scanner</literal> user; to allow
+        access to hardware that doesn't have <literal>scanner</literal> group
+        you should add needed groups to this user.
+      '';
+    };
+
+    services.saned.extraConfig = mkOption {
+      type = types.lines;
+      default = "";
+      example = "192.168.0.0/24";
+      description = ''
+        Extra saned configuration lines.
+      '';
+    };
+
+  };
+
+
+  ###### implementation
+
+  config = mkMerge [
+    (mkIf enabled {
+      hardware.sane.configDir = mkDefault "${saneConfig}/etc/sane.d";
+
+      environment.systemPackages = backends;
+      environment.sessionVariables = env;
+      services.udev.packages = backends;
+
+      users.groups."scanner".gid = config.ids.gids.scanner;
+    })
+
+    (mkIf config.services.saned.enable {
+      networking.firewall.connectionTrackingModules = [ "sane" ];
+
+      systemd.services."saned@" = {
+        description = "Scanner Service";
+        environment = mapAttrs (name: val: toString val) env;
+        serviceConfig = {
+          User = "scanner";
+          Group = "scanner";
+          ExecStart = "${pkg}/bin/saned";
+        };
+      };
+
+      systemd.sockets.saned = {
+        description = "saned incoming socket";
+        wantedBy = [ "sockets.target" ];
+        listenStreams = [ "0.0.0.0:6566" "[::]:6566" ];
+        socketConfig = {
+          # saned needs to distinguish between IPv4 and IPv6 to open matching data sockets.
+          BindIPv6Only = "ipv6-only";
+          Accept = true;
+          MaxConnections = 1;
+        };
+      };
+
+      users.users."scanner" = {
+        uid = config.ids.uids.scanner;
+        group = "scanner";
+      };
+    })
+  ];
+
+}
diff --git a/nixpkgs/nixos/modules/services/hardware/sane_extra_backends/brscan4.nix b/nixpkgs/nixos/modules/services/hardware/sane_extra_backends/brscan4.nix
new file mode 100644
index 000000000000..f6ed4e25e9cb
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/hardware/sane_extra_backends/brscan4.nix
@@ -0,0 +1,115 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.hardware.sane.brscan4;
+
+  netDeviceList = attrValues cfg.netDevices;
+
+  etcFiles = pkgs.callPackage ./brscan4_etc_files.nix { netDevices = netDeviceList; };
+
+  netDeviceOpts = { name, ... }: {
+
+    options = {
+
+      name = mkOption {
+        type = types.str;
+        description = ''
+          The friendly name you give to the network device. If undefined,
+          the name of attribute will be used.
+        '';
+
+        example = literalExample "office1";
+      };
+
+      model = mkOption {
+        type = types.str;
+        description = ''
+          The model of the network device.
+        '';
+
+        example = literalExample "MFC-7860DW";
+      };
+
+      ip = mkOption {
+        type = with types; nullOr str;
+        default = null;
+        description = ''
+          The ip address of the device. If undefined, you will have to
+          provide a nodename.
+        '';
+
+        example = literalExample "192.168.1.2";
+      };
+
+      nodename = mkOption {
+        type = with types; nullOr str;
+        default = null;
+        description = ''
+          The node name of the device. If undefined, you will have to
+          provide an ip.
+        '';
+
+        example = literalExample "BRW0080927AFBCE";
+      };
+
+    };
+
+
+    config =
+      { name = mkDefault name;
+      };
+  };
+
+in
+
+{
+  options = {
+
+    hardware.sane.brscan4.enable = 
+      mkEnableOption "Brother's brscan4 scan backend" // {
+      description = ''
+        When enabled, will automatically register the "brscan4" sane
+        backend and bring configuration files to their expected location. 
+      '';
+    };
+
+    hardware.sane.brscan4.netDevices = mkOption {
+      default = {};
+      example =
+        { office1 = { model = "MFC-7860DW"; ip = "192.168.1.2"; };
+          office2 = { model = "MFC-7860DW"; nodename = "BRW0080927AFBCE"; };
+        };
+      type = with types; loaOf (submodule netDeviceOpts);
+      description = ''
+        The list of network devices that will be registered against the brscan4
+        sane backend.
+      '';
+    };
+  };
+
+  config = mkIf (config.hardware.sane.enable && cfg.enable) {
+
+    hardware.sane.extraBackends = [
+      pkgs.brscan4
+    ];
+
+    environment.etc = singleton {
+      target = "opt/brother/scanner/brscan4";
+      source = "${etcFiles}/etc/opt/brother/scanner/brscan4";
+    };
+
+    assertions = [
+      { assertion = all (x: !(null != x.ip && null != x.nodename)) netDeviceList;
+          
+        message = ''
+          When describing a network device as part of the attribute list
+          `hardware.sane.brscan4.netDevices`, only one of its `ip` or `nodename`
+          attribute should be specified, not both!
+        '';
+      }
+    ];
+
+  };
+}
diff --git a/nixpkgs/nixos/modules/services/hardware/sane_extra_backends/brscan4_etc_files.nix b/nixpkgs/nixos/modules/services/hardware/sane_extra_backends/brscan4_etc_files.nix
new file mode 100644
index 000000000000..bd114f0d2cca
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/hardware/sane_extra_backends/brscan4_etc_files.nix
@@ -0,0 +1,71 @@
+{ stdenv, lib, brscan4, netDevices ? [] }:
+
+/*
+
+Testing
+-------
+
+No net devices:
+
+~~~
+nix-shell -E 'with import <nixpkgs> { }; brscan4-etc-files'
+~~~
+
+Two net devices:
+
+~~~
+nix-shell -E 'with import <nixpkgs> { }; brscan4-etc-files.override{netDevices=[{name="a"; model="MFC-7860DW"; nodename="BRW0080927AFBCE";} {name="b"; model="MFC-7860DW"; ip="192.168.1.2";}];}'
+~~~
+
+*/
+
+with lib; 
+
+let
+
+  addNetDev = nd: ''
+    brsaneconfig4 -a \
+    name="${nd.name}" \
+    model="${nd.model}" \
+    ${if (hasAttr "nodename" nd && nd.nodename != null) then
+      ''nodename="${nd.nodename}"'' else
+      ''ip="${nd.ip}"''}'';
+  addAllNetDev = xs: concatStringsSep "\n" (map addNetDev xs);
+in
+
+stdenv.mkDerivation rec {
+
+  name = "brscan4-etc-files-0.4.3-3";
+  src = "${brscan4}/opt/brother/scanner/brscan4";
+
+  nativeBuildInputs = [ brscan4 ];
+
+  configurePhase = ":";
+
+  buildPhase = ''
+    TARGET_DIR="$out/etc/opt/brother/scanner/brscan4"
+    mkdir -p "$TARGET_DIR"
+    cp -rp "./models4" "$TARGET_DIR"
+    cp -rp "./Brsane4.ini" "$TARGET_DIR"
+    cp -rp "./brsanenetdevice4.cfg" "$TARGET_DIR"
+
+    export BRSANENETDEVICE4_CFG_FILENAME="$TARGET_DIR/brsanenetdevice4.cfg"
+
+    printf '${addAllNetDev netDevices}\n'
+
+    ${addAllNetDev netDevices}
+  '';
+
+  installPhase = ":";
+
+  dontStrip = true;
+  dontPatchELF = true;
+
+  meta = {
+    description = "Brother brscan4 sane backend driver etc files";
+    homepage = http://www.brother.com;
+    platforms = stdenv.lib.platforms.linux;
+    license = stdenv.lib.licenses.unfree;
+    maintainers = with stdenv.lib.maintainers; [ jraygauthier ];
+  };
+}
diff --git a/nixpkgs/nixos/modules/services/hardware/sane_extra_backends/dsseries.nix b/nixpkgs/nixos/modules/services/hardware/sane_extra_backends/dsseries.nix
new file mode 100644
index 000000000000..d71a17f5ea6b
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/hardware/sane_extra_backends/dsseries.nix
@@ -0,0 +1,26 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+  options = {
+
+    hardware.sane.dsseries.enable =
+      mkEnableOption "Brother DSSeries scan backend" // {
+      description = ''
+        When enabled, will automatically register the "dsseries" SANE backend.
+
+        This supports the Brother DSmobile scanner series, including the
+        DS-620, DS-720D, DS-820W, and DS-920DW scanners.
+      '';
+    };
+  };
+
+  config = mkIf (config.hardware.sane.enable && config.hardware.sane.dsseries.enable) {
+
+    hardware.sane.extraBackends = [ pkgs.dsseries ];
+    services.udev.packages = [ pkgs.dsseries ];
+    boot.kernelModules = [ "sg" ];
+
+  };
+}
diff --git a/nixpkgs/nixos/modules/services/hardware/tcsd.nix b/nixpkgs/nixos/modules/services/hardware/tcsd.nix
new file mode 100644
index 000000000000..d4b0a9495d75
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/hardware/tcsd.nix
@@ -0,0 +1,151 @@
+# tcsd daemon.
+
+{ config, pkgs, lib, ... }:
+
+with lib;
+let
+
+  cfg = config.services.tcsd;
+
+  tcsdConf = pkgs.writeText "tcsd.conf" ''
+    port = 30003
+    num_threads = 10
+    system_ps_file = ${cfg.stateDir}/system.data
+    # This is the log of each individual measurement done by the system.
+    # By re-calculating the PCR registers based on this information, even
+    # finer details about the measured environment can be inferred than
+    # what is available directly from the PCR registers.
+    firmware_log_file = /sys/kernel/security/tpm0/binary_bios_measurements
+    kernel_log_file = /sys/kernel/security/ima/binary_runtime_measurements
+    firmware_pcrs = ${cfg.firmwarePCRs}
+    kernel_pcrs = ${cfg.kernelPCRs}
+    platform_cred = ${cfg.platformCred}
+    conformance_cred = ${cfg.conformanceCred}
+    endorsement_cred = ${cfg.endorsementCred}
+    #remote_ops = create_key,random
+    #host_platform_class = server_12
+    #all_platform_classes = pc_11,pc_12,mobile_12
+  '';
+
+in
+{
+
+  ###### interface
+
+  options = {
+
+    services.tcsd = {
+
+      enable = mkOption {
+        default = false;
+        type = types.bool;
+        description = ''
+          Whether to enable tcsd, a Trusted Computing management service
+          that provides TCG Software Stack (TSS).  The tcsd daemon is
+          the only portal to the Trusted Platform Module (TPM), a hardware
+          chip on the motherboard.
+        '';
+      };
+
+      user = mkOption {
+        default = "tss";
+        type = types.string;
+        description = "User account under which tcsd runs.";
+      };
+
+      group = mkOption {
+        default = "tss";
+        type = types.string;
+        description = "Group account under which tcsd runs.";
+      };
+
+      stateDir = mkOption {
+        default = "/var/lib/tpm";
+        type = types.path;
+        description = ''
+          The location of the system persistent storage file.
+          The system persistent storage file holds keys and data across
+          restarts of the TCSD and system reboots. 
+        '';
+      };
+
+      firmwarePCRs = mkOption {
+        default = "0,1,2,3,4,5,6,7";
+        type = types.string;
+        description = "PCR indices used in the TPM for firmware measurements.";
+      };
+
+      kernelPCRs = mkOption {
+        default = "8,9,10,11,12";
+        type = types.string;
+        description = "PCR indices used in the TPM for kernel measurements.";
+      };
+
+      platformCred = mkOption {
+        default = "${cfg.stateDir}/platform.cert";
+        type = types.path;
+        description = ''
+          Path to the platform credential for your TPM. Your TPM
+          manufacturer may have provided you with a set of credentials
+          (certificates) that should be used when creating identities
+          using your TPM. When a user of your TPM makes an identity,
+          this credential will be encrypted as part of that process.
+          See the 1.1b TPM Main specification section 9.3 for information
+          on this process. '';
+      };
+
+      conformanceCred = mkOption {
+        default = "${cfg.stateDir}/conformance.cert";
+        type = types.path;
+        description = ''
+          Path to the conformance credential for your TPM.
+          See also the platformCred option'';
+      };
+
+      endorsementCred = mkOption {
+        default = "${cfg.stateDir}/endorsement.cert";
+        type = types.path;
+        description = ''
+          Path to the endorsement credential for your TPM.
+          See also the platformCred option'';
+      };
+    };
+
+  };
+
+  ###### implementation
+
+  config = mkIf cfg.enable {
+
+    environment.systemPackages = [ pkgs.trousers ];
+
+#    system.activationScripts.tcsd =
+#      ''
+#        chown ${cfg.user}:${cfg.group} ${tcsdConf}
+#      '';
+
+    systemd.services.tcsd = {
+      description = "TCSD";
+      after = [ "systemd-udev-settle.service" ];
+      wantedBy = [ "multi-user.target" ];
+      path = [ pkgs.trousers ];
+      preStart =
+        ''
+        mkdir -m 0700 -p ${cfg.stateDir}
+        chown -R ${cfg.user}:${cfg.group} ${cfg.stateDir}
+        '';
+      serviceConfig.ExecStart = "${pkgs.trousers}/sbin/tcsd -f -c ${tcsdConf}";
+    };
+
+    users.users = optionalAttrs (cfg.user == "tss") (singleton
+      { name = "tss";
+        group = "tss";
+        uid = config.ids.uids.tss;
+      });
+
+    users.groups = optionalAttrs (cfg.group == "tss") (singleton
+      { name = "tss";
+        gid = config.ids.gids.tss;
+      });
+  };
+}
diff --git a/nixpkgs/nixos/modules/services/hardware/thermald.nix b/nixpkgs/nixos/modules/services/hardware/thermald.nix
new file mode 100644
index 000000000000..69577bbe0181
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/hardware/thermald.nix
@@ -0,0 +1,52 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.services.thermald;
+in {
+  ###### interface
+  options = {
+    services.thermald = {
+      enable = mkOption {
+        default = false;
+        description = ''
+          Whether to enable thermald, the temperature management daemon.
+        '';
+      };
+
+      debug = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Whether to enable debug logging.
+        '';
+      };
+
+      configFile = mkOption {
+        type = types.nullOr types.path;
+        default = null;
+        description = "the thermald manual configuration file.";
+      };
+    };
+  };
+
+  ###### implementation
+  config = mkIf cfg.enable {
+    services.dbus.packages = [ pkgs.thermald ];
+
+    systemd.services.thermald = {
+      description = "Thermal Daemon Service";
+      wantedBy = [ "multi-user.target" ];
+      serviceConfig = {
+        ExecStart = ''
+          ${pkgs.thermald}/sbin/thermald \
+            --no-daemon \
+            ${optionalString cfg.debug "--loglevel=debug"} \
+            ${optionalString (cfg.configFile != null) "--config-file ${cfg.configFile}"} \
+            --dbus-enable
+        '';
+      };
+    };
+  };
+}
diff --git a/nixpkgs/nixos/modules/services/hardware/thinkfan.nix b/nixpkgs/nixos/modules/services/hardware/thinkfan.nix
new file mode 100644
index 000000000000..7c105e99ca54
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/hardware/thinkfan.nix
@@ -0,0 +1,152 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  cfg = config.services.thinkfan;
+  configFile = pkgs.writeText "thinkfan.conf" ''
+    # ATTENTION: There is only very basic sanity checking on the configuration.
+    # That means you can set your temperature limits as insane as you like. You
+    # can do anything stupid, e.g. turn off your fan when your CPU reaches 70°C.
+    #
+    # That's why this program is called THINKfan: You gotta think for yourself.
+    #
+    ######################################################################
+    #
+    # IBM/Lenovo Thinkpads (thinkpad_acpi, /proc/acpi/ibm)
+    # ====================================================
+    #
+    # IMPORTANT:
+    #
+    # To keep your HD from overheating, you have to specify a correction value for
+    # the sensor that has the HD's temperature. You need to do this because
+    # thinkfan uses only the highest temperature it can find in the system, and
+    # that'll most likely never be your HD, as most HDs are already out of spec
+    # when they reach 55 °C.
+    # Correction values are applied from left to right in the same order as the
+    # temperatures are read from the file.
+    #
+    # For example:
+    # tp_thermal /proc/acpi/ibm/thermal (0, 0, 10)
+    # will add a fixed value of 10 °C the 3rd value read from that file. Check out
+    # http://www.thinkwiki.org/wiki/Thermal_Sensors to find out how much you may
+    # want to add to certain temperatures.
+
+    ${cfg.fan}
+    ${cfg.sensors}
+
+    #  Syntax:
+    #  (LEVEL, LOW, HIGH)
+    #  LEVEL is the fan level to use (0-7 with thinkpad_acpi)
+    #  LOW is the temperature at which to step down to the previous level
+    #  HIGH is the temperature at which to step up to the next level
+    #  All numbers are integers.
+    #
+
+    ${cfg.levels}
+  '';
+
+  thinkfan = pkgs.thinkfan.override { smartSupport = cfg.smartSupport; };
+
+in {
+
+  options = {
+
+    services.thinkfan = {
+
+      enable = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Whether to enable thinkfan, fan controller for IBM/Lenovo ThinkPads.
+        '';
+      };
+
+      smartSupport = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Whether to build thinkfan with SMART support to read temperatures 
+          directly from hard disks.
+        '';
+      };
+
+      sensors = mkOption {
+        type = types.lines;
+        default = ''
+          tp_thermal /proc/acpi/ibm/thermal (0,0,10)
+        '';
+        description =''
+          thinkfan can read temperatures from three possible sources:
+
+            /proc/acpi/ibm/thermal
+              Which is provided by the thinkpad_acpi kernel
+              module (keyword tp_thermal)
+
+            /sys/class/hwmon/*/temp*_input
+              Which may be provided by any hwmon drivers (keyword
+              hwmon)
+
+            S.M.A.R.T. (requires smartSupport to be enabled)
+              Which reads the temperature directly from the hard
+              disk using libatasmart (keyword atasmart)
+
+          Multiple sensors may be added, in which case they will be
+          numbered in their order of appearance.
+        '';
+      };
+
+      fan = mkOption {
+        type = types.str;
+        default = "tp_fan /proc/acpi/ibm/fan";
+        description =''
+          Specifies the fan we want to use.
+          On anything other than a Thinkpad you'll probably
+          use some PWM control file in /sys/class/hwmon.
+          A sysfs fan would be specified like this:
+            pwm_fan /sys/class/hwmon/hwmon2/device/pwm1
+        '';
+      };
+
+      levels = mkOption {
+        type = types.lines;
+        default = ''
+          (0,     0,      55)
+          (1,     48,     60)
+          (2,     50,     61)
+          (3,     52,     63)
+          (6,     56,     65)
+          (7,     60,     85)
+          (127,   80,     32767)
+        '';
+        description = ''
+          (LEVEL, LOW, HIGH)
+          LEVEL is the fan level to use (0-7 with thinkpad_acpi).
+          LOW is the temperature at which to step down to the previous level.
+          HIGH is the temperature at which to step up to the next level.
+          All numbers are integers.
+        '';
+      };
+
+
+    };
+
+  };
+
+  config = mkIf cfg.enable {
+
+    environment.systemPackages = [ thinkfan ];
+
+    systemd.services.thinkfan = {
+      description = "Thinkfan";
+      after = [ "basic.target" ];
+      wantedBy = [ "multi-user.target" ];
+      path = [ thinkfan ];
+      serviceConfig.ExecStart = "${thinkfan}/bin/thinkfan -n -c ${configFile}";
+    };
+
+    boot.extraModprobeConfig = "options thinkpad_acpi experimental=1 fan_control=1";
+
+  };
+}
diff --git a/nixpkgs/nixos/modules/services/hardware/tlp.nix b/nixpkgs/nixos/modules/services/hardware/tlp.nix
new file mode 100644
index 000000000000..092ff051a042
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/hardware/tlp.nix
@@ -0,0 +1,120 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+cfg = config.services.tlp;
+
+enableRDW = config.networking.networkmanager.enable;
+
+tlp = pkgs.tlp.override {
+  inherit enableRDW;
+};
+
+# XXX: We can't use writeTextFile + readFile here because it triggers
+# TLP build to get the .drv (even on --dry-run).
+confFile = pkgs.runCommand "tlp"
+  { config = cfg.extraConfig;
+    passAsFile = [ "config" ];
+    preferLocalBuild = true;
+  }
+  ''
+    cat ${tlp}/etc/default/tlp > $out
+    cat $configPath >> $out
+  '';
+
+in
+
+{
+
+  ###### interface
+
+  options = {
+
+    services.tlp = {
+
+      enable = mkOption {
+        type = types.bool;
+        default = false;
+        description = "Whether to enable the TLP daemon.";
+      };
+
+      extraConfig = mkOption {
+        type = types.lines;
+        default = "";
+        description = "Additional configuration variables for TLP";
+      };
+
+    };
+
+  };
+
+
+  ###### implementation
+
+  config = mkIf cfg.enable {
+
+    powerManagement.scsiLinkPolicy = null;
+    powerManagement.cpuFreqGovernor = null;
+    powerManagement.cpufreq.max = null;
+    powerManagement.cpufreq.min = null;
+
+    systemd.sockets."systemd-rfkill".enable = false;
+
+    systemd.services = {
+      "systemd-rfkill@".enable = false;
+      "systemd-rfkill".enable = false;
+
+      tlp = {
+        description = "TLP system startup/shutdown";
+
+        after = [ "multi-user.target" ];
+        wantedBy = [ "multi-user.target" ];
+        before = [ "shutdown.target" ];
+        restartTriggers = [ confFile ];
+
+        serviceConfig = {
+          Type = "oneshot";
+          RemainAfterExit = true;
+          ExecStart = "${tlp}/bin/tlp init start";
+          ExecStop = "${tlp}/bin/tlp init stop";
+        };
+      };
+
+      tlp-sleep = {
+        description = "TLP suspend/resume";
+
+        wantedBy = [ "sleep.target" ];
+        before = [ "sleep.target" ];
+
+        unitConfig = {
+          StopWhenUnneeded = true;
+        };
+
+        serviceConfig = {
+          Type = "oneshot";
+          RemainAfterExit = true;
+          ExecStart = "${tlp}/bin/tlp suspend";
+          ExecStop = "${tlp}/bin/tlp resume";
+        };
+      };
+    };
+
+    services.udev.packages = [ tlp ];
+
+    environment.etc = [{ source = confFile;
+                         target = "default/tlp";
+                       }
+                      ] ++ optional enableRDW {
+                        source = "${tlp}/etc/NetworkManager/dispatcher.d/99tlp-rdw-nm";
+                        target = "NetworkManager/dispatcher.d/99tlp-rdw-nm";
+                      };
+
+    environment.systemPackages = [ tlp ];
+
+    boot.kernelModules = [ "msr" ];
+
+  };
+
+}
diff --git a/nixpkgs/nixos/modules/services/hardware/trezord.nix b/nixpkgs/nixos/modules/services/hardware/trezord.nix
new file mode 100644
index 000000000000..c06a0665d02f
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/hardware/trezord.nix
@@ -0,0 +1,60 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+let
+  cfg = config.services.trezord;
+in {
+  
+  ### interface
+
+  options = {
+    services.trezord = {
+      enable = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Enable Trezor bridge daemon, for use with Trezor hardware bitcoin wallets.
+        '';
+      };
+    };
+  };
+  
+  ### implementation
+
+  config = mkIf cfg.enable {
+    services.udev.packages = lib.singleton (pkgs.writeTextFile {
+      name = "trezord-udev-rules";
+      destination = "/etc/udev/rules.d/51-trezor.rules";
+      text = ''
+        # TREZOR v1 (One)
+        SUBSYSTEM=="usb", ATTR{idVendor}=="534c", ATTR{idProduct}=="0001", MODE="0660", GROUP="trezord", TAG+="uaccess", SYMLINK+="trezor%n"
+        KERNEL=="hidraw*", ATTRS{idVendor}=="534c", ATTRS{idProduct}=="0001", MODE="0660", GROUP="trezord", TAG+="uaccess"
+
+        # TREZOR v2 (T)
+        SUBSYSTEM=="usb", ATTR{idVendor}=="1209", ATTR{idProduct}=="53c0", MODE="0660", GROUP="trezord", TAG+="uaccess", SYMLINK+="trezor%n"
+        SUBSYSTEM=="usb", ATTR{idVendor}=="1209", ATTR{idProduct}=="53c1", MODE="0660", GROUP="trezord", TAG+="uaccess", SYMLINK+="trezor%n"
+        KERNEL=="hidraw*", ATTRS{idVendor}=="1209", ATTRS{idProduct}=="53c1", MODE="0660", GROUP="trezord", TAG+="uaccess"
+      '';
+    });
+
+    systemd.services.trezord = {
+      description = "TREZOR Bridge";
+      after = [ "systemd-udev-settle.service" "network.target" ];
+      wantedBy = [ "multi-user.target" ];
+      path = [];
+      serviceConfig = {
+        Type = "simple";
+        ExecStart = "${pkgs.trezord}/bin/trezord-go";
+        User = "trezord";
+      };
+    };
+
+    users.users.trezord = {
+      group = "trezord";
+      description = "Trezor bridge daemon user";
+    };
+
+    users.groups.trezord = {};
+  };
+}
+
diff --git a/nixpkgs/nixos/modules/services/hardware/triggerhappy.nix b/nixpkgs/nixos/modules/services/hardware/triggerhappy.nix
new file mode 100644
index 000000000000..bffe7353b10e
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/hardware/triggerhappy.nix
@@ -0,0 +1,123 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  cfg = config.services.triggerhappy;
+
+  socket = "/run/thd.socket";
+
+  configFile = pkgs.writeText "triggerhappy.conf" ''
+    ${concatMapStringsSep "\n"
+      ({ keys, event, cmd, ... }:
+        ''${concatMapStringsSep "+" (x: "KEY_" + x) keys} ${toString { press = 1; hold = 2; release = 0; }.${event}} ${cmd}''
+      )
+      cfg.bindings}
+    ${cfg.extraConfig}
+  '';
+
+  bindingCfg = { config, ... }: {
+    options = {
+
+      keys = mkOption {
+        type = types.listOf types.str;
+        description = "List of keys to match.  Key names as defined in linux/input-event-codes.h";
+      };
+
+      event = mkOption {
+        type = types.enum ["press" "hold" "release"];
+        default = "press";
+        description = "Event to match.";
+      };
+
+      cmd = mkOption {
+        type = types.str;
+        description = "What to run.";
+      };
+
+    };
+  };
+
+in
+
+{
+
+  ###### interface
+
+  options = {
+
+    services.triggerhappy = {
+
+      enable = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Whether to enable the <command>triggerhappy</command> hotkey daemon.
+        '';
+      };
+
+      user = mkOption {
+        type = types.str;
+        default = "nobody";
+        example = "root";
+        description = ''
+          User account under which <command>triggerhappy</command> runs.
+        '';
+      };
+
+      bindings = mkOption {
+        type = types.listOf (types.submodule bindingCfg);
+        default = [];
+        example = lib.literalExample ''
+          [ { keys = ["PLAYPAUSE"];  cmd = "''${pkgs.mpc_cli}/bin/mpc -q toggle"; } ]
+        '';
+        description = ''
+          Key bindings for <command>triggerhappy</command>.
+        '';
+      };
+
+      extraConfig = mkOption {
+        type = types.lines;
+        default = "";
+        description = ''
+          Literal contents to append to the end of <command>triggerhappy</command> configuration file.
+        '';
+      };
+
+    };
+
+  };
+
+
+  ###### implementation
+
+  config = mkIf cfg.enable {
+
+    systemd.sockets.triggerhappy = {
+      description = "Triggerhappy Socket";
+      wantedBy = [ "sockets.target" ];
+      socketConfig.ListenDatagram = socket;
+    };
+
+    systemd.services.triggerhappy = {
+      wantedBy = [ "multi-user.target" ];
+      after = [ "local-fs.target" ];
+      description = "Global hotkey daemon";
+      serviceConfig = {
+        ExecStart = "${pkgs.triggerhappy}/bin/thd ${optionalString (cfg.user != "root") "--user ${cfg.user}"} --socket ${socket} --triggers ${configFile} --deviceglob /dev/input/event*";
+      };
+    };
+
+    services.udev.packages = lib.singleton (pkgs.writeTextFile {
+      name = "triggerhappy-udev-rules";
+      destination = "/etc/udev/rules.d/61-triggerhappy.rules";
+      text = ''
+        ACTION=="add", SUBSYSTEM=="input", KERNEL=="event[0-9]*", ATTRS{name}!="triggerhappy", \
+          RUN+="${pkgs.triggerhappy}/bin/th-cmd --socket ${socket} --passfd --udev"
+      '';
+    });
+
+  };
+
+}
diff --git a/nixpkgs/nixos/modules/services/hardware/u2f.nix b/nixpkgs/nixos/modules/services/hardware/u2f.nix
new file mode 100644
index 000000000000..bb4b2f05f890
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/hardware/u2f.nix
@@ -0,0 +1,23 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+let
+  cfg = config.hardware.u2f;
+in {
+  options = {
+    hardware.u2f = {
+      enable = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Enable U2F hardware support.
+        '';
+      };
+    };
+  };
+
+  config = mkIf cfg.enable {
+    services.udev.packages = [ pkgs.libu2f-host ];
+  };
+}
+
diff --git a/nixpkgs/nixos/modules/services/hardware/udev.nix b/nixpkgs/nixos/modules/services/hardware/udev.nix
new file mode 100644
index 000000000000..0266286aaacf
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/hardware/udev.nix
@@ -0,0 +1,320 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  udev = config.systemd.package;
+
+  cfg = config.services.udev;
+
+  extraUdevRules = pkgs.writeTextFile {
+    name = "extra-udev-rules";
+    text = cfg.extraRules;
+    destination = "/etc/udev/rules.d/99-local.rules";
+  };
+
+  extraHwdbFile = pkgs.writeTextFile {
+    name = "extra-hwdb-file";
+    text = cfg.extraHwdb;
+    destination = "/etc/udev/hwdb.d/99-local.hwdb";
+  };
+
+  nixosRules = ''
+    # Miscellaneous devices.
+    KERNEL=="kvm",                  MODE="0666"
+    KERNEL=="kqemu",                MODE="0666"
+
+    # Needed for gpm.
+    SUBSYSTEM=="input", KERNEL=="mice", TAG+="systemd"
+  '';
+
+  # Perform substitutions in all udev rules files.
+  udevRules = pkgs.runCommand "udev-rules"
+    { preferLocalBuild = true;
+      allowSubstitutes = false;
+      packages = unique (map toString cfg.packages);
+    }
+    ''
+      mkdir -p $out
+      shopt -s nullglob
+      set +o pipefail
+
+      # Set a reasonable $PATH for programs called by udev rules.
+      echo 'ENV{PATH}="${udevPath}/bin:${udevPath}/sbin"' > $out/00-path.rules
+
+      # Add the udev rules from other packages.
+      for i in $packages; do
+        echo "Adding rules for package $i"
+        for j in $i/{etc,lib}/udev/rules.d/*; do
+          echo "Copying $j to $out/$(basename $j)"
+          cat $j > $out/$(basename $j)
+        done
+      done
+
+      # Fix some paths in the standard udev rules.  Hacky.
+      for i in $out/*.rules; do
+        substituteInPlace $i \
+          --replace \"/sbin/modprobe \"${pkgs.kmod}/bin/modprobe \
+          --replace \"/sbin/mdadm \"${pkgs.mdadm}/sbin/mdadm \
+          --replace \"/sbin/blkid \"${pkgs.utillinux}/sbin/blkid \
+          --replace \"/bin/mount \"${pkgs.utillinux}/bin/mount \
+          --replace /usr/bin/readlink ${pkgs.coreutils}/bin/readlink \
+          --replace /usr/bin/basename ${pkgs.coreutils}/bin/basename
+      done
+
+      echo -n "Checking that all programs called by relative paths in udev rules exist in ${udev}/lib/udev... "
+      import_progs=$(grep 'IMPORT{program}="[^/$]' $out/* |
+        sed -e 's/.*IMPORT{program}="\([^ "]*\)[ "].*/\1/' | uniq)
+      run_progs=$(grep -v '^[[:space:]]*#' $out/* | grep 'RUN+="[^/$]' |
+        sed -e 's/.*RUN+="\([^ "]*\)[ "].*/\1/' | uniq)
+      for i in $import_progs $run_progs; do
+        if [[ ! -x ${udev}/lib/udev/$i && ! $i =~ socket:.* ]]; then
+          echo "FAIL"
+          echo "$i is called in udev rules but not installed by udev"
+          exit 1
+        fi
+      done
+      echo "OK"
+
+      echo -n "Checking that all programs called by absolute paths in udev rules exist... "
+      import_progs=$(grep 'IMPORT{program}="\/' $out/* |
+        sed -e 's/.*IMPORT{program}="\([^ "]*\)[ "].*/\1/' | uniq)
+      run_progs=$(grep -v '^[[:space:]]*#' $out/* | grep 'RUN+="/' |
+        sed -e 's/.*RUN+="\([^ "]*\)[ "].*/\1/' | uniq)
+      for i in $import_progs $run_progs; do
+        if [[ ! -x $i ]]; then
+          echo "FAIL"
+          echo "$i is called in udev rules but not installed by udev"
+          exit 1
+        fi
+      done
+      echo "OK"
+
+      filesToFixup="$(for i in "$out"/*; do
+        grep -l '\B\(/usr\)\?/s\?bin' "$i" || :
+      done)"
+
+      if [ -n "$filesToFixup" ]; then
+        echo "Consider fixing the following udev rules:"
+        echo "$filesToFixup" | while read localFile; do
+          remoteFile="origin unknown"
+          for i in ${toString cfg.packages}; do
+            for j in "$i"/*/udev/rules.d/*; do
+              [ -e "$out/$(basename "$j")" ] || continue
+              [ "$(basename "$j")" = "$(basename "$localFile")" ] || continue
+              remoteFile="originally from $j"
+              break 2
+            done
+          done
+          refs="$(
+            grep -o '\B\(/usr\)\?/s\?bin/[^ "]\+' "$localFile" \
+              | sed -e ':r;N;''${s/\n/ and /;br};s/\n/, /g;br'
+          )"
+          echo "$localFile ($remoteFile) contains references to $refs."
+        done
+        exit 1
+      fi
+
+      ${optionalString config.networking.usePredictableInterfaceNames ''
+        cp ${./80-net-setup-link.rules} $out/80-net-setup-link.rules
+      ''}
+
+      # If auto-configuration is disabled, then remove
+      # udev's 80-drivers.rules file, which contains rules for
+      # automatically calling modprobe.
+      ${optionalString (!config.boot.hardwareScan) ''
+        ln -s /dev/null $out/80-drivers.rules
+      ''}
+    ''; # */
+
+  hwdbBin = pkgs.runCommand "hwdb.bin"
+    { preferLocalBuild = true;
+      allowSubstitutes = false;
+      packages = unique (map toString ([udev] ++ cfg.packages));
+    }
+    ''
+      mkdir -p etc/udev/hwdb.d
+      for i in $packages; do
+        echo "Adding hwdb files for package $i"
+        for j in $i/{etc,lib}/udev/hwdb.d/*; do
+          ln -s $j etc/udev/hwdb.d/$(basename $j)
+        done
+      done
+
+      echo "Generating hwdb database..."
+      # hwdb --update doesn't return error code even on errors!
+      res="$(${pkgs.buildPackages.udev}/bin/udevadm hwdb --update --root=$(pwd) 2>&1)"
+      echo "$res"
+      [ -z "$(echo "$res" | egrep '^Error')" ]
+      mv etc/udev/hwdb.bin $out
+    '';
+
+  # Udev has a 512-character limit for ENV{PATH}, so create a symlink
+  # tree to work around this.
+  udevPath = pkgs.buildEnv {
+    name = "udev-path";
+    paths = cfg.path;
+    pathsToLink = [ "/bin" "/sbin" ];
+    ignoreCollisions = true;
+  };
+
+in
+
+{
+
+  ###### interface
+
+  options = {
+
+    boot.hardwareScan = mkOption {
+      type = types.bool;
+      default = true;
+      description = ''
+        Whether to try to load kernel modules for all detected hardware.
+        Usually this does a good job of providing you with the modules
+        you need, but sometimes it can crash the system or cause other
+        nasty effects.
+      '';
+    };
+
+    services.udev = {
+
+      packages = mkOption {
+        type = types.listOf types.path;
+        default = [];
+        description = ''
+          List of packages containing <command>udev</command> rules.
+          All files found in
+          <filename><replaceable>pkg</replaceable>/etc/udev/rules.d</filename> and
+          <filename><replaceable>pkg</replaceable>/lib/udev/rules.d</filename>
+          will be included.
+        '';
+        apply = map getBin;
+      };
+
+      path = mkOption {
+        type = types.listOf types.path;
+        default = [];
+        description = ''
+          Packages added to the <envar>PATH</envar> environment variable when
+          executing programs from Udev rules.
+        '';
+      };
+
+      extraRules = mkOption {
+        default = "";
+        example = ''
+          KERNEL=="eth*", ATTR{address}=="00:1D:60:B9:6D:4F", NAME="my_fast_network_card"
+        '';
+        type = types.lines;
+        description = ''
+          Additional <command>udev</command> rules. They'll be written
+          into file <filename>99-local.rules</filename>. Thus they are
+          read and applied after all other rules.
+        '';
+      };
+
+      extraHwdb = mkOption {
+        default = "";
+        example = ''
+          evdev:input:b0003v05AFp8277*
+            KEYBOARD_KEY_70039=leftalt
+            KEYBOARD_KEY_700e2=leftctrl
+        '';
+        type = types.lines;
+        description = ''
+          Additional <command>hwdb</command> files. They'll be written
+          into file <filename>10-local.hwdb</filename>. Thus they are
+          read before all other files.
+        '';
+      };
+
+    };
+
+    hardware.firmware = mkOption {
+      type = types.listOf types.package;
+      default = [];
+      description = ''
+        List of packages containing firmware files.  Such files
+        will be loaded automatically if the kernel asks for them
+        (i.e., when it has detected specific hardware that requires
+        firmware to function).  If multiple packages contain firmware
+        files with the same name, the first package in the list takes
+        precedence.  Note that you must rebuild your system if you add
+        files to any of these directories.
+      '';
+      apply = list: pkgs.buildEnv {
+        name = "firmware";
+        paths = list;
+        pathsToLink = [ "/lib/firmware" ];
+        ignoreCollisions = true;
+      };
+    };
+
+    networking.usePredictableInterfaceNames = mkOption {
+      default = true;
+      type = types.bool;
+      description = ''
+        Whether to assign <link
+        xlink:href='http://www.freedesktop.org/wiki/Software/systemd/PredictableNetworkInterfaceNames'>predictable
+        names to network interfaces</link>.  If enabled, interfaces
+        are assigned names that contain topology information
+        (e.g. <literal>wlp3s0</literal>) and thus should be stable
+        across reboots.  If disabled, names depend on the order in
+        which interfaces are discovered by the kernel, which may
+        change randomly across reboots; for instance, you may find
+        <literal>eth0</literal> and <literal>eth1</literal> flipping
+        unpredictably.
+      '';
+    };
+
+  };
+
+
+  ###### implementation
+
+  config = mkIf (!config.boot.isContainer) {
+
+    services.udev.extraRules = nixosRules;
+
+    services.udev.packages = [ extraUdevRules extraHwdbFile ];
+
+    services.udev.path = [ pkgs.coreutils pkgs.gnused pkgs.gnugrep pkgs.utillinux udev ];
+
+    environment.etc =
+      [ { source = udevRules;
+          target = "udev/rules.d";
+        }
+        { source = hwdbBin;
+          target = "udev/hwdb.bin";
+        }
+      ];
+
+    system.requiredKernelConfig = with config.lib.kernelConfig; [
+      (isEnabled "UNIX")
+      (isYes "INOTIFY_USER")
+      (isYes "NET")
+    ];
+
+    boot.extraModprobeConfig = "options firmware_class path=${config.hardware.firmware}/lib/firmware";
+
+    system.activationScripts.udevd =
+      ''
+        # The deprecated hotplug uevent helper is not used anymore
+        if [ -e /proc/sys/kernel/hotplug ]; then
+          echo "" > /proc/sys/kernel/hotplug
+        fi
+
+        # Allow the kernel to find our firmware.
+        if [ -e /sys/module/firmware_class/parameters/path ]; then
+          echo -n "${config.hardware.firmware}/lib/firmware" > /sys/module/firmware_class/parameters/path
+        fi
+      '';
+
+    systemd.services.systemd-udevd =
+      { restartTriggers = cfg.packages;
+      };
+
+  };
+}
diff --git a/nixpkgs/nixos/modules/services/hardware/udisks2.nix b/nixpkgs/nixos/modules/services/hardware/udisks2.nix
new file mode 100644
index 000000000000..ed8703be921c
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/hardware/udisks2.nix
@@ -0,0 +1,47 @@
+# Udisks daemon.
+
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+
+  ###### interface
+
+  options = {
+
+    services.udisks2 = {
+
+      enable = mkOption {
+        type = types.bool;
+        default = true;
+        description = ''
+          Whether to enable Udisks, a DBus service that allows
+          applications to query and manipulate storage devices.
+        '';
+      };
+
+    };
+
+  };
+
+
+  ###### implementation
+
+  config = mkIf config.services.udisks2.enable {
+
+    environment.systemPackages = [ pkgs.udisks2 ];
+
+    services.dbus.packages = [ pkgs.udisks2 ];
+
+    system.activationScripts.udisks2 =
+      ''
+        mkdir -m 0755 -p /var/lib/udisks2
+      '';
+
+    services.udev.packages = [ pkgs.udisks2 ];
+
+    systemd.packages = [ pkgs.udisks2 ];
+  };
+
+}
diff --git a/nixpkgs/nixos/modules/services/hardware/undervolt.nix b/nixpkgs/nixos/modules/services/hardware/undervolt.nix
new file mode 100644
index 000000000000..e5ef0601de3c
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/hardware/undervolt.nix
@@ -0,0 +1,134 @@
+{ config, pkgs, lib, ... }:
+
+with lib;
+
+let
+  cfg = config.services.undervolt;
+in {
+  options.services.undervolt = {
+    enable = mkOption {
+      type = types.bool;
+      default = false;
+      description = ''
+        Whether to undervolt intel cpus.
+      '';
+    };
+
+    verbose = mkOption {
+      type = types.bool;
+      default = false;
+      description = ''
+        Whether to enable verbose logging.
+      '';
+    };
+
+    package = mkOption {
+      type = types.package;
+      default = pkgs.undervolt;
+      defaultText = "pkgs.undervolt";
+      description = ''
+        undervolt derivation to use.
+      '';
+    };
+
+    coreOffset = mkOption {
+      type = types.nullOr types.str;
+      default = null;
+      description = ''
+        The amount of voltage to offset the CPU cores by. Accepts a floating point number.
+      '';
+    };
+
+    gpuOffset = mkOption {
+      type = types.nullOr types.str;
+      default = null;
+      description = ''
+        The amount of voltage to offset the GPU by. Accepts a floating point number.
+      '';
+    };
+
+    uncoreOffset = mkOption {
+      type = types.nullOr types.str;
+      default = null;
+      description = ''
+        The amount of voltage to offset uncore by. Accepts a floating point number.
+      '';
+    };
+
+    analogioOffset = mkOption {
+      type = types.nullOr types.str;
+      default = null;
+      description = ''
+        The amount of voltage to offset analogio by. Accepts a floating point number.
+      '';
+    };
+
+    temp = mkOption {
+      type = types.nullOr types.str;
+      default = null;
+      description = ''
+        The temperature target. Accepts a floating point number.
+      '';
+    };
+
+    tempAc = mkOption {
+      type = types.nullOr types.str;
+      default = null;
+      description = ''
+        The temperature target on AC power. Accepts a floating point number.
+      '';
+    };
+
+    tempBat = mkOption {
+      type = types.nullOr types.str;
+      default = null;
+      description = ''
+        The temperature target on battery power. Accepts a floating point number.
+      '';
+    };
+  };
+
+  config = mkIf cfg.enable {
+    boot.kernelModules = [ "msr" ];
+
+    environment.systemPackages = [ cfg.package ];
+
+    systemd.services.undervolt = {
+      path = [ pkgs.undervolt ];
+
+      description = "Intel Undervolting Service";
+      serviceConfig = {
+        Type = "oneshot";
+        Restart = "no";
+
+        # `core` and `cache` are both intentionally set to `cfg.coreOffset` as according to the undervolt docs:
+        #
+        #     Core or Cache offsets have no effect. It is not possible to set different offsets for
+        #     CPU Core and Cache. The CPU will take the smaller of the two offsets, and apply that to
+        #     both CPU and Cache. A warning message will be displayed if you attempt to set different offsets.
+        ExecStart = ''
+          ${pkgs.undervolt}/bin/undervolt \
+            ${optionalString cfg.verbose "--verbose"} \
+            ${optionalString (cfg.coreOffset != null) "--core ${cfg.coreOffset}"} \
+            ${optionalString (cfg.coreOffset != null) "--cache ${cfg.coreOffset}"} \
+            ${optionalString (cfg.gpuOffset != null) "--gpu ${cfg.gpuOffset}"} \
+            ${optionalString (cfg.uncoreOffset != null) "--uncore ${cfg.uncoreOffset}"} \
+            ${optionalString (cfg.analogioOffset != null) "--analogio ${cfg.analogioOffset}"} \
+            ${optionalString (cfg.temp != null) "--temp ${cfg.temp}"} \
+            ${optionalString (cfg.tempAc != null) "--temp-ac ${cfg.tempAc}"} \
+            ${optionalString (cfg.tempBat != null) "--temp-bat ${cfg.tempBat}"}
+        '';
+      };
+    };
+
+    systemd.timers.undervolt = {
+      description = "Undervolt timer to ensure voltage settings are always applied";
+      partOf = [ "undervolt.service" ];
+      wantedBy = [ "multi-user.target" ];
+      timerConfig = {
+        OnBootSec = "2min";
+        OnUnitActiveSec = "30";
+      };
+    };
+  };
+}
diff --git a/nixpkgs/nixos/modules/services/hardware/upower.nix b/nixpkgs/nixos/modules/services/hardware/upower.nix
new file mode 100644
index 000000000000..1da47349c077
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/hardware/upower.nix
@@ -0,0 +1,104 @@
+# Upower daemon.
+
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.services.upower;
+in
+{
+
+  ###### interface
+
+  options = {
+
+    services.upower = {
+
+      enable = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Whether to enable Upower, a DBus service that provides power
+          management support to applications.
+        '';
+      };
+
+      package = mkOption {
+        type = types.package;
+        default = pkgs.upower;
+        defaultText = "pkgs.upower";
+        example = lib.literalExample "pkgs.upower";
+        description = ''
+          Which upower package to use.
+        '';
+      };
+
+    };
+
+  };
+
+
+  ###### implementation
+
+  config = mkIf cfg.enable {
+
+    environment.systemPackages = [ cfg.package ];
+
+    services.dbus.packages = [ cfg.package ];
+
+    services.udev.packages = [ cfg.package ];
+
+    systemd.services.upower =
+      { description = "Power Management Daemon";
+        path = [ pkgs.glib.out ]; # needed for gdbus
+        serviceConfig =
+          { Type = "dbus";
+            BusName = "org.freedesktop.UPower";
+            ExecStart = "@${cfg.package}/libexec/upowerd upowerd";
+            Restart = "on-failure";
+            # Upstream lockdown:
+            # Filesystem lockdown
+            ProtectSystem = "strict";
+            # Needed by keyboard backlight support
+            ProtectKernelTunables = false;
+            ProtectControlGroups = true;
+            ReadWritePaths = "/var/lib/upower";
+            ProtectHome = true;
+            PrivateTmp = true;
+
+            # Network
+            # PrivateNetwork=true would block udev's netlink socket
+            RestrictAddressFamilies = "AF_UNIX AF_NETLINK";
+
+            # Execute Mappings
+            MemoryDenyWriteExecute = true;
+
+            # Modules
+            ProtectKernelModules = true;
+
+            # Real-time
+            RestrictRealtime = true;
+
+            # Privilege escalation
+            NoNewPrivileges = true;
+          };
+      };
+
+    system.activationScripts.upower =
+      ''
+        mkdir -m 0755 -p /var/lib/upower
+      '';
+
+    # The upower daemon seems to get stuck after doing a suspend
+    # (i.e. subsequent suspend requests will say "Sleep has already
+    # been requested and is pending").  So as a workaround, restart
+    # the daemon.
+    powerManagement.resumeCommands =
+      ''
+        ${config.systemd.package}/bin/systemctl try-restart upower
+      '';
+
+  };
+
+}
diff --git a/nixpkgs/nixos/modules/services/hardware/usbmuxd.nix b/nixpkgs/nixos/modules/services/hardware/usbmuxd.nix
new file mode 100644
index 000000000000..93ced0b9f04d
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/hardware/usbmuxd.nix
@@ -0,0 +1,74 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  defaultUserGroup = "usbmux";
+  apple = "05ac";
+
+  cfg = config.services.usbmuxd;
+
+in
+
+{
+  options.services.usbmuxd = {
+    enable = mkOption {
+      type = types.bool;
+      default = false;
+      description = ''
+        Enable the usbmuxd ("USB multiplexing daemon") service. This daemon is
+        in charge of multiplexing connections over USB to an iOS device. This is
+        needed for transferring data from and to iOS devices (see ifuse). Also
+        this may enable plug-n-play tethering for iPhones.
+      '';
+    };
+
+    user = mkOption {
+      type = types.str;
+      default = defaultUserGroup;
+      description = ''
+        The user usbmuxd should use to run after startup.
+      '';
+    };
+
+    group = mkOption {
+      type = types.str;
+      default = defaultUserGroup;
+      description = ''
+        The group usbmuxd should use to run after startup.
+      '';
+    };
+  };
+
+  config = mkIf cfg.enable {
+
+    users.users = optional (cfg.user == defaultUserGroup) {
+      name = cfg.user;
+      description = "usbmuxd user";
+      group = cfg.group;
+    };
+
+    users.groups = optional (cfg.group == defaultUserGroup) {
+      name = cfg.group;
+    };
+
+    # Give usbmuxd permission for Apple devices
+    services.udev.extraRules = ''
+      SUBSYSTEM=="usb", ATTR{idVendor}=="${apple}", GROUP="${cfg.group}"
+    '';
+
+    systemd.services.usbmuxd = {
+      description = "usbmuxd";
+      wantedBy = [ "multi-user.target" ];
+      unitConfig.Documentation = "man:usbmuxd(8)";
+      serviceConfig = {
+        # Trigger the udev rule manually. This doesn't require replugging the
+        # device when first enabling the option to get it to work
+        ExecStartPre = "${pkgs.udev}/bin/udevadm trigger -s usb -a idVendor=${apple}";
+        ExecStart = "${pkgs.usbmuxd}/bin/usbmuxd -U ${cfg.user} -f";
+      };
+    };
+
+  };
+}
diff --git a/nixpkgs/nixos/modules/services/hardware/vdr.nix b/nixpkgs/nixos/modules/services/hardware/vdr.nix
new file mode 100644
index 000000000000..6e246f70f515
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/hardware/vdr.nix
@@ -0,0 +1,81 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.services.vdr;
+  libDir = "/var/lib/vdr";
+in {
+
+  ###### interface
+
+  options = {
+
+    services.vdr = {
+      enable = mkEnableOption "VDR. Please put config into ${libDir}";
+
+      package = mkOption {
+        type = types.package;
+        default = pkgs.vdr;
+        defaultText = "pkgs.vdr";
+        example = literalExample "pkgs.wrapVdr.override { plugins = with pkgs.vdrPlugins; [ hello ]; }";
+        description = "Package to use.";
+      };
+
+      videoDir = mkOption {
+        type = types.path;
+        default = "/srv/vdr/video";
+        description = "Recording directory";
+      };
+
+      extraArguments = mkOption {
+        type = types.listOf types.str;
+        default = [];
+        description = "Additional command line arguments to pass to VDR.";
+      };
+
+      enableLirc = mkEnableOption "LIRC";
+    };
+  };
+
+  ###### implementation
+
+  config = mkIf cfg.enable (mkMerge [{
+    systemd.tmpfiles.rules = [
+      "d ${cfg.videoDir} 0755 vdr vdr -"
+      "Z ${cfg.videoDir} - vdr vdr -"
+    ];
+
+    systemd.services.vdr = {
+      description = "VDR";
+      wantedBy = [ "multi-user.target" ];
+      serviceConfig = {
+        ExecStart = ''
+          ${cfg.package}/bin/vdr \
+            --video="${cfg.videoDir}" \
+            --config="${libDir}" \
+            ${escapeShellArgs cfg.extraArguments}
+        '';
+        User = "vdr";
+        CacheDirectory = "vdr";
+        StateDirectory = "vdr";
+        Restart = "on-failure";
+      };
+    };
+
+    users.users.vdr = {
+      group = "vdr";
+      home = libDir;
+    };
+
+    users.groups.vdr = {};
+  }
+
+  (mkIf cfg.enableLirc {
+    services.lirc.enable = true;
+    users.users.vdr.extraGroups = [ "lirc" ];
+    services.vdr.extraArguments = [
+      "--lirc=${config.passthru.lirc.socket}"
+    ];
+  })]);
+}