blob: 09fc26bf3a63c5c6e4cc30930bd76d2f5253e82f [file] [log] [blame]
Brad Bishop613a5b32017-01-05 20:58:13 -05001/**
2 * Copyright © 2016 IBM Corporation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Patrick Venture043d3232018-08-31 10:10:53 -070016#include "config.h"
17
18#include "sysfs.hpp"
19
Brad Bishop754d38c2017-09-08 00:46:58 -040020#include <algorithm>
Brad Bishop8b574a72017-08-25 16:17:19 -040021#include <cerrno>
Brad Bishop613a5b32017-01-05 20:58:13 -050022#include <cstdlib>
Patrick Venture9e997b42019-03-08 13:42:10 -080023#include <filesystem>
Brad Bishop68c43b22017-08-28 16:24:00 -040024#include <fstream>
Brad Bishop613a5b32017-01-05 20:58:13 -050025#include <memory>
Matt Spinler626df172018-03-05 12:03:55 -060026#include <phosphor-logging/log.hpp>
Brad Bishop754d38c2017-09-08 00:46:58 -040027#include <thread>
Brad Bishop613a5b32017-01-05 20:58:13 -050028
Brad Bishopf4bf63a2017-08-28 15:39:19 -040029using namespace std::string_literals;
Patrick Venture9e997b42019-03-08 13:42:10 -080030namespace fs = std::filesystem;
Matthew Barth048ac872017-03-09 14:36:08 -060031
Patrick Venture043d3232018-08-31 10:10:53 -070032namespace sysfs
33{
Patrick Venture1e6324f2017-06-01 14:07:05 -070034
Brad Bishopf4bf63a2017-08-28 15:39:19 -040035static const auto emptyString = ""s;
Brandon Wyman8af8a202017-05-31 18:26:30 -050036static constexpr auto ofRoot = "/sys/firmware/devicetree/base";
37
Patrick Venture043d3232018-08-31 10:10:53 -070038std::string findPhandleMatch(const std::string& iochanneldir,
39 const std::string& phandledir)
Brad Bishop613a5b32017-01-05 20:58:13 -050040{
Brad Bishopf4bf63a2017-08-28 15:39:19 -040041 // TODO: At the moment this method only supports device trees
42 // with iio-hwmon nodes with a single sensor. Typically
43 // device trees are defined with all the iio sensors in a
44 // single iio-hwmon node so it would be nice to add support
45 // for lists of phandles (with variable sized entries) via
46 // libfdt or something like that, so that users are not
47 // forced into implementing unusual looking device trees
48 // with multiple iio-hwmon nodes - one for each sensor.
49
50 fs::path ioChannelsPath{iochanneldir};
51 ioChannelsPath /= "io-channels";
52
53 if (!fs::exists(ioChannelsPath))
54 {
55 return emptyString;
56 }
57
58 uint32_t ioChannelsValue;
59 std::ifstream ioChannelsFile(ioChannelsPath);
60
Patrick Venture043d3232018-08-31 10:10:53 -070061 ioChannelsFile.read(reinterpret_cast<char*>(&ioChannelsValue),
62 sizeof(ioChannelsValue));
Brad Bishopf4bf63a2017-08-28 15:39:19 -040063
Brandon Wyman8af8a202017-05-31 18:26:30 -050064 for (const auto& ofInst : fs::recursive_directory_iterator(phandledir))
Brad Bishop613a5b32017-01-05 20:58:13 -050065 {
Brandon Wyman8af8a202017-05-31 18:26:30 -050066 auto path = ofInst.path();
Brad Bishopf4bf63a2017-08-28 15:39:19 -040067 if ("phandle" != path.filename())
Brad Bishop613a5b32017-01-05 20:58:13 -050068 {
Brad Bishopf4bf63a2017-08-28 15:39:19 -040069 continue;
70 }
71 std::ifstream pHandleFile(path);
72 uint32_t pHandleValue;
Brandon Wyman4eb98582017-05-24 14:24:00 -050073
Patrick Venture043d3232018-08-31 10:10:53 -070074 pHandleFile.read(reinterpret_cast<char*>(&pHandleValue),
75 sizeof(pHandleValue));
Brandon Wyman4eb98582017-05-24 14:24:00 -050076
Brad Bishopf4bf63a2017-08-28 15:39:19 -040077 if (ioChannelsValue == pHandleValue)
78 {
79 return path;
Brandon Wyman8af8a202017-05-31 18:26:30 -050080 }
81 }
82
Brad Bishopf4bf63a2017-08-28 15:39:19 -040083 return emptyString;
Brandon Wyman8af8a202017-05-31 18:26:30 -050084}
85
Brad Bishop431d26a2017-08-25 09:47:58 -040086std::string findCalloutPath(const std::string& instancePath)
Brandon Wyman8af8a202017-05-31 18:26:30 -050087{
Brad Bishop431d26a2017-08-25 09:47:58 -040088 // Follow the hwmon instance (/sys/class/hwmon/hwmon<N>)
89 // /sys/devices symlink.
90 fs::path devPath{instancePath};
91 devPath /= "device";
Brandon Wyman8af8a202017-05-31 18:26:30 -050092
Brad Bishop431d26a2017-08-25 09:47:58 -040093 try
Brandon Wyman8af8a202017-05-31 18:26:30 -050094 {
Brad Bishop431d26a2017-08-25 09:47:58 -040095 devPath = fs::canonical(devPath);
96 }
97 catch (const std::system_error& e)
98 {
99 return emptyString;
100 }
101
102 // See if the device is backed by the iio-hwmon driver.
103 fs::path p{devPath};
104 p /= "driver";
105 p = fs::canonical(p);
106
107 if (p.filename() != "iio_hwmon")
108 {
109 // Not backed by iio-hwmon. The device pointed to
110 // is the callout device.
111 return devPath;
112 }
113
114 // Find the DT path to the iio-hwmon platform device.
115 fs::path ofDevPath{devPath};
116 ofDevPath /= "of_node";
117
118 try
119 {
120 ofDevPath = fs::canonical(ofDevPath);
121 }
122 catch (const std::system_error& e)
123 {
124 return emptyString;
125 }
126
127 // Search /sys/bus/iio/devices for the phandle in io-channels.
128 // If a match is found, use the corresponding /sys/devices
129 // iio device as the callout device.
130 static constexpr auto iioDevices = "/sys/bus/iio/devices";
Patrick Venture043d3232018-08-31 10:10:53 -0700131 for (const auto& iioDev : fs::recursive_directory_iterator(iioDevices))
Brad Bishop431d26a2017-08-25 09:47:58 -0400132 {
133 p = iioDev.path();
134 p /= "of_node";
135
136 try
137 {
138 p = fs::canonical(p);
139 }
140 catch (const std::system_error& e)
141 {
142 continue;
143 }
144
145 auto match = findPhandleMatch(ofDevPath, p);
146 auto n = match.rfind('/');
Brandon Wyman8af8a202017-05-31 18:26:30 -0500147 if (n != std::string::npos)
148 {
Brad Bishop431d26a2017-08-25 09:47:58 -0400149 // This is the iio device referred to by io-channels.
150 // Remove iio:device<N>.
151 try
152 {
153 return fs::canonical(iioDev).parent_path();
154 }
155 catch (const std::system_error& e)
156 {
157 return emptyString;
158 }
Brandon Wyman8af8a202017-05-31 18:26:30 -0500159 }
160 }
161
Brad Bishop431d26a2017-08-25 09:47:58 -0400162 return emptyString;
Brandon Wyman8af8a202017-05-31 18:26:30 -0500163}
164
Matt Spinler85ba64a2019-03-15 12:29:26 -0500165std::string findHwmonFromOFPath(std::string ofNode)
Brandon Wyman8af8a202017-05-31 18:26:30 -0500166{
167 static constexpr auto hwmonRoot = "/sys/class/hwmon";
168
Matt Spinler85ba64a2019-03-15 12:29:26 -0500169 // Can't append an absolute path
170 if (!ofNode.empty() && (ofNode.front() == '/'))
171 {
172 ofNode = ofNode.substr(1);
173 }
174
Brandon Wyman8af8a202017-05-31 18:26:30 -0500175 fs::path fullOfPath{ofRoot};
176 fullOfPath /= ofNode;
177
178 for (const auto& hwmonInst : fs::directory_iterator(hwmonRoot))
179 {
180 auto path = hwmonInst.path();
181 path /= "of_node";
Brad Bishop4e24ebd2017-08-28 16:19:16 -0400182
183 try
Brandon Wyman8af8a202017-05-31 18:26:30 -0500184 {
Brad Bishop4e24ebd2017-08-28 16:19:16 -0400185 path = fs::canonical(path);
186 }
187 catch (const std::system_error& e)
188 {
189 // realpath may encounter ENOENT (Hwmon
190 // instances have a nasty habit of
191 // going away without warning).
192 continue;
Brad Bishop613a5b32017-01-05 20:58:13 -0500193 }
194
Brad Bishop4e24ebd2017-08-28 16:19:16 -0400195 if (path == fullOfPath)
196 {
197 return hwmonInst.path();
198 }
199
200 // Try to find HWMON instance via phandle values.
201 // Used for IIO device drivers.
202 auto matchpath = findPhandleMatch(path, fullOfPath);
203 if (!matchpath.empty())
204 {
205 return hwmonInst.path();
206 }
Brad Bishop613a5b32017-01-05 20:58:13 -0500207 }
208
Brad Bishop4e24ebd2017-08-28 16:19:16 -0400209 return emptyString;
Brad Bishop613a5b32017-01-05 20:58:13 -0500210}
211
Matt Spinler85ba64a2019-03-15 12:29:26 -0500212std::string findHwmonFromDevPath(std::string devPath)
Matt Spinler626df172018-03-05 12:03:55 -0600213{
Matt Spinler85ba64a2019-03-15 12:29:26 -0500214 // Can't append an absolute path
215 if (!devPath.empty() && devPath.front() == '/')
216 {
217 devPath = devPath.substr(1);
218 }
219
Matt Spinler626df172018-03-05 12:03:55 -0600220 fs::path p{"/sys"};
221 p /= devPath;
222 p /= "hwmon";
223
224 try
225 {
Patrick Venture043d3232018-08-31 10:10:53 -0700226 // This path is also used as a filesystem path to an environment
227 // file, and that has issues with ':'s in the path so they've
228 // been converted to '--'s. Convert them back now.
Matt Spinler626df172018-03-05 12:03:55 -0600229 size_t pos = 0;
230 std::string path = p;
231 while ((pos = path.find("--")) != std::string::npos)
232 {
233 path.replace(pos, 2, ":");
234 }
235
Patrick Venture09560172018-10-13 13:25:15 -0700236 auto dir_iter = fs::directory_iterator(path);
237 auto hwmonInst = std::find_if(
238 dir_iter, end(dir_iter), [](const fs::directory_entry& d) {
239 return (d.path().filename().string().find("hwmon") !=
240 std::string::npos);
241 });
242 if (hwmonInst != end(dir_iter))
Matt Spinler626df172018-03-05 12:03:55 -0600243 {
Patrick Venture09560172018-10-13 13:25:15 -0700244 return hwmonInst->path();
Matt Spinler626df172018-03-05 12:03:55 -0600245 }
246 }
247 catch (const std::exception& e)
248 {
249 using namespace phosphor::logging;
Patrick Venture043d3232018-08-31 10:10:53 -0700250 log<level::ERR>("Unable to find hwmon directory from the dev path",
251 entry("PATH=%s", devPath.c_str()));
Matt Spinler626df172018-03-05 12:03:55 -0600252 }
253 return emptyString;
254}
255
Patrick Venture75e56c62018-04-20 18:10:15 -0700256} // namespace sysfs
Brad Bishop8b574a72017-08-25 16:17:19 -0400257
Brad Bishop613a5b32017-01-05 20:58:13 -0500258// vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4