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