17f4dd379Sjsg /*
27f4dd379Sjsg * Copyright (c) 2016 Intel Corporation
37f4dd379Sjsg *
47f4dd379Sjsg * Permission to use, copy, modify, distribute, and sell this software and its
57f4dd379Sjsg * documentation for any purpose is hereby granted without fee, provided that
67f4dd379Sjsg * the above copyright notice appear in all copies and that both that copyright
77f4dd379Sjsg * notice and this permission notice appear in supporting documentation, and
87f4dd379Sjsg * that the name of the copyright holders not be used in advertising or
97f4dd379Sjsg * publicity pertaining to distribution of the software without specific,
107f4dd379Sjsg * written prior permission. The copyright holders make no representations
117f4dd379Sjsg * about the suitability of this software for any purpose. It is provided "as
127f4dd379Sjsg * is" without express or implied warranty.
137f4dd379Sjsg *
147f4dd379Sjsg * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
157f4dd379Sjsg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
167f4dd379Sjsg * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
177f4dd379Sjsg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
187f4dd379Sjsg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
197f4dd379Sjsg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
207f4dd379Sjsg * OF THIS SOFTWARE.
217f4dd379Sjsg */
227f4dd379Sjsg
237f4dd379Sjsg #include <linux/export.h>
24c349dbc7Sjsg #include <linux/uaccess.h>
251bb76ff1Sjsg #include <linux/backlight.h>
26c349dbc7Sjsg
277f4dd379Sjsg #include <drm/drm_atomic.h>
28c349dbc7Sjsg #include <drm/drm_drv.h>
29c349dbc7Sjsg #include <drm/drm_device.h>
30c349dbc7Sjsg #include <drm/drm_file.h>
31c349dbc7Sjsg #include <drm/drm_mode_object.h>
32c349dbc7Sjsg #include <drm/drm_print.h>
337f4dd379Sjsg
347f4dd379Sjsg #include "drm_crtc_internal.h"
357f4dd379Sjsg
367f4dd379Sjsg /*
377f4dd379Sjsg * Internal function to assign a slot in the object idr and optionally
387f4dd379Sjsg * register the object into the idr.
397f4dd379Sjsg */
__drm_mode_object_add(struct drm_device * dev,struct drm_mode_object * obj,uint32_t obj_type,bool register_obj,void (* obj_free_cb)(struct kref * kref))407f4dd379Sjsg int __drm_mode_object_add(struct drm_device *dev, struct drm_mode_object *obj,
417f4dd379Sjsg uint32_t obj_type, bool register_obj,
427f4dd379Sjsg void (*obj_free_cb)(struct kref *kref))
437f4dd379Sjsg {
447f4dd379Sjsg int ret;
457f4dd379Sjsg
46c349dbc7Sjsg WARN_ON(!dev->driver->load && dev->registered && !obj_free_cb);
47c349dbc7Sjsg
487f4dd379Sjsg mutex_lock(&dev->mode_config.idr_mutex);
49c349dbc7Sjsg ret = idr_alloc(&dev->mode_config.object_idr, register_obj ? obj : NULL,
50c349dbc7Sjsg 1, 0, GFP_KERNEL);
517f4dd379Sjsg if (ret >= 0) {
527f4dd379Sjsg /*
537f4dd379Sjsg * Set up the object linking under the protection of the idr
547f4dd379Sjsg * lock so that other users can't see inconsistent state.
557f4dd379Sjsg */
567f4dd379Sjsg obj->id = ret;
577f4dd379Sjsg obj->type = obj_type;
587f4dd379Sjsg if (obj_free_cb) {
597f4dd379Sjsg obj->free_cb = obj_free_cb;
607f4dd379Sjsg kref_init(&obj->refcount);
617f4dd379Sjsg }
627f4dd379Sjsg }
637f4dd379Sjsg mutex_unlock(&dev->mode_config.idr_mutex);
647f4dd379Sjsg
657f4dd379Sjsg return ret < 0 ? ret : 0;
667f4dd379Sjsg }
677f4dd379Sjsg
687f4dd379Sjsg /**
697f4dd379Sjsg * drm_mode_object_add - allocate a new modeset identifier
707f4dd379Sjsg * @dev: DRM device
717f4dd379Sjsg * @obj: object pointer, used to generate unique ID
727f4dd379Sjsg * @obj_type: object type
737f4dd379Sjsg *
747f4dd379Sjsg * Create a unique identifier based on @ptr in @dev's identifier space. Used
757f4dd379Sjsg * for tracking modes, CRTCs and connectors.
767f4dd379Sjsg *
777f4dd379Sjsg * Returns:
787f4dd379Sjsg * Zero on success, error code on failure.
797f4dd379Sjsg */
drm_mode_object_add(struct drm_device * dev,struct drm_mode_object * obj,uint32_t obj_type)807f4dd379Sjsg int drm_mode_object_add(struct drm_device *dev,
817f4dd379Sjsg struct drm_mode_object *obj, uint32_t obj_type)
827f4dd379Sjsg {
837f4dd379Sjsg return __drm_mode_object_add(dev, obj, obj_type, true, NULL);
847f4dd379Sjsg }
857f4dd379Sjsg
drm_mode_object_register(struct drm_device * dev,struct drm_mode_object * obj)867f4dd379Sjsg void drm_mode_object_register(struct drm_device *dev,
877f4dd379Sjsg struct drm_mode_object *obj)
887f4dd379Sjsg {
897f4dd379Sjsg mutex_lock(&dev->mode_config.idr_mutex);
90c349dbc7Sjsg idr_replace(&dev->mode_config.object_idr, obj, obj->id);
917f4dd379Sjsg mutex_unlock(&dev->mode_config.idr_mutex);
927f4dd379Sjsg }
937f4dd379Sjsg
947f4dd379Sjsg /**
955ca02815Sjsg * drm_mode_object_unregister - free a modeset identifier
967f4dd379Sjsg * @dev: DRM device
977f4dd379Sjsg * @object: object to free
987f4dd379Sjsg *
997f4dd379Sjsg * Free @id from @dev's unique identifier pool.
1007f4dd379Sjsg * This function can be called multiple times, and guards against
1017f4dd379Sjsg * multiple removals.
1027f4dd379Sjsg * These modeset identifiers are _not_ reference counted. Hence don't use this
1037f4dd379Sjsg * for reference counted modeset objects like framebuffers.
1047f4dd379Sjsg */
drm_mode_object_unregister(struct drm_device * dev,struct drm_mode_object * object)1057f4dd379Sjsg void drm_mode_object_unregister(struct drm_device *dev,
1067f4dd379Sjsg struct drm_mode_object *object)
1077f4dd379Sjsg {
108c349dbc7Sjsg WARN_ON(!dev->driver->load && dev->registered && !object->free_cb);
109c349dbc7Sjsg
1107f4dd379Sjsg mutex_lock(&dev->mode_config.idr_mutex);
1117f4dd379Sjsg if (object->id) {
112c349dbc7Sjsg idr_remove(&dev->mode_config.object_idr, object->id);
1137f4dd379Sjsg object->id = 0;
1147f4dd379Sjsg }
1157f4dd379Sjsg mutex_unlock(&dev->mode_config.idr_mutex);
1167f4dd379Sjsg }
1177f4dd379Sjsg
1187f4dd379Sjsg /**
1195ca02815Sjsg * drm_mode_object_lease_required - check types which must be leased to be used
1207f4dd379Sjsg * @type: type of object
1217f4dd379Sjsg *
1227f4dd379Sjsg * Returns whether the provided type of drm_mode_object must
1237f4dd379Sjsg * be owned or leased to be used by a process.
1247f4dd379Sjsg */
drm_mode_object_lease_required(uint32_t type)1257f4dd379Sjsg bool drm_mode_object_lease_required(uint32_t type)
1267f4dd379Sjsg {
1277f4dd379Sjsg switch(type) {
1287f4dd379Sjsg case DRM_MODE_OBJECT_CRTC:
1297f4dd379Sjsg case DRM_MODE_OBJECT_CONNECTOR:
1307f4dd379Sjsg case DRM_MODE_OBJECT_PLANE:
1317f4dd379Sjsg return true;
1327f4dd379Sjsg default:
1337f4dd379Sjsg return false;
1347f4dd379Sjsg }
1357f4dd379Sjsg }
1367f4dd379Sjsg
__drm_mode_object_find(struct drm_device * dev,struct drm_file * file_priv,uint32_t id,uint32_t type)1377f4dd379Sjsg struct drm_mode_object *__drm_mode_object_find(struct drm_device *dev,
1387f4dd379Sjsg struct drm_file *file_priv,
1397f4dd379Sjsg uint32_t id, uint32_t type)
1407f4dd379Sjsg {
1417f4dd379Sjsg struct drm_mode_object *obj = NULL;
1427f4dd379Sjsg
1437f4dd379Sjsg mutex_lock(&dev->mode_config.idr_mutex);
144c349dbc7Sjsg obj = idr_find(&dev->mode_config.object_idr, id);
1457f4dd379Sjsg if (obj && type != DRM_MODE_OBJECT_ANY && obj->type != type)
1467f4dd379Sjsg obj = NULL;
1477f4dd379Sjsg if (obj && obj->id != id)
1487f4dd379Sjsg obj = NULL;
1497f4dd379Sjsg
1507f4dd379Sjsg #ifdef notyet
1517f4dd379Sjsg if (obj && drm_mode_object_lease_required(obj->type) &&
152*f005ef32Sjsg !_drm_lease_held(file_priv, obj->id)) {
153*f005ef32Sjsg drm_dbg_kms(dev, "[OBJECT:%d] not included in lease", id);
1547f4dd379Sjsg obj = NULL;
155*f005ef32Sjsg }
1567f4dd379Sjsg #endif
1577f4dd379Sjsg
1587f4dd379Sjsg if (obj && obj->free_cb) {
1597f4dd379Sjsg if (!kref_get_unless_zero(&obj->refcount))
1607f4dd379Sjsg obj = NULL;
1617f4dd379Sjsg }
1627f4dd379Sjsg mutex_unlock(&dev->mode_config.idr_mutex);
1637f4dd379Sjsg
1647f4dd379Sjsg return obj;
1657f4dd379Sjsg }
1667f4dd379Sjsg
1677f4dd379Sjsg /**
1687f4dd379Sjsg * drm_mode_object_find - look up a drm object with static lifetime
1697f4dd379Sjsg * @dev: drm device
1707f4dd379Sjsg * @file_priv: drm file
1717f4dd379Sjsg * @id: id of the mode object
1727f4dd379Sjsg * @type: type of the mode object
1737f4dd379Sjsg *
1747f4dd379Sjsg * This function is used to look up a modeset object. It will acquire a
1757f4dd379Sjsg * reference for reference counted objects. This reference must be dropped again
1767f4dd379Sjsg * by callind drm_mode_object_put().
1777f4dd379Sjsg */
drm_mode_object_find(struct drm_device * dev,struct drm_file * file_priv,uint32_t id,uint32_t type)1787f4dd379Sjsg struct drm_mode_object *drm_mode_object_find(struct drm_device *dev,
1797f4dd379Sjsg struct drm_file *file_priv,
1807f4dd379Sjsg uint32_t id, uint32_t type)
1817f4dd379Sjsg {
1827f4dd379Sjsg struct drm_mode_object *obj = NULL;
1837f4dd379Sjsg
1847f4dd379Sjsg obj = __drm_mode_object_find(dev, file_priv, id, type);
1857f4dd379Sjsg return obj;
1867f4dd379Sjsg }
1877f4dd379Sjsg EXPORT_SYMBOL(drm_mode_object_find);
1887f4dd379Sjsg
1897f4dd379Sjsg /**
1907f4dd379Sjsg * drm_mode_object_put - release a mode object reference
1917f4dd379Sjsg * @obj: DRM mode object
1927f4dd379Sjsg *
1937f4dd379Sjsg * This function decrements the object's refcount if it is a refcounted modeset
1947f4dd379Sjsg * object. It is a no-op on any other object. This is used to drop references
1957f4dd379Sjsg * acquired with drm_mode_object_get().
1967f4dd379Sjsg */
drm_mode_object_put(struct drm_mode_object * obj)1977f4dd379Sjsg void drm_mode_object_put(struct drm_mode_object *obj)
1987f4dd379Sjsg {
1997f4dd379Sjsg if (obj->free_cb) {
2007f4dd379Sjsg DRM_DEBUG("OBJ ID: %d (%d)\n", obj->id, kref_read(&obj->refcount));
2017f4dd379Sjsg kref_put(&obj->refcount, obj->free_cb);
2027f4dd379Sjsg }
2037f4dd379Sjsg }
2047f4dd379Sjsg EXPORT_SYMBOL(drm_mode_object_put);
2057f4dd379Sjsg
2067f4dd379Sjsg /**
2077f4dd379Sjsg * drm_mode_object_get - acquire a mode object reference
2087f4dd379Sjsg * @obj: DRM mode object
2097f4dd379Sjsg *
2107f4dd379Sjsg * This function increments the object's refcount if it is a refcounted modeset
2117f4dd379Sjsg * object. It is a no-op on any other object. References should be dropped again
2127f4dd379Sjsg * by calling drm_mode_object_put().
2137f4dd379Sjsg */
drm_mode_object_get(struct drm_mode_object * obj)2147f4dd379Sjsg void drm_mode_object_get(struct drm_mode_object *obj)
2157f4dd379Sjsg {
2167f4dd379Sjsg if (obj->free_cb) {
2177f4dd379Sjsg DRM_DEBUG("OBJ ID: %d (%d)\n", obj->id, kref_read(&obj->refcount));
2187f4dd379Sjsg kref_get(&obj->refcount);
2197f4dd379Sjsg }
2207f4dd379Sjsg }
2217f4dd379Sjsg EXPORT_SYMBOL(drm_mode_object_get);
2227f4dd379Sjsg
2237f4dd379Sjsg /**
2247f4dd379Sjsg * drm_object_attach_property - attach a property to a modeset object
2257f4dd379Sjsg * @obj: drm modeset object
2267f4dd379Sjsg * @property: property to attach
2277f4dd379Sjsg * @init_val: initial value of the property
2287f4dd379Sjsg *
2297f4dd379Sjsg * This attaches the given property to the modeset object with the given initial
2307f4dd379Sjsg * value. Currently this function cannot fail since the properties are stored in
2317f4dd379Sjsg * a statically sized array.
232c349dbc7Sjsg *
233c349dbc7Sjsg * Note that all properties must be attached before the object itself is
234c349dbc7Sjsg * registered and accessible from userspace.
2357f4dd379Sjsg */
drm_object_attach_property(struct drm_mode_object * obj,struct drm_property * property,uint64_t init_val)2367f4dd379Sjsg void drm_object_attach_property(struct drm_mode_object *obj,
2377f4dd379Sjsg struct drm_property *property,
2387f4dd379Sjsg uint64_t init_val)
2397f4dd379Sjsg {
2407f4dd379Sjsg int count = obj->properties->count;
241c349dbc7Sjsg struct drm_device *dev = property->dev;
242c349dbc7Sjsg
243c349dbc7Sjsg
244c349dbc7Sjsg if (obj->type == DRM_MODE_OBJECT_CONNECTOR) {
245c349dbc7Sjsg struct drm_connector *connector = obj_to_connector(obj);
246c349dbc7Sjsg
247c349dbc7Sjsg WARN_ON(!dev->driver->load &&
248c349dbc7Sjsg connector->registration_state == DRM_CONNECTOR_REGISTERED);
249c349dbc7Sjsg } else {
250c349dbc7Sjsg WARN_ON(!dev->driver->load && dev->registered);
251c349dbc7Sjsg }
2527f4dd379Sjsg
2537f4dd379Sjsg if (count == DRM_OBJECT_MAX_PROPERTY) {
2547f4dd379Sjsg WARN(1, "Failed to attach object property (type: 0x%x). Please "
2557f4dd379Sjsg "increase DRM_OBJECT_MAX_PROPERTY by 1 for each time "
2567f4dd379Sjsg "you see this message on the same object type.\n",
2577f4dd379Sjsg obj->type);
2587f4dd379Sjsg return;
2597f4dd379Sjsg }
2607f4dd379Sjsg
2617f4dd379Sjsg obj->properties->properties[count] = property;
2627f4dd379Sjsg obj->properties->values[count] = init_val;
2637f4dd379Sjsg obj->properties->count++;
2647f4dd379Sjsg }
2657f4dd379Sjsg EXPORT_SYMBOL(drm_object_attach_property);
2667f4dd379Sjsg
2677f4dd379Sjsg /**
2687f4dd379Sjsg * drm_object_property_set_value - set the value of a property
2697f4dd379Sjsg * @obj: drm mode object to set property value for
2707f4dd379Sjsg * @property: property to set
2717f4dd379Sjsg * @val: value the property should be set to
2727f4dd379Sjsg *
2737f4dd379Sjsg * This function sets a given property on a given object. This function only
2747f4dd379Sjsg * changes the software state of the property, it does not call into the
2757f4dd379Sjsg * driver's ->set_property callback.
2767f4dd379Sjsg *
2777f4dd379Sjsg * Note that atomic drivers should not have any need to call this, the core will
2787f4dd379Sjsg * ensure consistency of values reported back to userspace through the
2797f4dd379Sjsg * appropriate ->atomic_get_property callback. Only legacy drivers should call
2807f4dd379Sjsg * this function to update the tracked value (after clamping and other
2817f4dd379Sjsg * restrictions have been applied).
2827f4dd379Sjsg *
2837f4dd379Sjsg * Returns:
2847f4dd379Sjsg * Zero on success, error code on failure.
2857f4dd379Sjsg */
drm_object_property_set_value(struct drm_mode_object * obj,struct drm_property * property,uint64_t val)2867f4dd379Sjsg int drm_object_property_set_value(struct drm_mode_object *obj,
2877f4dd379Sjsg struct drm_property *property, uint64_t val)
2887f4dd379Sjsg {
2897f4dd379Sjsg int i;
2907f4dd379Sjsg
2917f4dd379Sjsg WARN_ON(drm_drv_uses_atomic_modeset(property->dev) &&
2927f4dd379Sjsg !(property->flags & DRM_MODE_PROP_IMMUTABLE));
2937f4dd379Sjsg
2947f4dd379Sjsg for (i = 0; i < obj->properties->count; i++) {
2957f4dd379Sjsg if (obj->properties->properties[i] == property) {
2967f4dd379Sjsg obj->properties->values[i] = val;
2977f4dd379Sjsg return 0;
2987f4dd379Sjsg }
2997f4dd379Sjsg }
3007f4dd379Sjsg
3017f4dd379Sjsg return -EINVAL;
3027f4dd379Sjsg }
3037f4dd379Sjsg EXPORT_SYMBOL(drm_object_property_set_value);
3047f4dd379Sjsg
__drm_object_property_get_prop_value(struct drm_mode_object * obj,struct drm_property * property,uint64_t * val)3051bb76ff1Sjsg static int __drm_object_property_get_prop_value(struct drm_mode_object *obj,
3067f4dd379Sjsg struct drm_property *property,
3077f4dd379Sjsg uint64_t *val)
3087f4dd379Sjsg {
3097f4dd379Sjsg int i;
3107f4dd379Sjsg
3111bb76ff1Sjsg for (i = 0; i < obj->properties->count; i++) {
3121bb76ff1Sjsg if (obj->properties->properties[i] == property) {
3131bb76ff1Sjsg *val = obj->properties->values[i];
3141bb76ff1Sjsg return 0;
3151bb76ff1Sjsg }
3161bb76ff1Sjsg }
3171bb76ff1Sjsg
3181bb76ff1Sjsg return -EINVAL;
3191bb76ff1Sjsg }
3201bb76ff1Sjsg
__drm_object_property_get_value(struct drm_mode_object * obj,struct drm_property * property,uint64_t * val)3211bb76ff1Sjsg static int __drm_object_property_get_value(struct drm_mode_object *obj,
3221bb76ff1Sjsg struct drm_property *property,
3231bb76ff1Sjsg uint64_t *val)
3241bb76ff1Sjsg {
3251bb76ff1Sjsg
3267f4dd379Sjsg #ifdef __OpenBSD__
3277f4dd379Sjsg if (obj->type == DRM_MODE_OBJECT_CONNECTOR) {
3287f4dd379Sjsg struct drm_connector *connector = obj_to_connector(obj);
3297f4dd379Sjsg
3307f4dd379Sjsg if (property == connector->backlight_property) {
3317f4dd379Sjsg struct backlight_device *bd =
3327f4dd379Sjsg connector->backlight_device;
3337f4dd379Sjsg
3347f4dd379Sjsg if (bd->props.type == BACKLIGHT_FIRMWARE)
3357f4dd379Sjsg *val = bd->ops->get_brightness(bd);
3367f4dd379Sjsg else
3377f4dd379Sjsg *val = bd->props.brightness;
3387f4dd379Sjsg return 0;
3397f4dd379Sjsg }
3407f4dd379Sjsg }
3417f4dd379Sjsg #endif
3427f4dd379Sjsg
3437f4dd379Sjsg /* read-only properties bypass atomic mechanism and still store
3447f4dd379Sjsg * their value in obj->properties->values[].. mostly to avoid
3457f4dd379Sjsg * having to deal w/ EDID and similar props in atomic paths:
3467f4dd379Sjsg */
3477f4dd379Sjsg if (drm_drv_uses_atomic_modeset(property->dev) &&
3487f4dd379Sjsg !(property->flags & DRM_MODE_PROP_IMMUTABLE))
3497f4dd379Sjsg return drm_atomic_get_property(obj, property, val);
3507f4dd379Sjsg
3511bb76ff1Sjsg return __drm_object_property_get_prop_value(obj, property, val);
3527f4dd379Sjsg }
3537f4dd379Sjsg
3547f4dd379Sjsg /**
3557f4dd379Sjsg * drm_object_property_get_value - retrieve the value of a property
3567f4dd379Sjsg * @obj: drm mode object to get property value from
3577f4dd379Sjsg * @property: property to retrieve
3587f4dd379Sjsg * @val: storage for the property value
3597f4dd379Sjsg *
3607f4dd379Sjsg * This function retrieves the softare state of the given property for the given
3617f4dd379Sjsg * property. Since there is no driver callback to retrieve the current property
3627f4dd379Sjsg * value this might be out of sync with the hardware, depending upon the driver
3637f4dd379Sjsg * and property.
3647f4dd379Sjsg *
3657f4dd379Sjsg * Atomic drivers should never call this function directly, the core will read
3667f4dd379Sjsg * out property values through the various ->atomic_get_property callbacks.
3677f4dd379Sjsg *
3687f4dd379Sjsg * Returns:
3697f4dd379Sjsg * Zero on success, error code on failure.
3707f4dd379Sjsg */
drm_object_property_get_value(struct drm_mode_object * obj,struct drm_property * property,uint64_t * val)3717f4dd379Sjsg int drm_object_property_get_value(struct drm_mode_object *obj,
3727f4dd379Sjsg struct drm_property *property, uint64_t *val)
3737f4dd379Sjsg {
3747f4dd379Sjsg WARN_ON(drm_drv_uses_atomic_modeset(property->dev));
3757f4dd379Sjsg
3767f4dd379Sjsg return __drm_object_property_get_value(obj, property, val);
3777f4dd379Sjsg }
3787f4dd379Sjsg EXPORT_SYMBOL(drm_object_property_get_value);
3797f4dd379Sjsg
3801bb76ff1Sjsg /**
3811bb76ff1Sjsg * drm_object_property_get_default_value - retrieve the default value of a
3821bb76ff1Sjsg * property when in atomic mode.
3831bb76ff1Sjsg * @obj: drm mode object to get property value from
3841bb76ff1Sjsg * @property: property to retrieve
3851bb76ff1Sjsg * @val: storage for the property value
3861bb76ff1Sjsg *
3871bb76ff1Sjsg * This function retrieves the default state of the given property as passed in
3881bb76ff1Sjsg * to drm_object_attach_property
3891bb76ff1Sjsg *
3901bb76ff1Sjsg * Only atomic drivers should call this function directly, as for non-atomic
3911bb76ff1Sjsg * drivers it will return the current value.
3921bb76ff1Sjsg *
3931bb76ff1Sjsg * Returns:
3941bb76ff1Sjsg * Zero on success, error code on failure.
3951bb76ff1Sjsg */
drm_object_property_get_default_value(struct drm_mode_object * obj,struct drm_property * property,uint64_t * val)3961bb76ff1Sjsg int drm_object_property_get_default_value(struct drm_mode_object *obj,
3971bb76ff1Sjsg struct drm_property *property,
3981bb76ff1Sjsg uint64_t *val)
3991bb76ff1Sjsg {
4001bb76ff1Sjsg WARN_ON(!drm_drv_uses_atomic_modeset(property->dev));
4011bb76ff1Sjsg
4021bb76ff1Sjsg return __drm_object_property_get_prop_value(obj, property, val);
4031bb76ff1Sjsg }
4041bb76ff1Sjsg EXPORT_SYMBOL(drm_object_property_get_default_value);
4051bb76ff1Sjsg
4067f4dd379Sjsg /* helper for getconnector and getproperties ioctls */
drm_mode_object_get_properties(struct drm_mode_object * obj,bool atomic,uint32_t __user * prop_ptr,uint64_t __user * prop_values,uint32_t * arg_count_props)4077f4dd379Sjsg int drm_mode_object_get_properties(struct drm_mode_object *obj, bool atomic,
4087f4dd379Sjsg uint32_t __user *prop_ptr,
4097f4dd379Sjsg uint64_t __user *prop_values,
4107f4dd379Sjsg uint32_t *arg_count_props)
4117f4dd379Sjsg {
4127f4dd379Sjsg int i, ret, count;
4137f4dd379Sjsg
4147f4dd379Sjsg for (i = 0, count = 0; i < obj->properties->count; i++) {
4157f4dd379Sjsg struct drm_property *prop = obj->properties->properties[i];
4167f4dd379Sjsg uint64_t val;
4177f4dd379Sjsg
4187f4dd379Sjsg if ((prop->flags & DRM_MODE_PROP_ATOMIC) && !atomic)
4197f4dd379Sjsg continue;
4207f4dd379Sjsg
4217f4dd379Sjsg if (*arg_count_props > count) {
4227f4dd379Sjsg ret = __drm_object_property_get_value(obj, prop, &val);
4237f4dd379Sjsg if (ret)
4247f4dd379Sjsg return ret;
4257f4dd379Sjsg
4267f4dd379Sjsg if (put_user(prop->base.id, prop_ptr + count))
4277f4dd379Sjsg return -EFAULT;
4287f4dd379Sjsg
4297f4dd379Sjsg if (put_user(val, prop_values + count))
4307f4dd379Sjsg return -EFAULT;
4317f4dd379Sjsg }
4327f4dd379Sjsg
4337f4dd379Sjsg count++;
4347f4dd379Sjsg }
4357f4dd379Sjsg *arg_count_props = count;
4367f4dd379Sjsg
4377f4dd379Sjsg return 0;
4387f4dd379Sjsg }
4397f4dd379Sjsg
4407f4dd379Sjsg /**
4417f4dd379Sjsg * drm_mode_obj_get_properties_ioctl - get the current value of a object's property
4427f4dd379Sjsg * @dev: DRM device
4437f4dd379Sjsg * @data: ioctl data
4447f4dd379Sjsg * @file_priv: DRM file info
4457f4dd379Sjsg *
4467f4dd379Sjsg * This function retrieves the current value for an object's property. Compared
4477f4dd379Sjsg * to the connector specific ioctl this one is extended to also work on crtc and
4487f4dd379Sjsg * plane objects.
4497f4dd379Sjsg *
4507f4dd379Sjsg * Called by the user via ioctl.
4517f4dd379Sjsg *
4527f4dd379Sjsg * Returns:
4537f4dd379Sjsg * Zero on success, negative errno on failure.
4547f4dd379Sjsg */
drm_mode_obj_get_properties_ioctl(struct drm_device * dev,void * data,struct drm_file * file_priv)4557f4dd379Sjsg int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data,
4567f4dd379Sjsg struct drm_file *file_priv)
4577f4dd379Sjsg {
4587f4dd379Sjsg struct drm_mode_obj_get_properties *arg = data;
4597f4dd379Sjsg struct drm_mode_object *obj;
460ad8b1aafSjsg struct drm_modeset_acquire_ctx ctx;
4617f4dd379Sjsg int ret = 0;
4627f4dd379Sjsg
4637f4dd379Sjsg if (!drm_core_check_feature(dev, DRIVER_MODESET))
464c349dbc7Sjsg return -EOPNOTSUPP;
4657f4dd379Sjsg
466ad8b1aafSjsg DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret);
4677f4dd379Sjsg
4687f4dd379Sjsg obj = drm_mode_object_find(dev, file_priv, arg->obj_id, arg->obj_type);
4697f4dd379Sjsg if (!obj) {
4707f4dd379Sjsg ret = -ENOENT;
4717f4dd379Sjsg goto out;
4727f4dd379Sjsg }
4737f4dd379Sjsg if (!obj->properties) {
4747f4dd379Sjsg ret = -EINVAL;
4757f4dd379Sjsg goto out_unref;
4767f4dd379Sjsg }
4777f4dd379Sjsg
4787f4dd379Sjsg ret = drm_mode_object_get_properties(obj, file_priv->atomic,
4797f4dd379Sjsg (uint32_t __user *)(unsigned long)(arg->props_ptr),
4807f4dd379Sjsg (uint64_t __user *)(unsigned long)(arg->prop_values_ptr),
4817f4dd379Sjsg &arg->count_props);
4827f4dd379Sjsg
4837f4dd379Sjsg out_unref:
4847f4dd379Sjsg drm_mode_object_put(obj);
4857f4dd379Sjsg out:
486ad8b1aafSjsg DRM_MODESET_LOCK_ALL_END(dev, ctx, ret);
4877f4dd379Sjsg return ret;
4887f4dd379Sjsg }
4897f4dd379Sjsg
drm_mode_obj_find_prop_id(struct drm_mode_object * obj,uint32_t prop_id)4907f4dd379Sjsg struct drm_property *drm_mode_obj_find_prop_id(struct drm_mode_object *obj,
4917f4dd379Sjsg uint32_t prop_id)
4927f4dd379Sjsg {
4937f4dd379Sjsg int i;
4947f4dd379Sjsg
4957f4dd379Sjsg for (i = 0; i < obj->properties->count; i++)
4967f4dd379Sjsg if (obj->properties->properties[i]->base.id == prop_id)
4977f4dd379Sjsg return obj->properties->properties[i];
4987f4dd379Sjsg
4997f4dd379Sjsg return NULL;
5007f4dd379Sjsg }
5017f4dd379Sjsg
set_property_legacy(struct drm_mode_object * obj,struct drm_property * prop,uint64_t prop_value)5027f4dd379Sjsg static int set_property_legacy(struct drm_mode_object *obj,
5037f4dd379Sjsg struct drm_property *prop,
5047f4dd379Sjsg uint64_t prop_value)
5057f4dd379Sjsg {
5067f4dd379Sjsg struct drm_device *dev = prop->dev;
5077f4dd379Sjsg struct drm_mode_object *ref;
508ad8b1aafSjsg struct drm_modeset_acquire_ctx ctx;
5097f4dd379Sjsg int ret = -EINVAL;
5107f4dd379Sjsg
5117f4dd379Sjsg if (!drm_property_change_valid_get(prop, prop_value, &ref))
5127f4dd379Sjsg return -EINVAL;
5137f4dd379Sjsg
514ad8b1aafSjsg DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret);
5157f4dd379Sjsg switch (obj->type) {
5167f4dd379Sjsg case DRM_MODE_OBJECT_CONNECTOR:
5177f4dd379Sjsg ret = drm_connector_set_obj_prop(obj, prop, prop_value);
5187f4dd379Sjsg break;
5197f4dd379Sjsg case DRM_MODE_OBJECT_CRTC:
5207f4dd379Sjsg ret = drm_mode_crtc_set_obj_prop(obj, prop, prop_value);
5217f4dd379Sjsg break;
5227f4dd379Sjsg case DRM_MODE_OBJECT_PLANE:
5237f4dd379Sjsg ret = drm_mode_plane_set_obj_prop(obj_to_plane(obj),
5247f4dd379Sjsg prop, prop_value);
5257f4dd379Sjsg break;
5267f4dd379Sjsg }
5277f4dd379Sjsg drm_property_change_valid_put(prop, ref);
528ad8b1aafSjsg DRM_MODESET_LOCK_ALL_END(dev, ctx, ret);
5297f4dd379Sjsg
5307f4dd379Sjsg return ret;
5317f4dd379Sjsg }
5327f4dd379Sjsg
set_property_atomic(struct drm_mode_object * obj,struct drm_file * file_priv,struct drm_property * prop,uint64_t prop_value)5337f4dd379Sjsg static int set_property_atomic(struct drm_mode_object *obj,
534c349dbc7Sjsg struct drm_file *file_priv,
5357f4dd379Sjsg struct drm_property *prop,
5367f4dd379Sjsg uint64_t prop_value)
5377f4dd379Sjsg {
5387f4dd379Sjsg struct drm_device *dev = prop->dev;
5397f4dd379Sjsg struct drm_atomic_state *state;
5407f4dd379Sjsg struct drm_modeset_acquire_ctx ctx;
5417f4dd379Sjsg int ret;
5427f4dd379Sjsg
5437f4dd379Sjsg state = drm_atomic_state_alloc(dev);
5447f4dd379Sjsg if (!state)
5457f4dd379Sjsg return -ENOMEM;
5467f4dd379Sjsg
5477f4dd379Sjsg drm_modeset_acquire_init(&ctx, 0);
5487f4dd379Sjsg state->acquire_ctx = &ctx;
5497f4dd379Sjsg
5507f4dd379Sjsg retry:
5517f4dd379Sjsg if (prop == state->dev->mode_config.dpms_property) {
5527f4dd379Sjsg if (obj->type != DRM_MODE_OBJECT_CONNECTOR) {
5537f4dd379Sjsg ret = -EINVAL;
5547f4dd379Sjsg goto out;
5557f4dd379Sjsg }
5567f4dd379Sjsg
5577f4dd379Sjsg ret = drm_atomic_connector_commit_dpms(state,
5587f4dd379Sjsg obj_to_connector(obj),
5597f4dd379Sjsg prop_value);
5607f4dd379Sjsg #ifdef __OpenBSD__
5617f4dd379Sjsg } else if (obj->type == DRM_MODE_OBJECT_CONNECTOR &&
5627f4dd379Sjsg prop == (obj_to_connector(obj))->backlight_property) {
5637f4dd379Sjsg struct drm_connector *connector = obj_to_connector(obj);
5647f4dd379Sjsg connector->backlight_device->props.brightness = prop_value;
5657f4dd379Sjsg backlight_schedule_update_status(connector->backlight_device);
566c78098b6Svisa knote_locked(&connector->dev->note, NOTE_CHANGE);
5677f4dd379Sjsg ret = 0;
5687f4dd379Sjsg #endif
5697f4dd379Sjsg } else {
570c349dbc7Sjsg ret = drm_atomic_set_property(state, file_priv, obj, prop, prop_value);
5717f4dd379Sjsg if (ret)
5727f4dd379Sjsg goto out;
5737f4dd379Sjsg ret = drm_atomic_commit(state);
5747f4dd379Sjsg }
5757f4dd379Sjsg out:
5767f4dd379Sjsg if (ret == -EDEADLK) {
5777f4dd379Sjsg drm_atomic_state_clear(state);
5787f4dd379Sjsg drm_modeset_backoff(&ctx);
5797f4dd379Sjsg goto retry;
5807f4dd379Sjsg }
5817f4dd379Sjsg
5827f4dd379Sjsg drm_atomic_state_put(state);
5837f4dd379Sjsg
5847f4dd379Sjsg drm_modeset_drop_locks(&ctx);
5857f4dd379Sjsg drm_modeset_acquire_fini(&ctx);
5867f4dd379Sjsg
5877f4dd379Sjsg return ret;
5887f4dd379Sjsg }
5897f4dd379Sjsg
drm_mode_obj_set_property_ioctl(struct drm_device * dev,void * data,struct drm_file * file_priv)5907f4dd379Sjsg int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data,
5917f4dd379Sjsg struct drm_file *file_priv)
5927f4dd379Sjsg {
5937f4dd379Sjsg struct drm_mode_obj_set_property *arg = data;
5947f4dd379Sjsg struct drm_mode_object *arg_obj;
5957f4dd379Sjsg struct drm_property *property;
5967f4dd379Sjsg int ret = -EINVAL;
5977f4dd379Sjsg
5987f4dd379Sjsg if (!drm_core_check_feature(dev, DRIVER_MODESET))
599c349dbc7Sjsg return -EOPNOTSUPP;
6007f4dd379Sjsg
6017f4dd379Sjsg arg_obj = drm_mode_object_find(dev, file_priv, arg->obj_id, arg->obj_type);
6027f4dd379Sjsg if (!arg_obj)
6037f4dd379Sjsg return -ENOENT;
6047f4dd379Sjsg
6057f4dd379Sjsg if (!arg_obj->properties)
6067f4dd379Sjsg goto out_unref;
6077f4dd379Sjsg
6087f4dd379Sjsg property = drm_mode_obj_find_prop_id(arg_obj, arg->prop_id);
6097f4dd379Sjsg if (!property)
6107f4dd379Sjsg goto out_unref;
6117f4dd379Sjsg
6127f4dd379Sjsg if (drm_drv_uses_atomic_modeset(property->dev))
613c349dbc7Sjsg ret = set_property_atomic(arg_obj, file_priv, property, arg->value);
6147f4dd379Sjsg else
6157f4dd379Sjsg ret = set_property_legacy(arg_obj, property, arg->value);
6167f4dd379Sjsg
6177f4dd379Sjsg out_unref:
6187f4dd379Sjsg drm_mode_object_put(arg_obj);
6197f4dd379Sjsg return ret;
6207f4dd379Sjsg }
621