blob: bd9e6979ff239767e282d4250c44d15c6d37dafb [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
Matt Spinler57868bc2017-08-03 10:07:41 -050051bool PMBus::readBitInPage(const std::string& name,
52 size_t page,
53 Type type)
Matt Spinler015e3ad2017-08-01 11:20:47 -050054{
55 auto pagedBit = insertPageNum(name, page);
Matt Spinler57868bc2017-08-03 10:07:41 -050056 return readBit(pagedBit, type);
Matt Spinler015e3ad2017-08-01 11:20:47 -050057}
58
Matt Spinler57868bc2017-08-03 10:07:41 -050059bool PMBus::readBit(const std::string& name, Type type)
Matt Spinler015e3ad2017-08-01 11:20:47 -050060{
61 unsigned long int value = 0;
62 std::ifstream file;
63 fs::path path{basePath};
64
Matt Spinler57868bc2017-08-03 10:07:41 -050065 if (type == Type::Hwmon)
66 {
67 path /= hwmonRelPath;
68 }
69
Matt Spinler015e3ad2017-08-01 11:20:47 -050070 path /= name;
71
72 file.exceptions(std::ifstream::failbit |
73 std::ifstream::badbit |
74 std::ifstream::eofbit);
75
76 try
77 {
78 char* err = NULL;
79 std::string val{1, '\0'};
80
81 file.open(path);
82 file.read(&val[0], 1);
83
84 value = strtoul(val.c_str(), &err, 10);
85
86 if (*err)
87 {
88 log<level::ERR>("Invalid character in sysfs file",
89 entry("FILE=%s", path.c_str()),
90 entry("CONTENTS=%s", val.c_str()));
91
92 //Catch below and handle as a read failure
93 elog<InternalFailure>();
94 }
95 }
96 catch (std::exception& e)
97 {
98 auto rc = errno;
99
100 log<level::ERR>("Failed to read sysfs file",
101 entry("FILENAME=%s", path.c_str()));
102
103 elog<ReadFailure>(xyz::openbmc_project::Sensor::Device::
104 ReadFailure::CALLOUT_ERRNO(rc),
105 xyz::openbmc_project::Sensor::Device::
106 ReadFailure::CALLOUT_DEVICE_PATH(
107 fs::canonical(basePath).c_str()));
108 }
109
110 return value != 0;
111}
112
Matt Spinler57868bc2017-08-03 10:07:41 -0500113void PMBus::write(const std::string& name, int value, Type type)
Matt Spinler015e3ad2017-08-01 11:20:47 -0500114{
115 std::ofstream file;
116 fs::path path{basePath};
117
Matt Spinler57868bc2017-08-03 10:07:41 -0500118 if (type == Type::Hwmon)
119 {
120 path /= hwmonRelPath;
121 }
122
Matt Spinler015e3ad2017-08-01 11:20:47 -0500123 path /= name;
124
125 file.exceptions(std::ofstream::failbit |
126 std::ofstream::badbit |
127 std::ofstream::eofbit);
128
129 try
130 {
131 file.open(path);
132 file << value;
133 }
134 catch (const std::exception& e)
135 {
136 auto rc = errno;
137
138 log<level::ERR>("Failed to write sysfs file",
139 entry("FILENAME=%s", path.c_str()));
140
141 elog<WriteFailure>(xyz::openbmc_project::Control::Device::
142 WriteFailure::CALLOUT_ERRNO(rc),
143 xyz::openbmc_project::Control::Device::
144 WriteFailure::CALLOUT_DEVICE_PATH(
145 fs::canonical(basePath).c_str()));
146 }
147}
148
Matt Spinler57868bc2017-08-03 10:07:41 -0500149void PMBus::findHwmonRelativePath()
150{
151 fs::path path{basePath};
152 path /= "hwmon";
153
154 //look for <basePath>/hwmon/hwmonN/
155 for (auto& f : fs::directory_iterator(path))
156 {
157 if ((f.path().filename().string().find("hwmon") !=
158 std::string::npos) &&
159 (fs::is_directory(f.path())))
160 {
161 hwmonRelPath = "hwmon";
162 hwmonRelPath /= f.path().filename();
163 break;
164 }
165 }
166
167 //Don't really want to crash here, just log it
168 //and let accesses fail later
169 if (hwmonRelPath.empty())
170 {
171 log<level::ERR>("Unable to find hwmon directory "
172 "in device base path",
173 entry("DEVICE_PATH=%s", basePath.c_str()));
174 }
175
176}
177
Matt Spinler015e3ad2017-08-01 11:20:47 -0500178}
179}