KWaylandServer

drmleasedevice_v1_interface.cpp
1 /*
2  SPDX-FileCopyrightText: 2021 Xaver Hugl <[email protected]>
3 
4  SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
5 */
6 
7 #include "drmleasedevice_v1_interface.h"
8 #include "drmleasedevice_v1_interface_p.h"
9 #include "display.h"
10 #include "logging.h"
11 #include "utils.h"
12 
13 #include <fcntl.h>
14 #include <unistd.h>
15 
16 namespace KWaylandServer
17 {
18 
19 static const quint32 s_version = 1;
20 
21 DrmLeaseDeviceV1Interface::DrmLeaseDeviceV1Interface(Display *display, std::function<int()> createNonMasterFd)
22  : d(new DrmLeaseDeviceV1InterfacePrivate(display, this, createNonMasterFd))
23 {
24 }
25 
26 DrmLeaseDeviceV1Interface::~DrmLeaseDeviceV1Interface()
27 {
28  d->remove();
29 }
30 
32 {
33  if (hasDrmMaster && !d->hasDrmMaster) {
34  // withdraw all connectors
35  for (const auto &connector : qAsConst(d->connectors)) {
36  DrmLeaseConnectorV1InterfacePrivate::get(connector)->withdraw();
37  }
38  // and revoke all leases
39  for (const auto &lease : qAsConst(d->leases)) {
40  lease->deny();
41  }
42  } else if (!hasDrmMaster && d->hasDrmMaster) {
43  // send pending drm fds
44  while (!d->pendingFds.isEmpty()) {
45  int fd = d->createNonMasterFd();
46  d->send_drm_fd(d->pendingFds.dequeue(), fd);
47  close(fd);
48  }
49  // offer all connectors again
50  for (const auto &connector : qAsConst(d->connectors)) {
51  auto connectorPrivate = DrmLeaseConnectorV1InterfacePrivate::get(connector);
52  connectorPrivate->withdrawn = false;
53  for (const auto &resource : d->resourceMap()) {
54  auto connectorResource = connectorPrivate->add(resource->client(), 0, s_version);
55  d->send_connector(resource->handle, connectorResource->handle);
56  connectorPrivate->send(connectorResource->handle);
57  }
58  }
59  }
60  d->hasDrmMaster = hasDrmMaster;
61 }
62 
63 
64 DrmLeaseDeviceV1InterfacePrivate::DrmLeaseDeviceV1InterfacePrivate(Display *display, DrmLeaseDeviceV1Interface *device, std::function<int()> createNonMasterFd)
65  : QtWaylandServer::wp_drm_lease_device_v1(*display, s_version)
66  , q(device)
67  , createNonMasterFd(createNonMasterFd)
68 {
69 }
70 
71 DrmLeaseDeviceV1InterfacePrivate::~DrmLeaseDeviceV1InterfacePrivate()
72 {
73 }
74 
75 void DrmLeaseDeviceV1InterfacePrivate::remove()
76 {
77  for (const auto &lease : qAsConst(leases)) {
78  lease->deny();
79  }
80  for (const auto &connector : qAsConst(connectors)) {
81  DrmLeaseConnectorV1InterfacePrivate::get(connector)->withdraw();
82  }
83  for (const auto &request : qAsConst(leaseRequests)) {
84  request->connectors.clear();
85  }
86  globalRemove();
87  removed = true;
88  if (resourceMap().isEmpty()) {
89  delete this;
90  }
91 }
92 
93 void DrmLeaseDeviceV1InterfacePrivate::registerConnector(DrmLeaseConnectorV1Interface *connector)
94 {
95  connectors << connector;
96  if (!hasDrmMaster) {
97  return;
98  }
99  for (const auto &resource : resourceMap()) {
100  auto connectorPrivate = DrmLeaseConnectorV1InterfacePrivate::get(connector);
101  auto connectorResource = connectorPrivate->add(resource->client(), 0, resource->version());
102  send_connector(resource->handle, connectorResource->handle);
103  connectorPrivate->send(connectorResource->handle);
104  }
105 }
106 
107 void DrmLeaseDeviceV1InterfacePrivate::unregisterConnector(DrmLeaseConnectorV1Interface *connector)
108 {
109  connectors.removeOne(connector);
110  for (const auto &lease : qAsConst(leases)) {
111  if (lease->d->connectors.contains(connector)) {
112  lease->d->connectors.removeOne(connector);
113  lease->deny();
114  }
115  }
116  for (const auto &leaseRequest : qAsConst(leaseRequests)) {
117  if (leaseRequest->connectors.removeOne(connector)) {
118  leaseRequest->invalid = true;
119  }
120  }
121 }
122 
123 DrmLeaseDeviceV1InterfacePrivate *DrmLeaseDeviceV1InterfacePrivate::get(DrmLeaseDeviceV1Interface *device)
124 {
125  return device->d;
126 }
127 
128 void DrmLeaseDeviceV1InterfacePrivate::wp_drm_lease_device_v1_create_lease_request(Resource *resource, uint32_t id)
129 {
130  wl_resource *requestResource = wl_resource_create(resource->client(), &wp_drm_lease_request_v1_interface,
131  resource->version(), id);
132  if (!requestResource) {
133  wl_resource_post_no_memory(resource->handle);
134  return;
135  }
136  leaseRequests << new DrmLeaseRequestV1Interface(this, requestResource);
137 }
138 
139 void DrmLeaseDeviceV1InterfacePrivate::wp_drm_lease_device_v1_release(Resource *resource)
140 {
141  send_released(resource->handle);
142  wl_resource_destroy(resource->handle);
143 }
144 
145 void DrmLeaseDeviceV1InterfacePrivate::wp_drm_lease_device_v1_bind_resource(Resource *resource)
146 {
147  if (!hasDrmMaster) {
148  pendingFds << resource->handle;
149  return;
150  }
151  int fd = createNonMasterFd();
152  send_drm_fd(resource->handle, fd);
153  close(fd);
154  for (const auto &connector : qAsConst(connectors)) {
155  auto connectorPrivate = DrmLeaseConnectorV1InterfacePrivate::get(connector);
156  if (!connectorPrivate->withdrawn) {
157  auto connectorResource = connectorPrivate->add(resource->client(), 0, s_version);
158  send_connector(resource->handle, connectorResource->handle);
159  connectorPrivate->send(connectorResource->handle);
160  }
161  }
162 }
163 
164 void DrmLeaseDeviceV1InterfacePrivate::wp_drm_lease_device_v1_destroy_resource(Resource *resource)
165 {
166  Q_UNUSED(resource)
167  if (removed && resourceMap().isEmpty()) {
168  delete this;
169  }
170 }
171 
172 
173 DrmLeaseConnectorV1Interface::DrmLeaseConnectorV1Interface(DrmLeaseDeviceV1Interface *leaseDevice,
174  uint32_t id,
175  const QString &name,
176  const QString &description)
177  : d(new DrmLeaseConnectorV1InterfacePrivate(leaseDevice, this, id, name, description))
178 {
179  DrmLeaseDeviceV1InterfacePrivate::get(leaseDevice)->registerConnector(this);
180 }
181 
182 DrmLeaseConnectorV1Interface::~DrmLeaseConnectorV1Interface()
183 {
184  d->withdraw();
185  if (d->device) {
186  auto devicePrivate = DrmLeaseDeviceV1InterfacePrivate::get(d->device);
187  devicePrivate->unregisterConnector(this);
188  }
189 }
190 
191 DrmLeaseConnectorV1Interface *DrmLeaseConnectorV1Interface::get(wl_resource *resource)
192 {
193  if (auto connectorPrivate = resource_cast<DrmLeaseConnectorV1InterfacePrivate*>(resource)) {
194  return connectorPrivate->q;
195  }
196  return nullptr;
197 }
198 
199 DrmLeaseConnectorV1InterfacePrivate::DrmLeaseConnectorV1InterfacePrivate(DrmLeaseDeviceV1Interface *device,
200  DrmLeaseConnectorV1Interface *connector,
201  uint32_t connectorId,
202  const QString &name,
203  const QString &description)
204  : wp_drm_lease_connector_v1()
205  , q(connector)
206  , device(device)
207  , connectorId(connectorId)
208  , name(name)
209  , description(description)
210 {
211 }
212 
213 DrmLeaseConnectorV1InterfacePrivate::~DrmLeaseConnectorV1InterfacePrivate()
214 {
215 }
216 
217 void DrmLeaseConnectorV1InterfacePrivate::send(wl_resource *resource)
218 {
219  send_connector_id(resource, connectorId);
220  send_name(resource, name);
221  send_description(resource, description);
222  send_done(resource);
223 }
224 
225 void DrmLeaseConnectorV1InterfacePrivate::withdraw()
226 {
227  if (!withdrawn) {
228  withdrawn = true;
229  for (const auto &resource : resourceMap()) {
230  send_withdrawn(resource->handle);
231  DrmLeaseDeviceV1InterfacePrivate::get(device)->send_done(resource->handle);
232  }
233  }
234 }
235 
236 DrmLeaseConnectorV1InterfacePrivate *DrmLeaseConnectorV1InterfacePrivate::get(DrmLeaseConnectorV1Interface *connector)
237 {
238  return connector->d.get();
239 }
240 
241 void DrmLeaseConnectorV1InterfacePrivate::wp_drm_lease_connector_v1_destroy(Resource *resource)
242 {
243  wl_resource_destroy(resource->handle);
244 }
245 
246 
247 DrmLeaseRequestV1Interface::DrmLeaseRequestV1Interface(DrmLeaseDeviceV1InterfacePrivate *device, wl_resource *resource)
248  : wp_drm_lease_request_v1(resource)
249  , device(device)
250 {
251 }
252 
253 DrmLeaseRequestV1Interface::~DrmLeaseRequestV1Interface()
254 {
255  device->leaseRequests.removeOne(this);
256 }
257 
258 void DrmLeaseRequestV1Interface::wp_drm_lease_request_v1_request_connector(Resource *resource, struct ::wl_resource *connector_handle)
259 {
260  Q_UNUSED(resource);
261  if (auto connector = DrmLeaseConnectorV1Interface::get(connector_handle)) {
262  auto connectorPrivate = DrmLeaseConnectorV1InterfacePrivate::get(connector);
263  if (connectorPrivate->device != device->q) {
264  wl_resource_post_error(resource->handle, WP_DRM_LEASE_REQUEST_V1_ERROR_WRONG_DEVICE, "Requested connector from invalid lease device");
265  } else if (connectorPrivate->withdrawn) {
266  qCWarning(KWAYLAND_SERVER) << "DrmLease: withdrawn connector requested";
267  } else if (connectors.contains(connector)) {
268  wl_resource_post_error(resource->handle, WP_DRM_LEASE_REQUEST_V1_ERROR_DUPLICATE_CONNECTOR, "Requested connector twice");
269  } else {
270  connectors << connector;
271  }
272  } else {
273  qCWarning(KWAYLAND_SERVER, "DrmLease: Invalid connector requested");
274  }
275 }
276 
277 void DrmLeaseRequestV1Interface::wp_drm_lease_request_v1_submit(Resource *resource, uint32_t id)
278 {
279  wl_resource *leaseResource = wl_resource_create(resource->client(), &wp_drm_lease_v1_interface, s_version, id);
280  if (!leaseResource) {
281  wl_resource_post_no_memory(resource->handle);
282  return;
283  }
284  DrmLeaseV1Interface *lease = new DrmLeaseV1Interface(device, leaseResource);
285  device->leases << lease;
286  if (!device->hasDrmMaster) {
287  qCWarning(KWAYLAND_SERVER) << "DrmLease: rejecting lease request without drm master";
288  lease->deny();
289  } else if (invalid) {
290  qCWarning(KWAYLAND_SERVER()) << "DrmLease: rejecting lease request with a withdrawn connector";
291  lease->deny();
292  } else if (connectors.isEmpty()) {
293  wl_resource_post_error(resource->handle, WP_DRM_LEASE_REQUEST_V1_ERROR_EMPTY_LEASE, "Requested lease without connectors");
294  } else {
295  lease->d->connectors = connectors;
296  emit device->q->leaseRequested(lease);
297  }
298  wl_resource_destroy(resource->handle);
299 }
300 
301 void DrmLeaseRequestV1Interface::wp_drm_lease_request_v1_destroy_resource(Resource *resource)
302 {
303  Q_UNUSED(resource)
304  delete this;
305 }
306 
307 DrmLeaseV1Interface::DrmLeaseV1Interface(DrmLeaseDeviceV1InterfacePrivate *device, wl_resource *resource)
308  : d(new DrmLeaseV1InterfacePrivate(device, this, resource))
309 {
310 }
311 
312 DrmLeaseV1Interface::~DrmLeaseV1Interface()
313 {
314  deny();
315  d->device->leases.removeOne(this);
316 }
317 
318 void DrmLeaseV1Interface::grant(int leaseFd, uint32_t lesseeId)
319 {
320  d->send_lease_fd(leaseFd);
321  close(leaseFd);
322  d->lesseeId = lesseeId;
323  for (const auto &connector : qAsConst(d->connectors)) {
324  DrmLeaseConnectorV1InterfacePrivate::get(connector)->withdraw();
325  }
326 }
327 
329 {
330  if (!d->finished) {
331  d->finished = true;
332  d->send_finished();
333  }
334  if (!d->lesseeId) {
335  return;
336  }
337  Q_EMIT d->device->q->leaseRevoked(this);
338  // check if we should offer connectors again
339  if (d->device->hasDrmMaster) {
340  bool sent = false;
341  for (const auto &connector : qAsConst(d->connectors)) {
342  auto connectorPrivate = DrmLeaseConnectorV1InterfacePrivate::get(connector);
343  connectorPrivate->withdrawn = false;
344  for (const auto &resource : d->device->resourceMap()) {
345  auto connectorResource = connectorPrivate->add(resource->client(), 0, s_version);
346  d->device->send_connector(resource->handle, connectorResource->handle);
347  connectorPrivate->send(connectorResource->handle);
348  sent = true;
349  }
350  }
351  if (sent) {
352  for (const auto &resource : d->device->resourceMap()) {
353  d->device->send_done(resource->handle);
354  }
355  }
356  }
357  d->lesseeId = 0;
358 }
359 
361 {
362  return d->lesseeId;
363 }
364 
366 {
367  return d->connectors;
368 }
369 
370 
371 DrmLeaseV1InterfacePrivate::DrmLeaseV1InterfacePrivate(DrmLeaseDeviceV1InterfacePrivate *device, DrmLeaseV1Interface *q, wl_resource *resource)
372  : wp_drm_lease_v1(resource)
373  , device(device)
374  , q(q)
375 {
376 }
377 
378 void DrmLeaseV1InterfacePrivate::wp_drm_lease_v1_destroy(Resource *resource)
379 {
380  wl_resource_destroy(resource->handle);
381 }
382 
383 void DrmLeaseV1InterfacePrivate::wp_drm_lease_v1_destroy_resource(Resource *resource)
384 {
385  Q_UNUSED(resource)
386  delete q;
387 }
388 
389 }
uint32_t lesseeId() const
The lesseeId passed to DrmLeaseV1Interface::grant, or 0 if this lease was not granted.
Class holding the Wayland server display loop.
Definition: display.h:47
Represents a lease offer from the compositor.
T * get() const const
The DrmLeaseV1DeviceInterface allows the wayland compositor to offer unused drm connectors for lease ...
DrmLeaseDeviceV1Interface(Display *display, std::function< int()> createNonMasterFd)
void grant(int leaseFd, uint32_t lesseeId)
Grant the client requesting the lease access to DRM resources needed to drive the outputs correspondi...
void setDrmMaster(bool hasDrmMaster)
Must be called by the compositor when it loses or gains drm master.
Represents a lease request or active lease.
QVector< DrmLeaseConnectorV1Interface * > connectors() const
The connectors this lease (request) encompasses.
Q_EMITQ_EMIT
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Sat Oct 23 2021 23:08:27 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.