at 23.11-pre 5.0 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 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 (lib.mdDoc "support for Bluetooth"); 40 41 hsphfpd.enable = mkEnableOption (lib.mdDoc "support for hsphfpd[-prototype] implementation"); 42 43 powerOnBoot = mkOption { 44 type = types.bool; 45 default = true; 46 description = lib.mdDoc "Whether to power up the default Bluetooth controller on boot."; 47 }; 48 49 package = mkOption { 50 type = types.package; 51 default = pkgs.bluez; 52 defaultText = literalExpression "pkgs.bluez"; 53 description = lib.mdDoc '' 54 Which BlueZ package to use. 55 ''; 56 }; 57 58 disabledPlugins = mkOption { 59 type = types.listOf types.str; 60 default = [ ]; 61 description = lib.mdDoc "Built-in plugins to disable"; 62 }; 63 64 settings = mkOption { 65 type = cfgFmt.type; 66 default = { }; 67 example = { 68 General = { 69 ControllerMode = "bredr"; 70 }; 71 }; 72 description = lib.mdDoc "Set configuration for system-wide bluetooth (/etc/bluetooth/main.conf)."; 73 }; 74 75 input = mkOption { 76 type = cfgFmt.type; 77 default = { }; 78 example = { 79 General = { 80 IdleTimeout = 30; 81 ClassicBondedOnly = true; 82 }; 83 }; 84 description = lib.mdDoc "Set configuration for the input service (/etc/bluetooth/input.conf)."; 85 }; 86 87 network = mkOption { 88 type = cfgFmt.type; 89 default = { }; 90 example = { 91 General = { 92 DisableSecurity = true; 93 }; 94 }; 95 description = lib.mdDoc "Set configuration for the network service (/etc/bluetooth/network.conf)."; 96 }; 97 }; 98 }; 99 100 ###### implementation 101 102 config = mkIf cfg.enable { 103 environment.systemPackages = [ package ] 104 ++ optional cfg.hsphfpd.enable pkgs.hsphfpd; 105 106 environment.etc."bluetooth/input.conf".source = 107 cfgFmt.generate "input.conf" cfg.input; 108 environment.etc."bluetooth/network.conf".source = 109 cfgFmt.generate "network.conf" cfg.network; 110 environment.etc."bluetooth/main.conf".source = 111 cfgFmt.generate "main.conf" (recursiveUpdate defaults cfg.settings); 112 services.udev.packages = [ package ]; 113 services.dbus.packages = [ package ] 114 ++ optional cfg.hsphfpd.enable pkgs.hsphfpd; 115 systemd.packages = [ package ]; 116 117 systemd.services = { 118 bluetooth = 119 let 120 # `man bluetoothd` will refer to main.conf in the nix store but bluez 121 # will in fact load the configuration file at /etc/bluetooth/main.conf 122 # so force it here to avoid any ambiguity and things suddenly breaking 123 # if/when the bluez derivation is changed. 124 args = [ "-f" "/etc/bluetooth/main.conf" ] 125 ++ optional hasDisabledPlugins 126 "--noplugin=${concatStringsSep "," cfg.disabledPlugins}"; 127 in 128 { 129 wantedBy = [ "bluetooth.target" ]; 130 aliases = [ "dbus-org.bluez.service" ]; 131 serviceConfig.ExecStart = [ 132 "" 133 "${package}/libexec/bluetooth/bluetoothd ${escapeShellArgs args}" 134 ]; 135 # restarting can leave people without a mouse/keyboard 136 unitConfig.X-RestartIfChanged = false; 137 }; 138 } 139 // (optionalAttrs cfg.hsphfpd.enable { 140 hsphfpd = { 141 after = [ "bluetooth.service" ]; 142 requires = [ "bluetooth.service" ]; 143 wantedBy = [ "bluetooth.target" ]; 144 145 description = "A prototype implementation used for connecting HSP/HFP Bluetooth devices"; 146 serviceConfig.ExecStart = "${pkgs.hsphfpd}/bin/hsphfpd.pl"; 147 }; 148 }); 149 150 systemd.user.services = { 151 obex.aliases = [ "dbus-org.bluez.obex.service" ]; 152 } 153 // optionalAttrs cfg.hsphfpd.enable { 154 telephony_client = { 155 wantedBy = [ "default.target" ]; 156 157 description = "telephony_client for hsphfpd"; 158 serviceConfig.ExecStart = "${pkgs.hsphfpd}/bin/telephony_client.pl"; 159 }; 160 }; 161 }; 162}