blob: b78d2bce9dfaa6d5521e15aa06a0907a6999c049 [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>
24#include <phosphor-logging/elog-errors.hpp>
Kuiying Wanga9d39e32018-08-14 13:47:32 +080025#include <xyz/openbmc_project/Common/error.hpp>
Kuiying Wanga9d39e32018-08-14 13:47:32 +080026
27const static constexpr char* SYSMGR_SERVICE = "org.openbmc.managers.System";
28const static constexpr char* SYSMGR_OBJ_PATH = "/org/openbmc/managers/System";
29const static constexpr char* SYSMGR_INTERFACE = "org.openbmc.managers.System";
30
31void closeGpio(int fd)
32{
33 if (fd > 0)
34 {
35 ::close(fd);
36 }
37}
38
39int configGpio(const char* gpioName, int* fd, sdbusplus::bus::bus& bus)
40{
41 auto method = bus.new_method_call(SYSMGR_SERVICE, SYSMGR_OBJ_PATH,
42 SYSMGR_INTERFACE, "gpioInit");
43
44 method.append(gpioName);
45
46 auto result = bus.call(method);
47
48 if (result.is_method_error())
49 {
50 phosphor::logging::log<phosphor::logging::level::ERR>(
51 "bus call error!");
52 return -1;
53 }
54
55 int32_t gpioNum;
56 std::string gpioDev;
57 std::string gpioDirection;
58
59 result.read(gpioDev, gpioNum, gpioDirection);
60
61 std::string devPath;
62
63 std::fstream stream;
64
65 stream.exceptions(std::ifstream::failbit | std::ifstream::badbit);
66
67 devPath.clear();
68 devPath = gpioDev + "/gpio" + std::to_string(gpioNum) + "/value";
69
70 std::experimental::filesystem::path fullPath(devPath);
71
72 if (std::experimental::filesystem::exists(fullPath))
73 {
74 phosphor::logging::log<phosphor::logging::level::INFO>(
75 "GPIO exported",
76 phosphor::logging::entry("PATH=%s", devPath.c_str()));
77 }
78 else
79 {
80 devPath.clear();
81 devPath = gpioDev + "/export";
82
83 stream.open(devPath, std::fstream::out);
84 try
85 {
86 stream << gpioNum;
87 stream.close();
88 }
89
Patrick Venture0d9377d2018-11-01 19:34:59 -070090 catch (const std::exception& e)
Kuiying Wanga9d39e32018-08-14 13:47:32 +080091 {
92 phosphor::logging::log<phosphor::logging::level::ERR>(
93 "Error in writing!",
94 phosphor::logging::entry("PATH=%s", devPath.c_str()),
95 phosphor::logging::entry("NUM=%d", gpioNum));
96 return -1;
97 }
98 }
99
100 if (gpioDirection == "out")
101 {
102 devPath.clear();
103 devPath = gpioDev + "/gpio" + std::to_string(gpioNum) + "/value";
104
105 uint32_t currentValue;
106
107 stream.open(devPath, std::fstream::in);
108 try
109 {
110 stream >> currentValue;
111 stream.close();
112 }
113
114 catch (const std::exception& e)
115 {
116 phosphor::logging::log<phosphor::logging::level::ERR>(
117 "Error in reading!",
118 phosphor::logging::entry("PATH=%s", devPath.c_str()));
119 return -1;
120 }
121
122 const char* direction = currentValue ? "high" : "low";
123
124 devPath.clear();
125 devPath = gpioDev + "/gpio" + std::to_string(gpioNum) + "/direction";
126
127 stream.open(devPath, std::fstream::out);
128 try
129 {
130 stream << direction;
131 stream.close();
132 }
133
134 catch (const std::exception& e)
135 {
136 phosphor::logging::log<phosphor::logging::level::ERR>(
137 "Error in writing!");
138 return -1;
139 }
140 }
141 else if (gpioDirection == "in")
142 {
143 devPath.clear();
144 devPath = gpioDev + "/gpio" + std::to_string(gpioNum) + "/direction";
145
146 stream.open(devPath, std::fstream::out);
147 try
148 {
149 stream << gpioDirection;
150 stream.close();
151 }
152
153 catch (const std::exception& e)
154 {
155 phosphor::logging::log<phosphor::logging::level::ERR>(
156 "Error in writing!");
157 return -1;
158 }
159 }
160 else if ((gpioDirection == "both"))
161 {
162
163 // For gpio configured as ‘both’, it is an interrupt pin and trigged on
164 // both rising and falling signals
165 devPath.clear();
166 devPath = gpioDev + "/gpio" + std::to_string(gpioNum) + "/edge";
167
168 stream.open(devPath, std::fstream::out);
169 try
170 {
171 stream << gpioDirection;
172 stream.close();
173 }
174
175 catch (const std::exception& e)
176 {
177 phosphor::logging::log<phosphor::logging::level::ERR>(
178 "Error in writing!");
179 return -1;
180 }
181 }
182
183 devPath.clear();
184 devPath = gpioDev + "/gpio" + std::to_string(gpioNum) + "/value";
185
186 *fd = ::open(devPath.c_str(), O_RDWR | O_NONBLOCK);
187
188 if (*fd < 0)
189 {
190 phosphor::logging::log<phosphor::logging::level::ERR>("open error!");
191 return -1;
192 }
193
194 return 0;
195}