OSDN Git Service

0514aa6ef9fad7204de0baac465444c04277a3c6
[android-x86/external-drm_hwcomposer.git] / drmeventlistener.cpp
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 "drmresources.h"
21
22 #include <assert.h>
23 #include <linux/netlink.h>
24 #include <sys/socket.h>
25
26 #include <cutils/log.h>
27 #include <xf86drm.h>
28
29 namespace android {
30
31 DrmEventListener::DrmEventListener(DrmResources *drm)
32     : Worker("drm-event-listener", HAL_PRIORITY_URGENT_DISPLAY),
33       drm_(drm) {
34 }
35
36 int DrmEventListener::Init() {
37   uevent_fd_.Set(socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT));
38   if (uevent_fd_.get() < 0) {
39     ALOGE("Failed to open uevent socket %d", uevent_fd_.get());
40     return uevent_fd_.get();
41   }
42
43   struct sockaddr_nl addr;
44   memset(&addr, 0, sizeof(addr));
45   addr.nl_family = AF_NETLINK;
46   addr.nl_pid = getpid();
47   addr.nl_groups = 0xFFFFFFFF;
48
49   int ret = bind(uevent_fd_.get(), (struct sockaddr *)&addr, sizeof(addr));
50   if (ret) {
51     ALOGE("Failed to bind uevent socket %d", -errno);
52     return -errno;
53   }
54
55   FD_ZERO(&fds_);
56   FD_SET(drm_->fd(), &fds_);
57   FD_SET(uevent_fd_.get(), &fds_);
58   max_fd_ = std::max(drm_->fd(), uevent_fd_.get());
59
60   return InitWorker();
61 }
62
63 void DrmEventListener::RegisterHotplugHandler(DrmEventHandler *handler) {
64   assert(!hotplug_handler_);
65   hotplug_handler_ = handler;
66 }
67
68 void DrmEventListener::FlipHandler(int /* fd */, unsigned int /* sequence */,
69                                    unsigned int tv_sec, unsigned int tv_usec,
70                                    void *user_data) {
71   DrmEventHandler *handler = (DrmEventHandler *)user_data;
72   if (!handler)
73     return;
74
75   handler->HandleEvent((uint64_t)tv_sec * 1000 * 1000 + tv_usec);
76   delete handler;
77 }
78
79 void DrmEventListener::UEventHandler() {
80   char buffer[1024];
81   int ret;
82
83   struct timespec ts;
84   uint64_t timestamp = 0;
85   ret = clock_gettime(CLOCK_MONOTONIC, &ts);
86   if (!ret)
87     timestamp = ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
88   else
89     ALOGE("Failed to get monotonic clock on hotplug %d", ret);
90
91   while (true) {
92     ret = read(uevent_fd_.get(), &buffer, sizeof(buffer));
93     if (ret == 0) {
94       return;
95     } else if (ret < 0) {
96       ALOGE("Got error reading uevent %d", ret);
97       return;
98     }
99
100     if (!hotplug_handler_)
101       continue;
102
103     bool drm_event = false, hotplug_event = false;
104     for (int i = 0; i < ret;) {
105       char *event = buffer + i;
106       if (strcmp(event, "DEVTYPE=drm_minor"))
107         drm_event = true;
108       else if (strcmp(event, "HOTPLUG=1"))
109         hotplug_event = true;
110
111       i += strlen(event) + 1;
112     }
113
114     if (drm_event && hotplug_event)
115       hotplug_handler_->HandleEvent(timestamp);
116   }
117 }
118
119 void DrmEventListener::Routine() {
120   int ret;
121   do {
122     ret = select(max_fd_ + 1, &fds_, NULL, NULL, NULL);
123   } while (ret == -1 && errno == EINTR);
124
125   if (FD_ISSET(drm_->fd(), &fds_)) {
126     drmEventContext event_context = {
127         .version = 2,
128         .vblank_handler = NULL,
129         .page_flip_handler = DrmEventListener::FlipHandler};
130     drmHandleEvent(drm_->fd(), &event_context);
131   }
132
133   if (FD_ISSET(uevent_fd_.get(), &fds_))
134     UEventHandler();
135 }
136 }