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