OSDN Git Service

drm_hwcomposer: Add hotplug event handler
authorSean Paul <seanpaul@chromium.org>
Mon, 26 Oct 2015 19:37:06 +0000 (15:37 -0400)
committerSean Paul <seanpaul@chromium.org>
Tue, 29 Mar 2016 17:56:13 +0000 (13:56 -0400)
Add a hotplug event handler to handle hotplug events. Upon
hotplug, the handler is responsible for finding and setting
the preferred mode of the new display.

BUG=chrome-os-partner:41682
TEST=Tested on ryu with DP

Change-Id: Ide57382624c7839ed81a712bc29ea2e1cc19dcae
Signed-off-by: Sean Paul <seanpaul@chromium.org>
hwcomposer.cpp

index efc9b95..0e0444b 100644 (file)
@@ -18,6 +18,7 @@
 #define LOG_TAG "hwcomposer-drm"
 
 #include "drmhwcomposer.h"
+#include "drmeventlistener.h"
 #include "drmresources.h"
 #include "importer.h"
 #include "virtualcompositorworker.h"
@@ -25,6 +26,7 @@
 
 #include <stdlib.h>
 
+#include <cinttypes>
 #include <map>
 #include <vector>
 #include <sstream>
@@ -124,6 +126,62 @@ typedef struct hwc_drm_display {
   VSyncWorker vsync_worker;
 } hwc_drm_display_t;
 
+class DrmHotplugHandler : public DrmEventHandler {
+ public:
+  void Init(DrmResources *drm, const struct hwc_procs *procs) {
+    drm_ = drm;
+    procs_ = procs;
+  }
+
+  void HandleEvent(uint64_t timestamp_us) {
+    for (auto &conn : drm_->connectors()) {
+      drmModeConnection old_state = conn->state();
+
+      conn->UpdateModes();
+
+      drmModeConnection cur_state = conn->state();
+
+      if (cur_state == old_state)
+        continue;
+
+      ALOGI("%s event @%" PRIu64 " for connector %u\n",
+            cur_state == DRM_MODE_CONNECTED ? "Plug" : "Unplug", timestamp_us,
+            conn->id());
+
+      if (cur_state == DRM_MODE_CONNECTED) {
+        // Take the first one, then look for the preferred
+        DrmMode mode = *(conn->modes().begin());
+        for (auto &m : conn->modes()) {
+          if (m.type() & DRM_MODE_TYPE_PREFERRED) {
+            mode = m;
+            break;
+          }
+        }
+        ALOGI("Setting mode %dx%d for connector %d\n", mode.h_display(),
+              mode.v_display(), conn->id());
+        int ret = drm_->SetDisplayActiveMode(conn->display(), mode);
+        if (ret) {
+          ALOGE("Failed to set active config %d", ret);
+          return;
+        }
+      } else {
+        int ret = drm_->SetDpmsMode(conn->display(), DRM_MODE_DPMS_OFF);
+        if (ret) {
+          ALOGE("Failed to set dpms mode off %d", ret);
+          return;
+        }
+      }
+
+      procs_->hotplug(procs_, conn->display(),
+                      cur_state == DRM_MODE_CONNECTED ? 1 : 0);
+    }
+  }
+
+ private:
+  DrmResources *drm_ = NULL;
+  const struct hwc_procs *procs_ = NULL;
+};
+
 struct hwc_context_t {
   // map of display:hwc_drm_display_t
   typedef std::map<int, hwc_drm_display_t> DisplayMap;
@@ -141,6 +199,7 @@ struct hwc_context_t {
   const gralloc_module_t *gralloc;
   DummySwSyncTimeline dummy_timeline;
   VirtualCompositorWorker virtual_compositor_worker;
+  DrmHotplugHandler hotplug_handler;
 };
 
 static native_handle_t *dup_buffer_handle(buffer_handle_t handle) {
@@ -626,6 +685,9 @@ static void hwc_register_procs(struct hwc_composer_device_1 *dev,
 
   for (std::pair<const int, hwc_drm_display> &display_entry : ctx->displays)
     display_entry.second.vsync_worker.SetProcs(procs);
+
+  ctx->hotplug_handler.Init(&ctx->drm, procs);
+  ctx->drm.event_listener()->RegisterHotplugHandler(&ctx->hotplug_handler);
 }
 
 static int hwc_get_display_configs(struct hwc_composer_device_1 *dev,
@@ -742,6 +804,10 @@ static int hwc_set_active_config(struct hwc_composer_device_1 *dev, int display,
     ALOGE("Failed to get connector for display %d", display);
     return -ENODEV;
   }
+
+  if (c->state() != DRM_MODE_CONNECTED)
+    return -ENODEV;
+
   DrmMode mode;
   for (const DrmMode &conn_mode : c->modes()) {
     if (conn_mode.id() == hd->config_ids[index]) {