blob: b87e139142b647ff47da47a0d7b27ebc183f0825 [file] [log] [blame]
Gunnar Mills5f101102017-06-29 13:07:39 -05001#include <libevdev/libevdev.h>
2#include <fcntl.h>
3#include <phosphor-logging/elog.hpp>
4#include <phosphor-logging/log.hpp>
5#include <phosphor-logging/elog-errors.hpp>
6#include "xyz/openbmc_project/Common/error.hpp"
Gunnar Mills72639152017-06-22 15:06:21 -05007#include "gpio_presence.hpp"
8
9namespace phosphor
10{
11namespace gpio
12{
13namespace presence
14{
15
Gunnar Mills5f101102017-06-29 13:07:39 -050016using namespace phosphor::logging;
17using namespace sdbusplus::xyz::openbmc_project::Common::Error;
18
Gunnar Mills80292bb2017-07-05 16:34:51 -050019constexpr auto INVENTORY_PATH = "/xyz/openbmc_project/inventory";
20constexpr auto INVENTORY_INTF = "xyz.openbmc_project.Inventory.Manager";
21
22constexpr auto MAPPER_BUSNAME = "xyz.openbmc_project.ObjectMapper";
23constexpr auto MAPPER_PATH = "/xyz/openbmc_project/object_mapper";
24constexpr auto MAPPER_INTERFACE = "xyz.openbmc_project.ObjectMapper";
25
26std::string getService(const std::string& path,
27 const std::string& interface,
28 sdbusplus::bus::bus& bus)
29{
30 auto mapperCall = bus.new_method_call(MAPPER_BUSNAME,
31 MAPPER_PATH,
32 MAPPER_INTERFACE,
33 "GetObject");
34
35 mapperCall.append(path);
36 mapperCall.append(std::vector<std::string>({interface}));
37
38 auto mapperResponseMsg = bus.call(mapperCall);
39 if (mapperResponseMsg.is_method_error())
40 {
41 log<level::ERR>("Error in mapper call to get service name",
42 entry("PATH=%s", path.c_str()),
43 entry("INTERFACE=%s", interface.c_str()));
44 elog<InternalFailure>();
45 }
46
47
48 std::map<std::string, std::vector<std::string>> mapperResponse;
49 mapperResponseMsg.read(mapperResponse);
50
51 if (mapperResponse.empty())
52 {
53 log<level::ERR>(
54 "Error in mapper response for getting service name",
55 entry("PATH=%s", path.c_str()),
56 entry("INTERFACE=%s", interface.c_str()));
57 elog<InternalFailure>();
58 }
59
60 return mapperResponse.begin()->first;
61}
62
Gunnar Mills5f101102017-06-29 13:07:39 -050063void Presence::determinePresence()
64{
Gunnar Mills80292bb2017-07-05 16:34:51 -050065 auto present = false;
Gunnar Mills5f101102017-06-29 13:07:39 -050066 auto value = static_cast<int>(0);
67 auto fetch_rc = libevdev_fetch_event_value(devicePtr.get(), EV_KEY,
68 key, &value);
69 if (0 == fetch_rc)
70 {
71 log<level::ERR>("Device does not support event type",
72 entry("KEYCODE=%d", key));
73 elog<InternalFailure>();
74 return;
75 }
Gunnar Mills80292bb2017-07-05 16:34:51 -050076 if (value > 0)
77 {
78 present = true;
79 }
80
81 updateInventory(present);
Gunnar Mills5f101102017-06-29 13:07:39 -050082}
83
Gunnar Mills765725e2017-07-06 14:17:44 -050084// Callback handler when there is an activity on the FD
85int Presence::processEvents(sd_event_source* es, int fd,
86 uint32_t revents, void* userData)
87{
88 auto presence = static_cast<Presence*>(userData);
89
90 presence->analyzeEvent();
91 return 0;
92}
93
94
95// Analyzes the GPIO event
96void Presence::analyzeEvent()
97{
98
99 // Data returned
100 struct input_event ev {};
101 int rc = 0;
102
103 // While testing, observed that not having a loop here was leading
104 // into events being missed.
105 while (rc >= 0)
106 {
107 // Wait until no more events are available on the device.
108 rc = libevdev_next_event(devicePtr.get(),
109 LIBEVDEV_READ_FLAG_NORMAL, &ev);
110 if (rc < 0)
111 {
112 // There was an error waiting for events, mostly that there are no
113 // events to be read.. So continue waiting...
114 return;
115 }
116
117 if (rc == LIBEVDEV_READ_STATUS_SUCCESS)
118 {
119 if (ev.type == EV_SYN && ev.code == SYN_REPORT)
120 {
121 continue;
122 }
123 else if (ev.code == key)
124 {
125 auto present = false;
126 if (ev.value > 0)
127 {
128 present = true;
129 }
130 updateInventory(present);
131 }
132 }
133 }
134
135 return;
136}
Gunnar Mills80292bb2017-07-05 16:34:51 -0500137
138Presence::ObjectMap Presence::getObjectMap(bool present)
139{
140 ObjectMap invObj;
141 InterfaceMap invIntf;
142 PropertyMap invProp;
143
144 invProp.emplace("Present", present);
145 invProp.emplace("PrettyName", name);
146 invIntf.emplace("xyz.openbmc_project.Inventory.Item",
147 std::move(invProp));
148 invObj.emplace(std::move(inventory), std::move(invIntf));
149
150 return invObj;
151}
152
153void Presence::updateInventory(bool present)
154{
155 ObjectMap invObj = getObjectMap(present);
156
Gunnar Mills765725e2017-07-06 14:17:44 -0500157 log<level::INFO>("Updating inventory present property",
158 entry("PRESENT=%d", present),
159 entry("PATH=%s", inventory));
160
Gunnar Mills80292bb2017-07-05 16:34:51 -0500161 auto invService = getService(INVENTORY_PATH, INVENTORY_INTF, bus);
162
163 // Update inventory
164 auto invMsg = bus.new_method_call(invService.c_str(),
165 INVENTORY_PATH,
166 INVENTORY_INTF,
167 "Notify");
168 invMsg.append(std::move(invObj));
169 auto invMgrResponseMsg = bus.call(invMsg);
170 if (invMgrResponseMsg.is_method_error())
171 {
172 log<level::ERR>(
173 "Error in inventory manager call to update inventory");
174 elog<InternalFailure>();
175 }
176}
177
178
Gunnar Mills72639152017-06-22 15:06:21 -0500179} // namespace presence
180} // namespace gpio
181} // namespace phosphor
182