blob: 6a2fa4a050a3fba55f79b5d2815ecbec0d9d20d1 [file] [log] [blame]
From dea4ead559635bf2408d43ab558d13a79f42413f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com>
Date: Fri, 18 May 2012 15:52:09 +0300
Subject: [PATCH 7/9] libdrm: atomic mode set
---
include/drm/drm.h | 1 +
include/drm/drm_mode.h | 22 ++++
xf86drmMode.c | 273 +++++++++++++++++++++++++++++++++++++++++++++++++
xf86drmMode.h | 20 ++++
4 files changed, 316 insertions(+)
diff --git a/include/drm/drm.h b/include/drm/drm.h
index 229a29f..768b7db 100644
--- a/include/drm/drm.h
+++ b/include/drm/drm.h
@@ -758,6 +758,7 @@ struct drm_prime_handle {
#define DRM_IOCTL_MODE_OBJ_GETPROPERTIES DRM_IOWR(0xB9, struct drm_mode_obj_get_properties)
#define DRM_IOCTL_MODE_OBJ_SETPROPERTY DRM_IOWR(0xBA, struct drm_mode_obj_set_property)
#define DRM_IOCTL_MODE_CURSOR2 DRM_IOWR(0xBB, struct drm_mode_cursor2)
+#define DRM_IOCTL_MODE_ATOMIC DRM_IOWR(0xBC, struct drm_mode_atomic)
/**
* Device specific ioctls should only be in their respective headers
diff --git a/include/drm/drm_mode.h b/include/drm/drm_mode.h
index a2ab88a..1c3f620 100644
--- a/include/drm/drm_mode.h
+++ b/include/drm/drm_mode.h
@@ -507,4 +507,26 @@ struct drm_mode_destroy_dumb {
__u32 handle;
};
+/* page-flip flags are valid, plus: */
+#define DRM_MODE_ATOMIC_TEST_ONLY 0x0100
+#define DRM_MODE_ATOMIC_NONBLOCK 0x0200
+
+#define DRM_MODE_ATOMIC_FLAGS (\
+ DRM_MODE_PAGE_FLIP_EVENT |\
+ DRM_MODE_PAGE_FLIP_ASYNC |\
+ DRM_MODE_ATOMIC_TEST_ONLY |\
+ DRM_MODE_ATOMIC_NONBLOCK)
+
+/* FIXME come up with some sane error reporting mechanism? */
+struct drm_mode_atomic {
+ __u32 flags;
+ __u32 count_objs;
+ __u64 objs_ptr;
+ __u64 count_props_ptr;
+ __u64 props_ptr;
+ __u64 prop_values_ptr;
+ __u64 blob_values_ptr;
+ __u64 user_data;
+};
+
#endif
diff --git a/xf86drmMode.c b/xf86drmMode.c
index 1333da4..0485113 100644
--- a/xf86drmMode.c
+++ b/xf86drmMode.c
@@ -40,6 +40,7 @@
#include <stdint.h>
#include <sys/ioctl.h>
#include <stdio.h>
+#include <stdbool.h>
#ifdef HAVE_CONFIG_H
#include "config.h"
@@ -1147,3 +1148,275 @@ int drmModeObjectSetProperty(int fd, uint32_t object_id, uint32_t object_type,
return DRM_IOCTL(fd, DRM_IOCTL_MODE_OBJ_SETPROPERTY, &prop);
}
+
+typedef struct _drmModePropertySetItem drmModePropertySetItem, *drmModePropertySetItemPtr;
+
+struct _drmModePropertySetItem {
+ uint32_t object_id;
+ uint32_t property_id;
+ bool is_blob;
+ uint64_t value;
+ void *blob;
+ drmModePropertySetItemPtr next;
+};
+
+struct _drmModePropertySet {
+ unsigned int count_objs;
+ unsigned int count_props;
+ unsigned int count_blobs;
+ drmModePropertySetItem list;
+};
+
+drmModePropertySetPtr drmModePropertySetAlloc(void)
+{
+ drmModePropertySetPtr set;
+
+ set = drmMalloc(sizeof *set);
+ if (!set)
+ return NULL;
+
+ set->list.next = NULL;
+ set->count_props = 0;
+ set->count_objs = 0;
+
+ return set;
+}
+
+int drmModePropertySetAdd(drmModePropertySetPtr set,
+ uint32_t object_id,
+ uint32_t property_id,
+ uint64_t value)
+{
+ drmModePropertySetItemPtr prev = &set->list;
+ bool new_obj = false;
+
+ /* keep it sorted by object_id and property_id */
+ while (prev->next) {
+ if (prev->next->object_id > object_id) {
+ new_obj = true;
+ break;
+ }
+
+ if (prev->next->object_id == object_id &&
+ prev->next->property_id >= property_id)
+ break;
+
+ prev = prev->next;
+ }
+
+ if (!prev->next &&
+ (prev == &set->list || prev->object_id != object_id))
+ new_obj = true;
+
+ /* replace or add? */
+ if (prev->next &&
+ prev->next->object_id == object_id &&
+ prev->next->property_id == property_id) {
+ drmModePropertySetItemPtr item = prev->next;
+
+ if (item->is_blob)
+ return -EINVAL;
+
+ item->value = value;
+ } else {
+ drmModePropertySetItemPtr item;
+
+ item = drmMalloc(sizeof *item);
+ if (!item)
+ return -1;
+
+ item->object_id = object_id;
+ item->property_id = property_id;
+ item->value = value;
+ item->is_blob = false;
+ item->blob = NULL;
+
+ item->next = prev->next;
+ prev->next = item;
+
+ set->count_props++;
+ }
+
+ if (new_obj)
+ set->count_objs++;
+
+ return 0;
+}
+
+int drmModePropertySetAddBlob(drmModePropertySetPtr set,
+ uint32_t object_id,
+ uint32_t property_id,
+ uint64_t length,
+ void *data)
+{
+ drmModePropertySetItemPtr prev = &set->list;
+ bool new_obj = false;
+
+ /* keep it sorted by object_id and property_id */
+ while (prev->next) {
+ if (prev->next->object_id > object_id) {
+ new_obj = true;
+ break;
+ }
+
+ if (prev->next->object_id == object_id &&
+ prev->next->property_id >= property_id)
+ break;
+
+ prev = prev->next;
+ }
+
+ if (!prev->next &&
+ (prev == &set->list || prev->object_id != object_id))
+ new_obj = true;
+
+ /* replace or add? */
+ if (prev->next &&
+ prev->next->object_id == object_id &&
+ prev->next->property_id == property_id) {
+ drmModePropertySetItemPtr item = prev->next;
+
+ if (!item->is_blob)
+ return -EINVAL;
+
+ item->value = length;
+ item->blob = data;
+ } else {
+ drmModePropertySetItemPtr item;
+
+ item = drmMalloc(sizeof *item);
+ if (!item)
+ return -1;
+
+ item->object_id = object_id;
+ item->property_id = property_id;
+ item->is_blob = true;
+ item->value = length;
+ item->blob = data;
+
+ item->next = prev->next;
+ prev->next = item;
+
+ set->count_props++;
+ set->count_blobs++;
+ }
+
+ if (new_obj)
+ set->count_objs++;
+
+ return 0;
+}
+
+void drmModePropertySetFree(drmModePropertySetPtr set)
+{
+ drmModePropertySetItemPtr item;
+
+ if (!set)
+ return;
+
+ item = set->list.next;
+
+ while (item) {
+ drmModePropertySetItemPtr next = item->next;
+
+ drmFree(item);
+
+ item = next;
+ }
+
+ drmFree(set);
+}
+
+int drmModePropertySetCommit(int fd, uint32_t flags, void *user_data,
+ drmModePropertySetPtr set)
+{
+ drmModePropertySetItemPtr item;
+ uint32_t *objs_ptr = NULL;
+ uint32_t *count_props_ptr = NULL;
+ uint32_t *props_ptr = NULL;
+ uint64_t *prop_values_ptr = NULL;
+ uint64_t *blob_values_ptr = NULL;
+ struct drm_mode_atomic atomic = { 0 };
+ unsigned int obj_idx = 0;
+ unsigned int prop_idx = 0;
+ unsigned int blob_idx = 0;
+ int ret = -1;
+
+ if (!set)
+ return -1;
+
+ objs_ptr = drmMalloc(set->count_objs * sizeof objs_ptr[0]);
+ if (!objs_ptr) {
+ errno = ENOMEM;
+ goto out;
+ }
+
+ count_props_ptr = drmMalloc(set->count_objs * sizeof count_props_ptr[0]);
+ if (!count_props_ptr) {
+ errno = ENOMEM;
+ goto out;
+ }
+
+ props_ptr = drmMalloc(set->count_props * sizeof props_ptr[0]);
+ if (!props_ptr) {
+ errno = ENOMEM;
+ goto out;
+ }
+
+ prop_values_ptr = drmMalloc(set->count_props * sizeof prop_values_ptr[0]);
+ if (!prop_values_ptr) {
+ errno = ENOMEM;
+ goto out;
+ }
+
+ blob_values_ptr = drmMalloc(set->count_blobs * sizeof blob_values_ptr[0]);
+ if (!blob_values_ptr) {
+ errno = ENOMEM;
+ goto out;
+ }
+
+ item = set->list.next;
+
+ while (item) {
+ int count_props = 0;
+ drmModePropertySetItemPtr next = item;
+
+ objs_ptr[obj_idx] = item->object_id;
+
+ while (next && next->object_id == item->object_id) {
+ props_ptr[prop_idx] = next->property_id;
+ prop_values_ptr[prop_idx] = next->value;
+ prop_idx++;
+
+ if (next->is_blob)
+ blob_values_ptr[blob_idx++] = VOID2U64(next->blob);
+
+ count_props++;
+
+ next = next->next;
+ }
+
+ count_props_ptr[obj_idx++] = count_props;
+
+ item = next;
+ }
+
+ atomic.count_objs = set->count_objs;
+ atomic.flags = flags;
+ atomic.objs_ptr = VOID2U64(objs_ptr);
+ atomic.count_props_ptr = VOID2U64(count_props_ptr);
+ atomic.props_ptr = VOID2U64(props_ptr);
+ atomic.prop_values_ptr = VOID2U64(prop_values_ptr);
+ atomic.blob_values_ptr = VOID2U64(blob_values_ptr);
+ atomic.user_data = VOID2U64(user_data);
+
+ ret = DRM_IOCTL(fd, DRM_IOCTL_MODE_ATOMIC, &atomic);
+
+out:
+ drmFree(objs_ptr);
+ drmFree(count_props_ptr);
+ drmFree(props_ptr);
+ drmFree(prop_values_ptr);
+
+ return ret;
+}
diff --git a/xf86drmMode.h b/xf86drmMode.h
index 20c3f15..003e158 100644
--- a/xf86drmMode.h
+++ b/xf86drmMode.h
@@ -484,6 +484,26 @@ extern int drmModeObjectSetProperty(int fd, uint32_t object_id,
uint32_t object_type, uint32_t property_id,
uint64_t value);
+
+typedef struct _drmModePropertySet drmModePropertySet, *drmModePropertySetPtr;
+
+extern drmModePropertySetPtr drmModePropertySetAlloc(void);
+
+extern int drmModePropertySetAdd(drmModePropertySetPtr set,
+ uint32_t object_id,
+ uint32_t property_id,
+ uint64_t value);
+extern int drmModePropertySetAddBlob(drmModePropertySetPtr set,
+ uint32_t object_id,
+ uint32_t property_id,
+ uint64_t length,
+ void *blob);
+
+extern int drmModePropertySetCommit(int fd, uint32_t flags,
+ void *user_data, drmModePropertySetPtr set);
+
+extern void drmModePropertySetFree(drmModePropertySetPtr set);
+
#if defined(__cplusplus) || defined(c_plusplus)
}
#endif
--
2.3.1