blob: aae6ff3ae9c78f5e03ab035dfb23bee7bac86eb0 [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
Patrick Williams64129932024-02-13 21:10:17 -060018#include <stdplus/print.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
Brandon Wyman8af8a202017-05-31 18:26:30 -050063 for (const auto& ofInst : fs::recursive_directory_iterator(phandledir))
Brad Bishop613a5b32017-01-05 20:58:13 -050064 {
Brandon Wyman8af8a202017-05-31 18:26:30 -050065 auto path = ofInst.path();
Brad Bishopf4bf63a2017-08-28 15:39:19 -040066 if ("phandle" != path.filename())
Brad Bishop613a5b32017-01-05 20:58:13 -050067 {
Brad Bishopf4bf63a2017-08-28 15:39:19 -040068 continue;
69 }
70 std::ifstream pHandleFile(path);
71 uint32_t pHandleValue;
Brandon Wyman4eb98582017-05-24 14:24:00 -050072
Patrick Venture043d3232018-08-31 10:10:53 -070073 pHandleFile.read(reinterpret_cast<char*>(&pHandleValue),
74 sizeof(pHandleValue));
Brandon Wyman4eb98582017-05-24 14:24:00 -050075
Brad Bishopf4bf63a2017-08-28 15:39:19 -040076 if (ioChannelsValue == pHandleValue)
77 {
78 return path;
Brandon Wyman8af8a202017-05-31 18:26:30 -050079 }
80 }
81
Brad Bishopf4bf63a2017-08-28 15:39:19 -040082 return emptyString;
Brandon Wyman8af8a202017-05-31 18:26:30 -050083}
84
Brad Bishop431d26a2017-08-25 09:47:58 -040085std::string findCalloutPath(const std::string& instancePath)
Brandon Wyman8af8a202017-05-31 18:26:30 -050086{
Brad Bishop431d26a2017-08-25 09:47:58 -040087 // Follow the hwmon instance (/sys/class/hwmon/hwmon<N>)
88 // /sys/devices symlink.
89 fs::path devPath{instancePath};
90 devPath /= "device";
Brandon Wyman8af8a202017-05-31 18:26:30 -050091
Brad Bishop431d26a2017-08-25 09:47:58 -040092 try
Brandon Wyman8af8a202017-05-31 18:26:30 -050093 {
Brad Bishop431d26a2017-08-25 09:47:58 -040094 devPath = fs::canonical(devPath);
95 }
96 catch (const std::system_error& e)
97 {
98 return emptyString;
99 }
100
101 // See if the device is backed by the iio-hwmon driver.
102 fs::path p{devPath};
103 p /= "driver";
104 p = fs::canonical(p);
105
106 if (p.filename() != "iio_hwmon")
107 {
108 // Not backed by iio-hwmon. The device pointed to
109 // is the callout device.
110 return devPath;
111 }
112
113 // Find the DT path to the iio-hwmon platform device.
114 fs::path ofDevPath{devPath};
115 ofDevPath /= "of_node";
116
117 try
118 {
119 ofDevPath = fs::canonical(ofDevPath);
120 }
121 catch (const std::system_error& e)
122 {
123 return emptyString;
124 }
125
126 // Search /sys/bus/iio/devices for the phandle in io-channels.
127 // If a match is found, use the corresponding /sys/devices
128 // iio device as the callout device.
129 static constexpr auto iioDevices = "/sys/bus/iio/devices";
Patrick Venture043d3232018-08-31 10:10:53 -0700130 for (const auto& iioDev : fs::recursive_directory_iterator(iioDevices))
Brad Bishop431d26a2017-08-25 09:47:58 -0400131 {
132 p = iioDev.path();
133 p /= "of_node";
134
135 try
136 {
137 p = fs::canonical(p);
138 }
139 catch (const std::system_error& e)
140 {
141 continue;
142 }
143
144 auto match = findPhandleMatch(ofDevPath, p);
145 auto n = match.rfind('/');
Brandon Wyman8af8a202017-05-31 18:26:30 -0500146 if (n != std::string::npos)
147 {
Brad Bishop431d26a2017-08-25 09:47:58 -0400148 // This is the iio device referred to by io-channels.
149 // Remove iio:device<N>.
150 try
151 {
152 return fs::canonical(iioDev).parent_path();
153 }
154 catch (const std::system_error& e)
155 {
156 return emptyString;
157 }
Brandon Wyman8af8a202017-05-31 18:26:30 -0500158 }
159 }
160
Brad Bishop431d26a2017-08-25 09:47:58 -0400161 return emptyString;
Brandon Wyman8af8a202017-05-31 18:26:30 -0500162}
163
Matt Spinler5c014d22019-04-16 09:13:14 -0500164std::string findHwmonFromOFPath(const std::string& ofNode)
Brandon Wyman8af8a202017-05-31 18:26:30 -0500165{
166 static constexpr auto hwmonRoot = "/sys/class/hwmon";
167
Matt Spinler5c014d22019-04-16 09:13:14 -0500168 auto fullOfPath = fs::path(ofRoot) / fs::path(ofNode).relative_path();
Brandon Wyman8af8a202017-05-31 18:26:30 -0500169
170 for (const auto& hwmonInst : fs::directory_iterator(hwmonRoot))
171 {
172 auto path = hwmonInst.path();
173 path /= "of_node";
Brad Bishop4e24ebd2017-08-28 16:19:16 -0400174
175 try
Brandon Wyman8af8a202017-05-31 18:26:30 -0500176 {
Brad Bishop4e24ebd2017-08-28 16:19:16 -0400177 path = fs::canonical(path);
178 }
179 catch (const std::system_error& e)
180 {
181 // realpath may encounter ENOENT (Hwmon
182 // instances have a nasty habit of
183 // going away without warning).
184 continue;
Brad Bishop613a5b32017-01-05 20:58:13 -0500185 }
186
Brad Bishop4e24ebd2017-08-28 16:19:16 -0400187 if (path == fullOfPath)
188 {
189 return hwmonInst.path();
190 }
191
192 // Try to find HWMON instance via phandle values.
193 // Used for IIO device drivers.
194 auto matchpath = findPhandleMatch(path, fullOfPath);
195 if (!matchpath.empty())
196 {
197 return hwmonInst.path();
198 }
Brad Bishop613a5b32017-01-05 20:58:13 -0500199 }
200
Brad Bishop4e24ebd2017-08-28 16:19:16 -0400201 return emptyString;
Brad Bishop613a5b32017-01-05 20:58:13 -0500202}
203
Matt Spinler5c014d22019-04-16 09:13:14 -0500204std::string findHwmonFromDevPath(const std::string& devPath)
Matt Spinler626df172018-03-05 12:03:55 -0600205{
206 fs::path p{"/sys"};
Matt Spinler5c014d22019-04-16 09:13:14 -0500207 p /= fs::path(devPath).relative_path();
Matt Spinler626df172018-03-05 12:03:55 -0600208 p /= "hwmon";
209
210 try
211 {
Patrick Venture043d3232018-08-31 10:10:53 -0700212 // This path is also used as a filesystem path to an environment
213 // file, and that has issues with ':'s in the path so they've
214 // been converted to '--'s. Convert them back now.
Matt Spinler626df172018-03-05 12:03:55 -0600215 size_t pos = 0;
216 std::string path = p;
217 while ((pos = path.find("--")) != std::string::npos)
218 {
219 path.replace(pos, 2, ":");
220 }
221
Patrick Venture09560172018-10-13 13:25:15 -0700222 auto dir_iter = fs::directory_iterator(path);
Patrick Williams02e598a2024-08-16 15:21:23 -0400223 auto hwmonInst = std::find_if(
224 dir_iter, end(dir_iter), [](const fs::directory_entry& d) {
225 return (d.path().filename().string().find("hwmon") !=
226 std::string::npos);
227 });
Patrick Venture09560172018-10-13 13:25:15 -0700228 if (hwmonInst != end(dir_iter))
Matt Spinler626df172018-03-05 12:03:55 -0600229 {
Patrick Venture09560172018-10-13 13:25:15 -0700230 return hwmonInst->path();
Matt Spinler626df172018-03-05 12:03:55 -0600231 }
232 }
233 catch (const std::exception& e)
234 {
Patrick Williams64129932024-02-13 21:10:17 -0600235 stdplus::print(stderr,
236 "Unable to find hwmon directory from the dev path: {}\n",
237 devPath.c_str());
Matt Spinler626df172018-03-05 12:03:55 -0600238 }
239 return emptyString;
240}
241
Patrick Venture75e56c62018-04-20 18:10:15 -0700242} // namespace sysfs
Brad Bishop8b574a72017-08-25 16:17:19 -0400243
Brad Bishop613a5b32017-01-05 20:58:13 -0500244// vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4