aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSean Paul <seanpaul@chromium.org>2015-07-28 14:15:42 -0400
committerSean Paul <seanpaul@chromium.org>2016-04-01 12:15:23 -0400
commit3b1c03ab6613789254e0406f015b05ebbe1383ea (patch)
tree06968556c238f50155fef0669965b9658e7547f5
parent4248d744d3be0fdd1233ef620678b581af56468f (diff)
downloaddrm_hwcomposer-3b1c03ab6613789254e0406f015b05ebbe1383ea.tar.gz
DO NOT MERGE: drm_hwcomposer: Add DrmEventListener worker
This patch adds a worker which listens to drm events. If the drm event has a handler associated with it, the listener will call the handler. BUG=chrome-os-partner:41682 TEST=Tested on ryu with DP Change-Id: I5d691d191425604766a00be3e72111095d025d06 Signed-off-by: Sean Paul <seanpaul@chromium.org>
-rw-r--r--Android.mk1
-rw-r--r--drmeventlistener.cpp135
-rw-r--r--drmeventlistener.h65
-rw-r--r--drmresources.cpp17
-rw-r--r--drmresources.h4
5 files changed, 221 insertions, 1 deletions
diff --git a/Android.mk b/Android.mk
index f9add2f..07f1e32 100644
--- a/Android.mk
+++ b/Android.mk
@@ -47,6 +47,7 @@ LOCAL_SRC_FILES := \
drmdisplaycomposition.cpp \
drmdisplaycompositor.cpp \
drmencoder.cpp \
+ drmeventlistener.cpp \
drmmode.cpp \
drmplane.cpp \
drmproperty.cpp \
diff --git a/drmeventlistener.cpp b/drmeventlistener.cpp
new file mode 100644
index 0000000..b3e2328
--- /dev/null
+++ b/drmeventlistener.cpp
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "hwc-drm-event-listener"
+
+#include "drmeventlistener.h"
+#include "drmresources.h"
+
+#include <linux/netlink.h>
+#include <sys/socket.h>
+
+#include <cutils/log.h>
+#include <xf86drm.h>
+
+namespace android {
+
+DrmEventListener::DrmEventListener(DrmResources *drm)
+ : Worker("drm-event-listener", HAL_PRIORITY_URGENT_DISPLAY),
+ drm_(drm) {
+}
+
+int DrmEventListener::Init() {
+ uevent_fd_.Set(socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT));
+ if (uevent_fd_.get() < 0) {
+ ALOGE("Failed to open uevent socket %d", uevent_fd_.get());
+ return uevent_fd_.get();
+ }
+
+ struct sockaddr_nl addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ addr.nl_pid = getpid();
+ addr.nl_groups = 0xFFFFFFFF;
+
+ int ret = bind(uevent_fd_.get(), (struct sockaddr *)&addr, sizeof(addr));
+ if (ret) {
+ ALOGE("Failed to bind uevent socket %d", -errno);
+ return -errno;
+ }
+
+ FD_ZERO(&fds_);
+ FD_SET(drm_->fd(), &fds_);
+ FD_SET(uevent_fd_.get(), &fds_);
+ max_fd_ = std::max(drm_->fd(), uevent_fd_.get());
+
+ return InitWorker();
+}
+
+void DrmEventListener::RegisterHotplugHandler(DrmEventHandler *handler) {
+ assert(!hotplug_handler_);
+ hotplug_handler_ = handler;
+}
+
+void DrmEventListener::FlipHandler(int /* fd */, unsigned int /* sequence */,
+ unsigned int tv_sec, unsigned int tv_usec,
+ void *user_data) {
+ DrmEventHandler *handler = (DrmEventHandler *)user_data;
+ if (!handler)
+ return;
+
+ handler->HandleEvent((uint64_t)tv_sec * 1000 * 1000 + tv_usec);
+ delete handler;
+}
+
+void DrmEventListener::UEventHandler() {
+ char buffer[1024];
+ int ret;
+
+ struct timespec ts;
+ uint64_t timestamp = 0;
+ ret = clock_gettime(CLOCK_MONOTONIC, &ts);
+ if (!ret)
+ timestamp = ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
+ else
+ ALOGE("Failed to get monotonic clock on hotplug %d", ret);
+
+ while (true) {
+ ret = read(uevent_fd_.get(), &buffer, sizeof(buffer));
+ if (ret == 0) {
+ return;
+ } else if (ret < 0) {
+ ALOGE("Got error reading uevent %d", ret);
+ return;
+ }
+
+ if (!hotplug_handler_)
+ continue;
+
+ bool drm_event = false, hotplug_event = false;
+ for (int i = 0; i < ret;) {
+ char *event = buffer + i;
+ if (strcmp(event, "DEVTYPE=drm_minor"))
+ drm_event = true;
+ else if (strcmp(event, "HOTPLUG=1"))
+ hotplug_event = true;
+
+ i += strlen(event) + 1;
+ }
+
+ if (drm_event && hotplug_event)
+ hotplug_handler_->HandleEvent(timestamp);
+ }
+}
+
+void DrmEventListener::Routine() {
+ int ret;
+ do {
+ ret = select(max_fd_ + 1, &fds_, NULL, NULL, NULL);
+ } while (ret == -1 && errno == EINTR);
+
+ if (FD_ISSET(drm_->fd(), &fds_)) {
+ drmEventContext event_context = {
+ .version = DRM_EVENT_CONTEXT_VERSION,
+ .vblank_handler = NULL,
+ .page_flip_handler = DrmEventListener::FlipHandler};
+ drmHandleEvent(drm_->fd(), &event_context);
+ }
+
+ if (FD_ISSET(uevent_fd_.get(), &fds_))
+ UEventHandler();
+}
+}
diff --git a/drmeventlistener.h b/drmeventlistener.h
new file mode 100644
index 0000000..61eefe8
--- /dev/null
+++ b/drmeventlistener.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_DRM_EVENT_LISTENER_H_
+#define ANDROID_DRM_EVENT_LISTENER_H_
+
+#include "autofd.h"
+#include "worker.h"
+
+namespace android {
+
+class DrmResources;
+
+class DrmEventHandler {
+ public:
+ DrmEventHandler() {
+ }
+ virtual ~DrmEventHandler() {
+ }
+
+ virtual void HandleEvent(uint64_t timestamp_us) = 0;
+};
+
+class DrmEventListener : public Worker {
+ public:
+ DrmEventListener(DrmResources *drm);
+ virtual ~DrmEventListener() {
+ }
+
+ int Init();
+
+ void RegisterHotplugHandler(DrmEventHandler *handler);
+
+ static void FlipHandler(int fd, unsigned int sequence, unsigned int tv_sec,
+ unsigned int tv_usec, void *user_data);
+
+ protected:
+ virtual void Routine();
+
+ private:
+ void UEventHandler();
+
+ fd_set fds_;
+ UniqueFd uevent_fd_;
+ int max_fd_ = -1;
+
+ DrmResources *drm_;
+ DrmEventHandler *hotplug_handler_ = NULL;
+};
+}
+
+#endif
diff --git a/drmresources.cpp b/drmresources.cpp
index 80e61ec..81381c3 100644
--- a/drmresources.cpp
+++ b/drmresources.cpp
@@ -19,6 +19,7 @@
#include "drmconnector.h"
#include "drmcrtc.h"
#include "drmencoder.h"
+#include "drmeventlistener.h"
#include "drmplane.h"
#include "drmresources.h"
@@ -33,7 +34,11 @@
namespace android {
-DrmResources::DrmResources() : compositor_(this) {
+DrmResources::DrmResources() : compositor_(this), event_listener_(this) {
+}
+
+DrmResources::~DrmResources() {
+ event_listener_.Exit();
}
int DrmResources::Init() {
@@ -194,6 +199,12 @@ int DrmResources::Init() {
if (ret)
return ret;
+ ret = event_listener_.Init();
+ if (ret) {
+ ALOGE("Can't initialize event listener %d", ret);
+ return ret;
+ }
+
for (auto &conn : connectors_) {
ret = CreateDisplayPipe(conn.get());
if (ret) {
@@ -363,6 +374,10 @@ DrmCompositor *DrmResources::compositor() {
return &compositor_;
}
+DrmEventListener *DrmResources::event_listener() {
+ return &event_listener_;
+}
+
int DrmResources::GetProperty(uint32_t obj_id, uint32_t obj_type,
const char *prop_name, DrmProperty *property) {
drmModeObjectPropertiesPtr props;
diff --git a/drmresources.h b/drmresources.h
index 6716807..64e6b57 100644
--- a/drmresources.h
+++ b/drmresources.h
@@ -21,6 +21,7 @@
#include "drmconnector.h"
#include "drmcrtc.h"
#include "drmencoder.h"
+#include "drmeventlistener.h"
#include "drmplane.h"
#include <stdint.h>
@@ -30,6 +31,7 @@ namespace android {
class DrmResources {
public:
DrmResources();
+ ~DrmResources();
int Init();
@@ -49,6 +51,7 @@ class DrmResources {
DrmCrtc *GetCrtcForDisplay(int display) const;
DrmPlane *GetPlane(uint32_t id) const;
DrmCompositor *compositor();
+ DrmEventListener *event_listener();
int GetPlaneProperty(const DrmPlane &plane, const char *prop_name,
DrmProperty *property);
@@ -79,6 +82,7 @@ class DrmResources {
std::vector<std::unique_ptr<DrmCrtc>> crtcs_;
std::vector<std::unique_ptr<DrmPlane>> planes_;
DrmCompositor compositor_;
+ DrmEventListener event_listener_;
};
}