• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "drmdevice.h"
21 #include <drm/samsung_drm.h>
22 
23 #include <assert.h>
24 #include <errno.h>
25 #include <linux/netlink.h>
26 #include <sys/socket.h>
27 
28 #include <hardware/hardware.h>
29 #include <hardware/hwcomposer.h>
30 #include <log/log.h>
31 #include <xf86drm.h>
32 
33 namespace android {
34 
DrmEventListener(DrmDevice * drm)35 DrmEventListener::DrmEventListener(DrmDevice *drm)
36     : Worker("drm-event-listener", HAL_PRIORITY_URGENT_DISPLAY), drm_(drm) {
37 }
38 
~DrmEventListener()39 DrmEventListener::~DrmEventListener() {
40     Exit();
41 }
42 
Init()43 int DrmEventListener::Init() {
44   struct epoll_event ev;
45   char buffer[1024];
46 
47   /* Open User Event File Descriptor */
48   uevent_fd_.Set(socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT));
49   if (uevent_fd_.get() < 0) {
50     ALOGE("Failed to open uevent socket: %s", strerror(errno));
51     return uevent_fd_.get();
52   }
53 
54   struct sockaddr_nl addr;
55   memset(&addr, 0, sizeof(addr));
56   addr.nl_family = AF_NETLINK;
57   addr.nl_pid = 0;
58   addr.nl_groups = 0xFFFFFFFF;
59 
60   int ret = bind(uevent_fd_.get(), (struct sockaddr *)&addr, sizeof(addr));
61   if (ret) {
62     ALOGE("Failed to bind uevent socket: %s", strerror(errno));
63     return -errno;
64   }
65 
66   /* Open TUI Event File Descriptor */
67   tuievent_fd_.Set(open(kTUIStatusPath, O_RDONLY));
68   if (tuievent_fd_.get() < 0) {
69     ALOGE("Failed to open sysfs(%s) for TUI event: %s", kTUIStatusPath, strerror(errno));
70   } else {
71     /* Read garbage data once */
72     pread(tuievent_fd_.get(), &buffer, sizeof(buffer), 0);
73 
74     ev.events = EPOLLPRI;
75     ev.data.fd = tuievent_fd_.get();
76     if (epoll_ctl(epoll_fd_.get(), EPOLL_CTL_ADD, tuievent_fd_.get(), &ev) < 0)
77       ALOGE("Failed to add tui fd into epoll: %s", strerror(errno));
78   }
79 
80   /* Set EPoll*/
81   epoll_fd_.Set(epoll_create(maxFds));
82   if (epoll_fd_.get() < 0) {
83     ALOGE("Failed to create epoll: %s", strerror(errno));
84     return epoll_fd_.get();
85   }
86 
87   ev.events = EPOLLIN;
88   ev.data.fd = uevent_fd_.get();
89   if (epoll_ctl(epoll_fd_.get(), EPOLL_CTL_ADD, uevent_fd_.get(), &ev) < 0) {
90     ALOGE("Failed to add uevent fd into epoll: %s", strerror(errno));
91     return -errno;
92   }
93 
94   ev.events = EPOLLIN;
95   ev.data.fd = drm_->fd();
96   if (epoll_ctl(epoll_fd_.get(), EPOLL_CTL_ADD, drm_->fd(), &ev) < 0) {
97     ALOGE("Failed to add drm fd into epoll: %s", strerror(errno));
98     return -errno;
99   }
100 
101   return InitWorker();
102 }
103 
RegisterHotplugHandler(DrmEventHandler * handler)104 void DrmEventListener::RegisterHotplugHandler(DrmEventHandler *handler) {
105   assert(!hotplug_handler_);
106   hotplug_handler_.reset(handler);
107 }
108 
UnRegisterHotplugHandler(DrmEventHandler * handler)109 void DrmEventListener::UnRegisterHotplugHandler(DrmEventHandler *handler) {
110   if (handler == hotplug_handler_.get())
111     hotplug_handler_ = NULL;
112 }
113 
RegisterHistogramHandler(DrmHistogramEventHandler * handler)114 void DrmEventListener::RegisterHistogramHandler(DrmHistogramEventHandler *handler) {
115     assert(!histogram_handler_);
116     histogram_handler_.reset(handler);
117 }
118 
UnRegisterHistogramHandler(DrmHistogramEventHandler * handler)119 void DrmEventListener::UnRegisterHistogramHandler(DrmHistogramEventHandler *handler) {
120     if (handler == histogram_handler_.get()) histogram_handler_ = NULL;
121 }
122 
RegisterTUIHandler(DrmTUIEventHandler * handler)123 void DrmEventListener::RegisterTUIHandler(DrmTUIEventHandler *handler) {
124   if (tui_handler_) {
125     ALOGE("TUI handler was already registered");
126     return;
127   }
128   tui_handler_.reset(handler);
129 }
130 
UnRegisterTUIHandler(DrmTUIEventHandler * handler)131 void DrmEventListener::UnRegisterTUIHandler(DrmTUIEventHandler *handler) {
132   if (handler == tui_handler_.get())
133     tui_handler_ = NULL;
134 }
135 
RegisterPanelIdleHandler(DrmPanelIdleEventHandler * handler)136 void DrmEventListener::RegisterPanelIdleHandler(DrmPanelIdleEventHandler *handler) {
137   assert(!panel_idle_handler_);
138   panel_idle_handler_.reset(handler);
139 }
140 
UnRegisterPanelIdleHandler(DrmPanelIdleEventHandler * handler)141 void DrmEventListener::UnRegisterPanelIdleHandler(DrmPanelIdleEventHandler *handler) {
142   if (handler == panel_idle_handler_.get())
143     panel_idle_handler_ = NULL;
144 }
145 
IsDrmInTUI()146 bool DrmEventListener::IsDrmInTUI() {
147   char buffer[1024];
148   int ret;
149 
150   if (tuievent_fd_.get() >= 0) {
151     ret = pread(tuievent_fd_.get(), &buffer, sizeof(buffer), 0);
152     if (ret == 0) {
153       return false;
154     } else if (ret < 0) {
155       ALOGE("Got error reading TUI event %s", strerror(errno));
156       return false;
157     }
158 
159     return atoi(buffer) == 1 ? true : false;
160   }
161 
162   return false;
163 }
164 
FlipHandler(int,unsigned int,unsigned int tv_sec,unsigned int tv_usec,void * user_data)165 void DrmEventListener::FlipHandler(int /* fd */, unsigned int /* sequence */,
166                                    unsigned int tv_sec, unsigned int tv_usec,
167                                    void *user_data) {
168   DrmEventHandler *handler = (DrmEventHandler *)user_data;
169   if (!handler)
170     return;
171 
172   handler->handleEvent((uint64_t)tv_sec * 1000 * 1000 + tv_usec);
173   delete handler;
174 }
175 
UEventHandler()176 void DrmEventListener::UEventHandler() {
177   char buffer[1024];
178   int ret;
179 
180   struct timespec ts;
181   uint64_t timestamp = 0;
182   ret = clock_gettime(CLOCK_MONOTONIC, &ts);
183   if (!ret)
184     timestamp = ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
185   else
186     ALOGE("Failed to get monotonic clock on hotplug %d", ret);
187 
188   ret = read(uevent_fd_.get(), &buffer, sizeof(buffer));
189   if (ret == 0) {
190     return;
191   } else if (ret < 0) {
192     ALOGE("Got error reading uevent %d", ret);
193     return;
194   }
195 
196   bool drm_event = false, hotplug_event = false;
197   for (int i = 0; i < ret;) {
198     char *event = buffer + i;
199 
200     if (!strcmp(event, "DEVTYPE=drm_minor")) {
201       drm_event = true;
202     } else if (!strncmp(event, "PANEL_IDLE_ENTER=", strlen("PANEL_IDLE_ENTER="))) {
203       panel_idle_handler_->handleIdleEnterEvent(event);
204     } else if (!strcmp(event, "HOTPLUG=1")) {
205       hotplug_event = true;
206     }
207 
208     i += strlen(event) + 1;
209   }
210 
211   if (drm_event && hotplug_event) {
212     if (!hotplug_handler_)
213       return;
214 
215     hotplug_handler_->handleEvent(timestamp);
216   }
217 }
218 
DRMEventHandler()219 void DrmEventListener::DRMEventHandler() {
220     char buffer[1024];
221     int len, i;
222     struct drm_event *e;
223     struct drm_event_vblank *vblank;
224     struct exynos_drm_histogram_event *histo;
225     void *user_data;
226 
227     len = read(drm_->fd(), &buffer, sizeof(buffer));
228     if (len == 0) return;
229     if (len < (int)sizeof(*e)) return;
230 
231     i = 0;
232     while (i < len) {
233         e = (struct drm_event *)(buffer + i);
234         switch (e->type) {
235             case EXYNOS_DRM_HISTOGRAM_EVENT:
236                 if (histogram_handler_) {
237                     histo = (struct exynos_drm_histogram_event *)e;
238                     histogram_handler_->handleHistogramEvent(histo->crtc_id,
239                                                              (void *)&(histo->bins));
240                 }
241                 break;
242             case DRM_EVENT_FLIP_COMPLETE:
243                 vblank = (struct drm_event_vblank *)e;
244                 user_data = (void *)(unsigned long)(vblank->user_data);
245                 FlipHandler(drm_->fd(), vblank->sequence, vblank->tv_sec, vblank->tv_usec,
246                             user_data);
247                 break;
248             case DRM_EVENT_VBLANK:
249             case DRM_EVENT_CRTC_SEQUENCE:
250                 /* These DRM events are not handled */
251                 break;
252             default:
253                 break;
254         }
255         i += e->length;
256     }
257 
258     return;
259 }
260 
TUIEventHandler()261 void DrmEventListener::TUIEventHandler() {
262   if (!tui_handler_) {
263     ALOGE("%s:: tui event handler is not valid", __func__);
264     return;
265   }
266 
267   tui_handler_->handleTUIEvent();
268 }
269 
Routine()270 void DrmEventListener::Routine() {
271   struct epoll_event events[maxFds];
272   int nfds, n;
273 
274   do {
275     nfds = epoll_wait(epoll_fd_.get(), events, maxFds, -1);
276   } while (nfds <= 0);
277 
278   for (n = 0; n < nfds; n++) {
279     if (events[n].events & EPOLLIN) {
280       if (events[n].data.fd == uevent_fd_.get()) {
281         UEventHandler();
282       } else if (events[n].data.fd == drm_->fd()) {
283           DRMEventHandler();
284       }
285     } else if (events[n].events & EPOLLPRI) {
286       if (tuievent_fd_.get() >= 0 && events[n].data.fd == tuievent_fd_.get()) {
287         TUIEventHandler();
288       }
289     }
290   }
291 }
292 }  // namespace android
293