aboutsummaryrefslogtreecommitdiff
path: root/nixos/modules/hardware
diff options
context:
space:
mode:
authorVladimír Čunát <v@cunat.cz>2019-09-04 11:00:56 +0200
committerVladimír Čunát <v@cunat.cz>2019-09-04 11:00:56 +0200
commit4aad2947f8d680f18e5b01e115cf8cff22186998 (patch)
treea7a3d020efc6ec7be822bc06e08eca3ac311c9e2 /nixos/modules/hardware
parent2c5835b09a1d4966756212902d36b1b8ab242da6 (diff)
parent1d8a3973f46a2d1360f855eaa0f3a19859771793 (diff)
Merge branch 'master' into staging-next
Diffstat (limited to 'nixos/modules/hardware')
-rw-r--r--nixos/modules/hardware/openrazer.nix133
-rw-r--r--nixos/modules/hardware/printers.nix135
2 files changed, 268 insertions, 0 deletions
diff --git a/nixos/modules/hardware/openrazer.nix b/nixos/modules/hardware/openrazer.nix
new file mode 100644
index 00000000000..883db7f2f4f
--- /dev/null
+++ b/nixos/modules/hardware/openrazer.nix
@@ -0,0 +1,133 @@
+{ config, pkgs, lib, ... }:
+
+with lib;
+
+let
+ cfg = config.hardware.openrazer;
+ kernelPackages = config.boot.kernelPackages;
+
+ toPyBoolStr = b: if b then "True" else "False";
+
+ daemonExe = "${pkgs.openrazer-daemon}/bin/openrazer-daemon --config ${daemonConfFile}";
+
+ daemonConfFile = pkgs.writeTextFile {
+ name = "razer.conf";
+ text = ''
+ [General]
+ verbose_logging = ${toPyBoolStr cfg.verboseLogging}
+
+ [Startup]
+ sync_effects_enabled = ${toPyBoolStr cfg.syncEffectsEnabled}
+ devices_off_on_screensaver = ${toPyBoolStr cfg.devicesOffOnScreensaver}
+ mouse_battery_notifier = ${toPyBoolStr cfg.mouseBatteryNotifier}
+
+ [Statistics]
+ key_statistics = ${toPyBoolStr cfg.keyStatistics}
+ '';
+ };
+
+ dbusServiceFile = pkgs.writeTextFile rec {
+ name = "org.razer.service";
+ destination = "/share/dbus-1/services/${name}";
+ text = ''
+ [D-BUS Service]
+ Name=org.razer
+ Exec=${daemonExe}
+ SystemdService=openrazer-daemon.service
+ '';
+ };
+
+ drivers = [
+ "razerkbd"
+ "razermouse"
+ "razerfirefly"
+ "razerkraken"
+ "razermug"
+ "razercore"
+ ];
+in
+{
+ options = {
+ hardware.openrazer = {
+ enable = mkEnableOption "OpenRazer drivers and userspace daemon.";
+
+ verboseLogging = mkOption {
+ type = types.bool;
+ default = false;
+ description = ''
+ Whether to enable verbose logging. Logs debug messages.
+ '';
+ };
+
+ syncEffectsEnabled = mkOption {
+ type = types.bool;
+ default = true;
+ description = ''
+ Set the sync effects flag to true so any assignment of
+ effects will work across devices.
+ '';
+ };
+
+ devicesOffOnScreensaver = mkOption {
+ type = types.bool;
+ default = true;
+ description = ''
+ Turn off the devices when the systems screensaver kicks in.
+ '';
+ };
+
+ mouseBatteryNotifier = mkOption {
+ type = types.bool;
+ default = true;
+ description = ''
+ Mouse battery notifier.
+ '';
+ };
+
+ keyStatistics = mkOption {
+ type = types.bool;
+ default = false;
+ description = ''
+ Collects number of keypresses per hour per key used to
+ generate a heatmap.
+ '';
+ };
+ };
+ };
+
+ config = mkIf cfg.enable {
+ boot.extraModulePackages = [ kernelPackages.openrazer ];
+ boot.kernelModules = drivers;
+
+ # Makes the man pages available so you can succesfully run
+ # > systemctl --user help openrazer-daemon
+ environment.systemPackages = [ pkgs.python3Packages.openrazer-daemon.man ];
+
+ services.udev.packages = [ kernelPackages.openrazer ];
+ services.dbus.packages = [ dbusServiceFile ];
+
+ # A user must be a member of the plugdev group in order to start
+ # the openrazer-daemon. Therefore we make sure that the plugdev
+ # group exists.
+ users.groups.plugdev = {};
+
+ systemd.user.services.openrazer-daemon = {
+ description = "Daemon to manage razer devices in userspace";
+ unitConfig.Documentation = "man:openrazer-daemon(8)";
+ # Requires a graphical session so the daemon knows when the screensaver
+ # starts. See the 'devicesOffOnScreensaver' option.
+ wantedBy = [ "graphical-session.target" ];
+ partOf = [ "graphical-session.target" ];
+ serviceConfig = {
+ Type = "dbus";
+ BusName = "org.razer";
+ ExecStart = "${daemonExe} --foreground";
+ Restart = "always";
+ };
+ };
+ };
+
+ meta = {
+ maintainers = with lib.maintainers; [ roelvandijk ];
+ };
+}
diff --git a/nixos/modules/hardware/printers.nix b/nixos/modules/hardware/printers.nix
new file mode 100644
index 00000000000..12ee5516d4e
--- /dev/null
+++ b/nixos/modules/hardware/printers.nix
@@ -0,0 +1,135 @@
+{ config, lib, pkgs, ... }:
+with lib;
+let
+ cfg = config.hardware.printers;
+ ppdOptionsString = options: optionalString (options != {})
+ (concatStringsSep " "
+ (mapAttrsToList (name: value: "-o '${name}'='${value}'") options)
+ );
+ ensurePrinter = p: ''
+ ${pkgs.cups}/bin/lpadmin -p '${p.name}' -E \
+ ${optionalString (p.location != null) "-L '${p.location}'"} \
+ ${optionalString (p.description != null) "-D '${p.description}'"} \
+ -v '${p.deviceUri}' \
+ -m '${p.model}' \
+ ${ppdOptionsString p.ppdOptions}
+ '';
+ ensureDefaultPrinter = name: ''
+ ${pkgs.cups}/bin/lpoptions -d '${name}'
+ '';
+
+ # "graph but not # or /" can't be implemented as regex alone due to missing lookahead support
+ noInvalidChars = str: all (c: c != "#" && c != "/") (stringToCharacters str);
+ printerName = (types.addCheck (types.strMatching "[[:graph:]]+") noInvalidChars)
+ // { description = "printable string without spaces, # and /"; };
+
+
+in {
+ options = {
+ hardware.printers = {
+ ensureDefaultPrinter = mkOption {
+ type = types.nullOr printerName;
+ default = null;
+ description = ''
+ Ensures the named printer is the default CUPS printer / printer queue.
+ '';
+ };
+ ensurePrinters = mkOption {
+ description = ''
+ Will regularly ensure that the given CUPS printers are configured as declared here.
+ If a printer's options are manually changed afterwards, they will be overwritten eventually.
+ This option will never delete any printer, even if removed from this list.
+ You can check existing printers with <command>lpstat -s</command>
+ and remove printers with <command>lpadmin -x &lt;printer-name&gt;</command>.
+ Printers not listed here can still be manually configured.
+ '';
+ default = [];
+ type = types.listOf (types.submodule {
+ options = {
+ name = mkOption {
+ type = printerName;
+ example = "BrotherHL_Workroom";
+ description = ''
+ Name of the printer / printer queue.
+ May contain any printable characters except "/", "#", and space.
+ '';
+ };
+ location = mkOption {
+ type = types.nullOr types.str;
+ default = null;
+ example = "Workroom";
+ description = ''
+ Optional human-readable location.
+ '';
+ };
+ description = mkOption {
+ type = types.nullOr types.str;
+ default = null;
+ example = "Brother HL-5140";
+ description = ''
+ Optional human-readable description.
+ '';
+ };
+ deviceUri = mkOption {
+ type = types.str;
+ example = [
+ "ipp://printserver.local/printers/BrotherHL_Workroom"
+ "usb://HP/DESKJET%20940C?serial=CN16E6C364BH"
+ ];
+ description = ''
+ How to reach the printer.
+ <command>lpinfo -v</command> shows a list of supported device URIs and schemes.
+ '';
+ };
+ model = mkOption {
+ type = types.str;
+ example = literalExample ''
+ gutenprint.''${lib.version.majorMinor (lib.getVersion pkgs.cups)}://brother-hl-5140/expert
+ '';
+ description = ''
+ Location of the ppd driver file for the printer.
+ <command>lpinfo -m</command> shows a list of supported models.
+ '';
+ };
+ ppdOptions = mkOption {
+ type = types.attrsOf types.str;
+ example = {
+ "PageSize" = "A4";
+ "Duplex" = "DuplexNoTumble";
+ };
+ default = {};
+ description = ''
+ Sets PPD options for the printer.
+ <command>lpoptions [-p printername] -l</command> shows suported PPD options for the given printer.
+ '';
+ };
+ };
+ });
+ };
+ };
+ };
+
+ config = mkIf (cfg.ensurePrinters != [] && config.services.printing.enable) {
+ systemd.services."ensure-printers" = let
+ cupsUnit = if config.services.printing.startWhenNeeded then "cups.socket" else "cups.service";
+ in {
+ description = "Ensure NixOS-configured CUPS printers";
+ wantedBy = [ "multi-user.target" ];
+ requires = [ cupsUnit ];
+ # in contrast to cups.socket, for cups.service, this is actually not enough,
+ # as the cups service reports its activation before clients can actually interact with it.
+ # Because of this, commands like `lpinfo -v` will report a bad file descriptor
+ # due to the missing UNIX socket without sufficient sleep time.
+ after = [ cupsUnit ];
+
+ serviceConfig = {
+ Type = "oneshot";
+ };
+
+ # sleep 10 is required to wait until cups.service is actually initialized and has created its UNIX socket file
+ script = (optionalString (!config.services.printing.startWhenNeeded) "sleep 10\n")
+ + (concatMapStringsSep "\n" ensurePrinter cfg.ensurePrinters)
+ + optionalString (cfg.ensureDefaultPrinter != null) (ensureDefaultPrinter cfg.ensureDefaultPrinter);
+ };
+ };
+}