1*a9d39e30SKuiying Wang /*
2*a9d39e30SKuiying Wang // Copyright (c) 2018 Intel Corporation
3*a9d39e30SKuiying Wang //
4*a9d39e30SKuiying Wang // Licensed under the Apache License, Version 2.0 (the "License");
5*a9d39e30SKuiying Wang // you may not use this file except in compliance with the License.
6*a9d39e30SKuiying Wang // You may obtain a copy of the License at
7*a9d39e30SKuiying Wang //
8*a9d39e30SKuiying Wang //      http://www.apache.org/licenses/LICENSE-2.0
9*a9d39e30SKuiying Wang //
10*a9d39e30SKuiying Wang // Unless required by applicable law or agreed to in writing, software
11*a9d39e30SKuiying Wang // distributed under the License is distributed on an "AS IS" BASIS,
12*a9d39e30SKuiying Wang // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*a9d39e30SKuiying Wang // See the License for the specific language governing permissions and
14*a9d39e30SKuiying Wang // limitations under the License.
15*a9d39e30SKuiying Wang */
16*a9d39e30SKuiying Wang 
17*a9d39e30SKuiying Wang #pragma once
18*a9d39e30SKuiying Wang #include <phosphor-logging/elog-errors.hpp>
19*a9d39e30SKuiying Wang #include <unistd.h>
20*a9d39e30SKuiying Wang #include "xyz/openbmc_project/Chassis/Common/error.hpp"
21*a9d39e30SKuiying Wang #include "xyz/openbmc_project/Chassis/Buttons/Reset/server.hpp"
22*a9d39e30SKuiying Wang #include "common.hpp"
23*a9d39e30SKuiying Wang #include "gpio.hpp"
24*a9d39e30SKuiying Wang 
25*a9d39e30SKuiying Wang const static constexpr char* RESET_BUTTON = "RESET_BUTTON";
26*a9d39e30SKuiying Wang 
27*a9d39e30SKuiying Wang struct ResetButton
28*a9d39e30SKuiying Wang     : sdbusplus::server::object::object<
29*a9d39e30SKuiying Wang           sdbusplus::xyz::openbmc_project::Chassis::Buttons::server::Reset>
30*a9d39e30SKuiying Wang {
31*a9d39e30SKuiying Wang 
32*a9d39e30SKuiying Wang     ResetButton(sdbusplus::bus::bus& bus, const char* path,
33*a9d39e30SKuiying Wang                 EventPtr& event,
34*a9d39e30SKuiying Wang                 sd_event_io_handler_t handler = ResetButton::EventHandler) :
35*a9d39e30SKuiying Wang         sdbusplus::server::object::object<
36*a9d39e30SKuiying Wang             sdbusplus::xyz::openbmc_project::Chassis::Buttons::server::Reset>(
37*a9d39e30SKuiying Wang             bus, path),
38*a9d39e30SKuiying Wang         fd(-1), bus(bus), event(event), callbackHandler(handler)
39*a9d39e30SKuiying Wang     {
40*a9d39e30SKuiying Wang 
41*a9d39e30SKuiying Wang         int ret = -1;
42*a9d39e30SKuiying Wang 
43*a9d39e30SKuiying Wang         // config gpio
44*a9d39e30SKuiying Wang         ret = ::configGpio(RESET_BUTTON, &fd, bus);
45*a9d39e30SKuiying Wang         if (ret < 0)
46*a9d39e30SKuiying Wang         {
47*a9d39e30SKuiying Wang             phosphor::logging::log<phosphor::logging::level::ERR>(
48*a9d39e30SKuiying Wang                 "RESET_BUTTON: failed to config GPIO");
49*a9d39e30SKuiying Wang             throw sdbusplus::xyz::openbmc_project::Chassis::Common::
50*a9d39e30SKuiying Wang                 Error::IOError();
51*a9d39e30SKuiying Wang         }
52*a9d39e30SKuiying Wang 
53*a9d39e30SKuiying Wang         ret = sd_event_add_io(event.get(), nullptr, fd, EPOLLPRI,
54*a9d39e30SKuiying Wang                               callbackHandler, this);
55*a9d39e30SKuiying Wang         if (ret < 0)
56*a9d39e30SKuiying Wang         {
57*a9d39e30SKuiying Wang             phosphor::logging::log<phosphor::logging::level::ERR>(
58*a9d39e30SKuiying Wang                 "RESET_BUTTON: failed to add to event loop");
59*a9d39e30SKuiying Wang             ::closeGpio(fd);
60*a9d39e30SKuiying Wang             throw sdbusplus::xyz::openbmc_project::Chassis::Common::
61*a9d39e30SKuiying Wang                 Error::IOError();
62*a9d39e30SKuiying Wang         }
63*a9d39e30SKuiying Wang     }
64*a9d39e30SKuiying Wang 
65*a9d39e30SKuiying Wang     ~ResetButton()
66*a9d39e30SKuiying Wang     {
67*a9d39e30SKuiying Wang         ::closeGpio(fd);
68*a9d39e30SKuiying Wang     }
69*a9d39e30SKuiying Wang 
70*a9d39e30SKuiying Wang     void simPress() override;
71*a9d39e30SKuiying Wang 
72*a9d39e30SKuiying Wang     static int EventHandler(sd_event_source* es, int fd,
73*a9d39e30SKuiying Wang                             uint32_t revents, void* userdata)
74*a9d39e30SKuiying Wang     {
75*a9d39e30SKuiying Wang 
76*a9d39e30SKuiying Wang         int n = -1;
77*a9d39e30SKuiying Wang         char buf = '0';
78*a9d39e30SKuiying Wang 
79*a9d39e30SKuiying Wang         if (!userdata)
80*a9d39e30SKuiying Wang         {
81*a9d39e30SKuiying Wang             phosphor::logging::log<phosphor::logging::level::ERR>(
82*a9d39e30SKuiying Wang                 "RESET_BUTTON: userdata null!");
83*a9d39e30SKuiying Wang             throw sdbusplus::xyz::openbmc_project::Chassis::Common::
84*a9d39e30SKuiying Wang                 Error::IOError();
85*a9d39e30SKuiying Wang         }
86*a9d39e30SKuiying Wang 
87*a9d39e30SKuiying Wang         ResetButton* resetButton = static_cast<ResetButton*>(userdata);
88*a9d39e30SKuiying Wang 
89*a9d39e30SKuiying Wang         if (!resetButton)
90*a9d39e30SKuiying Wang         {
91*a9d39e30SKuiying Wang             phosphor::logging::log<phosphor::logging::level::ERR>(
92*a9d39e30SKuiying Wang                 "RESET_BUTTON: null pointer!");
93*a9d39e30SKuiying Wang             throw sdbusplus::xyz::openbmc_project::Chassis::Common::
94*a9d39e30SKuiying Wang                 Error::IOError();
95*a9d39e30SKuiying Wang         }
96*a9d39e30SKuiying Wang 
97*a9d39e30SKuiying Wang         n = ::lseek(fd, 0, SEEK_SET);
98*a9d39e30SKuiying Wang 
99*a9d39e30SKuiying Wang         if (n < 0)
100*a9d39e30SKuiying Wang         {
101*a9d39e30SKuiying Wang             phosphor::logging::log<phosphor::logging::level::ERR>(
102*a9d39e30SKuiying Wang                 "RESET_BUTTON: lseek error!");
103*a9d39e30SKuiying Wang             throw sdbusplus::xyz::openbmc_project::Chassis::Common::
104*a9d39e30SKuiying Wang                 Error::IOError();
105*a9d39e30SKuiying Wang         }
106*a9d39e30SKuiying Wang 
107*a9d39e30SKuiying Wang         n = ::read(fd, &buf, sizeof(buf));
108*a9d39e30SKuiying Wang         if (n < 0)
109*a9d39e30SKuiying Wang         {
110*a9d39e30SKuiying Wang             phosphor::logging::log<phosphor::logging::level::ERR>(
111*a9d39e30SKuiying Wang                 "RESET_BUTTON: read error!");
112*a9d39e30SKuiying Wang             throw sdbusplus::xyz::openbmc_project::Chassis::Common::
113*a9d39e30SKuiying Wang                 Error::IOError();
114*a9d39e30SKuiying Wang         }
115*a9d39e30SKuiying Wang 
116*a9d39e30SKuiying Wang         if (buf == '0')
117*a9d39e30SKuiying Wang         {
118*a9d39e30SKuiying Wang             phosphor::logging::log<phosphor::logging::level::DEBUG>(
119*a9d39e30SKuiying Wang                 "RESET_BUTTON: pressed");
120*a9d39e30SKuiying Wang             // emit pressed signal
121*a9d39e30SKuiying Wang             resetButton->pressed();
122*a9d39e30SKuiying Wang         }
123*a9d39e30SKuiying Wang         else
124*a9d39e30SKuiying Wang         {
125*a9d39e30SKuiying Wang             phosphor::logging::log<phosphor::logging::level::DEBUG>(
126*a9d39e30SKuiying Wang                 "RESET_BUTTON: released");
127*a9d39e30SKuiying Wang             // released
128*a9d39e30SKuiying Wang             resetButton->released();
129*a9d39e30SKuiying Wang         }
130*a9d39e30SKuiying Wang 
131*a9d39e30SKuiying Wang         return 0;
132*a9d39e30SKuiying Wang     }
133*a9d39e30SKuiying Wang 
134*a9d39e30SKuiying Wang   private:
135*a9d39e30SKuiying Wang     int fd;
136*a9d39e30SKuiying Wang     sdbusplus::bus::bus& bus;
137*a9d39e30SKuiying Wang     EventPtr& event;
138*a9d39e30SKuiying Wang     sd_event_io_handler_t callbackHandler;
139*a9d39e30SKuiying Wang };
140