xref: /openbmc/phosphor-hwmon/sysfs.cpp (revision e8771fd4)
1613a5b37SBrad Bishop /**
2613a5b37SBrad Bishop  * Copyright © 2016 IBM Corporation
3613a5b37SBrad Bishop  *
4613a5b37SBrad Bishop  * Licensed under the Apache License, Version 2.0 (the "License");
5613a5b37SBrad Bishop  * you may not use this file except in compliance with the License.
6613a5b37SBrad Bishop  * You may obtain a copy of the License at
7613a5b37SBrad Bishop  *
8613a5b37SBrad Bishop  *     http://www.apache.org/licenses/LICENSE-2.0
9613a5b37SBrad Bishop  *
10613a5b37SBrad Bishop  * Unless required by applicable law or agreed to in writing, software
11613a5b37SBrad Bishop  * distributed under the License is distributed on an "AS IS" BASIS,
12613a5b37SBrad Bishop  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13613a5b37SBrad Bishop  * See the License for the specific language governing permissions and
14613a5b37SBrad Bishop  * limitations under the License.
15613a5b37SBrad Bishop  */
16043d3230SPatrick Venture #include "sysfs.hpp"
17043d3230SPatrick Venture 
18f9aff805SWilliam A. Kennington III #include <fmt/format.h>
19f9aff805SWilliam A. Kennington III 
20754d38cfSBrad Bishop #include <algorithm>
218b574a7eSBrad Bishop #include <cerrno>
22613a5b37SBrad Bishop #include <cstdlib>
239e997b4dSPatrick Venture #include <filesystem>
2468c43b21SBrad Bishop #include <fstream>
25f9aff805SWilliam A. Kennington III #include <string>
26613a5b37SBrad Bishop 
27f4bf63adSBrad Bishop using namespace std::string_literals;
289e997b4dSPatrick Venture namespace fs = std::filesystem;
298af8a200SBrandon Wyman 
30043d3230SPatrick Venture namespace sysfs
31043d3230SPatrick Venture {
321e6324faSPatrick Venture 
33f4bf63adSBrad Bishop static const auto emptyString = ""s;
3408379a31SBrad Bishop static constexpr auto ofRoot = "/sys/firmware/devicetree/base";
35613a5b37SBrad Bishop 
36043d3230SPatrick Venture std::string findPhandleMatch(const std::string& iochanneldir,
378af8a200SBrandon Wyman                              const std::string& phandledir)
38613a5b37SBrad Bishop {
39f4bf63adSBrad Bishop     // TODO: At the moment this method only supports device trees
40f4bf63adSBrad Bishop     // with iio-hwmon nodes with a single sensor.  Typically
41f4bf63adSBrad Bishop     // device trees are defined with all the iio sensors in a
42f4bf63adSBrad Bishop     // single iio-hwmon node so it would be nice to add support
43f4bf63adSBrad Bishop     // for lists of phandles (with variable sized entries) via
44f4bf63adSBrad Bishop     // libfdt or something like that, so that users are not
45f4bf63adSBrad Bishop     // forced into implementing unusual looking device trees
46f4bf63adSBrad Bishop     // with multiple iio-hwmon nodes - one for each sensor.
47f4bf63adSBrad Bishop 
48f4bf63adSBrad Bishop     fs::path ioChannelsPath{iochanneldir};
49f4bf63adSBrad Bishop     ioChannelsPath /= "io-channels";
50f4bf63adSBrad Bishop 
51f4bf63adSBrad Bishop     if (!fs::exists(ioChannelsPath))
52f4bf63adSBrad Bishop     {
53f4bf63adSBrad Bishop         return emptyString;
54f4bf63adSBrad Bishop     }
55f4bf63adSBrad Bishop 
56f4bf63adSBrad Bishop     uint32_t ioChannelsValue;
57f4bf63adSBrad Bishop     std::ifstream ioChannelsFile(ioChannelsPath);
58f4bf63adSBrad Bishop 
59043d3230SPatrick Venture     ioChannelsFile.read(reinterpret_cast<char*>(&ioChannelsValue),
60f4bf63adSBrad Bishop                         sizeof(ioChannelsValue));
61f4bf63adSBrad Bishop 
628af8a200SBrandon Wyman     for (const auto& ofInst : fs::recursive_directory_iterator(phandledir))
63613a5b37SBrad Bishop     {
648af8a200SBrandon Wyman         auto path = ofInst.path();
65f4bf63adSBrad Bishop         if ("phandle" != path.filename())
664eb9858dSBrandon Wyman         {
67f4bf63adSBrad Bishop             continue;
68f4bf63adSBrad Bishop         }
69f4bf63adSBrad Bishop         std::ifstream pHandleFile(path);
704eb9858dSBrandon Wyman         uint32_t pHandleValue;
714eb9858dSBrandon Wyman 
72043d3230SPatrick Venture         pHandleFile.read(reinterpret_cast<char*>(&pHandleValue),
734eb9858dSBrandon Wyman                          sizeof(pHandleValue));
744eb9858dSBrandon Wyman 
754eb9858dSBrandon Wyman         if (ioChannelsValue == pHandleValue)
764eb9858dSBrandon Wyman         {
77f4bf63adSBrad Bishop             return path;
788af8a200SBrandon Wyman         }
798af8a200SBrandon Wyman     }
808af8a200SBrandon Wyman 
81f4bf63adSBrad Bishop     return emptyString;
828af8a200SBrandon Wyman }
838af8a200SBrandon Wyman 
84431d26a5SBrad Bishop std::string findCalloutPath(const std::string& instancePath)
858af8a200SBrandon Wyman {
86431d26a5SBrad Bishop     // Follow the hwmon instance (/sys/class/hwmon/hwmon<N>)
87431d26a5SBrad Bishop     // /sys/devices symlink.
88431d26a5SBrad Bishop     fs::path devPath{instancePath};
89431d26a5SBrad Bishop     devPath /= "device";
908af8a200SBrandon Wyman 
91431d26a5SBrad Bishop     try
928af8a200SBrandon Wyman     {
93431d26a5SBrad Bishop         devPath = fs::canonical(devPath);
94431d26a5SBrad Bishop     }
95431d26a5SBrad Bishop     catch (const std::system_error& e)
96431d26a5SBrad Bishop     {
97431d26a5SBrad Bishop         return emptyString;
98431d26a5SBrad Bishop     }
99431d26a5SBrad Bishop 
100431d26a5SBrad Bishop     // See if the device is backed by the iio-hwmon driver.
101431d26a5SBrad Bishop     fs::path p{devPath};
102431d26a5SBrad Bishop     p /= "driver";
103431d26a5SBrad Bishop     p = fs::canonical(p);
104431d26a5SBrad Bishop 
105431d26a5SBrad Bishop     if (p.filename() != "iio_hwmon")
106431d26a5SBrad Bishop     {
107431d26a5SBrad Bishop         // Not backed by iio-hwmon.  The device pointed to
108431d26a5SBrad Bishop         // is the callout device.
109431d26a5SBrad Bishop         return devPath;
110431d26a5SBrad Bishop     }
111431d26a5SBrad Bishop 
112431d26a5SBrad Bishop     // Find the DT path to the iio-hwmon platform device.
113431d26a5SBrad Bishop     fs::path ofDevPath{devPath};
114431d26a5SBrad Bishop     ofDevPath /= "of_node";
115431d26a5SBrad Bishop 
116431d26a5SBrad Bishop     try
117431d26a5SBrad Bishop     {
118431d26a5SBrad Bishop         ofDevPath = fs::canonical(ofDevPath);
119431d26a5SBrad Bishop     }
120431d26a5SBrad Bishop     catch (const std::system_error& e)
121431d26a5SBrad Bishop     {
122431d26a5SBrad Bishop         return emptyString;
123431d26a5SBrad Bishop     }
124431d26a5SBrad Bishop 
125431d26a5SBrad Bishop     // Search /sys/bus/iio/devices for the phandle in io-channels.
126431d26a5SBrad Bishop     // If a match is found, use the corresponding /sys/devices
127431d26a5SBrad Bishop     // iio device as the callout device.
128431d26a5SBrad Bishop     static constexpr auto iioDevices = "/sys/bus/iio/devices";
129431d26a5SBrad Bishop     for (const auto& iioDev : fs::recursive_directory_iterator(iioDevices))
130431d26a5SBrad Bishop     {
131431d26a5SBrad Bishop         p = iioDev.path();
132431d26a5SBrad Bishop         p /= "of_node";
133431d26a5SBrad Bishop 
134431d26a5SBrad Bishop         try
135431d26a5SBrad Bishop         {
136431d26a5SBrad Bishop             p = fs::canonical(p);
137431d26a5SBrad Bishop         }
138431d26a5SBrad Bishop         catch (const std::system_error& e)
139431d26a5SBrad Bishop         {
140431d26a5SBrad Bishop             continue;
141431d26a5SBrad Bishop         }
142431d26a5SBrad Bishop 
143431d26a5SBrad Bishop         auto match = findPhandleMatch(ofDevPath, p);
144431d26a5SBrad Bishop         auto n = match.rfind('/');
1458af8a200SBrandon Wyman         if (n != std::string::npos)
1468af8a200SBrandon Wyman         {
147431d26a5SBrad Bishop             // This is the iio device referred to by io-channels.
148431d26a5SBrad Bishop             // Remove iio:device<N>.
149431d26a5SBrad Bishop             try
150431d26a5SBrad Bishop             {
151431d26a5SBrad Bishop                 return fs::canonical(iioDev).parent_path();
152431d26a5SBrad Bishop             }
153431d26a5SBrad Bishop             catch (const std::system_error& e)
154431d26a5SBrad Bishop             {
155431d26a5SBrad Bishop                 return emptyString;
156431d26a5SBrad Bishop             }
1578af8a200SBrandon Wyman         }
1588af8a200SBrandon Wyman     }
1598af8a200SBrandon Wyman 
160431d26a5SBrad Bishop     return emptyString;
1618af8a200SBrandon Wyman }
1628af8a200SBrandon Wyman 
1635c014d2bSMatt Spinler std::string findHwmonFromOFPath(const std::string& ofNode)
1648af8a200SBrandon Wyman {
1658af8a200SBrandon Wyman     static constexpr auto hwmonRoot = "/sys/class/hwmon";
1668af8a200SBrandon Wyman 
1675c014d2bSMatt Spinler     auto fullOfPath = fs::path(ofRoot) / fs::path(ofNode).relative_path();
1688af8a200SBrandon Wyman 
1698af8a200SBrandon Wyman     for (const auto& hwmonInst : fs::directory_iterator(hwmonRoot))
1708af8a200SBrandon Wyman     {
1718af8a200SBrandon Wyman         auto path = hwmonInst.path();
1728af8a200SBrandon Wyman         path /= "of_node";
1734e24ebd6SBrad Bishop 
1744e24ebd6SBrad Bishop         try
1758af8a200SBrandon Wyman         {
1764e24ebd6SBrad Bishop             path = fs::canonical(path);
1778af8a200SBrandon Wyman         }
1784e24ebd6SBrad Bishop         catch (const std::system_error& e)
1798af8a200SBrandon Wyman         {
1804e24ebd6SBrad Bishop             // realpath may encounter ENOENT (Hwmon
1814e24ebd6SBrad Bishop             // instances have a nasty habit of
1824e24ebd6SBrad Bishop             // going away without warning).
1838af8a200SBrandon Wyman             continue;
1848af8a200SBrandon Wyman         }
1858af8a200SBrandon Wyman 
1864e24ebd6SBrad Bishop         if (path == fullOfPath)
1874e24ebd6SBrad Bishop         {
18808379a31SBrad Bishop             return hwmonInst.path();
189613a5b37SBrad Bishop         }
190613a5b37SBrad Bishop 
1914e24ebd6SBrad Bishop         // Try to find HWMON instance via phandle values.
1924e24ebd6SBrad Bishop         // Used for IIO device drivers.
1934e24ebd6SBrad Bishop         auto matchpath = findPhandleMatch(path, fullOfPath);
1944e24ebd6SBrad Bishop         if (!matchpath.empty())
1954e24ebd6SBrad Bishop         {
1964e24ebd6SBrad Bishop             return hwmonInst.path();
1974e24ebd6SBrad Bishop         }
1984e24ebd6SBrad Bishop     }
1994e24ebd6SBrad Bishop 
2004e24ebd6SBrad Bishop     return emptyString;
201613a5b37SBrad Bishop }
202613a5b37SBrad Bishop 
2035c014d2bSMatt Spinler std::string findHwmonFromDevPath(const std::string& devPath)
204626df17aSMatt Spinler {
205626df17aSMatt Spinler     fs::path p{"/sys"};
2065c014d2bSMatt Spinler     p /= fs::path(devPath).relative_path();
207626df17aSMatt Spinler     p /= "hwmon";
208626df17aSMatt Spinler 
209626df17aSMatt Spinler     try
210626df17aSMatt Spinler     {
211626df17aSMatt Spinler         // This path is also used as a filesystem path to an environment
212626df17aSMatt Spinler         // file, and that has issues with ':'s in the path so they've
213626df17aSMatt Spinler         // been converted to '--'s.  Convert them back now.
214626df17aSMatt Spinler         size_t pos = 0;
215626df17aSMatt Spinler         std::string path = p;
216626df17aSMatt Spinler         while ((pos = path.find("--")) != std::string::npos)
217626df17aSMatt Spinler         {
218626df17aSMatt Spinler             path.replace(pos, 2, ":");
219626df17aSMatt Spinler         }
220626df17aSMatt Spinler 
22109560174SPatrick Venture         auto dir_iter = fs::directory_iterator(path);
222*e8771fd4SPatrick Williams         auto hwmonInst = std::find_if(dir_iter, end(dir_iter),
223*e8771fd4SPatrick Williams                                       [](const fs::directory_entry& d) {
22409560174SPatrick Venture             return (d.path().filename().string().find("hwmon") !=
22509560174SPatrick Venture                     std::string::npos);
22609560174SPatrick Venture         });
22709560174SPatrick Venture         if (hwmonInst != end(dir_iter))
228626df17aSMatt Spinler         {
22909560174SPatrick Venture             return hwmonInst->path();
230626df17aSMatt Spinler         }
231626df17aSMatt Spinler     }
232626df17aSMatt Spinler     catch (const std::exception& e)
233626df17aSMatt Spinler     {
234f9aff805SWilliam A. Kennington III         fmt::print(stderr,
235f9aff805SWilliam A. Kennington III                    "Unable to find hwmon directory from the dev path: {}\n",
236f9aff805SWilliam A. Kennington III                    devPath.c_str());
237626df17aSMatt Spinler     }
238626df17aSMatt Spinler     return emptyString;
239626df17aSMatt Spinler }
240626df17aSMatt Spinler 
24175e56c67SPatrick Venture } // namespace sysfs
2428b574a7eSBrad Bishop 
243613a5b37SBrad Bishop // vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
244