at 21.11-pre 6.8 kB view raw
1{ config, lib, pkgs, ... }: 2 3with lib; 4 5let 6 7 cfg = config.services.thinkfan; 8 settingsFormat = pkgs.formats.yaml { }; 9 configFile = settingsFormat.generate "thinkfan.yaml" cfg.settings; 10 thinkfan = pkgs.thinkfan.override { inherit (cfg) smartSupport; }; 11 12 # fan-speed and temperature levels 13 levelType = with types; 14 let 15 tuple = ts: mkOptionType { 16 name = "tuple"; 17 merge = mergeOneOption; 18 check = xs: all id (zipListsWith (t: x: t.check x) ts xs); 19 description = "tuple of" + concatMapStrings (t: " (${t.description})") ts; 20 }; 21 level = ints.unsigned; 22 special = enum [ "level auto" "level full-speed" "level disengage" ]; 23 in 24 tuple [ (either level special) level level ]; 25 26 # sensor or fan config 27 sensorType = name: types.submodule { 28 freeformType = types.attrsOf settingsFormat.type; 29 options = { 30 type = mkOption { 31 type = types.enum [ "hwmon" "atasmart" "tpacpi" "nvml" ]; 32 description = '' 33 The ${name} type, can be 34 <literal>hwmon</literal> for standard ${name}s, 35 36 <literal>atasmart</literal> to read the temperature via 37 S.M.A.R.T (requires smartSupport to be enabled), 38 39 <literal>tpacpi</literal> for the legacy thinkpac_acpi driver, or 40 41 <literal>nvml</literal> for the (proprietary) nVidia driver. 42 ''; 43 }; 44 query = mkOption { 45 type = types.str; 46 description = '' 47 The query string used to match one or more ${name}s: can be 48 a fullpath to the temperature file (single ${name}) or a fullpath 49 to a driver directory (multiple ${name}s). 50 51 <note><para> 52 When multiple ${name}s match, the query can be restricted using the 53 <option>name</option> or <option>indices</option> options. 54 </para></note> 55 ''; 56 }; 57 indices = mkOption { 58 type = with types; nullOr (listOf ints.unsigned); 59 default = null; 60 description = '' 61 A list of ${name}s to pick in case multiple ${name}s match the query. 62 63 <note><para>Indices start from 0.</para></note> 64 ''; 65 }; 66 } // optionalAttrs (name == "sensor") { 67 correction = mkOption { 68 type = with types; nullOr (listOf int); 69 default = null; 70 description = '' 71 A list of values to be added to the temperature of each sensor, 72 can be used to equalize small discrepancies in temperature ratings. 73 ''; 74 }; 75 }; 76 }; 77 78 # removes NixOS special and unused attributes 79 sensorToConf = { type, query, ... }@args: 80 (filterAttrs (k: v: v != null && !(elem k ["type" "query"])) args) 81 // { "${type}" = query; }; 82 83 syntaxNote = name: '' 84 <note><para> 85 This section slightly departs from the thinkfan.conf syntax. 86 The type and path must be specified like this: 87 <literal> 88 type = "tpacpi"; 89 query = "/proc/acpi/ibm/${name}"; 90 </literal> 91 instead of a single declaration like: 92 <literal> 93 - tpacpi: /proc/acpi/ibm/${name} 94 </literal> 95 </para></note> 96 ''; 97 98in { 99 100 options = { 101 102 services.thinkfan = { 103 104 enable = mkOption { 105 type = types.bool; 106 default = false; 107 description = '' 108 Whether to enable thinkfan, a fan control program. 109 110 <note><para> 111 This module targets IBM/Lenovo thinkpads by default, for 112 other hardware you will have configure it more carefully. 113 </para></note> 114 ''; 115 relatedPackages = [ "thinkfan" ]; 116 }; 117 118 smartSupport = mkOption { 119 type = types.bool; 120 default = false; 121 description = '' 122 Whether to build thinkfan with S.M.A.R.T. support to read temperatures 123 directly from hard disks. 124 ''; 125 }; 126 127 sensors = mkOption { 128 type = types.listOf (sensorType "sensor"); 129 default = [ 130 { type = "tpacpi"; 131 query = "/proc/acpi/ibm/thermal"; 132 } 133 ]; 134 description = '' 135 List of temperature sensors thinkfan will monitor. 136 '' + syntaxNote "thermal"; 137 }; 138 139 fans = mkOption { 140 type = types.listOf (sensorType "fan"); 141 default = [ 142 { type = "tpacpi"; 143 query = "/proc/acpi/ibm/fan"; 144 } 145 ]; 146 description = '' 147 List of fans thinkfan will control. 148 '' + syntaxNote "fan"; 149 }; 150 151 levels = mkOption { 152 type = types.listOf levelType; 153 default = [ 154 [0 0 55] 155 [1 48 60] 156 [2 50 61] 157 [3 52 63] 158 [6 56 65] 159 [7 60 85] 160 ["level auto" 80 32767] 161 ]; 162 description = '' 163 [LEVEL LOW HIGH] 164 165 LEVEL is the fan level to use: it can be an integer (0-7 with thinkpad_acpi), 166 "level auto" (to keep the default firmware behavior), "level full-speed" or 167 "level disengage" (to run the fan as fast as possible). 168 LOW is the temperature at which to step down to the previous level. 169 HIGH is the temperature at which to step up to the next level. 170 All numbers are integers. 171 ''; 172 }; 173 174 extraArgs = mkOption { 175 type = types.listOf types.str; 176 default = [ ]; 177 example = [ "-b" "0" ]; 178 description = '' 179 A list of extra command line arguments to pass to thinkfan. 180 Check the thinkfan(1) manpage for available arguments. 181 ''; 182 }; 183 184 settings = mkOption { 185 type = types.attrsOf settingsFormat.type; 186 default = { }; 187 description = '' 188 Thinkfan settings. Use this option to configure thinkfan 189 settings not exposed in a NixOS option or to bypass one. 190 Before changing this, read the <literal>thinkfan.conf(5)</literal> 191 manpage and take a look at the example config file at 192 <link xlink:href="https://github.com/vmatare/thinkfan/blob/master/examples/thinkfan.yaml"/> 193 ''; 194 }; 195 196 }; 197 198 }; 199 200 config = mkIf cfg.enable { 201 202 environment.systemPackages = [ thinkfan ]; 203 204 services.thinkfan.settings = mapAttrs (k: v: mkDefault v) { 205 sensors = map sensorToConf cfg.sensors; 206 fans = map sensorToConf cfg.fans; 207 levels = cfg.levels; 208 }; 209 210 systemd.packages = [ thinkfan ]; 211 212 systemd.services = { 213 thinkfan.environment.THINKFAN_ARGS = escapeShellArgs ([ "-c" configFile ] ++ cfg.extraArgs); 214 215 # must be added manually, see issue #81138 216 thinkfan.wantedBy = [ "multi-user.target" ]; 217 thinkfan-wakeup.wantedBy = [ "sleep.target" ]; 218 thinkfan-sleep.wantedBy = [ "sleep.target" ]; 219 }; 220 221 boot.extraModprobeConfig = "options thinkpad_acpi experimental=1 fan_control=1"; 222 223 }; 224}