* DEALINGS IN THE SOFTWARE.
*/
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
* If any other failure happened then it will output error mesage using
* drmMsg() call.
*/
-#if !defined(UDEV)
+#if !UDEV
static int chown_check_return(const char *path, uid_t owner, gid_t group)
{
int rv;
int fd;
mode_t devmode = DRM_DEV_MODE, serv_mode;
gid_t serv_group;
-#if !defined(UDEV)
+#if !UDEV
int isroot = !geteuid();
uid_t user = DRM_DEV_UID;
gid_t group = DRM_DEV_GID;
devmode &= ~(S_IXUSR|S_IXGRP|S_IXOTH);
}
-#if !defined(UDEV)
+#if !UDEV
if (stat(DRM_DIR_NAME, &st)) {
if (!isroot)
return DRM_ERR_NOT_ROOT;
}
#endif
- fd = open(buf, O_RDWR, 0);
+ fd = open(buf, O_RDWR | O_CLOEXEC, 0);
drmMsg("drmOpenDevice: open result is %d, (%s)\n",
fd, fd < 0 ? strerror(errno) : "OK");
if (fd >= 0)
return fd;
-#if !defined(UDEV)
+#if !UDEV
/* Check if the device node is not what we expect it to be, and recreate it
* and try again if so.
*/
chmod(buf, devmode);
}
}
- fd = open(buf, O_RDWR, 0);
+ fd = open(buf, O_RDWR | O_CLOEXEC, 0);
drmMsg("drmOpenDevice: open result is %d, (%s)\n",
fd, fd < 0 ? strerror(errno) : "OK");
if (fd >= 0)
};
sprintf(buf, dev_name, DRM_DIR_NAME, minor);
- if ((fd = open(buf, O_RDWR, 0)) >= 0)
+ if ((fd = open(buf, O_RDWR | O_CLOEXEC, 0)) >= 0)
return fd;
return -errno;
}
drmVersionPtr retval;
drm_version_t *version = drmMalloc(sizeof(*version));
- memclear(*version);
-
if (drmIoctl(fd, DRM_IOCTL_VERSION, version)) {
drmFreeKernelVersion(version);
return NULL;
if (drmIoctl(fd, DRM_IOCTL_GET_UNIQUE, &u))
return NULL;
u.unique = drmMalloc(u.unique_len + 1);
- if (drmIoctl(fd, DRM_IOCTL_GET_UNIQUE, &u))
+ if (drmIoctl(fd, DRM_IOCTL_GET_UNIQUE, &u)) {
+ drmFree(u.unique);
return NULL;
+ }
u.unique[u.unique_len] = '\0';
return u.unique;
if (!(list = drmMalloc(res.count * sizeof(*list))))
return NULL;
- if (!(retval = drmMalloc(res.count * sizeof(*retval)))) {
- drmFree(list);
- return NULL;
- }
+ if (!(retval = drmMalloc(res.count * sizeof(*retval))))
+ goto err_free_list;
res.contexts = list;
if (drmIoctl(fd, DRM_IOCTL_RES_CTX, &res))
- return NULL;
+ goto err_free_context;
for (i = 0; i < res.count; i++)
retval[i] = list[i].handle;
*count = res.count;
return retval;
+
+err_free_list:
+ drmFree(list);
+err_free_context:
+ drmFree(retval);
+ return NULL;
}
void drmFreeReservedContextList(drm_context_t *pt)
return 0;
}
+int drmCrtcGetSequence(int fd, uint32_t crtcId, uint64_t *sequence, uint64_t *ns)
+{
+ struct drm_crtc_get_sequence get_seq;
+ int ret;
+
+ memclear(get_seq);
+ get_seq.crtc_id = crtcId;
+ ret = drmIoctl(fd, DRM_IOCTL_CRTC_GET_SEQUENCE, &get_seq);
+ if (ret)
+ return ret;
+
+ if (sequence)
+ *sequence = get_seq.sequence;
+ if (ns)
+ *ns = get_seq.sequence_ns;
+ return 0;
+}
+
+int drmCrtcQueueSequence(int fd, uint32_t crtcId, uint32_t flags, uint64_t sequence,
+ uint64_t *sequence_queued, uint64_t user_data)
+{
+ struct drm_crtc_queue_sequence queue_seq;
+ int ret;
+
+ memclear(queue_seq);
+ queue_seq.crtc_id = crtcId;
+ queue_seq.flags = flags;
+ queue_seq.sequence = sequence;
+ queue_seq.user_data = user_data;
+
+ ret = drmIoctl(fd, DRM_IOCTL_CRTC_QUEUE_SEQUENCE, &queue_seq);
+ if (ret == 0 && sequence_queued)
+ *sequence_queued = queue_seq.sequence;
+
+ return ret;
+}
+
/**
* Acquire the AGP device.
*
{
#ifdef __linux__
DIR *sysdir;
- struct dirent *pent, *ent;
+ struct dirent *ent;
struct stat sbuf;
const char *name = drmGetMinorName(type);
int len;
char dev_name[64], buf[64];
- long name_max;
int maj, min;
if (!name)
if (!sysdir)
return NULL;
- name_max = fpathconf(dirfd(sysdir), _PC_NAME_MAX);
- if (name_max == -1)
- goto out_close_dir;
-
- pent = malloc(offsetof(struct dirent, d_name) + name_max + 1);
- if (pent == NULL)
- goto out_close_dir;
-
- while (readdir_r(sysdir, pent, &ent) == 0 && ent != NULL) {
+ while ((ent = readdir(sysdir))) {
if (strncmp(ent->d_name, name, len) == 0) {
snprintf(dev_name, sizeof(dev_name), DRM_DIR_NAME "/%s",
ent->d_name);
- free(pent);
closedir(sysdir);
-
return strdup(dev_name);
}
}
- free(pent);
-
-out_close_dir:
closedir(sysdir);
+ return NULL;
#else
struct stat sbuf;
char buf[PATH_MAX + 1];
return strdup(buf);
#endif
- return NULL;
}
char *drmGetPrimaryDeviceNameFromFd(int fd)
}
#endif
+/* Little white lie to avoid major rework of the existing code */
+#define DRM_BUS_VIRTIO 0x10
+
static int drmParseSubsystemType(int maj, int min)
{
#ifdef __linux__
if (strncmp(name, "/host1x", 7) == 0)
return DRM_BUS_HOST1X;
+ if (strncmp(name, "/virtio", 7) == 0)
+ return DRM_BUS_VIRTIO;
+
return -EINVAL;
#elif defined(__OpenBSD__)
return DRM_BUS_PCI;
#endif
}
+static char *
+get_real_pci_path(int maj, int min, char *real_path)
+{
+ char path[PATH_MAX + 1], *term;
+
+ snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min);
+ if (!realpath(path, real_path))
+ return NULL;
+
+ term = strrchr(real_path, '/');
+ if (term && strncmp(term, "/virtio", 7) == 0)
+ *term = 0;
+
+ return real_path;
+}
+
static int drmParsePciBusInfo(int maj, int min, drmPciBusInfoPtr info)
{
#ifdef __linux__
unsigned int domain, bus, dev, func;
- char path[PATH_MAX + 1], *value;
+ char real_path[PATH_MAX + 1], *value;
int num;
- snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min);
+ if (get_real_pci_path(maj, min, real_path) == NULL)
+ return -ENOENT;
- value = sysfs_uevent_get(path, "PCI_SLOT_NAME");
+ value = sysfs_uevent_get(real_path, "PCI_SLOT_NAME");
if (!value)
return -ENOENT;
#endif
}
-static int drmCompareBusInfo(drmDevicePtr a, drmDevicePtr b)
+int drmDevicesEqual(drmDevicePtr a, drmDevicePtr b)
{
if (a == NULL || b == NULL)
- return -1;
+ return 0;
if (a->bustype != b->bustype)
- return -1;
+ return 0;
switch (a->bustype) {
case DRM_BUS_PCI:
- return memcmp(a->businfo.pci, b->businfo.pci, sizeof(drmPciBusInfo));
+ return memcmp(a->businfo.pci, b->businfo.pci, sizeof(drmPciBusInfo)) == 0;
case DRM_BUS_USB:
- return memcmp(a->businfo.usb, b->businfo.usb, sizeof(drmUsbBusInfo));
+ return memcmp(a->businfo.usb, b->businfo.usb, sizeof(drmUsbBusInfo)) == 0;
case DRM_BUS_PLATFORM:
- return memcmp(a->businfo.platform, b->businfo.platform, sizeof(drmPlatformBusInfo));
+ return memcmp(a->businfo.platform, b->businfo.platform, sizeof(drmPlatformBusInfo)) == 0;
case DRM_BUS_HOST1X:
- return memcmp(a->businfo.host1x, b->businfo.host1x, sizeof(drmHost1xBusInfo));
+ return memcmp(a->businfo.host1x, b->businfo.host1x, sizeof(drmHost1xBusInfo)) == 0;
default:
break;
}
- return -1;
+ return 0;
}
static int drmGetNodeType(const char *name)
"subsystem_vendor",
"subsystem_device",
};
- char path[PATH_MAX + 1];
+ char path[PATH_MAX + 1], real_path[PATH_MAX + 1];
unsigned int data[ARRAY_SIZE(attrs)];
FILE *fp;
int ret;
+ if (get_real_pci_path(maj, min, real_path) == NULL)
+ return -ENOENT;
+
for (unsigned i = ignore_revision ? 1 : 0; i < ARRAY_SIZE(attrs); i++) {
- snprintf(path, PATH_MAX, "/sys/dev/char/%d:%d/device/%s", maj, min,
- attrs[i]);
+ snprintf(path, PATH_MAX, "%s/%s", real_path, attrs[i]);
fp = fopen(path, "r");
if (!fp)
return -errno;
static int parse_config_sysfs_file(int maj, int min,
drmPciDeviceInfoPtr device)
{
- char path[PATH_MAX + 1];
+ char path[PATH_MAX + 1], real_path[PATH_MAX + 1];
unsigned char config[64];
int fd, ret;
- snprintf(path, PATH_MAX, "/sys/dev/char/%d:%d/device/config", maj, min);
+ if (get_real_pci_path(maj, min, real_path) == NULL)
+ return -ENOENT;
+
+ snprintf(path, PATH_MAX, "%s/config", real_path);
fd = open(path, O_RDONLY);
if (fd < 0)
return -errno;
return ret;
}
+static int
+process_device(drmDevicePtr *device, const char *d_name,
+ int req_subsystem_type,
+ bool fetch_deviceinfo, uint32_t flags)
+{
+ struct stat sbuf;
+ char node[PATH_MAX + 1];
+ int node_type, subsystem_type;
+ unsigned int maj, min;
+
+ node_type = drmGetNodeType(d_name);
+ if (node_type < 0)
+ return -1;
+
+ snprintf(node, PATH_MAX, "%s/%s", DRM_DIR_NAME, d_name);
+ if (stat(node, &sbuf))
+ return -1;
+
+ maj = major(sbuf.st_rdev);
+ min = minor(sbuf.st_rdev);
+
+ if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode))
+ return -1;
+
+ subsystem_type = drmParseSubsystemType(maj, min);
+ if (req_subsystem_type != -1 && req_subsystem_type != subsystem_type)
+ return -1;
+
+ switch (subsystem_type) {
+ case DRM_BUS_PCI:
+ case DRM_BUS_VIRTIO:
+ return drmProcessPciDevice(device, node, node_type, maj, min,
+ fetch_deviceinfo, flags);
+ case DRM_BUS_USB:
+ return drmProcessUsbDevice(device, node, node_type, maj, min,
+ fetch_deviceinfo, flags);
+ case DRM_BUS_PLATFORM:
+ return drmProcessPlatformDevice(device, node, node_type, maj, min,
+ fetch_deviceinfo, flags);
+ case DRM_BUS_HOST1X:
+ return drmProcessHost1xDevice(device, node, node_type, maj, min,
+ fetch_deviceinfo, flags);
+ default:
+ return -1;
+ }
+}
+
/* Consider devices located on the same bus as duplicate and fold the respective
* entries into a single one.
*
for (i = 0; i < count; i++) {
for (j = i + 1; j < count; j++) {
- if (drmCompareBusInfo(local_devices[i], local_devices[j]) == 0) {
+ if (drmDevicesEqual(local_devices[i], local_devices[j])) {
local_devices[i]->available_nodes |= local_devices[j]->available_nodes;
node_type = log2(local_devices[j]->available_nodes);
memcpy(local_devices[i]->nodes[node_type],
return (flags & ~DRM_DEVICE_GET_PCI_REVISION);
}
+static bool
+drm_device_has_rdev(drmDevicePtr device, dev_t find_rdev)
+{
+ struct stat sbuf;
+
+ for (int i = 0; i < DRM_NODE_MAX; i++) {
+ if (device->available_nodes & 1 << i) {
+ if (stat(device->nodes[i], &sbuf) == 0 &&
+ sbuf.st_rdev == find_rdev)
+ return true;
+ }
+ }
+ return false;
+}
+
+/*
+ * The kernel drm core has a number of places that assume maximum of
+ * 3x64 devices nodes. That's 64 for each of primary, control and
+ * render nodes. Rounded it up to 256 for simplicity.
+ */
+#define MAX_DRM_NODES 256
+
/**
* Get information about the opened drm device
*
return 0;
#else
- drmDevicePtr *local_devices;
+ drmDevicePtr local_devices[MAX_DRM_NODES];
drmDevicePtr d;
DIR *sysdir;
struct dirent *dent;
struct stat sbuf;
- char node[PATH_MAX + 1];
- int node_type, subsystem_type;
+ int subsystem_type;
int maj, min;
int ret, i, node_count;
- int max_count = 16;
dev_t find_rdev;
if (drm_device_validate_flags(flags))
return -EINVAL;
subsystem_type = drmParseSubsystemType(maj, min);
-
- local_devices = calloc(max_count, sizeof(drmDevicePtr));
- if (local_devices == NULL)
- return -ENOMEM;
+ if (subsystem_type < 0)
+ return subsystem_type;
sysdir = opendir(DRM_DIR_NAME);
- if (!sysdir) {
- ret = -errno;
- goto free_locals;
- }
+ if (!sysdir)
+ return -errno;
i = 0;
while ((dent = readdir(sysdir))) {
- node_type = drmGetNodeType(dent->d_name);
- if (node_type < 0)
- continue;
-
- snprintf(node, PATH_MAX, "%s/%s", DRM_DIR_NAME, dent->d_name);
- if (stat(node, &sbuf))
- continue;
-
- maj = major(sbuf.st_rdev);
- min = minor(sbuf.st_rdev);
-
- if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode))
- continue;
-
- if (drmParseSubsystemType(maj, min) != subsystem_type)
+ ret = process_device(&d, dent->d_name, subsystem_type, true, flags);
+ if (ret)
continue;
- switch (subsystem_type) {
- case DRM_BUS_PCI:
- ret = drmProcessPciDevice(&d, node, node_type, maj, min, true, flags);
- if (ret)
- continue;
-
- break;
-
- case DRM_BUS_USB:
- ret = drmProcessUsbDevice(&d, node, node_type, maj, min, true, flags);
- if (ret)
- continue;
-
+ if (i >= MAX_DRM_NODES) {
+ fprintf(stderr, "More than %d drm nodes detected. "
+ "Please report a bug - that should not happen.\n"
+ "Skipping extra nodes\n", MAX_DRM_NODES);
break;
-
- case DRM_BUS_PLATFORM:
- ret = drmProcessPlatformDevice(&d, node, node_type, maj, min, true, flags);
- if (ret)
- continue;
-
- break;
-
- case DRM_BUS_HOST1X:
- ret = drmProcessHost1xDevice(&d, node, node_type, maj, min, true, flags);
- if (ret)
- continue;
-
- break;
-
- default:
- continue;
- }
-
- if (i >= max_count) {
- drmDevicePtr *temp;
-
- max_count += 16;
- temp = realloc(local_devices, max_count * sizeof(drmDevicePtr));
- if (!temp)
- goto free_devices;
- local_devices = temp;
}
-
- /* store target at local_devices[0] for ease to use below */
- if (find_rdev == sbuf.st_rdev && i) {
- local_devices[i] = local_devices[0];
- local_devices[0] = d;
- }
- else
- local_devices[i] = d;
+ local_devices[i] = d;
i++;
}
node_count = i;
drmFoldDuplicatedDevices(local_devices, node_count);
- *device = local_devices[0];
- drmFreeDevices(&local_devices[1], node_count - 1);
+ for (i = 0; i < node_count; i++) {
+ if (!local_devices[i])
+ continue;
+
+ if (drm_device_has_rdev(local_devices[i], find_rdev))
+ *device = local_devices[i];
+ else
+ drmFreeDevice(&local_devices[i]);
+ }
closedir(sysdir);
- free(local_devices);
if (*device == NULL)
return -ENODEV;
return 0;
-
-free_devices:
- drmFreeDevices(local_devices, i);
- closedir(sysdir);
-
-free_locals:
- free(local_devices);
- return ret;
#endif
}
*/
int drmGetDevices2(uint32_t flags, drmDevicePtr devices[], int max_devices)
{
- drmDevicePtr *local_devices;
+ drmDevicePtr local_devices[MAX_DRM_NODES];
drmDevicePtr device;
DIR *sysdir;
struct dirent *dent;
- struct stat sbuf;
- char node[PATH_MAX + 1];
- int node_type, subsystem_type;
- int maj, min;
int ret, i, node_count, device_count;
- int max_count = 16;
if (drm_device_validate_flags(flags))
return -EINVAL;
- local_devices = calloc(max_count, sizeof(drmDevicePtr));
- if (local_devices == NULL)
- return -ENOMEM;
-
sysdir = opendir(DRM_DIR_NAME);
- if (!sysdir) {
- ret = -errno;
- goto free_locals;
- }
+ if (!sysdir)
+ return -errno;
i = 0;
while ((dent = readdir(sysdir))) {
- node_type = drmGetNodeType(dent->d_name);
- if (node_type < 0)
- continue;
-
- snprintf(node, PATH_MAX, "%s/%s", DRM_DIR_NAME, dent->d_name);
- if (stat(node, &sbuf))
- continue;
-
- maj = major(sbuf.st_rdev);
- min = minor(sbuf.st_rdev);
-
- if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode))
- continue;
-
- subsystem_type = drmParseSubsystemType(maj, min);
-
- if (subsystem_type < 0)
+ ret = process_device(&device, dent->d_name, -1, devices != NULL, flags);
+ if (ret)
continue;
- switch (subsystem_type) {
- case DRM_BUS_PCI:
- ret = drmProcessPciDevice(&device, node, node_type,
- maj, min, devices != NULL, flags);
- if (ret)
- continue;
-
- break;
-
- case DRM_BUS_USB:
- ret = drmProcessUsbDevice(&device, node, node_type, maj, min,
- devices != NULL, flags);
- if (ret)
- goto free_devices;
-
+ if (i >= MAX_DRM_NODES) {
+ fprintf(stderr, "More than %d drm nodes detected. "
+ "Please report a bug - that should not happen.\n"
+ "Skipping extra nodes\n", MAX_DRM_NODES);
break;
-
- case DRM_BUS_PLATFORM:
- ret = drmProcessPlatformDevice(&device, node, node_type, maj, min,
- devices != NULL, flags);
- if (ret)
- goto free_devices;
-
- break;
-
- case DRM_BUS_HOST1X:
- ret = drmProcessHost1xDevice(&device, node, node_type, maj, min,
- devices != NULL, flags);
- if (ret)
- goto free_devices;
-
- break;
-
- default:
- continue;
}
-
- if (i >= max_count) {
- drmDevicePtr *temp;
-
- max_count += 16;
- temp = realloc(local_devices, max_count * sizeof(drmDevicePtr));
- if (!temp)
- goto free_devices;
- local_devices = temp;
- }
-
local_devices[i] = device;
i++;
}
}
closedir(sysdir);
- free(local_devices);
return device_count;
-
-free_devices:
- drmFreeDevices(local_devices, i);
- closedir(sysdir);
-
-free_locals:
- free(local_devices);
- return ret;
}
/**
return strdup(node);
#endif
}
+
+int drmSyncobjCreate(int fd, uint32_t flags, uint32_t *handle)
+{
+ struct drm_syncobj_create args;
+ int ret;
+
+ memclear(args);
+ args.flags = flags;
+ args.handle = 0;
+ ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_CREATE, &args);
+ if (ret)
+ return ret;
+ *handle = args.handle;
+ return 0;
+}
+
+int drmSyncobjDestroy(int fd, uint32_t handle)
+{
+ struct drm_syncobj_destroy args;
+
+ memclear(args);
+ args.handle = handle;
+ return drmIoctl(fd, DRM_IOCTL_SYNCOBJ_DESTROY, &args);
+}
+
+int drmSyncobjHandleToFD(int fd, uint32_t handle, int *obj_fd)
+{
+ struct drm_syncobj_handle args;
+ int ret;
+
+ memclear(args);
+ args.fd = -1;
+ args.handle = handle;
+ ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD, &args);
+ if (ret)
+ return ret;
+ *obj_fd = args.fd;
+ return 0;
+}
+
+int drmSyncobjFDToHandle(int fd, int obj_fd, uint32_t *handle)
+{
+ struct drm_syncobj_handle args;
+ int ret;
+
+ memclear(args);
+ args.fd = obj_fd;
+ args.handle = 0;
+ ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE, &args);
+ if (ret)
+ return ret;
+ *handle = args.handle;
+ return 0;
+}
+
+int drmSyncobjImportSyncFile(int fd, uint32_t handle, int sync_file_fd)
+{
+ struct drm_syncobj_handle args;
+
+ memclear(args);
+ args.fd = sync_file_fd;
+ args.handle = handle;
+ args.flags = DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_IMPORT_SYNC_FILE;
+ return drmIoctl(fd, DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE, &args);
+}
+
+int drmSyncobjExportSyncFile(int fd, uint32_t handle, int *sync_file_fd)
+{
+ struct drm_syncobj_handle args;
+ int ret;
+
+ memclear(args);
+ args.fd = -1;
+ args.handle = handle;
+ args.flags = DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_EXPORT_SYNC_FILE;
+ ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD, &args);
+ if (ret)
+ return ret;
+ *sync_file_fd = args.fd;
+ return 0;
+}
+
+int drmSyncobjWait(int fd, uint32_t *handles, unsigned num_handles,
+ int64_t timeout_nsec, unsigned flags,
+ uint32_t *first_signaled)
+{
+ struct drm_syncobj_wait args;
+ int ret;
+
+ memclear(args);
+ args.handles = (uintptr_t)handles;
+ args.timeout_nsec = timeout_nsec;
+ args.count_handles = num_handles;
+ args.flags = flags;
+
+ ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_WAIT, &args);
+ if (ret < 0)
+ return -errno;
+
+ if (first_signaled)
+ *first_signaled = args.first_signaled;
+ return ret;
+}
+
+int drmSyncobjReset(int fd, const uint32_t *handles, uint32_t handle_count)
+{
+ struct drm_syncobj_array args;
+ int ret;
+
+ memclear(args);
+ args.handles = (uintptr_t)handles;
+ args.count_handles = handle_count;
+
+ ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_RESET, &args);
+ return ret;
+}
+
+int drmSyncobjSignal(int fd, const uint32_t *handles, uint32_t handle_count)
+{
+ struct drm_syncobj_array args;
+ int ret;
+
+ memclear(args);
+ args.handles = (uintptr_t)handles;
+ args.count_handles = handle_count;
+
+ ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_SIGNAL, &args);
+ return ret;
+}