OSDN Git Service

Implement DRM hotplug events
authorlambdadroid <lambdadroid@gmail.com>
Tue, 8 Jan 2019 20:47:24 +0000 (21:47 +0100)
committerlambdadroid <lambdadroid@gmail.com>
Tue, 8 Jan 2019 20:47:24 +0000 (21:47 +0100)
Android.mk
DrmDevice.cpp
DrmDevice.h
DrmHotplugThread.cpp [new file with mode: 0644]
DrmHotplugThread.h [new file with mode: 0644]
DrmVsyncThread.h
GraphicsThread.cpp
GraphicsThread.h

index 9331e47..066fb58 100644 (file)
@@ -19,7 +19,8 @@ LOCAL_SRC_FILES := \
     DrmFramebuffer.cpp \
     DrmFramebufferLibDrm.cpp \
     GraphicsThread.cpp \
-    DrmVsyncThread.cpp
+    DrmVsyncThread.cpp \
+    DrmHotplugThread.cpp
 
 LOCAL_HEADER_LIBRARIES := \
     android.hardware.graphics.composer@2.1-hal
index 689ad4e..73ccdbb 100644 (file)
@@ -16,7 +16,7 @@ namespace composer {
 namespace V2_1 {
 namespace drmfb {
 
-DrmDevice::DrmDevice(int fd) : mFd(fd) {}
+DrmDevice::DrmDevice(int fd) : mFd(fd), mHotplugThread(*this) {}
 DrmDevice::DrmDevice(const std::string& path) : DrmDevice(open(path.c_str(), O_RDWR)) {
     if (mFd < 0)
         PLOG(ERROR) << "Failed to open DRM device (" << path << ")";
@@ -101,9 +101,13 @@ void DrmDevice::enable(DrmCallback *callback) {
             display->report();
         }
     }
+
+    mHotplugThread.enable();
 }
 
 void DrmDevice::disable() {
+    mHotplugThread.disable();
+
     mCallback = nullptr;
     for (auto& p : mDisplays) {
         p.second->disable();
index 62321ae..fba14b8 100644 (file)
@@ -9,6 +9,7 @@
 #include <android-base/unique_fd.h>
 #include "DrmDisplay.h"
 #include "DrmCallback.h"
+#include "DrmHotplugThread.h"
 
 namespace android {
 namespace hardware {
@@ -46,6 +47,7 @@ private:
     std::vector<uint32_t> mCrtcs;
     uint32_t mUsedCrtcs = 0; // The CRTCs that are already being used by a display
 
+    DrmHotplugThread mHotplugThread;
     DrmCallback* mCallback = nullptr;
 };
 
diff --git a/DrmHotplugThread.cpp b/DrmHotplugThread.cpp
new file mode 100644 (file)
index 0000000..c719be4
--- /dev/null
@@ -0,0 +1,65 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (C) 2019 Stephan Gerhold
+
+#define LOG_TAG "drmfb-hotplug"
+
+#include <cutils/uevent.h>
+#include <android-base/unique_fd.h>
+#include <android-base/logging.h>
+#include "DrmHotplugThread.h"
+#include "DrmDevice.h"
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_1 {
+namespace drmfb {
+
+namespace {
+constexpr int RECEIVE_BUFFER = 1 * 1024 * 1024; // 1 MiB
+constexpr int MESSAGE_BUFFER = 1 * 1024; // 1 KiB
+}
+
+DrmHotplugThread::DrmHotplugThread(DrmDevice& device)
+    : GraphicsThread("drm-hotplug"), mDevice(device) {}
+
+bool DrmHotplugThread::receiveEvent(int fd) {
+    char msg[MESSAGE_BUFFER];
+    auto n = uevent_kernel_multicast_recv(fd, msg, sizeof(msg));
+    if (n < 0)
+        return false;
+
+    bool drm = false;
+    bool hotplug = false;
+    for (auto buf = msg, end = msg + n; buf < end; buf += strlen(buf) + 1) {
+        if (!strcmp(buf, "DEVTYPE=drm_minor"))
+            drm = true;
+        else if (!strcmp(buf, "HOTPLUG=1"))
+            hotplug = true;
+    }
+
+    return drm && hotplug;
+}
+
+void DrmHotplugThread::work(std::unique_lock<std::mutex>& lock) {
+    base::unique_fd fd{uevent_open_socket(RECEIVE_BUFFER, true)};
+    if (fd < 0) {
+        PLOG(ERROR) << "Failed to open uevent socket";
+        return;
+    }
+
+    loop(lock, [this, &fd] {
+        if (receiveEvent(fd)) {
+            LOG(DEBUG) << "Received hotplug uevent";
+            mDevice.update();
+        }
+    });
+}
+
+}  // namespace drmfb
+}  // namespace V2_1
+}  // namespace composer
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
diff --git a/DrmHotplugThread.h b/DrmHotplugThread.h
new file mode 100644 (file)
index 0000000..bdfe767
--- /dev/null
@@ -0,0 +1,34 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (C) 2019 Stephan Gerhold
+
+#pragma once
+
+#include "GraphicsThread.h"
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_1 {
+namespace drmfb {
+
+struct DrmDevice;
+
+struct DrmHotplugThread : public GraphicsThread {
+    DrmHotplugThread(DrmDevice& device);
+
+protected:
+    void work(std::unique_lock<std::mutex>& lock) override;
+
+private:
+    bool receiveEvent(int fd);
+
+    DrmDevice& mDevice;
+};
+
+}  // namespace drmfb
+}  // namespace V2_1
+}  // namespace composer
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
index 59b534e..abcab68 100644 (file)
@@ -16,6 +16,8 @@ struct DrmDisplay;
 
 struct DrmVsyncThread : public GraphicsThread {
     DrmVsyncThread(DrmDisplay& display);
+
+protected:
     void run() override;
 
 private:
index 6b2696f..f6153d8 100644 (file)
@@ -30,7 +30,7 @@ void GraphicsThread::enable() {
 
         if (!mStarted) {
             mStarted = true;
-            mThread = std::thread(&GraphicsThread::loop, this);
+            mThread = std::thread(&GraphicsThread::main, this);
             return;
         }
     }
@@ -57,26 +57,23 @@ void GraphicsThread::stop() {
     mThread.join();
 }
 
-void GraphicsThread::loop() {
+void GraphicsThread::main() {
     setpriority(PRIO_PROCESS, 0, HAL_PRIORITY_URGENT_DISPLAY);
     prctl(PR_SET_NAME, mName.c_str(), 0, 0, 0);
 
     LOG(DEBUG) << "Starting thread " << mName;
 
     std::unique_lock lock{mMutex};
-    while (true) {
-        if (!mEnabled) {
-            mCondition.wait(lock, [this] { return mEnabled || !mStarted; });
-            if (!mStarted) {
-                LOG(DEBUG) << "Stopping thread " << mName;
-                return;
-            }
-        }
-
-        lock.unlock();
-        run();
-        lock.lock();
+    while (mStarted) {
+        work(lock);
+        mCondition.wait(lock, [this] { return mEnabled || !mStarted; });
     }
+
+    LOG(DEBUG) << "Stopping thread " << mName;
+}
+
+void GraphicsThread::work(std::unique_lock<std::mutex>& lock) {
+    loop(lock, [this] { run(); });
 }
 
 }  // namespace drmfb
index a6e2e41..476aece 100644 (file)
@@ -22,10 +22,22 @@ struct GraphicsThread {
     void disable();
     void stop();
 
-    virtual void run() = 0;
-    void loop();
+protected:
+    virtual void run() {};
+    virtual void work(std::unique_lock<std::mutex>& lock);
+
+    template<typename F>
+    void loop(std::unique_lock<std::mutex>& lock, F f) {
+        while (mEnabled) {
+            lock.unlock();
+            f();
+            lock.lock();
+        }
+    }
 
 private:
+    void main();
+
     std::mutex mMutex;
     std::thread mThread;
     std::string mName;