xref: /openbmc/linux/drivers/gpu/drm/drm_property.c (revision 69fdf420)
159e71ee7SDaniel Vetter /*
259e71ee7SDaniel Vetter  * Copyright (c) 2016 Intel Corporation
359e71ee7SDaniel Vetter  *
459e71ee7SDaniel Vetter  * Permission to use, copy, modify, distribute, and sell this software and its
559e71ee7SDaniel Vetter  * documentation for any purpose is hereby granted without fee, provided that
659e71ee7SDaniel Vetter  * the above copyright notice appear in all copies and that both that copyright
759e71ee7SDaniel Vetter  * notice and this permission notice appear in supporting documentation, and
859e71ee7SDaniel Vetter  * that the name of the copyright holders not be used in advertising or
959e71ee7SDaniel Vetter  * publicity pertaining to distribution of the software without specific,
1059e71ee7SDaniel Vetter  * written prior permission.  The copyright holders make no representations
1159e71ee7SDaniel Vetter  * about the suitability of this software for any purpose.  It is provided "as
1259e71ee7SDaniel Vetter  * is" without express or implied warranty.
1359e71ee7SDaniel Vetter  *
1459e71ee7SDaniel Vetter  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
1559e71ee7SDaniel Vetter  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
1659e71ee7SDaniel Vetter  * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
1759e71ee7SDaniel Vetter  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
1859e71ee7SDaniel Vetter  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
1959e71ee7SDaniel Vetter  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
2059e71ee7SDaniel Vetter  * OF THIS SOFTWARE.
2159e71ee7SDaniel Vetter  */
2259e71ee7SDaniel Vetter 
2359e71ee7SDaniel Vetter #include <linux/export.h>
2459e71ee7SDaniel Vetter #include <drm/drmP.h>
2559e71ee7SDaniel Vetter #include <drm/drm_property.h>
2659e71ee7SDaniel Vetter 
2759e71ee7SDaniel Vetter #include "drm_crtc_internal.h"
2859e71ee7SDaniel Vetter 
29c8458c7eSDaniel Vetter /**
30c8458c7eSDaniel Vetter  * DOC: overview
31c8458c7eSDaniel Vetter  *
32c8458c7eSDaniel Vetter  * Properties as represented by &drm_property are used to extend the modeset
33c8458c7eSDaniel Vetter  * interface exposed to userspace. For the atomic modeset IOCTL properties are
34c8458c7eSDaniel Vetter  * even the only way to transport metadata about the desired new modeset
35c8458c7eSDaniel Vetter  * configuration from userspace to the kernel. Properties have a well-defined
36c8458c7eSDaniel Vetter  * value range, which is enforced by the drm core. See the documentation of the
37ea0dd85aSDaniel Vetter  * flags member of &struct drm_property for an overview of the different
38c8458c7eSDaniel Vetter  * property types and ranges.
39c8458c7eSDaniel Vetter  *
40c8458c7eSDaniel Vetter  * Properties don't store the current value directly, but need to be
41c8458c7eSDaniel Vetter  * instatiated by attaching them to a &drm_mode_object with
42c8458c7eSDaniel Vetter  * drm_object_attach_property().
43c8458c7eSDaniel Vetter  *
44c8458c7eSDaniel Vetter  * Property values are only 64bit. To support bigger piles of data (like gamma
45d574528aSDaniel Vetter  * tables, color correction matrices or large structures) a property can instead
46d574528aSDaniel Vetter  * point at a &drm_property_blob with that additional data.
47c8458c7eSDaniel Vetter  *
48c8458c7eSDaniel Vetter  * Properties are defined by their symbolic name, userspace must keep a
49c8458c7eSDaniel Vetter  * per-object mapping from those names to the property ID used in the atomic
50c8458c7eSDaniel Vetter  * IOCTL and in the get/set property IOCTL.
51c8458c7eSDaniel Vetter  */
52c8458c7eSDaniel Vetter 
53100bc0d9SVille Syrjälä static bool drm_property_flags_valid(u32 flags)
5459e71ee7SDaniel Vetter {
55100bc0d9SVille Syrjälä 	u32 legacy_type = flags & DRM_MODE_PROP_LEGACY_TYPE;
56100bc0d9SVille Syrjälä 	u32 ext_type = flags & DRM_MODE_PROP_EXTENDED_TYPE;
57100bc0d9SVille Syrjälä 
58100bc0d9SVille Syrjälä 	/* Reject undefined/deprecated flags */
59100bc0d9SVille Syrjälä 	if (flags & ~(DRM_MODE_PROP_LEGACY_TYPE |
60100bc0d9SVille Syrjälä 		      DRM_MODE_PROP_EXTENDED_TYPE |
61100bc0d9SVille Syrjälä 		      DRM_MODE_PROP_IMMUTABLE |
62100bc0d9SVille Syrjälä 		      DRM_MODE_PROP_ATOMIC))
63100bc0d9SVille Syrjälä 		return false;
64100bc0d9SVille Syrjälä 
65100bc0d9SVille Syrjälä 	/* We want either a legacy type or an extended type, but not both */
66100bc0d9SVille Syrjälä 	if (!legacy_type == !ext_type)
67100bc0d9SVille Syrjälä 		return false;
68100bc0d9SVille Syrjälä 
69100bc0d9SVille Syrjälä 	/* Only one legacy type at a time please */
70100bc0d9SVille Syrjälä 	if (legacy_type && !is_power_of_2(legacy_type))
71100bc0d9SVille Syrjälä 		return false;
72100bc0d9SVille Syrjälä 
73100bc0d9SVille Syrjälä 	return true;
7459e71ee7SDaniel Vetter }
7559e71ee7SDaniel Vetter 
7659e71ee7SDaniel Vetter /**
7759e71ee7SDaniel Vetter  * drm_property_create - create a new property type
7859e71ee7SDaniel Vetter  * @dev: drm device
7959e71ee7SDaniel Vetter  * @flags: flags specifying the property type
8059e71ee7SDaniel Vetter  * @name: name of the property
8159e71ee7SDaniel Vetter  * @num_values: number of pre-defined values
8259e71ee7SDaniel Vetter  *
8359e71ee7SDaniel Vetter  * This creates a new generic drm property which can then be attached to a drm
846a8a66edSDaniel Vetter  * object with drm_object_attach_property(). The returned property object must
856a8a66edSDaniel Vetter  * be freed with drm_property_destroy(), which is done automatically when
866a8a66edSDaniel Vetter  * calling drm_mode_config_cleanup().
8759e71ee7SDaniel Vetter  *
8859e71ee7SDaniel Vetter  * Returns:
8959e71ee7SDaniel Vetter  * A pointer to the newly created property on success, NULL on failure.
9059e71ee7SDaniel Vetter  */
9151abc976SVille Syrjälä struct drm_property *drm_property_create(struct drm_device *dev,
9251abc976SVille Syrjälä 					 u32 flags, const char *name,
9351abc976SVille Syrjälä 					 int num_values)
9459e71ee7SDaniel Vetter {
9559e71ee7SDaniel Vetter 	struct drm_property *property = NULL;
9659e71ee7SDaniel Vetter 	int ret;
9759e71ee7SDaniel Vetter 
98100bc0d9SVille Syrjälä 	if (WARN_ON(!drm_property_flags_valid(flags)))
99100bc0d9SVille Syrjälä 		return NULL;
100100bc0d9SVille Syrjälä 
1015ebbb5b4SVille Syrjälä 	if (WARN_ON(strlen(name) >= DRM_PROP_NAME_LEN))
1025ebbb5b4SVille Syrjälä 		return NULL;
1035ebbb5b4SVille Syrjälä 
10459e71ee7SDaniel Vetter 	property = kzalloc(sizeof(struct drm_property), GFP_KERNEL);
10559e71ee7SDaniel Vetter 	if (!property)
10659e71ee7SDaniel Vetter 		return NULL;
10759e71ee7SDaniel Vetter 
10859e71ee7SDaniel Vetter 	property->dev = dev;
10959e71ee7SDaniel Vetter 
11059e71ee7SDaniel Vetter 	if (num_values) {
11159e71ee7SDaniel Vetter 		property->values = kcalloc(num_values, sizeof(uint64_t),
11259e71ee7SDaniel Vetter 					   GFP_KERNEL);
11359e71ee7SDaniel Vetter 		if (!property->values)
11459e71ee7SDaniel Vetter 			goto fail;
11559e71ee7SDaniel Vetter 	}
11659e71ee7SDaniel Vetter 
1172135ea7aSThierry Reding 	ret = drm_mode_object_add(dev, &property->base, DRM_MODE_OBJECT_PROPERTY);
11859e71ee7SDaniel Vetter 	if (ret)
11959e71ee7SDaniel Vetter 		goto fail;
12059e71ee7SDaniel Vetter 
12159e71ee7SDaniel Vetter 	property->flags = flags;
12259e71ee7SDaniel Vetter 	property->num_values = num_values;
12359e71ee7SDaniel Vetter 	INIT_LIST_HEAD(&property->enum_list);
12459e71ee7SDaniel Vetter 
12559e71ee7SDaniel Vetter 	strncpy(property->name, name, DRM_PROP_NAME_LEN);
12659e71ee7SDaniel Vetter 	property->name[DRM_PROP_NAME_LEN-1] = '\0';
12759e71ee7SDaniel Vetter 
12859e71ee7SDaniel Vetter 	list_add_tail(&property->head, &dev->mode_config.property_list);
12959e71ee7SDaniel Vetter 
13059e71ee7SDaniel Vetter 	return property;
13159e71ee7SDaniel Vetter fail:
13259e71ee7SDaniel Vetter 	kfree(property->values);
13359e71ee7SDaniel Vetter 	kfree(property);
13459e71ee7SDaniel Vetter 	return NULL;
13559e71ee7SDaniel Vetter }
13659e71ee7SDaniel Vetter EXPORT_SYMBOL(drm_property_create);
13759e71ee7SDaniel Vetter 
13859e71ee7SDaniel Vetter /**
13959e71ee7SDaniel Vetter  * drm_property_create_enum - create a new enumeration property type
14059e71ee7SDaniel Vetter  * @dev: drm device
14159e71ee7SDaniel Vetter  * @flags: flags specifying the property type
14259e71ee7SDaniel Vetter  * @name: name of the property
14359e71ee7SDaniel Vetter  * @props: enumeration lists with property values
14459e71ee7SDaniel Vetter  * @num_values: number of pre-defined values
14559e71ee7SDaniel Vetter  *
14659e71ee7SDaniel Vetter  * This creates a new generic drm property which can then be attached to a drm
1476a8a66edSDaniel Vetter  * object with drm_object_attach_property(). The returned property object must
1486a8a66edSDaniel Vetter  * be freed with drm_property_destroy(), which is done automatically when
1496a8a66edSDaniel Vetter  * calling drm_mode_config_cleanup().
15059e71ee7SDaniel Vetter  *
15159e71ee7SDaniel Vetter  * Userspace is only allowed to set one of the predefined values for enumeration
15259e71ee7SDaniel Vetter  * properties.
15359e71ee7SDaniel Vetter  *
15459e71ee7SDaniel Vetter  * Returns:
15559e71ee7SDaniel Vetter  * A pointer to the newly created property on success, NULL on failure.
15659e71ee7SDaniel Vetter  */
15751abc976SVille Syrjälä struct drm_property *drm_property_create_enum(struct drm_device *dev,
15851abc976SVille Syrjälä 					      u32 flags, const char *name,
15959e71ee7SDaniel Vetter 					      const struct drm_prop_enum_list *props,
16059e71ee7SDaniel Vetter 					      int num_values)
16159e71ee7SDaniel Vetter {
16259e71ee7SDaniel Vetter 	struct drm_property *property;
16359e71ee7SDaniel Vetter 	int i, ret;
16459e71ee7SDaniel Vetter 
16559e71ee7SDaniel Vetter 	flags |= DRM_MODE_PROP_ENUM;
16659e71ee7SDaniel Vetter 
16759e71ee7SDaniel Vetter 	property = drm_property_create(dev, flags, name, num_values);
16859e71ee7SDaniel Vetter 	if (!property)
16959e71ee7SDaniel Vetter 		return NULL;
17059e71ee7SDaniel Vetter 
17159e71ee7SDaniel Vetter 	for (i = 0; i < num_values; i++) {
17230e9db6dSVille Syrjälä 		ret = drm_property_add_enum(property,
17359e71ee7SDaniel Vetter 					    props[i].type,
17459e71ee7SDaniel Vetter 					    props[i].name);
17559e71ee7SDaniel Vetter 		if (ret) {
17659e71ee7SDaniel Vetter 			drm_property_destroy(dev, property);
17759e71ee7SDaniel Vetter 			return NULL;
17859e71ee7SDaniel Vetter 		}
17959e71ee7SDaniel Vetter 	}
18059e71ee7SDaniel Vetter 
18159e71ee7SDaniel Vetter 	return property;
18259e71ee7SDaniel Vetter }
18359e71ee7SDaniel Vetter EXPORT_SYMBOL(drm_property_create_enum);
18459e71ee7SDaniel Vetter 
18559e71ee7SDaniel Vetter /**
18659e71ee7SDaniel Vetter  * drm_property_create_bitmask - create a new bitmask property type
18759e71ee7SDaniel Vetter  * @dev: drm device
18859e71ee7SDaniel Vetter  * @flags: flags specifying the property type
18959e71ee7SDaniel Vetter  * @name: name of the property
19059e71ee7SDaniel Vetter  * @props: enumeration lists with property bitflags
19159e71ee7SDaniel Vetter  * @num_props: size of the @props array
19259e71ee7SDaniel Vetter  * @supported_bits: bitmask of all supported enumeration values
19359e71ee7SDaniel Vetter  *
19459e71ee7SDaniel Vetter  * This creates a new bitmask drm property which can then be attached to a drm
1956a8a66edSDaniel Vetter  * object with drm_object_attach_property(). The returned property object must
1966a8a66edSDaniel Vetter  * be freed with drm_property_destroy(), which is done automatically when
1976a8a66edSDaniel Vetter  * calling drm_mode_config_cleanup().
19859e71ee7SDaniel Vetter  *
19959e71ee7SDaniel Vetter  * Compared to plain enumeration properties userspace is allowed to set any
20059e71ee7SDaniel Vetter  * or'ed together combination of the predefined property bitflag values
20159e71ee7SDaniel Vetter  *
20259e71ee7SDaniel Vetter  * Returns:
20359e71ee7SDaniel Vetter  * A pointer to the newly created property on success, NULL on failure.
20459e71ee7SDaniel Vetter  */
20559e71ee7SDaniel Vetter struct drm_property *drm_property_create_bitmask(struct drm_device *dev,
20651abc976SVille Syrjälä 						 u32 flags, const char *name,
20759e71ee7SDaniel Vetter 						 const struct drm_prop_enum_list *props,
20859e71ee7SDaniel Vetter 						 int num_props,
20959e71ee7SDaniel Vetter 						 uint64_t supported_bits)
21059e71ee7SDaniel Vetter {
21159e71ee7SDaniel Vetter 	struct drm_property *property;
21230e9db6dSVille Syrjälä 	int i, ret;
21359e71ee7SDaniel Vetter 	int num_values = hweight64(supported_bits);
21459e71ee7SDaniel Vetter 
21559e71ee7SDaniel Vetter 	flags |= DRM_MODE_PROP_BITMASK;
21659e71ee7SDaniel Vetter 
21759e71ee7SDaniel Vetter 	property = drm_property_create(dev, flags, name, num_values);
21859e71ee7SDaniel Vetter 	if (!property)
21959e71ee7SDaniel Vetter 		return NULL;
22059e71ee7SDaniel Vetter 	for (i = 0; i < num_props; i++) {
22159e71ee7SDaniel Vetter 		if (!(supported_bits & (1ULL << props[i].type)))
22259e71ee7SDaniel Vetter 			continue;
22359e71ee7SDaniel Vetter 
22430e9db6dSVille Syrjälä 		ret = drm_property_add_enum(property,
22559e71ee7SDaniel Vetter 					    props[i].type,
22659e71ee7SDaniel Vetter 					    props[i].name);
22759e71ee7SDaniel Vetter 		if (ret) {
22859e71ee7SDaniel Vetter 			drm_property_destroy(dev, property);
22959e71ee7SDaniel Vetter 			return NULL;
23059e71ee7SDaniel Vetter 		}
23159e71ee7SDaniel Vetter 	}
23259e71ee7SDaniel Vetter 
23359e71ee7SDaniel Vetter 	return property;
23459e71ee7SDaniel Vetter }
23559e71ee7SDaniel Vetter EXPORT_SYMBOL(drm_property_create_bitmask);
23659e71ee7SDaniel Vetter 
23759e71ee7SDaniel Vetter static struct drm_property *property_create_range(struct drm_device *dev,
23851abc976SVille Syrjälä 						  u32 flags, const char *name,
23959e71ee7SDaniel Vetter 						  uint64_t min, uint64_t max)
24059e71ee7SDaniel Vetter {
24159e71ee7SDaniel Vetter 	struct drm_property *property;
24259e71ee7SDaniel Vetter 
24359e71ee7SDaniel Vetter 	property = drm_property_create(dev, flags, name, 2);
24459e71ee7SDaniel Vetter 	if (!property)
24559e71ee7SDaniel Vetter 		return NULL;
24659e71ee7SDaniel Vetter 
24759e71ee7SDaniel Vetter 	property->values[0] = min;
24859e71ee7SDaniel Vetter 	property->values[1] = max;
24959e71ee7SDaniel Vetter 
25059e71ee7SDaniel Vetter 	return property;
25159e71ee7SDaniel Vetter }
25259e71ee7SDaniel Vetter 
25359e71ee7SDaniel Vetter /**
25459e71ee7SDaniel Vetter  * drm_property_create_range - create a new unsigned ranged property type
25559e71ee7SDaniel Vetter  * @dev: drm device
25659e71ee7SDaniel Vetter  * @flags: flags specifying the property type
25759e71ee7SDaniel Vetter  * @name: name of the property
25859e71ee7SDaniel Vetter  * @min: minimum value of the property
25959e71ee7SDaniel Vetter  * @max: maximum value of the property
26059e71ee7SDaniel Vetter  *
26159e71ee7SDaniel Vetter  * This creates a new generic drm property which can then be attached to a drm
2626a8a66edSDaniel Vetter  * object with drm_object_attach_property(). The returned property object must
2636a8a66edSDaniel Vetter  * be freed with drm_property_destroy(), which is done automatically when
2646a8a66edSDaniel Vetter  * calling drm_mode_config_cleanup().
26559e71ee7SDaniel Vetter  *
26659e71ee7SDaniel Vetter  * Userspace is allowed to set any unsigned integer value in the (min, max)
26759e71ee7SDaniel Vetter  * range inclusive.
26859e71ee7SDaniel Vetter  *
26959e71ee7SDaniel Vetter  * Returns:
27059e71ee7SDaniel Vetter  * A pointer to the newly created property on success, NULL on failure.
27159e71ee7SDaniel Vetter  */
27251abc976SVille Syrjälä struct drm_property *drm_property_create_range(struct drm_device *dev,
27351abc976SVille Syrjälä 					       u32 flags, const char *name,
27459e71ee7SDaniel Vetter 					       uint64_t min, uint64_t max)
27559e71ee7SDaniel Vetter {
27659e71ee7SDaniel Vetter 	return property_create_range(dev, DRM_MODE_PROP_RANGE | flags,
27759e71ee7SDaniel Vetter 			name, min, max);
27859e71ee7SDaniel Vetter }
27959e71ee7SDaniel Vetter EXPORT_SYMBOL(drm_property_create_range);
28059e71ee7SDaniel Vetter 
28159e71ee7SDaniel Vetter /**
28259e71ee7SDaniel Vetter  * drm_property_create_signed_range - create a new signed ranged property type
28359e71ee7SDaniel Vetter  * @dev: drm device
28459e71ee7SDaniel Vetter  * @flags: flags specifying the property type
28559e71ee7SDaniel Vetter  * @name: name of the property
28659e71ee7SDaniel Vetter  * @min: minimum value of the property
28759e71ee7SDaniel Vetter  * @max: maximum value of the property
28859e71ee7SDaniel Vetter  *
28959e71ee7SDaniel Vetter  * This creates a new generic drm property which can then be attached to a drm
2906a8a66edSDaniel Vetter  * object with drm_object_attach_property(). The returned property object must
2916a8a66edSDaniel Vetter  * be freed with drm_property_destroy(), which is done automatically when
2926a8a66edSDaniel Vetter  * calling drm_mode_config_cleanup().
29359e71ee7SDaniel Vetter  *
29459e71ee7SDaniel Vetter  * Userspace is allowed to set any signed integer value in the (min, max)
29559e71ee7SDaniel Vetter  * range inclusive.
29659e71ee7SDaniel Vetter  *
29759e71ee7SDaniel Vetter  * Returns:
29859e71ee7SDaniel Vetter  * A pointer to the newly created property on success, NULL on failure.
29959e71ee7SDaniel Vetter  */
30059e71ee7SDaniel Vetter struct drm_property *drm_property_create_signed_range(struct drm_device *dev,
30151abc976SVille Syrjälä 						      u32 flags, const char *name,
30259e71ee7SDaniel Vetter 						      int64_t min, int64_t max)
30359e71ee7SDaniel Vetter {
30459e71ee7SDaniel Vetter 	return property_create_range(dev, DRM_MODE_PROP_SIGNED_RANGE | flags,
30559e71ee7SDaniel Vetter 			name, I642U64(min), I642U64(max));
30659e71ee7SDaniel Vetter }
30759e71ee7SDaniel Vetter EXPORT_SYMBOL(drm_property_create_signed_range);
30859e71ee7SDaniel Vetter 
30959e71ee7SDaniel Vetter /**
31059e71ee7SDaniel Vetter  * drm_property_create_object - create a new object property type
31159e71ee7SDaniel Vetter  * @dev: drm device
31259e71ee7SDaniel Vetter  * @flags: flags specifying the property type
31359e71ee7SDaniel Vetter  * @name: name of the property
31459e71ee7SDaniel Vetter  * @type: object type from DRM_MODE_OBJECT_* defines
31559e71ee7SDaniel Vetter  *
31659e71ee7SDaniel Vetter  * This creates a new generic drm property which can then be attached to a drm
3176a8a66edSDaniel Vetter  * object with drm_object_attach_property(). The returned property object must
3186a8a66edSDaniel Vetter  * be freed with drm_property_destroy(), which is done automatically when
3196a8a66edSDaniel Vetter  * calling drm_mode_config_cleanup().
32059e71ee7SDaniel Vetter  *
32159e71ee7SDaniel Vetter  * Userspace is only allowed to set this to any property value of the given
32259e71ee7SDaniel Vetter  * @type. Only useful for atomic properties, which is enforced.
32359e71ee7SDaniel Vetter  *
32459e71ee7SDaniel Vetter  * Returns:
32559e71ee7SDaniel Vetter  * A pointer to the newly created property on success, NULL on failure.
32659e71ee7SDaniel Vetter  */
32759e71ee7SDaniel Vetter struct drm_property *drm_property_create_object(struct drm_device *dev,
32851abc976SVille Syrjälä 						u32 flags, const char *name,
329c8458c7eSDaniel Vetter 						uint32_t type)
33059e71ee7SDaniel Vetter {
33159e71ee7SDaniel Vetter 	struct drm_property *property;
33259e71ee7SDaniel Vetter 
33359e71ee7SDaniel Vetter 	flags |= DRM_MODE_PROP_OBJECT;
33459e71ee7SDaniel Vetter 
33559e71ee7SDaniel Vetter 	if (WARN_ON(!(flags & DRM_MODE_PROP_ATOMIC)))
33659e71ee7SDaniel Vetter 		return NULL;
33759e71ee7SDaniel Vetter 
33859e71ee7SDaniel Vetter 	property = drm_property_create(dev, flags, name, 1);
33959e71ee7SDaniel Vetter 	if (!property)
34059e71ee7SDaniel Vetter 		return NULL;
34159e71ee7SDaniel Vetter 
34259e71ee7SDaniel Vetter 	property->values[0] = type;
34359e71ee7SDaniel Vetter 
34459e71ee7SDaniel Vetter 	return property;
34559e71ee7SDaniel Vetter }
34659e71ee7SDaniel Vetter EXPORT_SYMBOL(drm_property_create_object);
34759e71ee7SDaniel Vetter 
34859e71ee7SDaniel Vetter /**
34959e71ee7SDaniel Vetter  * drm_property_create_bool - create a new boolean property type
35059e71ee7SDaniel Vetter  * @dev: drm device
35159e71ee7SDaniel Vetter  * @flags: flags specifying the property type
35259e71ee7SDaniel Vetter  * @name: name of the property
35359e71ee7SDaniel Vetter  *
35459e71ee7SDaniel Vetter  * This creates a new generic drm property which can then be attached to a drm
3556a8a66edSDaniel Vetter  * object with drm_object_attach_property(). The returned property object must
3566a8a66edSDaniel Vetter  * be freed with drm_property_destroy(), which is done automatically when
3576a8a66edSDaniel Vetter  * calling drm_mode_config_cleanup().
35859e71ee7SDaniel Vetter  *
35959e71ee7SDaniel Vetter  * This is implemented as a ranged property with only {0, 1} as valid values.
36059e71ee7SDaniel Vetter  *
36159e71ee7SDaniel Vetter  * Returns:
36259e71ee7SDaniel Vetter  * A pointer to the newly created property on success, NULL on failure.
36359e71ee7SDaniel Vetter  */
36451abc976SVille Syrjälä struct drm_property *drm_property_create_bool(struct drm_device *dev,
36551abc976SVille Syrjälä 					      u32 flags, const char *name)
36659e71ee7SDaniel Vetter {
36759e71ee7SDaniel Vetter 	return drm_property_create_range(dev, flags, name, 0, 1);
36859e71ee7SDaniel Vetter }
36959e71ee7SDaniel Vetter EXPORT_SYMBOL(drm_property_create_bool);
37059e71ee7SDaniel Vetter 
37159e71ee7SDaniel Vetter /**
37259e71ee7SDaniel Vetter  * drm_property_add_enum - add a possible value to an enumeration property
37359e71ee7SDaniel Vetter  * @property: enumeration property to change
37459e71ee7SDaniel Vetter  * @value: value of the new enumeration
37559e71ee7SDaniel Vetter  * @name: symbolic name of the new enumeration
37659e71ee7SDaniel Vetter  *
37759e71ee7SDaniel Vetter  * This functions adds enumerations to a property.
37859e71ee7SDaniel Vetter  *
37959e71ee7SDaniel Vetter  * It's use is deprecated, drivers should use one of the more specific helpers
38059e71ee7SDaniel Vetter  * to directly create the property with all enumerations already attached.
38159e71ee7SDaniel Vetter  *
38259e71ee7SDaniel Vetter  * Returns:
38359e71ee7SDaniel Vetter  * Zero on success, error code on failure.
38459e71ee7SDaniel Vetter  */
38530e9db6dSVille Syrjälä int drm_property_add_enum(struct drm_property *property,
38659e71ee7SDaniel Vetter 			  uint64_t value, const char *name)
38759e71ee7SDaniel Vetter {
38859e71ee7SDaniel Vetter 	struct drm_property_enum *prop_enum;
38930e9db6dSVille Syrjälä 	int index = 0;
39059e71ee7SDaniel Vetter 
3915ebbb5b4SVille Syrjälä 	if (WARN_ON(strlen(name) >= DRM_PROP_NAME_LEN))
3925ebbb5b4SVille Syrjälä 		return -EINVAL;
3935ebbb5b4SVille Syrjälä 
3941371f260SVille Syrjälä 	if (WARN_ON(!drm_property_type_is(property, DRM_MODE_PROP_ENUM) &&
3951371f260SVille Syrjälä 		    !drm_property_type_is(property, DRM_MODE_PROP_BITMASK)))
39659e71ee7SDaniel Vetter 		return -EINVAL;
39759e71ee7SDaniel Vetter 
39859e71ee7SDaniel Vetter 	/*
39959e71ee7SDaniel Vetter 	 * Bitmask enum properties have the additional constraint of values
40059e71ee7SDaniel Vetter 	 * from 0 to 63
40159e71ee7SDaniel Vetter 	 */
4028c6c2fe2SVille Syrjälä 	if (WARN_ON(drm_property_type_is(property, DRM_MODE_PROP_BITMASK) &&
4038c6c2fe2SVille Syrjälä 		    value > 63))
40459e71ee7SDaniel Vetter 		return -EINVAL;
40559e71ee7SDaniel Vetter 
40659e71ee7SDaniel Vetter 	list_for_each_entry(prop_enum, &property->enum_list, head) {
4076f881d04SVille Syrjälä 		if (WARN_ON(prop_enum->value == value))
4086f881d04SVille Syrjälä 			return -EINVAL;
40930e9db6dSVille Syrjälä 		index++;
41059e71ee7SDaniel Vetter 	}
41159e71ee7SDaniel Vetter 
41230e9db6dSVille Syrjälä 	if (WARN_ON(index >= property->num_values))
41330e9db6dSVille Syrjälä 		return -EINVAL;
41430e9db6dSVille Syrjälä 
41559e71ee7SDaniel Vetter 	prop_enum = kzalloc(sizeof(struct drm_property_enum), GFP_KERNEL);
41659e71ee7SDaniel Vetter 	if (!prop_enum)
41759e71ee7SDaniel Vetter 		return -ENOMEM;
41859e71ee7SDaniel Vetter 
41959e71ee7SDaniel Vetter 	strncpy(prop_enum->name, name, DRM_PROP_NAME_LEN);
42059e71ee7SDaniel Vetter 	prop_enum->name[DRM_PROP_NAME_LEN-1] = '\0';
42159e71ee7SDaniel Vetter 	prop_enum->value = value;
42259e71ee7SDaniel Vetter 
42359e71ee7SDaniel Vetter 	property->values[index] = value;
42459e71ee7SDaniel Vetter 	list_add_tail(&prop_enum->head, &property->enum_list);
42559e71ee7SDaniel Vetter 	return 0;
42659e71ee7SDaniel Vetter }
42759e71ee7SDaniel Vetter EXPORT_SYMBOL(drm_property_add_enum);
42859e71ee7SDaniel Vetter 
42959e71ee7SDaniel Vetter /**
43059e71ee7SDaniel Vetter  * drm_property_destroy - destroy a drm property
43159e71ee7SDaniel Vetter  * @dev: drm device
43259e71ee7SDaniel Vetter  * @property: property to destry
43359e71ee7SDaniel Vetter  *
43459e71ee7SDaniel Vetter  * This function frees a property including any attached resources like
43559e71ee7SDaniel Vetter  * enumeration values.
43659e71ee7SDaniel Vetter  */
43759e71ee7SDaniel Vetter void drm_property_destroy(struct drm_device *dev, struct drm_property *property)
43859e71ee7SDaniel Vetter {
43959e71ee7SDaniel Vetter 	struct drm_property_enum *prop_enum, *pt;
44059e71ee7SDaniel Vetter 
44159e71ee7SDaniel Vetter 	list_for_each_entry_safe(prop_enum, pt, &property->enum_list, head) {
44259e71ee7SDaniel Vetter 		list_del(&prop_enum->head);
44359e71ee7SDaniel Vetter 		kfree(prop_enum);
44459e71ee7SDaniel Vetter 	}
44559e71ee7SDaniel Vetter 
44659e71ee7SDaniel Vetter 	if (property->num_values)
44759e71ee7SDaniel Vetter 		kfree(property->values);
44859e71ee7SDaniel Vetter 	drm_mode_object_unregister(dev, &property->base);
44959e71ee7SDaniel Vetter 	list_del(&property->head);
45059e71ee7SDaniel Vetter 	kfree(property);
45159e71ee7SDaniel Vetter }
45259e71ee7SDaniel Vetter EXPORT_SYMBOL(drm_property_destroy);
45359e71ee7SDaniel Vetter 
45459e71ee7SDaniel Vetter int drm_mode_getproperty_ioctl(struct drm_device *dev,
45559e71ee7SDaniel Vetter 			       void *data, struct drm_file *file_priv)
45659e71ee7SDaniel Vetter {
45759e71ee7SDaniel Vetter 	struct drm_mode_get_property *out_resp = data;
45859e71ee7SDaniel Vetter 	struct drm_property *property;
45959e71ee7SDaniel Vetter 	int enum_count = 0;
46059e71ee7SDaniel Vetter 	int value_count = 0;
461eb8eb02eSDaniel Vetter 	int i, copied;
46259e71ee7SDaniel Vetter 	struct drm_property_enum *prop_enum;
46359e71ee7SDaniel Vetter 	struct drm_mode_property_enum __user *enum_ptr;
46459e71ee7SDaniel Vetter 	uint64_t __user *values_ptr;
46559e71ee7SDaniel Vetter 
46659e71ee7SDaniel Vetter 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
46769fdf420SChris Wilson 		return -EOPNOTSUPP;
46859e71ee7SDaniel Vetter 
469418da172SKeith Packard 	property = drm_property_find(dev, file_priv, out_resp->prop_id);
470eb8eb02eSDaniel Vetter 	if (!property)
471eb8eb02eSDaniel Vetter 		return -ENOENT;
47259e71ee7SDaniel Vetter 
47359e71ee7SDaniel Vetter 	strncpy(out_resp->name, property->name, DRM_PROP_NAME_LEN);
47459e71ee7SDaniel Vetter 	out_resp->name[DRM_PROP_NAME_LEN-1] = 0;
47559e71ee7SDaniel Vetter 	out_resp->flags = property->flags;
47659e71ee7SDaniel Vetter 
477eb8eb02eSDaniel Vetter 	value_count = property->num_values;
478eb8eb02eSDaniel Vetter 	values_ptr = u64_to_user_ptr(out_resp->values_ptr);
479eb8eb02eSDaniel Vetter 
48059e71ee7SDaniel Vetter 	for (i = 0; i < value_count; i++) {
481eb8eb02eSDaniel Vetter 		if (i < out_resp->count_values &&
482eb8eb02eSDaniel Vetter 		    put_user(property->values[i], values_ptr + i)) {
483eb8eb02eSDaniel Vetter 			return -EFAULT;
48459e71ee7SDaniel Vetter 		}
48559e71ee7SDaniel Vetter 	}
48659e71ee7SDaniel Vetter 	out_resp->count_values = value_count;
48759e71ee7SDaniel Vetter 
488eb8eb02eSDaniel Vetter 	copied = 0;
489eb8eb02eSDaniel Vetter 	enum_ptr = u64_to_user_ptr(out_resp->enum_blob_ptr);
490eb8eb02eSDaniel Vetter 
49159e71ee7SDaniel Vetter 	if (drm_property_type_is(property, DRM_MODE_PROP_ENUM) ||
49259e71ee7SDaniel Vetter 	    drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) {
49359e71ee7SDaniel Vetter 		list_for_each_entry(prop_enum, &property->enum_list, head) {
494eb8eb02eSDaniel Vetter 			enum_count++;
4958cb68c83SDaniel Vetter 			if (out_resp->count_enum_blobs < enum_count)
496eb8eb02eSDaniel Vetter 				continue;
49759e71ee7SDaniel Vetter 
498eb8eb02eSDaniel Vetter 			if (copy_to_user(&enum_ptr[copied].value,
499eb8eb02eSDaniel Vetter 					 &prop_enum->value, sizeof(uint64_t)))
500eb8eb02eSDaniel Vetter 				return -EFAULT;
50159e71ee7SDaniel Vetter 
50259e71ee7SDaniel Vetter 			if (copy_to_user(&enum_ptr[copied].name,
503eb8eb02eSDaniel Vetter 					 &prop_enum->name, DRM_PROP_NAME_LEN))
504eb8eb02eSDaniel Vetter 				return -EFAULT;
50559e71ee7SDaniel Vetter 			copied++;
50659e71ee7SDaniel Vetter 		}
50759e71ee7SDaniel Vetter 		out_resp->count_enum_blobs = enum_count;
50859e71ee7SDaniel Vetter 	}
50959e71ee7SDaniel Vetter 
51059e71ee7SDaniel Vetter 	/*
51159e71ee7SDaniel Vetter 	 * NOTE: The idea seems to have been to use this to read all the blob
51259e71ee7SDaniel Vetter 	 * property values. But nothing ever added them to the corresponding
51359e71ee7SDaniel Vetter 	 * list, userspace always used the special-purpose get_blob ioctl to
51459e71ee7SDaniel Vetter 	 * read the value for a blob property. It also doesn't make a lot of
51559e71ee7SDaniel Vetter 	 * sense to return values here when everything else is just metadata for
51659e71ee7SDaniel Vetter 	 * the property itself.
51759e71ee7SDaniel Vetter 	 */
51859e71ee7SDaniel Vetter 	if (drm_property_type_is(property, DRM_MODE_PROP_BLOB))
51959e71ee7SDaniel Vetter 		out_resp->count_enum_blobs = 0;
520eb8eb02eSDaniel Vetter 
521eb8eb02eSDaniel Vetter 	return 0;
52259e71ee7SDaniel Vetter }
52359e71ee7SDaniel Vetter 
52459e71ee7SDaniel Vetter static void drm_property_free_blob(struct kref *kref)
52559e71ee7SDaniel Vetter {
52659e71ee7SDaniel Vetter 	struct drm_property_blob *blob =
52759e71ee7SDaniel Vetter 		container_of(kref, struct drm_property_blob, base.refcount);
52859e71ee7SDaniel Vetter 
52959e71ee7SDaniel Vetter 	mutex_lock(&blob->dev->mode_config.blob_lock);
53059e71ee7SDaniel Vetter 	list_del(&blob->head_global);
53159e71ee7SDaniel Vetter 	mutex_unlock(&blob->dev->mode_config.blob_lock);
53259e71ee7SDaniel Vetter 
53359e71ee7SDaniel Vetter 	drm_mode_object_unregister(blob->dev, &blob->base);
53459e71ee7SDaniel Vetter 
535718b5406SMichel Dänzer 	kvfree(blob);
53659e71ee7SDaniel Vetter }
53759e71ee7SDaniel Vetter 
53859e71ee7SDaniel Vetter /**
53959e71ee7SDaniel Vetter  * drm_property_create_blob - Create new blob property
54059e71ee7SDaniel Vetter  * @dev: DRM device to create property for
54159e71ee7SDaniel Vetter  * @length: Length to allocate for blob data
54259e71ee7SDaniel Vetter  * @data: If specified, copies data into blob
54359e71ee7SDaniel Vetter  *
544c8458c7eSDaniel Vetter  * Creates a new blob property for a specified DRM device, optionally
545c8458c7eSDaniel Vetter  * copying data. Note that blob properties are meant to be invariant, hence the
546c8458c7eSDaniel Vetter  * data must be filled out before the blob is used as the value of any property.
547c8458c7eSDaniel Vetter  *
54859e71ee7SDaniel Vetter  * Returns:
54959e71ee7SDaniel Vetter  * New blob property with a single reference on success, or an ERR_PTR
55059e71ee7SDaniel Vetter  * value on failure.
55159e71ee7SDaniel Vetter  */
55259e71ee7SDaniel Vetter struct drm_property_blob *
55359e71ee7SDaniel Vetter drm_property_create_blob(struct drm_device *dev, size_t length,
55459e71ee7SDaniel Vetter 			 const void *data)
55559e71ee7SDaniel Vetter {
55659e71ee7SDaniel Vetter 	struct drm_property_blob *blob;
55759e71ee7SDaniel Vetter 	int ret;
55859e71ee7SDaniel Vetter 
55959e71ee7SDaniel Vetter 	if (!length || length > ULONG_MAX - sizeof(struct drm_property_blob))
56059e71ee7SDaniel Vetter 		return ERR_PTR(-EINVAL);
56159e71ee7SDaniel Vetter 
562718b5406SMichel Dänzer 	blob = kvzalloc(sizeof(struct drm_property_blob)+length, GFP_KERNEL);
56359e71ee7SDaniel Vetter 	if (!blob)
56459e71ee7SDaniel Vetter 		return ERR_PTR(-ENOMEM);
56559e71ee7SDaniel Vetter 
56659e71ee7SDaniel Vetter 	/* This must be explicitly initialised, so we can safely call list_del
56759e71ee7SDaniel Vetter 	 * on it in the removal handler, even if it isn't in a file list. */
56859e71ee7SDaniel Vetter 	INIT_LIST_HEAD(&blob->head_file);
5699c60583cSVille Syrjälä 	blob->data = (void *)blob + sizeof(*blob);
57059e71ee7SDaniel Vetter 	blob->length = length;
57159e71ee7SDaniel Vetter 	blob->dev = dev;
57259e71ee7SDaniel Vetter 
57359e71ee7SDaniel Vetter 	if (data)
57459e71ee7SDaniel Vetter 		memcpy(blob->data, data, length);
57559e71ee7SDaniel Vetter 
5762135ea7aSThierry Reding 	ret = __drm_mode_object_add(dev, &blob->base, DRM_MODE_OBJECT_BLOB,
57759e71ee7SDaniel Vetter 				    true, drm_property_free_blob);
57859e71ee7SDaniel Vetter 	if (ret) {
579718b5406SMichel Dänzer 		kvfree(blob);
58059e71ee7SDaniel Vetter 		return ERR_PTR(-EINVAL);
58159e71ee7SDaniel Vetter 	}
58259e71ee7SDaniel Vetter 
58359e71ee7SDaniel Vetter 	mutex_lock(&dev->mode_config.blob_lock);
58459e71ee7SDaniel Vetter 	list_add_tail(&blob->head_global,
58559e71ee7SDaniel Vetter 	              &dev->mode_config.property_blob_list);
58659e71ee7SDaniel Vetter 	mutex_unlock(&dev->mode_config.blob_lock);
58759e71ee7SDaniel Vetter 
58859e71ee7SDaniel Vetter 	return blob;
58959e71ee7SDaniel Vetter }
59059e71ee7SDaniel Vetter EXPORT_SYMBOL(drm_property_create_blob);
59159e71ee7SDaniel Vetter 
59259e71ee7SDaniel Vetter /**
5936472e509SThierry Reding  * drm_property_blob_put - release a blob property reference
5946472e509SThierry Reding  * @blob: DRM blob property
59559e71ee7SDaniel Vetter  *
5966472e509SThierry Reding  * Releases a reference to a blob property. May free the object.
59759e71ee7SDaniel Vetter  */
5986472e509SThierry Reding void drm_property_blob_put(struct drm_property_blob *blob)
59959e71ee7SDaniel Vetter {
60059e71ee7SDaniel Vetter 	if (!blob)
60159e71ee7SDaniel Vetter 		return;
60259e71ee7SDaniel Vetter 
603020a218fSThierry Reding 	drm_mode_object_put(&blob->base);
60459e71ee7SDaniel Vetter }
6056472e509SThierry Reding EXPORT_SYMBOL(drm_property_blob_put);
60659e71ee7SDaniel Vetter 
60759e71ee7SDaniel Vetter void drm_property_destroy_user_blobs(struct drm_device *dev,
60859e71ee7SDaniel Vetter 				     struct drm_file *file_priv)
60959e71ee7SDaniel Vetter {
61059e71ee7SDaniel Vetter 	struct drm_property_blob *blob, *bt;
61159e71ee7SDaniel Vetter 
61259e71ee7SDaniel Vetter 	/*
61359e71ee7SDaniel Vetter 	 * When the file gets released that means no one else can access the
61459e71ee7SDaniel Vetter 	 * blob list any more, so no need to grab dev->blob_lock.
61559e71ee7SDaniel Vetter 	 */
61659e71ee7SDaniel Vetter 	list_for_each_entry_safe(blob, bt, &file_priv->blobs, head_file) {
61759e71ee7SDaniel Vetter 		list_del_init(&blob->head_file);
6186472e509SThierry Reding 		drm_property_blob_put(blob);
61959e71ee7SDaniel Vetter 	}
62059e71ee7SDaniel Vetter }
62159e71ee7SDaniel Vetter 
62259e71ee7SDaniel Vetter /**
6236472e509SThierry Reding  * drm_property_blob_get - acquire blob property reference
6246472e509SThierry Reding  * @blob: DRM blob property
625c8458c7eSDaniel Vetter  *
6266472e509SThierry Reding  * Acquires a reference to an existing blob property. Returns @blob, which
627c8458c7eSDaniel Vetter  * allows this to be used as a shorthand in assignments.
62859e71ee7SDaniel Vetter  */
6296472e509SThierry Reding struct drm_property_blob *drm_property_blob_get(struct drm_property_blob *blob)
63059e71ee7SDaniel Vetter {
631020a218fSThierry Reding 	drm_mode_object_get(&blob->base);
63259e71ee7SDaniel Vetter 	return blob;
63359e71ee7SDaniel Vetter }
6346472e509SThierry Reding EXPORT_SYMBOL(drm_property_blob_get);
63559e71ee7SDaniel Vetter 
63659e71ee7SDaniel Vetter /**
63759e71ee7SDaniel Vetter  * drm_property_lookup_blob - look up a blob property and take a reference
63859e71ee7SDaniel Vetter  * @dev: drm device
63959e71ee7SDaniel Vetter  * @id: id of the blob property
64059e71ee7SDaniel Vetter  *
64159e71ee7SDaniel Vetter  * If successful, this takes an additional reference to the blob property.
64259e71ee7SDaniel Vetter  * callers need to make sure to eventually unreference the returned property
6436472e509SThierry Reding  * again, using drm_property_blob_put().
644c8458c7eSDaniel Vetter  *
645c8458c7eSDaniel Vetter  * Return:
646c8458c7eSDaniel Vetter  * NULL on failure, pointer to the blob on success.
64759e71ee7SDaniel Vetter  */
64859e71ee7SDaniel Vetter struct drm_property_blob *drm_property_lookup_blob(struct drm_device *dev,
64959e71ee7SDaniel Vetter 					           uint32_t id)
65059e71ee7SDaniel Vetter {
65159e71ee7SDaniel Vetter 	struct drm_mode_object *obj;
65259e71ee7SDaniel Vetter 	struct drm_property_blob *blob = NULL;
65359e71ee7SDaniel Vetter 
654418da172SKeith Packard 	obj = __drm_mode_object_find(dev, NULL, id, DRM_MODE_OBJECT_BLOB);
65559e71ee7SDaniel Vetter 	if (obj)
65659e71ee7SDaniel Vetter 		blob = obj_to_blob(obj);
65759e71ee7SDaniel Vetter 	return blob;
65859e71ee7SDaniel Vetter }
65959e71ee7SDaniel Vetter EXPORT_SYMBOL(drm_property_lookup_blob);
66059e71ee7SDaniel Vetter 
66159e71ee7SDaniel Vetter /**
662c8458c7eSDaniel Vetter  * drm_property_replace_global_blob - replace existing blob property
66359e71ee7SDaniel Vetter  * @dev: drm device
66459e71ee7SDaniel Vetter  * @replace: location of blob property pointer to be replaced
66559e71ee7SDaniel Vetter  * @length: length of data for new blob, or 0 for no data
66659e71ee7SDaniel Vetter  * @data: content for new blob, or NULL for no data
66759e71ee7SDaniel Vetter  * @obj_holds_id: optional object for property holding blob ID
66859e71ee7SDaniel Vetter  * @prop_holds_id: optional property holding blob ID
66959e71ee7SDaniel Vetter  * @return 0 on success or error on failure
67059e71ee7SDaniel Vetter  *
671c8458c7eSDaniel Vetter  * This function will replace a global property in the blob list, optionally
672c8458c7eSDaniel Vetter  * updating a property which holds the ID of that property.
67359e71ee7SDaniel Vetter  *
67459e71ee7SDaniel Vetter  * If length is 0 or data is NULL, no new blob will be created, and the holding
67559e71ee7SDaniel Vetter  * property, if specified, will be set to 0.
67659e71ee7SDaniel Vetter  *
67759e71ee7SDaniel Vetter  * Access to the replace pointer is assumed to be protected by the caller, e.g.
67859e71ee7SDaniel Vetter  * by holding the relevant modesetting object lock for its parent.
67959e71ee7SDaniel Vetter  *
68059e71ee7SDaniel Vetter  * For example, a drm_connector has a 'PATH' property, which contains the ID
68159e71ee7SDaniel Vetter  * of a blob property with the value of the MST path information. Calling this
68259e71ee7SDaniel Vetter  * function with replace pointing to the connector's path_blob_ptr, length and
68359e71ee7SDaniel Vetter  * data set for the new path information, obj_holds_id set to the connector's
68459e71ee7SDaniel Vetter  * base object, and prop_holds_id set to the path property name, will perform
68559e71ee7SDaniel Vetter  * a completely atomic update. The access to path_blob_ptr is protected by the
68659e71ee7SDaniel Vetter  * caller holding a lock on the connector.
68759e71ee7SDaniel Vetter  */
68859e71ee7SDaniel Vetter int drm_property_replace_global_blob(struct drm_device *dev,
68959e71ee7SDaniel Vetter 				     struct drm_property_blob **replace,
69059e71ee7SDaniel Vetter 				     size_t length,
69159e71ee7SDaniel Vetter 				     const void *data,
69259e71ee7SDaniel Vetter 				     struct drm_mode_object *obj_holds_id,
69359e71ee7SDaniel Vetter 				     struct drm_property *prop_holds_id)
69459e71ee7SDaniel Vetter {
69559e71ee7SDaniel Vetter 	struct drm_property_blob *new_blob = NULL;
69659e71ee7SDaniel Vetter 	struct drm_property_blob *old_blob = NULL;
69759e71ee7SDaniel Vetter 	int ret;
69859e71ee7SDaniel Vetter 
69959e71ee7SDaniel Vetter 	WARN_ON(replace == NULL);
70059e71ee7SDaniel Vetter 
70159e71ee7SDaniel Vetter 	old_blob = *replace;
70259e71ee7SDaniel Vetter 
70359e71ee7SDaniel Vetter 	if (length && data) {
70459e71ee7SDaniel Vetter 		new_blob = drm_property_create_blob(dev, length, data);
70559e71ee7SDaniel Vetter 		if (IS_ERR(new_blob))
70659e71ee7SDaniel Vetter 			return PTR_ERR(new_blob);
70759e71ee7SDaniel Vetter 	}
70859e71ee7SDaniel Vetter 
70959e71ee7SDaniel Vetter 	if (obj_holds_id) {
71059e71ee7SDaniel Vetter 		ret = drm_object_property_set_value(obj_holds_id,
71159e71ee7SDaniel Vetter 						    prop_holds_id,
71259e71ee7SDaniel Vetter 						    new_blob ?
71359e71ee7SDaniel Vetter 						        new_blob->base.id : 0);
71459e71ee7SDaniel Vetter 		if (ret != 0)
71559e71ee7SDaniel Vetter 			goto err_created;
71659e71ee7SDaniel Vetter 	}
71759e71ee7SDaniel Vetter 
7186472e509SThierry Reding 	drm_property_blob_put(old_blob);
71959e71ee7SDaniel Vetter 	*replace = new_blob;
72059e71ee7SDaniel Vetter 
72159e71ee7SDaniel Vetter 	return 0;
72259e71ee7SDaniel Vetter 
72359e71ee7SDaniel Vetter err_created:
7246472e509SThierry Reding 	drm_property_blob_put(new_blob);
72559e71ee7SDaniel Vetter 	return ret;
72659e71ee7SDaniel Vetter }
72759e71ee7SDaniel Vetter EXPORT_SYMBOL(drm_property_replace_global_blob);
72859e71ee7SDaniel Vetter 
7295f057ffdSPeter Rosin /**
7305f057ffdSPeter Rosin  * drm_property_replace_blob - replace a blob property
7315f057ffdSPeter Rosin  * @blob: a pointer to the member blob to be replaced
7325f057ffdSPeter Rosin  * @new_blob: the new blob to replace with
7335f057ffdSPeter Rosin  *
7345f057ffdSPeter Rosin  * Return: true if the blob was in fact replaced.
7355f057ffdSPeter Rosin  */
7365f057ffdSPeter Rosin bool drm_property_replace_blob(struct drm_property_blob **blob,
7375f057ffdSPeter Rosin 			       struct drm_property_blob *new_blob)
7385f057ffdSPeter Rosin {
7395f057ffdSPeter Rosin 	struct drm_property_blob *old_blob = *blob;
7405f057ffdSPeter Rosin 
7415f057ffdSPeter Rosin 	if (old_blob == new_blob)
7425f057ffdSPeter Rosin 		return false;
7435f057ffdSPeter Rosin 
7445f057ffdSPeter Rosin 	drm_property_blob_put(old_blob);
7455f057ffdSPeter Rosin 	if (new_blob)
7465f057ffdSPeter Rosin 		drm_property_blob_get(new_blob);
7475f057ffdSPeter Rosin 	*blob = new_blob;
7485f057ffdSPeter Rosin 	return true;
7495f057ffdSPeter Rosin }
7505f057ffdSPeter Rosin EXPORT_SYMBOL(drm_property_replace_blob);
7515f057ffdSPeter Rosin 
75259e71ee7SDaniel Vetter int drm_mode_getblob_ioctl(struct drm_device *dev,
75359e71ee7SDaniel Vetter 			   void *data, struct drm_file *file_priv)
75459e71ee7SDaniel Vetter {
75559e71ee7SDaniel Vetter 	struct drm_mode_get_blob *out_resp = data;
75659e71ee7SDaniel Vetter 	struct drm_property_blob *blob;
75759e71ee7SDaniel Vetter 	int ret = 0;
75859e71ee7SDaniel Vetter 
75959e71ee7SDaniel Vetter 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
76069fdf420SChris Wilson 		return -EOPNOTSUPP;
76159e71ee7SDaniel Vetter 
76259e71ee7SDaniel Vetter 	blob = drm_property_lookup_blob(dev, out_resp->blob_id);
76359e71ee7SDaniel Vetter 	if (!blob)
76459e71ee7SDaniel Vetter 		return -ENOENT;
76559e71ee7SDaniel Vetter 
76659e71ee7SDaniel Vetter 	if (out_resp->length == blob->length) {
76775df6247SChris Wilson 		if (copy_to_user(u64_to_user_ptr(out_resp->data),
76875df6247SChris Wilson 				 blob->data,
76975df6247SChris Wilson 				 blob->length)) {
77059e71ee7SDaniel Vetter 			ret = -EFAULT;
77159e71ee7SDaniel Vetter 			goto unref;
77259e71ee7SDaniel Vetter 		}
77359e71ee7SDaniel Vetter 	}
77459e71ee7SDaniel Vetter 	out_resp->length = blob->length;
77559e71ee7SDaniel Vetter unref:
7766472e509SThierry Reding 	drm_property_blob_put(blob);
77759e71ee7SDaniel Vetter 
77859e71ee7SDaniel Vetter 	return ret;
77959e71ee7SDaniel Vetter }
78059e71ee7SDaniel Vetter 
78159e71ee7SDaniel Vetter int drm_mode_createblob_ioctl(struct drm_device *dev,
78259e71ee7SDaniel Vetter 			      void *data, struct drm_file *file_priv)
78359e71ee7SDaniel Vetter {
78459e71ee7SDaniel Vetter 	struct drm_mode_create_blob *out_resp = data;
78559e71ee7SDaniel Vetter 	struct drm_property_blob *blob;
78659e71ee7SDaniel Vetter 	int ret = 0;
78759e71ee7SDaniel Vetter 
78859e71ee7SDaniel Vetter 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
78969fdf420SChris Wilson 		return -EOPNOTSUPP;
79059e71ee7SDaniel Vetter 
79159e71ee7SDaniel Vetter 	blob = drm_property_create_blob(dev, out_resp->length, NULL);
79259e71ee7SDaniel Vetter 	if (IS_ERR(blob))
79359e71ee7SDaniel Vetter 		return PTR_ERR(blob);
79459e71ee7SDaniel Vetter 
79575df6247SChris Wilson 	if (copy_from_user(blob->data,
79675df6247SChris Wilson 			   u64_to_user_ptr(out_resp->data),
79775df6247SChris Wilson 			   out_resp->length)) {
79859e71ee7SDaniel Vetter 		ret = -EFAULT;
79959e71ee7SDaniel Vetter 		goto out_blob;
80059e71ee7SDaniel Vetter 	}
80159e71ee7SDaniel Vetter 
80259e71ee7SDaniel Vetter 	/* Dropping the lock between create_blob and our access here is safe
80359e71ee7SDaniel Vetter 	 * as only the same file_priv can remove the blob; at this point, it is
80459e71ee7SDaniel Vetter 	 * not associated with any file_priv. */
80559e71ee7SDaniel Vetter 	mutex_lock(&dev->mode_config.blob_lock);
80659e71ee7SDaniel Vetter 	out_resp->blob_id = blob->base.id;
80759e71ee7SDaniel Vetter 	list_add_tail(&blob->head_file, &file_priv->blobs);
80859e71ee7SDaniel Vetter 	mutex_unlock(&dev->mode_config.blob_lock);
80959e71ee7SDaniel Vetter 
81059e71ee7SDaniel Vetter 	return 0;
81159e71ee7SDaniel Vetter 
81259e71ee7SDaniel Vetter out_blob:
8136472e509SThierry Reding 	drm_property_blob_put(blob);
81459e71ee7SDaniel Vetter 	return ret;
81559e71ee7SDaniel Vetter }
81659e71ee7SDaniel Vetter 
81759e71ee7SDaniel Vetter int drm_mode_destroyblob_ioctl(struct drm_device *dev,
81859e71ee7SDaniel Vetter 			       void *data, struct drm_file *file_priv)
81959e71ee7SDaniel Vetter {
82059e71ee7SDaniel Vetter 	struct drm_mode_destroy_blob *out_resp = data;
82159e71ee7SDaniel Vetter 	struct drm_property_blob *blob = NULL, *bt;
82259e71ee7SDaniel Vetter 	bool found = false;
82359e71ee7SDaniel Vetter 	int ret = 0;
82459e71ee7SDaniel Vetter 
82559e71ee7SDaniel Vetter 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
82669fdf420SChris Wilson 		return -EOPNOTSUPP;
82759e71ee7SDaniel Vetter 
82859e71ee7SDaniel Vetter 	blob = drm_property_lookup_blob(dev, out_resp->blob_id);
82959e71ee7SDaniel Vetter 	if (!blob)
83059e71ee7SDaniel Vetter 		return -ENOENT;
83159e71ee7SDaniel Vetter 
83259e71ee7SDaniel Vetter 	mutex_lock(&dev->mode_config.blob_lock);
83359e71ee7SDaniel Vetter 	/* Ensure the property was actually created by this user. */
83459e71ee7SDaniel Vetter 	list_for_each_entry(bt, &file_priv->blobs, head_file) {
83559e71ee7SDaniel Vetter 		if (bt == blob) {
83659e71ee7SDaniel Vetter 			found = true;
83759e71ee7SDaniel Vetter 			break;
83859e71ee7SDaniel Vetter 		}
83959e71ee7SDaniel Vetter 	}
84059e71ee7SDaniel Vetter 
84159e71ee7SDaniel Vetter 	if (!found) {
84259e71ee7SDaniel Vetter 		ret = -EPERM;
84359e71ee7SDaniel Vetter 		goto err;
84459e71ee7SDaniel Vetter 	}
84559e71ee7SDaniel Vetter 
84659e71ee7SDaniel Vetter 	/* We must drop head_file here, because we may not be the last
84759e71ee7SDaniel Vetter 	 * reference on the blob. */
84859e71ee7SDaniel Vetter 	list_del_init(&blob->head_file);
84959e71ee7SDaniel Vetter 	mutex_unlock(&dev->mode_config.blob_lock);
85059e71ee7SDaniel Vetter 
85159e71ee7SDaniel Vetter 	/* One reference from lookup, and one from the filp. */
8526472e509SThierry Reding 	drm_property_blob_put(blob);
8536472e509SThierry Reding 	drm_property_blob_put(blob);
85459e71ee7SDaniel Vetter 
85559e71ee7SDaniel Vetter 	return 0;
85659e71ee7SDaniel Vetter 
85759e71ee7SDaniel Vetter err:
85859e71ee7SDaniel Vetter 	mutex_unlock(&dev->mode_config.blob_lock);
8596472e509SThierry Reding 	drm_property_blob_put(blob);
86059e71ee7SDaniel Vetter 
86159e71ee7SDaniel Vetter 	return ret;
86259e71ee7SDaniel Vetter }
86359e71ee7SDaniel Vetter 
86459e71ee7SDaniel Vetter /* Some properties could refer to dynamic refcnt'd objects, or things that
86559e71ee7SDaniel Vetter  * need special locking to handle lifetime issues (ie. to ensure the prop
86659e71ee7SDaniel Vetter  * value doesn't become invalid part way through the property update due to
86759e71ee7SDaniel Vetter  * race).  The value returned by reference via 'obj' should be passed back
86859e71ee7SDaniel Vetter  * to drm_property_change_valid_put() after the property is set (and the
86959e71ee7SDaniel Vetter  * object to which the property is attached has a chance to take it's own
87059e71ee7SDaniel Vetter  * reference).
87159e71ee7SDaniel Vetter  */
87259e71ee7SDaniel Vetter bool drm_property_change_valid_get(struct drm_property *property,
87359e71ee7SDaniel Vetter 				   uint64_t value, struct drm_mode_object **ref)
87459e71ee7SDaniel Vetter {
87559e71ee7SDaniel Vetter 	int i;
87659e71ee7SDaniel Vetter 
87759e71ee7SDaniel Vetter 	if (property->flags & DRM_MODE_PROP_IMMUTABLE)
87859e71ee7SDaniel Vetter 		return false;
87959e71ee7SDaniel Vetter 
88059e71ee7SDaniel Vetter 	*ref = NULL;
88159e71ee7SDaniel Vetter 
88259e71ee7SDaniel Vetter 	if (drm_property_type_is(property, DRM_MODE_PROP_RANGE)) {
88359e71ee7SDaniel Vetter 		if (value < property->values[0] || value > property->values[1])
88459e71ee7SDaniel Vetter 			return false;
88559e71ee7SDaniel Vetter 		return true;
88659e71ee7SDaniel Vetter 	} else if (drm_property_type_is(property, DRM_MODE_PROP_SIGNED_RANGE)) {
88759e71ee7SDaniel Vetter 		int64_t svalue = U642I64(value);
88859e71ee7SDaniel Vetter 
88959e71ee7SDaniel Vetter 		if (svalue < U642I64(property->values[0]) ||
89059e71ee7SDaniel Vetter 				svalue > U642I64(property->values[1]))
89159e71ee7SDaniel Vetter 			return false;
89259e71ee7SDaniel Vetter 		return true;
89359e71ee7SDaniel Vetter 	} else if (drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) {
89459e71ee7SDaniel Vetter 		uint64_t valid_mask = 0;
89559e71ee7SDaniel Vetter 
89659e71ee7SDaniel Vetter 		for (i = 0; i < property->num_values; i++)
89759e71ee7SDaniel Vetter 			valid_mask |= (1ULL << property->values[i]);
89859e71ee7SDaniel Vetter 		return !(value & ~valid_mask);
89930c06570SMaarten Lankhorst 	} else if (drm_property_type_is(property, DRM_MODE_PROP_BLOB)) {
90030c06570SMaarten Lankhorst 		struct drm_property_blob *blob;
90130c06570SMaarten Lankhorst 
90230c06570SMaarten Lankhorst 		if (value == 0)
90330c06570SMaarten Lankhorst 			return true;
90430c06570SMaarten Lankhorst 
90530c06570SMaarten Lankhorst 		blob = drm_property_lookup_blob(property->dev, value);
90630c06570SMaarten Lankhorst 		if (blob) {
90730c06570SMaarten Lankhorst 			*ref = &blob->base;
90830c06570SMaarten Lankhorst 			return true;
90930c06570SMaarten Lankhorst 		} else {
91030c06570SMaarten Lankhorst 			return false;
91130c06570SMaarten Lankhorst 		}
91230c06570SMaarten Lankhorst 	} else if (drm_property_type_is(property, DRM_MODE_PROP_OBJECT)) {
91359e71ee7SDaniel Vetter 		/* a zero value for an object property translates to null: */
91459e71ee7SDaniel Vetter 		if (value == 0)
91559e71ee7SDaniel Vetter 			return true;
91659e71ee7SDaniel Vetter 
917418da172SKeith Packard 		*ref = __drm_mode_object_find(property->dev, NULL, value,
91859e71ee7SDaniel Vetter 					      property->values[0]);
91959e71ee7SDaniel Vetter 		return *ref != NULL;
92059e71ee7SDaniel Vetter 	}
92159e71ee7SDaniel Vetter 
92259e71ee7SDaniel Vetter 	for (i = 0; i < property->num_values; i++)
92359e71ee7SDaniel Vetter 		if (property->values[i] == value)
92459e71ee7SDaniel Vetter 			return true;
92559e71ee7SDaniel Vetter 	return false;
92659e71ee7SDaniel Vetter }
92759e71ee7SDaniel Vetter 
92859e71ee7SDaniel Vetter void drm_property_change_valid_put(struct drm_property *property,
92959e71ee7SDaniel Vetter 		struct drm_mode_object *ref)
93059e71ee7SDaniel Vetter {
93159e71ee7SDaniel Vetter 	if (!ref)
93259e71ee7SDaniel Vetter 		return;
93359e71ee7SDaniel Vetter 
93430c06570SMaarten Lankhorst 	if (drm_property_type_is(property, DRM_MODE_PROP_OBJECT)) {
935020a218fSThierry Reding 		drm_mode_object_put(ref);
93630c06570SMaarten Lankhorst 	} else if (drm_property_type_is(property, DRM_MODE_PROP_BLOB))
9376472e509SThierry Reding 		drm_property_blob_put(obj_to_blob(ref));
93859e71ee7SDaniel Vetter }
939