1 { config, lib, pkgs, ... }:
3 cfg = config.hardware.bluetooth;
7 mkDefault mkEnableOption mkIf mkOption
8 mkRenamedOptionModule mkRemovedOptionModule
9 concatStringsSep escapeShellArgs literalExpression
10 optional optionals optionalAttrs recursiveUpdate types;
12 cfgFmt = pkgs.formats.ini { };
15 General.ControllerMode = "dual";
16 Policy.AutoEnable = cfg.powerOnBoot;
19 hasDisabledPlugins = builtins.length cfg.disabledPlugins > 0;
24 (mkRenamedOptionModule [ "hardware" "bluetooth" "config" ] [ "hardware" "bluetooth" "settings" ])
25 (mkRemovedOptionModule [ "hardware" "bluetooth" "extraConfig" ] ''
26 Use hardware.bluetooth.settings instead.
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
38 hardware.bluetooth = {
39 enable = mkEnableOption (lib.mdDoc "support for Bluetooth");
41 hsphfpd.enable = mkEnableOption (lib.mdDoc "support for hsphfpd[-prototype] implementation");
43 powerOnBoot = mkOption {
46 description = lib.mdDoc "Whether to power up the default Bluetooth controller on boot.";
52 defaultText = literalExpression "pkgs.bluez";
53 description = lib.mdDoc ''
54 Which BlueZ package to use.
58 disabledPlugins = mkOption {
59 type = types.listOf types.str;
61 description = lib.mdDoc "Built-in plugins to disable";
69 ControllerMode = "bredr";
72 description = lib.mdDoc "Set configuration for system-wide bluetooth (/etc/bluetooth/main.conf).";
81 ClassicBondedOnly = true;
84 description = lib.mdDoc "Set configuration for the input service (/etc/bluetooth/input.conf).";
92 DisableSecurity = true;
95 description = lib.mdDoc "Set configuration for the network service (/etc/bluetooth/network.conf).";
100 ###### implementation
102 config = mkIf cfg.enable {
103 environment.systemPackages = [ package ]
104 ++ optional cfg.hsphfpd.enable pkgs.hsphfpd;
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 ];
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}";
129 wantedBy = [ "bluetooth.target" ];
130 aliases = [ "dbus-org.bluez.service" ];
131 serviceConfig.ExecStart = [
133 "${package}/libexec/bluetooth/bluetoothd ${escapeShellArgs args}"
135 # restarting can leave people without a mouse/keyboard
136 unitConfig.X-RestartIfChanged = false;
139 // (optionalAttrs cfg.hsphfpd.enable {
141 after = [ "bluetooth.service" ];
142 requires = [ "bluetooth.service" ];
143 wantedBy = [ "bluetooth.target" ];
145 description = "A prototype implementation used for connecting HSP/HFP Bluetooth devices";
146 serviceConfig.ExecStart = "${pkgs.hsphfpd}/bin/hsphfpd.pl";
150 systemd.user.services = {
151 obex.aliases = [ "dbus-org.bluez.obex.service" ];
153 // optionalAttrs cfg.hsphfpd.enable {
155 wantedBy = [ "default.target" ];
157 description = "telephony_client for hsphfpd";
158 serviceConfig.ExecStart = "${pkgs.hsphfpd}/bin/telephony_client.pl";