diff options
Diffstat (limited to 'nixos/modules/services/hardware')
-rw-r--r-- | nixos/modules/services/hardware/acpid.nix | 114 | ||||
-rw-r--r-- | nixos/modules/services/hardware/bluetooth.nix | 41 | ||||
-rw-r--r-- | nixos/modules/services/hardware/nvidia-optimus.nix | 43 | ||||
-rw-r--r-- | nixos/modules/services/hardware/pcscd.nix | 46 | ||||
-rw-r--r-- | nixos/modules/services/hardware/pommed.nix | 49 | ||||
-rw-r--r-- | nixos/modules/services/hardware/sane.nix | 40 | ||||
-rw-r--r-- | nixos/modules/services/hardware/thinkfan.nix | 95 | ||||
-rw-r--r-- | nixos/modules/services/hardware/udev.nix | 239 | ||||
-rw-r--r-- | nixos/modules/services/hardware/udisks.nix | 44 | ||||
-rw-r--r-- | nixos/modules/services/hardware/udisks2.nix | 53 | ||||
-rw-r--r-- | nixos/modules/services/hardware/upower.nix | 64 |
11 files changed, 828 insertions, 0 deletions
diff --git a/nixos/modules/services/hardware/acpid.nix b/nixos/modules/services/hardware/acpid.nix new file mode 100644 index 0000000000000..6a595f8306bc6 --- /dev/null +++ b/nixos/modules/services/hardware/acpid.nix @@ -0,0 +1,114 @@ +{ config, pkgs, ... }: + +with pkgs.lib; + +let + + acpiConfDir = pkgs.runCommand "acpi-events" {} + '' + ensureDir $out + ${ + # Generate a configuration file for each event. (You can't have + # multiple events in one config file...) + let f = event: + '' + fn=$out/${event.name} + echo "event=${event.event}" > $fn + echo "action=${pkgs.writeScript "${event.name}.sh" event.action}" >> $fn + ''; + in pkgs.lib.concatMapStrings f events + } + ''; + + events = [powerEvent lidEvent acEvent]; + + # Called when the power button is pressed. + powerEvent = + { name = "power-button"; + event = "button/power.*"; + action = + '' + #! ${pkgs.bash}/bin/sh + ${config.services.acpid.powerEventCommands} + ''; + }; + + # Called when the laptop lid is opened/closed. + lidEvent = + { name = "lid"; + event = "button/lid.*"; + action = + '' + #! ${pkgs.bash}/bin/sh + ${config.services.acpid.lidEventCommands} + ''; + }; + + # Called when the AC power is connected or disconnected. + acEvent = + { name = "ac-power"; + event = "ac_adapter.*"; + action = + '' + #! ${pkgs.bash}/bin/sh + ${config.services.acpid.acEventCommands} + ''; + }; + +in + +{ + + ###### interface + + options = { + + services.acpid = { + + enable = mkOption { + default = false; + description = "Whether to enable the ACPI daemon."; + }; + + powerEventCommands = mkOption { + default = ""; + description = "Shell commands to execute on a button/power.* event."; + }; + + lidEventCommands = mkOption { + default = ""; + description = "Shell commands to execute on a button/lid.* event."; + }; + + acEventCommands = mkOption { + default = ""; + description = "Shell commands to execute on an ac_adapter.* event."; + }; + + }; + + }; + + + ###### implementation + + config = mkIf config.services.acpid.enable { + + jobs.acpid = + { description = "ACPI Daemon"; + + wantedBy = [ "multi-user.target" ]; + after = [ "systemd-udev-settle.service" ]; + + path = [ pkgs.acpid ]; + + daemonType = "fork"; + + exec = "acpid --confdir ${acpiConfDir}"; + + unitConfig.ConditionPathExists = [ "/proc/acpi" ]; + }; + + }; + +} diff --git a/nixos/modules/services/hardware/bluetooth.nix b/nixos/modules/services/hardware/bluetooth.nix new file mode 100644 index 0000000000000..6bc0ad0bf7746 --- /dev/null +++ b/nixos/modules/services/hardware/bluetooth.nix @@ -0,0 +1,41 @@ +{ config, pkgs, ... }: + +with pkgs.lib; + +{ + + ###### interface + + options = { + + hardware.bluetooth.enable = mkOption { + default = false; + description = "Whether to enable support for Bluetooth."; + }; + + }; + + + ###### implementation + + config = mkIf config.hardware.bluetooth.enable { + + environment.systemPackages = [ pkgs.bluez pkgs.openobex pkgs.obexftp ]; + + services.udev.packages = [ pkgs.bluez ]; + + services.dbus.packages = [ pkgs.bluez ]; + + systemd.services."dbus-org.bluez" = { + description = "Bluetooth service"; + serviceConfig = { + Type = "dbus"; + BusName = "org.bluez"; + ExecStart = "${pkgs.bluez}/sbin/bluetoothd -n"; + }; + wantedBy = [ "bluetooth.target" ]; + }; + + }; + +} diff --git a/nixos/modules/services/hardware/nvidia-optimus.nix b/nixos/modules/services/hardware/nvidia-optimus.nix new file mode 100644 index 0000000000000..4c0ce794d4f7d --- /dev/null +++ b/nixos/modules/services/hardware/nvidia-optimus.nix @@ -0,0 +1,43 @@ +{ config, pkgs, ... }: + +let kernel = config.boot.kernelPackages; in + +{ + + ###### interface + + options = { + + hardware.nvidiaOptimus.disable = pkgs.lib.mkOption { + default = false; + type = pkgs.lib.types.bool; + description = '' + Completely disable the NVIDIA graphics card and use the + integrated graphics processor instead. + ''; + }; + + }; + + + ###### implementation + + config = pkgs.lib.mkIf config.hardware.nvidiaOptimus.disable { + boot.blacklistedKernelModules = ["nouveau" "nvidia" "nvidiafb"]; + 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/nixos/modules/services/hardware/pcscd.nix b/nixos/modules/services/hardware/pcscd.nix new file mode 100644 index 0000000000000..9f389efc06d49 --- /dev/null +++ b/nixos/modules/services/hardware/pcscd.nix @@ -0,0 +1,46 @@ +{ config, pkgs, ... }: + +with pkgs.lib; + +{ + + ###### interface + + options = { + + services.pcscd = { + + enable = mkOption { + default = false; + description = "Whether to enable the PCSC-Lite daemon."; + }; + + }; + + }; + + + ###### implementation + + config = mkIf config.services.pcscd.enable { + + jobs.pcscd = + { description = "PCSC-Lite daemon"; + + startOn = "started udev"; + + daemonType = "fork"; + + # Add to the drivers directory the only drivers we have by now: ccid + preStart = '' + mkdir -p /var/lib/pcsc + rm -Rf /var/lib/pcsc/drivers + ln -s ${pkgs.ccid}/pcsc/drivers /var/lib/pcsc/ + ''; + + exec = "${pkgs.pcsclite}/sbin/pcscd"; + }; + + }; + +} diff --git a/nixos/modules/services/hardware/pommed.nix b/nixos/modules/services/hardware/pommed.nix new file mode 100644 index 0000000000000..32599554fc12c --- /dev/null +++ b/nixos/modules/services/hardware/pommed.nix @@ -0,0 +1,49 @@ +{ config, pkgs, ... }: + +with pkgs.lib; + +{ + + options.services.hardware.pommed = { + enable = mkOption { + default = false; + description = '' + Whether to use the pommed tool to handle Apple laptop keyboard hotkeys. + ''; + }; + + configFile = mkOption { + default = "${pkgs.pommed}/etc/pommed.conf"; + description = '' + The contents of the pommed.conf file. + ''; + }; + }; + + config = mkIf config.services.hardware.pommed.enable { + environment.systemPackages = [ pkgs.polkit ]; + + environment.etc = [ + { source = config.services.hardware.pommed.configFile; + target = "pommed.conf"; + } + ]; + + services.dbus.packages = [ pkgs.pommed ]; + + jobs.pommed = { name = "pommed"; + + description = "Pommed hotkey management"; + + startOn = "started dbus"; + + postStop = "rm -f /var/run/pommed.pid"; + + exec = "${pkgs.pommed}/bin/pommed"; + + daemonType = "fork"; + + path = [ pkgs.eject ]; + }; + }; +} diff --git a/nixos/modules/services/hardware/sane.nix b/nixos/modules/services/hardware/sane.nix new file mode 100644 index 0000000000000..905445f22c1b5 --- /dev/null +++ b/nixos/modules/services/hardware/sane.nix @@ -0,0 +1,40 @@ +{ config, pkgs, ... }: + +with pkgs.lib; + +{ + + ###### interface + + options = { + + hardware.sane.enable = mkOption { + default = false; + description = "Enable support for SANE scanners."; + }; + + hardware.sane.snapshot = mkOption { + default = false; + description = "Use a development snapshot of SANE scanner drivers."; + }; + + }; + + + ###### implementation + + config = let pkg = if config.hardware.sane.snapshot + then pkgs.saneBackendsGit + else pkgs.saneBackends; + in mkIf config.hardware.sane.enable { + environment.systemPackages = [ pkg ]; + services.udev.packages = [ pkg ]; + + users.extraGroups = singleton { + name = "scanner"; + gid = config.ids.gids.scanner; + }; + + }; + +} diff --git a/nixos/modules/services/hardware/thinkfan.nix b/nixos/modules/services/hardware/thinkfan.nix new file mode 100644 index 0000000000000..b39c9cb1d9bb0 --- /dev/null +++ b/nixos/modules/services/hardware/thinkfan.nix @@ -0,0 +1,95 @@ +{ config, pkgs, ... }: + +with pkgs.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: + # sensor /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. + + # 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. + # + + sensor ${cfg.sensor} (0, 10, 15, 2, 10, 5, 0, 3, 0, 3) + + (0, 0, 55) + (1, 48, 60) + (2, 50, 61) + (3, 52, 63) + (6, 56, 65) + (7, 60, 85) + (127, 80, 32767) + ''; + +in { + + options = { + + services.thinkfan = { + + enable = mkOption { + default = false; + description = '' + Whether to enable thinkfan, fan controller for ibm/lenovo thinkpads. + ''; + }; + + sensor = mkOption { + default = "/proc/acpi/ibm/thermal"; + description ='' + Sensor used by thinkfan + ''; + }; + + }; + + }; + + config = mkIf cfg.enable { + + environment.systemPackages = [ pkgs.thinkfan ]; + + systemd.services.thinkfan = { + description = "Thinkfan"; + after = [ "basic.target" ]; + wantedBy = [ "multi-user.target" ]; + path = [ pkgs.thinkfan ]; + serviceConfig.ExecStart = "${pkgs.thinkfan}/bin/thinkfan -n -c ${configFile}"; + }; + + boot.extraModprobeConfig = "options thinkpad_acpi experimental=1 fan_control=1"; + + }; + +} diff --git a/nixos/modules/services/hardware/udev.nix b/nixos/modules/services/hardware/udev.nix new file mode 100644 index 0000000000000..37dba8ce71dc1 --- /dev/null +++ b/nixos/modules/services/hardware/udev.nix @@ -0,0 +1,239 @@ +{ config, pkgs, ... }: + +with pkgs.lib; + +let + + inherit (pkgs) stdenv writeText procps; + + udev = config.systemd.package; + + cfg = config.services.udev; + + extraUdevRules = pkgs.writeTextFile { + name = "extra-udev-rules"; + text = cfg.extraRules; + destination = "/etc/udev/rules.d/10-local.rules"; + }; + + nixosRules = '' + # Miscellaneous devices. + KERNEL=="kvm", MODE="0666" + KERNEL=="kqemu", MODE="0666" + ''; + + # Perform substitutions in all udev rules files. + udevRules = stdenv.mkDerivation { + name = "udev-rules"; + buildCommand = '' + mkdir -p $out + shopt -s nullglob + + # 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 ${toString cfg.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 \"${config.system.sbin.modprobe}/sbin/modprobe \ + --replace \"/sbin/mdadm \"${pkgs.mdadm}/sbin/mdadm \ + --replace \"/sbin/blkid \"${pkgs.utillinux}/sbin/blkid \ + --replace \"/bin/mount \"${pkgs.utillinux}/bin/mount + 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 ${pkgs.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" + + echo "Consider fixing the following udev rules:" + for i in ${toString cfg.packages}; do + grep -l '\(RUN+\|IMPORT{program}\)="\(/usr\)\?/s\?bin' $i/*/udev/rules.d/* || true + done + + ${optionalString (!config.networking.usePredictableInterfaceNames) '' + ln -s /dev/null $out/80-net-name-slot.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 + ''} + ''; # */ + }; + + # 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 { + 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 { + default = []; + merge = mergeListOption; + 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. + ''; + }; + + path = mkOption { + default = []; + merge = mergeListOption; + 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>10-local.rules</filename>. Thus they are + read before all other rules. + ''; + }; + + }; + + hardware.firmware = mkOption { + default = []; + example = [ "/root/my-firmware" ]; + merge = mergeListOption; + description = '' + List of directories 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 more than one path contains a + firmware file with the same name, the first path in the list + takes precedence. Note that you must rebuild your system if + you add files to any of these directories. For quick testing, + put firmware files in /root/test-firmware and add that + directory to the list. + Note that you can also add firmware packages to this + list as these are directories in the nix store. + ''; + apply = list: pkgs.buildEnv { + name = "firmware"; + paths = list; + pathsToLink = [ "/" ]; + 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 = { + + services.udev.extraRules = nixosRules; + + services.udev.packages = [ extraUdevRules ]; + + services.udev.path = [ pkgs.coreutils pkgs.gnused pkgs.gnugrep pkgs.utillinux udev ]; + + environment.etc = + [ { source = udevRules; + target = "udev/rules.d"; + } + ]; + + system.requiredKernelConfig = with config.lib.kernelConfig; [ + (isEnabled "UNIX") + (isYes "INOTIFY_USER") + (isYes "NET") + ]; + + boot.extraModprobeConfig = "options firmware_class path=${config.hardware.firmware}"; + + system.activationScripts.clearHotplug = + '' + echo "" > /proc/sys/kernel/hotplug + ''; + + }; +} diff --git a/nixos/modules/services/hardware/udisks.nix b/nixos/modules/services/hardware/udisks.nix new file mode 100644 index 0000000000000..1ba17c589d23a --- /dev/null +++ b/nixos/modules/services/hardware/udisks.nix @@ -0,0 +1,44 @@ +# Udisks daemon. + +{ config, pkgs, ... }: + +with pkgs.lib; + +{ + + ###### interface + + options = { + + services.udisks = { + + enable = mkOption { + default = false; + description = '' + Whether to enable Udisks, a DBus service that allows + applications to query and manipulate storage devices. + ''; + }; + + }; + + }; + + + ###### implementation + + config = mkIf config.services.udisks.enable { + + environment.systemPackages = [ pkgs.udisks ]; + + services.dbus.packages = [ pkgs.udisks ]; + + system.activationScripts.udisks = + '' + mkdir -m 0755 -p /var/lib/udisks + ''; + + services.udev.packages = [ pkgs.udisks ]; + }; + +} diff --git a/nixos/modules/services/hardware/udisks2.nix b/nixos/modules/services/hardware/udisks2.nix new file mode 100644 index 0000000000000..eae4172ccb3ed --- /dev/null +++ b/nixos/modules/services/hardware/udisks2.nix @@ -0,0 +1,53 @@ +# Udisks daemon. + +{ config, pkgs, ... }: + +with pkgs.lib; + +{ + + ###### interface + + options = { + + services.udisks2 = { + + enable = mkOption { + default = false; + 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.services.udisks2 = { + description = "Udisks2 service"; + serviceConfig = { + Type = "dbus"; + BusName = "org.freedesktop.UDisks2"; + ExecStart = "${pkgs.udisks2}/lib/udisks2/udisksd --no-debug"; + }; + }; + }; + +} diff --git a/nixos/modules/services/hardware/upower.nix b/nixos/modules/services/hardware/upower.nix new file mode 100644 index 0000000000000..5d1658adb75f4 --- /dev/null +++ b/nixos/modules/services/hardware/upower.nix @@ -0,0 +1,64 @@ +# Upower daemon. + +{ config, pkgs, ... }: + +with pkgs.lib; + +{ + + ###### interface + + options = { + + services.upower = { + + enable = mkOption { + default = false; + description = '' + Whether to enable Upower, a DBus service that provides power + management support to applications. + ''; + }; + + }; + + }; + + + ###### implementation + + config = mkIf config.services.upower.enable { + + environment.systemPackages = [ pkgs.upower ]; + + services.dbus.packages = [ pkgs.upower ]; + + services.udev.packages = [ pkgs.upower ]; + + systemd.services.upower = + { description = "Power Management Daemon"; + path = [ pkgs.glib ]; # needed for gdbus + serviceConfig = + { Type = "dbus"; + BusName = "org.freedesktop.UPower"; + ExecStart = "@${pkgs.upower}/libexec/upowerd upowerd"; + }; + }; + + 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 + ''; + + }; + +} |