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