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