1 /*
2 * Copyright (C) 2016 The Android Open Source Project
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
17 #define LOG_TAG "hwc-drm-event-listener"
18
19 #include "drmeventlistener.h"
20
21 #include <assert.h>
22 #include <drm/samsung_drm.h>
23 #include <errno.h>
24 #include <hardware/hardware.h>
25 #include <hardware/hwcomposer.h>
26 #include <inttypes.h>
27 #include <linux/netlink.h>
28 #include <log/log.h>
29 #include <sys/socket.h>
30 #include <utils/String8.h>
31 #include <xf86drm.h>
32
33 #include "drmdevice.h"
34
35 namespace android {
36
DrmEventListener(DrmDevice * drm)37 DrmEventListener::DrmEventListener(DrmDevice *drm)
38 : Worker("drm-event-listener", HAL_PRIORITY_URGENT_DISPLAY), drm_(drm) {
39 }
40
~DrmEventListener()41 DrmEventListener::~DrmEventListener() {
42 Exit();
43 }
44
Init()45 int DrmEventListener::Init() {
46 struct epoll_event ev;
47 char buffer[1024];
48
49 /* Open User Event File Descriptor */
50 uevent_fd_.Set(socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT));
51 if (uevent_fd_.get() < 0) {
52 ALOGE("Failed to open uevent socket: %s", strerror(errno));
53 return uevent_fd_.get();
54 }
55
56 struct sockaddr_nl addr;
57 memset(&addr, 0, sizeof(addr));
58 addr.nl_family = AF_NETLINK;
59 addr.nl_pid = 0;
60 addr.nl_groups = 0xFFFFFFFF;
61
62 int ret = bind(uevent_fd_.get(), (struct sockaddr *)&addr, sizeof(addr));
63 if (ret) {
64 ALOGE("Failed to bind uevent socket: %s", strerror(errno));
65 return -errno;
66 }
67
68 /* Open TUI Event File Descriptor */
69 tuievent_fd_.Set(open(kTUIStatusPath, O_RDONLY));
70 if (tuievent_fd_.get() < 0) {
71 ALOGE("Failed to open sysfs(%s) for TUI event: %s", kTUIStatusPath, strerror(errno));
72 } else {
73 /* Read garbage data once */
74 pread(tuievent_fd_.get(), &buffer, sizeof(buffer), 0);
75
76 ev.events = EPOLLPRI;
77 ev.data.fd = tuievent_fd_.get();
78 if (epoll_ctl(epoll_fd_.get(), EPOLL_CTL_ADD, tuievent_fd_.get(), &ev) < 0)
79 ALOGE("Failed to add tui fd into epoll: %s", strerror(errno));
80 }
81
82 /* Set EPoll*/
83 epoll_fd_.Set(epoll_create(maxFds));
84 if (epoll_fd_.get() < 0) {
85 ALOGE("Failed to create epoll: %s", strerror(errno));
86 return epoll_fd_.get();
87 }
88
89 ev.events = EPOLLIN;
90 ev.data.fd = uevent_fd_.get();
91 if (epoll_ctl(epoll_fd_.get(), EPOLL_CTL_ADD, uevent_fd_.get(), &ev) < 0) {
92 ALOGE("Failed to add uevent fd into epoll: %s", strerror(errno));
93 return -errno;
94 }
95
96 ev.events = EPOLLIN;
97 ev.data.fd = drm_->fd();
98 if (epoll_ctl(epoll_fd_.get(), EPOLL_CTL_ADD, drm_->fd(), &ev) < 0) {
99 ALOGE("Failed to add drm fd into epoll: %s", strerror(errno));
100 return -errno;
101 }
102
103 return 0;
104 }
105
RegisterHotplugHandler(DrmEventHandler * handler)106 void DrmEventListener::RegisterHotplugHandler(DrmEventHandler *handler) {
107 assert(!hotplug_handler_);
108 hotplug_handler_.reset(handler);
109 }
110
UnRegisterHotplugHandler(DrmEventHandler * handler)111 void DrmEventListener::UnRegisterHotplugHandler(DrmEventHandler *handler) {
112 if (handler == hotplug_handler_.get())
113 hotplug_handler_ = NULL;
114 }
115
RegisterHistogramHandler(DrmHistogramEventHandler * handler)116 void DrmEventListener::RegisterHistogramHandler(DrmHistogramEventHandler *handler) {
117 assert(!histogram_handler_);
118 histogram_handler_.reset(handler);
119 }
120
UnRegisterHistogramHandler(DrmHistogramEventHandler * handler)121 void DrmEventListener::UnRegisterHistogramHandler(DrmHistogramEventHandler *handler) {
122 if (handler == histogram_handler_.get()) histogram_handler_ = NULL;
123 }
124
RegisterHistogramChannelHandler(DrmHistogramChannelEventHandler * handler)125 void DrmEventListener::RegisterHistogramChannelHandler(DrmHistogramChannelEventHandler *handler) {
126 assert(!histogram_channel_handler_);
127
128 if (handler) {
129 histogram_channel_handler_.reset(handler);
130 } else {
131 ALOGE("%s: failed to register, handler is nullptr", __func__);
132 }
133 }
134
UnRegisterHistogramChannelHandler(DrmHistogramChannelEventHandler * handler)135 void DrmEventListener::UnRegisterHistogramChannelHandler(DrmHistogramChannelEventHandler *handler) {
136 if (handler == histogram_channel_handler_.get()) {
137 histogram_channel_handler_ = NULL;
138 } else {
139 ALOGE("%s: failed to unregister, handler(%p), histogram_channel_handler(%p)", __func__,
140 handler, histogram_channel_handler_.get());
141 }
142 }
143
RegisterTUIHandler(DrmTUIEventHandler * handler)144 void DrmEventListener::RegisterTUIHandler(DrmTUIEventHandler *handler) {
145 if (tui_handler_) {
146 ALOGE("TUI handler was already registered");
147 return;
148 }
149 tui_handler_.reset(handler);
150 }
151
UnRegisterTUIHandler(DrmTUIEventHandler * handler)152 void DrmEventListener::UnRegisterTUIHandler(DrmTUIEventHandler *handler) {
153 if (handler == tui_handler_.get())
154 tui_handler_ = NULL;
155 }
156
RegisterPanelIdleHandler(DrmPanelIdleEventHandler * handler)157 void DrmEventListener::RegisterPanelIdleHandler(DrmPanelIdleEventHandler *handler) {
158 assert(!panel_idle_handler_);
159 panel_idle_handler_.reset(handler);
160 }
161
UnRegisterPanelIdleHandler(DrmPanelIdleEventHandler * handler)162 void DrmEventListener::UnRegisterPanelIdleHandler(DrmPanelIdleEventHandler *handler) {
163 if (handler == panel_idle_handler_.get())
164 panel_idle_handler_ = NULL;
165 }
166
RegisterSysfsHandler(std::shared_ptr<DrmSysfsEventHandler> handler)167 int DrmEventListener::RegisterSysfsHandler(std::shared_ptr<DrmSysfsEventHandler> handler) {
168 if (!handler)
169 return -EINVAL;
170 if (handler->getFd() < 0)
171 return -EINVAL;
172 std::scoped_lock lock(mutex_);
173 if (sysfs_handlers_.find(handler->getFd()) != sysfs_handlers_.end()) {
174 ALOGE("%s: DrmSysfsEventHandler for fd:%d has been added to epoll", __func__, handler->getFd());
175 return -EINVAL;
176 }
177
178 struct epoll_event ev;
179 ev.events = EPOLLPRI;
180 ev.data.fd = handler->getFd();
181 if (epoll_ctl(epoll_fd_.get(), EPOLL_CTL_ADD, handler->getFd(), &ev) < 0) {
182 ALOGE("%s: Failed to add fd into epoll: %s", __func__, strerror(errno));
183 return -errno;
184 }
185 sysfs_handlers_.emplace(handler->getFd(), std::move(handler));
186 return 0;
187 }
188
UnRegisterSysfsHandler(int sysfs_fd)189 int DrmEventListener::UnRegisterSysfsHandler(int sysfs_fd) {
190 std::scoped_lock lock(mutex_);
191 auto it = sysfs_handlers_.find(sysfs_fd);
192 if (it == sysfs_handlers_.end()) {
193 ALOGE("%s: DrmSysfsEventHandler for fd:%d not found", __func__, sysfs_fd);
194 return -EINVAL;
195 }
196 if (epoll_ctl(epoll_fd_.get(), EPOLL_CTL_DEL, sysfs_fd, nullptr) < 0) {
197 ALOGE("%s: Failed to remove fd from epoll: %s", __func__, strerror(errno));
198 return -errno;
199 }
200 sysfs_handlers_.erase(it);
201 return 0;
202 }
203
IsDrmInTUI()204 bool DrmEventListener::IsDrmInTUI() {
205 char buffer[1024];
206 int ret;
207
208 if (tuievent_fd_.get() >= 0) {
209 ret = pread(tuievent_fd_.get(), &buffer, sizeof(buffer), 0);
210 if (ret == 0) {
211 return false;
212 } else if (ret < 0) {
213 ALOGE("Got error reading TUI event %s", strerror(errno));
214 return false;
215 }
216
217 return atoi(buffer) == 1 ? true : false;
218 }
219
220 return false;
221 }
222
FlipHandler(int,unsigned int,unsigned int tv_sec,unsigned int tv_usec,void * user_data)223 void DrmEventListener::FlipHandler(int /* fd */, unsigned int /* sequence */,
224 unsigned int tv_sec, unsigned int tv_usec,
225 void *user_data) {
226 DrmEventHandler *handler = (DrmEventHandler *)user_data;
227 if (!handler)
228 return;
229
230 handler->handleEvent((uint64_t)tv_sec * 1000 * 1000 + tv_usec);
231 delete handler;
232 }
233
UEventHandler()234 void DrmEventListener::UEventHandler() {
235 char buffer[1024];
236 int ret;
237
238 struct timespec ts;
239 uint64_t timestamp = 0;
240 ret = clock_gettime(CLOCK_MONOTONIC, &ts);
241 if (!ret)
242 timestamp = ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
243 else
244 ALOGE("Failed to get monotonic clock on hotplug %d", ret);
245
246 ret = read(uevent_fd_.get(), &buffer, sizeof(buffer));
247 if (ret == 0) {
248 return;
249 } else if (ret < 0) {
250 ALOGE("Got error reading uevent %d", ret);
251 return;
252 }
253
254 bool drm_event = false, hotplug_event = false;
255 for (int i = 0; i < ret;) {
256 char *event = buffer + i;
257
258 if (!strcmp(event, "DEVTYPE=drm_minor")) {
259 drm_event = true;
260 } else if (!strncmp(event, "PANEL_IDLE_ENTER=", strlen("PANEL_IDLE_ENTER="))) {
261 panel_idle_handler_->handleIdleEnterEvent(event);
262 } else if (!strcmp(event, "HOTPLUG=1")) {
263 hotplug_event = true;
264 }
265
266 i += strlen(event) + 1;
267 }
268
269 if (drm_event && hotplug_event) {
270 if (!hotplug_handler_)
271 return;
272
273 hotplug_handler_->handleEvent(timestamp);
274 }
275 }
276
DRMEventHandler()277 void DrmEventListener::DRMEventHandler() {
278 char buffer[1024];
279 int len, i;
280 struct drm_event *e;
281 struct drm_event_vblank *vblank;
282 struct exynos_drm_histogram_event *histo;
283 void *user_data;
284
285 len = read(drm_->fd(), &buffer, sizeof(buffer));
286 if (len == 0) return;
287 if (len < (int)sizeof(*e)) return;
288
289 i = 0;
290 while (i < len) {
291 e = (struct drm_event *)(buffer + i);
292 switch (e->type) {
293 case EXYNOS_DRM_HISTOGRAM_EVENT:
294 if (histogram_handler_) {
295 histo = (struct exynos_drm_histogram_event *)e;
296 histogram_handler_->handleHistogramEvent(histo->crtc_id,
297 (void *)&(histo->bins));
298 }
299 break;
300 #if defined(EXYNOS_DRM_HISTOGRAM_CHANNEL_EVENT)
301 case EXYNOS_DRM_HISTOGRAM_CHANNEL_EVENT:
302 if (histogram_channel_handler_) {
303 histogram_channel_handler_->handleHistogramChannelEvent((void *)e);
304 } else {
305 ALOGE("%s: no valid histogram channel event handler", __func__);
306 }
307 break;
308 #endif
309 case DRM_EVENT_FLIP_COMPLETE:
310 vblank = (struct drm_event_vblank *)e;
311 user_data = (void *)(unsigned long)(vblank->user_data);
312 FlipHandler(drm_->fd(), vblank->sequence, vblank->tv_sec, vblank->tv_usec,
313 user_data);
314 break;
315 case DRM_EVENT_VBLANK:
316 case DRM_EVENT_CRTC_SEQUENCE:
317 /* These DRM events are not handled */
318 break;
319 default:
320 break;
321 }
322 i += e->length;
323 }
324
325 return;
326 }
327
TUIEventHandler()328 void DrmEventListener::TUIEventHandler() {
329 if (!tui_handler_) {
330 ALOGE("%s:: tui event handler is not valid", __func__);
331 return;
332 }
333
334 tui_handler_->handleTUIEvent();
335 }
336
SysfsEventHandler(int fd)337 void DrmEventListener::SysfsEventHandler(int fd) {
338 std::shared_ptr<DrmSysfsEventHandler> handler;
339 {
340 std::scoped_lock lock(mutex_);
341 // Copy the shared_ptr to avoid the handler object gets destroyed
342 // while it's handling the event without holding mutex_
343 auto it = sysfs_handlers_.find(fd);
344 if (it != sysfs_handlers_.end())
345 handler = it->second;
346 }
347 if (handler) {
348 handler->handleSysfsEvent();
349 } else {
350 ALOGW("Unhandled sysfs event from fd:%d", fd);
351 }
352 }
353
Routine()354 void DrmEventListener::Routine() {
355 struct epoll_event events[maxFds];
356 int nfds, n;
357
358 do {
359 nfds = epoll_wait(epoll_fd_.get(), events, maxFds, -1);
360 } while (nfds <= 0);
361
362 for (n = 0; n < nfds; n++) {
363 if (events[n].events & EPOLLIN) {
364 if (events[n].data.fd == uevent_fd_.get()) {
365 UEventHandler();
366 } else if (events[n].data.fd == drm_->fd()) {
367 DRMEventHandler();
368 }
369 } else if (events[n].events & EPOLLPRI) {
370 if (tuievent_fd_.get() >= 0 && events[n].data.fd == tuievent_fd_.get()) {
371 TUIEventHandler();
372 } else {
373 SysfsEventHandler(events[n].data.fd);
374 }
375 }
376 }
377 }
378 } // namespace android
379