xref: /linux/drivers/gpu/drm/drm_mode_object.c (revision 2c935bc57221cc2edc787c72ea0e2d30cdcd3d5e)
1949619f3SDaniel Vetter /*
2949619f3SDaniel Vetter  * Copyright (c) 2016 Intel Corporation
3949619f3SDaniel Vetter  *
4949619f3SDaniel Vetter  * Permission to use, copy, modify, distribute, and sell this software and its
5949619f3SDaniel Vetter  * documentation for any purpose is hereby granted without fee, provided that
6949619f3SDaniel Vetter  * the above copyright notice appear in all copies and that both that copyright
7949619f3SDaniel Vetter  * notice and this permission notice appear in supporting documentation, and
8949619f3SDaniel Vetter  * that the name of the copyright holders not be used in advertising or
9949619f3SDaniel Vetter  * publicity pertaining to distribution of the software without specific,
10949619f3SDaniel Vetter  * written prior permission.  The copyright holders make no representations
11949619f3SDaniel Vetter  * about the suitability of this software for any purpose.  It is provided "as
12949619f3SDaniel Vetter  * is" without express or implied warranty.
13949619f3SDaniel Vetter  *
14949619f3SDaniel Vetter  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15949619f3SDaniel Vetter  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16949619f3SDaniel Vetter  * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17949619f3SDaniel Vetter  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18949619f3SDaniel Vetter  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19949619f3SDaniel Vetter  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
20949619f3SDaniel Vetter  * OF THIS SOFTWARE.
21949619f3SDaniel Vetter  */
22949619f3SDaniel Vetter 
23949619f3SDaniel Vetter #include <linux/export.h>
24949619f3SDaniel Vetter #include <drm/drmP.h>
25949619f3SDaniel Vetter #include <drm/drm_mode_object.h>
26949619f3SDaniel Vetter 
27949619f3SDaniel Vetter #include "drm_crtc_internal.h"
28949619f3SDaniel Vetter 
29949619f3SDaniel Vetter /*
30949619f3SDaniel Vetter  * Internal function to assign a slot in the object idr and optionally
31949619f3SDaniel Vetter  * register the object into the idr.
32949619f3SDaniel Vetter  */
33949619f3SDaniel Vetter int drm_mode_object_get_reg(struct drm_device *dev,
34949619f3SDaniel Vetter 			    struct drm_mode_object *obj,
35949619f3SDaniel Vetter 			    uint32_t obj_type,
36949619f3SDaniel Vetter 			    bool register_obj,
37949619f3SDaniel Vetter 			    void (*obj_free_cb)(struct kref *kref))
38949619f3SDaniel Vetter {
39949619f3SDaniel Vetter 	int ret;
40949619f3SDaniel Vetter 
41949619f3SDaniel Vetter 	mutex_lock(&dev->mode_config.idr_mutex);
42949619f3SDaniel Vetter 	ret = idr_alloc(&dev->mode_config.crtc_idr, register_obj ? obj : NULL, 1, 0, GFP_KERNEL);
43949619f3SDaniel Vetter 	if (ret >= 0) {
44949619f3SDaniel Vetter 		/*
45949619f3SDaniel Vetter 		 * Set up the object linking under the protection of the idr
46949619f3SDaniel Vetter 		 * lock so that other users can't see inconsistent state.
47949619f3SDaniel Vetter 		 */
48949619f3SDaniel Vetter 		obj->id = ret;
49949619f3SDaniel Vetter 		obj->type = obj_type;
50949619f3SDaniel Vetter 		if (obj_free_cb) {
51949619f3SDaniel Vetter 			obj->free_cb = obj_free_cb;
52949619f3SDaniel Vetter 			kref_init(&obj->refcount);
53949619f3SDaniel Vetter 		}
54949619f3SDaniel Vetter 	}
55949619f3SDaniel Vetter 	mutex_unlock(&dev->mode_config.idr_mutex);
56949619f3SDaniel Vetter 
57949619f3SDaniel Vetter 	return ret < 0 ? ret : 0;
58949619f3SDaniel Vetter }
59949619f3SDaniel Vetter 
60949619f3SDaniel Vetter /**
61949619f3SDaniel Vetter  * drm_mode_object_get - allocate a new modeset identifier
62949619f3SDaniel Vetter  * @dev: DRM device
63949619f3SDaniel Vetter  * @obj: object pointer, used to generate unique ID
64949619f3SDaniel Vetter  * @obj_type: object type
65949619f3SDaniel Vetter  *
66949619f3SDaniel Vetter  * Create a unique identifier based on @ptr in @dev's identifier space.  Used
67949619f3SDaniel Vetter  * for tracking modes, CRTCs and connectors. Note that despite the _get postfix
68949619f3SDaniel Vetter  * modeset identifiers are _not_ reference counted. Hence don't use this for
69949619f3SDaniel Vetter  * reference counted modeset objects like framebuffers.
70949619f3SDaniel Vetter  *
71949619f3SDaniel Vetter  * Returns:
72949619f3SDaniel Vetter  * Zero on success, error code on failure.
73949619f3SDaniel Vetter  */
74949619f3SDaniel Vetter int drm_mode_object_get(struct drm_device *dev,
75949619f3SDaniel Vetter 			struct drm_mode_object *obj, uint32_t obj_type)
76949619f3SDaniel Vetter {
77949619f3SDaniel Vetter 	return drm_mode_object_get_reg(dev, obj, obj_type, true, NULL);
78949619f3SDaniel Vetter }
79949619f3SDaniel Vetter 
80949619f3SDaniel Vetter void drm_mode_object_register(struct drm_device *dev,
81949619f3SDaniel Vetter 			      struct drm_mode_object *obj)
82949619f3SDaniel Vetter {
83949619f3SDaniel Vetter 	mutex_lock(&dev->mode_config.idr_mutex);
84949619f3SDaniel Vetter 	idr_replace(&dev->mode_config.crtc_idr, obj, obj->id);
85949619f3SDaniel Vetter 	mutex_unlock(&dev->mode_config.idr_mutex);
86949619f3SDaniel Vetter }
87949619f3SDaniel Vetter 
88949619f3SDaniel Vetter /**
89949619f3SDaniel Vetter  * drm_mode_object_unregister - free a modeset identifer
90949619f3SDaniel Vetter  * @dev: DRM device
91949619f3SDaniel Vetter  * @object: object to free
92949619f3SDaniel Vetter  *
93949619f3SDaniel Vetter  * Free @id from @dev's unique identifier pool.
94949619f3SDaniel Vetter  * This function can be called multiple times, and guards against
95949619f3SDaniel Vetter  * multiple removals.
96949619f3SDaniel Vetter  * These modeset identifiers are _not_ reference counted. Hence don't use this
97949619f3SDaniel Vetter  * for reference counted modeset objects like framebuffers.
98949619f3SDaniel Vetter  */
99949619f3SDaniel Vetter void drm_mode_object_unregister(struct drm_device *dev,
100949619f3SDaniel Vetter 				struct drm_mode_object *object)
101949619f3SDaniel Vetter {
102949619f3SDaniel Vetter 	mutex_lock(&dev->mode_config.idr_mutex);
103949619f3SDaniel Vetter 	if (object->id) {
104949619f3SDaniel Vetter 		idr_remove(&dev->mode_config.crtc_idr, object->id);
105949619f3SDaniel Vetter 		object->id = 0;
106949619f3SDaniel Vetter 	}
107949619f3SDaniel Vetter 	mutex_unlock(&dev->mode_config.idr_mutex);
108949619f3SDaniel Vetter }
109949619f3SDaniel Vetter 
110949619f3SDaniel Vetter struct drm_mode_object *__drm_mode_object_find(struct drm_device *dev,
111949619f3SDaniel Vetter 					       uint32_t id, uint32_t type)
112949619f3SDaniel Vetter {
113949619f3SDaniel Vetter 	struct drm_mode_object *obj = NULL;
114949619f3SDaniel Vetter 
115949619f3SDaniel Vetter 	mutex_lock(&dev->mode_config.idr_mutex);
116949619f3SDaniel Vetter 	obj = idr_find(&dev->mode_config.crtc_idr, id);
117949619f3SDaniel Vetter 	if (obj && type != DRM_MODE_OBJECT_ANY && obj->type != type)
118949619f3SDaniel Vetter 		obj = NULL;
119949619f3SDaniel Vetter 	if (obj && obj->id != id)
120949619f3SDaniel Vetter 		obj = NULL;
121949619f3SDaniel Vetter 
122949619f3SDaniel Vetter 	if (obj && obj->free_cb) {
123949619f3SDaniel Vetter 		if (!kref_get_unless_zero(&obj->refcount))
124949619f3SDaniel Vetter 			obj = NULL;
125949619f3SDaniel Vetter 	}
126949619f3SDaniel Vetter 	mutex_unlock(&dev->mode_config.idr_mutex);
127949619f3SDaniel Vetter 
128949619f3SDaniel Vetter 	return obj;
129949619f3SDaniel Vetter }
130949619f3SDaniel Vetter 
131949619f3SDaniel Vetter /**
132949619f3SDaniel Vetter  * drm_mode_object_find - look up a drm object with static lifetime
133949619f3SDaniel Vetter  * @dev: drm device
134949619f3SDaniel Vetter  * @id: id of the mode object
135949619f3SDaniel Vetter  * @type: type of the mode object
136949619f3SDaniel Vetter  *
137949619f3SDaniel Vetter  * This function is used to look up a modeset object. It will acquire a
138949619f3SDaniel Vetter  * reference for reference counted objects. This reference must be dropped again
139949619f3SDaniel Vetter  * by callind drm_mode_object_unreference().
140949619f3SDaniel Vetter  */
141949619f3SDaniel Vetter struct drm_mode_object *drm_mode_object_find(struct drm_device *dev,
142949619f3SDaniel Vetter 		uint32_t id, uint32_t type)
143949619f3SDaniel Vetter {
144949619f3SDaniel Vetter 	struct drm_mode_object *obj = NULL;
145949619f3SDaniel Vetter 
146949619f3SDaniel Vetter 	obj = __drm_mode_object_find(dev, id, type);
147949619f3SDaniel Vetter 	return obj;
148949619f3SDaniel Vetter }
149949619f3SDaniel Vetter EXPORT_SYMBOL(drm_mode_object_find);
150949619f3SDaniel Vetter 
151949619f3SDaniel Vetter /**
152949619f3SDaniel Vetter  * drm_mode_object_unreference - decr the object refcnt
153949619f3SDaniel Vetter  * @obj: mode_object
154949619f3SDaniel Vetter  *
155a2511a55SDaniel Vetter  * This function decrements the object's refcount if it is a refcounted modeset
156949619f3SDaniel Vetter  * object. It is a no-op on any other object. This is used to drop references
157949619f3SDaniel Vetter  * acquired with drm_mode_object_reference().
158949619f3SDaniel Vetter  */
159949619f3SDaniel Vetter void drm_mode_object_unreference(struct drm_mode_object *obj)
160949619f3SDaniel Vetter {
161949619f3SDaniel Vetter 	if (obj->free_cb) {
162*2c935bc5SPeter Zijlstra 		DRM_DEBUG("OBJ ID: %d (%d)\n", obj->id, kref_read(&obj->refcount));
163949619f3SDaniel Vetter 		kref_put(&obj->refcount, obj->free_cb);
164949619f3SDaniel Vetter 	}
165949619f3SDaniel Vetter }
166949619f3SDaniel Vetter EXPORT_SYMBOL(drm_mode_object_unreference);
167949619f3SDaniel Vetter 
168949619f3SDaniel Vetter /**
169949619f3SDaniel Vetter  * drm_mode_object_reference - incr the object refcnt
170949619f3SDaniel Vetter  * @obj: mode_object
171949619f3SDaniel Vetter  *
172a2511a55SDaniel Vetter  * This function increments the object's refcount if it is a refcounted modeset
173949619f3SDaniel Vetter  * object. It is a no-op on any other object. References should be dropped again
174949619f3SDaniel Vetter  * by calling drm_mode_object_unreference().
175949619f3SDaniel Vetter  */
176949619f3SDaniel Vetter void drm_mode_object_reference(struct drm_mode_object *obj)
177949619f3SDaniel Vetter {
178949619f3SDaniel Vetter 	if (obj->free_cb) {
179*2c935bc5SPeter Zijlstra 		DRM_DEBUG("OBJ ID: %d (%d)\n", obj->id, kref_read(&obj->refcount));
180949619f3SDaniel Vetter 		kref_get(&obj->refcount);
181949619f3SDaniel Vetter 	}
182949619f3SDaniel Vetter }
183949619f3SDaniel Vetter EXPORT_SYMBOL(drm_mode_object_reference);
184949619f3SDaniel Vetter 
185949619f3SDaniel Vetter /**
186949619f3SDaniel Vetter  * drm_object_attach_property - attach a property to a modeset object
187949619f3SDaniel Vetter  * @obj: drm modeset object
188949619f3SDaniel Vetter  * @property: property to attach
189949619f3SDaniel Vetter  * @init_val: initial value of the property
190949619f3SDaniel Vetter  *
191949619f3SDaniel Vetter  * This attaches the given property to the modeset object with the given initial
192949619f3SDaniel Vetter  * value. Currently this function cannot fail since the properties are stored in
193949619f3SDaniel Vetter  * a statically sized array.
194949619f3SDaniel Vetter  */
195949619f3SDaniel Vetter void drm_object_attach_property(struct drm_mode_object *obj,
196949619f3SDaniel Vetter 				struct drm_property *property,
197949619f3SDaniel Vetter 				uint64_t init_val)
198949619f3SDaniel Vetter {
199949619f3SDaniel Vetter 	int count = obj->properties->count;
200949619f3SDaniel Vetter 
201949619f3SDaniel Vetter 	if (count == DRM_OBJECT_MAX_PROPERTY) {
202949619f3SDaniel Vetter 		WARN(1, "Failed to attach object property (type: 0x%x). Please "
203949619f3SDaniel Vetter 			"increase DRM_OBJECT_MAX_PROPERTY by 1 for each time "
204949619f3SDaniel Vetter 			"you see this message on the same object type.\n",
205949619f3SDaniel Vetter 			obj->type);
206949619f3SDaniel Vetter 		return;
207949619f3SDaniel Vetter 	}
208949619f3SDaniel Vetter 
209949619f3SDaniel Vetter 	obj->properties->properties[count] = property;
210949619f3SDaniel Vetter 	obj->properties->values[count] = init_val;
211949619f3SDaniel Vetter 	obj->properties->count++;
212949619f3SDaniel Vetter }
213949619f3SDaniel Vetter EXPORT_SYMBOL(drm_object_attach_property);
214949619f3SDaniel Vetter 
215949619f3SDaniel Vetter /**
216949619f3SDaniel Vetter  * drm_object_property_set_value - set the value of a property
217949619f3SDaniel Vetter  * @obj: drm mode object to set property value for
218949619f3SDaniel Vetter  * @property: property to set
219949619f3SDaniel Vetter  * @val: value the property should be set to
220949619f3SDaniel Vetter  *
221a2511a55SDaniel Vetter  * This function sets a given property on a given object. This function only
222949619f3SDaniel Vetter  * changes the software state of the property, it does not call into the
223949619f3SDaniel Vetter  * driver's ->set_property callback.
224949619f3SDaniel Vetter  *
225a2511a55SDaniel Vetter  * Note that atomic drivers should not have any need to call this, the core will
226a2511a55SDaniel Vetter  * ensure consistency of values reported back to userspace through the
227a2511a55SDaniel Vetter  * appropriate ->atomic_get_property callback. Only legacy drivers should call
228a2511a55SDaniel Vetter  * this function to update the tracked value (after clamping and other
229a2511a55SDaniel Vetter  * restrictions have been applied).
230a2511a55SDaniel Vetter  *
231949619f3SDaniel Vetter  * Returns:
232949619f3SDaniel Vetter  * Zero on success, error code on failure.
233949619f3SDaniel Vetter  */
234949619f3SDaniel Vetter int drm_object_property_set_value(struct drm_mode_object *obj,
235949619f3SDaniel Vetter 				  struct drm_property *property, uint64_t val)
236949619f3SDaniel Vetter {
237949619f3SDaniel Vetter 	int i;
238949619f3SDaniel Vetter 
239949619f3SDaniel Vetter 	for (i = 0; i < obj->properties->count; i++) {
240949619f3SDaniel Vetter 		if (obj->properties->properties[i] == property) {
241949619f3SDaniel Vetter 			obj->properties->values[i] = val;
242949619f3SDaniel Vetter 			return 0;
243949619f3SDaniel Vetter 		}
244949619f3SDaniel Vetter 	}
245949619f3SDaniel Vetter 
246949619f3SDaniel Vetter 	return -EINVAL;
247949619f3SDaniel Vetter }
248949619f3SDaniel Vetter EXPORT_SYMBOL(drm_object_property_set_value);
249949619f3SDaniel Vetter 
250949619f3SDaniel Vetter /**
251949619f3SDaniel Vetter  * drm_object_property_get_value - retrieve the value of a property
252949619f3SDaniel Vetter  * @obj: drm mode object to get property value from
253949619f3SDaniel Vetter  * @property: property to retrieve
254949619f3SDaniel Vetter  * @val: storage for the property value
255949619f3SDaniel Vetter  *
256949619f3SDaniel Vetter  * This function retrieves the softare state of the given property for the given
257949619f3SDaniel Vetter  * property. Since there is no driver callback to retrieve the current property
258949619f3SDaniel Vetter  * value this might be out of sync with the hardware, depending upon the driver
259949619f3SDaniel Vetter  * and property.
260949619f3SDaniel Vetter  *
261a2511a55SDaniel Vetter  * Atomic drivers should never call this function directly, the core will read
262a2511a55SDaniel Vetter  * out property values through the various ->atomic_get_property callbacks.
263a2511a55SDaniel Vetter  *
264949619f3SDaniel Vetter  * Returns:
265949619f3SDaniel Vetter  * Zero on success, error code on failure.
266949619f3SDaniel Vetter  */
267949619f3SDaniel Vetter int drm_object_property_get_value(struct drm_mode_object *obj,
268949619f3SDaniel Vetter 				  struct drm_property *property, uint64_t *val)
269949619f3SDaniel Vetter {
270949619f3SDaniel Vetter 	int i;
271949619f3SDaniel Vetter 
272949619f3SDaniel Vetter 	/* read-only properties bypass atomic mechanism and still store
273949619f3SDaniel Vetter 	 * their value in obj->properties->values[].. mostly to avoid
274949619f3SDaniel Vetter 	 * having to deal w/ EDID and similar props in atomic paths:
275949619f3SDaniel Vetter 	 */
276949619f3SDaniel Vetter 	if (drm_core_check_feature(property->dev, DRIVER_ATOMIC) &&
277949619f3SDaniel Vetter 			!(property->flags & DRM_MODE_PROP_IMMUTABLE))
278949619f3SDaniel Vetter 		return drm_atomic_get_property(obj, property, val);
279949619f3SDaniel Vetter 
280949619f3SDaniel Vetter 	for (i = 0; i < obj->properties->count; i++) {
281949619f3SDaniel Vetter 		if (obj->properties->properties[i] == property) {
282949619f3SDaniel Vetter 			*val = obj->properties->values[i];
283949619f3SDaniel Vetter 			return 0;
284949619f3SDaniel Vetter 		}
285949619f3SDaniel Vetter 
286949619f3SDaniel Vetter 	}
287949619f3SDaniel Vetter 
288949619f3SDaniel Vetter 	return -EINVAL;
289949619f3SDaniel Vetter }
290949619f3SDaniel Vetter EXPORT_SYMBOL(drm_object_property_get_value);
291949619f3SDaniel Vetter 
292949619f3SDaniel Vetter /* helper for getconnector and getproperties ioctls */
293949619f3SDaniel Vetter int drm_mode_object_get_properties(struct drm_mode_object *obj, bool atomic,
294949619f3SDaniel Vetter 				   uint32_t __user *prop_ptr,
295949619f3SDaniel Vetter 				   uint64_t __user *prop_values,
296949619f3SDaniel Vetter 				   uint32_t *arg_count_props)
297949619f3SDaniel Vetter {
298f094d881SDaniel Vetter 	int i, ret, count;
299949619f3SDaniel Vetter 
300f094d881SDaniel Vetter 	for (i = 0, count = 0; i < obj->properties->count; i++) {
301949619f3SDaniel Vetter 		struct drm_property *prop = obj->properties->properties[i];
302949619f3SDaniel Vetter 		uint64_t val;
303949619f3SDaniel Vetter 
304949619f3SDaniel Vetter 		if ((prop->flags & DRM_MODE_PROP_ATOMIC) && !atomic)
305949619f3SDaniel Vetter 			continue;
306949619f3SDaniel Vetter 
307f094d881SDaniel Vetter 		if (*arg_count_props > count) {
308949619f3SDaniel Vetter 			ret = drm_object_property_get_value(obj, prop, &val);
309949619f3SDaniel Vetter 			if (ret)
310949619f3SDaniel Vetter 				return ret;
311949619f3SDaniel Vetter 
312f094d881SDaniel Vetter 			if (put_user(prop->base.id, prop_ptr + count))
313949619f3SDaniel Vetter 				return -EFAULT;
314949619f3SDaniel Vetter 
315f094d881SDaniel Vetter 			if (put_user(val, prop_values + count))
316949619f3SDaniel Vetter 				return -EFAULT;
317f094d881SDaniel Vetter 		}
318949619f3SDaniel Vetter 
319f094d881SDaniel Vetter 		count++;
320949619f3SDaniel Vetter 	}
321f094d881SDaniel Vetter 	*arg_count_props = count;
322949619f3SDaniel Vetter 
323949619f3SDaniel Vetter 	return 0;
324949619f3SDaniel Vetter }
325949619f3SDaniel Vetter 
326949619f3SDaniel Vetter /**
327949619f3SDaniel Vetter  * drm_mode_obj_get_properties_ioctl - get the current value of a object's property
328949619f3SDaniel Vetter  * @dev: DRM device
329949619f3SDaniel Vetter  * @data: ioctl data
330949619f3SDaniel Vetter  * @file_priv: DRM file info
331949619f3SDaniel Vetter  *
332949619f3SDaniel Vetter  * This function retrieves the current value for an object's property. Compared
333949619f3SDaniel Vetter  * to the connector specific ioctl this one is extended to also work on crtc and
334949619f3SDaniel Vetter  * plane objects.
335949619f3SDaniel Vetter  *
336949619f3SDaniel Vetter  * Called by the user via ioctl.
337949619f3SDaniel Vetter  *
338949619f3SDaniel Vetter  * Returns:
339949619f3SDaniel Vetter  * Zero on success, negative errno on failure.
340949619f3SDaniel Vetter  */
341949619f3SDaniel Vetter int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data,
342949619f3SDaniel Vetter 				      struct drm_file *file_priv)
343949619f3SDaniel Vetter {
344949619f3SDaniel Vetter 	struct drm_mode_obj_get_properties *arg = data;
345949619f3SDaniel Vetter 	struct drm_mode_object *obj;
346949619f3SDaniel Vetter 	int ret = 0;
347949619f3SDaniel Vetter 
348949619f3SDaniel Vetter 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
349949619f3SDaniel Vetter 		return -EINVAL;
350949619f3SDaniel Vetter 
351949619f3SDaniel Vetter 	drm_modeset_lock_all(dev);
352949619f3SDaniel Vetter 
353949619f3SDaniel Vetter 	obj = drm_mode_object_find(dev, arg->obj_id, arg->obj_type);
354949619f3SDaniel Vetter 	if (!obj) {
355949619f3SDaniel Vetter 		ret = -ENOENT;
356949619f3SDaniel Vetter 		goto out;
357949619f3SDaniel Vetter 	}
358949619f3SDaniel Vetter 	if (!obj->properties) {
359949619f3SDaniel Vetter 		ret = -EINVAL;
360949619f3SDaniel Vetter 		goto out_unref;
361949619f3SDaniel Vetter 	}
362949619f3SDaniel Vetter 
363949619f3SDaniel Vetter 	ret = drm_mode_object_get_properties(obj, file_priv->atomic,
364949619f3SDaniel Vetter 			(uint32_t __user *)(unsigned long)(arg->props_ptr),
365949619f3SDaniel Vetter 			(uint64_t __user *)(unsigned long)(arg->prop_values_ptr),
366949619f3SDaniel Vetter 			&arg->count_props);
367949619f3SDaniel Vetter 
368949619f3SDaniel Vetter out_unref:
369949619f3SDaniel Vetter 	drm_mode_object_unreference(obj);
370949619f3SDaniel Vetter out:
371949619f3SDaniel Vetter 	drm_modeset_unlock_all(dev);
372949619f3SDaniel Vetter 	return ret;
373949619f3SDaniel Vetter }
374949619f3SDaniel Vetter 
375f92f053bSMaarten Lankhorst struct drm_property *drm_mode_obj_find_prop_id(struct drm_mode_object *obj,
376f92f053bSMaarten Lankhorst 					       uint32_t prop_id)
377f92f053bSMaarten Lankhorst {
378f92f053bSMaarten Lankhorst 	int i;
379f92f053bSMaarten Lankhorst 
380f92f053bSMaarten Lankhorst 	for (i = 0; i < obj->properties->count; i++)
381f92f053bSMaarten Lankhorst 		if (obj->properties->properties[i]->base.id == prop_id)
382f92f053bSMaarten Lankhorst 			return obj->properties->properties[i];
383f92f053bSMaarten Lankhorst 
384f92f053bSMaarten Lankhorst 	return NULL;
385f92f053bSMaarten Lankhorst }
386f92f053bSMaarten Lankhorst 
387949619f3SDaniel Vetter int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data,
388949619f3SDaniel Vetter 				    struct drm_file *file_priv)
389949619f3SDaniel Vetter {
390949619f3SDaniel Vetter 	struct drm_mode_obj_set_property *arg = data;
391949619f3SDaniel Vetter 	struct drm_mode_object *arg_obj;
392949619f3SDaniel Vetter 	struct drm_property *property;
393f92f053bSMaarten Lankhorst 	int ret = -EINVAL;
394949619f3SDaniel Vetter 	struct drm_mode_object *ref;
395949619f3SDaniel Vetter 
396949619f3SDaniel Vetter 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
397949619f3SDaniel Vetter 		return -EINVAL;
398949619f3SDaniel Vetter 
399949619f3SDaniel Vetter 	drm_modeset_lock_all(dev);
400949619f3SDaniel Vetter 
401949619f3SDaniel Vetter 	arg_obj = drm_mode_object_find(dev, arg->obj_id, arg->obj_type);
402949619f3SDaniel Vetter 	if (!arg_obj) {
403949619f3SDaniel Vetter 		ret = -ENOENT;
404949619f3SDaniel Vetter 		goto out;
405949619f3SDaniel Vetter 	}
406f92f053bSMaarten Lankhorst 
407949619f3SDaniel Vetter 	if (!arg_obj->properties)
408949619f3SDaniel Vetter 		goto out_unref;
409949619f3SDaniel Vetter 
410f92f053bSMaarten Lankhorst 	property = drm_mode_obj_find_prop_id(arg_obj, arg->prop_id);
411f92f053bSMaarten Lankhorst 	if (!property)
412949619f3SDaniel Vetter 		goto out_unref;
413949619f3SDaniel Vetter 
414949619f3SDaniel Vetter 	if (!drm_property_change_valid_get(property, arg->value, &ref))
415949619f3SDaniel Vetter 		goto out_unref;
416949619f3SDaniel Vetter 
417949619f3SDaniel Vetter 	switch (arg_obj->type) {
418949619f3SDaniel Vetter 	case DRM_MODE_OBJECT_CONNECTOR:
419949619f3SDaniel Vetter 		ret = drm_mode_connector_set_obj_prop(arg_obj, property,
420949619f3SDaniel Vetter 						      arg->value);
421949619f3SDaniel Vetter 		break;
422949619f3SDaniel Vetter 	case DRM_MODE_OBJECT_CRTC:
423949619f3SDaniel Vetter 		ret = drm_mode_crtc_set_obj_prop(arg_obj, property, arg->value);
424949619f3SDaniel Vetter 		break;
425949619f3SDaniel Vetter 	case DRM_MODE_OBJECT_PLANE:
426949619f3SDaniel Vetter 		ret = drm_mode_plane_set_obj_prop(obj_to_plane(arg_obj),
427949619f3SDaniel Vetter 						  property, arg->value);
428949619f3SDaniel Vetter 		break;
429949619f3SDaniel Vetter 	}
430949619f3SDaniel Vetter 
431949619f3SDaniel Vetter 	drm_property_change_valid_put(property, ref);
432949619f3SDaniel Vetter 
433949619f3SDaniel Vetter out_unref:
434949619f3SDaniel Vetter 	drm_mode_object_unreference(arg_obj);
435949619f3SDaniel Vetter out:
436949619f3SDaniel Vetter 	drm_modeset_unlock_all(dev);
437949619f3SDaniel Vetter 	return ret;
438949619f3SDaniel Vetter }
439