1*dabd48ddSZev Weiss #include <DeviceMgmt.hpp> 2*dabd48ddSZev Weiss 3*dabd48ddSZev Weiss #include <filesystem> 4*dabd48ddSZev Weiss #include <fstream> 5*dabd48ddSZev Weiss 6*dabd48ddSZev Weiss namespace fs = std::filesystem; 7*dabd48ddSZev Weiss 8*dabd48ddSZev Weiss std::optional<I2CDevice> getI2CDevice(const I2CDeviceTypeMap& dtmap, 9*dabd48ddSZev Weiss const SensorBaseConfigMap& cfg) 10*dabd48ddSZev Weiss { 11*dabd48ddSZev Weiss auto findType = cfg.find("Type"); 12*dabd48ddSZev Weiss auto findBus = cfg.find("Bus"); 13*dabd48ddSZev Weiss auto findAddr = cfg.find("Address"); 14*dabd48ddSZev Weiss 15*dabd48ddSZev Weiss if (findType == cfg.end() || findBus == cfg.end() || findAddr == cfg.end()) 16*dabd48ddSZev Weiss { 17*dabd48ddSZev Weiss return std::nullopt; 18*dabd48ddSZev Weiss } 19*dabd48ddSZev Weiss 20*dabd48ddSZev Weiss const std::string* type = std::get_if<std::string>(&findType->second); 21*dabd48ddSZev Weiss const uint64_t* bus = std::get_if<uint64_t>(&findBus->second); 22*dabd48ddSZev Weiss const uint64_t* addr = std::get_if<uint64_t>(&findAddr->second); 23*dabd48ddSZev Weiss 24*dabd48ddSZev Weiss if (type == nullptr || bus == nullptr || addr == nullptr) 25*dabd48ddSZev Weiss { 26*dabd48ddSZev Weiss return std::nullopt; 27*dabd48ddSZev Weiss } 28*dabd48ddSZev Weiss 29*dabd48ddSZev Weiss auto findDevType = dtmap.find(type->c_str()); 30*dabd48ddSZev Weiss if (findDevType == dtmap.end()) 31*dabd48ddSZev Weiss { 32*dabd48ddSZev Weiss return std::nullopt; 33*dabd48ddSZev Weiss } 34*dabd48ddSZev Weiss 35*dabd48ddSZev Weiss return I2CDevice(findDevType->second, *bus, *addr); 36*dabd48ddSZev Weiss } 37*dabd48ddSZev Weiss 38*dabd48ddSZev Weiss static fs::path i2cBusPath(uint64_t bus) 39*dabd48ddSZev Weiss { 40*dabd48ddSZev Weiss return {"/sys/bus/i2c/devices/i2c-" + std::to_string(bus)}; 41*dabd48ddSZev Weiss } 42*dabd48ddSZev Weiss 43*dabd48ddSZev Weiss static std::string deviceDirName(uint64_t bus, uint64_t address) 44*dabd48ddSZev Weiss { 45*dabd48ddSZev Weiss std::ostringstream name; 46*dabd48ddSZev Weiss name << bus << "-" << std::hex << std::setw(4) << std::setfill('0') 47*dabd48ddSZev Weiss << address; 48*dabd48ddSZev Weiss return name.str(); 49*dabd48ddSZev Weiss } 50*dabd48ddSZev Weiss 51*dabd48ddSZev Weiss bool I2CDevice::present(void) const 52*dabd48ddSZev Weiss { 53*dabd48ddSZev Weiss fs::path path = i2cBusPath(bus) / deviceDirName(bus, address); 54*dabd48ddSZev Weiss 55*dabd48ddSZev Weiss if (type->createsHWMon) 56*dabd48ddSZev Weiss { 57*dabd48ddSZev Weiss path /= "hwmon"; 58*dabd48ddSZev Weiss } 59*dabd48ddSZev Weiss 60*dabd48ddSZev Weiss // Ignore errors; anything but a clean 'true' is fine as 'false' 61*dabd48ddSZev Weiss std::error_code ec; 62*dabd48ddSZev Weiss return fs::exists(path, ec); 63*dabd48ddSZev Weiss } 64*dabd48ddSZev Weiss 65*dabd48ddSZev Weiss int I2CDevice::create(void) const 66*dabd48ddSZev Weiss { 67*dabd48ddSZev Weiss // If it's already instantiated, there's nothing we need to do. 68*dabd48ddSZev Weiss if (present()) 69*dabd48ddSZev Weiss { 70*dabd48ddSZev Weiss return 0; 71*dabd48ddSZev Weiss } 72*dabd48ddSZev Weiss 73*dabd48ddSZev Weiss // Try to create it: 'echo $devtype $addr > .../i2c-$bus/new_device' 74*dabd48ddSZev Weiss fs::path ctorPath = i2cBusPath(bus) / "new_device"; 75*dabd48ddSZev Weiss std::ofstream ctor(ctorPath); 76*dabd48ddSZev Weiss if (!ctor.good()) 77*dabd48ddSZev Weiss { 78*dabd48ddSZev Weiss std::cerr << "Failed to open " << ctorPath << "\n"; 79*dabd48ddSZev Weiss return -1; 80*dabd48ddSZev Weiss } 81*dabd48ddSZev Weiss 82*dabd48ddSZev Weiss ctor << type->name << " " << address << "\n"; 83*dabd48ddSZev Weiss ctor.flush(); 84*dabd48ddSZev Weiss if (!ctor.good()) 85*dabd48ddSZev Weiss { 86*dabd48ddSZev Weiss std::cerr << "Failed to write to " << ctorPath << "\n"; 87*dabd48ddSZev Weiss return -1; 88*dabd48ddSZev Weiss } 89*dabd48ddSZev Weiss 90*dabd48ddSZev Weiss // Check if that created the requisite sysfs directory 91*dabd48ddSZev Weiss if (!present()) 92*dabd48ddSZev Weiss { 93*dabd48ddSZev Weiss destroy(); 94*dabd48ddSZev Weiss return -1; 95*dabd48ddSZev Weiss } 96*dabd48ddSZev Weiss 97*dabd48ddSZev Weiss return 0; 98*dabd48ddSZev Weiss } 99*dabd48ddSZev Weiss 100*dabd48ddSZev Weiss int I2CDevice::destroy(void) const 101*dabd48ddSZev Weiss { 102*dabd48ddSZev Weiss // No present() check on this like in create(), since it might be used to 103*dabd48ddSZev Weiss // clean up after a device instantiation that was only partially 104*dabd48ddSZev Weiss // successful (i.e. when present() would return false but there's still a 105*dabd48ddSZev Weiss // dummy i2c client device to remove) 106*dabd48ddSZev Weiss 107*dabd48ddSZev Weiss fs::path dtorPath = i2cBusPath(bus) / "delete_device"; 108*dabd48ddSZev Weiss std::ofstream dtor(dtorPath); 109*dabd48ddSZev Weiss if (!dtor.good()) 110*dabd48ddSZev Weiss { 111*dabd48ddSZev Weiss std::cerr << "Failed to open " << dtorPath << "\n"; 112*dabd48ddSZev Weiss return -1; 113*dabd48ddSZev Weiss } 114*dabd48ddSZev Weiss 115*dabd48ddSZev Weiss dtor << address << "\n"; 116*dabd48ddSZev Weiss dtor.flush(); 117*dabd48ddSZev Weiss if (!dtor.good()) 118*dabd48ddSZev Weiss { 119*dabd48ddSZev Weiss std::cerr << "Failed to write to " << dtorPath << "\n"; 120*dabd48ddSZev Weiss return -1; 121*dabd48ddSZev Weiss } 122*dabd48ddSZev Weiss 123*dabd48ddSZev Weiss return 0; 124*dabd48ddSZev Weiss } 125