blob: f5b12bcb834a25eb17557c5b9e3097ba02e42760 [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
William A. Kennington IIIf9aff802021-05-05 12:06:24 -070018#include <fmt/format.h>
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>
William A. Kennington IIIf9aff802021-05-05 12:06:24 -070025#include <string>
Brad Bishop613a5b32017-01-05 20:58:13 -050026
Brad Bishopf4bf63a2017-08-28 15:39:19 -040027using namespace std::string_literals;
Patrick Venture9e997b42019-03-08 13:42:10 -080028namespace fs = std::filesystem;
Matthew Barth048ac872017-03-09 14:36:08 -060029
Patrick Venture043d3232018-08-31 10:10:53 -070030namespace sysfs
31{
Patrick Venture1e6324f2017-06-01 14:07:05 -070032
Brad Bishopf4bf63a2017-08-28 15:39:19 -040033static const auto emptyString = ""s;
Brandon Wyman8af8a202017-05-31 18:26:30 -050034static constexpr auto ofRoot = "/sys/firmware/devicetree/base";
35
Patrick Venture043d3232018-08-31 10:10:53 -070036std::string findPhandleMatch(const std::string& iochanneldir,
37 const std::string& phandledir)
Brad Bishop613a5b32017-01-05 20:58:13 -050038{
Brad Bishopf4bf63a2017-08-28 15:39:19 -040039 // TODO: At the moment this method only supports device trees
40 // with iio-hwmon nodes with a single sensor. Typically
41 // device trees are defined with all the iio sensors in a
42 // single iio-hwmon node so it would be nice to add support
43 // for lists of phandles (with variable sized entries) via
44 // libfdt or something like that, so that users are not
45 // forced into implementing unusual looking device trees
46 // with multiple iio-hwmon nodes - one for each sensor.
47
48 fs::path ioChannelsPath{iochanneldir};
49 ioChannelsPath /= "io-channels";
50
51 if (!fs::exists(ioChannelsPath))
52 {
53 return emptyString;
54 }
55
56 uint32_t ioChannelsValue;
57 std::ifstream ioChannelsFile(ioChannelsPath);
58
Patrick Venture043d3232018-08-31 10:10:53 -070059 ioChannelsFile.read(reinterpret_cast<char*>(&ioChannelsValue),
60 sizeof(ioChannelsValue));
Brad Bishopf4bf63a2017-08-28 15:39:19 -040061
Brandon Wyman8af8a202017-05-31 18:26:30 -050062 for (const auto& ofInst : fs::recursive_directory_iterator(phandledir))
Brad Bishop613a5b32017-01-05 20:58:13 -050063 {
Brandon Wyman8af8a202017-05-31 18:26:30 -050064 auto path = ofInst.path();
Brad Bishopf4bf63a2017-08-28 15:39:19 -040065 if ("phandle" != path.filename())
Brad Bishop613a5b32017-01-05 20:58:13 -050066 {
Brad Bishopf4bf63a2017-08-28 15:39:19 -040067 continue;
68 }
69 std::ifstream pHandleFile(path);
70 uint32_t pHandleValue;
Brandon Wyman4eb98582017-05-24 14:24:00 -050071
Patrick Venture043d3232018-08-31 10:10:53 -070072 pHandleFile.read(reinterpret_cast<char*>(&pHandleValue),
73 sizeof(pHandleValue));
Brandon Wyman4eb98582017-05-24 14:24:00 -050074
Brad Bishopf4bf63a2017-08-28 15:39:19 -040075 if (ioChannelsValue == pHandleValue)
76 {
77 return path;
Brandon Wyman8af8a202017-05-31 18:26:30 -050078 }
79 }
80
Brad Bishopf4bf63a2017-08-28 15:39:19 -040081 return emptyString;
Brandon Wyman8af8a202017-05-31 18:26:30 -050082}
83
Brad Bishop431d26a2017-08-25 09:47:58 -040084std::string findCalloutPath(const std::string& instancePath)
Brandon Wyman8af8a202017-05-31 18:26:30 -050085{
Brad Bishop431d26a2017-08-25 09:47:58 -040086 // Follow the hwmon instance (/sys/class/hwmon/hwmon<N>)
87 // /sys/devices symlink.
88 fs::path devPath{instancePath};
89 devPath /= "device";
Brandon Wyman8af8a202017-05-31 18:26:30 -050090
Brad Bishop431d26a2017-08-25 09:47:58 -040091 try
Brandon Wyman8af8a202017-05-31 18:26:30 -050092 {
Brad Bishop431d26a2017-08-25 09:47:58 -040093 devPath = fs::canonical(devPath);
94 }
95 catch (const std::system_error& e)
96 {
97 return emptyString;
98 }
99
100 // See if the device is backed by the iio-hwmon driver.
101 fs::path p{devPath};
102 p /= "driver";
103 p = fs::canonical(p);
104
105 if (p.filename() != "iio_hwmon")
106 {
107 // Not backed by iio-hwmon. The device pointed to
108 // is the callout device.
109 return devPath;
110 }
111
112 // Find the DT path to the iio-hwmon platform device.
113 fs::path ofDevPath{devPath};
114 ofDevPath /= "of_node";
115
116 try
117 {
118 ofDevPath = fs::canonical(ofDevPath);
119 }
120 catch (const std::system_error& e)
121 {
122 return emptyString;
123 }
124
125 // Search /sys/bus/iio/devices for the phandle in io-channels.
126 // If a match is found, use the corresponding /sys/devices
127 // iio device as the callout device.
128 static constexpr auto iioDevices = "/sys/bus/iio/devices";
Patrick Venture043d3232018-08-31 10:10:53 -0700129 for (const auto& iioDev : fs::recursive_directory_iterator(iioDevices))
Brad Bishop431d26a2017-08-25 09:47:58 -0400130 {
131 p = iioDev.path();
132 p /= "of_node";
133
134 try
135 {
136 p = fs::canonical(p);
137 }
138 catch (const std::system_error& e)
139 {
140 continue;
141 }
142
143 auto match = findPhandleMatch(ofDevPath, p);
144 auto n = match.rfind('/');
Brandon Wyman8af8a202017-05-31 18:26:30 -0500145 if (n != std::string::npos)
146 {
Brad Bishop431d26a2017-08-25 09:47:58 -0400147 // This is the iio device referred to by io-channels.
148 // Remove iio:device<N>.
149 try
150 {
151 return fs::canonical(iioDev).parent_path();
152 }
153 catch (const std::system_error& e)
154 {
155 return emptyString;
156 }
Brandon Wyman8af8a202017-05-31 18:26:30 -0500157 }
158 }
159
Brad Bishop431d26a2017-08-25 09:47:58 -0400160 return emptyString;
Brandon Wyman8af8a202017-05-31 18:26:30 -0500161}
162
Matt Spinler5c014d22019-04-16 09:13:14 -0500163std::string findHwmonFromOFPath(const std::string& ofNode)
Brandon Wyman8af8a202017-05-31 18:26:30 -0500164{
165 static constexpr auto hwmonRoot = "/sys/class/hwmon";
166
Matt Spinler5c014d22019-04-16 09:13:14 -0500167 auto fullOfPath = fs::path(ofRoot) / fs::path(ofNode).relative_path();
Brandon Wyman8af8a202017-05-31 18:26:30 -0500168
169 for (const auto& hwmonInst : fs::directory_iterator(hwmonRoot))
170 {
171 auto path = hwmonInst.path();
172 path /= "of_node";
Brad Bishop4e24ebd2017-08-28 16:19:16 -0400173
174 try
Brandon Wyman8af8a202017-05-31 18:26:30 -0500175 {
Brad Bishop4e24ebd2017-08-28 16:19:16 -0400176 path = fs::canonical(path);
177 }
178 catch (const std::system_error& e)
179 {
180 // realpath may encounter ENOENT (Hwmon
181 // instances have a nasty habit of
182 // going away without warning).
183 continue;
Brad Bishop613a5b32017-01-05 20:58:13 -0500184 }
185
Brad Bishop4e24ebd2017-08-28 16:19:16 -0400186 if (path == fullOfPath)
187 {
188 return hwmonInst.path();
189 }
190
191 // Try to find HWMON instance via phandle values.
192 // Used for IIO device drivers.
193 auto matchpath = findPhandleMatch(path, fullOfPath);
194 if (!matchpath.empty())
195 {
196 return hwmonInst.path();
197 }
Brad Bishop613a5b32017-01-05 20:58:13 -0500198 }
199
Brad Bishop4e24ebd2017-08-28 16:19:16 -0400200 return emptyString;
Brad Bishop613a5b32017-01-05 20:58:13 -0500201}
202
Matt Spinler5c014d22019-04-16 09:13:14 -0500203std::string findHwmonFromDevPath(const std::string& devPath)
Matt Spinler626df172018-03-05 12:03:55 -0600204{
205 fs::path p{"/sys"};
Matt Spinler5c014d22019-04-16 09:13:14 -0500206 p /= fs::path(devPath).relative_path();
Matt Spinler626df172018-03-05 12:03:55 -0600207 p /= "hwmon";
208
209 try
210 {
Patrick Venture043d3232018-08-31 10:10:53 -0700211 // This path is also used as a filesystem path to an environment
212 // file, and that has issues with ':'s in the path so they've
213 // been converted to '--'s. Convert them back now.
Matt Spinler626df172018-03-05 12:03:55 -0600214 size_t pos = 0;
215 std::string path = p;
216 while ((pos = path.find("--")) != std::string::npos)
217 {
218 path.replace(pos, 2, ":");
219 }
220
Patrick Venture09560172018-10-13 13:25:15 -0700221 auto dir_iter = fs::directory_iterator(path);
222 auto hwmonInst = std::find_if(
223 dir_iter, end(dir_iter), [](const fs::directory_entry& d) {
224 return (d.path().filename().string().find("hwmon") !=
225 std::string::npos);
226 });
227 if (hwmonInst != end(dir_iter))
Matt Spinler626df172018-03-05 12:03:55 -0600228 {
Patrick Venture09560172018-10-13 13:25:15 -0700229 return hwmonInst->path();
Matt Spinler626df172018-03-05 12:03:55 -0600230 }
231 }
232 catch (const std::exception& e)
233 {
William A. Kennington IIIf9aff802021-05-05 12:06:24 -0700234 fmt::print(stderr,
235 "Unable to find hwmon directory from the dev path: {}\n",
236 devPath.c_str());
Matt Spinler626df172018-03-05 12:03:55 -0600237 }
238 return emptyString;
239}
240
Patrick Venture75e56c62018-04-20 18:10:15 -0700241} // namespace sysfs
Brad Bishop8b574a72017-08-25 16:17:19 -0400242
Brad Bishop613a5b32017-01-05 20:58:13 -0500243// vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4