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