diff options
Diffstat (limited to 'nixos/modules/services/hardware/bluetooth.nix')
-rw-r--r-- | nixos/modules/services/hardware/bluetooth.nix | 141 |
1 files changed, 141 insertions, 0 deletions
diff --git a/nixos/modules/services/hardware/bluetooth.nix b/nixos/modules/services/hardware/bluetooth.nix new file mode 100644 index 00000000000..69a66723e76 --- /dev/null +++ b/nixos/modules/services/hardware/bluetooth.nix @@ -0,0 +1,141 @@ +{ config, lib, pkgs, ... }: +let + cfg = config.hardware.bluetooth; + package = cfg.package; + + inherit (lib) + mkDefault mkEnableOption mkIf mkOption + mkRenamedOptionModule mkRemovedOptionModule + concatStringsSep escapeShellArgs literalExpression + optional optionals optionalAttrs recursiveUpdate types; + + cfgFmt = pkgs.formats.ini { }; + + defaults = { + General.ControllerMode = "dual"; + Policy.AutoEnable = cfg.powerOnBoot; + }; + + hasDisabledPlugins = builtins.length cfg.disabledPlugins > 0; + +in +{ + imports = [ + (mkRenamedOptionModule [ "hardware" "bluetooth" "config" ] [ "hardware" "bluetooth" "settings" ]) + (mkRemovedOptionModule [ "hardware" "bluetooth" "extraConfig" ] '' + Use hardware.bluetooth.settings instead. + + This is part of the general move to use structured settings instead of raw + text for config as introduced by RFC0042: + https://github.com/NixOS/rfcs/blob/master/rfcs/0042-config-option.md + '') + ]; + + ###### interface + + options = { + + hardware.bluetooth = { + enable = mkEnableOption "support for Bluetooth"; + + hsphfpd.enable = mkEnableOption "support for hsphfpd[-prototype] implementation"; + + 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 = literalExpression "pkgs.bluez"; + example = literalExpression "pkgs.bluezFull"; + description = '' + Which BlueZ package to use. + + <note><para> + Use the <literal>pkgs.bluezFull</literal> package to enable all + bluez plugins. + </para></note> + ''; + }; + + disabledPlugins = mkOption { + type = types.listOf types.str; + default = [ ]; + description = "Built-in plugins to disable"; + }; + + settings = mkOption { + type = cfgFmt.type; + default = { }; + example = { + General = { + ControllerMode = "bredr"; + }; + }; + description = "Set configuration for system-wide bluetooth (/etc/bluetooth/main.conf)."; + }; + }; + }; + + ###### implementation + + config = mkIf cfg.enable { + environment.systemPackages = [ package ] + ++ optional cfg.hsphfpd.enable pkgs.hsphfpd; + + environment.etc."bluetooth/main.conf".source = + cfgFmt.generate "main.conf" (recursiveUpdate defaults cfg.settings); + services.udev.packages = [ package ]; + services.dbus.packages = [ package ] + ++ optional cfg.hsphfpd.enable pkgs.hsphfpd; + systemd.packages = [ package ]; + + systemd.services = { + bluetooth = + let + # `man bluetoothd` will refer to main.conf in the nix store but bluez + # will in fact load the configuration file at /etc/bluetooth/main.conf + # so force it here to avoid any ambiguity and things suddenly breaking + # if/when the bluez derivation is changed. + args = [ "-f" "/etc/bluetooth/main.conf" ] + ++ optional hasDisabledPlugins + "--noplugin=${concatStringsSep "," cfg.disabledPlugins}"; + in + { + wantedBy = [ "bluetooth.target" ]; + aliases = [ "dbus-org.bluez.service" ]; + serviceConfig.ExecStart = [ + "" + "${package}/libexec/bluetooth/bluetoothd ${escapeShellArgs args}" + ]; + # restarting can leave people without a mouse/keyboard + unitConfig.X-RestartIfChanged = false; + }; + } + // (optionalAttrs cfg.hsphfpd.enable { + hsphfpd = { + after = [ "bluetooth.service" ]; + requires = [ "bluetooth.service" ]; + wantedBy = [ "bluetooth.target" ]; + + description = "A prototype implementation used for connecting HSP/HFP Bluetooth devices"; + serviceConfig.ExecStart = "${pkgs.hsphfpd}/bin/hsphfpd.pl"; + }; + }); + + systemd.user.services = { + obex.aliases = [ "dbus-org.bluez.obex.service" ]; + } + // optionalAttrs cfg.hsphfpd.enable { + telephony_client = { + wantedBy = [ "default.target" ]; + + description = "telephony_client for hsphfpd"; + serviceConfig.ExecStart = "${pkgs.hsphfpd}/bin/telephony_client.pl"; + }; + }; + }; +} |