blob: 3ca2ec4d1f44f2f7382e592c859a6dcbb20dc737 [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 */
16#include <cstdlib>
Brad Bishop08379a32017-03-06 21:28:46 -050017#include <experimental/filesystem>
Brad Bishop613a5b32017-01-05 20:58:13 -050018#include <memory>
Matthew Barth048ac872017-03-09 14:36:08 -060019#include <phosphor-logging/elog.hpp>
20#include <phosphor-logging/elog-errors.hpp>
21#include <xyz/openbmc_project/Control/Device/error.hpp>
Matthew Barth4e1f30f2017-03-21 16:13:27 -050022#include <xyz/openbmc_project/Sensor/Device/error.hpp>
Brad Bishop613a5b32017-01-05 20:58:13 -050023#include "sysfs.hpp"
24#include "util.hpp"
Brandon Wyman4eb98582017-05-24 14:24:00 -050025#include <fstream>
Brad Bishop613a5b32017-01-05 20:58:13 -050026
Matthew Barth048ac872017-03-09 14:36:08 -060027using namespace phosphor::logging;
Brandon Wyman8af8a202017-05-31 18:26:30 -050028namespace fs = std::experimental::filesystem;
Matthew Barth048ac872017-03-09 14:36:08 -060029
Brandon Wyman8af8a202017-05-31 18:26:30 -050030static constexpr auto ofRoot = "/sys/firmware/devicetree/base";
31
32/**
33 * @brief Return the path to the phandle file matching value in io-channels.
34 *
35 * This function will take two passed in paths.
36 * One path is used to find the io-channels file.
37 * The other path is used to find the phandle file.
38 * The 4 byte phandle value is read from the phandle file(s).
39 * The 4 byte phandle value and 4 byte index value is read from io-channels.
40 * When a match is found, the path to the matching phandle file is returned.
41 *
42 * @param[in] iochanneldir - Path to file for getting phandle from io-channels
43 * @param[in] phandledir - Path to use for reading from phandle file
44 *
45 * @return Path to phandle file with value matching that in io-channels
46 */
47std::string findPhandleMatch(const std::string& iochanneldir,
48 const std::string& phandledir)
Brad Bishop613a5b32017-01-05 20:58:13 -050049{
Brandon Wyman8af8a202017-05-31 18:26:30 -050050 for (const auto& ofInst : fs::recursive_directory_iterator(phandledir))
Brad Bishop613a5b32017-01-05 20:58:13 -050051 {
Brandon Wyman8af8a202017-05-31 18:26:30 -050052 auto path = ofInst.path();
53 if ("phandle" == ofInst.path().filename())
Brad Bishop613a5b32017-01-05 20:58:13 -050054 {
Brandon Wyman8af8a202017-05-31 18:26:30 -050055 auto ioChannelsPath = iochanneldir + "/io-channels";
56 if (fs::exists(ioChannelsPath))
Brandon Wyman4eb98582017-05-24 14:24:00 -050057 {
Brandon Wyman8af8a202017-05-31 18:26:30 -050058 auto fullOfPathPhandle = ofInst.path();
Brandon Wyman4eb98582017-05-24 14:24:00 -050059 std::ifstream ioChannelsFile(path);
60 std::ifstream pHandleFile(fullOfPathPhandle);
61
62 uint32_t ioChannelsValue;
63 uint32_t pHandleValue;
64
65 try
66 {
67 ioChannelsFile.read(reinterpret_cast<char*>(&ioChannelsValue),
68 sizeof(ioChannelsValue));
69 pHandleFile.read(reinterpret_cast<char*>(&pHandleValue),
70 sizeof(pHandleValue));
71
72 if (ioChannelsValue == pHandleValue)
73 {
Brandon Wyman8af8a202017-05-31 18:26:30 -050074 return ofInst.path();
Brandon Wyman4eb98582017-05-24 14:24:00 -050075 }
76 }
77 catch (const std::exception& e)
78 {
79 log<level::INFO>(e.what());
Brandon Wyman8af8a202017-05-31 18:26:30 -050080 continue;
Brandon Wyman4eb98582017-05-24 14:24:00 -050081 }
82
Brandon Wyman4eb98582017-05-24 14:24:00 -050083 }
Brandon Wyman8af8a202017-05-31 18:26:30 -050084 }
85 }
86
87 return std::string();
88}
89
90/**
91 * @brief Return the path to use for a call out.
92 *
93 * If the path does not contain iio-hwmon, assume passed in path is the call
94 * out path.
95 *
96 * @param[in] ofPath - Open firmware path to search for matching phandle value
97 *
98 * @return Path to use for call out
99 */
100std::string findCalloutPath(const std::string& ofPath)
101{
102 static constexpr auto iioHwmonStr = "iio-hwmon";
103
104 if (ofPath.find(iioHwmonStr) != std::string::npos)
105 {
106 auto matchpath = findPhandleMatch(ofPath, ofRoot);
107 auto n = matchpath.rfind('/');
108 if (n != std::string::npos)
109 {
110 return matchpath.substr(0, n);
111 }
112 }
113
114 return ofPath;
115}
116
117std::string findHwmon(const std::string& ofNode)
118{
119 static constexpr auto hwmonRoot = "/sys/class/hwmon";
120
121 fs::path fullOfPath{ofRoot};
122 fullOfPath /= ofNode;
123
124 for (const auto& hwmonInst : fs::directory_iterator(hwmonRoot))
125 {
126 auto path = hwmonInst.path();
127 path /= "of_node";
128 if (fs::canonical(path) != fullOfPath)
129 {
130 // Try to find HWMON instance via phandle values.
131 // Used for IIO device drivers.
132 auto ofpath = fullOfPath.string();
133 auto matchpath = findPhandleMatch(path, ofpath);
134 if (!std::string(matchpath).empty())
135 {
136 return hwmonInst.path();
137 }
138 else
139 {
140 continue;
141 }
Brad Bishop613a5b32017-01-05 20:58:13 -0500142 }
143
Brad Bishop08379a32017-03-06 21:28:46 -0500144 return hwmonInst.path();
Brad Bishop613a5b32017-01-05 20:58:13 -0500145 }
146
147 return std::string();
148}
149
Brad Bishop4db64422017-02-16 11:33:32 -0500150int readSysfsWithCallout(const std::string& root,
151 const std::string& instance,
152 const std::string& type,
153 const std::string& id,
154 const std::string& sensor)
155{
Brad Bishop5ec68ab2017-03-27 13:41:02 -0400156 namespace fs = std::experimental::filesystem;
157
Brad Bishop4db64422017-02-16 11:33:32 -0500158 int value = 0;
Brad Bishop5ec68ab2017-03-27 13:41:02 -0400159 std::ifstream ifs;
160 fs::path instancePath{root};
161 instancePath /= instance;
Brad Bishop4db64422017-02-16 11:33:32 -0500162 std::string fullPath = make_sysfs_path(instancePath,
163 type, id, sensor);
Brad Bishop4db64422017-02-16 11:33:32 -0500164
Brandon Wyman8af8a202017-05-31 18:26:30 -0500165 auto callOutPath = findCalloutPath(fs::canonical(instancePath));
166
Brad Bishop4db64422017-02-16 11:33:32 -0500167 ifs.exceptions(std::ifstream::failbit
168 | std::ifstream::badbit
169 | std::ifstream::eofbit);
170 try
171 {
172 ifs.open(fullPath);
173 ifs >> value;
174 }
175 catch (const std::exception& e)
176 {
177 // Too many GCC bugs (53984, 66145) to do
178 // this the right way...
Brad Bishop4db64422017-02-16 11:33:32 -0500179
180 // errno should still reflect the error from the failing open
181 // or read system calls that got us here.
182 auto rc = errno;
Brad Bishop5ec68ab2017-03-27 13:41:02 -0400183 instancePath /= "device";
Matthew Barth4e1f30f2017-03-21 16:13:27 -0500184 using namespace sdbusplus::xyz::openbmc_project::Sensor::Device::Error;
Marri Devender Rao05711eb2017-04-15 06:47:11 -0500185 report<ReadFailure>(
186 xyz::openbmc_project::Sensor::Device::
187 ReadFailure::CALLOUT_ERRNO(rc),
188 xyz::openbmc_project::Sensor::Device::
189 ReadFailure::CALLOUT_DEVICE_PATH(
Brandon Wyman8af8a202017-05-31 18:26:30 -0500190 fs::canonical(callOutPath).c_str()));
Marri Devender Rao05711eb2017-04-15 06:47:11 -0500191
Brad Bishop4db64422017-02-16 11:33:32 -0500192 exit(EXIT_FAILURE);
193 }
194
195 return value;
196}
197
Matthew Barth048ac872017-03-09 14:36:08 -0600198uint64_t writeSysfsWithCallout(const uint64_t& value,
199 const std::string& root,
200 const std::string& instance,
201 const std::string& type,
202 const std::string& id,
203 const std::string& sensor)
204{
205 namespace fs = std::experimental::filesystem;
206
207 std::string valueStr = std::to_string(value);
208 std::ofstream ofs;
209 fs::path instancePath{root};
210 instancePath /= instance;
211 std::string fullPath = make_sysfs_path(instancePath,
212 type, id, sensor);
213
Brandon Wyman8af8a202017-05-31 18:26:30 -0500214 auto callOutPath = findCalloutPath(fs::canonical(instancePath));
215
Matthew Barth048ac872017-03-09 14:36:08 -0600216 ofs.exceptions(std::ofstream::failbit
217 | std::ofstream::badbit
218 | std::ofstream::eofbit);
219 try
220 {
221 ofs.open(fullPath);
222 ofs << valueStr;
223 }
224 catch (const std::exception& e)
225 {
226 // errno should still reflect the error from the failing open
227 // or write system calls that got us here.
228 auto rc = errno;
229 instancePath /= "device";
230 using namespace sdbusplus::xyz::openbmc_project::Control::Device::Error;
Marri Devender Rao05711eb2017-04-15 06:47:11 -0500231 report<WriteFailure>(
232 xyz::openbmc_project::Control::Device::
233 WriteFailure::CALLOUT_ERRNO(rc),
234 xyz::openbmc_project::Control::Device::
235 WriteFailure::CALLOUT_DEVICE_PATH(
Brandon Wyman8af8a202017-05-31 18:26:30 -0500236 fs::canonical(callOutPath).c_str()));
Marri Devender Rao05711eb2017-04-15 06:47:11 -0500237
Matthew Barth048ac872017-03-09 14:36:08 -0600238 exit(EXIT_FAILURE);
239 }
240
241 return value;
242}
243
Brad Bishop613a5b32017-01-05 20:58:13 -0500244// vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4