mirror of
https://gitlab.freedesktop.org/emersion/libliftoff.git
synced 2024-11-16 19:47:55 +01:00
f6b4cd6197
From the kernel docs: > -EINTR, -EAGAIN or -ERESTARTSYS, if the IOCTL should be restarted. This can > either be due to a pending signal, or because the driver needs to completely > bail out to recover from an exceptional situation like a GPU hang. From a > userspace point of view all errors are treated equally. We're not handling ERESTARTSYS because it's non-POSIX.
106 lines
2.4 KiB
C
106 lines
2.4 KiB
C
#include <errno.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include "log.h"
|
|
#include "private.h"
|
|
|
|
struct liftoff_device *liftoff_device_create(int drm_fd)
|
|
{
|
|
struct liftoff_device *device;
|
|
drmModeRes *drm_res;
|
|
drmModePlaneRes *drm_plane_res;
|
|
uint32_t i;
|
|
|
|
device = calloc(1, sizeof(*device));
|
|
if (device == NULL) {
|
|
liftoff_log_errno(LIFTOFF_ERROR, "calloc");
|
|
return NULL;
|
|
}
|
|
|
|
liftoff_list_init(&device->planes);
|
|
liftoff_list_init(&device->outputs);
|
|
|
|
device->drm_fd = dup(drm_fd);
|
|
if (device->drm_fd < 0) {
|
|
liftoff_log_errno(LIFTOFF_ERROR, "dup");
|
|
liftoff_device_destroy(device);
|
|
return NULL;
|
|
}
|
|
|
|
drm_res = drmModeGetResources(drm_fd);
|
|
if (drm_res == NULL) {
|
|
liftoff_log_errno(LIFTOFF_ERROR, "drmModeGetResources");
|
|
liftoff_device_destroy(device);
|
|
return NULL;
|
|
}
|
|
|
|
device->crtcs = malloc(drm_res->count_crtcs * sizeof(uint32_t));
|
|
if (device->crtcs == NULL) {
|
|
liftoff_log_errno(LIFTOFF_ERROR, "malloc");
|
|
drmModeFreeResources(drm_res);
|
|
liftoff_device_destroy(device);
|
|
return NULL;
|
|
}
|
|
device->crtcs_len = drm_res->count_crtcs;
|
|
memcpy(device->crtcs, drm_res->crtcs,
|
|
drm_res->count_crtcs * sizeof(uint32_t));
|
|
|
|
drmModeFreeResources(drm_res);
|
|
|
|
/* TODO: allow users to choose which layers to hand over */
|
|
drm_plane_res = drmModeGetPlaneResources(drm_fd);
|
|
if (drm_plane_res == NULL) {
|
|
liftoff_log_errno(LIFTOFF_ERROR, "drmModeGetPlaneResources");
|
|
liftoff_device_destroy(device);
|
|
return NULL;
|
|
}
|
|
|
|
for (i = 0; i < drm_plane_res->count_planes; i++) {
|
|
if (plane_create(device, drm_plane_res->planes[i]) == NULL) {
|
|
liftoff_device_destroy(device);
|
|
return NULL;
|
|
}
|
|
}
|
|
drmModeFreePlaneResources(drm_plane_res);
|
|
|
|
return device;
|
|
}
|
|
|
|
void liftoff_device_destroy(struct liftoff_device *device)
|
|
{
|
|
struct liftoff_plane *plane, *tmp;
|
|
|
|
if (device == NULL) {
|
|
return;
|
|
}
|
|
|
|
close(device->drm_fd);
|
|
liftoff_list_for_each_safe(plane, tmp, &device->planes, link) {
|
|
plane_destroy(plane);
|
|
}
|
|
free(device->crtcs);
|
|
free(device);
|
|
}
|
|
|
|
bool device_test_commit(struct liftoff_device *device,
|
|
drmModeAtomicReq *req, bool *compatible)
|
|
{
|
|
int ret;
|
|
|
|
do {
|
|
ret = drmModeAtomicCommit(device->drm_fd, req,
|
|
DRM_MODE_ATOMIC_TEST_ONLY, NULL);
|
|
} while (-ret == EINTR || -ret == EAGAIN);
|
|
if (ret == 0) {
|
|
*compatible = true;
|
|
} else if (-ret == EINVAL || -ret == ERANGE) {
|
|
*compatible = false;
|
|
} else {
|
|
liftoff_log_errno(LIFTOFF_ERROR, "drmModeAtomicCommit");
|
|
*compatible = false;
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|