blob: 5fbbe3ea687a6072da6965fe005ae1b72a2baa2a [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 Wymanf855e822017-08-08 18:04:47 -0500130uint64_t PMBus::read(const std::string& name, Type type)
131{
132 uint64_t data = 0;
133 std::ifstream file;
134 auto path = getPath(type);
135 path /= name;
136
137 file.exceptions(std::ifstream::failbit |
138 std::ifstream::badbit |
139 std::ifstream::eofbit);
140
141 try
142 {
143 file.open(path);
144 file >> std::hex >> data;
145 }
146 catch (std::exception& e)
147 {
148 auto rc = errno;
149 log<level::ERR>("Failed to read sysfs file",
150 entry("FILENAME=%s", path.c_str()));
151
152 using metadata = xyz::openbmc_project::Sensor::Device::ReadFailure;
153
154 elog<ReadFailure>(metadata::CALLOUT_ERRNO(rc),
155 metadata::CALLOUT_DEVICE_PATH(
156 fs::canonical(basePath).c_str()));
157 }
158
159 return data;
160}
161
Matt Spinler57868bc2017-08-03 10:07:41 -0500162void PMBus::write(const std::string& name, int value, Type type)
Matt Spinler015e3ad2017-08-01 11:20:47 -0500163{
164 std::ofstream file;
Brandon Wymanff5f3392017-08-11 17:43:22 -0500165 fs::path path = getPath(type);
Matt Spinler57868bc2017-08-03 10:07:41 -0500166
Matt Spinler015e3ad2017-08-01 11:20:47 -0500167 path /= name;
168
169 file.exceptions(std::ofstream::failbit |
170 std::ofstream::badbit |
171 std::ofstream::eofbit);
172
173 try
174 {
175 file.open(path);
176 file << value;
177 }
178 catch (const std::exception& e)
179 {
180 auto rc = errno;
181
182 log<level::ERR>("Failed to write sysfs file",
Brandon Wymanf855e822017-08-08 18:04:47 -0500183 entry("FILENAME=%s", path.c_str()));
Matt Spinler015e3ad2017-08-01 11:20:47 -0500184
185 elog<WriteFailure>(xyz::openbmc_project::Control::Device::
186 WriteFailure::CALLOUT_ERRNO(rc),
187 xyz::openbmc_project::Control::Device::
188 WriteFailure::CALLOUT_DEVICE_PATH(
189 fs::canonical(basePath).c_str()));
190 }
191}
192
Brandon Wymanff5f3392017-08-11 17:43:22 -0500193void PMBus::findHwmonDir()
Matt Spinler57868bc2017-08-03 10:07:41 -0500194{
195 fs::path path{basePath};
196 path /= "hwmon";
197
Brandon Wymanaad73e92017-08-16 16:27:54 -0500198 // Make sure the directory exists, otherwise for things that can be
199 // dynamically present or not present an exception will be thrown if the
200 // hwmon directory is not there, resulting in a program termination.
201 if (fs::is_directory(path))
Matt Spinler57868bc2017-08-03 10:07:41 -0500202 {
Brandon Wymanaad73e92017-08-16 16:27:54 -0500203 //look for <basePath>/hwmon/hwmonN/
204 for (auto& f : fs::directory_iterator(path))
Matt Spinler57868bc2017-08-03 10:07:41 -0500205 {
Brandon Wymanaad73e92017-08-16 16:27:54 -0500206 if ((f.path().filename().string().find("hwmon") !=
207 std::string::npos) &&
208 (fs::is_directory(f.path())))
209 {
210 hwmonDir = f.path().filename();
211 break;
212 }
Matt Spinler57868bc2017-08-03 10:07:41 -0500213 }
214 }
215
216 //Don't really want to crash here, just log it
217 //and let accesses fail later
Brandon Wymanff5f3392017-08-11 17:43:22 -0500218 if (hwmonDir.empty())
Matt Spinler57868bc2017-08-03 10:07:41 -0500219 {
Brandon Wymanaad73e92017-08-16 16:27:54 -0500220 log<level::INFO>("Unable to find hwmon directory "
221 "in device base path",
222 entry("DEVICE_PATH=%s", basePath.c_str()));
Matt Spinler57868bc2017-08-03 10:07:41 -0500223 }
224
225}
226
Matt Spinler015e3ad2017-08-01 11:20:47 -0500227}
228}