blob: b525bd95169668b9cde00f68a539d41819f60dbc [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:
56 /* fall through */
57 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",
114 entry("FILENAME=%s", path.c_str()));
115
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
Matt Spinler57868bc2017-08-03 10:07:41 -0500126void PMBus::write(const std::string& name, int value, Type type)
Matt Spinler015e3ad2017-08-01 11:20:47 -0500127{
128 std::ofstream file;
Brandon Wymanff5f3392017-08-11 17:43:22 -0500129 fs::path path = getPath(type);
Matt Spinler57868bc2017-08-03 10:07:41 -0500130
Matt Spinler015e3ad2017-08-01 11:20:47 -0500131 path /= name;
132
133 file.exceptions(std::ofstream::failbit |
134 std::ofstream::badbit |
135 std::ofstream::eofbit);
136
137 try
138 {
139 file.open(path);
140 file << value;
141 }
142 catch (const std::exception& e)
143 {
144 auto rc = errno;
145
146 log<level::ERR>("Failed to write sysfs file",
147 entry("FILENAME=%s", path.c_str()));
148
149 elog<WriteFailure>(xyz::openbmc_project::Control::Device::
150 WriteFailure::CALLOUT_ERRNO(rc),
151 xyz::openbmc_project::Control::Device::
152 WriteFailure::CALLOUT_DEVICE_PATH(
153 fs::canonical(basePath).c_str()));
154 }
155}
156
Brandon Wymanff5f3392017-08-11 17:43:22 -0500157void PMBus::findHwmonDir()
Matt Spinler57868bc2017-08-03 10:07:41 -0500158{
159 fs::path path{basePath};
160 path /= "hwmon";
161
162 //look for <basePath>/hwmon/hwmonN/
163 for (auto& f : fs::directory_iterator(path))
164 {
165 if ((f.path().filename().string().find("hwmon") !=
166 std::string::npos) &&
167 (fs::is_directory(f.path())))
168 {
Brandon Wymanff5f3392017-08-11 17:43:22 -0500169 hwmonDir = f.path().filename();
Matt Spinler57868bc2017-08-03 10:07:41 -0500170 break;
171 }
172 }
173
174 //Don't really want to crash here, just log it
175 //and let accesses fail later
Brandon Wymanff5f3392017-08-11 17:43:22 -0500176 if (hwmonDir.empty())
Matt Spinler57868bc2017-08-03 10:07:41 -0500177 {
178 log<level::ERR>("Unable to find hwmon directory "
179 "in device base path",
180 entry("DEVICE_PATH=%s", basePath.c_str()));
181 }
182
183}
184
Matt Spinler015e3ad2017-08-01 11:20:47 -0500185}
186}