194df8c90SGunnar Mills #include "config.h"
294df8c90SGunnar Mills
394df8c90SGunnar Mills #include "i2c_occ.hpp"
494df8c90SGunnar Mills
50ab90ca7SLei YU #include <algorithm>
6b5259a1eSLei YU #include <cassert>
70ab90ca7SLei YU #include <fstream>
80ab90ca7SLei YU
90ab90ca7SLei YU #ifdef I2C_OCC
100ab90ca7SLei YU
110ab90ca7SLei YU namespace i2c_occ
120ab90ca7SLei YU {
130ab90ca7SLei YU
14*bcef3b48SGeorge Liu namespace fs = std::filesystem;
150ab90ca7SLei YU
1641470e56SLei YU // The occ_master sysfs file
1741470e56SLei YU constexpr auto OCC_MASTER_FILE = "occ_master";
180ab90ca7SLei YU // The device name's length, e.g. "p8-occ-hwmon"
190ab90ca7SLei YU constexpr auto DEVICE_NAME_LENGTH = 12;
20b5259a1eSLei YU // The occ name's length, e.g. "occ"
21b5259a1eSLei YU constexpr auto OCC_NAME_LENGTH = 3;
220ab90ca7SLei YU
230ab90ca7SLei YU // static assert to make sure the i2c occ device name is expected
240ab90ca7SLei YU static_assert(sizeof(I2C_OCC_DEVICE_NAME) - 1 == DEVICE_NAME_LENGTH);
25b5259a1eSLei YU static_assert(sizeof(OCC_NAME) - 1 == OCC_NAME_LENGTH);
260ab90ca7SLei YU
isMasterOcc(const fs::directory_entry & p)2741470e56SLei YU static bool isMasterOcc(const fs::directory_entry& p)
2841470e56SLei YU {
29*bcef3b48SGeorge Liu auto f = p / fs::path{OCC_MASTER_FILE};
3041470e56SLei YU auto str = getFileContent(f);
3141470e56SLei YU return (!str.empty()) && (str[0] == '1');
3241470e56SLei YU }
3341470e56SLei YU
getFileContent(const fs::path & f)340ab90ca7SLei YU std::string getFileContent(const fs::path& f)
350ab90ca7SLei YU {
360ab90ca7SLei YU std::string ret(DEVICE_NAME_LENGTH, 0);
370ab90ca7SLei YU std::ifstream ifs(f.c_str(), std::ios::binary);
380ab90ca7SLei YU if (ifs.is_open())
390ab90ca7SLei YU {
400ab90ca7SLei YU ifs.read(&ret[0], DEVICE_NAME_LENGTH);
410ab90ca7SLei YU ret.resize(ifs.gcount());
420ab90ca7SLei YU }
430ab90ca7SLei YU return ret;
440ab90ca7SLei YU }
450ab90ca7SLei YU
getOccHwmonDevices(const char * path)460ab90ca7SLei YU std::vector<std::string> getOccHwmonDevices(const char* path)
470ab90ca7SLei YU {
480ab90ca7SLei YU std::vector<std::string> result{};
490ab90ca7SLei YU
500ab90ca7SLei YU if (fs::is_directory(path))
510ab90ca7SLei YU {
520ab90ca7SLei YU for (auto& p : fs::directory_iterator(path))
530ab90ca7SLei YU {
540ab90ca7SLei YU // Check if a device's name is "p8-occ-hwmon"
55*bcef3b48SGeorge Liu auto f = p / fs::path{"name"};
560ab90ca7SLei YU auto str = getFileContent(f);
570ab90ca7SLei YU if (str == I2C_OCC_DEVICE_NAME)
580ab90ca7SLei YU {
5941470e56SLei YU if (isMasterOcc(p))
6041470e56SLei YU {
6141470e56SLei YU // Insert master occ at the beginning
6241470e56SLei YU result.emplace(result.begin(), p.path().filename());
6341470e56SLei YU }
6441470e56SLei YU else
6541470e56SLei YU {
660ab90ca7SLei YU result.emplace_back(p.path().filename());
670ab90ca7SLei YU }
680ab90ca7SLei YU }
6941470e56SLei YU }
7041470e56SLei YU }
7141470e56SLei YU if (!result.empty())
7241470e56SLei YU {
7341470e56SLei YU // Sort the occ devices except for master
7441470e56SLei YU std::sort(result.begin() + 1, result.end());
750ab90ca7SLei YU }
760ab90ca7SLei YU return result;
770ab90ca7SLei YU }
780ab90ca7SLei YU
i2cToDbus(std::string & path)790ab90ca7SLei YU void i2cToDbus(std::string& path)
800ab90ca7SLei YU {
810ab90ca7SLei YU std::replace(path.begin(), path.end(), '-', '_');
820ab90ca7SLei YU }
830ab90ca7SLei YU
dbusToI2c(std::string & path)840ab90ca7SLei YU void dbusToI2c(std::string& path)
850ab90ca7SLei YU {
860ab90ca7SLei YU std::replace(path.begin(), path.end(), '_', '-');
870ab90ca7SLei YU }
880ab90ca7SLei YU
getI2cDeviceName(const std::string & dbusPath)890ab90ca7SLei YU std::string getI2cDeviceName(const std::string& dbusPath)
900ab90ca7SLei YU {
910ab90ca7SLei YU auto name = fs::path(dbusPath).filename().string();
92b5259a1eSLei YU
93b5259a1eSLei YU // Need to make sure the name starts with "occ"
94b5259a1eSLei YU assert(name.compare(0, OCC_NAME_LENGTH, OCC_NAME) == 0);
95b5259a1eSLei YU
96b5259a1eSLei YU // Change name like occ_3_0050 to 3_0050
97b5259a1eSLei YU name.erase(0, OCC_NAME_LENGTH + 1);
98b5259a1eSLei YU
990ab90ca7SLei YU dbusToI2c(name);
1000ab90ca7SLei YU return name;
1010ab90ca7SLei YU }
1020ab90ca7SLei YU
1030ab90ca7SLei YU } // namespace i2c_occ
1040ab90ca7SLei YU
1050ab90ca7SLei YU #endif
106