@@ -4162,3 +4162,149 @@ int drm_calc_vscale(struct drm_region *src, struct drm_region *dst,
return vscale;
}
EXPORT_SYMBOL(drm_calc_vscale);
+
+int drm_mode_atomic_ioctl(struct drm_device *dev,
+ void *data, struct drm_file *file_priv)
+{
+ struct drm_mode_atomic *arg = data;
+ uint32_t __user *objs_ptr = (uint32_t __user *)(unsigned long)(arg->objs_ptr);
+ uint32_t __user *count_props_ptr = (uint32_t __user *)(unsigned long)(arg->count_props_ptr);
+ uint32_t __user *props_ptr = (uint32_t __user *)(unsigned long)(arg->props_ptr);
+ uint64_t __user *prop_values_ptr = (uint64_t __user *)(unsigned long)(arg->prop_values_ptr);
+ uint64_t __user *blob_values_ptr = (uint64_t __user *)(unsigned long)(arg->blob_values_ptr);
+ unsigned int copied_objs = 0;
+ unsigned int copied_props = 0;
+ unsigned int copied_blobs = 0;
+ void *state;
+ int ret = 0;
+ unsigned int i, j;
+
+ if (!dev->driver->atomic_funcs ||
+ !dev->driver->atomic_funcs->begin ||
+ !dev->driver->atomic_funcs->set ||
+ !dev->driver->atomic_funcs->check ||
+ !dev->driver->atomic_funcs->commit ||
+ !dev->driver->atomic_funcs->end)
+ return -ENOSYS;
+
+ if (arg->flags & ~(DRM_MODE_ATOMIC_TEST_ONLY | DRM_MODE_ATOMIC_EVENT | DRM_MODE_ATOMIC_NONBLOCK))
+ return -EINVAL;
+
+ /* can't test and expect an event at the same time. */
+ if (arg->flags & DRM_MODE_ATOMIC_TEST_ONLY && arg->flags & DRM_MODE_ATOMIC_EVENT)
+ return -EINVAL;
+
+ mutex_lock(&dev->mode_config.mutex);
+
+ state = dev->driver->atomic_funcs->begin(dev, file_priv, arg->flags, arg->user_data);
+ if (IS_ERR(state)) {
+ ret = PTR_ERR(state);
+ goto unlock;
+ }
+
+ for (i = 0; i < arg->count_objs; i++) {
+ uint32_t obj_id, count_props;
+ struct drm_mode_object *obj;
+
+ if (get_user(obj_id, objs_ptr + copied_objs)) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ obj = drm_mode_object_find(dev, obj_id, DRM_MODE_OBJECT_ANY);
+ if (!obj || !obj->properties) {
+ ret = -ENOENT;
+ goto out;
+ }
+
+ if (get_user(count_props, count_props_ptr + copied_objs)) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ copied_objs++;
+
+ for (j = 0; j < count_props; j++) {
+ uint32_t prop_id;
+ uint64_t prop_value;
+ struct drm_mode_object *prop_obj;
+ struct drm_property *prop;
+ void *blob_data = NULL;
+
+ if (get_user(prop_id, props_ptr + copied_props)) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ if (!object_has_prop(obj, prop_id)) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ prop_obj = drm_mode_object_find(dev, prop_id, DRM_MODE_OBJECT_PROPERTY);
+ if (!prop_obj) {
+ ret = -ENOENT;
+ goto out;
+ }
+ prop = obj_to_property(prop_obj);
+
+ if (get_user(prop_value, prop_values_ptr + copied_props)) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ if (!drm_property_change_is_valid(prop, prop_value)) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (prop->flags & DRM_MODE_PROP_BLOB && prop_value) {
+ uint64_t blob_ptr;
+
+ if (get_user(blob_ptr, blob_values_ptr + copied_blobs)) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ blob_data = kmalloc(prop_value, GFP_KERNEL);
+ if (!blob_data) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ if (copy_from_user(blob_data, (void __user *)(unsigned long)blob_ptr, prop_value)) {
+ kfree(blob_data);
+ ret = -EFAULT;
+ goto out;
+ }
+ }
+
+ /* User space sends the blob pointer even if we don't use it (length==0). */
+ if (prop->flags & DRM_MODE_PROP_BLOB)
+ copied_blobs++;
+
+ /* The driver will be in charge of blob_data from now on. */
+ ret = dev->driver->atomic_funcs->set(dev, state, obj, prop, prop_value, blob_data);
+ if (ret)
+ goto out;
+
+ copied_props++;
+ }
+ }
+
+ ret = dev->driver->atomic_funcs->check(dev, state);
+ if (ret)
+ goto out;
+
+ if (arg->flags & DRM_MODE_ATOMIC_TEST_ONLY)
+ goto out;
+
+ ret = dev->driver->atomic_funcs->commit(dev, state);
+
+ out:
+ dev->driver->atomic_funcs->end(dev, state);
+ unlock:
+ mutex_unlock(&dev->mode_config.mutex);
+
+ return ret;
+}
@@ -166,6 +166,7 @@ static struct drm_ioctl_desc drm_ioctls[] = {
DRM_IOCTL_DEF(DRM_IOCTL_MODE_DESTROY_DUMB, drm_mode_destroy_dumb_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_GETPROPERTIES, drm_mode_obj_get_properties_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_SETPROPERTY, drm_mode_obj_set_property_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_IOCTL_MODE_ATOMIC, drm_mode_atomic_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
};
#define DRM_CORE_IOCTL_COUNT ARRAY_SIZE( drm_ioctls )
@@ -732,6 +732,7 @@ struct drm_prime_handle {
#define DRM_IOCTL_MODE_ADDFB2 DRM_IOWR(0xB8, struct drm_mode_fb_cmd2)
#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_ATOMIC DRM_IOWR(0xBB, struct drm_mode_atomic)
/**
* Device specific ioctls should only be in their respective headers
@@ -763,6 +764,7 @@ struct drm_event {
#define DRM_EVENT_VBLANK 0x01
#define DRM_EVENT_FLIP_COMPLETE 0x02
+#define DRM_EVENT_ATOMIC_COMPLETE 0x03
struct drm_event_vblank {
struct drm_event base;
@@ -773,6 +775,16 @@ struct drm_event_vblank {
__u32 reserved;
};
+struct drm_event_atomic {
+ struct drm_event base;
+ __u64 user_data;
+ __u32 tv_sec;
+ __u32 tv_usec;
+ __u32 sequence;
+ __u32 obj_id;
+ __u32 old_fb_id;
+};
+
#define DRM_CAP_DUMB_BUFFER 0x1
#define DRM_CAP_VBLANK_HIGH_CRTC 0x2
#define DRM_CAP_DUMB_PREFERRED_DEPTH 0x3
@@ -957,6 +957,8 @@ struct drm_driver {
/* List of devices hanging off this driver */
struct list_head device_list;
+
+ const struct drm_atomic_funcs *atomic_funcs;
};
#define DRM_MINOR_UNASSIGNED 0
@@ -1050,6 +1052,12 @@ struct drm_pending_vblank_event {
struct drm_event_vblank event;
};
+struct drm_pending_atomic_event {
+ struct drm_pending_event base;
+ int pipe;
+ struct drm_event_atomic event;
+};
+
/**
* DRM device structure. This structure represent a complete card that
* may contain multiple heads.
@@ -1071,6 +1071,8 @@ extern int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);
extern int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);
+extern int drm_mode_atomic_ioctl(struct drm_device *dev,
+ void *data, struct drm_file *file_priv);
extern void drm_fb_get_bpp_depth(uint32_t format, unsigned int *depth,
int *bpp);
@@ -1111,4 +1113,15 @@ extern int drm_calc_hscale(struct drm_region *src, struct drm_region *dst,
extern int drm_calc_vscale(struct drm_region *src, struct drm_region *dst,
int min_vscale, int max_vscale);
+struct drm_atomic_funcs {
+ void *(*begin)(struct drm_device *dev, struct drm_file *file,
+ uint32_t flags, uint64_t user_data);
+ int (*set)(struct drm_device *dev, void *state,
+ struct drm_mode_object *obj, struct drm_property *prop,
+ uint64_t value, void *blob_data);
+ int (*check)(struct drm_device *dev, void *state);
+ int (*commit)(struct drm_device *dev, void *state);
+ void (*end)(struct drm_device *dev, void *state);
+};
+
#endif /* __DRM_CRTC_H__ */
@@ -459,4 +459,20 @@ struct drm_mode_destroy_dumb {
uint32_t handle;
};
+#define DRM_MODE_ATOMIC_TEST_ONLY (1<<0)
+#define DRM_MODE_ATOMIC_EVENT (1<<1)
+#define DRM_MODE_ATOMIC_NONBLOCK (1<<2)
+
+/* 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