xref: /openbmc/phosphor-hwmon/sysfs.cpp (revision 64129937)
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 
18*64129937SPatrick Williams #include <stdplus/print.hpp>
19f9aff805SWilliam A. Kennington III 
20754d38cfSBrad Bishop #include <algorithm>
218b574a7eSBrad Bishop #include <cerrno>
22613a5b37SBrad Bishop #include <cstdlib>
239e997b4dSPatrick Venture #include <filesystem>
24*64129937SPatrick Williams #include <format>
2568c43b21SBrad Bishop #include <fstream>
26f9aff805SWilliam A. Kennington III #include <string>
27613a5b37SBrad Bishop 
28f4bf63adSBrad Bishop using namespace std::string_literals;
299e997b4dSPatrick Venture namespace fs = std::filesystem;
308af8a200SBrandon Wyman 
31043d3230SPatrick Venture namespace sysfs
32043d3230SPatrick Venture {
331e6324faSPatrick Venture 
34f4bf63adSBrad Bishop static const auto emptyString = ""s;
3508379a31SBrad Bishop static constexpr auto ofRoot = "/sys/firmware/devicetree/base";
36613a5b37SBrad Bishop 
findPhandleMatch(const std::string & iochanneldir,const std::string & phandledir)37043d3230SPatrick Venture std::string findPhandleMatch(const std::string& iochanneldir,
388af8a200SBrandon Wyman                              const std::string& phandledir)
39613a5b37SBrad Bishop {
40f4bf63adSBrad Bishop     // TODO: At the moment this method only supports device trees
41f4bf63adSBrad Bishop     // with iio-hwmon nodes with a single sensor.  Typically
42f4bf63adSBrad Bishop     // device trees are defined with all the iio sensors in a
43f4bf63adSBrad Bishop     // single iio-hwmon node so it would be nice to add support
44f4bf63adSBrad Bishop     // for lists of phandles (with variable sized entries) via
45f4bf63adSBrad Bishop     // libfdt or something like that, so that users are not
46f4bf63adSBrad Bishop     // forced into implementing unusual looking device trees
47f4bf63adSBrad Bishop     // with multiple iio-hwmon nodes - one for each sensor.
48f4bf63adSBrad Bishop 
49f4bf63adSBrad Bishop     fs::path ioChannelsPath{iochanneldir};
50f4bf63adSBrad Bishop     ioChannelsPath /= "io-channels";
51f4bf63adSBrad Bishop 
52f4bf63adSBrad Bishop     if (!fs::exists(ioChannelsPath))
53f4bf63adSBrad Bishop     {
54f4bf63adSBrad Bishop         return emptyString;
55f4bf63adSBrad Bishop     }
56f4bf63adSBrad Bishop 
57f4bf63adSBrad Bishop     uint32_t ioChannelsValue;
58f4bf63adSBrad Bishop     std::ifstream ioChannelsFile(ioChannelsPath);
59f4bf63adSBrad Bishop 
60043d3230SPatrick Venture     ioChannelsFile.read(reinterpret_cast<char*>(&ioChannelsValue),
61f4bf63adSBrad Bishop                         sizeof(ioChannelsValue));
62f4bf63adSBrad Bishop 
638af8a200SBrandon Wyman     for (const auto& ofInst : fs::recursive_directory_iterator(phandledir))
64613a5b37SBrad Bishop     {
658af8a200SBrandon Wyman         auto path = ofInst.path();
66f4bf63adSBrad Bishop         if ("phandle" != path.filename())
674eb9858dSBrandon Wyman         {
68f4bf63adSBrad Bishop             continue;
69f4bf63adSBrad Bishop         }
70f4bf63adSBrad Bishop         std::ifstream pHandleFile(path);
714eb9858dSBrandon Wyman         uint32_t pHandleValue;
724eb9858dSBrandon Wyman 
73043d3230SPatrick Venture         pHandleFile.read(reinterpret_cast<char*>(&pHandleValue),
744eb9858dSBrandon Wyman                          sizeof(pHandleValue));
754eb9858dSBrandon Wyman 
764eb9858dSBrandon Wyman         if (ioChannelsValue == pHandleValue)
774eb9858dSBrandon Wyman         {
78f4bf63adSBrad Bishop             return path;
798af8a200SBrandon Wyman         }
808af8a200SBrandon Wyman     }
818af8a200SBrandon Wyman 
82f4bf63adSBrad Bishop     return emptyString;
838af8a200SBrandon Wyman }
848af8a200SBrandon Wyman 
findCalloutPath(const std::string & instancePath)85431d26a5SBrad Bishop std::string findCalloutPath(const std::string& instancePath)
868af8a200SBrandon Wyman {
87431d26a5SBrad Bishop     // Follow the hwmon instance (/sys/class/hwmon/hwmon<N>)
88431d26a5SBrad Bishop     // /sys/devices symlink.
89431d26a5SBrad Bishop     fs::path devPath{instancePath};
90431d26a5SBrad Bishop     devPath /= "device";
918af8a200SBrandon Wyman 
92431d26a5SBrad Bishop     try
938af8a200SBrandon Wyman     {
94431d26a5SBrad Bishop         devPath = fs::canonical(devPath);
95431d26a5SBrad Bishop     }
96431d26a5SBrad Bishop     catch (const std::system_error& e)
97431d26a5SBrad Bishop     {
98431d26a5SBrad Bishop         return emptyString;
99431d26a5SBrad Bishop     }
100431d26a5SBrad Bishop 
101431d26a5SBrad Bishop     // See if the device is backed by the iio-hwmon driver.
102431d26a5SBrad Bishop     fs::path p{devPath};
103431d26a5SBrad Bishop     p /= "driver";
104431d26a5SBrad Bishop     p = fs::canonical(p);
105431d26a5SBrad Bishop 
106431d26a5SBrad Bishop     if (p.filename() != "iio_hwmon")
107431d26a5SBrad Bishop     {
108431d26a5SBrad Bishop         // Not backed by iio-hwmon.  The device pointed to
109431d26a5SBrad Bishop         // is the callout device.
110431d26a5SBrad Bishop         return devPath;
111431d26a5SBrad Bishop     }
112431d26a5SBrad Bishop 
113431d26a5SBrad Bishop     // Find the DT path to the iio-hwmon platform device.
114431d26a5SBrad Bishop     fs::path ofDevPath{devPath};
115431d26a5SBrad Bishop     ofDevPath /= "of_node";
116431d26a5SBrad Bishop 
117431d26a5SBrad Bishop     try
118431d26a5SBrad Bishop     {
119431d26a5SBrad Bishop         ofDevPath = fs::canonical(ofDevPath);
120431d26a5SBrad Bishop     }
121431d26a5SBrad Bishop     catch (const std::system_error& e)
122431d26a5SBrad Bishop     {
123431d26a5SBrad Bishop         return emptyString;
124431d26a5SBrad Bishop     }
125431d26a5SBrad Bishop 
126431d26a5SBrad Bishop     // Search /sys/bus/iio/devices for the phandle in io-channels.
127431d26a5SBrad Bishop     // If a match is found, use the corresponding /sys/devices
128431d26a5SBrad Bishop     // iio device as the callout device.
129431d26a5SBrad Bishop     static constexpr auto iioDevices = "/sys/bus/iio/devices";
130431d26a5SBrad Bishop     for (const auto& iioDev : fs::recursive_directory_iterator(iioDevices))
131431d26a5SBrad Bishop     {
132431d26a5SBrad Bishop         p = iioDev.path();
133431d26a5SBrad Bishop         p /= "of_node";
134431d26a5SBrad Bishop 
135431d26a5SBrad Bishop         try
136431d26a5SBrad Bishop         {
137431d26a5SBrad Bishop             p = fs::canonical(p);
138431d26a5SBrad Bishop         }
139431d26a5SBrad Bishop         catch (const std::system_error& e)
140431d26a5SBrad Bishop         {
141431d26a5SBrad Bishop             continue;
142431d26a5SBrad Bishop         }
143431d26a5SBrad Bishop 
144431d26a5SBrad Bishop         auto match = findPhandleMatch(ofDevPath, p);
145431d26a5SBrad Bishop         auto n = match.rfind('/');
1468af8a200SBrandon Wyman         if (n != std::string::npos)
1478af8a200SBrandon Wyman         {
148431d26a5SBrad Bishop             // This is the iio device referred to by io-channels.
149431d26a5SBrad Bishop             // Remove iio:device<N>.
150431d26a5SBrad Bishop             try
151431d26a5SBrad Bishop             {
152431d26a5SBrad Bishop                 return fs::canonical(iioDev).parent_path();
153431d26a5SBrad Bishop             }
154431d26a5SBrad Bishop             catch (const std::system_error& e)
155431d26a5SBrad Bishop             {
156431d26a5SBrad Bishop                 return emptyString;
157431d26a5SBrad Bishop             }
1588af8a200SBrandon Wyman         }
1598af8a200SBrandon Wyman     }
1608af8a200SBrandon Wyman 
161431d26a5SBrad Bishop     return emptyString;
1628af8a200SBrandon Wyman }
1638af8a200SBrandon Wyman 
findHwmonFromOFPath(const std::string & ofNode)1645c014d2bSMatt Spinler std::string findHwmonFromOFPath(const std::string& ofNode)
1658af8a200SBrandon Wyman {
1668af8a200SBrandon Wyman     static constexpr auto hwmonRoot = "/sys/class/hwmon";
1678af8a200SBrandon Wyman 
1685c014d2bSMatt Spinler     auto fullOfPath = fs::path(ofRoot) / fs::path(ofNode).relative_path();
1698af8a200SBrandon Wyman 
1708af8a200SBrandon Wyman     for (const auto& hwmonInst : fs::directory_iterator(hwmonRoot))
1718af8a200SBrandon Wyman     {
1728af8a200SBrandon Wyman         auto path = hwmonInst.path();
1738af8a200SBrandon Wyman         path /= "of_node";
1744e24ebd6SBrad Bishop 
1754e24ebd6SBrad Bishop         try
1768af8a200SBrandon Wyman         {
1774e24ebd6SBrad Bishop             path = fs::canonical(path);
1788af8a200SBrandon Wyman         }
1794e24ebd6SBrad Bishop         catch (const std::system_error& e)
1808af8a200SBrandon Wyman         {
1814e24ebd6SBrad Bishop             // realpath may encounter ENOENT (Hwmon
1824e24ebd6SBrad Bishop             // instances have a nasty habit of
1834e24ebd6SBrad Bishop             // going away without warning).
1848af8a200SBrandon Wyman             continue;
1858af8a200SBrandon Wyman         }
1868af8a200SBrandon Wyman 
1874e24ebd6SBrad Bishop         if (path == fullOfPath)
1884e24ebd6SBrad Bishop         {
18908379a31SBrad Bishop             return hwmonInst.path();
190613a5b37SBrad Bishop         }
191613a5b37SBrad Bishop 
1924e24ebd6SBrad Bishop         // Try to find HWMON instance via phandle values.
1934e24ebd6SBrad Bishop         // Used for IIO device drivers.
1944e24ebd6SBrad Bishop         auto matchpath = findPhandleMatch(path, fullOfPath);
1954e24ebd6SBrad Bishop         if (!matchpath.empty())
1964e24ebd6SBrad Bishop         {
1974e24ebd6SBrad Bishop             return hwmonInst.path();
1984e24ebd6SBrad Bishop         }
1994e24ebd6SBrad Bishop     }
2004e24ebd6SBrad Bishop 
2014e24ebd6SBrad Bishop     return emptyString;
202613a5b37SBrad Bishop }
203613a5b37SBrad Bishop 
findHwmonFromDevPath(const std::string & devPath)2045c014d2bSMatt Spinler std::string findHwmonFromDevPath(const std::string& devPath)
205626df17aSMatt Spinler {
206626df17aSMatt Spinler     fs::path p{"/sys"};
2075c014d2bSMatt Spinler     p /= fs::path(devPath).relative_path();
208626df17aSMatt Spinler     p /= "hwmon";
209626df17aSMatt Spinler 
210626df17aSMatt Spinler     try
211626df17aSMatt Spinler     {
212626df17aSMatt Spinler         // This path is also used as a filesystem path to an environment
213626df17aSMatt Spinler         // file, and that has issues with ':'s in the path so they've
214626df17aSMatt Spinler         // been converted to '--'s.  Convert them back now.
215626df17aSMatt Spinler         size_t pos = 0;
216626df17aSMatt Spinler         std::string path = p;
217626df17aSMatt Spinler         while ((pos = path.find("--")) != std::string::npos)
218626df17aSMatt Spinler         {
219626df17aSMatt Spinler             path.replace(pos, 2, ":");
220626df17aSMatt Spinler         }
221626df17aSMatt Spinler 
22209560174SPatrick Venture         auto dir_iter = fs::directory_iterator(path);
223e8771fd4SPatrick Williams         auto hwmonInst = std::find_if(dir_iter, end(dir_iter),
224e8771fd4SPatrick Williams                                       [](const fs::directory_entry& d) {
22509560174SPatrick Venture             return (d.path().filename().string().find("hwmon") !=
22609560174SPatrick Venture                     std::string::npos);
22709560174SPatrick Venture         });
22809560174SPatrick Venture         if (hwmonInst != end(dir_iter))
229626df17aSMatt Spinler         {
23009560174SPatrick Venture             return hwmonInst->path();
231626df17aSMatt Spinler         }
232626df17aSMatt Spinler     }
233626df17aSMatt Spinler     catch (const std::exception& e)
234626df17aSMatt Spinler     {
235*64129937SPatrick Williams         stdplus::print(stderr,
236f9aff805SWilliam A. Kennington III                        "Unable to find hwmon directory from the dev path: {}\n",
237f9aff805SWilliam A. Kennington III                        devPath.c_str());
238626df17aSMatt Spinler     }
239626df17aSMatt Spinler     return emptyString;
240626df17aSMatt Spinler }
241626df17aSMatt Spinler 
24275e56c67SPatrick Venture } // namespace sysfs
2438b574a7eSBrad Bishop 
244613a5b37SBrad Bishop // vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
245