github.com/nya3jp/tast@v0.0.0-20230601000426-85c8e4d83a9b/src/go.chromium.org/tast/core/testing/hwdep/hwdep.go (about)

     1  // Copyright 2023 The ChromiumOS Authors
     2  // Use of this source code is governed by a BSD-style license that can be
     3  // found in the LICENSE file.
     4  
     5  // Package hwdep provides the hardware dependency mechanism to select tests to run on
     6  // a DUT based on its hardware features and setup.
     7  package hwdep
     8  
     9  import (
    10  	"fmt"
    11  	"regexp"
    12  	"strings"
    13  
    14  	configpb "go.chromium.org/chromiumos/config/go/api"
    15  
    16  	"go.chromium.org/tast/core/errors"
    17  	"go.chromium.org/tast/core/internal/dep"
    18  	"go.chromium.org/tast/core/testing/cellularconst"
    19  	"go.chromium.org/tast/core/testing/wlan"
    20  
    21  	"go.chromium.org/tast/core/framework/protocol"
    22  )
    23  
    24  // These are form factor values that can be passed to FormFactor and SkipOnFormFactor.
    25  const (
    26  	FormFactorUnknown = configpb.HardwareFeatures_FormFactor_FORM_FACTOR_UNKNOWN
    27  	Clamshell         = configpb.HardwareFeatures_FormFactor_CLAMSHELL
    28  	Convertible       = configpb.HardwareFeatures_FormFactor_CONVERTIBLE
    29  	Detachable        = configpb.HardwareFeatures_FormFactor_DETACHABLE
    30  	Chromebase        = configpb.HardwareFeatures_FormFactor_CHROMEBASE
    31  	Chromebox         = configpb.HardwareFeatures_FormFactor_CHROMEBOX
    32  	Chromebit         = configpb.HardwareFeatures_FormFactor_CHROMEBIT
    33  	Chromeslate       = configpb.HardwareFeatures_FormFactor_CHROMESLATE
    34  )
    35  
    36  // Deps holds hardware dependencies all of which need to be satisfied to run a test.
    37  type Deps = dep.HardwareDeps
    38  
    39  // Condition represents one condition of hardware dependencies.
    40  type Condition = dep.HardwareCondition
    41  
    42  // D returns hardware dependencies representing the given Conditions.
    43  func D(conds ...Condition) Deps {
    44  	return dep.NewHardwareDeps(conds...)
    45  }
    46  
    47  // idRegexp is the pattern that the given model/platform ID names should match with.
    48  var idRegexp = regexp.MustCompile(`^[a-z0-9_-]+$`)
    49  
    50  func satisfied() (bool, string, error) {
    51  	return true, "", nil
    52  }
    53  
    54  func unsatisfied(reason string) (bool, string, error) {
    55  	return false, reason, nil
    56  }
    57  
    58  func withError(err error) (bool, string, error) {
    59  	return false, "", err
    60  }
    61  
    62  func withErrorStr(s string) (bool, string, error) {
    63  	return false, "", errors.New(s)
    64  }
    65  
    66  // modelListed returns whether the model represented by a protocol.DeprecatedDeviceConfig is listed
    67  // in the given list of names or not.
    68  func modelListed(dc *protocol.DeprecatedDeviceConfig, names ...string) (bool, error) {
    69  	if dc == nil || dc.Id == nil || dc.Id.Model == "" {
    70  		return false, errors.New("DeprecatedDeviceConfig does not have model ID")
    71  	}
    72  	m := dc.Id.Model
    73  	// Remove the suffix _signed since it is not a part of a model name.
    74  	modelID := strings.TrimSuffix(strings.ToLower(m), "_signed")
    75  	for _, name := range names {
    76  		if name == modelID {
    77  			return true, nil
    78  		}
    79  	}
    80  	return false, nil
    81  }
    82  
    83  // platformListed returns whether the platform represented by a protocol.HardwareFeatures
    84  // is listed in the given list of names or not.
    85  func platformListed(dc *protocol.DeprecatedDeviceConfig, names ...string) (bool, error) {
    86  	if dc == nil || dc.Id == nil {
    87  		return false, errors.New("DeprecatedDeviceConfig does not have platform ID")
    88  	}
    89  	p := dc.Id.Platform
    90  	platformID := strings.ToLower(p)
    91  	for _, name := range names {
    92  		if name == platformID {
    93  			return true, nil
    94  		}
    95  	}
    96  	return false, nil
    97  }
    98  
    99  // WLAN device IDs. Convenience wrappers.
   100  const (
   101  	Marvell88w8897SDIO         = wlan.Marvell88w8897SDIO
   102  	Marvell88w8997PCIE         = wlan.Marvell88w8997PCIE
   103  	QualcommAtherosQCA6174     = wlan.QualcommAtherosQCA6174
   104  	QualcommAtherosQCA6174SDIO = wlan.QualcommAtherosQCA6174SDIO
   105  	QualcommWCN3990            = wlan.QualcommWCN3990
   106  	QualcommWCN6750            = wlan.QualcommWCN6750
   107  	QualcommWCN6855            = wlan.QualcommWCN6855
   108  	Intel7260                  = wlan.Intel7260
   109  	Intel7265                  = wlan.Intel7265
   110  	Intel8265                  = wlan.Intel8265
   111  	Intel9000                  = wlan.Intel9000
   112  	Intel9260                  = wlan.Intel9260
   113  	Intel22260                 = wlan.Intel22260
   114  	Intel22560                 = wlan.Intel22560
   115  	IntelAX201                 = wlan.IntelAX201
   116  	IntelAX203                 = wlan.IntelAX203
   117  	IntelAX211                 = wlan.IntelAX211
   118  	BroadcomBCM4354SDIO        = wlan.BroadcomBCM4354SDIO
   119  	BroadcomBCM4356PCIE        = wlan.BroadcomBCM4356PCIE
   120  	BroadcomBCM4371PCIE        = wlan.BroadcomBCM4371PCIE
   121  	Realtek8822CPCIE           = wlan.Realtek8822CPCIE
   122  	Realtek8852APCIE           = wlan.Realtek8852APCIE
   123  	Realtek8852CPCIE           = wlan.Realtek8852CPCIE
   124  	MediaTekMT7921PCIE         = wlan.MediaTekMT7921PCIE
   125  	MediaTekMT7921SDIO         = wlan.MediaTekMT7921SDIO
   126  	MediaTekMT7922PCIE         = wlan.MediaTekMT7922PCIE
   127  )
   128  
   129  // wifiDeviceListed returns whether a WiFi device given in HardwareFeatures is listed in the given list of names or not.
   130  func wifiDeviceListed(hwf *protocol.HardwareFeatures, devices ...wlan.DeviceID) (bool, error) {
   131  	wifi := hwf.GetHardwareFeatures().GetWifi()
   132  	if wifi == nil {
   133  		return false, errors.New("Wifi data has not been passed from DUT")
   134  	}
   135  
   136  	chipset := int32(wifi.WifiChips[0])
   137  
   138  	for _, id := range devices {
   139  		if id == wlan.DeviceID(chipset) {
   140  			return true, nil
   141  		}
   142  	}
   143  	return false, nil
   144  }
   145  
   146  // Model returns a hardware dependency condition that is satisfied if the DUT's model ID is
   147  // one of the given names.
   148  // Practically, this is not recommended to be used in most cases. Please consider again
   149  // if this is the appropriate use, and whether there exists another option, such as
   150  // check whether DUT needs to have touchscreen, some specific SKU, internal display etc.
   151  //
   152  // Expected example use case is; there is a problem in some code where we do not have
   153  // control, such as a device specific driver, or hardware etc., and unfortunately
   154  // it unlikely be fixed for a while.
   155  // Another use case is; a test is stably running on most of models, but failing on some
   156  // specific models. By using Model() and SkipOnModel() combination, the test can be
   157  // promoted to critical on stably running models, while it is still informational
   158  // on other models. Note that, in this case, it is expected that an engineer is
   159  // assigned to stabilize/fix issues of the test on informational models.
   160  func Model(names ...string) Condition {
   161  	for _, n := range names {
   162  		if !idRegexp.MatchString(n) {
   163  			return Condition{Err: errors.Errorf("ModelId should match with %v: %q", idRegexp, n)}
   164  		}
   165  	}
   166  	return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
   167  		listed, err := modelListed(f.GetDeprecatedDeviceConfig(), names...)
   168  		if err != nil {
   169  			return withError(err)
   170  		}
   171  		if !listed {
   172  			return unsatisfied("ModelId did not match")
   173  		}
   174  		return satisfied()
   175  	}}
   176  }
   177  
   178  // SkipOnModel returns a hardware dependency condition that is satisfied
   179  // iff the DUT's model ID is none of the given names.
   180  // Please find the doc of Model(), too, for details about the expected usage.
   181  func SkipOnModel(names ...string) Condition {
   182  	for _, n := range names {
   183  		if !idRegexp.MatchString(n) {
   184  			return Condition{Err: errors.Errorf("ModelId should match with %v: %q", idRegexp, n)}
   185  		}
   186  	}
   187  	return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
   188  		listed, err := modelListed(f.GetDeprecatedDeviceConfig(), names...)
   189  		if err != nil {
   190  			// Failed to get the model name.
   191  			// Run the test to report error if it fails on this device.
   192  			return satisfied()
   193  		}
   194  		if listed {
   195  			return unsatisfied("ModelId matched with skip-on list")
   196  		}
   197  		return satisfied()
   198  	}}
   199  }
   200  
   201  // Platform returns a hardware dependency condition that is satisfied
   202  // iff the DUT's platform ID is one of the give names.
   203  // Please find the doc of Model(), too, for details about the expected usage.
   204  // Deprecated. Use Model() or "board:*" software dependency.
   205  func Platform(names ...string) Condition {
   206  	for _, n := range names {
   207  		if !idRegexp.MatchString(n) {
   208  			return Condition{Err: errors.Errorf("PlatformId should match with %v: %q", idRegexp, n)}
   209  		}
   210  	}
   211  	return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
   212  		listed, err := platformListed(f.GetDeprecatedDeviceConfig(), names...)
   213  		if err != nil {
   214  			return withError(err)
   215  		}
   216  		if !listed {
   217  			return unsatisfied("PlatformId did not match")
   218  		}
   219  		return satisfied()
   220  	}}
   221  }
   222  
   223  // SkipOnPlatform returns a hardware dependency condition that is satisfied
   224  // iff the DUT's platform ID is none of the give names.
   225  // Please find the doc of Model(), too, for details about the expected usage.
   226  // Deprecated. Use SkipOnModel() or "board:*" software dependency.
   227  func SkipOnPlatform(names ...string) Condition {
   228  	for _, n := range names {
   229  		if !idRegexp.MatchString(n) {
   230  			return Condition{Err: errors.Errorf("PlatformId should match with %v: %q", idRegexp, n)}
   231  		}
   232  	}
   233  	return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
   234  		listed, err := platformListed(f.GetDeprecatedDeviceConfig(), names...)
   235  		if err != nil {
   236  			return withError(err)
   237  		}
   238  		if listed {
   239  			return unsatisfied("PlatformId matched with skip-on list")
   240  		}
   241  		return satisfied()
   242  	}}
   243  }
   244  
   245  // WifiDevice returns a hardware dependency condition that is satisfied
   246  // iff the DUT's WiFi device is one of the given names.
   247  // Please find the doc of Model(), too, for details about the expected usage.
   248  func WifiDevice(devices ...wlan.DeviceID) Condition {
   249  	return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
   250  		listed, err := wifiDeviceListed(f, devices...)
   251  		if err != nil {
   252  			// Fail-open. Assumption is that if the device is not recognized, it doesn't match.
   253  			return unsatisfied(fmt.Sprintf("Unrecognized device. Assume not matching. Err %v", err))
   254  		}
   255  		if !listed {
   256  			return unsatisfied("WiFi device did not match")
   257  		}
   258  		return satisfied()
   259  	}}
   260  }
   261  
   262  // SkipOnWifiDevice returns a hardware dependency condition that is satisfied
   263  // iff the DUT's WiFi device is none of the given names.
   264  // Please find the doc of Model(), too, for details about the expected usage.
   265  func SkipOnWifiDevice(devices ...wlan.DeviceID) Condition {
   266  	return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
   267  		listed, err := wifiDeviceListed(f, devices...)
   268  		if err != nil {
   269  			// Failed to get the device id.
   270  			// Run the test to report error if it fails on this device.
   271  			return satisfied()
   272  
   273  		}
   274  		if listed {
   275  			return unsatisfied("WiFi device matched with skip-on list")
   276  		}
   277  		return satisfied()
   278  	}}
   279  }
   280  
   281  // TouchScreen returns a hardware dependency condition that is satisfied
   282  // iff the DUT has touchscreen.
   283  func TouchScreen() Condition {
   284  	return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
   285  		hf := f.GetHardwareFeatures()
   286  		if hf == nil {
   287  			return withErrorStr("DUT HardwareFeatures data is not given")
   288  		}
   289  		if hf.GetScreen().GetTouchSupport() == configpb.HardwareFeatures_PRESENT {
   290  			return satisfied()
   291  		}
   292  		return unsatisfied("DUT does not have touchscreen")
   293  	},
   294  	}
   295  }
   296  
   297  // NoTouchScreen returns a hardware dependency condition that is satisfied
   298  // if the DUT doesn't have a touchscreen.
   299  func NoTouchScreen() Condition {
   300  	return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
   301  		hf := f.GetHardwareFeatures()
   302  		if hf == nil {
   303  			return withErrorStr("DUT HardwareFeatures data is not given")
   304  		}
   305  		if status := hf.GetScreen().GetTouchSupport(); status == configpb.HardwareFeatures_NOT_PRESENT {
   306  			return satisfied()
   307  		}
   308  		return unsatisfied("DUT has a touchscreen")
   309  	},
   310  	}
   311  }
   312  
   313  // ChromeEC returns a hardware dependency condition that is satisfied
   314  // iff the DUT has a present EC of the "Chrome EC" type.
   315  func ChromeEC() Condition {
   316  	return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
   317  		hf := f.GetHardwareFeatures()
   318  		if hf == nil {
   319  			return withErrorStr("Did not find hardware features")
   320  		}
   321  		ecIsPresent := hf.GetEmbeddedController().GetPresent() == configpb.HardwareFeatures_PRESENT
   322  		ecIsChrome := hf.GetEmbeddedController().GetEcType() == configpb.HardwareFeatures_EmbeddedController_EC_CHROME
   323  		if ecIsPresent && ecIsChrome {
   324  			return satisfied()
   325  		}
   326  		return unsatisfied("DUT does not have chrome EC")
   327  	},
   328  	}
   329  }
   330  
   331  // ECFeatureTypecCmd returns a hardware dependency condition that is satisfied
   332  // iff the DUT has an EC which supports the EC_FEATURE_TYPEC_CMD feature flag.
   333  func ECFeatureTypecCmd() Condition {
   334  	return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
   335  		hf := f.GetHardwareFeatures()
   336  		if hf == nil {
   337  			return withErrorStr("Did not find hardware features")
   338  		}
   339  		// We only return unsatisfied if we know for sure that the EC doesn't support the feature flag.
   340  		// In cases where the result is UNKNOWN, we allow the test to continue and fail.
   341  		if hf.GetEmbeddedController().GetFeatureTypecCmd() == configpb.HardwareFeatures_NOT_PRESENT {
   342  			return unsatisfied("DUT EC does not support EC_FEATURE_TYPEC_CMD")
   343  		}
   344  		return satisfied()
   345  	},
   346  	}
   347  }
   348  
   349  // ECFeatureCBI returns a hardware dependency condition that
   350  // is satisfied iff the DUT has an EC which supports CBI.
   351  func ECFeatureCBI() Condition {
   352  	return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
   353  		hf := f.GetHardwareFeatures()
   354  		if hf == nil {
   355  			return withErrorStr("Did not find hardware features")
   356  		}
   357  		if status := hf.GetEmbeddedController().GetCbi(); status == configpb.HardwareFeatures_NOT_PRESENT {
   358  			return unsatisfied("DUT does not have cbi")
   359  		} else if status == configpb.HardwareFeatures_PRESENT_UNKNOWN {
   360  			return unsatisfied("Could not determine cbi presence")
   361  		}
   362  		return satisfied()
   363  	},
   364  	}
   365  }
   366  
   367  // ECFeatureDetachableBase returns a hardware dependency condition that is
   368  // satisfied iff the DUT has the detachable base attached.
   369  func ECFeatureDetachableBase() Condition {
   370  	return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
   371  		hf := f.GetHardwareFeatures()
   372  		if hf == nil {
   373  			return withErrorStr("Did not find hardware features")
   374  		}
   375  		status := hf.GetEmbeddedController().GetDetachableBase()
   376  		if status == configpb.HardwareFeatures_NOT_PRESENT {
   377  			return unsatisfied("Detachable base is not attached to DUT")
   378  		}
   379  		if status == configpb.HardwareFeatures_PRESENT_UNKNOWN {
   380  			return unsatisfied("Could not determine detachable base presence")
   381  		}
   382  		return satisfied()
   383  	},
   384  	}
   385  }
   386  
   387  // ECFeatureChargeControlV2 returns a hardware dependency condition that is
   388  // satisfied iff the DUT supports version 2 of the EC_CMD_CHARGE_CONTROL feature
   389  // (which adds battery sustain).
   390  func ECFeatureChargeControlV2() Condition {
   391  	return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
   392  		hf := f.GetHardwareFeatures()
   393  		if hf == nil {
   394  			return withErrorStr("Did not find hardware features")
   395  		}
   396  		if hf.GetEmbeddedController().GetFeatureChargeControlV2() == configpb.HardwareFeatures_NOT_PRESENT {
   397  			return unsatisfied("DUT EC does not support EC_CMD_CHARGE_CONTROL version 2")
   398  		}
   399  		return satisfied()
   400  	},
   401  	}
   402  }
   403  
   404  // Cellular returns a hardware dependency condition that
   405  // is satisfied iff the DUT has a cellular modem.
   406  func Cellular() Condition {
   407  	return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
   408  		hf := f.GetHardwareFeatures()
   409  		if hf == nil {
   410  			return withErrorStr("Did not find hardware features")
   411  		}
   412  		if status := hf.GetCellular().Present; status == configpb.HardwareFeatures_NOT_PRESENT {
   413  			return unsatisfied("DUT does not have a cellular modem")
   414  		} else if status == configpb.HardwareFeatures_PRESENT_UNKNOWN {
   415  			return unsatisfied("Could not determine if cellular model is present")
   416  		}
   417  		return satisfied()
   418  	},
   419  	}
   420  }
   421  
   422  // SkipOnCellularVariant returns a hardware dependency condition that is satisfied
   423  // iff the DUT's cellular variant is none of the given names.
   424  func SkipOnCellularVariant(names ...string) Condition {
   425  	for _, n := range names {
   426  		if !idRegexp.MatchString(n) {
   427  			return Condition{Err: errors.Errorf("Variant should match with %v: %q", idRegexp, n)}
   428  		}
   429  	}
   430  	return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
   431  		hf := f.GetHardwareFeatures()
   432  		if hf == nil {
   433  			return withErrorStr("Did not find hardware features")
   434  		}
   435  		if status := hf.GetCellular().Present; status == configpb.HardwareFeatures_NOT_PRESENT {
   436  			return unsatisfied("DUT does not have a cellular modem")
   437  		} else if status == configpb.HardwareFeatures_PRESENT_UNKNOWN {
   438  			return unsatisfied("Could not determine if cellular model is present")
   439  		}
   440  		variant := hf.GetCellular().GetModel()
   441  		for _, name := range names {
   442  			if name == variant {
   443  				return unsatisfied("Variant matched with skip-on list")
   444  			}
   445  		}
   446  		return satisfied()
   447  	}}
   448  }
   449  
   450  // CellularVariant returns a hardware dependency condition that is satisfied
   451  // iff the DUT's cellular variant is one of the given names.
   452  func CellularVariant(names ...string) Condition {
   453  	for _, n := range names {
   454  		if !idRegexp.MatchString(n) {
   455  			return Condition{Err: errors.Errorf("Variant should match with %v: %q", idRegexp, n)}
   456  		}
   457  	}
   458  	return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
   459  		hf := f.GetHardwareFeatures()
   460  		if hf == nil {
   461  			return withErrorStr("Did not find hardware features")
   462  		}
   463  		if status := hf.GetCellular().Present; status == configpb.HardwareFeatures_NOT_PRESENT {
   464  			return unsatisfied("DUT does not have a cellular modem")
   465  		} else if status == configpb.HardwareFeatures_PRESENT_UNKNOWN {
   466  			return unsatisfied("Could not determine if cellular model is present")
   467  		}
   468  		variant := hf.GetCellular().GetModel()
   469  		for _, name := range names {
   470  			if name == variant {
   471  				return satisfied()
   472  			}
   473  		}
   474  		return unsatisfied("Variant did not match")
   475  	}}
   476  }
   477  
   478  // CellularModemType returns a hardware dependency condition that is satisfied
   479  // iff the DUT's cellular modem type is one of the given types.
   480  func CellularModemType(modemTypes ...cellularconst.ModemType) Condition {
   481  	return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
   482  		hf := f.GetHardwareFeatures()
   483  		if hf == nil {
   484  			return withErrorStr("Did not find hardware features")
   485  		}
   486  		if status := hf.GetCellular().Present; status == configpb.HardwareFeatures_NOT_PRESENT {
   487  			return unsatisfied("DUT does not have a cellular modem")
   488  		} else if status == configpb.HardwareFeatures_PRESENT_UNKNOWN {
   489  			return unsatisfied("Could not determine if cellular model is present")
   490  		}
   491  		variant := hf.GetCellular().GetModel()
   492  		modemType, err := cellularconst.GetModemTypeFromVariant(variant)
   493  		if err != nil {
   494  			return withError(err)
   495  		}
   496  		for _, m := range modemTypes {
   497  			if m == modemType {
   498  				return satisfied()
   499  			}
   500  		}
   501  		return unsatisfied("Modem type did not match")
   502  	}}
   503  }
   504  
   505  // SkipOnCellularModemType returns a hardware dependency condition that is satisfied
   506  // iff the DUT's cellular modem type is none of the given types.
   507  func SkipOnCellularModemType(modemTypes ...cellularconst.ModemType) Condition {
   508  	return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
   509  		hf := f.GetHardwareFeatures()
   510  		if hf == nil {
   511  			return withErrorStr("Did not find hardware features")
   512  		}
   513  		if status := hf.GetCellular().Present; status == configpb.HardwareFeatures_NOT_PRESENT {
   514  			return unsatisfied("DUT does not have a cellular modem")
   515  		} else if status == configpb.HardwareFeatures_PRESENT_UNKNOWN {
   516  			return unsatisfied("Could not determine if cellular model is present")
   517  		}
   518  		variant := hf.GetCellular().GetModel()
   519  		modemType, err := cellularconst.GetModemTypeFromVariant(variant)
   520  		if err != nil {
   521  			return withError(err)
   522  		}
   523  		for _, m := range modemTypes {
   524  			if m == modemType {
   525  				return unsatisfied("Modem type matched with skip-on list")
   526  			}
   527  		}
   528  		return satisfied()
   529  	}}
   530  }
   531  
   532  // CellularSoftwareDynamicSar returns a hardware dependency condition that
   533  // is satisfied iff the DUT has enabled software dynamic sar.
   534  func CellularSoftwareDynamicSar() Condition {
   535  	return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
   536  		hf := f.GetHardwareFeatures()
   537  		if hf == nil {
   538  			return withErrorStr("Did not find hardware features")
   539  		}
   540  		if status := hf.GetCellular().GetDynamicPowerReductionConfig().GetModemManager(); status {
   541  			return satisfied()
   542  		}
   543  		return unsatisfied("DUT does not support cellular sw dynamic sar")
   544  	},
   545  	}
   546  }
   547  
   548  // NoCellular returns a hardware dependency condition that
   549  // is satisfied iff the DUT does not have a cellular modem.
   550  func NoCellular() Condition {
   551  	return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
   552  		hf := f.GetHardwareFeatures()
   553  		if hf == nil {
   554  			return withErrorStr("Did not find hardware features")
   555  		}
   556  		if status := hf.GetCellular().Present; status == configpb.HardwareFeatures_NOT_PRESENT {
   557  			return satisfied()
   558  		} else if status == configpb.HardwareFeatures_PRESENT_UNKNOWN {
   559  			return unsatisfied("Could not determine if cellular model is present")
   560  		}
   561  		return unsatisfied("DUT has a cellular modem")
   562  	},
   563  	}
   564  }
   565  
   566  // Bluetooth returns a hardware dependency condition that
   567  // is satisfied iff the DUT has a bluetooth adapter.
   568  func Bluetooth() Condition {
   569  	return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
   570  		if hf := f.GetHardwareFeatures(); hf == nil {
   571  			return withErrorStr("Did not find hardware features")
   572  		} else if status := hf.GetBluetooth().Present; status == configpb.HardwareFeatures_NOT_PRESENT {
   573  			return unsatisfied("DUT does not have a bluetooth adapter")
   574  		} else if status == configpb.HardwareFeatures_PRESENT_UNKNOWN {
   575  			return unsatisfied("Could not determine bluetooth adapter presence")
   576  		}
   577  		return satisfied()
   578  	},
   579  	}
   580  }
   581  
   582  // GSCUART returns a hardware dependency condition that is satisfied iff the DUT has a GSC and that GSC has a working UART.
   583  // TODO(b/224608005): Add a cros_config for this and use that instead.
   584  func GSCUART() Condition {
   585  	// There is no way to probe for this condition, and there should be no machines newer than 2017 without working UARTs.
   586  	return SkipOnModel(
   587  		"astronaut",
   588  		"blacktiplte",
   589  		"caroline",
   590  		"celes",
   591  		"electro",
   592  		"elm",
   593  		"eve",
   594  		"hana",
   595  		"kefka",
   596  		"lars",
   597  		"nasher",
   598  		"nocturne",
   599  		"relm",
   600  		"robo360",
   601  		"sand",
   602  		"sentry",
   603  		"snappy",
   604  	)
   605  }
   606  
   607  // GSCRWKeyIDProd returns a hardware dependency condition that
   608  // is satisfied iff the DUT does have a GSC RW image signed with prod key.
   609  func GSCRWKeyIDProd() Condition {
   610  	return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
   611  		hf := f.GetHardwareFeatures()
   612  		if hf == nil {
   613  			return withErrorStr("Did not find hardware features")
   614  		}
   615  		if status := hf.GetTrustedPlatformModule().GetProductionRwKeyId(); status == configpb.HardwareFeatures_PRESENT {
   616  			return satisfied()
   617  		} else if status == configpb.HardwareFeatures_PRESENT_UNKNOWN {
   618  			return unsatisfied("Could not determine if production RW key is used to sign GSC image")
   619  		}
   620  		return unsatisfied("DUT has a dev signed GSC image")
   621  	},
   622  	}
   623  }
   624  
   625  // HasNoTpm returns a hardware dependency condition that is satisfied iff the DUT
   626  // doesn't have an enabled TPM.
   627  func HasNoTpm() Condition {
   628  	return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
   629  		hf := f.GetHardwareFeatures()
   630  		if hf == nil {
   631  			return withErrorStr("Did not find hardware features")
   632  		}
   633  		if hf.GetTrustedPlatformModule().GetRuntimeTpmVersion() != configpb.HardwareFeatures_TrustedPlatformModule_TPM_VERSION_DISABLED {
   634  			return unsatisfied("DUT has an enabled TPM")
   635  		}
   636  		return satisfied()
   637  	},
   638  	}
   639  }
   640  
   641  // HasTpm returns a hardware dependency condition that is satisfied iff the DUT
   642  // does have an enabled TPM.
   643  func HasTpm() Condition {
   644  	return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
   645  		hf := f.GetHardwareFeatures()
   646  		if hf == nil {
   647  			return withErrorStr("Did not find hardware features")
   648  		}
   649  		if hf.GetTrustedPlatformModule().GetRuntimeTpmVersion() == configpb.HardwareFeatures_TrustedPlatformModule_TPM_VERSION_DISABLED {
   650  			return unsatisfied("DUT has no enabled TPM")
   651  		}
   652  		return satisfied()
   653  	},
   654  	}
   655  }
   656  
   657  // HasTpm1 returns a hardware dependency condition that is satisfied iff the DUT
   658  // does have an enabled TPM1.2.
   659  func HasTpm1() Condition {
   660  	return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
   661  		hf := f.GetHardwareFeatures()
   662  		if hf == nil {
   663  			return withErrorStr("Did not find hardware features")
   664  		}
   665  		if hf.GetTrustedPlatformModule().GetRuntimeTpmVersion() == configpb.HardwareFeatures_TrustedPlatformModule_TPM_VERSION_V1_2 {
   666  			return satisfied()
   667  		}
   668  		return unsatisfied("DUT has no enabled TPM1.2")
   669  	},
   670  	}
   671  }
   672  
   673  // HasTpm2 returns a hardware dependency condition that is satisfied iff the DUT
   674  // does have an enabled TPM2.0.
   675  func HasTpm2() Condition {
   676  	return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
   677  		hf := f.GetHardwareFeatures()
   678  		if hf == nil {
   679  			return withErrorStr("Did not find hardware features")
   680  		}
   681  		if hf.GetTrustedPlatformModule().GetRuntimeTpmVersion() == configpb.HardwareFeatures_TrustedPlatformModule_TPM_VERSION_V2 {
   682  			return satisfied()
   683  		}
   684  		return unsatisfied("DUT has no enabled TPM2.0")
   685  	},
   686  	}
   687  }
   688  
   689  // CPUNotNeedsCoreScheduling returns a hardware dependency condition that is satisfied iff the DUT's
   690  // CPU is does not need to use core scheduling to mitigate hardware vulnerabilities.
   691  func CPUNotNeedsCoreScheduling() Condition {
   692  	return cpuNeedsCoreScheduling(false)
   693  }
   694  
   695  // CPUNeedsCoreScheduling returns a hardware dependency condition that is satisfied iff the DUT's
   696  // CPU needs to use core scheduling to mitigate hardware vulnerabilities.
   697  func CPUNeedsCoreScheduling() Condition {
   698  	return cpuNeedsCoreScheduling(true)
   699  }
   700  
   701  // cpuNeedsCoreScheduling generates a Condition for CPUNeedsCoreScheduling() and its inverse,
   702  // CPUNotNeedsCoreScheduling(). A CPU needs core scheduling if it is vulnerable to either L1TF or
   703  // MDS hardware vulnerabilities.
   704  func cpuNeedsCoreScheduling(enabled bool) Condition {
   705  	needsCoreScheduling := func(hf *configpb.HardwareFeatures) (bool, string) {
   706  		for _, f := range hf.GetSoc().Vulnerabilities {
   707  			if f == configpb.Component_Soc_L1TF {
   708  				return true, "CPU is vulnerable to L1TF"
   709  			}
   710  			if f == configpb.Component_Soc_MDS {
   711  				return true, "CPU is vulnerable MDS"
   712  			}
   713  		}
   714  		return false, "CPU is not vulnerable to L1TF or MDS"
   715  	}
   716  	return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
   717  		hf := f.GetHardwareFeatures()
   718  		if hf == nil {
   719  			return withErrorStr("HardwareFeatures is not given")
   720  		}
   721  		needed, description := needsCoreScheduling(hf)
   722  		if needed == enabled {
   723  			return satisfied()
   724  		}
   725  		return unsatisfied(description)
   726  	},
   727  	}
   728  }
   729  
   730  // CPUSupportsSMT returns a hardware dependency condition that is satisfied iff the DUT supports
   731  // Symmetric Multi-Threading.
   732  func CPUSupportsSMT() Condition {
   733  	return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
   734  		hf := f.GetHardwareFeatures()
   735  		if hf == nil {
   736  			return withErrorStr("HardwareFeatures is not given")
   737  		}
   738  		for _, f := range hf.GetSoc().Features {
   739  			if f == configpb.Component_Soc_SMT {
   740  				return satisfied()
   741  			}
   742  		}
   743  		return unsatisfied("CPU does not have SMT support")
   744  	},
   745  	}
   746  }
   747  
   748  // CPUSupportsSHANI returns a hardware dependency condition that is satisfied iff the DUT supports
   749  // SHA-NI instruction extension.
   750  func CPUSupportsSHANI() Condition {
   751  	return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
   752  		hf := f.GetHardwareFeatures()
   753  		if hf == nil {
   754  			return withErrorStr("HardwareFeatures is not given")
   755  		}
   756  		for _, f := range hf.GetSoc().Features {
   757  			if f == configpb.Component_Soc_SHA_NI {
   758  				return satisfied()
   759  			}
   760  		}
   761  		return unsatisfied("CPU does not have SHA-NI support")
   762  	},
   763  	}
   764  }
   765  
   766  // Fingerprint returns a hardware dependency condition that is satisfied
   767  // iff the DUT has fingerprint sensor.
   768  func Fingerprint() Condition {
   769  	return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
   770  		hf := f.GetHardwareFeatures()
   771  		if hf == nil {
   772  			return withErrorStr("HardwareFeatures is not given")
   773  		}
   774  		if !hf.GetFingerprint().GetPresent() {
   775  			return unsatisfied("DUT does not have fingerprint sensor")
   776  		}
   777  		return satisfied()
   778  	},
   779  	}
   780  }
   781  
   782  // NoFingerprint returns a hardware dependency condition that is satisfied
   783  // if the DUT doesn't have fingerprint sensor.
   784  func NoFingerprint() Condition {
   785  	return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
   786  		hf := f.GetHardwareFeatures()
   787  		if hf == nil {
   788  			return withErrorStr("HardwareFeatures is not given")
   789  		}
   790  		if hf.GetFingerprint().GetPresent() {
   791  			return unsatisfied("DUT has fingerprint sensor")
   792  		}
   793  		return satisfied()
   794  	},
   795  	}
   796  }
   797  
   798  // ExternalDisplay returns a hardware dependency condition that is satisfied
   799  // iff the DUT has an external display
   800  func ExternalDisplay() Condition {
   801  	return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
   802  		hf := f.GetHardwareFeatures()
   803  		if hf == nil {
   804  			return withErrorStr("HardwareFeatures is not given")
   805  		}
   806  		display := hf.GetDisplay()
   807  		if display == nil {
   808  			return withErrorStr("Display is not given")
   809  		}
   810  		if display.GetType() == configpb.HardwareFeatures_Display_TYPE_EXTERNAL || display.GetType() == configpb.HardwareFeatures_Display_TYPE_INTERNAL_EXTERNAL {
   811  			return satisfied()
   812  		}
   813  		return unsatisfied("DUT does not have an external display")
   814  	},
   815  	}
   816  }
   817  
   818  // InternalDisplay returns a hardware dependency condition that is satisfied
   819  // iff the DUT has an internal display, e.g. Chromeboxes and Chromebits don't.
   820  func InternalDisplay() Condition {
   821  	return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
   822  		hf := f.GetHardwareFeatures()
   823  		if hf == nil {
   824  			return withErrorStr("HardwareFeatures is not given")
   825  		}
   826  		if hf.GetScreen().GetPanelProperties() != nil {
   827  			return satisfied()
   828  		}
   829  		return unsatisfied("DUT does not have an internal display")
   830  	},
   831  	}
   832  }
   833  
   834  // NoInternalDisplay returns a hardware dependency condition that is satisfied
   835  // iff the DUT does not have an internal display.
   836  func NoInternalDisplay() Condition {
   837  	return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
   838  		hf := f.GetHardwareFeatures()
   839  		if hf == nil {
   840  			return withErrorStr("HardwareFeatures is not given")
   841  		}
   842  		if hf.GetScreen().GetPanelProperties() != nil {
   843  			return unsatisfied("DUT has an internal display")
   844  		}
   845  		return satisfied()
   846  	},
   847  	}
   848  }
   849  
   850  // Keyboard returns a hardware dependency condition that is satisfied
   851  // iff the DUT has an keyboard, e.g. Chromeboxes and Chromebits don't.
   852  // Tablets might have a removable keyboard.
   853  func Keyboard() Condition {
   854  	return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
   855  		hf := f.GetHardwareFeatures()
   856  		if hf == nil {
   857  			return withErrorStr("HardwareFeatures is not given")
   858  		}
   859  		if hf.GetKeyboard() == nil ||
   860  			hf.GetKeyboard().KeyboardType == configpb.HardwareFeatures_Keyboard_KEYBOARD_TYPE_UNKNOWN ||
   861  			hf.GetKeyboard().KeyboardType == configpb.HardwareFeatures_Keyboard_NONE {
   862  			return unsatisfied("DUT does not have a keyboard")
   863  		}
   864  		return satisfied()
   865  	},
   866  	}
   867  }
   868  
   869  // KeyboardBacklight returns a hardware dependency condition that is satisfied
   870  // if the DUT supports keyboard backlight functionality.
   871  func KeyboardBacklight() Condition {
   872  	return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
   873  		hf := f.GetHardwareFeatures()
   874  		if hf == nil {
   875  			return withErrorStr("HardwareFeatures is not given")
   876  		}
   877  		if hf.GetKeyboard().GetBacklight() != configpb.HardwareFeatures_PRESENT {
   878  			return unsatisfied("DUT does not have keyboard backlight")
   879  		}
   880  		return satisfied()
   881  	},
   882  	}
   883  }
   884  
   885  // Touchpad returns a hardware dependency condition that is satisfied
   886  // iff the DUT has a touchpad.
   887  func Touchpad() Condition {
   888  	return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
   889  		hf := f.GetHardwareFeatures()
   890  		if hf == nil {
   891  			return withErrorStr("Did not find hardware features")
   892  		}
   893  		if hf.GetTouchpad().GetPresent() != configpb.HardwareFeatures_PRESENT {
   894  			return unsatisfied("DUT does not have a touchpad")
   895  		}
   896  		return satisfied()
   897  	},
   898  	}
   899  }
   900  
   901  // WifiWEP returns a hardware dependency condition that is satisfied
   902  // if the DUT's WiFi module supports WEP.
   903  // New generation of Qcom chipsets do not support WEP security protocols.
   904  func WifiWEP() Condition {
   905  	return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
   906  		platformCondition := SkipOnPlatform(
   907  			"herobrine")
   908  		if satisfied, reason, err := platformCondition.Satisfied(f); err != nil || !satisfied {
   909  			return satisfied, reason, err
   910  		}
   911  
   912  		modelCondition := SkipOnModel(
   913  			"nipperkin")
   914  		if satisfied, reason, err := modelCondition.Satisfied(f); err != nil || !satisfied {
   915  			return satisfied, reason, err
   916  		}
   917  		return satisfied()
   918  	},
   919  	}
   920  }
   921  
   922  // Wifi80211ax returns a hardware dependency condition that is satisfied
   923  // iff the DUT's WiFi module supports 802.11ax.
   924  func Wifi80211ax() Condition {
   925  	return WifiDevice(
   926  		QualcommWCN6750,
   927  		QualcommWCN6855,
   928  		Intel22260,
   929  		Intel22560,
   930  		IntelAX201,
   931  		IntelAX203,
   932  		IntelAX211,
   933  		Realtek8852APCIE,
   934  		Realtek8852CPCIE,
   935  		MediaTekMT7921PCIE,
   936  		MediaTekMT7921SDIO,
   937  		MediaTekMT7922PCIE,
   938  	)
   939  }
   940  
   941  // Wifi80211ax6E returns a hardware dependency condition that is satisfied
   942  // iff the DUT's WiFi module supports WiFi 6E.
   943  func Wifi80211ax6E() Condition {
   944  	// Note: this is currently an allowlist. We can move this to a blocklist if the number of platforms gets out of hand.
   945  	// TODO(crbug.com/1070299): replace this when we have hwdep for WiFi chips.
   946  	return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
   947  		modelCondition := Model(
   948  			"anahera",
   949  			"brya",
   950  			"felwinter",
   951  			"gimble",
   952  			"herobrine",
   953  			"kano",
   954  			"nipperkin",
   955  			"primus",
   956  			"redrix",
   957  			"taeko",
   958  			"taeland",
   959  			"vell",
   960  		)
   961  		if satisfied, reason, err := modelCondition.Satisfied(f); err != nil || !satisfied {
   962  			return satisfied, reason, err
   963  		}
   964  		return satisfied()
   965  	},
   966  	}
   967  }
   968  
   969  // WifiMACAddrRandomize returns a hardware dependency condition that is satisfied
   970  // iff the DUT supports WiFi MAC Address Randomization.
   971  func WifiMACAddrRandomize() Condition {
   972  	return SkipOnWifiDevice(
   973  		// mwifiex in 3.10 kernel does not support it.
   974  		Marvell88w8897SDIO, Marvell88w8997PCIE,
   975  		// Broadcom driver has only NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR
   976  		// but not NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR. We require randomization
   977  		// for all supported scan types.
   978  		BroadcomBCM4354SDIO,
   979  		// RTL8822CE reports only NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR.
   980  		Realtek8822CPCIE,
   981  	)
   982  }
   983  
   984  // WifiTDLS returns a hardware dependency condition that is satisfied
   985  // iff the DUT fully supports TDLS MGMT and OPER.
   986  func WifiTDLS() Condition {
   987  	return SkipOnWifiDevice(
   988  		// QCA 6174 does not support TDLS.
   989  		QualcommAtherosQCA6174, QualcommAtherosQCA6174SDIO,
   990  		// MTK7921/SDIO (Pico6) has support issues.
   991  		MediaTekMT7921SDIO,
   992  	)
   993  }
   994  
   995  // WifiFT returns a hardware dependency condition that is satisfied
   996  // iff the DUT supports Fast Transition roaming mode.
   997  func WifiFT() Condition {
   998  	return SkipOnWifiDevice(Marvell88w8897SDIO, Marvell88w8997PCIE)
   999  }
  1000  
  1001  // WifiNotMarvell returns a hardware dependency condition that is satisfied iff
  1002  // the DUT's not using a Marvell WiFi chip.
  1003  func WifiNotMarvell() Condition {
  1004  	// TODO(b/187699768): we don't yet have relevant fields in device.Config
  1005  	// about WiFi chip, so list the known platforms here for now.
  1006  	// TODO(b/187699664): remove "Elm" and "Hana" after unibuild migration
  1007  	// completed.
  1008  	return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
  1009  		platformCondition := SkipOnPlatform(
  1010  			"bob", "elm", "fievel", "hana", "kevin", "kevin64", "oak", "tiger",
  1011  		)
  1012  		if satisfied, reason, err := platformCondition.Satisfied(f); err != nil || !satisfied {
  1013  			return satisfied, reason, err
  1014  		}
  1015  		modelCondition := SkipOnModel(
  1016  			"bob",
  1017  			"kevin",
  1018  			"kevin64",
  1019  		)
  1020  		if satisfied, reason, err := modelCondition.Satisfied(f); err != nil || !satisfied {
  1021  			return satisfied, reason, err
  1022  		}
  1023  		return satisfied()
  1024  	},
  1025  	}
  1026  }
  1027  
  1028  // WifiNotMarvell8997 returns a hardware dependency condition that is satisfied if
  1029  // the DUT is not using Marvell 8997 chipsets.
  1030  func WifiNotMarvell8997() Condition {
  1031  	// TODO(b/187699768): replace this when we have hwdep for WiFi chips.
  1032  	return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
  1033  		platformCondition := SkipOnPlatform(
  1034  			"bob", "kevin", "kevin64",
  1035  		)
  1036  		if satisfied, reason, err := platformCondition.Satisfied(f); err != nil || !satisfied {
  1037  			return satisfied, reason, err
  1038  		}
  1039  		modelCondition := SkipOnModel(
  1040  			"bob",
  1041  			"kevin",
  1042  			"kevin64",
  1043  		)
  1044  		if satisfied, reason, err := modelCondition.Satisfied(f); err != nil || !satisfied {
  1045  			return satisfied, reason, err
  1046  		}
  1047  		return satisfied()
  1048  	},
  1049  	}
  1050  }
  1051  
  1052  // WifiMarvell returns a hardware dependency condition that is satisfied if the
  1053  // the DUT is using a Marvell WiFi chip.
  1054  func WifiMarvell() Condition {
  1055  	// TODO(b/187699768): replace this when we have hwdep for WiFi chips.
  1056  	// TODO(b/187699664): remove "Elm" and "Hana" after unibuild migration
  1057  	// completed.
  1058  	return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
  1059  		platformCondition := Platform(
  1060  			"bob", "elm", "fievel", "hana", "kevin", "kevin64", "oak", "tiger",
  1061  		)
  1062  		if platformSatisfied, _, err := platformCondition.Satisfied(f); err == nil && platformSatisfied {
  1063  			return satisfied()
  1064  		}
  1065  		// bob, kevin may be the platform name or model name,
  1066  		// return satisfied if its platform name or model name is bob/kevin
  1067  		modelCondition := Model(
  1068  			"bob", "kevin", "kevin64",
  1069  		)
  1070  		if modelSatisfied, _, err := modelCondition.Satisfied(f); err == nil && modelSatisfied {
  1071  			return satisfied()
  1072  		}
  1073  		return unsatisfied("DUT does not have a Marvell WiFi chip")
  1074  	},
  1075  	}
  1076  }
  1077  
  1078  // WifiIntel returns a hardware dependency condition that if satisfied, indicates
  1079  // that a device uses Intel WiFi. It is not guaranteed that the condition will be
  1080  // satisfied for all devices with Intel WiFi.
  1081  func WifiIntel() Condition {
  1082  	return WifiDevice(
  1083  		Intel7260,
  1084  		Intel7265,
  1085  		Intel8265,
  1086  		Intel9000,
  1087  		Intel9260,
  1088  		Intel22260,
  1089  		Intel22560,
  1090  		IntelAX201,
  1091  		IntelAX203,
  1092  		IntelAX211,
  1093  	)
  1094  }
  1095  
  1096  // WifiQualcomm returns a hardware dependency condition that if satisfied, indicates
  1097  // that a device uses Qualcomm WiFi.
  1098  func WifiQualcomm() Condition {
  1099  	return WifiDevice(
  1100  		QualcommAtherosQCA6174,
  1101  		QualcommAtherosQCA6174SDIO,
  1102  		QualcommWCN3990,
  1103  		QualcommWCN6750,
  1104  		QualcommWCN6855,
  1105  	)
  1106  }
  1107  
  1108  // WifiNotQualcomm returns a hardware dependency condition that if satisfied, indicates
  1109  // that a device doesn't use Qualcomm WiFi.
  1110  func WifiNotQualcomm() Condition {
  1111  	return SkipOnWifiDevice(
  1112  		QualcommAtherosQCA6174,
  1113  		QualcommAtherosQCA6174SDIO,
  1114  		QualcommWCN3990,
  1115  		QualcommWCN6750,
  1116  		QualcommWCN6855,
  1117  	)
  1118  }
  1119  
  1120  // WifiSAP returns a hardware dependency condition that if satisfied, indicates
  1121  // that a device supports SoftAP.
  1122  func WifiSAP() Condition {
  1123  	return SkipOnWifiDevice(
  1124  		MediaTekMT7921PCIE,
  1125  		MediaTekMT7921SDIO,
  1126  		QualcommWCN6855,
  1127  	)
  1128  }
  1129  
  1130  // WifiP2P returns a hardware dependency condition that if satisfied, indicates
  1131  // that a device supports P2P.
  1132  func WifiP2P() Condition {
  1133  	return SkipOnWifiDevice(
  1134  		MediaTekMT7921PCIE,
  1135  		MediaTekMT7921SDIO,
  1136  		Realtek8822CPCIE,
  1137  		QualcommWCN6855,
  1138  	)
  1139  }
  1140  
  1141  // These are the models which utilize SAR tables stored in VPD. See (b/204199379#comment10)
  1142  // for the methodology used to determine this list as well as a justification as
  1143  // to why it is stable.
  1144  var modelsWithVpdSarTables = []string{
  1145  	"akali360",
  1146  	"ampton",
  1147  	"arcada",
  1148  	"babytiger",
  1149  	"caroline",
  1150  	"eve",
  1151  	"leona",
  1152  	"nautilus",
  1153  	"nautiluslte",
  1154  	"pantheon",
  1155  	"shyvanna",
  1156  	"vayne",
  1157  }
  1158  
  1159  // WifiVpdSar returns a hardware dependency condition that if satisfied, indicates
  1160  // that a device supports VPD SAR tables, and the device actually has such tables
  1161  // in VPD.
  1162  func WifiVpdSar() Condition {
  1163  	return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
  1164  		modelCondition := Model(modelsWithVpdSarTables...)
  1165  		if satisfied, reason, err := modelCondition.Satisfied(f); err != nil || !satisfied {
  1166  			return satisfied, reason, err
  1167  		}
  1168  		wifi := f.GetHardwareFeatures().GetWifi()
  1169  		if wifi == nil {
  1170  			return unsatisfied("WiFi data has not been passed from DUT")
  1171  		}
  1172  		if !wifi.GetWifiVpdSar() {
  1173  			return unsatisfied("Device has no \"wifi_sar\" field in vpd")
  1174  		}
  1175  		return satisfied()
  1176  	},
  1177  	}
  1178  }
  1179  
  1180  // WifiNoVpdSar returns a hardware dependency condition that if satisfied, indicates
  1181  // that the device does not support VPD SAR tables.
  1182  func WifiNoVpdSar() Condition {
  1183  	return SkipOnModel(modelsWithVpdSarTables...)
  1184  }
  1185  
  1186  func hasBattery(f *protocol.HardwareFeatures) (bool, error) {
  1187  	dc := f.GetDeprecatedDeviceConfig()
  1188  	if dc == nil {
  1189  		return false, errors.New("DeprecatedDeviceConfig is not given")
  1190  	}
  1191  	return dc.GetPower() == protocol.DeprecatedDeviceConfig_POWER_SUPPLY_BATTERY, nil
  1192  }
  1193  
  1194  // Battery returns a hardware dependency condition that is satisfied iff the DUT
  1195  // has a battery, e.g. Chromeboxes and Chromebits don't.
  1196  func Battery() Condition {
  1197  	return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
  1198  		hasBattery, err := hasBattery(f)
  1199  		if err != nil {
  1200  			return withError(err)
  1201  		}
  1202  		if !hasBattery {
  1203  			return unsatisfied("DUT does not have a battery")
  1204  		}
  1205  		return satisfied()
  1206  	},
  1207  	}
  1208  }
  1209  
  1210  // NoBatteryBootSupported returns a hardware dependency condition that is satisfied iff the DUT
  1211  // supports booting without a battery.
  1212  func NoBatteryBootSupported() Condition {
  1213  	return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
  1214  		hasBattery, err := hasBattery(f)
  1215  		if err != nil {
  1216  			return withError(err)
  1217  		}
  1218  		if !hasBattery {
  1219  			return unsatisfied("DUT does not have a battery")
  1220  		}
  1221  
  1222  		hf := f.GetHardwareFeatures()
  1223  		if hf == nil {
  1224  			return withErrorStr("Did not find hardware features")
  1225  		}
  1226  		if !hf.GetBattery().GetNoBatteryBootSupported() {
  1227  			return unsatisfied("DUT does not support booting without a battery")
  1228  		}
  1229  
  1230  		return satisfied()
  1231  	},
  1232  	}
  1233  }
  1234  
  1235  // SupportsHardwareOverlays returns a hardware dependency condition that is satisfied if the SoC
  1236  // supports hardware overlays.
  1237  func SupportsHardwareOverlays() Condition {
  1238  	return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
  1239  		dc := f.GetDeprecatedDeviceConfig()
  1240  		if dc == nil {
  1241  			return withErrorStr("DeprecatedDeviceConfig is not given")
  1242  		}
  1243  
  1244  		if dc.GetSoc() == protocol.DeprecatedDeviceConfig_SOC_STONEY_RIDGE ||
  1245  			dc.GetSoc() == protocol.DeprecatedDeviceConfig_SOC_SC7180 {
  1246  			return unsatisfied("SoC does not support Hardware Overlays")
  1247  		}
  1248  		return satisfied()
  1249  	},
  1250  	}
  1251  }
  1252  
  1253  // platformHasNV12Overlays returns true if the the given platform is known
  1254  // to support NV12 hardware overlays.
  1255  func platformHasNV12Overlays(SocType protocol.DeprecatedDeviceConfig_SOC) bool {
  1256  	return SocType != protocol.DeprecatedDeviceConfig_SOC_HASWELL &&
  1257  		SocType != protocol.DeprecatedDeviceConfig_SOC_BAY_TRAIL &&
  1258  		SocType != protocol.DeprecatedDeviceConfig_SOC_BROADWELL &&
  1259  		SocType != protocol.DeprecatedDeviceConfig_SOC_BRASWELL &&
  1260  		SocType != protocol.DeprecatedDeviceConfig_SOC_SKYLAKE_U &&
  1261  		SocType != protocol.DeprecatedDeviceConfig_SOC_SKYLAKE_Y &&
  1262  		SocType != protocol.DeprecatedDeviceConfig_SOC_APOLLO_LAKE &&
  1263  		SocType != protocol.DeprecatedDeviceConfig_SOC_STONEY_RIDGE &&
  1264  		SocType != protocol.DeprecatedDeviceConfig_SOC_MT8173 &&
  1265  		SocType != protocol.DeprecatedDeviceConfig_SOC_MT8176 &&
  1266  		SocType != protocol.DeprecatedDeviceConfig_SOC_MT8183 &&
  1267  		SocType != protocol.DeprecatedDeviceConfig_SOC_MT8192 &&
  1268  		SocType != protocol.DeprecatedDeviceConfig_SOC_MT8195 &&
  1269  		SocType != protocol.DeprecatedDeviceConfig_SOC_MT8186 &&
  1270  		SocType != protocol.DeprecatedDeviceConfig_SOC_MT8188G &&
  1271  		SocType != protocol.DeprecatedDeviceConfig_SOC_SC7180 &&
  1272  		SocType != protocol.DeprecatedDeviceConfig_SOC_SC7280
  1273  }
  1274  
  1275  // SupportsNV12Overlays says true if the SoC supports NV12 hardware overlays,
  1276  // which are commonly used for video overlays. SoCs with Intel Gen 7.5 (Haswell,
  1277  // BayTrail) and Gen 8 GPUs (Broadwell, Braswell) for example, don't support
  1278  // those.
  1279  func SupportsNV12Overlays() Condition {
  1280  	return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
  1281  		dc := f.GetDeprecatedDeviceConfig()
  1282  		if dc == nil {
  1283  			return withErrorStr("DeprecatedDeviceConfig is not given")
  1284  		}
  1285  		if !platformHasNV12Overlays(dc.GetSoc()) {
  1286  			return unsatisfied("SoC does not support NV12 Overlays")
  1287  		}
  1288  		return satisfied()
  1289  	},
  1290  	}
  1291  }
  1292  
  1293  // SupportsVideoOverlays says true if the SoC supports some type of YUV
  1294  // hardware overlay. This includes NV12, I420, and YUY2.
  1295  func SupportsVideoOverlays() Condition {
  1296  	return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
  1297  		dc := f.GetDeprecatedDeviceConfig()
  1298  		if dc == nil {
  1299  			return withErrorStr("DeprecatedDeviceConfig is not given")
  1300  		}
  1301  
  1302  		var supportsYUY2Overlays = dc.GetSoc() == protocol.DeprecatedDeviceConfig_SOC_MT8183 ||
  1303  			dc.GetSoc() == protocol.DeprecatedDeviceConfig_SOC_MT8192 ||
  1304  			dc.GetSoc() == protocol.DeprecatedDeviceConfig_SOC_MT8195 ||
  1305  			dc.GetSoc() == protocol.DeprecatedDeviceConfig_SOC_MT8186 ||
  1306  			dc.GetSoc() == protocol.DeprecatedDeviceConfig_SOC_MT8188G
  1307  		if !platformHasNV12Overlays(dc.GetSoc()) && !supportsYUY2Overlays {
  1308  			return unsatisfied("SoC does not support Video Overlays")
  1309  		}
  1310  		return satisfied()
  1311  	},
  1312  	}
  1313  }
  1314  
  1315  // Since there are no way to get whether an EC supports force discharging on a device or not,
  1316  // list up the models known not to support force discharging here.
  1317  var modelsWithoutForceDischargeSupport = []string{
  1318  	"arcada",
  1319  	"celes",
  1320  	"drallion",
  1321  	"drallion360",
  1322  	"lulu",
  1323  	"sarien",
  1324  }
  1325  
  1326  // ForceDischarge returns a hardware dependency condition that is satisfied iff the DUT
  1327  // has a battery and it supports force discharge through `ectool chargecontrol`.
  1328  // The devices listed in modelsWithoutForceDischargeSupport do not satisfy this condition
  1329  // even though they have a battery since they does not support force discharge via ectool.
  1330  // This is a complementary condition of NoForceDischarge.
  1331  func ForceDischarge() Condition {
  1332  	return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
  1333  		hasBattery, err := hasBattery(f)
  1334  		if err != nil {
  1335  			return withError(err)
  1336  		}
  1337  		if !hasBattery {
  1338  			return unsatisfied("DUT does not have a battery")
  1339  		}
  1340  		doesNotSupportForceDischarge, err := modelListed(f.GetDeprecatedDeviceConfig(), modelsWithoutForceDischargeSupport...)
  1341  		if err != nil {
  1342  			return withError(err)
  1343  		}
  1344  		if doesNotSupportForceDischarge {
  1345  			return unsatisfied("DUT has a battery but does not support force discharge")
  1346  		}
  1347  		return satisfied()
  1348  	}}
  1349  }
  1350  
  1351  // NoForceDischarge is a complementary condition of ForceDischarge.
  1352  func NoForceDischarge() Condition {
  1353  	return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
  1354  		doesNotSupportForceDischarge, err := modelListed(f.GetDeprecatedDeviceConfig(), modelsWithoutForceDischargeSupport...)
  1355  		if err != nil {
  1356  			return withError(err)
  1357  		}
  1358  		if doesNotSupportForceDischarge {
  1359  			// Devices listed in modelsWithoutForceDischargeSupport
  1360  			// are known to always satisfy this condition
  1361  			return satisfied()
  1362  		}
  1363  		hasBattery, err := hasBattery(f)
  1364  		if err != nil {
  1365  			return withError(err)
  1366  		}
  1367  		if hasBattery {
  1368  			return unsatisfied("DUT supports force discharge")
  1369  		}
  1370  		return satisfied()
  1371  	}}
  1372  }
  1373  
  1374  // X86 returns a hardware dependency condition matching x86 ABI compatible platform.
  1375  func X86() Condition {
  1376  	return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
  1377  		dc := f.GetDeprecatedDeviceConfig()
  1378  		if dc == nil {
  1379  			return withErrorStr("DeprecatedDeviceConfig is not given")
  1380  		}
  1381  		if dc.GetCpu() == protocol.DeprecatedDeviceConfig_X86 || dc.GetCpu() == protocol.DeprecatedDeviceConfig_X86_64 {
  1382  			return satisfied()
  1383  		}
  1384  		return unsatisfied("DUT's CPU is not x86 compatible")
  1385  	}}
  1386  }
  1387  
  1388  // NoX86 returns a hardware dependency condition matching non-x86 ABI compatible platform.
  1389  func NoX86() Condition {
  1390  	return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
  1391  		dc := f.GetDeprecatedDeviceConfig()
  1392  		if dc == nil {
  1393  			return withErrorStr("DeprecatedDeviceConfig is not given")
  1394  		}
  1395  		if dc.GetCpu() != protocol.DeprecatedDeviceConfig_X86 && dc.GetCpu() != protocol.DeprecatedDeviceConfig_X86_64 {
  1396  			return satisfied()
  1397  		}
  1398  		return unsatisfied("DUT's CPU is x86 compatible")
  1399  	}}
  1400  }
  1401  
  1402  // Emmc returns a hardware dependency condition if the device has an eMMC
  1403  // storage device.
  1404  func Emmc() Condition {
  1405  	return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
  1406  		hf := f.GetHardwareFeatures()
  1407  		if hf == nil {
  1408  			return withErrorStr("Did not find hardware features")
  1409  		}
  1410  		if hf.GetStorage().GetStorageType() == configpb.Component_Storage_EMMC {
  1411  			return satisfied()
  1412  		}
  1413  		return unsatisfied("DUT does not have an eMMC storage device")
  1414  	}}
  1415  }
  1416  
  1417  // Nvme returns a hardware dependency condition if the device has an NVMe
  1418  // storage device.
  1419  func Nvme() Condition {
  1420  	return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
  1421  		hf := f.GetHardwareFeatures()
  1422  		if hf == nil {
  1423  			return withErrorStr("Did not find hardware features")
  1424  		}
  1425  		if hf.GetStorage().GetStorageType() == configpb.Component_Storage_NVME {
  1426  			return satisfied()
  1427  		}
  1428  		return unsatisfied("DUT does not have an NVMe storage device")
  1429  	}}
  1430  }
  1431  
  1432  // NvmeSelfTest returns a dependency condition if the device has an NVMe storage device which supported NVMe self-test.
  1433  func NvmeSelfTest() Condition {
  1434  	return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
  1435  		dc := f.GetDeprecatedDeviceConfig()
  1436  		if dc == nil {
  1437  			return withErrorStr("DeprecatedDeviceConfig is not given")
  1438  		}
  1439  		if dc.HasNvmeSelfTest {
  1440  			return satisfied()
  1441  		}
  1442  		return unsatisfied("DUT does not have an NVMe storage device which supports self-test")
  1443  	}}
  1444  }
  1445  
  1446  // Ufs returns a hardware dependency condition if the device has a UFS storage
  1447  // device.
  1448  func Ufs() Condition {
  1449  	return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
  1450  		hf := f.GetHardwareFeatures()
  1451  		if hf == nil {
  1452  			return withErrorStr("Did not find hardware features")
  1453  		}
  1454  		if hf.GetStorage().GetStorageType() == configpb.Component_Storage_UFS {
  1455  			return satisfied()
  1456  		}
  1457  		return unsatisfied("DUT does not have a UFS storage device")
  1458  	}}
  1459  }
  1460  
  1461  // MinStorage returns a hardware dependency condition requiring the minimum size of the storage in gigabytes.
  1462  func MinStorage(reqGigabytes int) Condition {
  1463  	return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
  1464  		hf := f.GetHardwareFeatures()
  1465  		if hf == nil {
  1466  			return withErrorStr("Did not find hardware features")
  1467  		}
  1468  		if hf.GetStorage() == nil {
  1469  			return withErrorStr("Features.Storage was nil")
  1470  		}
  1471  		s := hf.GetStorage().GetSizeGb()
  1472  		if s < uint32(reqGigabytes) {
  1473  			return unsatisfied(fmt.Sprintf("The total storage size is smaller than required; got %dGB, need %dGB", s, reqGigabytes))
  1474  		}
  1475  		return satisfied()
  1476  	}}
  1477  }
  1478  
  1479  // MinMemory returns a hardware dependency condition requiring the minimum size of the memory in megabytes.
  1480  func MinMemory(reqMegabytes int) Condition {
  1481  	return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
  1482  		hf := f.GetHardwareFeatures()
  1483  		if hf == nil {
  1484  			return withErrorStr("Did not find hardware features")
  1485  		}
  1486  		if hf.GetMemory() == nil {
  1487  			return withErrorStr("Features.Memory was nil")
  1488  		}
  1489  		if hf.GetMemory().GetProfile() == nil {
  1490  			return withErrorStr("Features.Memory.Profile was nil")
  1491  		}
  1492  		s := hf.GetMemory().GetProfile().GetSizeMegabytes()
  1493  		if s < int32(reqMegabytes) {
  1494  			return unsatisfied(fmt.Sprintf("The total memory size is smaller than required; got %dMB, need %dMB", s, reqMegabytes))
  1495  		}
  1496  		return satisfied()
  1497  	}}
  1498  }
  1499  
  1500  // MaxMemory returns a hardware dependency condition requiring no more than the
  1501  // maximum size of the memory in megabytes.
  1502  func MaxMemory(reqMegabytes int) Condition {
  1503  	return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
  1504  		hf := f.GetHardwareFeatures()
  1505  		if hf == nil {
  1506  			return withErrorStr("Did not find hardware features")
  1507  		}
  1508  		if hf.GetMemory() == nil {
  1509  			return withErrorStr("Features.Memory was nil")
  1510  		}
  1511  		if hf.GetMemory().GetProfile() == nil {
  1512  			return withErrorStr("Features.Memory.Profile was nil")
  1513  		}
  1514  		s := hf.GetMemory().GetProfile().GetSizeMegabytes()
  1515  		if s > int32(reqMegabytes) {
  1516  			return unsatisfied(fmt.Sprintf("The total memory size is larger than required; got %dMB, need <= %dMB", s, reqMegabytes))
  1517  		}
  1518  		return satisfied()
  1519  	}}
  1520  }
  1521  
  1522  // Speaker returns a hardware dependency condition that is satisfied iff the DUT has a speaker.
  1523  func Speaker() Condition {
  1524  	return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
  1525  		hf := f.GetHardwareFeatures()
  1526  		if hf == nil {
  1527  			return withErrorStr("Did not find hardware features")
  1528  		}
  1529  		if hf.GetAudio().GetSpeakerAmplifier() != nil {
  1530  			return satisfied()
  1531  		}
  1532  		return unsatisfied("DUT does not have speaker")
  1533  	},
  1534  	}
  1535  }
  1536  
  1537  // Microphone returns a hardware dependency condition that is satisfied iff the DUT has a microphone.
  1538  func Microphone() Condition {
  1539  	return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
  1540  		hf := f.GetHardwareFeatures()
  1541  		if hf == nil {
  1542  			return withErrorStr("Did not find hardware features")
  1543  		}
  1544  		if hf.GetAudio().GetLidMicrophone().GetValue() > 0 || hf.GetAudio().GetBaseMicrophone().GetValue() > 0 {
  1545  			return satisfied()
  1546  		}
  1547  		return unsatisfied("DUT does not have microphone")
  1548  	},
  1549  	}
  1550  }
  1551  
  1552  // PrivacyScreen returns a hardware dependency condition that is satisfied iff the DUT has a privacy screen.
  1553  func PrivacyScreen() Condition {
  1554  	return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
  1555  		hf := f.GetHardwareFeatures()
  1556  		if hf == nil {
  1557  			return withErrorStr("Did not find hardware features")
  1558  		}
  1559  		if hf.GetPrivacyScreen().GetPresent() != configpb.HardwareFeatures_PRESENT {
  1560  			return unsatisfied("DUT does not have privacy screen")
  1561  		}
  1562  		return satisfied()
  1563  	},
  1564  	}
  1565  }
  1566  
  1567  // NoPrivacyScreen returns a hardware dependency condition that is satisfied if the DUT
  1568  // does not have a privacy screen.
  1569  func NoPrivacyScreen() Condition {
  1570  	return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
  1571  		hf := f.GetHardwareFeatures()
  1572  		if hf == nil {
  1573  			return withErrorStr("Did not find hardware features")
  1574  		}
  1575  		if status := hf.GetPrivacyScreen().GetPresent(); status != configpb.HardwareFeatures_NOT_PRESENT {
  1576  			return satisfied()
  1577  		} else if status == configpb.HardwareFeatures_PRESENT_UNKNOWN {
  1578  			return unsatisfied("Could not determine if a privacy screen is present")
  1579  		}
  1580  		return unsatisfied("DUT has a privacy screen")
  1581  	},
  1582  	}
  1583  }
  1584  
  1585  var smartAmps = []string{
  1586  	configpb.HardwareFeatures_Audio_MAX98373.String(),
  1587  	configpb.HardwareFeatures_Audio_MAX98390.String(),
  1588  	configpb.HardwareFeatures_Audio_ALC1011.String(),
  1589  	configpb.HardwareFeatures_Audio_CS35L41.String(),
  1590  }
  1591  
  1592  // SmartAmp returns a hardware dependency condition that is satisfied iff the DUT
  1593  // has smart amplifier.
  1594  func SmartAmp() Condition {
  1595  	return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
  1596  		hf := f.GetHardwareFeatures()
  1597  		if hf == nil {
  1598  			return withErrorStr("Did not find hardware features")
  1599  		}
  1600  		if hf.GetAudio().GetSpeakerAmplifier() != nil {
  1601  			for _, amp := range smartAmps {
  1602  				if amp == hf.GetAudio().GetSpeakerAmplifier().GetName() {
  1603  					return satisfied()
  1604  				}
  1605  			}
  1606  		}
  1607  		return unsatisfied("DUT does not has smart amp :" + hf.GetAudio().GetSpeakerAmplifier().GetName())
  1608  	}}
  1609  }
  1610  
  1611  // SmartAmpBootTimeCalibration returns a hardware dependency condition that is satisfied iff
  1612  // the DUT enables boot time calibration for smart amplifier.
  1613  func SmartAmpBootTimeCalibration() Condition {
  1614  	return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
  1615  		hf := f.GetHardwareFeatures()
  1616  		if hf == nil {
  1617  			return withErrorStr("Did not find hardware features")
  1618  		}
  1619  		if hf.GetAudio().GetSpeakerAmplifier() != nil {
  1620  			for _, feature := range hf.GetAudio().GetSpeakerAmplifier().GetFeatures() {
  1621  				if feature == configpb.Component_Amplifier_BOOT_TIME_CALIBRATION {
  1622  					return satisfied()
  1623  				}
  1624  			}
  1625  		}
  1626  		return unsatisfied("DUT does not enable smart amp boot time calibration")
  1627  	}}
  1628  }
  1629  
  1630  // formFactorListed returns whether the form factor represented by a configpb.HardwareFeatures
  1631  // is listed in the given list of form factor values.
  1632  func formFactorListed(hf *configpb.HardwareFeatures, ffList ...configpb.HardwareFeatures_FormFactor_FormFactorType) bool {
  1633  	for _, ffValue := range ffList {
  1634  		if hf.GetFormFactor().FormFactor == ffValue {
  1635  			return true
  1636  		}
  1637  	}
  1638  	return false
  1639  }
  1640  
  1641  // FormFactor returns a hardware dependency condition that is satisfied
  1642  // iff the DUT's form factor is one of the given values.
  1643  func FormFactor(ffList ...configpb.HardwareFeatures_FormFactor_FormFactorType) Condition {
  1644  	return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
  1645  		hf := f.GetHardwareFeatures()
  1646  		if hf == nil {
  1647  			return withErrorStr("HardwareFeatures is not given")
  1648  		}
  1649  		listed := formFactorListed(hf, ffList...)
  1650  		if !listed {
  1651  			return unsatisfied("Form factor did not match")
  1652  		}
  1653  		return satisfied()
  1654  	}}
  1655  }
  1656  
  1657  // SkipOnFormFactor returns a hardware dependency condition that is satisfied
  1658  // iff the DUT's form factor is none of the give values.
  1659  func SkipOnFormFactor(ffList ...configpb.HardwareFeatures_FormFactor_FormFactorType) Condition {
  1660  	return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
  1661  		hf := f.GetHardwareFeatures()
  1662  		if hf == nil {
  1663  			return withErrorStr("HardwareFeatures is not given")
  1664  		}
  1665  		listed := formFactorListed(hf, ffList...)
  1666  		if listed {
  1667  			return unsatisfied("Form factor matched to SkipOn list")
  1668  		}
  1669  		return satisfied()
  1670  	}}
  1671  }
  1672  
  1673  // socTypeIsV4l2Stateful returns true when stateful API is supported on the given |SocType|
  1674  // or returns false when stateless API is supported.
  1675  func socTypeIsV4l2Stateful(SocType protocol.DeprecatedDeviceConfig_SOC) bool {
  1676  	switch SocType {
  1677  	case protocol.DeprecatedDeviceConfig_SOC_MT8173,
  1678  		protocol.DeprecatedDeviceConfig_SOC_SC7180,
  1679  		protocol.DeprecatedDeviceConfig_SOC_SC7280:
  1680  		return true
  1681  	case protocol.DeprecatedDeviceConfig_SOC_MT8183,
  1682  		protocol.DeprecatedDeviceConfig_SOC_MT8192,
  1683  		protocol.DeprecatedDeviceConfig_SOC_MT8195,
  1684  		protocol.DeprecatedDeviceConfig_SOC_MT8186,
  1685  		protocol.DeprecatedDeviceConfig_SOC_MT8188G,
  1686  		protocol.DeprecatedDeviceConfig_SOC_RK3399:
  1687  		return false
  1688  	// TODO(stevecho): stateful is more common for now, but we can change this in the future
  1689  	default:
  1690  		return true
  1691  	}
  1692  }
  1693  
  1694  // SupportsV4L2StatefulVideoDecoding says true if the SoC supports the V4L2
  1695  // stateful video decoding kernel API. Examples of this are MTK8173 and
  1696  // Qualcomm devices (7180, etc). In general, we prefer to use stateless
  1697  // decoding APIs, so listing them individually makes sense.
  1698  func SupportsV4L2StatefulVideoDecoding() Condition {
  1699  	return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
  1700  		dc := f.GetDeprecatedDeviceConfig()
  1701  		if dc == nil {
  1702  			return withErrorStr("DeprecatedDeviceConfig is not given")
  1703  		}
  1704  		if dc.GetCpu() == protocol.DeprecatedDeviceConfig_X86 || dc.GetCpu() == protocol.DeprecatedDeviceConfig_X86_64 {
  1705  			return unsatisfied("DUT's CPU is x86 compatible, which doesn't support V4L2")
  1706  		}
  1707  		if dc.GetSoc() == protocol.DeprecatedDeviceConfig_SOC_MT8173 {
  1708  			return unsatisfied("MT8173 devices only support MT21C output (b/230654454).")
  1709  		}
  1710  		if socTypeIsV4l2Stateful(dc.GetSoc()) {
  1711  			return satisfied()
  1712  		}
  1713  		return unsatisfied("SoC does not support V4L2 Stateful HW video decoding")
  1714  	}}
  1715  }
  1716  
  1717  // SupportsV4L2StatelessVideoDecoding says true if the SoC supports the V4L2
  1718  // stateless video decoding kernel API. Examples of this are MTK8192 (Asurada),
  1719  // MTK8195 (Cherry), MTK8186 (Corsola), and RK3399 (scarlet/kevin/bob).
  1720  func SupportsV4L2StatelessVideoDecoding() Condition {
  1721  	return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
  1722  		dc := f.GetDeprecatedDeviceConfig()
  1723  		if dc == nil {
  1724  			return withErrorStr("DeprecatedDeviceConfig is not given")
  1725  		}
  1726  		if dc.GetCpu() == protocol.DeprecatedDeviceConfig_X86 || dc.GetCpu() == protocol.DeprecatedDeviceConfig_X86_64 {
  1727  			return unsatisfied("DUT's CPU is x86 compatible, which doesn't support V4L2")
  1728  		}
  1729  		if !socTypeIsV4l2Stateful(dc.GetSoc()) {
  1730  			return satisfied()
  1731  		}
  1732  		return unsatisfied("SoC does not support V4L2 Stateless HW video decoding")
  1733  	}}
  1734  }
  1735  
  1736  // SupportsHEVCVideoDecodingInChrome says true if the device supports HEVC video
  1737  // decoding in Chrome. Note that this might be different from support at the
  1738  // platform (i.e. drivers, kernel, hardware) level.
  1739  // This function represents a policy: Tast tests using this should still make
  1740  // use of SoftwareDeps "caps.HWDecodeHEVC" (or "caps.HWDecodeHEVC10BPP").
  1741  func SupportsHEVCVideoDecodingInChrome() Condition {
  1742  	return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
  1743  		// Disabled on any device where the config is explicitly disabled.
  1744  		if f.GetHardwareFeatures().GetSoc().GetHevcSupport() == configpb.HardwareFeatures_NOT_PRESENT {
  1745  			return unsatisfied("Chrome has HEVC disabled on this device")
  1746  		}
  1747  		// Enabled on any device where the config is explicitly enabled.
  1748  		if f.GetHardwareFeatures().GetSoc().GetHevcSupport() == configpb.HardwareFeatures_PRESENT {
  1749  			return satisfied()
  1750  		}
  1751  		// ARM embedders don't support it.
  1752  		if satisfied, _, err := SkipCPUSocFamily([]string{"mediatek", "rockchip", "qualcomm"}).Satisfied(f); err != nil || !satisfied {
  1753  			return unsatisfied("Chrome does not support HEVC video decoding on this SoC")
  1754  		}
  1755  		// AMD Zork (Picasso) and before also don't.
  1756  		if satisfied, _, err := SkipGPUFamily([]string{"picasso", "stoney"}).Satisfied(f); err != nil || !satisfied {
  1757  			return unsatisfied("Chrome does not support HEVC video decoding on this SoC")
  1758  		}
  1759  		// Any Intel TGL, ADL-P do support it.
  1760  		if supported, _, err := GPUFamily([]string{"tigerlake", "alderlake"}).Satisfied(f); err == nil && supported {
  1761  			return satisfied()
  1762  		}
  1763  		return unsatisfied("Chrome does not support HEVC video decoding on this SoC")
  1764  	}}
  1765  }
  1766  
  1767  // Lid returns a hardware dependency condition that is satisfied iff the DUT's form factor has a lid.
  1768  func Lid() Condition {
  1769  	return FormFactor(Clamshell, Convertible, Detachable)
  1770  }
  1771  
  1772  // InternalKeyboard returns a hardware dependency condition that is satisfied iff the DUT's form factor has a fixed undetachable keyboard.
  1773  func InternalKeyboard() Condition {
  1774  	return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
  1775  		hf := f.GetHardwareFeatures()
  1776  		if hf == nil {
  1777  			return withErrorStr("HardwareFeatures is not given")
  1778  		}
  1779  		if hf.GetKeyboard() == nil ||
  1780  			hf.GetKeyboard().KeyboardType != configpb.HardwareFeatures_Keyboard_INTERNAL {
  1781  			return unsatisfied("DUT does not have a fixed keyboard")
  1782  		}
  1783  		return satisfied()
  1784  	},
  1785  	}
  1786  }
  1787  
  1788  // DisplayPortConverter is satisfied if a DP converter with one of the given names
  1789  // is present.
  1790  func DisplayPortConverter(names ...string) Condition {
  1791  	return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
  1792  		hf := f.GetHardwareFeatures()
  1793  		if hf == nil {
  1794  			return withErrorStr("HardwareFeatures is not given")
  1795  		}
  1796  
  1797  		for _, name := range names {
  1798  			for _, conv := range hf.GetDpConverter().GetConverters() {
  1799  				if conv.GetName() == name {
  1800  					return satisfied()
  1801  				}
  1802  			}
  1803  		}
  1804  		return unsatisfied("DP converter did not match")
  1805  	}}
  1806  }
  1807  
  1808  // Vboot2 is satisfied iff crossystem param 'fw_vboot2' indicates that DUT uses vboot2.
  1809  func Vboot2() Condition {
  1810  	return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
  1811  		dc := f.GetDeprecatedDeviceConfig()
  1812  		if dc == nil {
  1813  			return withErrorStr("DeprecatedDeviceConfig is not given")
  1814  		}
  1815  		if dc.HasVboot2 {
  1816  			return satisfied()
  1817  		}
  1818  		return unsatisfied("DUT is not a vboot2 device")
  1819  	}}
  1820  }
  1821  
  1822  // SupportsVP9KSVCHWDecoding is satisfied if the SoC supports VP9 k-SVC
  1823  // hardware decoding. They are x86 devices that are capable of VP9 hardware
  1824  // decoding and Qualcomm7180/7280.
  1825  // VP9 k-SVC is a SVC stream in which a frame only on keyframe can refer frames
  1826  // in a different spatial layer. See https://www.w3.org/TR/webrtc-svc/#dependencydiagrams* for detail.
  1827  func SupportsVP9KSVCHWDecoding() Condition {
  1828  	return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
  1829  		dc := f.GetDeprecatedDeviceConfig()
  1830  		if dc == nil {
  1831  			return withErrorStr("DeprecatedDeviceConfig is not given")
  1832  		}
  1833  
  1834  		if dc.GetCpu() == protocol.DeprecatedDeviceConfig_X86_64 {
  1835  			return satisfied()
  1836  		}
  1837  
  1838  		if dc.GetSoc() == protocol.DeprecatedDeviceConfig_SOC_SC7180 ||
  1839  			dc.GetSoc() == protocol.DeprecatedDeviceConfig_SOC_SC7280 {
  1840  			return satisfied()
  1841  		}
  1842  
  1843  		return unsatisfied("SoC does not support VP9 k-SVC HW decoding")
  1844  	}}
  1845  }
  1846  
  1847  // AssistantKey is satisfied if a model has an assistant key.
  1848  func AssistantKey() Condition {
  1849  	return Model("eve", "nocturne", "atlas")
  1850  }
  1851  
  1852  // NoAssistantKey is satisfied if a model does not have an assistant key.
  1853  func NoAssistantKey() Condition {
  1854  	return SkipOnModel("eve", "nocturne", "atlas")
  1855  }
  1856  
  1857  // HapticTouchpad is satisfied if a model has a haptic touchpad.
  1858  func HapticTouchpad() Condition {
  1859  	return Model("vell", "redrix")
  1860  }
  1861  
  1862  // HPS is satisfied if the HPS peripheral (go/cros-hps) is present in the DUT.
  1863  func HPS() Condition {
  1864  	return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
  1865  		if hf := f.GetHardwareFeatures(); hf == nil {
  1866  			return withErrorStr("Did not find hardware features")
  1867  		} else if status := hf.GetHps().Present; status == configpb.HardwareFeatures_PRESENT {
  1868  			return satisfied()
  1869  		}
  1870  		return unsatisfied("HPS peripheral is not present")
  1871  	}}
  1872  }
  1873  
  1874  func containsCameraFeature(strs []string, feature string) bool {
  1875  	for _, f := range strs {
  1876  		if f == feature {
  1877  			return true
  1878  		}
  1879  	}
  1880  	return false
  1881  }
  1882  
  1883  // CameraFeature is satisfied if all the features listed in |names| are enabled on the DUT.
  1884  func CameraFeature(names ...string) Condition {
  1885  	return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
  1886  		if hf := f.GetHardwareFeatures(); hf == nil {
  1887  			return withErrorStr("Did not find hardware features")
  1888  		} else if features := hf.GetCamera().Features; features != nil {
  1889  			unsatisfiedFeatures := make([]string, 0, 10)
  1890  			for _, n := range names {
  1891  				if !containsCameraFeature(features, n) {
  1892  					unsatisfiedFeatures = append(unsatisfiedFeatures, n)
  1893  				}
  1894  			}
  1895  			if len(unsatisfiedFeatures) != 0 {
  1896  				return unsatisfied(fmt.Sprintf("Camera features not enabled: %v", unsatisfiedFeatures))
  1897  			}
  1898  			return satisfied()
  1899  		}
  1900  		return unsatisfied("Camera features not probed")
  1901  	}}
  1902  }
  1903  
  1904  // MainboardHasEarlyLibgfxinit is satisfied if the BIOS was built with Kconfig CONFIG_MAINBOARD_HAS_EARLY_LIBGFXINIT
  1905  func MainboardHasEarlyLibgfxinit() Condition {
  1906  	return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
  1907  		hf := f.GetHardwareFeatures()
  1908  		if hf != nil {
  1909  			fwc := hf.GetFwConfig()
  1910  			if fwc != nil {
  1911  				if fwc.MainboardHasEarlyLibgfxinit == configpb.HardwareFeatures_PRESENT {
  1912  					return satisfied()
  1913  				}
  1914  				if fwc.MainboardHasEarlyLibgfxinit == configpb.HardwareFeatures_NOT_PRESENT {
  1915  					return unsatisfied("MainboardHasEarlyLibgfxinit Kconfig disabled")
  1916  				}
  1917  			}
  1918  		}
  1919  		// Some Brya models default to PRESENT
  1920  		listed, err := modelListed(f.GetDeprecatedDeviceConfig(), "skolas", "brya0", "kano", "agah", "taeko", "crota", "osiris", "gaelen", "lisbon", "gladios", "marasov", "omnigul", "constitution")
  1921  		if err != nil {
  1922  			return withError(err)
  1923  		}
  1924  		if listed {
  1925  			return satisfied()
  1926  		}
  1927  		// The default for this Kconfig is off, so not found is the same as disabled.
  1928  		return unsatisfied("Kconfig not found")
  1929  	}}
  1930  }
  1931  
  1932  // VbootCbfsIntegration is satisfied if the BIOS was built with Kconfig CONFIG_VBOOT_CBFS_INTEGRATION
  1933  func VbootCbfsIntegration() Condition {
  1934  	return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
  1935  		hf := f.GetHardwareFeatures()
  1936  		if hf != nil {
  1937  			fwc := hf.GetFwConfig()
  1938  			if fwc != nil {
  1939  				if fwc.VbootCbfsIntegration == configpb.HardwareFeatures_PRESENT {
  1940  					return satisfied()
  1941  				}
  1942  				if fwc.VbootCbfsIntegration == configpb.HardwareFeatures_NOT_PRESENT {
  1943  					return unsatisfied("VbootCbfsIntegration Kconfig disabled")
  1944  				}
  1945  			}
  1946  		}
  1947  		// The default for this Kconfig is off, so not found is the same as disabled.
  1948  		return unsatisfied("Kconfig not found")
  1949  	}}
  1950  }
  1951  
  1952  // RuntimeProbeConfig is satisfied if the probe config of the model exists.
  1953  func RuntimeProbeConfig() Condition {
  1954  	return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
  1955  		hf := f.GetHardwareFeatures()
  1956  		if hf == nil {
  1957  			return withErrorStr("DUT HardwareFeatures data is not given")
  1958  		}
  1959  		if hf.GetRuntimeProbeConfig().GetPresent() != configpb.HardwareFeatures_PRESENT {
  1960  			return unsatisfied("DUT does not have Runtime Probe config")
  1961  		}
  1962  		return satisfied()
  1963  	}}
  1964  }
  1965  
  1966  // SeamlessRefreshRate is satisfied if the device supports changing refresh rates without modeset.
  1967  func SeamlessRefreshRate() Condition {
  1968  	// TODO: Determine at runtime if a device meets the requirements by inspecting EDID, kernel, and SoC versions.
  1969  	return Model("mithrax", "taniks")
  1970  }
  1971  
  1972  // GPUFamily is satisfied if the devices GPU family is categorized as one of the families specified.
  1973  // For a complete list of values or to add new ones please check the pciid maps at
  1974  // https://chromium.googlesource.com/chromiumos/platform/graphics/+/refs/heads/main/src/go.chromium.org/chromiumos/graphics-utils-go/hardware_probe/cmd/hardware_probe
  1975  func GPUFamily(families []string) Condition {
  1976  	return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
  1977  		hf := f.GetHardwareFeatures()
  1978  		if hf == nil {
  1979  			return withErrorStr("DUT HardwareFeatures data is not given")
  1980  		}
  1981  		for _, family := range families {
  1982  			if hf.GetHardwareProbeConfig().GetGpuFamily() == family {
  1983  				return satisfied()
  1984  			}
  1985  		}
  1986  		return unsatisfied("DUT GPU family is not met")
  1987  	}}
  1988  }
  1989  
  1990  // SkipGPUFamily is satisfied if the devices GPU family is none of the families specified.
  1991  // For a complete list of values or to add new ones please check the pciid maps at
  1992  // https://chromium.googlesource.com/chromiumos/platform/graphics/+/refs/heads/main/src/go.chromium.org/chromiumos/graphics-utils-go/hardware_probe/cmd/hardware_probe
  1993  func SkipGPUFamily(families []string) Condition {
  1994  	return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
  1995  		hf := f.GetHardwareFeatures()
  1996  		if hf == nil {
  1997  			return withErrorStr("DUT HardwareFeatures data is not given")
  1998  		}
  1999  		for _, family := range families {
  2000  			if hf.GetHardwareProbeConfig().GetGpuFamily() == family {
  2001  				return unsatisfied("DUT GPU family matched with skip list")
  2002  			}
  2003  		}
  2004  		return satisfied()
  2005  	}}
  2006  }
  2007  
  2008  // GPUVendor is satisfied if the devices GPU vendor is categorized as one of the vendors specified.
  2009  // For a complete list of values or to add new ones please check the files at
  2010  // https://chromium.googlesource.com/chromiumos/platform/graphics/+/refs/heads/main/src/go.chromium.org/chromiumos/graphics-utils-go/hardware_probe/cmd/hardware_probe
  2011  func GPUVendor(vendors []string) Condition {
  2012  	return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
  2013  		hf := f.GetHardwareFeatures()
  2014  		if hf == nil {
  2015  			return withErrorStr("DUT HardwareFeatures data is not given")
  2016  		}
  2017  		for _, vendor := range vendors {
  2018  			if hf.GetHardwareProbeConfig().GetGpuVendor() == vendor {
  2019  				return satisfied()
  2020  			}
  2021  		}
  2022  		return unsatisfied("DUT GPU vendor is not met")
  2023  	}}
  2024  }
  2025  
  2026  // SkipGPUVendor is satisfied if the devices GPU vendor is categorized as none of the vendors specified.
  2027  // For a complete list of values or to add new ones please check the files at
  2028  // https://chromium.googlesource.com/chromiumos/platform/graphics/+/refs/heads/main/src/go.chromium.org/chromiumos/graphics-utils-go/hardware_probe/cmd/hardware_probe
  2029  func SkipGPUVendor(vendors []string) Condition {
  2030  	return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
  2031  		hf := f.GetHardwareFeatures()
  2032  		if hf == nil {
  2033  			return withErrorStr("DUT HardwareFeatures data is not given")
  2034  		}
  2035  		for _, vendor := range vendors {
  2036  			if hf.GetHardwareProbeConfig().GetGpuVendor() == vendor {
  2037  				return unsatisfied("DUT GPU vendor matched with skip list")
  2038  			}
  2039  		}
  2040  		return satisfied()
  2041  	}}
  2042  }
  2043  
  2044  // CPUSocFamily is satisfied if the devices CPU SOC family is categorized as one of the families specified.
  2045  // For a complete list of values or to add new ones please check the files at
  2046  // https://chromium.googlesource.com/chromiumos/platform/graphics/+/refs/heads/main/src/go.chromium.org/chromiumos/graphics-utils-go/hardware_probe/cmd/hardware_probe
  2047  func CPUSocFamily(families []string) Condition {
  2048  	return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
  2049  		hf := f.GetHardwareFeatures()
  2050  		if hf == nil {
  2051  			return withErrorStr("DUT HardwareFeatures data is not given")
  2052  		}
  2053  		for _, family := range families {
  2054  			if hf.GetHardwareProbeConfig().GetCpuSocFamily() == family {
  2055  				return satisfied()
  2056  			}
  2057  		}
  2058  		return unsatisfied("DUT CPU soc family is not met")
  2059  	}}
  2060  }
  2061  
  2062  // SkipCPUSocFamily is satisfied if the device's CPU SOC family is none of the families specified.
  2063  // For a complete list of values or to add new ones please check the files at
  2064  // https://chromium.googlesource.com/chromiumos/platform/graphics/+/refs/heads/main/src/go.chromium.org/chromiumos/graphics-utils-go/hardware_probe/cmd/hardware_probe
  2065  func SkipCPUSocFamily(families []string) Condition {
  2066  	return Condition{Satisfied: func(f *protocol.HardwareFeatures) (bool, string, error) {
  2067  		hf := f.GetHardwareFeatures()
  2068  		if hf == nil {
  2069  			return withErrorStr("DUT HardwareFeatures data is not given")
  2070  		}
  2071  		for _, family := range families {
  2072  			if hf.GetHardwareProbeConfig().GetCpuSocFamily() == family {
  2073  				return unsatisfied("DUT CPU soc family matched with skip list")
  2074  			}
  2075  		}
  2076  		return satisfied()
  2077  	}}
  2078  }
  2079  
  2080  // InternalTrackpoint is satisfied if a model has an internal trackpoint.
  2081  func InternalTrackpoint() Condition {
  2082  	return Model("morphius")
  2083  }