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