Make the IMC FRU scanner's I2C paths and HAL drivers configurable.

`ImcFruScanner` hardcoded the two gBMC HAL driver names it resolves through the
registry (`I2cBusI2c`, `At24Eeprom`) and the `/dev/i2c-` device prefix, and took
the sysfs enumeration directory as a constructor parameter that only tests ever
set. That is three sources of truth for what is one thing: where the scanner
looks for I2C hardware. Move all four onto `GnicMonitorConfig`, with the previous hardcoded values as
proto defaults.

PiperOrigin-RevId: 993924842
Change-Id: I20d025209eba0875d6b04a7f771ab6ecc97a5682
diff --git a/bmc/gnic_monitor.cc b/bmc/gnic_monitor.cc
index a4a089d..08831f9 100644
--- a/bmc/gnic_monitor.cc
+++ b/bmc/gnic_monitor.cc
@@ -151,7 +151,6 @@
 }
 
 namespace {
-constexpr absl::string_view kEepromDriverName = "At24Eeprom";
 
 void ApplyEepromOverride(
     const safepower_agent_config::EepromDeviceConfig& config,
@@ -202,22 +201,22 @@
 
 std::shared_ptr<ImcFruScanner> ImcFruScanner::Create(
     const safepower_agent_config::GnicMonitorConfig& config,
-    std::shared_ptr<StateUpdater<safepower_agent_proto::SystemState>> reactor,
-    std::string sysfs_i2c_dev_path) {
+    std::shared_ptr<StateUpdater<safepower_agent_proto::SystemState>> reactor) {
   return std::make_shared<ImcFruScanner>(PrivateToken{}, config,
-                                         std::move(reactor),
-                                         std::move(sysfs_i2c_dev_path));
+                                         std::move(reactor));
 }
 
 ImcFruScanner::ImcFruScanner(
     PrivateToken /*token*/,
     const safepower_agent_config::GnicMonitorConfig& config,
-    std::shared_ptr<StateUpdater<safepower_agent_proto::SystemState>> reactor,
-    std::string sysfs_i2c_dev_path)
+    std::shared_ptr<StateUpdater<safepower_agent_proto::SystemState>> reactor)
     : fru_address_(kDefaultFruEepromAddress),
       collection_interval_ms_(config.collection_interval_ms()),
       error_timeout_(absl::Milliseconds(config.error_timeout_ms())),
-      sysfs_i2c_dev_path_(std::move(sysfs_i2c_dev_path)),
+      sysfs_i2c_dev_path_(config.sysfs_i2c_dev_path()),
+      i2c_dev_path_prefix_(config.i2c_dev_path_prefix()),
+      i2c_bus_driver_(config.i2c_bus_driver()),
+      eeprom_driver_(config.eeprom_driver()),
       max_fru_size_(config.max_fru_size()),
       reactor_(std::move(reactor)) {
   for (int bus : config.i2c_bus_block_list()) {
@@ -296,16 +295,16 @@
 }
 
 absl::Status ImcFruScanner::ScanBus(int bus_id) {
-  ASSIGN_OR_RETURN(
-      std::shared_ptr<I2cBus> i2c_bus,
-      I2cBusRegistry::Create("I2cBusI2c",
-                             I2cConfig{absl::StrCat("/dev/i2c-", bus_id)}));
+  ASSIGN_OR_RETURN(std::shared_ptr<I2cBus> i2c_bus,
+                   I2cBusRegistry::Create(
+                       i2c_bus_driver_,
+                       I2cConfig{absl::StrCat(i2c_dev_path_prefix_, bus_id)}));
 
   auto eeprom_config = base_fru_eeprom_config_;
   eeprom_config.i2c_bus = i2c_bus;
 
   ASSIGN_OR_RETURN(auto eeprom,
-                   EepromRegistry::Create(kEepromDriverName, eeprom_config));
+                   EepromRegistry::Create(eeprom_driver_, eeprom_config));
 
   FruInventoryConfig inventory_config;
   inventory_config.eeprom = eeprom.get();
@@ -344,7 +343,7 @@
 
   ASSIGN_OR_RETURN(
       auto emulated_eeprom,
-      EepromRegistry::Create(kEepromDriverName, emulated_eeprom_config));
+      EepromRegistry::Create(eeprom_driver_, emulated_eeprom_config));
 
   GnicTelemetryConfig telemetry_config;
   telemetry_config.eeprom = emulated_eeprom.get();
diff --git a/bmc/gnic_monitor.h b/bmc/gnic_monitor.h
index f0dde06..794b278 100644
--- a/bmc/gnic_monitor.h
+++ b/bmc/gnic_monitor.h
@@ -65,13 +65,13 @@
   ImcFruScanner(
       PrivateToken token,
       const safepower_agent_config::GnicMonitorConfig& config,
-      std::shared_ptr<StateUpdater<safepower_agent_proto::SystemState>> reactor,
-      std::string sysfs_i2c_dev_path);
+      std::shared_ptr<StateUpdater<safepower_agent_proto::SystemState>>
+          reactor);
 
   static std::shared_ptr<ImcFruScanner> Create(
       const safepower_agent_config::GnicMonitorConfig& config,
-      std::shared_ptr<StateUpdater<safepower_agent_proto::SystemState>> reactor,
-      std::string sysfs_i2c_dev_path = "/sys/class/i2c-dev/");
+      std::shared_ptr<StateUpdater<safepower_agent_proto::SystemState>>
+          reactor);
 
   absl::Status Start();
   ~ImcFruScanner();
@@ -85,6 +85,9 @@
   uint32_t collection_interval_ms_;
   absl::Duration error_timeout_;
   std::string sysfs_i2c_dev_path_;
+  std::string i2c_dev_path_prefix_;
+  std::string i2c_bus_driver_;
+  std::string eeprom_driver_;
   std::vector<int> actual_buses_;
   size_t max_fru_size_;
 
diff --git a/piper_cl.txt b/piper_cl.txt
index afe0de5..129331e 100644
--- a/piper_cl.txt
+++ b/piper_cl.txt
@@ -1 +1 @@
-993756256
+993924842
diff --git a/proto/safepower_agent_config.proto b/proto/safepower_agent_config.proto
index aa018ab..980eeea 100644
--- a/proto/safepower_agent_config.proto
+++ b/proto/safepower_agent_config.proto
@@ -111,6 +111,20 @@
   EepromDeviceConfig emulated_eeprom = 5;
 
   int32 max_fru_size = 6 [default = 8192];
+
+  // Directory enumerated to discover I2C buses. Every entry named "i2c-<N>"
+  // is taken to be bus N.
+  string sysfs_i2c_dev_path = 7 [default = "/sys/class/i2c-dev/"];
+
+  // Prefix of the character device for a bus; the bus number is appended to
+  // form e.g. "/dev/i2c-3".
+  string i2c_dev_path_prefix = 8 [default = "/dev/i2c-"];
+
+  // Names of the gBMC HAL drivers used to reach the IMC EEPROMs. These are
+  // only overridden by tests, which substitute file-backed drivers to
+  // simulate hardware; see bmc/mock_hal/.
+  string i2c_bus_driver = 9 [default = "I2cBusI2c"];
+  string eeprom_driver = 10 [default = "At24Eeprom"];
 }
 
 // node os specific configs will go here