From 7f500a6c366a16fedfaba8bf67b147ccc8239eb7 Mon Sep 17 00:00:00 2001 From: Eric Curtin Date: Fri, 17 Jun 2022 11:00:44 +0100 Subject: 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 Tested-by: Ian Mullins Signed-off-by: Eric Curtin Reviewed-by: Laurent Pinchart Signed-off-by: Laurent Pinchart --- src/cam/drm.cpp | 65 +++++++++++++++++++++++++++++++++++++++++---------------- src/cam/drm.h | 1 + 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 +#include #include #include #include @@ -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(); -- cgit v1.2.1