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