blob: d48448ff05768ee787dd074330454dfcb546f83f [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 "sysfs.hpp"
17
Willy Tudd7b3882026-01-06 23:01:47 +000018#include <phosphor-logging/lg2.hpp>
William A. Kennington IIIf9aff802021-05-05 12:06:24 -070019
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>
Patrick Williams64129932024-02-13 21:10:17 -060024#include <format>
Brad Bishop68c43b22017-08-28 16:24:00 -040025#include <fstream>
William A. Kennington IIIf9aff802021-05-05 12:06:24 -070026#include <string>
Brad Bishop613a5b32017-01-05 20:58:13 -050027
Brad Bishopf4bf63a2017-08-28 15:39:19 -040028using namespace std::string_literals;
Patrick Venture9e997b42019-03-08 13:42:10 -080029namespace fs = std::filesystem;
Matthew Barth048ac872017-03-09 14:36:08 -060030
Patrick Venture043d3232018-08-31 10:10:53 -070031namespace sysfs
32{
Patrick Venture1e6324f2017-06-01 14:07:05 -070033
Brad Bishopf4bf63a2017-08-28 15:39:19 -040034static const auto emptyString = ""s;
Brandon Wyman8af8a202017-05-31 18:26:30 -050035static constexpr auto ofRoot = "/sys/firmware/devicetree/base";
36
Patrick Venture043d3232018-08-31 10:10:53 -070037std::string findPhandleMatch(const std::string& iochanneldir,
38 const std::string& phandledir)
Brad Bishop613a5b32017-01-05 20:58:13 -050039{
Brad Bishopf4bf63a2017-08-28 15:39:19 -040040 // TODO: At the moment this method only supports device trees
41 // with iio-hwmon nodes with a single sensor. Typically
42 // device trees are defined with all the iio sensors in a
43 // single iio-hwmon node so it would be nice to add support
44 // for lists of phandles (with variable sized entries) via
45 // libfdt or something like that, so that users are not
46 // forced into implementing unusual looking device trees
47 // with multiple iio-hwmon nodes - one for each sensor.
48
49 fs::path ioChannelsPath{iochanneldir};
50 ioChannelsPath /= "io-channels";
51
52 if (!fs::exists(ioChannelsPath))
53 {
54 return emptyString;
55 }
56
57 uint32_t ioChannelsValue;
58 std::ifstream ioChannelsFile(ioChannelsPath);
59
Patrick Venture043d3232018-08-31 10:10:53 -070060 ioChannelsFile.read(reinterpret_cast<char*>(&ioChannelsValue),
61 sizeof(ioChannelsValue));
Brad Bishopf4bf63a2017-08-28 15:39:19 -040062
Willy Tudd7b3882026-01-06 23:01:47 +000063 std::error_code ec;
64 fs::recursive_directory_iterator it(phandledir, ec);
65 if (ec)
66 {
67 lg2::error("Unable to run recursive_directory_iterator: {ERR}", "ERR",
68 ec.message());
69 return emptyString;
70 }
71 for (const auto& ofInst : it)
Brad Bishop613a5b32017-01-05 20:58:13 -050072 {
Brandon Wyman8af8a202017-05-31 18:26:30 -050073 auto path = ofInst.path();
Brad Bishopf4bf63a2017-08-28 15:39:19 -040074 if ("phandle" != path.filename())
Brad Bishop613a5b32017-01-05 20:58:13 -050075 {
Brad Bishopf4bf63a2017-08-28 15:39:19 -040076 continue;
77 }
78 std::ifstream pHandleFile(path);
79 uint32_t pHandleValue;
Brandon Wyman4eb98582017-05-24 14:24:00 -050080
Patrick Venture043d3232018-08-31 10:10:53 -070081 pHandleFile.read(reinterpret_cast<char*>(&pHandleValue),
82 sizeof(pHandleValue));
Brandon Wyman4eb98582017-05-24 14:24:00 -050083
Brad Bishopf4bf63a2017-08-28 15:39:19 -040084 if (ioChannelsValue == pHandleValue)
85 {
86 return path;
Brandon Wyman8af8a202017-05-31 18:26:30 -050087 }
88 }
89
Brad Bishopf4bf63a2017-08-28 15:39:19 -040090 return emptyString;
Brandon Wyman8af8a202017-05-31 18:26:30 -050091}
92
Brad Bishop431d26a2017-08-25 09:47:58 -040093std::string findCalloutPath(const std::string& instancePath)
Brandon Wyman8af8a202017-05-31 18:26:30 -050094{
Brad Bishop431d26a2017-08-25 09:47:58 -040095 // Follow the hwmon instance (/sys/class/hwmon/hwmon<N>)
96 // /sys/devices symlink.
97 fs::path devPath{instancePath};
98 devPath /= "device";
Brandon Wyman8af8a202017-05-31 18:26:30 -050099
Brad Bishop431d26a2017-08-25 09:47:58 -0400100 try
Brandon Wyman8af8a202017-05-31 18:26:30 -0500101 {
Brad Bishop431d26a2017-08-25 09:47:58 -0400102 devPath = fs::canonical(devPath);
103 }
104 catch (const std::system_error& e)
105 {
106 return emptyString;
107 }
108
109 // See if the device is backed by the iio-hwmon driver.
110 fs::path p{devPath};
111 p /= "driver";
112 p = fs::canonical(p);
113
114 if (p.filename() != "iio_hwmon")
115 {
116 // Not backed by iio-hwmon. The device pointed to
117 // is the callout device.
118 return devPath;
119 }
120
121 // Find the DT path to the iio-hwmon platform device.
122 fs::path ofDevPath{devPath};
123 ofDevPath /= "of_node";
124
125 try
126 {
127 ofDevPath = fs::canonical(ofDevPath);
128 }
129 catch (const std::system_error& e)
130 {
131 return emptyString;
132 }
133
134 // Search /sys/bus/iio/devices for the phandle in io-channels.
135 // If a match is found, use the corresponding /sys/devices
136 // iio device as the callout device.
137 static constexpr auto iioDevices = "/sys/bus/iio/devices";
Willy Tudd7b3882026-01-06 23:01:47 +0000138 std::error_code ec;
139 fs::recursive_directory_iterator it(iioDevices, ec);
140 if (ec)
141 {
142 lg2::error("Unable to run recursive_directory_iterator: {ERR}", "ERR",
143 ec.message());
144 return emptyString;
145 }
146
147 for (const auto& iioDev : it)
Brad Bishop431d26a2017-08-25 09:47:58 -0400148 {
149 p = iioDev.path();
150 p /= "of_node";
151
152 try
153 {
154 p = fs::canonical(p);
155 }
156 catch (const std::system_error& e)
157 {
158 continue;
159 }
160
161 auto match = findPhandleMatch(ofDevPath, p);
162 auto n = match.rfind('/');
Brandon Wyman8af8a202017-05-31 18:26:30 -0500163 if (n != std::string::npos)
164 {
Brad Bishop431d26a2017-08-25 09:47:58 -0400165 // This is the iio device referred to by io-channels.
166 // Remove iio:device<N>.
167 try
168 {
169 return fs::canonical(iioDev).parent_path();
170 }
171 catch (const std::system_error& e)
172 {
173 return emptyString;
174 }
Brandon Wyman8af8a202017-05-31 18:26:30 -0500175 }
176 }
177
Brad Bishop431d26a2017-08-25 09:47:58 -0400178 return emptyString;
Brandon Wyman8af8a202017-05-31 18:26:30 -0500179}
180
Matt Spinler5c014d22019-04-16 09:13:14 -0500181std::string findHwmonFromOFPath(const std::string& ofNode)
Brandon Wyman8af8a202017-05-31 18:26:30 -0500182{
183 static constexpr auto hwmonRoot = "/sys/class/hwmon";
184
Matt Spinler5c014d22019-04-16 09:13:14 -0500185 auto fullOfPath = fs::path(ofRoot) / fs::path(ofNode).relative_path();
Brandon Wyman8af8a202017-05-31 18:26:30 -0500186
187 for (const auto& hwmonInst : fs::directory_iterator(hwmonRoot))
188 {
189 auto path = hwmonInst.path();
190 path /= "of_node";
Brad Bishop4e24ebd2017-08-28 16:19:16 -0400191
192 try
Brandon Wyman8af8a202017-05-31 18:26:30 -0500193 {
Brad Bishop4e24ebd2017-08-28 16:19:16 -0400194 path = fs::canonical(path);
195 }
196 catch (const std::system_error& e)
197 {
198 // realpath may encounter ENOENT (Hwmon
199 // instances have a nasty habit of
200 // going away without warning).
201 continue;
Brad Bishop613a5b32017-01-05 20:58:13 -0500202 }
203
Brad Bishop4e24ebd2017-08-28 16:19:16 -0400204 if (path == fullOfPath)
205 {
206 return hwmonInst.path();
207 }
208
209 // Try to find HWMON instance via phandle values.
210 // Used for IIO device drivers.
211 auto matchpath = findPhandleMatch(path, fullOfPath);
212 if (!matchpath.empty())
213 {
214 return hwmonInst.path();
215 }
Brad Bishop613a5b32017-01-05 20:58:13 -0500216 }
217
Brad Bishop4e24ebd2017-08-28 16:19:16 -0400218 return emptyString;
Brad Bishop613a5b32017-01-05 20:58:13 -0500219}
220
Matt Spinler5c014d22019-04-16 09:13:14 -0500221std::string findHwmonFromDevPath(const std::string& devPath)
Matt Spinler626df172018-03-05 12:03:55 -0600222{
223 fs::path p{"/sys"};
Matt Spinler5c014d22019-04-16 09:13:14 -0500224 p /= fs::path(devPath).relative_path();
Matt Spinler626df172018-03-05 12:03:55 -0600225 p /= "hwmon";
226
227 try
228 {
Patrick Venture043d3232018-08-31 10:10:53 -0700229 // This path is also used as a filesystem path to an environment
230 // file, and that has issues with ':'s in the path so they've
231 // been converted to '--'s. Convert them back now.
Matt Spinler626df172018-03-05 12:03:55 -0600232 size_t pos = 0;
233 std::string path = p;
234 while ((pos = path.find("--")) != std::string::npos)
235 {
236 path.replace(pos, 2, ":");
237 }
238
Patrick Venture09560172018-10-13 13:25:15 -0700239 auto dir_iter = fs::directory_iterator(path);
Patrick Williams02e598a2024-08-16 15:21:23 -0400240 auto hwmonInst = std::find_if(
241 dir_iter, end(dir_iter), [](const fs::directory_entry& d) {
242 return (d.path().filename().string().find("hwmon") !=
243 std::string::npos);
244 });
Patrick Venture09560172018-10-13 13:25:15 -0700245 if (hwmonInst != end(dir_iter))
Matt Spinler626df172018-03-05 12:03:55 -0600246 {
Patrick Venture09560172018-10-13 13:25:15 -0700247 return hwmonInst->path();
Matt Spinler626df172018-03-05 12:03:55 -0600248 }
249 }
250 catch (const std::exception& e)
251 {
Willy Tudd7b3882026-01-06 23:01:47 +0000252 lg2::error("Unable to find hwmon directory from the dev path: {ERR}",
253 "ERR", devPath);
Matt Spinler626df172018-03-05 12:03:55 -0600254 }
255 return emptyString;
256}
257
Patrick Venture75e56c62018-04-20 18:10:15 -0700258} // namespace sysfs