OSDN Git Service

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