KWin
Loading...
Searching...
No Matches
udev.cpp
Go to the documentation of this file.
1/*
2 KWin - the KDE window manager
3 This file is part of the KDE project.
4
5 SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
6
7 SPDX-License-Identifier: GPL-2.0-or-later
8*/
9#include "udev.h"
10#include "utils/common.h"
11// Qt
12#include <QByteArray>
13#include <QDebug>
14// system
15#include <cerrno>
16#include <functional>
17#include <libudev.h>
18
19namespace KWin
20{
21
23 : m_udev(udev_new())
24{
25}
26
28{
29 if (m_udev) {
30 udev_unref(m_udev);
31 }
32}
33
35{
36public:
37 UdevEnumerate(Udev *udev);
39
40 enum class Match {
43 };
44 void addMatch(Match match, const char *name);
45 void scan();
46 std::vector<std::unique_ptr<UdevDevice>> find();
47
48private:
49 Udev *m_udev;
50
51 struct EnumerateDeleter
52 {
53 void operator()(udev_enumerate *e)
54 {
55 udev_enumerate_unref(e);
56 }
57 };
58 std::unique_ptr<udev_enumerate, EnumerateDeleter> m_enumerate;
59};
60
62 : m_udev(udev)
63 , m_enumerate(udev_enumerate_new(*m_udev))
64{
65}
66
68
70{
71 if (!m_enumerate) {
72 return;
73 }
74 switch (match) {
76 udev_enumerate_add_match_subsystem(m_enumerate.get(), name);
77 break;
78 case Match::SysName:
79 udev_enumerate_add_match_sysname(m_enumerate.get(), name);
80 break;
81 default:
82 Q_UNREACHABLE();
83 break;
84 }
85}
86
88{
89 if (!m_enumerate) {
90 return;
91 }
92 udev_enumerate_scan_devices(m_enumerate.get());
93}
94
95std::vector<std::unique_ptr<UdevDevice>> UdevEnumerate::find()
96{
97 if (!m_enumerate) {
98 return {};
99 }
100 std::vector<std::unique_ptr<UdevDevice>> vect;
101 udev_list_entry *it = udev_enumerate_get_list_entry(m_enumerate.get());
102 while (it) {
103 auto current = it;
104 it = udev_list_entry_get_next(it);
105 auto device = m_udev->deviceFromSyspath(udev_list_entry_get_name(current));
106 if (device) {
107 vect.push_back(std::move(device));
108 }
109 }
110 return vect;
111}
112
113std::vector<std::unique_ptr<UdevDevice>> Udev::listGPUs()
114{
115 if (!m_udev) {
116 return {};
117 }
118#if defined(Q_OS_FREEBSD)
119 std::vector<std::unique_ptr<UdevDevice>> r;
120 r.push_back(deviceFromSyspath("/dev/dri/card0"));
121 return r;
122#else
123 UdevEnumerate enumerate(this);
125 enumerate.addMatch(UdevEnumerate::Match::SysName, "card[0-9]");
126 enumerate.scan();
127 auto vect = enumerate.find();
128 std::sort(vect.begin(), vect.end(), [](const auto &device1, const auto &device2) {
129 // prevent usb devices from becoming the primaryGpu
130 if (device1->isHotpluggable()) {
131 return false;
132 }
133
134 if (device2->isHotpluggable()) {
135 return true;
136 }
137
138 // if set as boot GPU, prefer 1
139 if (device1->isBootVga()) {
140 return true;
141 }
142 // if set as boot GPU, prefer 2
143 if (device2->isBootVga()) {
144 return false;
145 }
146 return true;
147 });
148 return vect;
149#endif
150}
151
152std::unique_ptr<UdevDevice> Udev::deviceFromSyspath(const char *syspath)
153{
154 auto dev = udev_device_new_from_syspath(m_udev, syspath);
155 if (!dev) {
156 qCWarning(KWIN_CORE) << "failed to retrieve device for" << syspath << strerror(errno);
157 return {};
158 }
159 return std::make_unique<UdevDevice>(dev);
160}
161
162std::unique_ptr<UdevMonitor> Udev::monitor()
163{
164 auto m = std::make_unique<UdevMonitor>(this);
165 if (m->isValid()) {
166 return m;
167 } else {
168 return nullptr;
169 }
170}
171
172UdevDevice::UdevDevice(udev_device *device)
173 : m_device(device)
174{
175 Q_ASSERT(device);
176}
177
179{
180 udev_device_unref(m_device);
181}
182
183QString UdevDevice::devNode() const
184{
185 return QString::fromUtf8(udev_device_get_devnode(m_device));
186}
187
189{
190 return udev_device_get_devnum(m_device);
191}
192
193const char *UdevDevice::property(const char *key)
194{
195 return udev_device_get_property_value(m_device, key);
196}
197
198QMap<QByteArray, QByteArray> UdevDevice::properties() const
199{
200 QMap<QByteArray, QByteArray> r;
201 auto it = udev_device_get_properties_list_entry(m_device);
202 auto current = it;
203 udev_list_entry_foreach(current, it)
204 {
205 r.insert(udev_list_entry_get_name(current), udev_list_entry_get_value(current));
206 }
207 return r;
208}
209
210bool UdevDevice::hasProperty(const char *key, const char *value)
211{
212 const char *p = property(key);
213 if (!p) {
214 return false;
215 }
216 return qstrcmp(p, value) == 0;
217}
218
220{
221 auto pci = udev_device_get_parent_with_subsystem_devtype(m_device, "pci", nullptr);
222 if (!pci) {
223 return false;
224 }
225 const char *systAttrValue = udev_device_get_sysattr_value(pci, "boot_vga");
226 return systAttrValue && qstrcmp(systAttrValue, "1") == 0;
227}
228
229QString UdevDevice::seat() const
230{
231 QString deviceSeat = udev_device_get_property_value(m_device, "ID_SEAT");
232 if (deviceSeat.isEmpty()) {
233 deviceSeat = QStringLiteral("seat0");
234 }
235 return deviceSeat;
236}
237
238QString UdevDevice::action() const
239{
240 return QString::fromLocal8Bit(udev_device_get_action(m_device));
241}
242
244{
245 QString devPath = QString::fromUtf8(udev_device_get_devpath(m_device));
246 return devPath.toLower().contains("usb");
247}
248
250 : m_monitor(udev_monitor_new_from_netlink(*udev, "udev"))
251{
252}
253
255{
256 if (m_monitor) {
257 udev_monitor_unref(m_monitor);
258 }
259}
260
262{
263 if (m_monitor) {
264 return udev_monitor_get_fd(m_monitor);
265 }
266 return -1;
267}
268
269void UdevMonitor::filterSubsystemDevType(const char *subSystem, const char *devType)
270{
271 if (!m_monitor) {
272 return;
273 }
274 udev_monitor_filter_add_match_subsystem_devtype(m_monitor, subSystem, devType);
275}
276
278{
279 if (!m_monitor) {
280 return;
281 }
282 udev_monitor_enable_receiving(m_monitor);
283}
284
285std::unique_ptr<UdevDevice> UdevMonitor::getDevice()
286{
287 if (!m_monitor) {
288 return nullptr;
289 }
290 auto dev = udev_monitor_receive_device(m_monitor);
291 return dev ? std::make_unique<UdevDevice>(dev) : nullptr;
292}
293
294}
bool hasProperty(const char *key, const char *value)
Definition udev.cpp:210
QString seat() const
Definition udev.cpp:229
bool isBootVga() const
Definition udev.cpp:219
dev_t devNum() const
Definition udev.cpp:188
QMap< QByteArray, QByteArray > properties() const
Definition udev.cpp:198
const char * property(const char *key)
Definition udev.cpp:193
bool isHotpluggable() const
Definition udev.cpp:243
QString devNode() const
Definition udev.cpp:183
QString action() const
Definition udev.cpp:238
UdevEnumerate(Udev *udev)
Definition udev.cpp:61
void addMatch(Match match, const char *name)
Definition udev.cpp:69
std::vector< std::unique_ptr< UdevDevice > > find()
Definition udev.cpp:95
std::vector< std::unique_ptr< UdevDevice > > listGPUs()
Definition udev.cpp:113
std::unique_ptr< UdevDevice > deviceFromSyspath(const char *syspath)
Definition udev.cpp:152
UdevMonitor(Udev *udev)
Definition udev.cpp:249
std::unique_ptr< UdevDevice > getDevice()
Definition udev.cpp:285
int fd() const
Definition udev.cpp:261
void filterSubsystemDevType(const char *subSystem, const char *devType=nullptr)
Definition udev.cpp:269
bool match(QList< GlobalShortcut > &shortcuts, Args... args)