#endif
#include <math.h>
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+
/* Not all systems have MAP_FAILED defined */
#ifndef MAP_FAILED
#define MAP_FAILED ((void *)-1)
#include "util_math.h"
-#ifdef __OpenBSD__
-#define DRM_PRIMARY_MINOR_NAME "drm"
-#define DRM_CONTROL_MINOR_NAME "drmC"
-#define DRM_RENDER_MINOR_NAME "drmR"
-#else
-#define DRM_PRIMARY_MINOR_NAME "card"
-#define DRM_CONTROL_MINOR_NAME "controlD"
-#define DRM_RENDER_MINOR_NAME "renderD"
-#endif
-
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
#define DRM_MAJOR 145
#endif
#define DRM_MAJOR 226 /* Linux */
#endif
-#ifdef __OpenBSD__
+#if defined(__OpenBSD__) || defined(__DragonFly__)
struct drm_pciinfo {
uint16_t domain;
uint8_t bus;
}
/**
- * Call ioctl, restarting if it is interupted
+ * Call ioctl, restarting if it is interrupted
*/
drm_public int
drmIoctl(int fd, unsigned long request, void *arg)
*
* \internal
* Checks for failure. If failure was caused by signal call chown again.
- * If any other failure happened then it will output error mesage using
+ * If any other failure happened then it will output error message using
* drmMsg() call.
*/
#if !UDEV
}
#endif
+static const char *drmGetDeviceName(int type)
+{
+ switch (type) {
+ case DRM_NODE_PRIMARY:
+ return DRM_DEV_NAME;
+ case DRM_NODE_CONTROL:
+ return DRM_CONTROL_DEV_NAME;
+ case DRM_NODE_RENDER:
+ return DRM_RENDER_DEV_NAME;
+ }
+ return NULL;
+}
+
/**
* Open the DRM device, creating it if necessary.
*
static int drmOpenDevice(dev_t dev, int minor, int type)
{
stat_t st;
- const char *dev_name;
- char buf[64];
+ const char *dev_name = drmGetDeviceName(type);
+ char buf[DRM_NODE_NAME_MAX];
int fd;
mode_t devmode = DRM_DEV_MODE, serv_mode;
gid_t serv_group;
gid_t group = DRM_DEV_GID;
#endif
- switch (type) {
- case DRM_NODE_PRIMARY:
- dev_name = DRM_DEV_NAME;
- break;
- case DRM_NODE_CONTROL:
- dev_name = DRM_CONTROL_DEV_NAME;
- break;
- case DRM_NODE_RENDER:
- dev_name = DRM_RENDER_DEV_NAME;
- break;
- default:
+ if (!dev_name)
return -EINVAL;
- };
sprintf(buf, dev_name, DRM_DIR_NAME, minor);
drmMsg("drmOpenDevice: node name is %s\n", buf);
static int drmOpenMinor(int minor, int create, int type)
{
int fd;
- char buf[64];
- const char *dev_name;
+ char buf[DRM_NODE_NAME_MAX];
+ const char *dev_name = drmGetDeviceName(type);
if (create)
return drmOpenDevice(makedev(DRM_MAJOR, minor), minor, type);
- switch (type) {
- case DRM_NODE_PRIMARY:
- dev_name = DRM_DEV_NAME;
- break;
- case DRM_NODE_CONTROL:
- dev_name = DRM_CONTROL_DEV_NAME;
- break;
- case DRM_NODE_RENDER:
- dev_name = DRM_RENDER_DEV_NAME;
- break;
- default:
+ if (!dev_name)
return -EINVAL;
- };
sprintf(buf, dev_name, DRM_DIR_NAME, minor);
if ((fd = open(buf, O_RDWR | O_CLOEXEC, 0)) >= 0)
*/
drm_public int drmOpenWithType(const char *name, const char *busid, int type)
{
- if (!drmAvailable() && name != NULL && drm_server_info &&
- drm_server_info->load_module) {
+ if (name != NULL && drm_server_info &&
+ drm_server_info->load_module && !drmAvailable()) {
/* try to load the kernel module */
if (!drm_server_info->load_module(name)) {
drmMsg("[drm] failed to load kernel module \"%s\"\n", name);
*
* \param fd file descriptor.
* \param context context.
- * \param flags flags that determine the sate of the hardware when the function
+ * \param flags flags that determine the state of the hardware when the function
* returns.
*
* \return always zero.
return drmIoctl(fd, DRM_IOCTL_DROP_MASTER, NULL);
}
+drm_public int drmIsMaster(int fd)
+{
+ /* Detect master by attempting something that requires master.
+ *
+ * Authenticating magic tokens requires master and 0 is an
+ * internal kernel detail which we could use. Attempting this on
+ * a master fd would fail therefore fail with EINVAL because 0
+ * is invalid.
+ *
+ * A non-master fd will fail with EACCES, as the kernel checks
+ * for master before attempting to do anything else.
+ *
+ * Since we don't want to leak implementation details, use
+ * EACCES.
+ */
+ return drmAuthMagic(fd, 0) != -EACCES;
+}
+
drm_public char *drmGetDeviceNameFromFd(int fd)
{
char name[128];
return strdup(name);
}
+static bool drmNodeIsDRM(int maj, int min)
+{
+#ifdef __linux__
+ char path[64];
+ struct stat sbuf;
+
+ snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device/drm",
+ maj, min);
+ return stat(path, &sbuf) == 0;
+#else
+ return maj == DRM_MAJOR;
+#endif
+}
+
drm_public int drmGetNodeTypeFromFd(int fd)
{
struct stat sbuf;
maj = major(sbuf.st_rdev);
min = minor(sbuf.st_rdev);
- if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode)) {
+ if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode)) {
errno = EINVAL;
return -1;
}
maj = major(sbuf.st_rdev);
min = minor(sbuf.st_rdev);
- if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode))
+ if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode))
return NULL;
snprintf(buf, sizeof(buf), "/sys/dev/char/%d:%d/device/drm", maj, min);
#else
struct stat sbuf;
char buf[PATH_MAX + 1];
- const char *dev_name;
+ const char *dev_name = drmGetDeviceName(type);
unsigned int maj, min;
- int n, base;
+ int n;
if (fstat(fd, &sbuf))
return NULL;
maj = major(sbuf.st_rdev);
min = minor(sbuf.st_rdev);
- if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode))
+ if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode))
return NULL;
- switch (type) {
- case DRM_NODE_PRIMARY:
- dev_name = DRM_DEV_NAME;
- break;
- case DRM_NODE_CONTROL:
- dev_name = DRM_CONTROL_DEV_NAME;
- break;
- case DRM_NODE_RENDER:
- dev_name = DRM_RENDER_DEV_NAME;
- break;
- default:
+ if (!dev_name)
return NULL;
- };
- base = drmGetMinorBase(type);
- if (base < 0)
- return NULL;
-
- n = snprintf(buf, sizeof(buf), dev_name, DRM_DIR_NAME, min - base);
+ n = snprintf(buf, sizeof(buf), dev_name, DRM_DIR_NAME, min);
if (n == -1 || n >= sizeof(buf))
return NULL;
char path[PATH_MAX + 1];
char link[PATH_MAX + 1] = "";
char *name;
+ struct {
+ const char *name;
+ int bus_type;
+ } bus_types[] = {
+ { "/pci", DRM_BUS_PCI },
+ { "/usb", DRM_BUS_USB },
+ { "/platform", DRM_BUS_PLATFORM },
+ { "/spi", DRM_BUS_PLATFORM },
+ { "/host1x", DRM_BUS_HOST1X },
+ { "/virtio", DRM_BUS_VIRTIO },
+ };
snprintf(path, PATH_MAX, "/sys/dev/char/%d:%d/device/subsystem",
maj, min);
if (!name)
return -EINVAL;
- if (strncmp(name, "/pci", 4) == 0)
- return DRM_BUS_PCI;
-
- if (strncmp(name, "/usb", 4) == 0)
- return DRM_BUS_USB;
-
- if (strncmp(name, "/platform", 9) == 0)
- return DRM_BUS_PLATFORM;
-
- if (strncmp(name, "/host1x", 7) == 0)
- return DRM_BUS_HOST1X;
-
- if (strncmp(name, "/virtio", 7) == 0)
- return DRM_BUS_VIRTIO;
+ for (unsigned i = 0; i < ARRAY_SIZE(bus_types); i++) {
+ if (strncmp(name, bus_types[i].name, strlen(bus_types[i].name)) == 0)
+ return bus_types[i].bus_type;
+ }
return -EINVAL;
-#elif defined(__OpenBSD__)
+#elif defined(__OpenBSD__) || defined(__DragonFly__)
return DRM_BUS_PCI;
#else
#warning "Missing implementation of drmParseSubsystemType"
info->func = func;
return 0;
-#elif defined(__OpenBSD__)
+#elif defined(__OpenBSD__) || defined(__DragonFly__)
struct drm_pciinfo pinfo;
int fd, type;
static int drmGetNodeType(const char *name)
{
- if (strncmp(name, DRM_PRIMARY_MINOR_NAME,
- sizeof(DRM_PRIMARY_MINOR_NAME) - 1) == 0)
- return DRM_NODE_PRIMARY;
-
if (strncmp(name, DRM_CONTROL_MINOR_NAME,
sizeof(DRM_CONTROL_MINOR_NAME ) - 1) == 0)
return DRM_NODE_CONTROL;
sizeof(DRM_RENDER_MINOR_NAME) - 1) == 0)
return DRM_NODE_RENDER;
+ if (strncmp(name, DRM_PRIMARY_MINOR_NAME,
+ sizeof(DRM_PRIMARY_MINOR_NAME) - 1) == 0)
+ return DRM_NODE_PRIMARY;
+
return -EINVAL;
}
drmPciDeviceInfoPtr device,
bool ignore_revision)
{
-#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
static const char *attrs[] = {
"revision", /* Older kernels are missing the file, so check for it first */
"vendor",
return parse_config_sysfs_file(maj, min, device);
return 0;
-#elif defined(__OpenBSD__)
+#elif defined(__OpenBSD__) || defined(__DragonFly__)
struct drm_pciinfo pinfo;
int fd, type;
return ret;
}
-static int drmParsePlatformBusInfo(int maj, int min, drmPlatformBusInfoPtr info)
+static int drmParseOFBusInfo(int maj, int min, char *fullname)
{
#ifdef __linux__
- char path[PATH_MAX + 1], *name;
+ char path[PATH_MAX + 1], *name, *tmp_name;
snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min);
name = sysfs_uevent_get(path, "OF_FULLNAME");
- if (!name)
- return -ENOENT;
+ tmp_name = name;
+ if (!name) {
+ /* If the device lacks OF data, pick the MODALIAS info */
+ name = sysfs_uevent_get(path, "MODALIAS");
+ if (!name)
+ return -ENOENT;
+
+ /* .. and strip the MODALIAS=[platform,usb...]: part. */
+ tmp_name = strrchr(name, ':');
+ if (!tmp_name) {
+ free(name);
+ return -ENOENT;
+ }
+ tmp_name++;
+ }
- strncpy(info->fullname, name, DRM_PLATFORM_DEVICE_NAME_LEN);
- info->fullname[DRM_PLATFORM_DEVICE_NAME_LEN - 1] = '\0';
+ strncpy(fullname, tmp_name, DRM_PLATFORM_DEVICE_NAME_LEN);
+ fullname[DRM_PLATFORM_DEVICE_NAME_LEN - 1] = '\0';
free(name);
return 0;
#else
-#warning "Missing implementation of drmParsePlatformBusInfo"
+#warning "Missing implementation of drmParseOFBusInfo"
return -EINVAL;
#endif
}
-static int drmParsePlatformDeviceInfo(int maj, int min,
- drmPlatformDeviceInfoPtr info)
+static int drmParseOFDeviceInfo(int maj, int min, char ***compatible)
{
#ifdef __linux__
- char path[PATH_MAX + 1], *value;
+ char path[PATH_MAX + 1], *value, *tmp_name;
unsigned int count, i;
int err;
snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min);
value = sysfs_uevent_get(path, "OF_COMPATIBLE_N");
- if (!value)
- return -ENOENT;
-
- sscanf(value, "%u", &count);
- free(value);
+ if (value) {
+ sscanf(value, "%u", &count);
+ free(value);
+ } else {
+ /* Assume one entry if the device lack OF data */
+ count = 1;
+ }
- info->compatible = calloc(count + 1, sizeof(*info->compatible));
- if (!info->compatible)
+ *compatible = calloc(count + 1, sizeof(char *));
+ if (!*compatible)
return -ENOMEM;
for (i = 0; i < count; i++) {
value = sysfs_uevent_get(path, "OF_COMPATIBLE_%u", i);
+ tmp_name = value;
if (!value) {
- err = -ENOENT;
- goto free;
+ /* If the device lacks OF data, pick the MODALIAS info */
+ value = sysfs_uevent_get(path, "MODALIAS");
+ if (!value) {
+ err = -ENOENT;
+ goto free;
+ }
+
+ /* .. and strip the MODALIAS=[platform,usb...]: part. */
+ tmp_name = strrchr(value, ':');
+ if (!tmp_name) {
+ free(value);
+ return -ENOENT;
+ }
+ tmp_name = strdup(tmp_name + 1);
+ free(value);
}
- info->compatible[i] = value;
+ (*compatible)[i] = tmp_name;
}
return 0;
free:
while (i--)
- free(info->compatible[i]);
+ free((*compatible)[i]);
- free(info->compatible);
+ free(*compatible);
return err;
#else
-#warning "Missing implementation of drmParsePlatformDeviceInfo"
+#warning "Missing implementation of drmParseOFDeviceInfo"
return -EINVAL;
#endif
}
dev->businfo.platform = (drmPlatformBusInfoPtr)ptr;
- ret = drmParsePlatformBusInfo(maj, min, dev->businfo.platform);
+ ret = drmParseOFBusInfo(maj, min, dev->businfo.platform->fullname);
if (ret < 0)
goto free_device;
ptr += sizeof(drmPlatformBusInfo);
dev->deviceinfo.platform = (drmPlatformDeviceInfoPtr)ptr;
- ret = drmParsePlatformDeviceInfo(maj, min, dev->deviceinfo.platform);
+ ret = drmParseOFDeviceInfo(maj, min, &dev->deviceinfo.platform->compatible);
if (ret < 0)
goto free_device;
}
return ret;
}
-static int drmParseHost1xBusInfo(int maj, int min, drmHost1xBusInfoPtr info)
-{
-#ifdef __linux__
- char path[PATH_MAX + 1], *name;
-
- snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min);
-
- name = sysfs_uevent_get(path, "OF_FULLNAME");
- if (!name)
- return -ENOENT;
-
- strncpy(info->fullname, name, DRM_HOST1X_DEVICE_NAME_LEN);
- info->fullname[DRM_HOST1X_DEVICE_NAME_LEN - 1] = '\0';
- free(name);
-
- return 0;
-#else
-#warning "Missing implementation of drmParseHost1xBusInfo"
- return -EINVAL;
-#endif
-}
-
-static int drmParseHost1xDeviceInfo(int maj, int min,
- drmHost1xDeviceInfoPtr info)
-{
-#ifdef __linux__
- char path[PATH_MAX + 1], *value;
- unsigned int count, i;
- int err;
-
- snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min);
-
- value = sysfs_uevent_get(path, "OF_COMPATIBLE_N");
- if (!value)
- return -ENOENT;
-
- sscanf(value, "%u", &count);
- free(value);
-
- info->compatible = calloc(count + 1, sizeof(*info->compatible));
- if (!info->compatible)
- return -ENOMEM;
-
- for (i = 0; i < count; i++) {
- value = sysfs_uevent_get(path, "OF_COMPATIBLE_%u", i);
- if (!value) {
- err = -ENOENT;
- goto free;
- }
-
- info->compatible[i] = value;
- }
-
- return 0;
-
-free:
- while (i--)
- free(info->compatible[i]);
-
- free(info->compatible);
- return err;
-#else
-#warning "Missing implementation of drmParseHost1xDeviceInfo"
- return -EINVAL;
-#endif
-}
-
static int drmProcessHost1xDevice(drmDevicePtr *device,
const char *node, int node_type,
int maj, int min, bool fetch_deviceinfo,
dev->businfo.host1x = (drmHost1xBusInfoPtr)ptr;
- ret = drmParseHost1xBusInfo(maj, min, dev->businfo.host1x);
+ ret = drmParseOFBusInfo(maj, min, dev->businfo.host1x->fullname);
if (ret < 0)
goto free_device;
ptr += sizeof(drmHost1xBusInfo);
dev->deviceinfo.host1x = (drmHost1xDeviceInfoPtr)ptr;
- ret = drmParseHost1xDeviceInfo(maj, min, dev->deviceinfo.host1x);
+ ret = drmParseOFDeviceInfo(maj, min, &dev->deviceinfo.host1x->compatible);
if (ret < 0)
goto free_device;
}
maj = major(sbuf.st_rdev);
min = minor(sbuf.st_rdev);
- if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode))
+ if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode))
return -1;
subsystem_type = drmParseSubsystemType(maj, min);
char node[PATH_MAX + 1];
const char *dev_name;
int node_type, subsystem_type;
- int maj, min, n, ret, base;
+ int maj, min, n, ret;
if (fd == -1 || device == NULL)
return -EINVAL;
maj = major(sbuf.st_rdev);
min = minor(sbuf.st_rdev);
- if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode))
+ if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode))
return -EINVAL;
node_type = drmGetMinorType(min);
if (node_type == -1)
return -ENODEV;
- switch (node_type) {
- case DRM_NODE_PRIMARY:
- dev_name = DRM_DEV_NAME;
- break;
- case DRM_NODE_CONTROL:
- dev_name = DRM_CONTROL_DEV_NAME;
- break;
- case DRM_NODE_RENDER:
- dev_name = DRM_RENDER_DEV_NAME;
- break;
- default:
- return -EINVAL;
- };
-
- base = drmGetMinorBase(node_type);
- if (base < 0)
+ dev_name = drmGetDeviceName(node_type);
+ if (!dev_name)
return -EINVAL;
- n = snprintf(node, PATH_MAX, dev_name, DRM_DIR_NAME, min - base);
+ n = snprintf(node, PATH_MAX, dev_name, DRM_DIR_NAME, min);
if (n == -1 || n >= PATH_MAX)
return -errno;
if (stat(node, &sbuf))
maj = major(sbuf.st_rdev);
min = minor(sbuf.st_rdev);
- if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode))
+ if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode))
return -EINVAL;
subsystem_type = drmParseSubsystemType(maj, min);
maj = major(sbuf.st_rdev);
min = minor(sbuf.st_rdev);
- if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode))
+ if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode))
return NULL;
snprintf(path, sizeof(path), "/sys/dev/char/%d:%d", maj, min);
char node[PATH_MAX + 1];
const char *dev_name;
int node_type;
- int maj, min, n, base;
+ int maj, min, n;
if (fstat(fd, &sbuf))
return NULL;
maj = major(sbuf.st_rdev);
min = minor(sbuf.st_rdev);
- if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode))
+ if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode))
return NULL;
node_type = drmGetMinorType(min);
if (node_type == -1)
return NULL;
- switch (node_type) {
- case DRM_NODE_PRIMARY:
- dev_name = DRM_DEV_NAME;
- break;
- case DRM_NODE_CONTROL:
- dev_name = DRM_CONTROL_DEV_NAME;
- break;
- case DRM_NODE_RENDER:
- dev_name = DRM_RENDER_DEV_NAME;
- break;
- default:
+ dev_name = drmGetDeviceName(node_type);
+ if (!dev_name)
return NULL;
- };
- base = drmGetMinorBase(node_type);
- if (base < 0)
- return NULL;
-
- n = snprintf(node, PATH_MAX, dev_name, DRM_DIR_NAME, min - base);
+ n = snprintf(node, PATH_MAX, dev_name, DRM_DIR_NAME, min);
if (n == -1 || n >= PATH_MAX)
return NULL;
ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_SIGNAL, &args);
return ret;
}
+
+drm_public int drmSyncobjTimelineSignal(int fd, const uint32_t *handles,
+ uint64_t *points, uint32_t handle_count)
+{
+ struct drm_syncobj_timeline_array args;
+ int ret;
+
+ memclear(args);
+ args.handles = (uintptr_t)handles;
+ args.points = (uintptr_t)points;
+ args.count_handles = handle_count;
+
+ ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_TIMELINE_SIGNAL, &args);
+ return ret;
+}
+
+drm_public int drmSyncobjTimelineWait(int fd, uint32_t *handles, uint64_t *points,
+ unsigned num_handles,
+ int64_t timeout_nsec, unsigned flags,
+ uint32_t *first_signaled)
+{
+ struct drm_syncobj_timeline_wait args;
+ int ret;
+
+ memclear(args);
+ args.handles = (uintptr_t)handles;
+ args.points = (uintptr_t)points;
+ args.timeout_nsec = timeout_nsec;
+ args.count_handles = num_handles;
+ args.flags = flags;
+
+ ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_TIMELINE_WAIT, &args);
+ if (ret < 0)
+ return -errno;
+
+ if (first_signaled)
+ *first_signaled = args.first_signaled;
+ return ret;
+}
+
+
+drm_public int drmSyncobjQuery(int fd, uint32_t *handles, uint64_t *points,
+ uint32_t handle_count)
+{
+ struct drm_syncobj_timeline_array args;
+ int ret;
+
+ memclear(args);
+ args.handles = (uintptr_t)handles;
+ args.points = (uintptr_t)points;
+ args.count_handles = handle_count;
+
+ ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_QUERY, &args);
+ if (ret)
+ return ret;
+ return 0;
+}
+
+drm_public int drmSyncobjQuery2(int fd, uint32_t *handles, uint64_t *points,
+ uint32_t handle_count, uint32_t flags)
+{
+ struct drm_syncobj_timeline_array args;
+
+ memclear(args);
+ args.handles = (uintptr_t)handles;
+ args.points = (uintptr_t)points;
+ args.count_handles = handle_count;
+ args.flags = flags;
+
+ return drmIoctl(fd, DRM_IOCTL_SYNCOBJ_QUERY, &args);
+}
+
+
+drm_public int drmSyncobjTransfer(int fd,
+ uint32_t dst_handle, uint64_t dst_point,
+ uint32_t src_handle, uint64_t src_point,
+ uint32_t flags)
+{
+ struct drm_syncobj_transfer args;
+ int ret;
+
+ memclear(args);
+ args.src_handle = src_handle;
+ args.dst_handle = dst_handle;
+ args.src_point = src_point;
+ args.dst_point = dst_point;
+ args.flags = flags;
+
+ ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_TRANSFER, &args);
+
+ return ret;
+}