1 /**
2  * Copyright © 2017 IBM 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 #include <fcntl.h>
17 #include <phosphor-logging/elog.hpp>
18 #include <phosphor-logging/elog-errors.hpp>
19 #include <phosphor-logging/log.hpp>
20 #include <sys/ioctl.h>
21 #include <xyz/openbmc_project/Common/error.hpp>
22 #include "gpio.hpp"
23 
24 namespace witherspoon
25 {
26 namespace gpio
27 {
28 
29 using namespace phosphor::logging;
30 
31 using InternalFailure = sdbusplus::xyz::openbmc_project::Common::
32                         Error::InternalFailure;
33 
34 Value GPIO::read()
35 {
36     assert(direction == Direction::input);
37 
38     requestLine();
39 
40     gpiohandle_data data{};
41 
42     auto rc = ioctl(lineFD(),
43                     GPIOHANDLE_GET_LINE_VALUES_IOCTL,
44                     &data);
45 
46     if (rc < 0)
47     {
48         auto e = errno;
49         log<level::ERR>("Failed GET_LINE_VALUES ioctl",
50                         entry("ERRNO=%d", e));
51         elog<InternalFailure>();
52     }
53 
54     return (data.values[0] == 0) ? Value::low : Value::high;
55 }
56 
57 
58 void GPIO::requestLine()
59 {
60     //Only need to do this once
61     if (lineFD)
62     {
63         return;
64     }
65 
66     power::util::FileDescriptor fd{open(device.c_str(), 0)};
67     if (fd() == -1)
68     {
69         auto e = errno;
70         log<level::ERR>("Failed opening GPIO device",
71                         entry("DEVICE=%s", device),
72                         entry("ERRNO=%d", e));
73         elog<InternalFailure>();
74     }
75 
76     //Make an ioctl call to request the GPIO line, which will
77     //return the descriptor to use to access it.
78     gpiohandle_request request{};
79     strncpy(request.consumer_label,
80             "witherspoon-pfault-analysis",
81             sizeof(request.consumer_label));
82 
83     request.flags = (direction == Direction::input) ?
84                     GPIOHANDLE_REQUEST_INPUT : GPIOHANDLE_REQUEST_OUTPUT;
85 
86     request.lineoffsets[0] = gpio;
87     request.lines = 1;
88 
89     auto rc = ioctl(fd(), GPIO_GET_LINEHANDLE_IOCTL, &request);
90     if (rc == -1)
91     {
92         auto e = errno;
93         log<level::ERR>("Failed GET_LINEHANDLE ioctl",
94                         entry("GPIO=%d", gpio),
95                         entry("ERRNO=%d", e));
96         elog<InternalFailure>();
97     }
98 
99     lineFD.set(request.fd);
100 }
101 
102 }
103 }
104