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 "gpio.hpp"
17 
18 #include "rpolicy.hpp"
19 
20 #include <phosphor-logging/elog-errors.hpp>
21 #include <phosphor-logging/elog.hpp>
22 #include <sdeventplus/event.hpp>
23 #include <xyz/openbmc_project/Common/Callout/error.hpp>
24 
25 #include <functional>
26 #include <tuple>
27 
28 namespace phosphor
29 {
30 namespace fan
31 {
32 namespace presence
33 {
34 
35 Gpio::Gpio(const std::string& physDevice, const std::string& device,
36            unsigned int physPin) :
37     currentState(false),
38     evdevfd(open(device.c_str(), O_RDONLY | O_NONBLOCK)),
39     evdev(evdevpp::evdev::newFromFD(evdevfd())), phys(physDevice), pin(physPin)
40 {}
41 
42 bool Gpio::start()
43 {
44     source.emplace(sdeventplus::Event::get_default(), evdevfd(), EPOLLIN,
45                    std::bind(&Gpio::ioCallback, this));
46     currentState = present();
47     return currentState;
48 }
49 
50 void Gpio::stop()
51 {
52     source.reset();
53 }
54 
55 bool Gpio::present()
56 {
57     return evdev.fetch(EV_KEY, pin) != 0;
58 }
59 
60 void Gpio::fail()
61 {
62     using namespace sdbusplus::xyz::openbmc_project::Common::Callout::Error;
63     using namespace phosphor::logging;
64     using namespace xyz::openbmc_project::Common::Callout;
65 
66     report<sdbusplus::xyz::openbmc_project::Common::Callout::Error::GPIO>(
67         GPIO::CALLOUT_GPIO_NUM(pin), GPIO::CALLOUT_ERRNO(0),
68         GPIO::CALLOUT_DEVICE_PATH(phys.c_str()));
69 }
70 
71 void Gpio::ioCallback()
72 {
73     unsigned int type, code, value;
74 
75     std::tie(type, code, value) = evdev.next();
76     if (type != EV_KEY || code != pin)
77     {
78         return;
79     }
80 
81     bool newState = value != 0;
82 
83     if (currentState != newState)
84     {
85         getPolicy().stateChanged(newState, *this);
86         currentState = newState;
87     }
88 }
89 } // namespace presence
90 } // namespace fan
91 } // namespace phosphor
92