• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1"""Functions related to hardware topology.
2
3See proto definitions for descriptions of arguments.
4"""
5
6load(
7    "@proto//chromiumos/config/api/component.proto",
8    comp_pb = "chromiumos.config.api",
9)
10load(
11    "@proto//chromiumos/config/api/hardware_topology.proto",
12    hw_topo_pb = "chromiumos.config.api",
13)
14load(
15    "@proto//chromiumos/config/api/proximity_config.proto",
16    prox_pb = "chromiumos.config.api",
17)
18load(
19    "@proto//chromiumos/config/api/topology.proto",
20    topo_pb = "chromiumos.config.api",
21)
22
23# Needed to load from @proto. Add @unused to silence lint.
24load("//config/util/bindings/proto.star", "protos")
25load("//config/util/hw_features.star", "hw_feat")
26
27_HW_FEAT = topo_pb.HardwareFeatures
28
29_PRESENT = struct(
30    UNKNOWN = _HW_FEAT.PRESENT_UNKNOWN,
31    PRESENT = _HW_FEAT.PRESENT,
32    NOT_PRESENT = _HW_FEAT.NOT_PRESENT,
33)
34
35_AUDIO_CODEC = struct(
36    RT5682 = _HW_FEAT.Audio.RT5682,
37    ALC5682I = _HW_FEAT.Audio.ALC5682I,
38    ALC5682 = _HW_FEAT.Audio.ALC5682,
39    DA7219 = _HW_FEAT.Audio.DA7219,
40    NAU88L25B = _HW_FEAT.Audio.NAU88L25B,
41    CS42L42 = _HW_FEAT.Audio.CS42L42,
42    ALC5682IVS = _HW_FEAT.Audio.ALC5682IVS,
43    WCD9385 = _HW_FEAT.Audio.WCD9385,
44    ALC5650 = _HW_FEAT.Audio.AUDIO_CODEC_ALC5650,
45    ES8326 = _HW_FEAT.Audio.ES8326,
46    ALC256 = _HW_FEAT.Audio.AUDIO_CODEC_ALC256,
47    ALC3247 = _HW_FEAT.Audio.AUDIO_CODEC_ALC3247,
48    ALC3287 = _HW_FEAT.Audio.AUDIO_CODEC_ALC3287,
49    ALC272 = _HW_FEAT.Audio.ALC272,
50    ALC722 = _HW_FEAT.Audio.AUDIO_CODEC_ALC722,
51    ALC721 = _HW_FEAT.Audio.AUDIO_CODEC_ALC721,
52    ALC3204 = _HW_FEAT.Audio.AUDIO_CODEC_ALC3204,
53)
54
55_AMPLIFIER = struct(
56    MAX98357 = _HW_FEAT.Audio.MAX98357,
57    MAX98373 = _HW_FEAT.Audio.MAX98373,
58    MAX98360 = _HW_FEAT.Audio.MAX98360,
59    RT1015 = _HW_FEAT.Audio.RT1015,
60    ALC1011 = _HW_FEAT.Audio.ALC1011,
61    RT1015P = _HW_FEAT.Audio.RT1015P,
62    ALC1019 = _HW_FEAT.Audio.ALC1019,
63    MAX98390 = _HW_FEAT.Audio.MAX98390,
64    MAX98396 = _HW_FEAT.Audio.MAX98396,
65    CS35L41 = _HW_FEAT.Audio.CS35L41,
66    MAX98363 = _HW_FEAT.Audio.MAX98363,
67    NAU8318 = _HW_FEAT.Audio.NAU8318,
68    ALC5650 = _HW_FEAT.Audio.AMPLIFIER_ALC5650,
69    ALC256 = _HW_FEAT.Audio.AMPLIFIER_ALC256,
70    ALC3247 = _HW_FEAT.Audio.AMPLIFIER_ALC3247,
71    ALC3287 = _HW_FEAT.Audio.AMPLIFIER_ALC3287,
72    TAS2563 = _HW_FEAT.Audio.TAS2563,
73    ALC722 = _HW_FEAT.Audio.AMPLIFIER_ALC722,
74    ALC721 = _HW_FEAT.Audio.AMPLIFIER_ALC721,
75    ALC3204 = _HW_FEAT.Audio.AMPLIFIER_ALC3204,
76)
77
78_CELLULAR = struct(
79    CELLULAR_UNKNOWN = _HW_FEAT.Cellular.CELLULAR_UNKNOWN,
80    CELLULAR_LTE = _HW_FEAT.Cellular.CELLULAR_LTE,
81    CELLULAR_5G = _HW_FEAT.Cellular.CELLULAR_5G,
82)
83
84_MODEM = struct(
85    MODEM_UNKNOWN = _HW_FEAT.Cellular.MODEM_UNKNOWN,
86    MODEM_L850 = _HW_FEAT.Cellular.MODEM_L850,
87    MODEM_NL668 = _HW_FEAT.Cellular.MODEM_NL668,
88    MODEM_FM101 = _HW_FEAT.Cellular.MODEM_FM101,
89    MODEM_FM350 = _HW_FEAT.Cellular.MODEM_FM350,
90    MODEM_SC7180 = _HW_FEAT.Cellular.MODEM_SC7180,
91    MODEM_SC7280 = _HW_FEAT.Cellular.MODEM_SC7280,
92    MODEM_EM060 = _HW_FEAT.Cellular.MODEM_EM060,
93    MODEM_RW101 = _HW_FEAT.Cellular.MODEM_RW101,
94    MODEM_RW135 = _HW_FEAT.Cellular.MODEM_RW135,
95    MODEM_LCUK54 = _HW_FEAT.Cellular.MODEM_LCUK54,
96)
97
98_DGPU = struct(
99    DGPU_UNKNOWN = _HW_FEAT.Dgpu.DGPU_UNKNOWN,
100    DGPU_NV3050 = _HW_FEAT.Dgpu.DGPU_NV3050,
101    DGPU_NV4050 = _HW_FEAT.Dgpu.DGPU_NV4050,
102)
103
104_FP_LOC = struct(
105    UNKNOWN = _HW_FEAT.Fingerprint.LOCATION_UNKNOWN,
106    POWER_BUTTON_TOP_LEFT = _HW_FEAT.Fingerprint.POWER_BUTTON_TOP_LEFT,
107    KEYBOARD_BOTTOM_LEFT = _HW_FEAT.Fingerprint.KEYBOARD_BOTTOM_LEFT,
108    KEYBOARD_BOTTOM_RIGHT = _HW_FEAT.Fingerprint.KEYBOARD_BOTTOM_RIGHT,
109    KEYBOARD_TOP_RIGHT = _HW_FEAT.Fingerprint.KEYBOARD_TOP_RIGHT,
110    RIGHT_SIDE = _HW_FEAT.Fingerprint.RIGHT_SIDE,
111    LEFT_SIDE = _HW_FEAT.Fingerprint.LEFT_SIDE,
112    LEFT_OF_POWER_BUTTON_TOP_RIGHT = _HW_FEAT.Fingerprint.LEFT_OF_POWER_BUTTON_TOP_RIGHT,
113)
114
115_PS_RADIO_TYPE = struct(
116    UNKNOWN = prox_pb.ProximityConfig.Location.UNKNOWN,
117    WIFI = prox_pb.ProximityConfig.Location.WIFI,
118    CELLULAR = prox_pb.ProximityConfig.Location.CELLULAR,
119)
120
121_STORAGE = struct(
122    UNKNOWN = comp_pb.Component.Storage.STORAGE_TYPE_UNKNOWN,
123    EMMC = comp_pb.Component.Storage.EMMC,
124    NVME = comp_pb.Component.Storage.NVME,
125    SATA = comp_pb.Component.Storage.SATA,
126    UFS = comp_pb.Component.Storage.UFS,
127    BRIDGED_EMMC = comp_pb.Component.Storage.BRIDGED_EMMC,
128)
129
130_DISPLAY_PANEL_TYPE = struct(
131    UNKNOWN = comp_pb.Component.DisplayPanel.PANEL_TYPE_UNKNOWN,
132    OLED = comp_pb.Component.DisplayPanel.OLED,
133)
134
135_KB_TYPE = struct(
136    NONE = _HW_FEAT.Keyboard.NONE,
137    INTERNAL = _HW_FEAT.Keyboard.INTERNAL,
138    DETACHABLE = _HW_FEAT.Keyboard.DETACHABLE,
139)
140
141_KB_MCU_TYPE = struct(
142    NONE = _HW_FEAT.Keyboard.KEYBOARD_MCU_NOT_PRESENT,
143    MCU_PRISM = _HW_FEAT.Keyboard.KEYBOARD_MCU_PRISM,
144)
145
146_KB_BOTTOM_LEFT_LAYOUT = struct(
147    UNKNOWN = _HW_FEAT.Keyboard.KEYBOARD_BOTTOM_LEFT_LAYOUT_UNKNOWN,
148    BOTTOM_LEFT_3_KEYS = _HW_FEAT.Keyboard.KEYBOARD_BOTTOM_LEFT_3_KEYS,
149    BOTTOM_LEFT_4_KEYS = _HW_FEAT.Keyboard.KEYBOARD_BOTTOM_LEFT_4_KEYS,
150)
151
152_KB_BOTTOM_RIGHT_LAYOUT = struct(
153    UNKNOWN = _HW_FEAT.Keyboard.KEYBOARD_BOTTOM_RIGHT_LAYOUT_UNKNOWN,
154    BOTTOM_RIGHT_2_KEYS = _HW_FEAT.Keyboard.KEYBOARD_BOTTOM_RIGHT_2_KEYS,
155    BOTTOM_RIGHT_3_KEYS = _HW_FEAT.Keyboard.KEYBOARD_BOTTOM_RIGHT_3_KEYS,
156    BOTTOM_RIGHT_4_KEYS = _HW_FEAT.Keyboard.KEYBOARD_BOTTOM_RIGHT_4_KEYS,
157)
158
159_KB_NUMERIC_PAD_LAYOUT = struct(
160    UNKNOWN = _HW_FEAT.Keyboard.NUMERIC_PAD_LAYOUT_UNKNOWN,
161    NUMERIC_PAD_3_COLUMN = _HW_FEAT.Keyboard.NUMERIC_PAD_3_COLUMN,
162    NUMERIC_PAD_4_COLUMN = _HW_FEAT.Keyboard.NUMERIC_PAD_4_COLUMN,
163)
164
165_STYLUS = struct(
166    NONE = _HW_FEAT.Stylus.NONE,
167    INTERNAL = _HW_FEAT.Stylus.INTERNAL,
168    EXTERNAL = _HW_FEAT.Stylus.EXTERNAL,
169)
170
171_REGION = struct(
172    SCREEN = _HW_FEAT.Button.SCREEN,
173    KEYBOARD = _HW_FEAT.Button.KEYBOARD,
174)
175
176_EDGE = struct(
177    LEFT = _HW_FEAT.Button.LEFT,
178    RIGHT = _HW_FEAT.Button.RIGHT,
179    TOP = _HW_FEAT.Button.TOP,
180    BOTTOM = _HW_FEAT.Button.BOTTOM,
181)
182
183_CAMERA_FLAGS = struct(
184    SUPPORT_1080P = _HW_FEAT.Camera.FLAGS_SUPPORT_1080P,
185    SUPPORT_AUTOFOCUS = _HW_FEAT.Camera.FLAGS_SUPPORT_AUTOFOCUS,
186)
187
188_EC_TYPE = struct(
189    UNKNOWN = _HW_FEAT.EmbeddedController.EC_TYPE_UNKNOWN,
190    CHROME = _HW_FEAT.EmbeddedController.EC_CHROME,
191    WILCO = _HW_FEAT.EmbeddedController.EC_WILCO,
192)
193
194_TPM_TYPE = struct(
195    UNKNOWN = _HW_FEAT.TrustedPlatformModule.TPM_TYPE_UNKNOWN,
196    THIRD_PARTY = _HW_FEAT.TrustedPlatformModule.THIRD_PARTY,
197    GSC_H1B = _HW_FEAT.TrustedPlatformModule.GSC_H1B,
198    GSC_H1D = _HW_FEAT.TrustedPlatformModule.GSC_H1D,
199)
200
201_PORT_POSITION = struct(
202    LEFT = _HW_FEAT.LEFT,
203    RIGHT = _HW_FEAT.RIGHT,
204    BACK = _HW_FEAT.BACK,
205    FRONT = _HW_FEAT.FRONT,
206)
207
208_AUDIO_CONFIG_STRUCTURE = struct(
209    NONE = _HW_FEAT.Audio.AUDIO_CONFIG_STRUCTURE_NONE,
210    DESIGN = _HW_FEAT.Audio.DESIGN,
211    COMMON = _HW_FEAT.Audio.COMMON,
212)
213
214_RECOVERY_INPUT = struct(
215    UNKNOWN = _HW_FEAT.FormFactor.RECOVERY_INPUT_UNKNOWN,
216    KEYBOARD = _HW_FEAT.FormFactor.KEYBOARD,
217    POWER_BUTTON = _HW_FEAT.FormFactor.POWER_BUTTON,
218    RECOVERY_BUTTON = _HW_FEAT.FormFactor.RECOVERY_BUTTON,
219)
220
221# Starlark doesn't support converting enums to their names. Add helper fns. to
222# do so.
223def _button_region_to_str(region):
224    return {
225        _REGION.SCREEN: "SCREEN",
226        _REGION.KEYBOARD: "KEYBOARD",
227    }.get(region, "UNKNOWN")
228
229def _button_edge_to_str(edge):
230    return {
231        _EDGE.LEFT: "LEFT",
232        _EDGE.RIGHT: "RIGHT",
233        _EDGE.TOP: "TOP",
234        _EDGE.BOTTOM: "BOTTOM",
235    }.get(edge, "UNKNOWN")
236
237def _make_fw_config(mask, id, coreboot_customizations = None):
238    """Builds a HardwareFeatures.FirmwareConfiguration proto.
239
240    Takes a 32-bit mask for the field and an id. Shifts the id
241    into the mask region and checks that the value fits within the bit mask.
242    """
243    lsb_bit_set = (~mask + 1) & mask
244    shifted_id = id * lsb_bit_set
245    if shifted_id & mask != shifted_id:
246        fail("Specified id %d out of range [0, %d]" % (id, mask // lsb_bit_set))
247
248    return _HW_FEAT.FirmwareConfiguration(
249        value = shifted_id,
250        mask = mask,
251        coreboot_customizations = coreboot_customizations,
252    )
253
254def _accumulate_fw_config(existing_fw_config, new_fw_config):
255    """Adds fw config to existing fw config."""
256    if existing_fw_config.mask & new_fw_config.mask:
257        fail("FW_CONFIG masks cannot overlap! 0x%x and 0x%x" %
258             (existing_fw_config.mask, new_fw_config.mask))
259
260    existing_fw_config.value += new_fw_config.value
261    existing_fw_config.mask += new_fw_config.mask
262    existing_fw_config.coreboot_customizations += new_fw_config.coreboot_customizations
263
264def _accumulate_fw_configs(result_hw_features, fw_configs):
265    for fw_config in fw_configs:
266        _accumulate_fw_config(result_hw_features.fw_config, fw_config)
267
268def _create_design_features(form_factor = hw_feat.form_factor.CLAMSHELL):
269    """Builds a HardwareFeatures proto with form_factor."""
270    return _HW_FEAT(
271        form_factor = _HW_FEAT.FormFactor(
272            form_factor = form_factor,
273        ),
274    )
275
276_DEFAULT_FF = [hw_feat.form_factor.CLAMSHELL, hw_feat.form_factor.CONVERTIBLE]
277
278def _create_features(form_factors = _DEFAULT_FF):
279    """Builds a HardwareFeatures proto for each of form_factors."""
280    return [_create_design_features(ff) for ff in form_factors]
281
282def _bool_to_present(value):
283    """Returns correct value of present enum depending on value"""
284    if value == None:
285        return _PRESENT.UNKNOWN
286    elif value:
287        return _PRESENT.PRESENT
288    else:
289        return _PRESENT.NOT_PRESENT
290
291def _create_screen(
292        id = None,
293        description = None,
294        inches = 0,
295        width_px = None,
296        height_px = None,
297        pixels_per_in = None,
298        touch = False,
299        no_als_battery_brightness = None,
300        no_als_battery_brightness_nits = None,
301        no_als_ac_brightness = None,
302        no_als_ac_brightness_nits = None,
303        max_brightness_nits = None,
304        min_visible_backlight_level = None,
305        turn_off_screen_timeout_ms = None,
306        als_steps = None,
307        fw_configs = [],
308        seamless_refresh_rate_switching = False,
309        privacy_screen = False,
310        connector_type = None,
311        rounded_corners = None,
312        variable_refresh_rate_available = False,
313        panel_type = None):
314    """Builds a Topology proto for a screen."""
315    hw_features = _HW_FEAT()
316
317    if no_als_battery_brightness and no_als_battery_brightness_nits:
318        fail("no_als_battery_brightness: Specify percentage or nits, not both")
319    if no_als_ac_brightness and no_als_ac_brightness_nits:
320        fail("no_als_ac_brightness: Specify percentage or nits, not both")
321
322    if (no_als_battery_brightness_nits or no_als_ac_brightness_nits) and not max_brightness_nits:
323        fail("max_brightness_nits must be specified when using " +
324             "no_als_battery_brightness_nits or no_als_ac_brightness_nits.")
325
326    if als_steps:
327        for step in als_steps:
328            if (step.battery_backlight_nits or step.ac_backlight_nits) and not max_brightness_nits:
329                fail("max_brightness_nits must be specified when using " +
330                     "AlsStep with battery_backlight_nits or " +
331                     "ac_backlight_nits.")
332            else:
333                step.max_screen_brightness = max_brightness_nits
334
335    if max_brightness_nits:
336        # The default battery brightnesses can be assumed to be 80 nits if omitted.
337        if not no_als_battery_brightness and not no_als_battery_brightness_nits:
338            no_als_battery_brightness_nits = 80
339
340    hw_features.screen.panel_properties = comp_pb.Component.DisplayPanel.Properties(
341        diagonal_milliinch = inches * 1000,
342        width_px = width_px,
343        height_px = height_px,
344        pixels_per_in = pixels_per_in,
345    )
346    hw_features.screen.touch_support = _bool_to_present(touch)
347    hw_features.screen.connector_type = connector_type
348    hw_features.screen.panel_properties.no_als_battery_brightness = no_als_battery_brightness
349    hw_features.screen.panel_properties.no_als_battery_brightness_nits = no_als_battery_brightness_nits
350    hw_features.screen.panel_properties.no_als_ac_brightness = no_als_ac_brightness
351    hw_features.screen.panel_properties.no_als_ac_brightness_nits = no_als_ac_brightness_nits
352    hw_features.screen.panel_properties.min_visible_backlight_level = min_visible_backlight_level
353    hw_features.screen.panel_properties.als_steps = als_steps
354    hw_features.screen.panel_properties.max_screen_brightness = max_brightness_nits
355    if turn_off_screen_timeout_ms != None:
356        hw_features.screen.panel_properties.turn_off_screen_timeout_ms.value = turn_off_screen_timeout_ms
357    hw_features.screen.panel_properties.rounded_corners = rounded_corners
358    hw_features.screen.panel_properties.panel_type = panel_type
359
360    if privacy_screen:
361        hw_features.privacy_screen.present = _PRESENT.PRESENT
362
363    _accumulate_fw_configs(hw_features, fw_configs)
364
365    if touch:
366        screen_id = id if id else "TOUCHSCREEN"
367        screen_desc = description if description else "Touchscreen"
368    else:
369        screen_id = id if id else "SCREEN"
370        screen_desc = description if description else "Default screen"
371
372    if seamless_refresh_rate_switching:
373        hw_features.screen.panel_properties.features.append(comp_pb.Component.DisplayPanel.SEAMLESS_REFRESH_RATE_SWITCHING)
374
375    if variable_refresh_rate_available:
376        hw_features.screen.panel_properties.features.append(comp_pb.Component.DisplayPanel.VARIABLE_REFRESH_RATE_AVAILABLE)
377
378    return topo_pb.Topology(
379        id = screen_id,
380        type = topo_pb.Topology.SCREEN,
381        description = {"EN": screen_desc},
382        hardware_feature = hw_features,
383    )
384
385def _create_lux_threshold(
386        lux_decrease_threshold,
387        lux_increase_threshold):
388    """Builds a Component.LuxThreshold."""
389
390    lux_threshold = comp_pb.Component.LuxThreshold()
391    lux_threshold.increase_threshold = lux_increase_threshold if lux_increase_threshold != None else -1
392    lux_threshold.decrease_threshold = lux_decrease_threshold if lux_decrease_threshold != None else -1
393    return lux_threshold
394
395def _create_als_step(
396        lux_decrease_threshold,
397        lux_increase_threshold,
398        ac_backlight_percent = None,
399        battery_backlight_percent = None,
400        ac_backlight_nits = None,
401        battery_backlight_nits = None):
402    """Builds a Component.AlsStep.
403
404    Args:
405    lux_decrease_threshold: An int containing the sensor value below which the
406        previous step should be considered. A value of None indicates negative
407        infinity.
408    lux_increase_threshold: An int containing the sensor value above which the
409        next step should be considered. A value of None indicates infinity.
410    ac_backlight_percent: A double containing the backlight brightness
411        percentage to use at this step while on AC power. One of
412        ac_backlight_percent or ac_backlight_nits must be set.
413    ac_backlight_nits: A double containing the backlight brightess in nits to
414        use at this step while on AC power. One of ac_backlight_percent or
415        ac_backlight_nits must be set.
416    battery_backlight_percent: A double containing the backlight brightness
417        percentage to use at this step while on battery power. If unset,
418        defaults to the ac_backlight_percent value. Only oen of
419        battery_backlight_percent or backlight_battery_nits can be set.
420    battery_backlight_nits: A double containing the backlight brighness in nits
421        to use at this step while on battery power. If unset, defaults to the
422        ac_backlight_nits value. Only one of battery_backlight_percent or
423        battery_backlight_nits can be set.
424    """
425    if ac_backlight_percent and ac_backlight_nits:
426        fail("ac_backlight: Specify percentage or nits, not both")
427    if not ac_backlight_percent and not ac_backlight_nits:
428        fail("One of ac_backlight_percent and ac_backlight_nits must be set")
429    if battery_backlight_percent and battery_backlight_nits:
430        fail("battery_backlight: Specify percentage or nits, not both")
431
432    step = comp_pb.Component.AlsStep()
433    step.lux_threshold = _create_lux_threshold(lux_decrease_threshold, lux_increase_threshold)
434    step.ac_backlight_percent = ac_backlight_percent
435    step.ac_backlight_nits = ac_backlight_nits
436    if battery_backlight_percent != None:
437        step.battery_backlight_percent = battery_backlight_percent
438    else:
439        step.battery_backlight_percent = step.ac_backlight_percent
440    if battery_backlight_nits != None:
441        step.battery_backlight_nits = battery_backlight_nits
442    else:
443        step.battery_backlight_nits = step.ac_backlight_nits
444    return step
445
446def _create_kb_als_step(
447        lux_decrease_threshold,
448        lux_increase_threshold,
449        backlight_percent):
450    """Builds a Component.AlsStep.
451
452    Args:
453    lux_decrease_threshold: An int containing the sensor value below which the
454        previous step should be considered. A value of None indicates negative
455        infinity.
456    lux_increase_threshold: An int containing the sensor value above which the
457        next step should be considered. A value of None indicates infinity.
458    backlight_percent: A double containing the backlight brightness
459        percentage to use at this step.
460    """
461    if backlight_percent == None:
462        fail("backlight_percent must be set")
463
464    step = topo_pb.HardwareFeatures.KbAlsStep()
465    step.lux_threshold.increase_threshold = lux_increase_threshold if lux_increase_threshold != None else -1
466    step.lux_threshold.decrease_threshold = lux_decrease_threshold if lux_decrease_threshold != None else -1
467    step.backlight_percent = backlight_percent
468    return step
469
470def _create_form_factor(
471        form_factor,
472        recovery_input = None,
473        fw_configs = [],
474        id = None,
475        description = None,
476        detachable_ui = None):
477    """Builds a Topology proto for a form factor.
478
479    Args:
480        form_factor: A FormFactorType enum. Required.
481        recovery_input: A RecoveryInputType enum. Will be auto-generated if not specified.
482        fw_configs: A list of FirmwareConfiguration protos for the form factor.
483        id: A string identifier for the Topology. If not passed, a default is
484            provided based on form_factor.
485        description: An English description for the Topology. If not passed, a
486            default is provided based on form_factor.
487        detachable_ui: Whether to enable the detachable ui mode for recovery screens.
488    """
489    if not id:
490        id = {
491            hw_feat.form_factor.CLAMSHELL: "CLAMSHELL",
492            hw_feat.form_factor.CONVERTIBLE: "CONVERTIBLE",
493            hw_feat.form_factor.CHROMEBASE: "CHROMEBASE",
494            hw_feat.form_factor.CHROMEBOX: "CHROMEBOX",
495            hw_feat.form_factor.DETACHABLE: "DETACHABLE",
496            hw_feat.form_factor.CHROMESLATE: "CHROMESLATE",
497        }[form_factor]
498
499    if not description:
500        description = {
501            hw_feat.form_factor.CLAMSHELL: "Device cannot rotate past 180 degrees",
502            hw_feat.form_factor.CONVERTIBLE: "Device can rotate 360 degrees",
503            hw_feat.form_factor.CHROMEBASE: "Desktop chrome all-in-one.",
504            hw_feat.form_factor.CHROMEBOX: "Desktop chrome device.",
505            hw_feat.form_factor.DETACHABLE: "Device can detach from its keyboard.",
506            hw_feat.form_factor.CHROMESLATE: "Tablet chrome device.",
507        }[form_factor]
508
509    if not recovery_input:
510        recovery_input = {
511            hw_feat.form_factor.CLAMSHELL: hw_feat.recovery_input.KEYBOARD,
512            hw_feat.form_factor.CONVERTIBLE: hw_feat.recovery_input.KEYBOARD,
513            hw_feat.form_factor.DETACHABLE: hw_feat.recovery_input.KEYBOARD,
514            hw_feat.form_factor.CHROMEBASE: hw_feat.recovery_input.RECOVERY_BUTTON,
515            hw_feat.form_factor.CHROMEBOX: hw_feat.recovery_input.RECOVERY_BUTTON,
516            hw_feat.form_factor.CHROMEBIT: hw_feat.recovery_input.RECOVERY_BUTTON,
517            hw_feat.form_factor.CHROMESLATE: hw_feat.recovery_input.KEYBOARD,
518        }[form_factor]
519
520    hw_features = _HW_FEAT()
521
522    hw_features.form_factor.form_factor = form_factor
523    hw_features.form_factor.recovery_input = recovery_input
524
525    if detachable_ui != None:
526        hw_features.form_factor.detachable_ui.value = detachable_ui
527
528    _accumulate_fw_configs(hw_features, fw_configs)
529
530    return topo_pb.Topology(
531        id = id,
532        type = topo_pb.Topology.FORM_FACTOR,
533        description = {"EN": description},
534        hardware_feature = hw_features,
535    )
536
537def _create_audio_card_config(
538        card_name,
539        ucm_suffix = None,
540        cras_config = _AUDIO_CONFIG_STRUCTURE.DESIGN,
541        cras_suffix = None,
542        ucm_config = _AUDIO_CONFIG_STRUCTURE.DESIGN,
543        sound_card_init_config = _AUDIO_CONFIG_STRUCTURE.NONE):
544    """Builds a CardConfig proto for an audio card config.
545
546    Args:
547        card_name: A string. This should match the card used by ALSA, with an
548            optional suffix starting with a dot, if a suffix representing
549            hardware details, such as the speaker amplifier or jack codec is
550            required. For example, "sof-rt5682.max98373".
551        ucm_suffix: An optional format string used to generate the remainder of
552            the UCM suffix not referring to audio components. If unset, the
553            program-wide default suffix is used. The following placeholders
554            may be used:
555                {design}: The design name.
556                {camera_count}: The number of cameras (usually 0, 1 or 2).
557                {headset_codec}: The headset codec name (in lowercase)
558                    specified in the topology containing this card config.
559                {speaker_amp}: The speaker amp name (in lowercase) specified in
560                    the topology containing this card config.
561                {mic_description}: A description of the microphone topology, of
562                    the form {user_facing_mic_count}uf{world_facing_mic_count}wf, with
563                    components elided if their count is 0.
564                {total_mic_count}: The total number of internal microphones.
565                {user_facing_mic_count}: The number of internal user-facing microphones.
566                {world_facing_mic_count}: The number of internal world-facing microphones.
567            It is strongly recommended that any details of the speaker
568            amplifier or jack codec not be included in this suffix - they
569            should instead be included as part of card_name.
570        cras_config: An AudioConfigStructure enum specifying how cras config
571            files are structured for this card. If unset, defaults to DESIGN.
572        cras_suffix: Similar to ucm_suffix, using same placeholders. If unset, the
573            default cras config path will be used.
574        ucm_config: An AudioConfigStructure enum specifying how ALSA UCM config
575            files are structured for this card. If unset, defaults to DESIGN.
576        sound_card_init_config: An AudioConfigStructure enum specifying how
577            sound card init config files are structured for this card. If unset,
578            defaults to NONE.
579    """
580    if ucm_config == _AUDIO_CONFIG_STRUCTURE.NONE:
581        fail("ucm_config cannot be NONE.")
582
583    config = _HW_FEAT.Audio.CardConfig(
584        card_name = card_name,
585        sound_card_init_config = sound_card_init_config,
586        cras_config = cras_config,
587        ucm_config = ucm_config,
588    )
589    if ucm_suffix != None:
590        config.ucm_suffix.value = ucm_suffix
591    if cras_suffix != None:
592        config.cras_suffix.value = cras_suffix
593    return config
594
595def _create_audio(
596        id,
597        description,
598        codec = None,
599        speaker_amp = None,
600        headphone_codec = None,
601        fw_configs = [],
602        card_configs = [],
603        cras_config = None):
604    """Builds a Topology proto for audio.
605
606    Args:
607        id: A string identifier for the Topology.
608        description: An English description for the Topology.
609        codec: Deprecated.
610        speaker_amp: An Amplifier enum value specifying the speaker amplifier.
611        headphone_codec: An AudioCodec enum value specifying the jack codec.
612        fw_configs: A list of FirmwareConfiguration protos for this audio
613            topology.
614        card_configs: A list of CardConfig protos specifying card configs to be
615            installed and used for this audio topology.
616        cras_config: An AudioConfigStructure enum specifying how card-agnostic
617            cras config files are structured. If unset, defaults to
618            DESIGN if any card_configs are passed, otherwise NONE.
619    """
620    hw_features = _HW_FEAT()
621
622    if codec:
623        hw_features.audio.audio_codec = codec
624    if speaker_amp:
625        hw_features.audio.speaker_amp = speaker_amp
626    if headphone_codec:
627        hw_features.audio.headphone_codec = headphone_codec
628    if card_configs:
629        hw_features.audio.card_configs = card_configs
630    if cras_config != None:
631        hw_features.audio.cras_config = cras_config
632    elif card_configs:
633        hw_features.audio.cras_config = _AUDIO_CONFIG_STRUCTURE.DESIGN
634
635    _accumulate_fw_configs(hw_features, fw_configs)
636
637    return topo_pb.Topology(
638        id = id,
639        type = topo_pb.Topology.AUDIO,
640        description = {"EN": description},
641        hardware_feature = hw_features,
642    )
643
644def _override_audio(
645        source_topo,
646        fw_configs = None,
647        ucm_suffix = None,
648        cras_config = None,
649        cras_suffix = None,
650        ucm_config = None,
651        sound_card_init_config = None,
652        id = None):
653    if source_topo.type != topo_pb.Topology.AUDIO:
654        fail("Invalid audio topology")
655
656    topo = proto.clone(source_topo)
657    if id != None:
658        topo.id = "%s_%s" % (topo.id, id)
659    hw_features = topo.hardware_feature
660    if fw_configs != None:
661        hw_features.fw_config = _HW_FEAT.FirmwareConfiguration()
662        _accumulate_fw_configs(hw_features, fw_configs)
663    for card_config in hw_features.audio.card_configs:
664        if ucm_config != None:
665            if ucm_config == _AUDIO_CONFIG_STRUCTURE.NONE:
666                fail("ucm_config cannot be NONE.")
667            card_config.ucm_config = ucm_config
668        if ucm_suffix != None:
669            card_config.ucm_suffix.value = ucm_suffix
670        if cras_config != None:
671            card_config.cras_config = cras_config
672        if sound_card_init_config != None:
673            card_config.sound_card_init_config = sound_card_init_config
674        if cras_suffix != None:
675            card_config.cras_suffix.value = cras_suffix
676    if cras_config != None:
677        hw_features.audio.cras_config = cras_config
678    return topo
679
680def _create_stylus(id, description, stylus_type, fw_configs = []):
681    """Builds a Topology proto for a stylus."""
682    hw_features = _HW_FEAT()
683
684    hw_features.stylus.stylus = stylus_type
685
686    _accumulate_fw_configs(hw_features, fw_configs)
687
688    return topo_pb.Topology(
689        id = id,
690        type = topo_pb.Topology.STYLUS,
691        description = {"EN": description},
692        hardware_feature = hw_features,
693    )
694
695def _create_keyboard(backlight, pwr_btn_present, kb_type, numpad_present = False, fw_configs = [], id = None, description = None, backlight_user_steps = None, no_als_brightness = None, als_steps = None, mcu_type = _KB_MCU_TYPE.NONE, bottom_left_layout = _KB_BOTTOM_LEFT_LAYOUT.UNKNOWN, bottom_right_layout = _KB_BOTTOM_RIGHT_LAYOUT.UNKNOWN, numeric_pad_layout = _KB_NUMERIC_PAD_LAYOUT.UNKNOWN):
696    """Builds a Topology proto for a keyboard.
697
698    Args:
699        backlight: True if a backlight is present. Required.
700        pwr_btn_present: True if a power button is present. Required.
701        kb_type: A KeyboardType enum. Required.
702        numpad_present: True if numeric pad is present.
703        fw_configs: A list of FirmwareConfiguration protos for the form factor.
704        id: A string identifier for the Topology. If not passed, a default is
705            provided.
706        description: An English description for the Topology. If not passed, a
707            default is provided.
708        backlight_user_steps: A list of doubles specifying the user-selectable
709            backlight steps in increasing order, starting from 0. This controls
710            the keyboard_backlight_user_steps powerd pref.
711        no_als_brightness: A double specifying the default keyboard backlight
712            percentage.
713        als_steps: A list of als_step setting with lux decrease and increase
714            threshold, and the backlight percentage of the step.
715        mcu_type: A KeyboardMcuType enum. Optional.
716	bottom_left_layout: A KeyboardBottomLeftLayout enum. Optional.
717	bottom_right_layout: A KeyboardBottomRightLayout enum. Optional.
718	numeric_pad_layout: A NumericPadLayout enum. Optional.
719    """
720
721    if not id:
722        id = "KB_{backlight}".format(
723            backlight = "BL" if backlight else "NO_BL",
724        )
725
726    if not description:
727        # Starlark doesn't seem to have a way to find the enum name with
728        # reflection.
729        if kb_type == _HW_FEAT.Keyboard.INTERNAL:
730            type_str = "Internal"
731        elif kb_type == _HW_FEAT.Keyboard.DETACHABLE:
732            type_str = "Detachable"
733        else:
734            type_str = "Unknown type"
735
736        description = "{type} keyboard {backlight} backlight".format(
737            type = type_str,
738            backlight = "with" if backlight else "without",
739        )
740
741    hw_features = _HW_FEAT()
742
743    hw_features.keyboard.keyboard_type = kb_type
744    hw_features.keyboard.backlight = _bool_to_present(backlight)
745    hw_features.keyboard.power_button = _bool_to_present(pwr_btn_present)
746    hw_features.keyboard.numeric_pad = _bool_to_present(numpad_present)
747    hw_features.keyboard.backlight_user_steps = backlight_user_steps
748    hw_features.keyboard.no_als_brightness = no_als_brightness
749    hw_features.keyboard.als_steps = als_steps
750    hw_features.keyboard.mcu_type = mcu_type
751    hw_features.keyboard.bottom_left_layout = bottom_left_layout
752    hw_features.keyboard.bottom_right_layout = bottom_right_layout
753    hw_features.keyboard.numeric_pad_layout = numeric_pad_layout
754
755    _accumulate_fw_configs(hw_features, fw_configs)
756
757    return topo_pb.Topology(
758        id = id,
759        type = topo_pb.Topology.KEYBOARD,
760        description = {"EN": description},
761        hardware_feature = hw_features,
762    )
763
764def _create_thermal(
765        id,
766        description,
767        fw_configs = [],
768        config_path_suffix = None):
769    """Builds a Topology proto for thermal solution.
770
771    Args:
772        id: A string identifier for the Topology.
773        description: An English description for the Topology.
774        fw_configs: A list of FirmwareConfiguration protos for this audio
775            topology.
776        config_path_suffix: A suffix to append to the design name when
777        searching for thermal config files, e.g. dptf.dv. The following paths
778        with the thermal directory will be considered, in order:
779            * {suffix}
780            * {design}_{suffix}
781            * {design}_{suffix}/{config_id}.
782        If unset, suffix is treated as an empty string and the underscore after
783        the design name is omitted.
784    """
785    hw_features = _HW_FEAT()
786
787    if config_path_suffix != None:
788        hw_features.thermal.config_path_suffix = config_path_suffix
789
790    _accumulate_fw_configs(hw_features, fw_configs)
791
792    return topo_pb.Topology(
793        id = id,
794        type = topo_pb.Topology.THERMAL,
795        description = {"EN": description},
796        hardware_feature = hw_features,
797    )
798
799def _make_camera_device(
800        interface,
801        facing,
802        orientation,
803        flags,
804        ids,
805        privacy_switch_present = None,
806        microphone_count = None,
807        detachable = False):
808    """Builds a HardwareFeatures.Camera.Device proto."""
809    camera_pb = _HW_FEAT.Camera
810    device = camera_pb.Device()
811
812    device.interface = {
813        "mipi": camera_pb.INTERFACE_MIPI,
814        "usb": camera_pb.INTERFACE_USB,
815    }[interface]
816    device.facing = {
817        "back": camera_pb.FACING_BACK,
818        "front": camera_pb.FACING_FRONT,
819    }[facing]
820    device.orientation = {
821        0: camera_pb.ORIENTATION_0,
822        90: camera_pb.ORIENTATION_90,
823        180: camera_pb.ORIENTATION_180,
824        270: camera_pb.ORIENTATION_270,
825    }[orientation]
826    device.flags = flags
827    device.ids = ids
828
829    if privacy_switch_present != None:
830        device.privacy_switch = _bool_to_present(privacy_switch_present)
831
832    if microphone_count != None:
833        device.microphone_count.value = microphone_count
834
835    device.detachable = detachable
836
837    return device
838
839def _create_camera(
840        id,
841        description,
842        fw_configs = [],
843        camera_devices = []):
844    """Builds a Topology proto for cameras.
845
846    Args:
847        id: A string identifier for the Topology.
848        description: An English description for the Topology.
849        fw_configs: A list of FirmwareConfiguration protos for the form factor.
850        camera_devices: A list of HardwareFeatures.Camera.Device protos.
851    """
852    hw_features = _HW_FEAT()
853
854    camera = hw_features.camera
855    camera.devices = camera_devices
856
857    _accumulate_fw_configs(hw_features, fw_configs)
858
859    return topo_pb.Topology(
860        id = id,
861        type = topo_pb.Topology.CAMERA,
862        description = {"EN": description},
863        hardware_feature = hw_features,
864    )
865
866def _create_sensor(
867        id,
868        description,
869        fw_configs = [],
870        lid_accel_present = None,
871        base_accel_present = None,
872        lid_gyro_present = None,
873        base_gyro_present = None,
874        lid_magno_present = None,
875        base_magno_present = None,
876        lid_light_present = None,
877        base_light_present = None,
878        camera_light_present = None):
879    """Builds a Topology proto for accelerometer/gyroscrope/magnometer sensors."""
880    hw_features = _HW_FEAT()
881
882    _accumulate_fw_configs(hw_features, fw_configs)
883
884    if lid_accel_present:
885        hw_features.accelerometer.lid_accelerometer = _bool_to_present(lid_accel_present)
886
887    if base_accel_present:
888        hw_features.accelerometer.base_accelerometer = _bool_to_present(base_accel_present)
889
890    if lid_gyro_present:
891        hw_features.gyroscope.lid_gyroscope = _bool_to_present(lid_gyro_present)
892
893    if base_gyro_present:
894        hw_features.gyroscope.base_gyroscope = _bool_to_present(base_gyro_present)
895
896    if lid_magno_present:
897        hw_features.magnetometer.lid_magnetometer = _bool_to_present(lid_magno_present)
898
899    if base_magno_present:
900        hw_features.magnetometer.base_magnetometer = _bool_to_present(base_magno_present)
901
902    if lid_light_present:
903        hw_features.light_sensor.lid_lightsensor = _bool_to_present(lid_light_present)
904
905    if base_light_present:
906        hw_features.light_sensor.base_lightsensor = _bool_to_present(base_light_present)
907
908    if camera_light_present:
909        hw_features.light_sensor.camera_lightsensor = _bool_to_present(camera_light_present)
910
911    return topo_pb.Topology(
912        id = id,
913        type = topo_pb.Topology.ACCELEROMETER_GYROSCOPE_MAGNETOMETER,
914        description = {"EN": description},
915        hardware_feature = hw_features,
916    )
917
918def _create_fan(id, description, fw_configs = [], fan_count = None):
919    """Builds a Topology proto for Fan."""
920    hw_features = _HW_FEAT()
921
922    _accumulate_fw_configs(hw_features, fw_configs)
923
924    if fan_count != None:
925        hw_features.fan.fan_count.value = fan_count
926
927    return topo_pb.Topology(
928        id = id,
929        type = topo_pb.Topology.FAN,
930        description = {"EN": description},
931        hardware_feature = hw_features,
932    )
933
934def _create_fingerprint(
935        id,
936        description,
937        present = False,
938        location = _FP_LOC.UNKNOWN,
939        board = None,
940        fw_configs = [],
941        fingerprint_diag = None):
942    """Builds a Topology proto for a fingerprint reader."""
943    hw_features = _HW_FEAT()
944
945    hw_features.fingerprint.present = present
946    hw_features.fingerprint.location = location
947
948    if board:
949        hw_features.fingerprint.board = board
950        if board == "bloonchipper":
951            hw_features.fingerprint.ro_version = "bloonchipper_v2.0.5938-197506c1"
952    if fingerprint_diag:
953        hw_features.fingerprint.fingerprint_diag = fingerprint_diag
954
955    _accumulate_fw_configs(hw_features, fw_configs)
956
957    return topo_pb.Topology(
958        id = id,
959        type = topo_pb.Topology.FINGERPRINT,
960        description = {"EN": description},
961        hardware_feature = hw_features,
962    )
963
964def _create_fingerprint_diag_pixel_median(
965        cb_type1_lower = 0,
966        cb_type1_upper = 0,
967        cb_type2_lower = 0,
968        cb_type2_upper = 0,
969        icb_type1_lower = 0,
970        icb_type1_upper = 0,
971        icb_type2_lower = 0,
972        icb_type2_upper = 0):
973    """ Builds a fingerprint diagnostic PixelMedian proto."""
974    return _HW_FEAT.Fingerprint.FingerprintDiag.PixelMedian(
975        cb_type1_lower = cb_type1_lower,
976        cb_type1_upper = cb_type1_upper,
977        cb_type2_lower = cb_type2_lower,
978        cb_type2_upper = cb_type2_upper,
979        icb_type1_lower = icb_type1_lower,
980        icb_type1_upper = icb_type1_upper,
981        icb_type2_lower = icb_type2_lower,
982        icb_type2_upper = icb_type2_upper,
983    )
984
985def _create_fingerprint_diag_detect_zone(
986        x1 = 0,
987        y1 = 0,
988        x2 = 0,
989        y2 = 0):
990    """ Builds a fingerprint diagnostic DetectZone proto."""
991    return _HW_FEAT.Fingerprint.FingerprintDiag.DetectZone(
992        x1 = x1,
993        y1 = y1,
994        x2 = x2,
995        y2 = y2,
996    )
997
998def _create_fingerprint_diag(
999        routine_enable = False,
1000        max_pixel_dev = 0,
1001        max_dead_pixels = 0,
1002        pixel_median = _create_fingerprint_diag_pixel_median(),
1003        num_detect_zone = 0,
1004        detect_zones = [],
1005        max_dead_pixels_in_detect_zone = 0,
1006        max_reset_pixel_dev = 0,
1007        max_error_reset_pixels = 0):
1008    """ Builds a health routine FingerprintDiag proto."""
1009    return _HW_FEAT.Fingerprint.FingerprintDiag(
1010        routine_enable = routine_enable,
1011        max_pixel_dev = max_pixel_dev,
1012        max_dead_pixels = max_dead_pixels,
1013        pixel_median = pixel_median,
1014        num_detect_zone = num_detect_zone,
1015        detect_zones = detect_zones,
1016        max_dead_pixels_in_detect_zone = max_dead_pixels_in_detect_zone,
1017        max_reset_pixel_dev = max_reset_pixel_dev,
1018        max_error_reset_pixels = max_error_reset_pixels,
1019    )
1020
1021def _create_hps(id, description, present = False, fw_configs = []):
1022    """Builds a Topology proto for HPS."""
1023    hw_features = _HW_FEAT()
1024
1025    hw_features.hps.present = _bool_to_present(present)
1026
1027    _accumulate_fw_configs(hw_features, fw_configs)
1028
1029    return topo_pb.Topology(
1030        id = id,
1031        type = topo_pb.Topology.HPS,
1032        description = {"EN": description},
1033        hardware_feature = hw_features,
1034    )
1035
1036def _create_dp_converter(id, description, names = []):
1037    """Builds a Topology proto for DisplayPort converters."""
1038    return topo_pb.Topology(
1039        id = id,
1040        type = topo_pb.Topology.DP_CONVERTER,
1041        description = {"EN": description},
1042        hardware_feature = _HW_FEAT(
1043            dp_converter = _HW_FEAT.DisplayPortConverter(
1044                converters = [
1045                    comp_pb.Component.DisplayPortConverter(name = name)
1046                    for name in names
1047                ],
1048            ),
1049        ),
1050    )
1051
1052def _create_poe(id, description, present = False, fw_configs = []):
1053    """Builds a Topology proto for PoE."""
1054    hw_features = _HW_FEAT()
1055
1056    hw_features.poe.present = _bool_to_present(present)
1057
1058    _accumulate_fw_configs(hw_features, fw_configs)
1059
1060    return topo_pb.Topology(
1061        id = id,
1062        type = topo_pb.Topology.POE,
1063        description = {"EN": description},
1064        hardware_feature = hw_features,
1065    )
1066
1067def _create_proximity_sensor(id, description, fw_configs = [], proximity_config = None):
1068    """Builds a Topology proto for a proximity sensor."""
1069    hw_features = _HW_FEAT()
1070
1071    if proximity_config:
1072        if type(proximity_config) == "list":
1073            hw_features.proximity.configs.extend(proximity_config)
1074        else:
1075            hw_features.proximity.configs.append(proximity_config)
1076
1077    _accumulate_fw_configs(hw_features, fw_configs)
1078
1079    return topo_pb.Topology(
1080        id = id,
1081        type = topo_pb.Topology.PROXIMITY_SENSOR,
1082        description = {"EN": description},
1083        hardware_feature = hw_features,
1084    )
1085
1086def _create_hdmi(id, description, fw_configs = [], cec = None):
1087    """Builds a Topology proto for HDMI."""
1088    hw_features = _HW_FEAT()
1089
1090    _accumulate_fw_configs(hw_features, fw_configs)
1091
1092    hw_features.hdmi.present = _PRESENT.PRESENT
1093    hw_features.hdmi.cec = cec
1094
1095    return topo_pb.Topology(
1096        id = id,
1097        type = topo_pb.Topology.HDMI,
1098        description = {"EN": description},
1099        hardware_feature = hw_features,
1100    )
1101
1102def _create_hdmi_cec(
1103        power_on_displays_on_boot = False,
1104        power_off_displays_on_shutdown = False):
1105    """ Build a proto for HDMI CEC."""
1106    return _HW_FEAT.Hdmi.Cec(
1107        power_on_displays_on_boot = power_on_displays_on_boot,
1108        power_off_displays_on_shutdown = power_off_displays_on_shutdown,
1109    )
1110
1111def _create_daughter_board(
1112        id,
1113        description,
1114        fw_configs = [],
1115        usbc_count = 0,
1116        usba_count = 0,
1117        usb4 = False,
1118        defer_external_display_timeout = None,
1119        cellular_support = False,
1120        cellular_model = None,
1121        cellular_type = _CELLULAR.CELLULAR_UNKNOWN,
1122        cellular_dynamic_power_reduction_config = None,
1123        cellular_wedge_timeout_in_ms = None,
1124        cellular_modem_type = _MODEM.MODEM_UNKNOWN,
1125        hdmi_support = False,
1126        hdmi_cec = None,
1127        side = None,
1128        usbc_ports = None):
1129    """Builds a Topology proto for a daughter board."""
1130    hw_features = _HW_FEAT()
1131
1132    _accumulate_fw_configs(hw_features, fw_configs)
1133
1134    hw_features.usb_c = _build_usbc(
1135        side,
1136        usbc_ports,
1137        usbc_count,
1138        usb4,
1139        defer_external_display_timeout,
1140    )
1141    hw_features.usb_a.count.value = usba_count
1142
1143    hw_features.cellular.present = _bool_to_present(cellular_support)
1144    hw_features.cellular.model = cellular_model
1145    hw_features.cellular.type = cellular_type
1146    hw_features.cellular.modem_type = cellular_modem_type
1147    hw_features.cellular.dynamic_power_reduction_config = cellular_dynamic_power_reduction_config
1148    if cellular_wedge_timeout_in_ms:
1149        hw_features.cellular.wedge_timeout_in_ms = cellular_wedge_timeout_in_ms
1150
1151    hw_features.hdmi.present = _bool_to_present(hdmi_support)
1152    if hdmi_cec and not hdmi_support:
1153        fail("Daughter board cannot have hdmi_cec without hdmi_support")
1154    hw_features.hdmi.cec = hdmi_cec
1155
1156    return topo_pb.Topology(
1157        id = id,
1158        type = topo_pb.Topology.DAUGHTER_BOARD,
1159        description = {"EN": description},
1160        hardware_feature = hw_features,
1161    )
1162
1163def _create_non_volatile_storage(id, description, storage_type, fw_configs = []):
1164    """Builds a Topology proto for non-volatile storage."""
1165    hw_features = _HW_FEAT()
1166
1167    hw_features.storage.storage_type = storage_type
1168
1169    _accumulate_fw_configs(hw_features, fw_configs)
1170
1171    return topo_pb.Topology(
1172        id = id,
1173        type = topo_pb.Topology.NON_VOLATILE_STORAGE,
1174        description = {"EN": description},
1175        hardware_feature = hw_features,
1176    )
1177
1178def _create_wifi(id, description, fw_configs = [], wifi_config = None):
1179    """Builds a Topology proto for a WiFi chip."""
1180    hw_features = _HW_FEAT()
1181
1182    if wifi_config:
1183        hw_features.wifi.wifi_config = wifi_config
1184
1185    _accumulate_fw_configs(hw_features, fw_configs)
1186
1187    return topo_pb.Topology(
1188        id = id,
1189        type = topo_pb.Topology.WIFI,
1190        description = {"EN": description},
1191        hardware_feature = hw_features,
1192    )
1193
1194def _create_cellular_board(
1195        id,
1196        description,
1197        present,
1198        type = _CELLULAR.CELLULAR_UNKNOWN,
1199        fw_configs = [],
1200        model = None,
1201        dynamic_power_reduction_config = None,
1202        wedge_timeout_in_ms = None,
1203        modem_type = _MODEM.MODEM_UNKNOWN):
1204    """Builds a Topology proto for a Cellular board."""
1205    hw_features = _HW_FEAT()
1206
1207    hw_features.cellular.present = _bool_to_present(present)
1208    hw_features.cellular.model = model
1209    hw_features.cellular.type = type
1210    hw_features.cellular.modem_type = modem_type
1211    hw_features.cellular.dynamic_power_reduction_config = dynamic_power_reduction_config
1212    if wedge_timeout_in_ms:
1213        hw_features.cellular.wedge_timeout_in_ms = wedge_timeout_in_ms
1214
1215    _accumulate_fw_configs(hw_features, fw_configs)
1216
1217    return topo_pb.Topology(
1218        id = id,
1219        type = topo_pb.Topology.CELLULAR_BOARD,
1220        description = {"EN": description},
1221        hardware_feature = hw_features,
1222    )
1223
1224def _make_cellular_dynamic_power_reduction_config(
1225        gpio = None,
1226        modem_manager = False,
1227        tablet_mode = False,
1228        multi_power_level_sar = False,
1229        default_proximity_state_far = False,
1230        power_level_mapping = None,
1231        regulatory_domain_mapping = None):
1232    """Builds a configuration for cellular dynamic power reduction."""
1233    config = _HW_FEAT.Cellular.DynamicPowerReductionConfig()
1234
1235    if modem_manager and gpio != None:
1236        fail("A Cellular.DynamicPowerReductionConfig supports either a GPIO or modem manager based power reduction.")
1237
1238    if modem_manager:
1239        config.modem_manager = True
1240    elif gpio != None:
1241        config.gpio = gpio
1242        if (
1243            multi_power_level_sar or
1244            default_proximity_state_far or
1245            power_level_mapping or
1246            regulatory_domain_mapping
1247        ):
1248            fail("A Cellular.DynamicPowerReductionConfig does not support any customization in GPIO mode.")
1249    else:
1250        fail("A Cellular.DynamicPowerReductionConfig must configure a GPIO or the use of modem manager.")
1251
1252    config.enable_multi_power_level_sar = multi_power_level_sar
1253    config.enable_default_proximity_state_far = default_proximity_state_far
1254    config.tablet_mode = tablet_mode
1255    config.power_level_mapping = power_level_mapping
1256    config.regulatory_domain_mapping = regulatory_domain_mapping
1257
1258    return config
1259
1260def _create_sd_reader(id, description, present = True, fw_configs = []):
1261    """Builds a Topology proto for a SD reader."""
1262    hw_features = _HW_FEAT()
1263
1264    _accumulate_fw_configs(hw_features, fw_configs)
1265    hw_features.sd_reader.present = _bool_to_present(present)
1266
1267    return topo_pb.Topology(
1268        id = id,
1269        type = topo_pb.Topology.SD_READER,
1270        description = {"EN": description},
1271        hardware_feature = hw_features,
1272    )
1273
1274_USB_PORT_POSITIONS = {
1275    _PORT_POSITION.LEFT: {
1276        _PORT_POSITION.FRONT: _HW_FEAT.LEFT_FRONT,
1277        _PORT_POSITION.BACK: _HW_FEAT.LEFT_BACK,
1278        _HW_FEAT.UNKNOWN: _PORT_POSITION.LEFT,
1279    },
1280    _PORT_POSITION.RIGHT: {
1281        _PORT_POSITION.FRONT: _HW_FEAT.RIGHT_FRONT,
1282        _PORT_POSITION.BACK: _HW_FEAT.RIGHT_BACK,
1283        _HW_FEAT.UNKNOWN: _PORT_POSITION.RIGHT,
1284    },
1285    _PORT_POSITION.BACK: {
1286        _PORT_POSITION.LEFT: _HW_FEAT.BACK_LEFT,
1287        _PORT_POSITION.RIGHT: _HW_FEAT.BACK_RIGHT,
1288        _HW_FEAT.UNKNOWN: _PORT_POSITION.BACK,
1289    },
1290}
1291
1292def _normalize_usbc_port(side, port):
1293    position = _USB_PORT_POSITIONS.get(side, {}).get(
1294        port.position,
1295        _HW_FEAT.UNKNOWN,
1296    )
1297    normalized_port = _HW_FEAT.UsbC.Port()
1298    normalized_port.position = position
1299    if proto.has(port, "index_override"):
1300        normalized_port.index_override = port.index_override
1301    return normalized_port
1302
1303def _build_usbc(side, ports, count, usb4, defer_external_display_timeout):
1304    if ports != None:
1305        count = len(ports)
1306    else:
1307        ports = [_create_usbc_port()] * count
1308
1309    result = _HW_FEAT.UsbC()
1310    result.usb4 = usb4
1311    result.count.value = count
1312
1313    if defer_external_display_timeout:
1314        result.defer_external_display_timeout = defer_external_display_timeout
1315
1316    if side:
1317        result.ports = [_normalize_usbc_port(side, port) for port in ports]
1318    return result
1319
1320def _create_usbc_port(position = _HW_FEAT.UNKNOWN, index_override = None):
1321    """Builds a UsbC Port.
1322
1323    Args:
1324        position: An optional _HW_FEAT.PortPosition indicating
1325            the position of this port on the side of the chassis it occupies.
1326            Required if more than one USB-C port is present on the same side of
1327            the chassis.
1328        index_override: An optional int specifying the 0-indexed index of this
1329            port. For ports with this unset, the motherboard ports will be
1330            ordered before the daughter board ports, in the order they are
1331            specified, leaving gaps as needed for ports with an override set.
1332            If set, this value must be in the range [0, number_of_usb_c_ports).
1333    """
1334    port = _HW_FEAT.UsbC.Port()
1335    port.position = position
1336    if index_override != None:
1337        port.index_override.value = index_override
1338    return port
1339
1340def _create_motherboard_usb(
1341        id,
1342        description,
1343        fw_configs = [],
1344        usbc_count = 0,
1345        usba_count = 0,
1346        usb4 = False,
1347        defer_external_display_timeout = None,
1348        side = None,
1349        usbc_ports = None):
1350    """Builds a Topology proto for a motherboard."""
1351    hw_features = _HW_FEAT()
1352
1353    _accumulate_fw_configs(hw_features, fw_configs)
1354
1355    hw_features.usb_c = _build_usbc(
1356        side,
1357        usbc_ports,
1358        usbc_count,
1359        usb4,
1360        defer_external_display_timeout,
1361    )
1362    hw_features.usb_a.count.value = usba_count
1363
1364    return topo_pb.Topology(
1365        id = id,
1366        type = topo_pb.Topology.MOTHERBOARD_USB,
1367        description = {"EN": description},
1368        hardware_feature = hw_features,
1369    )
1370
1371def _create_bluetooth(id, description, bt_component, fw_configs = [], present = True):
1372    """Builds a Topology proto for bluetooth."""
1373    hw_features = _HW_FEAT()
1374
1375    hw_features.bluetooth.present = _bool_to_present(present)
1376    hw_features.bluetooth.component = bt_component
1377
1378    _accumulate_fw_configs(hw_features, fw_configs)
1379
1380    return topo_pb.Topology(
1381        id = id,
1382        type = topo_pb.Topology.BLUETOOTH,
1383        description = {"EN": description},
1384        hardware_feature = hw_features,
1385    )
1386
1387def _create_barreljack(id, description, bj_present, fw_configs = []):
1388    """Builds a Topology proto for barreljack."""
1389    hw_features = _HW_FEAT()
1390
1391    hw_features.barreljack.present = _bool_to_present(bj_present)
1392
1393    _accumulate_fw_configs(hw_features, fw_configs)
1394
1395    return topo_pb.Topology(
1396        id = id,
1397        type = topo_pb.Topology.BARRELJACK,
1398        description = {"EN": description},
1399        hardware_feature = hw_features,
1400    )
1401
1402def _create_power_supply(id, description, bj_present = False, usb_min_ac_watts = None, fw_configs = []):
1403    """Builds a Topology proto for power supply.
1404
1405    Args:
1406        id: A string identifier for the Topology.
1407        description: An English description for the Topology.
1408        bj_present: A bool containing whether a barreljack power port is present
1409        usb_min_ac_watts: The input power below which a warning should be shown
1410            to use a higher-power USB adapter.
1411        fw_configs: A list of firmware configs implied by the Topology.
1412
1413    """
1414    hw_features = _HW_FEAT()
1415
1416    hw_features.power_supply.barreljack = _bool_to_present(bj_present)
1417
1418    if usb_min_ac_watts:
1419        hw_features.power_supply.usb_min_ac_watts = usb_min_ac_watts
1420
1421    _accumulate_fw_configs(hw_features, fw_configs)
1422
1423    return topo_pb.Topology(
1424        id = id,
1425        type = topo_pb.Topology.POWER_SUPPLY,
1426        description = {"EN": description},
1427        hardware_feature = hw_features,
1428    )
1429
1430def _create_power_button(region, edge, position, id = None, description = None):
1431    """Builds a Topology proto for a power button.
1432
1433    Args:
1434        region: A HardwareFeatures.Button.Region enum. Required.
1435        edge: A HardwareFeatures.Button.Edge enum. Required.
1436        position: The percentage for button center position to the display's
1437            width/height in primary landscape screen orientation. If edge is
1438            LEFT or RIGHT, specifies the button's center position as a fraction
1439            of region's height relative to the top of region. For TOP and
1440            BOTTOM, specifies the position as a fraction of region width
1441            relative to the left side of region. Must be in the range
1442            [0.0, 1.0]. Required.
1443        id: A string identifier for the Topology. If not passed, a default is
1444            provided.
1445        description: An English description for the Topology. If not passed, a
1446            default is provided.
1447    """
1448    if not id:
1449        id = "{region}_{edge}_POWER_BUTTON".format(
1450            region = _button_region_to_str(region),
1451            edge = _button_edge_to_str(edge),
1452        )
1453
1454    if not description:
1455        description = "Power button on the {edge} edge of the {region}".format(
1456            region = _button_region_to_str(region).lower(),
1457            edge = _button_edge_to_str(edge).lower(),
1458        )
1459    return topo_pb.Topology(
1460        id = id,
1461        type = topo_pb.Topology.POWER_BUTTON,
1462        description = {"EN": description},
1463        hardware_feature = _HW_FEAT(
1464            power_button = _HW_FEAT.Button(
1465                region = region,
1466                edge = edge,
1467                position = position,
1468            ),
1469        ),
1470    )
1471
1472def _create_volume_button(region, edge, position, id = None, description = None):
1473    """Builds a Topology proto for a volume button.
1474
1475    Args:
1476        region: A HardwareFeatures.Button.Region enum. Required.
1477        edge: A HardwareFeatures.Button.Edge enum. Required.
1478        position: The percentage for button center position to the display's
1479            width/height in primary landscape screen orientation. If edge is
1480            LEFT or RIGHT, specifies the button's center position as a fraction
1481            of region's height relative to the top of region. For TOP and
1482            BOTTOM, specifies the position as a fraction of region width
1483            relative to the left side of region. Must be in the range
1484            [0.0, 1.0]. Required.
1485        id: A string identifier for the Topology. If not passed, a default is
1486            provided.
1487        description: An English description for the Topology. If not passed, a
1488            default is provided.
1489    """
1490    if not id:
1491        id = "{region}_{edge}_VOLUME_BUTTON".format(
1492            region = _button_region_to_str(region),
1493            edge = _button_edge_to_str(edge),
1494        )
1495
1496    if not description:
1497        description = "Volume button on the {edge} edge of the {region}".format(
1498            region = _button_region_to_str(region).lower(),
1499            edge = _button_edge_to_str(edge).lower(),
1500        )
1501    return topo_pb.Topology(
1502        id = id,
1503        type = topo_pb.Topology.POWER_BUTTON,
1504        description = {"EN": description},
1505        hardware_feature = _HW_FEAT(
1506            volume_button = _HW_FEAT.Button(
1507                region = region,
1508                edge = edge,
1509                position = position,
1510            ),
1511        ),
1512    )
1513
1514def _create_ec(present = True, ec_type = _EC_TYPE.CHROME, id = None, max_sensor_odr_mhz = None):
1515    """Builds a Topology proto for an embedded controller.
1516
1517    Args:
1518        present: flag indicating whether the device has an EC at all
1519        ec_type: An EmbeddedControllerType enum
1520        id: A string identifier for the Topology. If not passed, a default is
1521            provided.
1522        max_sensor_odr_mhz: Maximal Sensor ODR override.
1523    """
1524    hw_features = _HW_FEAT()
1525    hw_features.embedded_controller.ec_type = ec_type
1526    hw_features.embedded_controller.present = _bool_to_present(present)
1527    if max_sensor_odr_mhz != None:
1528        hw_features.embedded_controller.max_sensor_odr_mhz.value = max_sensor_odr_mhz
1529
1530    return topo_pb.Topology(
1531        id = id or "ec",
1532        type = topo_pb.Topology.EC,
1533        hardware_feature = hw_features,
1534    )
1535
1536# enumerate the common cases
1537_EC_NONE = _create_ec(present = False, ec_type = _EC_TYPE.UNKNOWN)
1538_EC_CHROME = _create_ec(ec_type = _EC_TYPE.CHROME)
1539_EC_WILCO = _create_ec(ec_type = _EC_TYPE.WILCO)
1540
1541def _create_touch(id, description, fw_configs = [], touch_slop_distance = None):
1542    """Builds a Topology proto for touch."""
1543    hw_features = _HW_FEAT()
1544    if touch_slop_distance != None:
1545        hw_features.touch.touch_slop_distance.value = touch_slop_distance
1546
1547    _accumulate_fw_configs(hw_features, fw_configs)
1548
1549    return topo_pb.Topology(
1550        id = id,
1551        type = topo_pb.Topology.TOUCH,
1552        description = {"EN": description},
1553        hardware_feature = hw_features,
1554    )
1555
1556def _create_tpm(tpm_type = _TPM_TYPE.GSC_H1B, id = None, fw_configs = []):
1557    """Builds a Topology proto for a trusted platform module.
1558
1559    Args:
1560        tpm_type: A TrustedPlatformModuleType enum
1561        id: A string identifier for the Topology. If not passed, a default is
1562            provided.
1563        fw_configs: A list of FirmwareConfiguration protos for the tpm.
1564    """
1565    hw_features = _HW_FEAT()
1566    hw_features.trusted_platform_module.tpm_type = tpm_type
1567
1568    _accumulate_fw_configs(hw_features, fw_configs)
1569
1570    return topo_pb.Topology(
1571        id = id or "TPM",
1572        type = topo_pb.Topology.TPM,
1573        hardware_feature = hw_features,
1574    )
1575
1576def _create_dgpu(id, description, fw_configs = [], dgpu_type = _DGPU.DGPU_UNKNOWN):
1577    """Builds a Topology proto for dgpu."""
1578    hw_features = _HW_FEAT()
1579
1580    hw_features.dgpu_config.present = _bool_to_present(True)
1581    hw_features.dgpu_config.dgpu_type = dgpu_type
1582    _accumulate_fw_configs(hw_features, fw_configs)
1583
1584    return topo_pb.Topology(
1585        id = id,
1586        type = topo_pb.Topology.DGPU,
1587        description = {"EN": description},
1588        hardware_feature = hw_features,
1589    )
1590
1591def _create_uwb(id, description, fw_configs = []):
1592    """Builds a Topology proto for uwb."""
1593    hw_features = _HW_FEAT()
1594
1595    hw_features.uwb_config.present = _bool_to_present(True)
1596
1597    _accumulate_fw_configs(hw_features, fw_configs)
1598
1599    return topo_pb.Topology(
1600        id = id,
1601        type = topo_pb.Topology.UWB,
1602        description = {"EN": description},
1603        hardware_feature = hw_features,
1604    )
1605
1606def _create_detachable_base(
1607        ec_image_name,
1608        product_id,
1609        vendor_id,
1610        fw_configs = [],
1611        i2c_path = None,
1612        usb_path = None,
1613        touch_image_name = None,
1614        id = None,
1615        description = None):
1616    """Builds a Topology proto for detachable.
1617
1618    Args:
1619        ec_image_name: The target EC binary name.
1620        product_id: The Product ID of the detachable base.
1621        vendor_id: The Vendor ID of the detachable base.
1622        fw_configs: A list of FirmwareConfiguration protos for the detachable
1623            base topology.
1624        i2c_path: Searches and finds the idVendor and idProduct under sysfs
1625            /sys/bus/i2c/devices/* which matches the vendor-id and product-id
1626            due to hid-over-i2c is used.
1627            This is required if detachable base goes through i2c interface.
1628            Note - i2c bus numbering can shift across reboots, please have
1629            corresponding setup based on your platform to ensure consistency.
1630        usb_path: Searches and finds the idVendor and idProduct under sysfs
1631            /sys/bus/usb/devices/* which matches the vendor-id and product-id.
1632            This is required if detachable base goes through usb interface.
1633        touch_image_name: The touchpad binary name. This is only needed if the
1634            detachable base contains touchpad.
1635        id: A string identifier for the Topology. If not passed, a default is
1636            provided.
1637        description: An English description for the Topology. There will be a
1638            default string provided based on touch_image_name exist or not.
1639    """
1640    hw_features = _HW_FEAT()
1641
1642    if not id:
1643        id = "DB_{touchpad_str}".format(
1644            touchpad_str = "TP" if touch_image_name else "NO_TP",
1645        )
1646
1647    if not description:
1648        description = "Detachable Base {touchpad_str}".format(
1649            touchpad_str = "With Touchpad" if touch_image_name else "Without Touchpad",
1650        )
1651
1652    if (usb_path and i2c_path) or (not usb_path and not i2c_path):
1653        fail("Specify either usb_path or i2c_path, but not both.")
1654
1655    hw_features.detachable_base.ec_image_name = ec_image_name
1656    hw_features.detachable_base.product_id = product_id
1657    hw_features.detachable_base.i2c_path = i2c_path
1658    hw_features.detachable_base.usb_path = usb_path
1659    hw_features.detachable_base.vendor_id = vendor_id
1660    hw_features.detachable_base.touch_image_name = touch_image_name
1661    _accumulate_fw_configs(hw_features, fw_configs)
1662
1663    return topo_pb.Topology(
1664        id = id,
1665        type = topo_pb.Topology.DETACHABLE_BASE,
1666        description = {"EN": description},
1667        hardware_feature = hw_features,
1668    )
1669
1670def _create_soc(id, description, fw_configs = [], hevc_support = None, arc_media_codecs_suffix = None, resource = None):
1671    """Builds a Topology proto for soc."""
1672    hw_features = _HW_FEAT()
1673
1674    hw_features.soc.arc_media_codecs_suffix = arc_media_codecs_suffix
1675    hw_features.soc.hevc_support = _bool_to_present(hevc_support)
1676    hw_features.soc.resource_config = resource
1677
1678    _accumulate_fw_configs(hw_features, fw_configs)
1679
1680    return topo_pb.Topology(
1681        id = id,
1682        type = topo_pb.Topology.SOC,
1683        description = {"EN": description},
1684        hardware_feature = hw_features,
1685    )
1686
1687def _create_microphone_mute_switch(present = False):
1688    """Builds a Topology proto for an microphone mute switch.
1689
1690    Args:
1691        present: flag indicating whether the device has an microphone mute
1692                 switch
1693    """
1694    hw_features = _HW_FEAT()
1695    hw_features.microphone_mute_switch.present = _bool_to_present(present)
1696
1697    return topo_pb.Topology(
1698        id = "Default",
1699        type = topo_pb.Topology.MICROPHONE_MUTE_SWITCH,
1700        hardware_feature = hw_features,
1701    )
1702
1703def _create_battery(no_battery_boot_supported = False):
1704    """Builds a Topology proto for a battery.
1705
1706    Args:
1707        no_battery_boot_supported: flag indicating whether the device
1708            supports booting with no battery.
1709    """
1710    hw_features = _HW_FEAT()
1711    hw_features.battery.no_battery_boot_supported = no_battery_boot_supported
1712
1713    return topo_pb.Topology(
1714        id = "Default",
1715        type = topo_pb.Topology.BATTERY,
1716        hardware_feature = hw_features,
1717    )
1718
1719def _create_proximity_location(type, modifier = None):
1720    return prox_pb.ProximityConfig.Location(
1721        radio_type = type,
1722        modifier = modifier,
1723    )
1724
1725def _create_legacy_proximity(location):
1726    prox_config = prox_pb.ProximityConfig(
1727        location = None,
1728        legacy_config = prox_pb.ProximityConfig.LegacyProximityConfig(),
1729    )
1730    if type(location) == "list":
1731        prox_config.location.extend(location)
1732    else:
1733        prox_config.location.append(location)
1734
1735    return prox_config
1736
1737def _create_semtech_proximity_channel(
1738        channel,
1739        hardwaregain = 0,
1740        thresh_falling = 0,
1741        thresh_falling_hysteresis = 0,
1742        thresh_rising = 0,
1743        thresh_rising_hysteresis = 0):
1744    return prox_pb.ProximityConfig.SemtechProximityConfig.ChannelConfig(
1745        channel = channel,
1746        hardwaregain = hardwaregain,
1747        thresh_falling = thresh_falling,
1748        thresh_falling_hysteresis = thresh_falling_hysteresis,
1749        thresh_rising = thresh_rising,
1750        thresh_rising_hysteresis = thresh_rising_hysteresis,
1751    )
1752
1753def _create_semtech_proximity(
1754        location,
1755        channels,
1756        sampling_frequency = 0,
1757        thresh_falling_period = 0,
1758        thresh_rising_period = 0):
1759    """ Builds a configuration for Semtech sensors.
1760    """
1761    prox_config = prox_pb.ProximityConfig(
1762        location = None,
1763        semtech_config = prox_pb.ProximityConfig.SemtechProximityConfig(
1764            channel_config = channels,
1765            sampling_frequency = sampling_frequency,
1766            thresh_falling_period = thresh_falling_period,
1767            thresh_rising_period = thresh_rising_period,
1768        ),
1769    )
1770    if type(location) == "list":
1771        prox_config.location.extend(location)
1772    else:
1773        prox_config.location.append(location)
1774
1775    return prox_config
1776
1777def _create_activity_proximity(location):
1778    prox_config = prox_pb.ProximityConfig(
1779        location = None,
1780        activity_config = prox_pb.ProximityConfig.ActivityProximityConfig(),
1781    )
1782    if type(location) == "list":
1783        prox_config.location.extend(location)
1784    else:
1785        prox_config.location.append(location)
1786
1787    return prox_config
1788
1789# enumerate the common cases
1790_TPM_THIRD_PARTY = _create_tpm(tpm_type = _TPM_TYPE.THIRD_PARTY)
1791_TPM_GSC_H1B = _create_tpm(tpm_type = _TPM_TYPE.GSC_H1B)
1792_TPM_GSC_H1D = _create_tpm(tpm_type = _TPM_TYPE.GSC_H1D)
1793
1794def _create_hardware_topology(
1795        screen = None,
1796        form_factor = None,
1797        audio = None,
1798        stylus = None,
1799        keyboard = None,
1800        thermal = None,
1801        camera = None,
1802        accelerometer_gyroscope_magnetometer = None,
1803        fingerprint = None,
1804        proximity_sensor = None,
1805        daughter_board = None,
1806        non_volatile_storage = None,
1807        wifi = None,
1808        cellular_board = None,
1809        sd_reader = None,
1810        motherboard_usb = None,
1811        bluetooth = None,
1812        barreljack = None,
1813        power_supply = None,
1814        power_button = None,
1815        volume_button = None,
1816        ec = None,
1817        touch = None,
1818        tpm = None,
1819        microphone_mute_switch = None,
1820        hdmi = None,
1821        hps = None,
1822        dp_converter = None,
1823        poe = None,
1824        battery = None,
1825        dgpu = None,
1826        uwb = None,
1827        detachable_base = None,
1828        soc = None,
1829        fan = None):
1830    """Builds a HardwareTopology proto from Topology protos."""
1831
1832    # Only allow form_factor topologies for form factors
1833    if screen and screen.type != topo_pb.Topology.SCREEN:
1834        fail("Invalid screen topology")
1835
1836    if form_factor and form_factor.type != topo_pb.Topology.FORM_FACTOR:
1837        fail("Invalid form factor topology")
1838
1839    if audio and audio.type != topo_pb.Topology.AUDIO:
1840        fail("Invalid audio topology")
1841
1842    if stylus and stylus.type != topo_pb.Topology.STYLUS:
1843        fail("Invalid stylus topology")
1844
1845    if keyboard and keyboard.type != topo_pb.Topology.KEYBOARD:
1846        fail("Invalid keyboard topology")
1847
1848    if thermal and thermal.type != topo_pb.Topology.THERMAL:
1849        fail("Invalid thermal topology")
1850
1851    if camera and camera.type != topo_pb.Topology.CAMERA:
1852        fail("Invalid camera topology")
1853
1854    if accelerometer_gyroscope_magnetometer and accelerometer_gyroscope_magnetometer.type != topo_pb.Topology.ACCELEROMETER_GYROSCOPE_MAGNETOMETER:
1855        fail("Invalid accelerometer/gyroscope/magnetometer topology")
1856
1857    if fingerprint and fingerprint.type != topo_pb.Topology.FINGERPRINT:
1858        fail("Invalid fingerprint topology")
1859
1860    if proximity_sensor and proximity_sensor.type != topo_pb.Topology.PROXIMITY_SENSOR:
1861        fail("Invalid proximity sensor topology")
1862
1863    if daughter_board and daughter_board.type != topo_pb.Topology.DAUGHTER_BOARD:
1864        fail("Invalid daughter board topology")
1865
1866    if non_volatile_storage and non_volatile_storage.type != topo_pb.Topology.NON_VOLATILE_STORAGE:
1867        fail("Invalid non-volatile storage topology")
1868
1869    if wifi and wifi.type != topo_pb.Topology.WIFI:
1870        fail("Invalid wifi topology")
1871
1872    if cellular_board and cellular_board.type != topo_pb.Topology.CELLULAR_BOARD:
1873        fail("Invalid cellular board topology")
1874
1875    if sd_reader and sd_reader.type != topo_pb.Topology.SD_READER:
1876        fail("Invalid sd_reader topology")
1877
1878    if motherboard_usb and motherboard_usb.type != topo_pb.Topology.MOTHERBOARD_USB:
1879        fail("Invalid motherboard usb board topology")
1880
1881    if bluetooth and bluetooth.type != topo_pb.Topology.BLUETOOTH:
1882        fail("Invalid bluetooth topology")
1883
1884    if barreljack and barreljack.type != topo_pb.Topology.BARRELJACK:
1885        fail("Invalid barreljack topology")
1886
1887    if power_button and power_button.type != topo_pb.Topology.POWER_BUTTON:
1888        fail("Invalid power button topology")
1889
1890    if volume_button and volume_button.type != topo_pb.Topology.POWER_BUTTON:
1891        fail("Invalid volume button topology")
1892
1893    if ec and ec.type != topo_pb.Topology.EC:
1894        fail("Invalid ec type")
1895
1896    if touch and touch.type != topo_pb.Topology.TOUCH:
1897        fail("Invalid touch topology")
1898
1899    if tpm and tpm.type != topo_pb.Topology.TPM:
1900        fail("Invalid tpm type")
1901
1902    if microphone_mute_switch and microphone_mute_switch.type != topo_pb.Topology.MICROPHONE_MUTE_SWITCH:
1903        fail("Invalid microphone mute switch type")
1904
1905    if hdmi and hdmi.type != topo_pb.Topology.HDMI:
1906        fail("Invalid hdmi topology")
1907
1908    if hps and hps.type != topo_pb.Topology.HPS:
1909        fail("Invalid hps topology")
1910
1911    if dp_converter and dp_converter.type != topo_pb.Topology.DP_CONVERTER:
1912        fail("Invalid cp_converters topology")
1913
1914    if poe and poe.type != topo_pb.Topology.POE:
1915        fail("Invalid PoE topology")
1916
1917    if power_supply and power_supply.type != topo_pb.Topology.POWER_SUPPLY:
1918        fail("Invalid power supply topology")
1919
1920    if battery and battery.type != topo_pb.Topology.BATTERY:
1921        fail("Invalid battery type")
1922
1923    if dgpu and dgpu.type != topo_pb.Topology.DGPU:
1924        fail("Invalid dGPU type")
1925
1926    if uwb and uwb.type != topo_pb.Topology.UWB:
1927        fail("Invalid UWB type")
1928
1929    if detachable_base and detachable_base.type != topo_pb.Topology.DETACHABLE_BASE:
1930        fail("Invalid detachable base type")
1931
1932    if soc and soc.type != topo_pb.Topology.SOC:
1933        fail("Invalid SoC type")
1934
1935    if fan and fan.type != topo_pb.Topology.FAN:
1936        fail("Invalid fan type")
1937
1938    return hw_topo_pb.HardwareTopology(
1939        screen = screen,
1940        form_factor = form_factor,
1941        audio = audio,
1942        stylus = stylus,
1943        keyboard = keyboard,
1944        thermal = thermal,
1945        camera = camera,
1946        accelerometer_gyroscope_magnetometer = accelerometer_gyroscope_magnetometer,
1947        fingerprint = fingerprint,
1948        proximity_sensor = proximity_sensor,
1949        daughter_board = daughter_board,
1950        non_volatile_storage = non_volatile_storage,
1951        wifi = wifi,
1952        cellular_board = cellular_board,
1953        sd_reader = sd_reader,
1954        motherboard_usb = motherboard_usb,
1955        bluetooth = bluetooth,
1956        barreljack = barreljack,
1957        power_button = power_button,
1958        volume_button = volume_button,
1959        ec = ec,
1960        touch = touch,
1961        tpm = tpm,
1962        microphone_mute_switch = microphone_mute_switch,
1963        hdmi = hdmi,
1964        hps = hps,
1965        dp_converter = dp_converter,
1966        poe = poe,
1967        power_supply = power_supply,
1968        battery = battery,
1969        dgpu = dgpu,
1970        uwb = uwb,
1971        detachable_base = detachable_base,
1972        soc = soc,
1973        fan = fan,
1974    )
1975
1976def _accumulate_usbc(existing_usbc, new_usbc):
1977    existing_usbc.count.value += new_usbc.count.value
1978    existing_usbc.usb4 = existing_usbc.usb4 or new_usbc.usb4
1979    existing_usbc.ports += new_usbc.ports
1980
1981def _accumulate_usba(existing_usba, new_usba):
1982    existing_usba.count.value += new_usba.count.value
1983
1984def _accumulate_cellular(existing_cellular, new_cellular):
1985    if existing_cellular.present != _PRESENT.PRESENT:
1986        if new_cellular.present != _PRESENT.UNKNOWN:
1987            existing_cellular.present = new_cellular.present
1988        if new_cellular.present == _PRESENT.PRESENT:
1989            existing_cellular.model = new_cellular.model
1990            existing_cellular.type = new_cellular.type
1991            existing_cellular.modem_type = new_cellular.modem_type
1992            if proto.has(new_cellular, "dynamic_power_reduction_config"):
1993                existing_cellular.dynamic_power_reduction_config = new_cellular.dynamic_power_reduction_config
1994            if new_cellular.wedge_timeout_in_ms:
1995                existing_cellular.wedge_timeout_in_ms = new_cellular.wedge_timeout_in_ms
1996
1997def _accumulate_hdmi(existing_hdmi, new_hdmi):
1998    if existing_hdmi.present != _PRESENT.PRESENT:
1999        if new_hdmi.present != _PRESENT.UNKNOWN:
2000            existing_hdmi.present = new_hdmi.present
2001
2002    if new_hdmi.cec != _HW_FEAT.Hdmi.Cec():
2003        if existing_hdmi.cec != _HW_FEAT.Hdmi.Cec() and existing_hdmi.cec != new_hdmi.cec:
2004            fail("All HDMI ports must have the same CEC settings")
2005        existing_hdmi.cec = new_hdmi.cec
2006
2007def _convert_to_hw_features(hardware_topology):
2008    """Converts a HardwareTopology proto to a HardwareFeatures proto."""
2009    result = _HW_FEAT()
2010
2011    # Need to make deep-copy otherwise we change the has_ message serialization
2012    copy = proto.clone(hardware_topology)
2013
2014    # Handle all possible screen hardware features attributes
2015    _accumulate_fw_config(result.fw_config, copy.screen.hardware_feature.fw_config)
2016
2017    if copy.screen.hardware_feature.screen != _HW_FEAT.Screen():
2018        result.screen = copy.screen.hardware_feature.screen
2019    if copy.screen.hardware_feature.privacy_screen != _HW_FEAT.PrivacyScreen():
2020        result.privacy_screen = copy.screen.hardware_feature.privacy_screen
2021
2022    # Handle all possible form factor hardware features attributes
2023    _accumulate_fw_config(result.fw_config, copy.form_factor.hardware_feature.fw_config)
2024
2025    if copy.form_factor.hardware_feature.form_factor != _HW_FEAT.FormFactor():
2026        result.form_factor = copy.form_factor.hardware_feature.form_factor
2027
2028    # Handle all possible audio features attributes
2029    _accumulate_fw_config(result.fw_config, copy.audio.hardware_feature.fw_config)
2030
2031    if copy.audio.hardware_feature.audio != _HW_FEAT.Audio():
2032        result.audio = copy.audio.hardware_feature.audio
2033
2034    # Handle all possible stylus hardware features attributes
2035    _accumulate_fw_config(result.fw_config, copy.stylus.hardware_feature.fw_config)
2036
2037    if copy.stylus.hardware_feature.stylus != _HW_FEAT.Stylus():
2038        result.stylus = copy.stylus.hardware_feature.stylus
2039
2040    # Handle all possible tpm features attributes
2041    _accumulate_fw_config(result.fw_config, copy.tpm.hardware_feature.fw_config)
2042
2043    # Handle all possible keyboard hardware features attributes
2044    _accumulate_fw_config(result.fw_config, copy.keyboard.hardware_feature.fw_config)
2045
2046    if copy.keyboard.hardware_feature.keyboard != _HW_FEAT.Keyboard():
2047        result.keyboard = copy.keyboard.hardware_feature.keyboard
2048
2049    # Handle all possible thermal features attributes
2050    _accumulate_fw_config(result.fw_config, copy.thermal.hardware_feature.fw_config)
2051
2052    # Handle all possible camera features attributes
2053    _accumulate_fw_config(result.fw_config, copy.camera.hardware_feature.fw_config)
2054
2055    if copy.camera.hardware_feature.camera != _HW_FEAT.Camera():
2056        result.camera = copy.camera.hardware_feature.camera
2057
2058    # Handle all possible sensor attributes
2059    _accumulate_fw_config(result.fw_config, copy.accelerometer_gyroscope_magnetometer.hardware_feature.fw_config)
2060
2061    if copy.accelerometer_gyroscope_magnetometer.hardware_feature.accelerometer != _HW_FEAT.Accelerometer():
2062        result.accelerometer = copy.accelerometer_gyroscope_magnetometer.hardware_feature.accelerometer
2063
2064    if copy.accelerometer_gyroscope_magnetometer.hardware_feature.gyroscope != _HW_FEAT.Gyroscope():
2065        result.gyroscope = copy.accelerometer_gyroscope_magnetometer.hardware_feature.gyroscope
2066
2067    if copy.accelerometer_gyroscope_magnetometer.hardware_feature.magnetometer != _HW_FEAT.Magnetometer():
2068        result.magnetometer = copy.accelerometer_gyroscope_magnetometer.hardware_feature.magnetometer
2069
2070    if copy.accelerometer_gyroscope_magnetometer.hardware_feature.light_sensor != _HW_FEAT.LightSensor():
2071        result.light_sensor = copy.accelerometer_gyroscope_magnetometer.hardware_feature.light_sensor
2072
2073    # Handle all possible fingerprint hardware features attributes
2074    _accumulate_fw_config(result.fw_config, copy.fingerprint.hardware_feature.fw_config)
2075
2076    if copy.fingerprint.hardware_feature.fingerprint != _HW_FEAT.Fingerprint():
2077        result.fingerprint = copy.fingerprint.hardware_feature.fingerprint
2078
2079    # Handle all possible hps hardware features attributes
2080    _accumulate_fw_config(result.fw_config, copy.hps.hardware_feature.fw_config)
2081
2082    if copy.hps.hardware_feature.hps != _HW_FEAT.Hps():
2083        result.hps = copy.hps.hardware_feature.hps
2084
2085    # Handle all possible poe hardware features attributes
2086    _accumulate_fw_config(result.fw_config, copy.poe.hardware_feature.fw_config)
2087
2088    if copy.poe.hardware_feature.poe != _HW_FEAT.PoE():
2089        result.poe = copy.poe.hardware_feature.poe
2090
2091    # Handle all possible proximity sensor hardware features attributes
2092    _accumulate_fw_config(result.fw_config, copy.proximity_sensor.hardware_feature.fw_config)
2093
2094    if proto.has(copy.proximity_sensor.hardware_feature, "proximity"):
2095        result.proximity = copy.proximity_sensor.hardware_feature.proximity
2096
2097    # Handle all possible hdmi hardware features attributes
2098    _accumulate_fw_config(result.fw_config, copy.hdmi.hardware_feature.fw_config)
2099
2100    if copy.hdmi.hardware_feature.hdmi != _HW_FEAT.Hdmi():
2101        result.hdmi = copy.hdmi.hardware_feature.hdmi
2102
2103    # Handle all possible motherboard usb features attributes
2104    _accumulate_fw_config(result.fw_config, copy.motherboard_usb.hardware_feature.fw_config)
2105
2106    if copy.motherboard_usb.hardware_feature.usb_c != _HW_FEAT.UsbC():
2107        _accumulate_usbc(result.usb_c, copy.motherboard_usb.hardware_feature.usb_c)
2108
2109    if copy.motherboard_usb.hardware_feature.usb_a != _HW_FEAT.UsbA():
2110        _accumulate_usba(result.usb_a, copy.motherboard_usb.hardware_feature.usb_a)
2111
2112    # Handle all possible daughter board hardware features attributes
2113    _accumulate_fw_config(result.fw_config, copy.daughter_board.hardware_feature.fw_config)
2114
2115    if copy.daughter_board.hardware_feature.usb_c != _HW_FEAT.UsbC():
2116        _accumulate_usbc(result.usb_c, copy.daughter_board.hardware_feature.usb_c)
2117
2118    if copy.daughter_board.hardware_feature.usb_a != _HW_FEAT.UsbA():
2119        _accumulate_usba(result.usb_a, copy.daughter_board.hardware_feature.usb_a)
2120
2121    if copy.daughter_board.hardware_feature.cellular != _HW_FEAT.Cellular():
2122        _accumulate_cellular(result.cellular, copy.daughter_board.hardware_feature.cellular)
2123
2124    if copy.daughter_board.hardware_feature.hdmi != _HW_FEAT.Hdmi():
2125        _accumulate_hdmi(result.hdmi, copy.daughter_board.hardware_feature.hdmi)
2126
2127    # Handle all possible non volatile storage hardware features attributes
2128    _accumulate_fw_config(result.fw_config, copy.non_volatile_storage.hardware_feature.fw_config)
2129
2130    if copy.non_volatile_storage.hardware_feature.storage != _HW_FEAT.Storage():
2131        result.storage = copy.non_volatile_storage.hardware_feature.storage
2132
2133    # Handle all possible wifi hardware features attributes
2134    _accumulate_fw_config(result.fw_config, copy.wifi.hardware_feature.fw_config)
2135
2136    if copy.wifi.hardware_feature.wifi != _HW_FEAT.Wifi():
2137        result.wifi = copy.wifi.hardware_feature.wifi
2138
2139    # Handle all possible cellular board attributes
2140    _accumulate_fw_config(result.fw_config, copy.cellular_board.hardware_feature.fw_config)
2141
2142    if copy.cellular_board.hardware_feature.cellular != _HW_FEAT.Cellular():
2143        _accumulate_cellular(result.cellular, copy.cellular_board.hardware_feature.cellular)
2144
2145    # Handle all possible sd reader hardware features attributes
2146    _accumulate_fw_config(result.fw_config, copy.sd_reader.hardware_feature.fw_config)
2147
2148    if copy.sd_reader.hardware_feature.sd_reader != _HW_FEAT.SdReader():
2149        result.sd_reader = copy.sd_reader.hardware_feature.sd_reader
2150
2151    # Handle all possible bluetooth features attributes
2152    _accumulate_fw_config(result.fw_config, copy.bluetooth.hardware_feature.fw_config)
2153
2154    if copy.bluetooth.hardware_feature.bluetooth != _HW_FEAT.Bluetooth():
2155        result.bluetooth = copy.bluetooth.hardware_feature.bluetooth
2156
2157    # Handle all possible barreljack features
2158    _accumulate_fw_config(result.fw_config, copy.barreljack.hardware_feature.fw_config)
2159
2160    if copy.barreljack.hardware_feature.barreljack != _HW_FEAT.BarrelJack():
2161        result.barreljack = copy.barreljack.hardware_feature.barreljack
2162
2163    # Handle all possible power supply features
2164    _accumulate_fw_config(result.fw_config, copy.power_supply.hardware_feature.fw_config)
2165
2166    if copy.power_supply.hardware_feature.power_supply != _HW_FEAT.PowerSupply():
2167        result.power_supply = copy.power_supply.hardware_feature.power_supply
2168
2169    if copy.power_button.hardware_feature.power_button != _HW_FEAT.Button():
2170        result.power_button = copy.power_button.hardware_feature.power_button
2171
2172    if copy.volume_button.hardware_feature.volume_button != _HW_FEAT.Button():
2173        result.volume_button = copy.volume_button.hardware_feature.volume_button
2174
2175    if copy.microphone_mute_switch.hardware_feature.microphone_mute_switch != _HW_FEAT.MicrophoneMuteSwitch():
2176        result.microphone_mute_switch = copy.microphone_mute_switch.hardware_feature.microphone_mute_switch
2177
2178    if copy.battery.hardware_feature.battery != _HW_FEAT.Battery():
2179        result.battery = copy.battery.hardware_feature.battery
2180
2181    if copy.thermal.hardware_feature.thermal != _HW_FEAT.Thermal():
2182        result.thermal = copy.thermal.hardware_feature.thermal
2183
2184    # Handle all possible touch hardware features
2185    _accumulate_fw_config(result.fw_config, copy.touch.hardware_feature.fw_config)
2186    if copy.touch.hardware_feature.touch != _HW_FEAT.Touch():
2187        result.touch = copy.touch.hardware_feature.touch
2188
2189    # Handle all possible detachable base attributes
2190    _accumulate_fw_config(result.fw_config, copy.detachable_base.hardware_feature.fw_config)
2191
2192    if copy.detachable_base.hardware_feature.detachable_base != _HW_FEAT.DetachableBase():
2193        result.detachable_base = copy.detachable_base.hardware_feature.detachable_base
2194
2195    _accumulate_fw_config(result.fw_config, copy.soc.hardware_feature.fw_config)
2196
2197    if copy.soc.hardware_feature.soc != _HW_FEAT.Soc():
2198        result.soc = copy.soc.hardware_feature.soc
2199
2200    _accumulate_fw_config(result.fw_config, copy.uwb.hardware_feature.fw_config)
2201    if copy.uwb.hardware_feature.uwb_config != _HW_FEAT.Uwb():
2202        result.uwb_config = copy.uwb.hardware_feature.uwb_config
2203
2204    _accumulate_fw_config(result.fw_config, copy.dgpu.hardware_feature.fw_config)
2205    if copy.dgpu.hardware_feature.dgpu_config != _HW_FEAT.Dgpu():
2206        result.dgpu_config = copy.dgpu.hardware_feature.dgpu_config
2207
2208    # Handle all possible fan hardware features attributes
2209    _accumulate_fw_config(result.fw_config, copy.fan.hardware_feature.fw_config)
2210    if copy.fan.hardware_feature.fan != _HW_FEAT.Fan():
2211        result.fan = copy.fan.hardware_feature.fan
2212
2213    if copy.ec.hardware_feature.embedded_controller != _HW_FEAT.EmbeddedController():
2214        result.embedded_controller = copy.ec.hardware_feature.embedded_controller
2215
2216    return result
2217
2218def _version_topology(topology):
2219    if type(topology) != "tuple":
2220        return struct(
2221            topology = topology,
2222            version = 0,
2223        )
2224    version = topology[1]
2225    if version < 0:
2226        fail("Invalid version: %d" % version)
2227    return struct(
2228        topology = topology[0],
2229        version = topology[1],
2230    )
2231
2232def _create_hardware_topology_bundle(
2233        sort_order = None,
2234        **hardware_topologies):
2235    """Creates a bundle of hardware topology values.
2236
2237    Parameters match those of hw_topo.create_hardware_topology. Each field may
2238    be a single topology value, a list of topologies values returned by
2239    create_versioned_topology(). Additionally, sort_order can be used to
2240    control iteration order.
2241
2242    In order to maintain existing config ID allocations, any additional
2243    topology values must be added with a greater version number than previous
2244    values. Modifying an existing topology (including from unset/None to
2245    non-None) is supported.
2246    """
2247    processed_topologies = []
2248    for topology_type, topologies in hardware_topologies.items():
2249        if not topologies:
2250            continue
2251        if type(topologies) != "list":
2252            topologies = [topologies]
2253        processed_topologies.append(struct(
2254            name = topology_type,
2255            topologies = [_version_topology(topology) for topology in topologies],
2256        ))
2257
2258    if sort_order == None:
2259        sort_order = []
2260
2261    order = sort_order + sorted([key for key in hardware_topologies.keys() if key not in sort_order])
2262    return sorted(processed_topologies, key = lambda item: order.index(item.name))
2263
2264def _create_versioned_topology(topology, version):
2265    return (topology, version)
2266
2267hw_topo = struct(
2268    create_design_features = _create_design_features,
2269    create_features = _create_features,
2270    create_screen = _create_screen,
2271    create_als_step = _create_als_step,
2272    create_kb_als_step = _create_kb_als_step,
2273    create_form_factor = _create_form_factor,
2274    create_audio = _create_audio,
2275    create_audio_card_config = _create_audio_card_config,
2276    override_audio = _override_audio,
2277    create_stylus = _create_stylus,
2278    create_keyboard = _create_keyboard,
2279    create_thermal = _create_thermal,
2280    create_camera = _create_camera,
2281    create_sensor = _create_sensor,
2282    create_legacy_proximity = _create_legacy_proximity,
2283    create_semtech_proximity = _create_semtech_proximity,
2284    create_activity_proximity = _create_activity_proximity,
2285    create_semtech_proximity_channel = _create_semtech_proximity_channel,
2286    create_proximity_location = _create_proximity_location,
2287    create_fingerprint = _create_fingerprint,
2288    create_fingerprint_diag = _create_fingerprint_diag,
2289    create_fingerprint_diag_detect_zone = _create_fingerprint_diag_detect_zone,
2290    create_fingerprint_diag_pixel_median = _create_fingerprint_diag_pixel_median,
2291    create_proximity_sensor = _create_proximity_sensor,
2292    create_daughter_board = _create_daughter_board,
2293    create_non_volatile_storage = _create_non_volatile_storage,
2294    create_wifi = _create_wifi,
2295    create_cellular_board = _create_cellular_board,
2296    create_sd_reader = _create_sd_reader,
2297    create_motherboard_usb = _create_motherboard_usb,
2298    create_usbc_port = _create_usbc_port,
2299    create_bluetooth = _create_bluetooth,
2300    create_barreljack = _create_barreljack,
2301    create_power_supply = _create_power_supply,
2302    create_hardware_topology = _create_hardware_topology,
2303    create_power_button = _create_power_button,
2304    create_volume_button = _create_volume_button,
2305    create_touch = _create_touch,
2306    create_microphone_mute_switch = _create_microphone_mute_switch,
2307    create_hdmi = _create_hdmi,
2308    create_hdmi_cec = _create_hdmi_cec,
2309    create_hps = _create_hps,
2310    create_dp_converter = _create_dp_converter,
2311    create_poe = _create_poe,
2312    create_battery = _create_battery,
2313    create_dgpu = _create_dgpu,
2314    create_uwb = _create_uwb,
2315    create_detachable_base = _create_detachable_base,
2316    create_soc = _create_soc,
2317    create_fan = _create_fan,
2318    convert_to_hw_features = _convert_to_hw_features,
2319    make_camera_device = _make_camera_device,
2320    make_cellular_dynamic_power_reduction_config = _make_cellular_dynamic_power_reduction_config,
2321    make_fw_config = _make_fw_config,
2322    ff = hw_feat.form_factor,
2323    amplifier = _AMPLIFIER,
2324    audio_codec = _AUDIO_CODEC,
2325    cellular = _CELLULAR,
2326    modem = _MODEM,
2327    dgpu = _DGPU,
2328    fp_loc = _FP_LOC,
2329    proximity_sensor_radio_type = _PS_RADIO_TYPE,
2330    storage = _STORAGE,
2331    kb_type = _KB_TYPE,
2332    kb_mcu_type = _KB_MCU_TYPE,
2333    kb_bottom_left_layout = _KB_BOTTOM_LEFT_LAYOUT,
2334    kb_bottom_right_layout = _KB_BOTTOM_RIGHT_LAYOUT,
2335    kb_numeric_pad_layout = _KB_NUMERIC_PAD_LAYOUT,
2336    stylus = _STYLUS,
2337    region = _REGION,
2338    edge = _EDGE,
2339    camera_flags = _CAMERA_FLAGS,
2340    present = _PRESENT,
2341    port_position = _PORT_POSITION,
2342    audio_config_structure = _AUDIO_CONFIG_STRUCTURE,
2343    recovery_input = _RECOVERY_INPUT,
2344    panel_type = _DISPLAY_PANEL_TYPE,
2345
2346    # embedded controller exports
2347    ec_type = _EC_TYPE,
2348    create_ec = _create_ec,
2349    EC_NONE = _EC_NONE,
2350    EC_CHROME = _EC_CHROME,
2351    EC_WILCO = _EC_WILCO,
2352
2353    # trusted platform module exports
2354    tpm_type = _TPM_TYPE,
2355    create_tpm = _create_tpm,
2356    TPM_THIRD_PARTY = _TPM_THIRD_PARTY,
2357    TPM_GSC_H1B = _TPM_GSC_H1B,
2358    TPM_GSC_H1D = _TPM_GSC_H1D,
2359
2360    # helper functions
2361    create_hardware_topology_bundle = _create_hardware_topology_bundle,
2362    create_versioned_topology = _create_versioned_topology,
2363    bool_to_present = _bool_to_present,
2364)
2365