nixos/preload: init
[NixPkgs.git] / nixos / modules / services / hardware / bluetooth.nix
blob2a58be51bb02385096db04710aab90bd6d3af4bf
1 { config, lib, pkgs, ... }:
2 let
3   cfg = config.hardware.bluetooth;
4   package = cfg.package;
6   inherit (lib)
7     mkDefault mkEnableOption mkIf mkOption
8     mkRenamedOptionModule mkRemovedOptionModule
9     concatStringsSep escapeShellArgs literalExpression
10     optional optionals optionalAttrs recursiveUpdate types;
12   cfgFmt = pkgs.formats.ini { };
14   defaults = {
15     General.ControllerMode = "dual";
16     Policy.AutoEnable = cfg.powerOnBoot;
17   };
19   hasDisabledPlugins = builtins.length cfg.disabledPlugins > 0;
23   imports = [
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
31     '')
32   ];
34   ###### interface
36   options = {
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 {
44         type = types.bool;
45         default = true;
46         description = lib.mdDoc "Whether to power up the default Bluetooth controller on boot.";
47       };
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       };
58       disabledPlugins = mkOption {
59         type = types.listOf types.str;
60         default = [ ];
61         description = lib.mdDoc "Built-in plugins to disable";
62       };
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       };
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       };
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   };
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 ];
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" ];
145         description = "A prototype implementation used for connecting HSP/HFP Bluetooth devices";
146         serviceConfig.ExecStart = "${pkgs.hsphfpd}/bin/hsphfpd.pl";
147       };
148     });
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" ];
157         description = "telephony_client for hsphfpd";
158         serviceConfig.ExecStart = "${pkgs.hsphfpd}/bin/telephony_client.pl";
159       };
160     };
161   };