blob: 95e3bbb251548b42edfc81cba45183c6393d7122 [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:
64 return debugPath / hwmonDir;
65 break;
66 }
67}
68
Matt Spinler57868bc2017-08-03 10:07:41 -050069bool PMBus::readBitInPage(const std::string& name,
70 size_t page,
71 Type type)
Matt Spinler015e3ad2017-08-01 11:20:47 -050072{
73 auto pagedBit = insertPageNum(name, page);
Matt Spinler57868bc2017-08-03 10:07:41 -050074 return readBit(pagedBit, type);
Matt Spinler015e3ad2017-08-01 11:20:47 -050075}
76
Matt Spinler57868bc2017-08-03 10:07:41 -050077bool PMBus::readBit(const std::string& name, Type type)
Matt Spinler015e3ad2017-08-01 11:20:47 -050078{
79 unsigned long int value = 0;
80 std::ifstream file;
Brandon Wymanff5f3392017-08-11 17:43:22 -050081 fs::path path = getPath(type);
Matt Spinler57868bc2017-08-03 10:07:41 -050082
Matt Spinler015e3ad2017-08-01 11:20:47 -050083 path /= name;
84
85 file.exceptions(std::ifstream::failbit |
86 std::ifstream::badbit |
87 std::ifstream::eofbit);
88
89 try
90 {
91 char* err = NULL;
92 std::string val{1, '\0'};
93
94 file.open(path);
95 file.read(&val[0], 1);
96
97 value = strtoul(val.c_str(), &err, 10);
98
99 if (*err)
100 {
101 log<level::ERR>("Invalid character in sysfs file",
102 entry("FILE=%s", path.c_str()),
103 entry("CONTENTS=%s", val.c_str()));
104
105 //Catch below and handle as a read failure
106 elog<InternalFailure>();
107 }
108 }
109 catch (std::exception& e)
110 {
111 auto rc = errno;
112
113 log<level::ERR>("Failed to read sysfs file",
Brandon Wymanf855e822017-08-08 18:04:47 -0500114 entry("FILENAME=%s", path.c_str()));
Matt Spinler015e3ad2017-08-01 11:20:47 -0500115
116 elog<ReadFailure>(xyz::openbmc_project::Sensor::Device::
117 ReadFailure::CALLOUT_ERRNO(rc),
118 xyz::openbmc_project::Sensor::Device::
119 ReadFailure::CALLOUT_DEVICE_PATH(
120 fs::canonical(basePath).c_str()));
121 }
122
123 return value != 0;
124}
125
Brandon Wymanf855e822017-08-08 18:04:47 -0500126uint64_t PMBus::read(const std::string& name, Type type)
127{
128 uint64_t data = 0;
129 std::ifstream file;
130 auto path = getPath(type);
131 path /= name;
132
133 file.exceptions(std::ifstream::failbit |
134 std::ifstream::badbit |
135 std::ifstream::eofbit);
136
137 try
138 {
139 file.open(path);
140 file >> std::hex >> data;
141 }
142 catch (std::exception& e)
143 {
144 auto rc = errno;
145 log<level::ERR>("Failed to read sysfs file",
146 entry("FILENAME=%s", path.c_str()));
147
148 using metadata = xyz::openbmc_project::Sensor::Device::ReadFailure;
149
150 elog<ReadFailure>(metadata::CALLOUT_ERRNO(rc),
151 metadata::CALLOUT_DEVICE_PATH(
152 fs::canonical(basePath).c_str()));
153 }
154
155 return data;
156}
157
Matt Spinler57868bc2017-08-03 10:07:41 -0500158void PMBus::write(const std::string& name, int value, Type type)
Matt Spinler015e3ad2017-08-01 11:20:47 -0500159{
160 std::ofstream file;
Brandon Wymanff5f3392017-08-11 17:43:22 -0500161 fs::path path = getPath(type);
Matt Spinler57868bc2017-08-03 10:07:41 -0500162
Matt Spinler015e3ad2017-08-01 11:20:47 -0500163 path /= name;
164
165 file.exceptions(std::ofstream::failbit |
166 std::ofstream::badbit |
167 std::ofstream::eofbit);
168
169 try
170 {
171 file.open(path);
172 file << value;
173 }
174 catch (const std::exception& e)
175 {
176 auto rc = errno;
177
178 log<level::ERR>("Failed to write sysfs file",
Brandon Wymanf855e822017-08-08 18:04:47 -0500179 entry("FILENAME=%s", path.c_str()));
Matt Spinler015e3ad2017-08-01 11:20:47 -0500180
181 elog<WriteFailure>(xyz::openbmc_project::Control::Device::
182 WriteFailure::CALLOUT_ERRNO(rc),
183 xyz::openbmc_project::Control::Device::
184 WriteFailure::CALLOUT_DEVICE_PATH(
185 fs::canonical(basePath).c_str()));
186 }
187}
188
Brandon Wymanff5f3392017-08-11 17:43:22 -0500189void PMBus::findHwmonDir()
Matt Spinler57868bc2017-08-03 10:07:41 -0500190{
191 fs::path path{basePath};
192 path /= "hwmon";
193
194 //look for <basePath>/hwmon/hwmonN/
195 for (auto& f : fs::directory_iterator(path))
196 {
197 if ((f.path().filename().string().find("hwmon") !=
Brandon Wymanf855e822017-08-08 18:04:47 -0500198 std::string::npos) &&
Matt Spinler57868bc2017-08-03 10:07:41 -0500199 (fs::is_directory(f.path())))
200 {
Brandon Wymanff5f3392017-08-11 17:43:22 -0500201 hwmonDir = f.path().filename();
Matt Spinler57868bc2017-08-03 10:07:41 -0500202 break;
203 }
204 }
205
206 //Don't really want to crash here, just log it
207 //and let accesses fail later
Brandon Wymanff5f3392017-08-11 17:43:22 -0500208 if (hwmonDir.empty())
Matt Spinler57868bc2017-08-03 10:07:41 -0500209 {
210 log<level::ERR>("Unable to find hwmon directory "
211 "in device base path",
212 entry("DEVICE_PATH=%s", basePath.c_str()));
213 }
214
215}
216
Matt Spinler015e3ad2017-08-01 11:20:47 -0500217}
218}