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>
This commit is contained in:
Eric Curtin
2022-06-17 11:00:44 +01:00
committed by Laurent Pinchart
parent 4bb284e0fa
commit 7f500a6c36
2 changed files with 48 additions and 18 deletions

View File

@@ -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;

View File

@@ -311,6 +311,7 @@ private:
Device &operator=(const Device &) = delete;
Device &operator=(const Device &&) = delete;
int openCard();
int getResources();
void drmEvent();