245 lines
8.0 KiB
Diff
245 lines
8.0 KiB
Diff
Change udev detect mothod.
|
|
|
|
Signed-off-by: Windsome Zeng <windsome.zeng@starfivetech.com>
|
|
|
|
diff -purN a/src/native-state-drm.cpp b/src/native-state-drm.cpp
|
|
--- a/src/native-state-drm.cpp 2022-08-11 16:49:38.274490554 +0800
|
|
+++ b/src/native-state-drm.cpp 2022-08-11 16:48:41.759513413 +0800
|
|
@@ -29,6 +29,7 @@
|
|
#include <libudev.h>
|
|
#include <cstring>
|
|
#include <string>
|
|
+#include <unistd.h>
|
|
|
|
/******************
|
|
* Public methods *
|
|
@@ -157,180 +158,72 @@ inline static bool invalid_drm_node_path
|
|
return !(valid_drm_node_path(provided_node_path));
|
|
}
|
|
|
|
-/* Udev methods */
|
|
-// Udev detection functions
|
|
-#define UDEV_TEST_FUNC_SIGNATURE(udev_identifier, device_identifier, syspath_identifier) \
|
|
- struct udev * __restrict const udev_identifier, \
|
|
- struct udev_device * __restrict const device_identifier, \
|
|
- char const * __restrict syspath_identifier
|
|
-
|
|
-/* Omitting the parameter names is kind of ugly but is the only way
|
|
- * to force G++ to forget about the unused parameters.
|
|
- * Having big warnings during the compilation isn't very nice.
|
|
- *
|
|
- * These functions will be used as function pointers and should have
|
|
- * the same signature to avoid weird stack related issues.
|
|
- *
|
|
- * Another way to deal with that issue will be to mark unused parameters
|
|
- * with __attribute__((unused))
|
|
- */
|
|
-static bool udev_drm_test_virtual(
|
|
- UDEV_TEST_FUNC_SIGNATURE(,,tested_node_syspath))
|
|
-{
|
|
- return strstr(tested_node_syspath, "virtual") != NULL;
|
|
-}
|
|
-
|
|
-static bool udev_drm_test_not_virtual(
|
|
- UDEV_TEST_FUNC_SIGNATURE(udev, current_device, tested_node_syspath))
|
|
-{
|
|
- return !udev_drm_test_virtual(udev,
|
|
- current_device,
|
|
- tested_node_syspath);
|
|
-}
|
|
-
|
|
static bool
|
|
-udev_drm_test_primary_gpu(UDEV_TEST_FUNC_SIGNATURE(, current_device,))
|
|
-{
|
|
- bool is_main_gpu = false;
|
|
-
|
|
- auto const drm_node_parent = udev_device_get_parent(current_device);
|
|
-
|
|
- /* While tempting, using udev_device_unref will generate issues
|
|
- * when unreferencing the child in udev_get_node_that_pass_in_enum
|
|
- *
|
|
- * udev_device_unref WILL unreference the parent, so avoid doing
|
|
- * that here.
|
|
- *
|
|
- * ( See udev sources : src/libudev/libudev-device.c )
|
|
- */
|
|
- if (drm_node_parent != NULL) {
|
|
- is_main_gpu =
|
|
- (udev_device_get_sysattr_value(drm_node_parent, "boot_vga")
|
|
- != NULL);
|
|
- }
|
|
-
|
|
- return is_main_gpu;
|
|
-}
|
|
-
|
|
-/* Test if the drm-device is actually modeset capable.
|
|
- * Render-only devices cannot drive an actual display,
|
|
- * so the GETRESOURCES ioctl will fail in that case.
|
|
- */
|
|
-static bool udev_drm_test_modeset(std::string const& dev_path)
|
|
-{
|
|
- struct drm_mode_card_res res {};
|
|
- int fd, ret;
|
|
-
|
|
- fd = open(dev_path.c_str(), O_RDWR);
|
|
- if (!valid_fd(fd))
|
|
- return false;
|
|
-
|
|
- ret = drmIoctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res);
|
|
- drmClose(fd);
|
|
-
|
|
- return !ret;
|
|
-}
|
|
-
|
|
-static std::string
|
|
-udev_get_node_that_pass_in_enum(
|
|
- struct udev * __restrict const udev,
|
|
- struct udev_enumerate * __restrict const dev_enum,
|
|
- bool (* check_function)(UDEV_TEST_FUNC_SIGNATURE(,,)))
|
|
+drm_device_is_kms(struct udev_device *device)
|
|
{
|
|
- std::string result;
|
|
+ const char *filename = NULL;
|
|
+ drmModeRes *res = NULL;
|
|
+ int fd = -1;
|
|
+ bool ret = false;
|
|
|
|
- auto current_element = udev_enumerate_get_list_entry(dev_enum);
|
|
+ if (!device)
|
|
+ goto out_fail;
|
|
|
|
- while (current_element && result.empty()) {
|
|
- char const * __restrict current_element_sys_path =
|
|
- udev_list_entry_get_name(current_element);
|
|
+ filename = udev_device_get_devnode(device);
|
|
+ if (!filename)
|
|
+ goto out_fail;
|
|
|
|
- if (current_element_sys_path) {
|
|
- struct udev_device * current_device =
|
|
- udev_device_new_from_syspath(udev,
|
|
- current_element_sys_path);
|
|
- auto check_passed = check_function(
|
|
- udev, current_device, current_element_sys_path);
|
|
+ fd = open(filename, O_RDWR);
|
|
+ if (fd < 0)
|
|
+ goto out_fail;
|
|
|
|
- if (check_passed) {
|
|
- const char * device_node_path =
|
|
- udev_device_get_devnode(current_device);
|
|
+ res = drmModeGetResources(fd);
|
|
+ if (!res)
|
|
+ goto out_fail;
|
|
|
|
- if (device_node_path &&
|
|
- udev_drm_test_modeset(device_node_path)) {
|
|
- result = device_node_path;
|
|
- }
|
|
+ if (res->count_crtcs <= 0 || res->count_connectors <= 0 ||
|
|
+ res->count_encoders <= 0)
|
|
+ goto out_fail;
|
|
|
|
- }
|
|
+ ret = true;
|
|
|
|
- udev_device_unref(current_device);
|
|
- }
|
|
-
|
|
- current_element = udev_list_entry_get_next(current_element);
|
|
- }
|
|
+out_fail:
|
|
+ if (res)
|
|
+ drmModeFreeResources(res);
|
|
+ if (fd >= 0)
|
|
+ close(fd);
|
|
|
|
- return result;
|
|
+ return ret;
|
|
}
|
|
|
|
-/* Inspired by KWin detection mechanism */
|
|
-/* And yet KWin got it wrong too, it seems.
|
|
- * 1 - Looking for the primary GPU by checking the flag 'boot_vga'
|
|
- * won't get you far with some embedded chipsets, like Rockchip.
|
|
- * 2 - Looking for a GPU plugged in PCI will fail on various embedded
|
|
- * devices !
|
|
- * 3 - Looking for a render node is not guaranteed to work on some
|
|
- * poorly maintained DRM drivers, which plague some embedded
|
|
- * devices too...
|
|
- *
|
|
- * So, we won't play too smart here.
|
|
- * - We first check for a primary GPU plugged in PCI with the 'boot_vga'
|
|
- * attribute, to take care of Desktop users using multiple GPU.
|
|
- * - Then, we just check for a DRM node that is not virtual
|
|
- * - At least, we use the first virtual node we get, if we didn't find
|
|
- * anything yet.
|
|
- * This should take care of almost every potential use case.
|
|
- *
|
|
- * The remaining ones will be dealt with an additional option to
|
|
- * specify the DRM dev node manually.
|
|
- */
|
|
+/* Inspired by Wayland's Weston detection mechanism */
|
|
static std::string udev_main_gpu_drm_node_path()
|
|
{
|
|
- Log::debug("Using Udev to detect the right DRM node to use\n");
|
|
auto udev = udev_new();
|
|
- auto dev_enumeration = udev_enumerate_new(udev);
|
|
-
|
|
- udev_enumerate_add_match_subsystem(dev_enumeration, "drm");
|
|
- udev_enumerate_add_match_sysname(dev_enumeration, "card[0-9]*");
|
|
- udev_enumerate_scan_devices(dev_enumeration);
|
|
-
|
|
- Log::debug("Looking for the main GPU DRM node...\n");
|
|
- std::string node_path = udev_get_node_that_pass_in_enum(
|
|
- udev, dev_enumeration, udev_drm_test_primary_gpu);
|
|
-
|
|
- if (invalid_drm_node_path(node_path)) {
|
|
- Log::debug("Not found!\n");
|
|
- Log::debug("Looking for a concrete GPU DRM node...\n");
|
|
- node_path = udev_get_node_that_pass_in_enum(
|
|
- udev, dev_enumeration, udev_drm_test_not_virtual);
|
|
- }
|
|
- if (invalid_drm_node_path(node_path)) {
|
|
- Log::debug("Not found!?\n");
|
|
- Log::debug("Looking for a virtual GPU DRM node...\n");
|
|
- node_path = udev_get_node_that_pass_in_enum(
|
|
- udev, dev_enumeration, udev_drm_test_virtual);
|
|
- }
|
|
- if (invalid_drm_node_path(node_path)) {
|
|
- Log::debug("Not found.\n");
|
|
- Log::debug("Cannot find a single DRM node using UDEV...\n");
|
|
+ struct udev_enumerate *e;
|
|
+ struct udev_list_entry *entry;
|
|
+ const char *path;
|
|
+ struct udev_device *device;
|
|
+ std::string node_path;
|
|
+
|
|
+ e = udev_enumerate_new(udev);
|
|
+ udev_enumerate_add_match_subsystem(e, "drm");
|
|
+ udev_enumerate_add_match_sysname(e, "card[0-9]*");
|
|
+
|
|
+ udev_enumerate_scan_devices(e);
|
|
+ udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
|
|
+ path = udev_list_entry_get_name(entry);
|
|
+ device = udev_device_new_from_syspath(udev, path);
|
|
+ if (drm_device_is_kms(device))
|
|
+ node_path = udev_device_get_devnode(device);
|
|
+
|
|
+ udev_device_unref(device);
|
|
+ if (!node_path.empty())
|
|
+ break;
|
|
}
|
|
|
|
- if (valid_drm_node_path(node_path)) {
|
|
- Log::debug("Success!\n");
|
|
- }
|
|
-
|
|
- udev_enumerate_unref(dev_enumeration);
|
|
+ udev_enumerate_unref(e);
|
|
udev_unref(udev);
|
|
-
|
|
return node_path;
|
|
}
|
|
|