xref: /openbmc/phosphor-hwmon/sysfs.cpp (revision 043d32306e00484afc446a44789b61869ea14f84)
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  */
16*043d3230SPatrick Venture #include "config.h"
17*043d3230SPatrick Venture 
18*043d3230SPatrick Venture #include "sysfs.hpp"
19*043d3230SPatrick Venture 
20754d38cfSBrad Bishop #include <algorithm>
218b574a7eSBrad Bishop #include <cerrno>
22613a5b37SBrad Bishop #include <cstdlib>
2308379a31SBrad Bishop #include <experimental/filesystem>
2468c43b21SBrad Bishop #include <fstream>
25613a5b37SBrad Bishop #include <memory>
26626df17aSMatt Spinler #include <phosphor-logging/log.hpp>
27754d38cfSBrad Bishop #include <thread>
28613a5b37SBrad Bishop 
29f4bf63adSBrad Bishop using namespace std::string_literals;
3008379a31SBrad Bishop namespace fs = std::experimental::filesystem;
318af8a200SBrandon Wyman 
32*043d3230SPatrick Venture namespace sysfs
33*043d3230SPatrick Venture {
341e6324faSPatrick Venture 
35f4bf63adSBrad Bishop static const auto emptyString = ""s;
3608379a31SBrad Bishop static constexpr auto ofRoot = "/sys/firmware/devicetree/base";
37613a5b37SBrad Bishop 
38*043d3230SPatrick Venture std::string findPhandleMatch(const std::string& iochanneldir,
398af8a200SBrandon Wyman                              const std::string& phandledir)
40613a5b37SBrad Bishop {
41f4bf63adSBrad Bishop     // TODO: At the moment this method only supports device trees
42f4bf63adSBrad Bishop     // with iio-hwmon nodes with a single sensor.  Typically
43f4bf63adSBrad Bishop     // device trees are defined with all the iio sensors in a
44f4bf63adSBrad Bishop     // single iio-hwmon node so it would be nice to add support
45f4bf63adSBrad Bishop     // for lists of phandles (with variable sized entries) via
46f4bf63adSBrad Bishop     // libfdt or something like that, so that users are not
47f4bf63adSBrad Bishop     // forced into implementing unusual looking device trees
48f4bf63adSBrad Bishop     // with multiple iio-hwmon nodes - one for each sensor.
49f4bf63adSBrad Bishop 
50f4bf63adSBrad Bishop     fs::path ioChannelsPath{iochanneldir};
51f4bf63adSBrad Bishop     ioChannelsPath /= "io-channels";
52f4bf63adSBrad Bishop 
53f4bf63adSBrad Bishop     if (!fs::exists(ioChannelsPath))
54f4bf63adSBrad Bishop     {
55f4bf63adSBrad Bishop         return emptyString;
56f4bf63adSBrad Bishop     }
57f4bf63adSBrad Bishop 
58f4bf63adSBrad Bishop     uint32_t ioChannelsValue;
59f4bf63adSBrad Bishop     std::ifstream ioChannelsFile(ioChannelsPath);
60f4bf63adSBrad Bishop 
61*043d3230SPatrick Venture     ioChannelsFile.read(reinterpret_cast<char*>(&ioChannelsValue),
62f4bf63adSBrad Bishop                         sizeof(ioChannelsValue));
63f4bf63adSBrad Bishop 
648af8a200SBrandon Wyman     for (const auto& ofInst : fs::recursive_directory_iterator(phandledir))
65613a5b37SBrad Bishop     {
668af8a200SBrandon Wyman         auto path = ofInst.path();
67f4bf63adSBrad Bishop         if ("phandle" != path.filename())
684eb9858dSBrandon Wyman         {
69f4bf63adSBrad Bishop             continue;
70f4bf63adSBrad Bishop         }
71f4bf63adSBrad Bishop         std::ifstream pHandleFile(path);
724eb9858dSBrandon Wyman         uint32_t pHandleValue;
734eb9858dSBrandon Wyman 
74*043d3230SPatrick Venture         pHandleFile.read(reinterpret_cast<char*>(&pHandleValue),
754eb9858dSBrandon Wyman                          sizeof(pHandleValue));
764eb9858dSBrandon Wyman 
774eb9858dSBrandon Wyman         if (ioChannelsValue == pHandleValue)
784eb9858dSBrandon Wyman         {
79f4bf63adSBrad Bishop             return path;
808af8a200SBrandon Wyman         }
818af8a200SBrandon Wyman     }
828af8a200SBrandon Wyman 
83f4bf63adSBrad Bishop     return emptyString;
848af8a200SBrandon Wyman }
858af8a200SBrandon Wyman 
86431d26a5SBrad Bishop std::string findCalloutPath(const std::string& instancePath)
878af8a200SBrandon Wyman {
88431d26a5SBrad Bishop     // Follow the hwmon instance (/sys/class/hwmon/hwmon<N>)
89431d26a5SBrad Bishop     // /sys/devices symlink.
90431d26a5SBrad Bishop     fs::path devPath{instancePath};
91431d26a5SBrad Bishop     devPath /= "device";
928af8a200SBrandon Wyman 
93431d26a5SBrad Bishop     try
948af8a200SBrandon Wyman     {
95431d26a5SBrad Bishop         devPath = fs::canonical(devPath);
96431d26a5SBrad Bishop     }
97431d26a5SBrad Bishop     catch (const std::system_error& e)
98431d26a5SBrad Bishop     {
99431d26a5SBrad Bishop         return emptyString;
100431d26a5SBrad Bishop     }
101431d26a5SBrad Bishop 
102431d26a5SBrad Bishop     // See if the device is backed by the iio-hwmon driver.
103431d26a5SBrad Bishop     fs::path p{devPath};
104431d26a5SBrad Bishop     p /= "driver";
105431d26a5SBrad Bishop     p = fs::canonical(p);
106431d26a5SBrad Bishop 
107431d26a5SBrad Bishop     if (p.filename() != "iio_hwmon")
108431d26a5SBrad Bishop     {
109431d26a5SBrad Bishop         // Not backed by iio-hwmon.  The device pointed to
110431d26a5SBrad Bishop         // is the callout device.
111431d26a5SBrad Bishop         return devPath;
112431d26a5SBrad Bishop     }
113431d26a5SBrad Bishop 
114431d26a5SBrad Bishop     // Find the DT path to the iio-hwmon platform device.
115431d26a5SBrad Bishop     fs::path ofDevPath{devPath};
116431d26a5SBrad Bishop     ofDevPath /= "of_node";
117431d26a5SBrad Bishop 
118431d26a5SBrad Bishop     try
119431d26a5SBrad Bishop     {
120431d26a5SBrad Bishop         ofDevPath = fs::canonical(ofDevPath);
121431d26a5SBrad Bishop     }
122431d26a5SBrad Bishop     catch (const std::system_error& e)
123431d26a5SBrad Bishop     {
124431d26a5SBrad Bishop         return emptyString;
125431d26a5SBrad Bishop     }
126431d26a5SBrad Bishop 
127431d26a5SBrad Bishop     // Search /sys/bus/iio/devices for the phandle in io-channels.
128431d26a5SBrad Bishop     // If a match is found, use the corresponding /sys/devices
129431d26a5SBrad Bishop     // iio device as the callout device.
130431d26a5SBrad Bishop     static constexpr auto iioDevices = "/sys/bus/iio/devices";
131431d26a5SBrad Bishop     for (const auto& iioDev : fs::recursive_directory_iterator(iioDevices))
132431d26a5SBrad Bishop     {
133431d26a5SBrad Bishop         p = iioDev.path();
134431d26a5SBrad Bishop         p /= "of_node";
135431d26a5SBrad Bishop 
136431d26a5SBrad Bishop         try
137431d26a5SBrad Bishop         {
138431d26a5SBrad Bishop             p = fs::canonical(p);
139431d26a5SBrad Bishop         }
140431d26a5SBrad Bishop         catch (const std::system_error& e)
141431d26a5SBrad Bishop         {
142431d26a5SBrad Bishop             continue;
143431d26a5SBrad Bishop         }
144431d26a5SBrad Bishop 
145431d26a5SBrad Bishop         auto match = findPhandleMatch(ofDevPath, p);
146431d26a5SBrad Bishop         auto n = match.rfind('/');
1478af8a200SBrandon Wyman         if (n != std::string::npos)
1488af8a200SBrandon Wyman         {
149431d26a5SBrad Bishop             // This is the iio device referred to by io-channels.
150431d26a5SBrad Bishop             // Remove iio:device<N>.
151431d26a5SBrad Bishop             try
152431d26a5SBrad Bishop             {
153431d26a5SBrad Bishop                 return fs::canonical(iioDev).parent_path();
154431d26a5SBrad Bishop             }
155431d26a5SBrad Bishop             catch (const std::system_error& e)
156431d26a5SBrad Bishop             {
157431d26a5SBrad Bishop                 return emptyString;
158431d26a5SBrad Bishop             }
1598af8a200SBrandon Wyman         }
1608af8a200SBrandon Wyman     }
1618af8a200SBrandon Wyman 
162431d26a5SBrad Bishop     return emptyString;
1638af8a200SBrandon Wyman }
1648af8a200SBrandon Wyman 
16531dbe062SMatt Spinler std::string findHwmonFromOFPath(const std::string& ofNode)
1668af8a200SBrandon Wyman {
1678af8a200SBrandon Wyman     static constexpr auto hwmonRoot = "/sys/class/hwmon";
1688af8a200SBrandon Wyman 
1698af8a200SBrandon Wyman     fs::path fullOfPath{ofRoot};
1708af8a200SBrandon Wyman     fullOfPath /= ofNode;
1718af8a200SBrandon Wyman 
1728af8a200SBrandon Wyman     for (const auto& hwmonInst : fs::directory_iterator(hwmonRoot))
1738af8a200SBrandon Wyman     {
1748af8a200SBrandon Wyman         auto path = hwmonInst.path();
1758af8a200SBrandon Wyman         path /= "of_node";
1764e24ebd6SBrad Bishop 
1774e24ebd6SBrad Bishop         try
1788af8a200SBrandon Wyman         {
1794e24ebd6SBrad Bishop             path = fs::canonical(path);
1808af8a200SBrandon Wyman         }
1814e24ebd6SBrad Bishop         catch (const std::system_error& e)
1828af8a200SBrandon Wyman         {
1834e24ebd6SBrad Bishop             // realpath may encounter ENOENT (Hwmon
1844e24ebd6SBrad Bishop             // instances have a nasty habit of
1854e24ebd6SBrad Bishop             // going away without warning).
1868af8a200SBrandon Wyman             continue;
1878af8a200SBrandon Wyman         }
1888af8a200SBrandon Wyman 
1894e24ebd6SBrad Bishop         if (path == fullOfPath)
1904e24ebd6SBrad Bishop         {
19108379a31SBrad Bishop             return hwmonInst.path();
192613a5b37SBrad Bishop         }
193613a5b37SBrad Bishop 
1944e24ebd6SBrad Bishop         // Try to find HWMON instance via phandle values.
1954e24ebd6SBrad Bishop         // Used for IIO device drivers.
1964e24ebd6SBrad Bishop         auto matchpath = findPhandleMatch(path, fullOfPath);
1974e24ebd6SBrad Bishop         if (!matchpath.empty())
1984e24ebd6SBrad Bishop         {
1994e24ebd6SBrad Bishop             return hwmonInst.path();
2004e24ebd6SBrad Bishop         }
2014e24ebd6SBrad Bishop     }
2024e24ebd6SBrad Bishop 
2034e24ebd6SBrad Bishop     return emptyString;
204613a5b37SBrad Bishop }
205613a5b37SBrad Bishop 
206626df17aSMatt Spinler std::string findHwmonFromDevPath(const std::string& devPath)
207626df17aSMatt Spinler {
208626df17aSMatt Spinler     fs::path p{"/sys"};
209626df17aSMatt Spinler     p /= devPath;
210626df17aSMatt Spinler     p /= "hwmon";
211626df17aSMatt Spinler 
212626df17aSMatt Spinler     try
213626df17aSMatt Spinler     {
214626df17aSMatt Spinler         // This path is also used as a filesystem path to an environment
215626df17aSMatt Spinler         // file, and that has issues with ':'s in the path so they've
216626df17aSMatt Spinler         // been converted to '--'s.  Convert them back now.
217626df17aSMatt Spinler         size_t pos = 0;
218626df17aSMatt Spinler         std::string path = p;
219626df17aSMatt Spinler         while ((pos = path.find("--")) != std::string::npos)
220626df17aSMatt Spinler         {
221626df17aSMatt Spinler             path.replace(pos, 2, ":");
222626df17aSMatt Spinler         }
223626df17aSMatt Spinler 
224626df17aSMatt Spinler         for (const auto& hwmonInst : fs::directory_iterator(path))
225626df17aSMatt Spinler         {
226626df17aSMatt Spinler             if ((hwmonInst.path().filename().string().find("hwmon") !=
227626df17aSMatt Spinler                  std::string::npos))
228626df17aSMatt Spinler             {
229626df17aSMatt Spinler                 return hwmonInst.path();
230626df17aSMatt Spinler             }
231626df17aSMatt Spinler         }
232626df17aSMatt Spinler     }
233626df17aSMatt Spinler     catch (const std::exception& e)
234626df17aSMatt Spinler     {
235626df17aSMatt Spinler         using namespace phosphor::logging;
236*043d3230SPatrick Venture         log<level::ERR>("Unable to find hwmon directory from the dev path",
237626df17aSMatt Spinler                         entry("PATH=%s", 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