1{ lib, config, ... }:
2
3with lib;
4let
5 mergeFalseByDefault = locs: defs:
6 if defs == [] then abort "This case should never happen."
7 else if any (x: x == false) (getValues defs) then false
8 else true;
9
10 kernelItem = types.submodule {
11 options = {
12 tristate = mkOption {
13 type = types.enum [ "y" "m" "n" null ];
14 default = null;
15 internal = true;
16 visible = true;
17 description = ''
18 Use this field for tristate kernel options expecting a "y" or "m" or "n".
19 '';
20 };
21
22 freeform = mkOption {
23 type = types.nullOr types.str // {
24 merge = mergeEqualOption;
25 };
26 default = null;
27 example = ''MMC_BLOCK_MINORS.freeform = "32";'';
28 description = ''
29 Freeform description of a kernel configuration item value.
30 '';
31 };
32
33 optional = mkOption {
34 type = types.bool // { merge = mergeFalseByDefault; };
35 default = false;
36 description = ''
37 Whether option should generate a failure when unused.
38 Upon merging values, mandatory wins over optional.
39 '';
40 };
41 };
42 };
43
44 mkValue = with lib; val:
45 let
46 isNumber = c: elem c ["0" "1" "2" "3" "4" "5" "6" "7" "8" "9"];
47
48 in
49 if (val == "") then "\"\""
50 else if val == "y" || val == "m" || val == "n" then val
51 else if all isNumber (stringToCharacters val) then val
52 else if substring 0 2 val == "0x" then val
53 else val; # FIXME: fix quoting one day
54
55
56 # generate nix intermediate kernel config file of the form
57 #
58 # VIRTIO_MMIO m
59 # VIRTIO_BLK y
60 # VIRTIO_CONSOLE n
61 # NET_9P_VIRTIO? y
62 #
63 # Borrowed from copumpkin https://github.com/NixOS/nixpkgs/pull/12158
64 # returns a string, expr should be an attribute set
65 # Use mkValuePreprocess to preprocess option values, aka mark 'modules' as 'yes' or vice-versa
66 # use the identity if you don't want to override the configured values
67 generateNixKConf = exprs:
68 let
69 mkConfigLine = key: item:
70 let
71 val = if item.freeform != null then item.freeform else item.tristate;
72 in
73 optionalString (val != null)
74 (if (item.optional)
75 then "${key}? ${mkValue val}\n"
76 else "${key} ${mkValue val}\n");
77
78 mkConf = cfg: concatStrings (mapAttrsToList mkConfigLine cfg);
79 in mkConf exprs;
80
81in
82{
83
84 options = {
85
86 intermediateNixConfig = mkOption {
87 readOnly = true;
88 type = types.lines;
89 example = ''
90 USB? y
91 DEBUG n
92 '';
93 description = ''
94 The result of converting the structured kernel configuration in settings
95 to an intermediate string that can be parsed by generate-config.pl to
96 answer the kernel `make defconfig`.
97 '';
98 };
99
100 settings = mkOption {
101 type = types.attrsOf kernelItem;
102 example = literalExpression '' with lib.kernel; {
103 "9P_NET" = yes;
104 USB = option yes;
105 MMC_BLOCK_MINORS = freeform "32";
106 }'';
107 description = ''
108 Structured kernel configuration.
109 '';
110 };
111 };
112
113 config = {
114 intermediateNixConfig = generateNixKConf config.settings;
115 };
116}