diff --git a/udev.cpp b/udev.cpp
index b97550cbad..4809f67362 100644
--- a/udev.cpp
+++ b/udev.cpp
@@ -18,7 +18,12 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see .
*********************************************************************/
#include "udev.h"
+// Qt
+#include
+#include
+// system
#include
+#include
namespace KWin
{
@@ -35,4 +40,145 @@ Udev::~Udev()
}
}
+class UdevEnumerate
+{
+public:
+ UdevEnumerate(Udev *udev);
+ ~UdevEnumerate();
+
+ enum class Match {
+ SubSystem,
+ SysName
+ };
+ void addMatch(Match match, const char *name);
+ void scan();
+ UdevDevice::Ptr find(std::function test);
+
+private:
+ Udev *m_udev;
+
+ struct EnumerateDeleter
+ {
+ static inline void cleanup(udev_enumerate *e)
+ {
+ udev_enumerate_unref(e);
+ }
+ };
+ QScopedPointer m_enumerate;
+};
+
+UdevEnumerate::UdevEnumerate(Udev *udev)
+ : m_udev(udev)
+ , m_enumerate(udev_enumerate_new(*m_udev))
+{
+}
+
+UdevEnumerate::~UdevEnumerate() = default;
+
+void UdevEnumerate::addMatch(UdevEnumerate::Match match, const char *name)
+{
+ if (m_enumerate.isNull()) {
+ return;
+ }
+ switch (match) {
+ case Match::SubSystem:
+ udev_enumerate_add_match_subsystem(m_enumerate.data(), name);
+ break;
+ case Match::SysName:
+ udev_enumerate_add_match_sysname(m_enumerate.data(), name);
+ break;
+ default:
+ Q_UNREACHABLE();
+ break;
+ }
+}
+
+void UdevEnumerate::scan()
+{
+ if (m_enumerate.isNull()) {
+ return;
+ }
+ udev_enumerate_scan_devices(m_enumerate.data());
+}
+
+UdevDevice::Ptr UdevEnumerate::find(std::function test)
+{
+ if (m_enumerate.isNull()) {
+ return UdevDevice::Ptr();
+ }
+ udev_list_entry *it = udev_enumerate_get_list_entry(m_enumerate.data());
+ UdevDevice::Ptr firstFound;
+ while (it) {
+ auto current = it;
+ it = udev_list_entry_get_next(it);
+ auto device = m_udev->deviceFromSyspath(udev_list_entry_get_name(current));
+ if (!device) {
+ continue;
+ }
+ if (test(device)) {
+ return std::move(device);
+ }
+ if (!firstFound) {
+ firstFound.swap(device);
+ }
+ }
+ return std::move(firstFound);
+}
+
+UdevDevice::Ptr Udev::primaryGpu()
+{
+ if (!m_udev) {
+ return UdevDevice::Ptr();
+ }
+ UdevEnumerate enumerate(this);
+ enumerate.addMatch(UdevEnumerate::Match::SubSystem, "drm");
+ enumerate.addMatch(UdevEnumerate::Match::SysName, "card[0-9]*");
+ enumerate.scan();
+ return enumerate.find([](const UdevDevice::Ptr &device) {
+ // TODO: check seat
+ auto pci = device->getParentWithSubsystemDevType("pci");
+ if (!pci) {
+ return false;
+ }
+ const char *systAttrValue = udev_device_get_sysattr_value(pci, "boot_vga");
+ if (systAttrValue && qstrcmp(systAttrValue, "1") == 0) {
+ return true;
+ }
+ return false;
+ });
+}
+
+UdevDevice::Ptr Udev::deviceFromSyspath(const char *syspath)
+{
+ return std::move(UdevDevice::Ptr(new UdevDevice(udev_device_new_from_syspath(m_udev, syspath))));
+}
+
+UdevDevice::UdevDevice(udev_device *device)
+ : m_device(device)
+{
+}
+
+UdevDevice::~UdevDevice()
+{
+ if (m_device) {
+ udev_device_unref(m_device);
+ }
+}
+
+udev_device *UdevDevice::getParentWithSubsystemDevType(const char *subsystem, const char *devtype) const
+{
+ if (!m_device) {
+ return nullptr;
+ }
+ return udev_device_get_parent_with_subsystem_devtype(m_device, subsystem, devtype);
+}
+
+const char *UdevDevice::devNode()
+{
+ if (!m_device) {
+ return nullptr;
+ }
+ return udev_device_get_devnode(m_device);
+}
+
}
diff --git a/udev.h b/udev.h
index 86e8dcf59d..a3833037b0 100644
--- a/udev.h
+++ b/udev.h
@@ -19,12 +19,36 @@ along with this program. If not, see .
*********************************************************************/
#ifndef KWIN_UDEV_H
#define KWIN_UDEV_H
+#include
struct udev;
+struct udev_device;
namespace KWin
{
+
+class UdevDevice
+{
+public:
+ UdevDevice(udev_device *device);
+ ~UdevDevice();
+
+ udev_device *getParentWithSubsystemDevType(const char *subsystem, const char *devtype = nullptr) const;
+ const char *devNode();
+
+ operator udev_device*() const {
+ return m_device;
+ }
+ operator udev_device*() {
+ return m_device;
+ }
+ typedef std::unique_ptr Ptr;
+
+private:
+ udev_device *m_device;
+};
+
class Udev
{
public:
@@ -34,6 +58,8 @@ public:
bool isValid() const {
return m_udev != nullptr;
}
+ UdevDevice::Ptr primaryGpu();
+ UdevDevice::Ptr deviceFromSyspath(const char *syspath);
operator udev*() const {
return m_udev;
}