summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Curtin <ecurtin@redhat.com>2022-06-17 11:00:44 +0100
committerLaurent Pinchart <laurent.pinchart@ideasonboard.com>2022-06-19 00:02:47 +0300
commit7f500a6c366a16fedfaba8bf67b147ccc8239eb7 (patch)
treef687c4e11f2fcd5ce5fbea95081f7297c3a64d17
parent4bb284e0fa5669bbf6adda93e2f770014834c8cb (diff)
cam: drm: Support /dev/dri cards other than 0
Existing code is hardcoded to card0. Since recent fedora upgrades, we have noticed on more than one machine that card1 is present as the lowest numbered device, could theoretically be higher. This technique tries every file starting with card and continue only when we have successfully opened one. These devices with card1 as the lowest device were simply failing when they do not see a /dev/dri/card0 file present. Reported-by: Ian Mullins <imullins@redhat.com> Tested-by: Ian Mullins <imullins@redhat.com> Signed-off-by: Eric Curtin <ecurtin@redhat.com> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
-rw-r--r--src/cam/drm.cpp65
-rw-r--r--src/cam/drm.h1
2 files changed, 48 insertions, 18 deletions
diff --git a/src/cam/drm.cpp b/src/cam/drm.cpp
index 42c5a3b1..fbfc0a59 100644
--- a/src/cam/drm.cpp
+++ b/src/cam/drm.cpp
@@ -8,6 +8,7 @@
#include "drm.h"
#include <algorithm>
+#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <iostream>
@@ -393,24 +394,10 @@ Device::~Device()
int Device::init()
{
- constexpr size_t NODE_NAME_MAX = sizeof("/dev/dri/card255");
- char name[NODE_NAME_MAX];
- int ret;
-
- /*
- * Open the first DRM/KMS device. The libdrm drmOpen*() functions
- * require either a module name or a bus ID, which we don't have, so
- * bypass them. The automatic module loading and device node creation
- * from drmOpen() is of no practical use as any modern system will
- * handle that through udev or an equivalent component.
- */
- snprintf(name, sizeof(name), "/dev/dri/card%u", 0);
- fd_ = open(name, O_RDWR | O_CLOEXEC);
- if (fd_ < 0) {
- ret = -errno;
- std::cerr
- << "Failed to open DRM/KMS device " << name << ": "
- << strerror(-ret) << std::endl;
+ int ret = openCard();
+ if (ret < 0) {
+ std::cerr << "Failed to open any DRM/KMS device: "
+ << strerror(-ret) << std::endl;
return ret;
}
@@ -438,6 +425,48 @@ int Device::init()
return 0;
}
+int Device::openCard()
+{
+ const std::string dirName = "/dev/dri/";
+ int ret = -ENOENT;
+
+ /*
+ * Open the first DRM/KMS device beginning with /dev/dri/card. The
+ * libdrm drmOpen*() functions require either a module name or a bus ID,
+ * which we don't have, so bypass them. The automatic module loading and
+ * device node creation from drmOpen() is of no practical use as any
+ * modern system will handle that through udev or an equivalent
+ * component.
+ */
+ DIR *folder = opendir(dirName.c_str());
+ if (!folder) {
+ ret = -errno;
+ std::cerr << "Failed to open " << dirName
+ << " directory: " << strerror(-ret) << std::endl;
+ return ret;
+ }
+
+ for (struct dirent *res; (res = readdir(folder));) {
+ if (strncmp(res->d_name, "card", 4))
+ continue;
+
+ const std::string devName = dirName + res->d_name;
+ fd_ = open(devName.c_str(), O_RDWR | O_CLOEXEC);
+ if (fd_ >= 0) {
+ ret = 0;
+ break;
+ }
+
+ ret = -errno;
+ std::cerr << "Failed to open DRM/KMS device " << devName << ": "
+ << strerror(-ret) << std::endl;
+ }
+
+ closedir(folder);
+
+ return ret;
+}
+
int Device::getResources()
{
int ret;
diff --git a/src/cam/drm.h b/src/cam/drm.h
index de57e445..655a7509 100644
--- a/src/cam/drm.h
+++ b/src/cam/drm.h
@@ -311,6 +311,7 @@ private:
Device &operator=(const Device &) = delete;
Device &operator=(const Device &&) = delete;
+ int openCard();
int getResources();
void drmEvent();