From f63f1b1a16269ddcce75a61d540429fe3d41cfc8 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Thu, 10 Jan 2019 13:59:34 +0200 Subject: Card: improve DRM card selection Add new Card constructor: Card(const std::string& driver, uint32_t idx) which can be used to open Nth card for the given driver. The default constructor behavior is: - If KMSXX_DEVICE env variable is set, the card device with that path is opened. - If KMSXX_DRIVER env variable is set, the card with the given driver name and index is opened. The format is either "drvname" or "drvname:idx". - If neither env variable is given, open /dev/dri/card0 Signed-off-by: Tomi Valkeinen --- kms++/inc/kms++/card.h | 4 ++- kms++/src/card.cpp | 91 ++++++++++++++++++++++++++++++++++++++++++++++---- py/pykms/pykmsbase.cpp | 1 + 3 files changed, 89 insertions(+), 7 deletions(-) diff --git a/kms++/inc/kms++/card.h b/kms++/inc/kms++/card.h index 77f97a3..b96e1c1 100644 --- a/kms++/inc/kms++/card.h +++ b/kms++/inc/kms++/card.h @@ -14,7 +14,8 @@ class Card friend class Framebuffer; public: Card(); - Card(const std::string& device); + Card(const std::string& dev_path); + Card(const std::string& driver, uint32_t idx); virtual ~Card(); Card(const Card& other) = delete; @@ -54,6 +55,7 @@ public: const std::string& version_name() const { return m_version_name; } private: + void setup(); void restore_modes(); std::map m_obmap; diff --git a/kms++/src/card.cpp b/kms++/src/card.cpp index a5c6d53..5d6a597 100644 --- a/kms++/src/card.cpp +++ b/kms++/src/card.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -17,19 +18,97 @@ using namespace std; namespace kms { +static int open_device_by_path(string path) +{ + int fd = open(path.c_str(), O_RDWR | O_CLOEXEC); + if (fd < 0) + throw invalid_argument(string(strerror(errno)) + " opening device " + path); + return fd; +} + +// open Nth DRM card with the given driver name +static int open_device_by_driver(string name, uint32_t idx) +{ + uint32_t matches = 0; + + transform(name.begin(), name.end(), name.begin(), ::tolower); + + for (uint32_t i = 0; ; ++i) { + string path = "/dev/dri/card" + to_string(i); + + int fd = open(path.c_str(), O_RDWR | O_CLOEXEC); + if (fd < 0) { + // presume no more card nodes + throw invalid_argument("no card found for " + name + ":" + to_string(idx)); + } + + drmVersionPtr ver = drmGetVersion(fd); + string drv_name = string(ver->name, ver->name_len); + drmFreeVersion(ver); + + transform(drv_name.begin(), drv_name.end(), drv_name.begin(), ::tolower); + + if (name == drv_name) { + if (idx == matches) + return fd; + matches++; + } + + close(fd); + } +} + Card::Card() - : Card("/dev/dri/card0") { + const char* drv_p = getenv("KMSXX_DRIVER"); + const char* dev_p = getenv("KMSXX_DEVICE"); + + if (dev_p) { + string dev(dev_p); + m_fd = open_device_by_path(dev); + } else if (drv_p) { + string drv(drv_p); + + auto isplit = find(drv.begin(), drv.end(), ':'); + + if (isplit == drv.begin()) + throw runtime_error("Invalid KMSXX_DRIVER"); + + string name; + uint32_t num = 0; + + if (isplit == drv.end()) { + name = drv; + } else { + name = string(drv.begin(), isplit); + string numstr = string(isplit + 1, drv.end()); + num = stoul(numstr); + } + + m_fd = open_device_by_driver(name, num); + } else { + m_fd = open_device_by_path("/dev/dri/card0"); + } + + setup(); } +Card::Card(const std::string& driver, uint32_t idx) +{ + m_fd = open_device_by_driver(driver, idx); + + setup(); +} -Card::Card(const std::string& device) +Card::Card(const std::string& dev_path) { - int fd = open(device.c_str(), O_RDWR | O_CLOEXEC); - if (fd < 0) - throw invalid_argument(string(strerror(errno)) + " opening " + device); - m_fd = fd; + m_fd = open_device_by_path(dev_path); + + setup(); +} +void Card::setup() +{ drmVersionPtr ver = drmGetVersion(m_fd); m_version_major = ver->version_major; m_version_minor = ver->version_minor; diff --git a/py/pykms/pykmsbase.cpp b/py/pykms/pykmsbase.cpp index 7a2ce75..668e6e3 100644 --- a/py/pykms/pykmsbase.cpp +++ b/py/pykms/pykmsbase.cpp @@ -22,6 +22,7 @@ void init_pykmsbase(py::module &m) py::class_(m, "Card") .def(py::init<>()) .def(py::init()) + .def(py::init()) .def_property_readonly("fd", &Card::fd) .def_property_readonly("get_first_connected_connector", &Card::get_first_connected_connector) -- cgit v1.2.3