blob: 12b8aa810c3ee919f792c7d653ba9b03a9d3ede2 [file] [log] [blame]
Matt Spinler015e3ad2017-08-01 11:20:47 -05001/**
2 * Copyright © 2017 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 <experimental/filesystem>
17#include <fstream>
18#include <phosphor-logging/elog.hpp>
19#include <phosphor-logging/elog-errors.hpp>
20#include <xyz/openbmc_project/Common/error.hpp>
21#include <xyz/openbmc_project/Control/Device/error.hpp>
22#include <xyz/openbmc_project/Sensor/Device/error.hpp>
23#include "pmbus.hpp"
24
25namespace witherspoon
26{
27namespace pmbus
28{
29
30using namespace phosphor::logging;
31using namespace sdbusplus::xyz::openbmc_project::Common::Error;
32using namespace sdbusplus::xyz::openbmc_project::Control::Device::Error;
33using namespace sdbusplus::xyz::openbmc_project::Sensor::Device::Error;
34namespace fs = std::experimental::filesystem;
35
36std::string PMBus::insertPageNum(const std::string& templateName,
37 size_t page)
38{
39 auto name = templateName;
40
41 //insert the page where the P was
42 auto pos = name.find('P');
43 if (pos != std::string::npos)
44 {
45 name.replace(pos, 1, std::to_string(page));
46 }
47
48 return name;
49}
50
Brandon Wymanff5f3392017-08-11 17:43:22 -050051fs::path PMBus::getPath(Type type)
52{
53 switch (type)
54 {
55 default:
Brandon Wymanf855e822017-08-08 18:04:47 -050056 /* fall through */
Brandon Wymanff5f3392017-08-11 17:43:22 -050057 case Type::Base:
58 return basePath;
59 break;
60 case Type::Hwmon:
61 return basePath / "hwmon" / hwmonDir;
62 break;
63 case Type::Debug:
Matt Spinler8f0d9532017-08-21 11:22:37 -050064 return debugPath / "pmbus" / hwmonDir;
65 break;
66 case Type::DeviceDebug:
67 auto dir = driverName + "." + std::to_string(instance);
68 return debugPath / dir;
Brandon Wymanff5f3392017-08-11 17:43:22 -050069 break;
70 }
71}
72
Matt Spinler57868bc2017-08-03 10:07:41 -050073bool PMBus::readBitInPage(const std::string& name,
74 size_t page,
75 Type type)
Matt Spinler015e3ad2017-08-01 11:20:47 -050076{
77 auto pagedBit = insertPageNum(name, page);
Matt Spinler57868bc2017-08-03 10:07:41 -050078 return readBit(pagedBit, type);
Matt Spinler015e3ad2017-08-01 11:20:47 -050079}
80
Matt Spinler57868bc2017-08-03 10:07:41 -050081bool PMBus::readBit(const std::string& name, Type type)
Matt Spinler015e3ad2017-08-01 11:20:47 -050082{
83 unsigned long int value = 0;
84 std::ifstream file;
Brandon Wymanff5f3392017-08-11 17:43:22 -050085 fs::path path = getPath(type);
Matt Spinler57868bc2017-08-03 10:07:41 -050086
Matt Spinler015e3ad2017-08-01 11:20:47 -050087 path /= name;
88
89 file.exceptions(std::ifstream::failbit |
90 std::ifstream::badbit |
91 std::ifstream::eofbit);
92
93 try
94 {
95 char* err = NULL;
96 std::string val{1, '\0'};
97
98 file.open(path);
99 file.read(&val[0], 1);
100
101 value = strtoul(val.c_str(), &err, 10);
102
103 if (*err)
104 {
105 log<level::ERR>("Invalid character in sysfs file",
106 entry("FILE=%s", path.c_str()),
107 entry("CONTENTS=%s", val.c_str()));
108
109 //Catch below and handle as a read failure
110 elog<InternalFailure>();
111 }
112 }
113 catch (std::exception& e)
114 {
115 auto rc = errno;
116
117 log<level::ERR>("Failed to read sysfs file",
Brandon Wymanf855e822017-08-08 18:04:47 -0500118 entry("FILENAME=%s", path.c_str()));
Matt Spinler015e3ad2017-08-01 11:20:47 -0500119
120 elog<ReadFailure>(xyz::openbmc_project::Sensor::Device::
121 ReadFailure::CALLOUT_ERRNO(rc),
122 xyz::openbmc_project::Sensor::Device::
123 ReadFailure::CALLOUT_DEVICE_PATH(
124 fs::canonical(basePath).c_str()));
125 }
126
127 return value != 0;
128}
129
Brandon Wyman3b7b38b2017-09-25 16:43:45 -0500130bool PMBus::exists(const std::string& name, Type type)
131{
132 auto path = getPath(type);
133 path /= name;
134 return fs::exists(path);
135}
136
Brandon Wymanf855e822017-08-08 18:04:47 -0500137uint64_t PMBus::read(const std::string& name, Type type)
138{
139 uint64_t data = 0;
140 std::ifstream file;
141 auto path = getPath(type);
142 path /= name;
143
144 file.exceptions(std::ifstream::failbit |
145 std::ifstream::badbit |
146 std::ifstream::eofbit);
147
148 try
149 {
150 file.open(path);
151 file >> std::hex >> data;
152 }
153 catch (std::exception& e)
154 {
155 auto rc = errno;
156 log<level::ERR>("Failed to read sysfs file",
157 entry("FILENAME=%s", path.c_str()));
158
159 using metadata = xyz::openbmc_project::Sensor::Device::ReadFailure;
160
161 elog<ReadFailure>(metadata::CALLOUT_ERRNO(rc),
162 metadata::CALLOUT_DEVICE_PATH(
163 fs::canonical(basePath).c_str()));
164 }
165
166 return data;
167}
168
Matt Spinler57868bc2017-08-03 10:07:41 -0500169void PMBus::write(const std::string& name, int value, Type type)
Matt Spinler015e3ad2017-08-01 11:20:47 -0500170{
171 std::ofstream file;
Brandon Wymanff5f3392017-08-11 17:43:22 -0500172 fs::path path = getPath(type);
Matt Spinler57868bc2017-08-03 10:07:41 -0500173
Matt Spinler015e3ad2017-08-01 11:20:47 -0500174 path /= name;
175
176 file.exceptions(std::ofstream::failbit |
177 std::ofstream::badbit |
178 std::ofstream::eofbit);
179
180 try
181 {
182 file.open(path);
183 file << value;
184 }
185 catch (const std::exception& e)
186 {
187 auto rc = errno;
188
189 log<level::ERR>("Failed to write sysfs file",
Brandon Wymanf855e822017-08-08 18:04:47 -0500190 entry("FILENAME=%s", path.c_str()));
Matt Spinler015e3ad2017-08-01 11:20:47 -0500191
192 elog<WriteFailure>(xyz::openbmc_project::Control::Device::
193 WriteFailure::CALLOUT_ERRNO(rc),
194 xyz::openbmc_project::Control::Device::
195 WriteFailure::CALLOUT_DEVICE_PATH(
196 fs::canonical(basePath).c_str()));
197 }
198}
199
Brandon Wymanff5f3392017-08-11 17:43:22 -0500200void PMBus::findHwmonDir()
Matt Spinler57868bc2017-08-03 10:07:41 -0500201{
202 fs::path path{basePath};
203 path /= "hwmon";
204
Brandon Wymanaad73e92017-08-16 16:27:54 -0500205 // Make sure the directory exists, otherwise for things that can be
206 // dynamically present or not present an exception will be thrown if the
207 // hwmon directory is not there, resulting in a program termination.
208 if (fs::is_directory(path))
Matt Spinler57868bc2017-08-03 10:07:41 -0500209 {
Brandon Wymanaad73e92017-08-16 16:27:54 -0500210 //look for <basePath>/hwmon/hwmonN/
211 for (auto& f : fs::directory_iterator(path))
Matt Spinler57868bc2017-08-03 10:07:41 -0500212 {
Brandon Wymanaad73e92017-08-16 16:27:54 -0500213 if ((f.path().filename().string().find("hwmon") !=
214 std::string::npos) &&
215 (fs::is_directory(f.path())))
216 {
217 hwmonDir = f.path().filename();
218 break;
219 }
Matt Spinler57868bc2017-08-03 10:07:41 -0500220 }
221 }
222
223 //Don't really want to crash here, just log it
224 //and let accesses fail later
Brandon Wymanff5f3392017-08-11 17:43:22 -0500225 if (hwmonDir.empty())
Matt Spinler57868bc2017-08-03 10:07:41 -0500226 {
Brandon Wymanaad73e92017-08-16 16:27:54 -0500227 log<level::INFO>("Unable to find hwmon directory "
228 "in device base path",
229 entry("DEVICE_PATH=%s", basePath.c_str()));
Matt Spinler57868bc2017-08-03 10:07:41 -0500230 }
231
232}
233
Matt Spinler015e3ad2017-08-01 11:20:47 -0500234}
235}