blob: 27fc74dcabf689167f4168ea4d1d80f32174219e [file] [log] [blame]
Kuiying Wanga9d39e32018-08-14 13:47:32 +08001/*
2// Copyright (c) 2018 Intel 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
Patrick Venture0d9377d2018-11-01 19:34:59 -070017#include "gpio.hpp"
18
Kuiying Wanga9d39e32018-08-14 13:47:32 +080019#include <fcntl.h>
Patrick Venture0d9377d2018-11-01 19:34:59 -070020#include <unistd.h>
21
22#include <experimental/filesystem>
Kuiying Wanga9d39e32018-08-14 13:47:32 +080023#include <fstream>
Matt Spinler8605bdf2018-11-05 14:55:46 -060024#include <nlohmann/json.hpp>
Kuiying Wanga9d39e32018-08-14 13:47:32 +080025#include <phosphor-logging/elog-errors.hpp>
Matt Spinler8605bdf2018-11-05 14:55:46 -060026#include <phosphor-logging/log.hpp>
Kuiying Wanga9d39e32018-08-14 13:47:32 +080027#include <xyz/openbmc_project/Common/error.hpp>
Kuiying Wanga9d39e32018-08-14 13:47:32 +080028
29const static constexpr char* SYSMGR_SERVICE = "org.openbmc.managers.System";
30const static constexpr char* SYSMGR_OBJ_PATH = "/org/openbmc/managers/System";
31const static constexpr char* SYSMGR_INTERFACE = "org.openbmc.managers.System";
32
Matt Spinler8605bdf2018-11-05 14:55:46 -060033static constexpr auto gpioDefs = "/etc/default/obmc/gpio/gpio_defs.json";
34
35using namespace phosphor::logging;
36
Kuiying Wanga9d39e32018-08-14 13:47:32 +080037void closeGpio(int fd)
38{
39 if (fd > 0)
40 {
41 ::close(fd);
42 }
43}
44
Matt Spinler8605bdf2018-11-05 14:55:46 -060045bool gpioDefined(const std::string& gpioName)
46{
47 try
48 {
49 std::ifstream gpios{gpioDefs};
50 auto json = nlohmann::json::parse(gpios, nullptr, true);
51 auto defs = json["gpio_definitions"];
52
53 auto gpio =
54 std::find_if(defs.begin(), defs.end(), [&gpioName](const auto g) {
55 return gpioName == g["name"];
56 });
57
58 if (gpio != defs.end())
59 {
60 return true;
61 }
62 }
63 catch (std::exception& e)
64 {
65 log<level::ERR>("Error parsing GPIO JSON", entry("ERROR=%s", e.what()),
66 entry("GPIO_NAME=%s", gpioName.c_str()));
67 }
68 return false;
69}
70
Kuiying Wanga9d39e32018-08-14 13:47:32 +080071int configGpio(const char* gpioName, int* fd, sdbusplus::bus::bus& bus)
72{
73 auto method = bus.new_method_call(SYSMGR_SERVICE, SYSMGR_OBJ_PATH,
74 SYSMGR_INTERFACE, "gpioInit");
75
76 method.append(gpioName);
77
78 auto result = bus.call(method);
79
80 if (result.is_method_error())
81 {
Matt Spinler8605bdf2018-11-05 14:55:46 -060082 log<level::ERR>("bus call error!");
Kuiying Wanga9d39e32018-08-14 13:47:32 +080083 return -1;
84 }
85
86 int32_t gpioNum;
87 std::string gpioDev;
88 std::string gpioDirection;
89
90 result.read(gpioDev, gpioNum, gpioDirection);
91
92 std::string devPath;
93
94 std::fstream stream;
95
96 stream.exceptions(std::ifstream::failbit | std::ifstream::badbit);
97
98 devPath.clear();
99 devPath = gpioDev + "/gpio" + std::to_string(gpioNum) + "/value";
100
101 std::experimental::filesystem::path fullPath(devPath);
102
103 if (std::experimental::filesystem::exists(fullPath))
104 {
Matt Spinler8605bdf2018-11-05 14:55:46 -0600105 log<level::INFO>("GPIO exported", entry("PATH=%s", devPath.c_str()));
Kuiying Wanga9d39e32018-08-14 13:47:32 +0800106 }
107 else
108 {
109 devPath.clear();
110 devPath = gpioDev + "/export";
111
112 stream.open(devPath, std::fstream::out);
113 try
114 {
115 stream << gpioNum;
116 stream.close();
117 }
118
Patrick Venture0d9377d2018-11-01 19:34:59 -0700119 catch (const std::exception& e)
Kuiying Wanga9d39e32018-08-14 13:47:32 +0800120 {
Matt Spinler8605bdf2018-11-05 14:55:46 -0600121 log<level::ERR>("Error in writing!",
122 entry("PATH=%s", devPath.c_str()),
123 entry("NUM=%d", gpioNum));
Kuiying Wanga9d39e32018-08-14 13:47:32 +0800124 return -1;
125 }
126 }
127
128 if (gpioDirection == "out")
129 {
130 devPath.clear();
131 devPath = gpioDev + "/gpio" + std::to_string(gpioNum) + "/value";
132
133 uint32_t currentValue;
134
135 stream.open(devPath, std::fstream::in);
136 try
137 {
138 stream >> currentValue;
139 stream.close();
140 }
141
142 catch (const std::exception& e)
143 {
Matt Spinler8605bdf2018-11-05 14:55:46 -0600144 log<level::ERR>("Error in reading!",
145 entry("PATH=%s", devPath.c_str()));
Kuiying Wanga9d39e32018-08-14 13:47:32 +0800146 return -1;
147 }
148
149 const char* direction = currentValue ? "high" : "low";
150
151 devPath.clear();
152 devPath = gpioDev + "/gpio" + std::to_string(gpioNum) + "/direction";
153
154 stream.open(devPath, std::fstream::out);
155 try
156 {
157 stream << direction;
158 stream.close();
159 }
160
161 catch (const std::exception& e)
162 {
Matt Spinler8605bdf2018-11-05 14:55:46 -0600163 log<level::ERR>("Error in writing!");
Kuiying Wanga9d39e32018-08-14 13:47:32 +0800164 return -1;
165 }
166 }
167 else if (gpioDirection == "in")
168 {
169 devPath.clear();
170 devPath = gpioDev + "/gpio" + std::to_string(gpioNum) + "/direction";
171
172 stream.open(devPath, std::fstream::out);
173 try
174 {
175 stream << gpioDirection;
176 stream.close();
177 }
178
179 catch (const std::exception& e)
180 {
Matt Spinler8605bdf2018-11-05 14:55:46 -0600181 log<level::ERR>("Error in writing!");
Kuiying Wanga9d39e32018-08-14 13:47:32 +0800182 return -1;
183 }
184 }
185 else if ((gpioDirection == "both"))
186 {
187
188 // For gpio configured as ‘both’, it is an interrupt pin and trigged on
189 // both rising and falling signals
190 devPath.clear();
191 devPath = gpioDev + "/gpio" + std::to_string(gpioNum) + "/edge";
192
193 stream.open(devPath, std::fstream::out);
194 try
195 {
196 stream << gpioDirection;
197 stream.close();
198 }
199
200 catch (const std::exception& e)
201 {
Matt Spinler8605bdf2018-11-05 14:55:46 -0600202 log<level::ERR>("Error in writing!");
Kuiying Wanga9d39e32018-08-14 13:47:32 +0800203 return -1;
204 }
205 }
206
207 devPath.clear();
208 devPath = gpioDev + "/gpio" + std::to_string(gpioNum) + "/value";
209
210 *fd = ::open(devPath.c_str(), O_RDWR | O_NONBLOCK);
211
212 if (*fd < 0)
213 {
Matt Spinler8605bdf2018-11-05 14:55:46 -0600214 log<level::ERR>("open error!");
Kuiying Wanga9d39e32018-08-14 13:47:32 +0800215 return -1;
216 }
217
218 return 0;
219}