at 24.11-pre 4.8 kB view raw
1{ config, lib, pkgs, ... }: 2let 3 cfg = config.hardware.bluetooth; 4 package = cfg.package; 5 6 inherit (lib) 7 mkDefault mkEnableOption mkIf mkOption mkPackageOption 8 mkRenamedOptionModule mkRemovedOptionModule 9 concatStringsSep escapeShellArgs literalExpression 10 optional optionals optionalAttrs recursiveUpdate types; 11 12 cfgFmt = pkgs.formats.ini { }; 13 14 defaults = { 15 General.ControllerMode = "dual"; 16 Policy.AutoEnable = cfg.powerOnBoot; 17 }; 18 19 hasDisabledPlugins = builtins.length cfg.disabledPlugins > 0; 20 21in 22{ 23 imports = [ 24 (mkRenamedOptionModule [ "hardware" "bluetooth" "config" ] [ "hardware" "bluetooth" "settings" ]) 25 (mkRemovedOptionModule [ "hardware" "bluetooth" "extraConfig" ] '' 26 Use hardware.bluetooth.settings instead. 27 28 This is part of the general move to use structured settings instead of raw 29 text for config as introduced by RFC0042: 30 https://github.com/NixOS/rfcs/blob/master/rfcs/0042-config-option.md 31 '') 32 ]; 33 34 ###### interface 35 36 options = { 37 38 hardware.bluetooth = { 39 enable = mkEnableOption "support for Bluetooth"; 40 41 hsphfpd.enable = mkEnableOption "support for hsphfpd[-prototype] implementation"; 42 43 powerOnBoot = mkOption { 44 type = types.bool; 45 default = true; 46 description = "Whether to power up the default Bluetooth controller on boot."; 47 }; 48 49 package = mkPackageOption pkgs "bluez" { }; 50 51 disabledPlugins = mkOption { 52 type = types.listOf types.str; 53 default = [ ]; 54 description = "Built-in plugins to disable"; 55 }; 56 57 settings = mkOption { 58 type = cfgFmt.type; 59 default = { }; 60 example = { 61 General = { 62 ControllerMode = "bredr"; 63 }; 64 }; 65 description = "Set configuration for system-wide bluetooth (/etc/bluetooth/main.conf)."; 66 }; 67 68 input = mkOption { 69 type = cfgFmt.type; 70 default = { }; 71 example = { 72 General = { 73 IdleTimeout = 30; 74 ClassicBondedOnly = true; 75 }; 76 }; 77 description = "Set configuration for the input service (/etc/bluetooth/input.conf)."; 78 }; 79 80 network = mkOption { 81 type = cfgFmt.type; 82 default = { }; 83 example = { 84 General = { 85 DisableSecurity = true; 86 }; 87 }; 88 description = "Set configuration for the network service (/etc/bluetooth/network.conf)."; 89 }; 90 }; 91 }; 92 93 ###### implementation 94 95 config = mkIf cfg.enable { 96 environment.systemPackages = [ package ] 97 ++ optional cfg.hsphfpd.enable pkgs.hsphfpd; 98 99 environment.etc."bluetooth/input.conf".source = 100 cfgFmt.generate "input.conf" cfg.input; 101 environment.etc."bluetooth/network.conf".source = 102 cfgFmt.generate "network.conf" cfg.network; 103 environment.etc."bluetooth/main.conf".source = 104 cfgFmt.generate "main.conf" (recursiveUpdate defaults cfg.settings); 105 services.udev.packages = [ package ]; 106 services.dbus.packages = [ package ] 107 ++ optional cfg.hsphfpd.enable pkgs.hsphfpd; 108 systemd.packages = [ package ]; 109 110 systemd.services = { 111 bluetooth = 112 let 113 # `man bluetoothd` will refer to main.conf in the nix store but bluez 114 # will in fact load the configuration file at /etc/bluetooth/main.conf 115 # so force it here to avoid any ambiguity and things suddenly breaking 116 # if/when the bluez derivation is changed. 117 args = [ "-f" "/etc/bluetooth/main.conf" ] 118 ++ optional hasDisabledPlugins 119 "--noplugin=${concatStringsSep "," cfg.disabledPlugins}"; 120 in 121 { 122 wantedBy = [ "bluetooth.target" ]; 123 aliases = [ "dbus-org.bluez.service" ]; 124 serviceConfig.ExecStart = [ 125 "" 126 "${package}/libexec/bluetooth/bluetoothd ${escapeShellArgs args}" 127 ]; 128 # restarting can leave people without a mouse/keyboard 129 unitConfig.X-RestartIfChanged = false; 130 }; 131 } 132 // (optionalAttrs cfg.hsphfpd.enable { 133 hsphfpd = { 134 after = [ "bluetooth.service" ]; 135 requires = [ "bluetooth.service" ]; 136 wantedBy = [ "bluetooth.target" ]; 137 138 description = "A prototype implementation used for connecting HSP/HFP Bluetooth devices"; 139 serviceConfig.ExecStart = "${pkgs.hsphfpd}/bin/hsphfpd.pl"; 140 }; 141 }); 142 143 systemd.user.services = { 144 obex.aliases = [ "dbus-org.bluez.obex.service" ]; 145 } 146 // optionalAttrs cfg.hsphfpd.enable { 147 telephony_client = { 148 wantedBy = [ "default.target" ]; 149 150 description = "telephony_client for hsphfpd"; 151 serviceConfig.ExecStart = "${pkgs.hsphfpd}/bin/telephony_client.pl"; 152 }; 153 }; 154 }; 155}