minigbm: add minigbm_create_default_device helper

Variants of minigbm_create_default_device are open-coded in multiple
places.  This should be used wherever minigbm can be assumed.

BUG=none
TEST=manual check that the function works

Change-Id: I3ad9897355ab72080fdca329674df09087b9adfd
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/minigbm/+/4163418
Reviewed-by: Yiwei Zhang <zzyiwei@chromium.org>
Tested-by: Chia-I Wu <olv@google.com>
Commit-Queue: Chia-I Wu <olv@google.com>
diff --git a/cros_gralloc/Makefile b/cros_gralloc/Makefile
index c95ad2c..b0d62d7 100644
--- a/cros_gralloc/Makefile
+++ b/cros_gralloc/Makefile
@@ -9,7 +9,7 @@
 
 SRCS   += $(wildcard gralloc0/*.cc)
 
-SOURCES = $(filter-out ../gbm%, $(SRCS))
+SOURCES = $(filter-out ../gbm% ../minigbm%, $(SRCS))
 PKG_CONFIG ?= pkg-config
 
 VPATH = $(dir $(SOURCES))
diff --git a/minigbm_helpers.c b/minigbm_helpers.c
index cea0b48..6420742 100644
--- a/minigbm_helpers.c
+++ b/minigbm_helpers.c
@@ -17,6 +17,7 @@
 #include <xf86drm.h>
 #include <xf86drmMode.h>
 
+#include "gbm.h"
 #include "minigbm_helpers.h"
 #include "util.h"
 
@@ -312,3 +313,60 @@
 	close(fd);
 	return ret;
 }
+
+static struct gbm_device *
+try_drm_devices(drmDevicePtr *devs, int dev_count, int type, int *out_fd)
+{
+	int i;
+
+	for (i = 0; i < dev_count; i++) {
+		drmDevicePtr dev = devs[i];
+		int fd;
+
+		if (!(dev->available_nodes & (1 << type)))
+			continue;
+
+		fd = open(dev->nodes[type], O_RDWR | O_CLOEXEC);
+		if (fd >= 0) {
+			struct gbm_device *gbm = gbm_create_device(fd);
+			if (gbm) {
+				*out_fd = fd;
+				return gbm;
+			}
+			close(fd);
+		}
+	}
+
+	return NULL;
+}
+
+PUBLIC struct gbm_device *
+minigbm_create_default_device(int *out_fd)
+{
+        struct gbm_device *gbm;
+	drmDevicePtr devs[64];
+	int dev_count;
+	int fd;
+
+	/* try gbm_get_default_device_fd first */
+	fd = gbm_get_default_device_fd();
+	if (fd >= 0) {
+		gbm = gbm_create_device(fd);
+		if (gbm) {
+			*out_fd = fd;
+			return gbm;
+		}
+		close(fd);
+	}
+
+	dev_count = drmGetDevices2(0, devs, sizeof(devs) / sizeof(devs[0]));
+
+	/* try render nodes and then primary nodes */
+        gbm = try_drm_devices(devs, dev_count, DRM_NODE_RENDER, out_fd);
+	if (!gbm)
+		gbm = try_drm_devices(devs, dev_count, DRM_NODE_PRIMARY, out_fd);
+
+	drmFreeDevices(devs, dev_count);
+
+	return gbm;
+}
diff --git a/minigbm_helpers.h b/minigbm_helpers.h
index 08e6283..500d97e 100644
--- a/minigbm_helpers.h
+++ b/minigbm_helpers.h
@@ -6,6 +6,8 @@
 #ifndef _MINIGBM_HELPERS_H_
 #define _MINIGBM_HELPERS_H_
 
+#include <stdint.h>
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -18,6 +20,8 @@
 #define GBM_DEV_TYPE_FLAG_BLOCKED (1u << 5)	 /* Unsuitable device e.g. vgem, udl, evdi. */
 #define GBM_DEV_TYPE_FLAG_INTERNAL_LCD (1u << 6) /* Device is driving internal LCD. */
 
+struct gbm_device;
+
 struct gbm_device_info {
 	uint32_t dev_type_flags;
 	int dri_node_num; /* DRI node number (0..63), for easy matching of devices. */
@@ -36,6 +40,12 @@
  */
 int gbm_get_default_device_fd(void);
 
+/*
+ * Create "default" gbm device.  This can pick a different DRM device than
+ * gbm_get_default_device_fd and should be preferred in most cases.
+ */
+struct gbm_device *minigbm_create_default_device(int *out_fd);
+
 #ifdef __cplusplus
 }
 #endif