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