xref: /openbmc/linux/drivers/gpu/drm/drm_property.c (revision 0ae865ef)
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>
240500c04eSSam Ravnborg #include <linux/uaccess.h>
250500c04eSSam Ravnborg 
260500c04eSSam Ravnborg #include <drm/drm_crtc.h>
270500c04eSSam Ravnborg #include <drm/drm_drv.h>
280500c04eSSam Ravnborg #include <drm/drm_file.h>
290500c04eSSam Ravnborg #include <drm/drm_framebuffer.h>
3059e71ee7SDaniel Vetter #include <drm/drm_property.h>
3159e71ee7SDaniel Vetter 
3259e71ee7SDaniel Vetter #include "drm_crtc_internal.h"
3359e71ee7SDaniel Vetter 
34c8458c7eSDaniel Vetter /**
35c8458c7eSDaniel Vetter  * DOC: overview
36c8458c7eSDaniel Vetter  *
37c8458c7eSDaniel Vetter  * Properties as represented by &drm_property are used to extend the modeset
38c8458c7eSDaniel Vetter  * interface exposed to userspace. For the atomic modeset IOCTL properties are
39c8458c7eSDaniel Vetter  * even the only way to transport metadata about the desired new modeset
40c8458c7eSDaniel Vetter  * configuration from userspace to the kernel. Properties have a well-defined
41c8458c7eSDaniel Vetter  * value range, which is enforced by the drm core. See the documentation of the
42ea0dd85aSDaniel Vetter  * flags member of &struct drm_property for an overview of the different
43c8458c7eSDaniel Vetter  * property types and ranges.
44c8458c7eSDaniel Vetter  *
45c8458c7eSDaniel Vetter  * Properties don't store the current value directly, but need to be
464cf1d871SBhaskar Chowdhury  * instantiated by attaching them to a &drm_mode_object with
47c8458c7eSDaniel Vetter  * drm_object_attach_property().
48c8458c7eSDaniel Vetter  *
49c8458c7eSDaniel Vetter  * Property values are only 64bit. To support bigger piles of data (like gamma
50d574528aSDaniel Vetter  * tables, color correction matrices or large structures) a property can instead
51d574528aSDaniel Vetter  * point at a &drm_property_blob with that additional data.
52c8458c7eSDaniel Vetter  *
53c8458c7eSDaniel Vetter  * Properties are defined by their symbolic name, userspace must keep a
54c8458c7eSDaniel Vetter  * per-object mapping from those names to the property ID used in the atomic
55c8458c7eSDaniel Vetter  * IOCTL and in the get/set property IOCTL.
56c8458c7eSDaniel Vetter  */
57c8458c7eSDaniel Vetter 
58100bc0d9SVille Syrjälä static bool drm_property_flags_valid(u32 flags)
5959e71ee7SDaniel Vetter {
60100bc0d9SVille Syrjälä 	u32 legacy_type = flags & DRM_MODE_PROP_LEGACY_TYPE;
61100bc0d9SVille Syrjälä 	u32 ext_type = flags & DRM_MODE_PROP_EXTENDED_TYPE;
62100bc0d9SVille Syrjälä 
63100bc0d9SVille Syrjälä 	/* Reject undefined/deprecated flags */
64100bc0d9SVille Syrjälä 	if (flags & ~(DRM_MODE_PROP_LEGACY_TYPE |
65100bc0d9SVille Syrjälä 		      DRM_MODE_PROP_EXTENDED_TYPE |
66100bc0d9SVille Syrjälä 		      DRM_MODE_PROP_IMMUTABLE |
67100bc0d9SVille Syrjälä 		      DRM_MODE_PROP_ATOMIC))
68100bc0d9SVille Syrjälä 		return false;
69100bc0d9SVille Syrjälä 
70100bc0d9SVille Syrjälä 	/* We want either a legacy type or an extended type, but not both */
71100bc0d9SVille Syrjälä 	if (!legacy_type == !ext_type)
72100bc0d9SVille Syrjälä 		return false;
73100bc0d9SVille Syrjälä 
74100bc0d9SVille Syrjälä 	/* Only one legacy type at a time please */
75100bc0d9SVille Syrjälä 	if (legacy_type && !is_power_of_2(legacy_type))
76100bc0d9SVille Syrjälä 		return false;
77100bc0d9SVille Syrjälä 
78100bc0d9SVille Syrjälä 	return true;
7959e71ee7SDaniel Vetter }
8059e71ee7SDaniel Vetter 
8159e71ee7SDaniel Vetter /**
8259e71ee7SDaniel Vetter  * drm_property_create - create a new property type
8359e71ee7SDaniel Vetter  * @dev: drm device
8459e71ee7SDaniel Vetter  * @flags: flags specifying the property type
8559e71ee7SDaniel Vetter  * @name: name of the property
8659e71ee7SDaniel Vetter  * @num_values: number of pre-defined values
8759e71ee7SDaniel Vetter  *
8859e71ee7SDaniel Vetter  * This creates a new generic drm property which can then be attached to a drm
896a8a66edSDaniel Vetter  * object with drm_object_attach_property(). The returned property object must
906a8a66edSDaniel Vetter  * be freed with drm_property_destroy(), which is done automatically when
916a8a66edSDaniel Vetter  * calling drm_mode_config_cleanup().
9259e71ee7SDaniel Vetter  *
9359e71ee7SDaniel Vetter  * Returns:
9459e71ee7SDaniel Vetter  * A pointer to the newly created property on success, NULL on failure.
9559e71ee7SDaniel Vetter  */
9651abc976SVille Syrjälä struct drm_property *drm_property_create(struct drm_device *dev,
9751abc976SVille Syrjälä 					 u32 flags, const char *name,
9851abc976SVille Syrjälä 					 int num_values)
9959e71ee7SDaniel Vetter {
10059e71ee7SDaniel Vetter 	struct drm_property *property = NULL;
10159e71ee7SDaniel Vetter 	int ret;
10259e71ee7SDaniel Vetter 
103100bc0d9SVille Syrjälä 	if (WARN_ON(!drm_property_flags_valid(flags)))
104100bc0d9SVille Syrjälä 		return NULL;
105100bc0d9SVille Syrjälä 
1065ebbb5b4SVille Syrjälä 	if (WARN_ON(strlen(name) >= DRM_PROP_NAME_LEN))
1075ebbb5b4SVille Syrjälä 		return NULL;
1085ebbb5b4SVille Syrjälä 
10959e71ee7SDaniel Vetter 	property = kzalloc(sizeof(struct drm_property), GFP_KERNEL);
11059e71ee7SDaniel Vetter 	if (!property)
11159e71ee7SDaniel Vetter 		return NULL;
11259e71ee7SDaniel Vetter 
11359e71ee7SDaniel Vetter 	property->dev = dev;
11459e71ee7SDaniel Vetter 
11559e71ee7SDaniel Vetter 	if (num_values) {
11659e71ee7SDaniel Vetter 		property->values = kcalloc(num_values, sizeof(uint64_t),
11759e71ee7SDaniel Vetter 					   GFP_KERNEL);
11859e71ee7SDaniel Vetter 		if (!property->values)
11959e71ee7SDaniel Vetter 			goto fail;
12059e71ee7SDaniel Vetter 	}
12159e71ee7SDaniel Vetter 
1222135ea7aSThierry Reding 	ret = drm_mode_object_add(dev, &property->base, DRM_MODE_OBJECT_PROPERTY);
12359e71ee7SDaniel Vetter 	if (ret)
12459e71ee7SDaniel Vetter 		goto fail;
12559e71ee7SDaniel Vetter 
12659e71ee7SDaniel Vetter 	property->flags = flags;
12759e71ee7SDaniel Vetter 	property->num_values = num_values;
12859e71ee7SDaniel Vetter 	INIT_LIST_HEAD(&property->enum_list);
12959e71ee7SDaniel Vetter 
13059e71ee7SDaniel Vetter 	strncpy(property->name, name, DRM_PROP_NAME_LEN);
13159e71ee7SDaniel Vetter 	property->name[DRM_PROP_NAME_LEN-1] = '\0';
13259e71ee7SDaniel Vetter 
13359e71ee7SDaniel Vetter 	list_add_tail(&property->head, &dev->mode_config.property_list);
13459e71ee7SDaniel Vetter 
13559e71ee7SDaniel Vetter 	return property;
13659e71ee7SDaniel Vetter fail:
13759e71ee7SDaniel Vetter 	kfree(property->values);
13859e71ee7SDaniel Vetter 	kfree(property);
13959e71ee7SDaniel Vetter 	return NULL;
14059e71ee7SDaniel Vetter }
14159e71ee7SDaniel Vetter EXPORT_SYMBOL(drm_property_create);
14259e71ee7SDaniel Vetter 
14359e71ee7SDaniel Vetter /**
14459e71ee7SDaniel Vetter  * drm_property_create_enum - create a new enumeration property type
14559e71ee7SDaniel Vetter  * @dev: drm device
14659e71ee7SDaniel Vetter  * @flags: flags specifying the property type
14759e71ee7SDaniel Vetter  * @name: name of the property
14859e71ee7SDaniel Vetter  * @props: enumeration lists with property values
14959e71ee7SDaniel Vetter  * @num_values: number of pre-defined values
15059e71ee7SDaniel Vetter  *
15159e71ee7SDaniel Vetter  * This creates a new generic drm property which can then be attached to a drm
1526a8a66edSDaniel Vetter  * object with drm_object_attach_property(). The returned property object must
1536a8a66edSDaniel Vetter  * be freed with drm_property_destroy(), which is done automatically when
1546a8a66edSDaniel Vetter  * calling drm_mode_config_cleanup().
15559e71ee7SDaniel Vetter  *
15659e71ee7SDaniel Vetter  * Userspace is only allowed to set one of the predefined values for enumeration
15759e71ee7SDaniel Vetter  * properties.
15859e71ee7SDaniel Vetter  *
15959e71ee7SDaniel Vetter  * Returns:
16059e71ee7SDaniel Vetter  * A pointer to the newly created property on success, NULL on failure.
16159e71ee7SDaniel Vetter  */
16251abc976SVille Syrjälä struct drm_property *drm_property_create_enum(struct drm_device *dev,
16351abc976SVille Syrjälä 					      u32 flags, const char *name,
16459e71ee7SDaniel Vetter 					      const struct drm_prop_enum_list *props,
16559e71ee7SDaniel Vetter 					      int num_values)
16659e71ee7SDaniel Vetter {
16759e71ee7SDaniel Vetter 	struct drm_property *property;
16859e71ee7SDaniel Vetter 	int i, ret;
16959e71ee7SDaniel Vetter 
17059e71ee7SDaniel Vetter 	flags |= DRM_MODE_PROP_ENUM;
17159e71ee7SDaniel Vetter 
17259e71ee7SDaniel Vetter 	property = drm_property_create(dev, flags, name, num_values);
17359e71ee7SDaniel Vetter 	if (!property)
17459e71ee7SDaniel Vetter 		return NULL;
17559e71ee7SDaniel Vetter 
17659e71ee7SDaniel Vetter 	for (i = 0; i < num_values; i++) {
17730e9db6dSVille Syrjälä 		ret = drm_property_add_enum(property,
17859e71ee7SDaniel Vetter 					    props[i].type,
17959e71ee7SDaniel Vetter 					    props[i].name);
18059e71ee7SDaniel Vetter 		if (ret) {
18159e71ee7SDaniel Vetter 			drm_property_destroy(dev, property);
18259e71ee7SDaniel Vetter 			return NULL;
18359e71ee7SDaniel Vetter 		}
18459e71ee7SDaniel Vetter 	}
18559e71ee7SDaniel Vetter 
18659e71ee7SDaniel Vetter 	return property;
18759e71ee7SDaniel Vetter }
18859e71ee7SDaniel Vetter EXPORT_SYMBOL(drm_property_create_enum);
18959e71ee7SDaniel Vetter 
19059e71ee7SDaniel Vetter /**
19159e71ee7SDaniel Vetter  * drm_property_create_bitmask - create a new bitmask property type
19259e71ee7SDaniel Vetter  * @dev: drm device
19359e71ee7SDaniel Vetter  * @flags: flags specifying the property type
19459e71ee7SDaniel Vetter  * @name: name of the property
19559e71ee7SDaniel Vetter  * @props: enumeration lists with property bitflags
19659e71ee7SDaniel Vetter  * @num_props: size of the @props array
19759e71ee7SDaniel Vetter  * @supported_bits: bitmask of all supported enumeration values
19859e71ee7SDaniel Vetter  *
19959e71ee7SDaniel Vetter  * This creates a new bitmask drm property which can then be attached to a drm
2006a8a66edSDaniel Vetter  * object with drm_object_attach_property(). The returned property object must
2016a8a66edSDaniel Vetter  * be freed with drm_property_destroy(), which is done automatically when
2026a8a66edSDaniel Vetter  * calling drm_mode_config_cleanup().
20359e71ee7SDaniel Vetter  *
20459e71ee7SDaniel Vetter  * Compared to plain enumeration properties userspace is allowed to set any
20559e71ee7SDaniel Vetter  * or'ed together combination of the predefined property bitflag values
20659e71ee7SDaniel Vetter  *
20759e71ee7SDaniel Vetter  * Returns:
20859e71ee7SDaniel Vetter  * A pointer to the newly created property on success, NULL on failure.
20959e71ee7SDaniel Vetter  */
21059e71ee7SDaniel Vetter struct drm_property *drm_property_create_bitmask(struct drm_device *dev,
21151abc976SVille Syrjälä 						 u32 flags, const char *name,
21259e71ee7SDaniel Vetter 						 const struct drm_prop_enum_list *props,
21359e71ee7SDaniel Vetter 						 int num_props,
21459e71ee7SDaniel Vetter 						 uint64_t supported_bits)
21559e71ee7SDaniel Vetter {
21659e71ee7SDaniel Vetter 	struct drm_property *property;
21730e9db6dSVille Syrjälä 	int i, ret;
21859e71ee7SDaniel Vetter 	int num_values = hweight64(supported_bits);
21959e71ee7SDaniel Vetter 
22059e71ee7SDaniel Vetter 	flags |= DRM_MODE_PROP_BITMASK;
22159e71ee7SDaniel Vetter 
22259e71ee7SDaniel Vetter 	property = drm_property_create(dev, flags, name, num_values);
22359e71ee7SDaniel Vetter 	if (!property)
22459e71ee7SDaniel Vetter 		return NULL;
22559e71ee7SDaniel Vetter 	for (i = 0; i < num_props; i++) {
22659e71ee7SDaniel Vetter 		if (!(supported_bits & (1ULL << props[i].type)))
22759e71ee7SDaniel Vetter 			continue;
22859e71ee7SDaniel Vetter 
22930e9db6dSVille Syrjälä 		ret = drm_property_add_enum(property,
23059e71ee7SDaniel Vetter 					    props[i].type,
23159e71ee7SDaniel Vetter 					    props[i].name);
23259e71ee7SDaniel Vetter 		if (ret) {
23359e71ee7SDaniel Vetter 			drm_property_destroy(dev, property);
23459e71ee7SDaniel Vetter 			return NULL;
23559e71ee7SDaniel Vetter 		}
23659e71ee7SDaniel Vetter 	}
23759e71ee7SDaniel Vetter 
23859e71ee7SDaniel Vetter 	return property;
23959e71ee7SDaniel Vetter }
24059e71ee7SDaniel Vetter EXPORT_SYMBOL(drm_property_create_bitmask);
24159e71ee7SDaniel Vetter 
24259e71ee7SDaniel Vetter static struct drm_property *property_create_range(struct drm_device *dev,
24351abc976SVille Syrjälä 						  u32 flags, const char *name,
24459e71ee7SDaniel Vetter 						  uint64_t min, uint64_t max)
24559e71ee7SDaniel Vetter {
24659e71ee7SDaniel Vetter 	struct drm_property *property;
24759e71ee7SDaniel Vetter 
24859e71ee7SDaniel Vetter 	property = drm_property_create(dev, flags, name, 2);
24959e71ee7SDaniel Vetter 	if (!property)
25059e71ee7SDaniel Vetter 		return NULL;
25159e71ee7SDaniel Vetter 
25259e71ee7SDaniel Vetter 	property->values[0] = min;
25359e71ee7SDaniel Vetter 	property->values[1] = max;
25459e71ee7SDaniel Vetter 
25559e71ee7SDaniel Vetter 	return property;
25659e71ee7SDaniel Vetter }
25759e71ee7SDaniel Vetter 
25859e71ee7SDaniel Vetter /**
25959e71ee7SDaniel Vetter  * drm_property_create_range - create a new unsigned ranged property type
26059e71ee7SDaniel Vetter  * @dev: drm device
26159e71ee7SDaniel Vetter  * @flags: flags specifying the property type
26259e71ee7SDaniel Vetter  * @name: name of the property
26359e71ee7SDaniel Vetter  * @min: minimum value of the property
26459e71ee7SDaniel Vetter  * @max: maximum value of the property
26559e71ee7SDaniel Vetter  *
26659e71ee7SDaniel Vetter  * This creates a new generic drm property which can then be attached to a drm
2676a8a66edSDaniel Vetter  * object with drm_object_attach_property(). The returned property object must
2686a8a66edSDaniel Vetter  * be freed with drm_property_destroy(), which is done automatically when
2696a8a66edSDaniel Vetter  * calling drm_mode_config_cleanup().
27059e71ee7SDaniel Vetter  *
27159e71ee7SDaniel Vetter  * Userspace is allowed to set any unsigned integer value in the (min, max)
27259e71ee7SDaniel Vetter  * range inclusive.
27359e71ee7SDaniel Vetter  *
27459e71ee7SDaniel Vetter  * Returns:
27559e71ee7SDaniel Vetter  * A pointer to the newly created property on success, NULL on failure.
27659e71ee7SDaniel Vetter  */
27751abc976SVille Syrjälä struct drm_property *drm_property_create_range(struct drm_device *dev,
27851abc976SVille Syrjälä 					       u32 flags, const char *name,
27959e71ee7SDaniel Vetter 					       uint64_t min, uint64_t max)
28059e71ee7SDaniel Vetter {
28159e71ee7SDaniel Vetter 	return property_create_range(dev, DRM_MODE_PROP_RANGE | flags,
28259e71ee7SDaniel Vetter 			name, min, max);
28359e71ee7SDaniel Vetter }
28459e71ee7SDaniel Vetter EXPORT_SYMBOL(drm_property_create_range);
28559e71ee7SDaniel Vetter 
28659e71ee7SDaniel Vetter /**
28759e71ee7SDaniel Vetter  * drm_property_create_signed_range - create a new signed ranged property type
28859e71ee7SDaniel Vetter  * @dev: drm device
28959e71ee7SDaniel Vetter  * @flags: flags specifying the property type
29059e71ee7SDaniel Vetter  * @name: name of the property
29159e71ee7SDaniel Vetter  * @min: minimum value of the property
29259e71ee7SDaniel Vetter  * @max: maximum value of the property
29359e71ee7SDaniel Vetter  *
29459e71ee7SDaniel Vetter  * This creates a new generic drm property which can then be attached to a drm
2956a8a66edSDaniel Vetter  * object with drm_object_attach_property(). The returned property object must
2966a8a66edSDaniel Vetter  * be freed with drm_property_destroy(), which is done automatically when
2976a8a66edSDaniel Vetter  * calling drm_mode_config_cleanup().
29859e71ee7SDaniel Vetter  *
29959e71ee7SDaniel Vetter  * Userspace is allowed to set any signed integer value in the (min, max)
30059e71ee7SDaniel Vetter  * range inclusive.
30159e71ee7SDaniel Vetter  *
30259e71ee7SDaniel Vetter  * Returns:
30359e71ee7SDaniel Vetter  * A pointer to the newly created property on success, NULL on failure.
30459e71ee7SDaniel Vetter  */
30559e71ee7SDaniel Vetter struct drm_property *drm_property_create_signed_range(struct drm_device *dev,
30651abc976SVille Syrjälä 						      u32 flags, const char *name,
30759e71ee7SDaniel Vetter 						      int64_t min, int64_t max)
30859e71ee7SDaniel Vetter {
30959e71ee7SDaniel Vetter 	return property_create_range(dev, DRM_MODE_PROP_SIGNED_RANGE | flags,
31059e71ee7SDaniel Vetter 			name, I642U64(min), I642U64(max));
31159e71ee7SDaniel Vetter }
31259e71ee7SDaniel Vetter EXPORT_SYMBOL(drm_property_create_signed_range);
31359e71ee7SDaniel Vetter 
31459e71ee7SDaniel Vetter /**
31559e71ee7SDaniel Vetter  * drm_property_create_object - create a new object property type
31659e71ee7SDaniel Vetter  * @dev: drm device
31759e71ee7SDaniel Vetter  * @flags: flags specifying the property type
31859e71ee7SDaniel Vetter  * @name: name of the property
31959e71ee7SDaniel Vetter  * @type: object type from DRM_MODE_OBJECT_* defines
32059e71ee7SDaniel Vetter  *
32159e71ee7SDaniel Vetter  * This creates a new generic drm property which can then be attached to a drm
3226a8a66edSDaniel Vetter  * object with drm_object_attach_property(). The returned property object must
3236a8a66edSDaniel Vetter  * be freed with drm_property_destroy(), which is done automatically when
3246a8a66edSDaniel Vetter  * calling drm_mode_config_cleanup().
32559e71ee7SDaniel Vetter  *
32659e71ee7SDaniel Vetter  * Userspace is only allowed to set this to any property value of the given
32759e71ee7SDaniel Vetter  * @type. Only useful for atomic properties, which is enforced.
32859e71ee7SDaniel Vetter  *
32959e71ee7SDaniel Vetter  * Returns:
33059e71ee7SDaniel Vetter  * A pointer to the newly created property on success, NULL on failure.
33159e71ee7SDaniel Vetter  */
33259e71ee7SDaniel Vetter struct drm_property *drm_property_create_object(struct drm_device *dev,
33351abc976SVille Syrjälä 						u32 flags, const char *name,
334c8458c7eSDaniel Vetter 						uint32_t type)
33559e71ee7SDaniel Vetter {
33659e71ee7SDaniel Vetter 	struct drm_property *property;
33759e71ee7SDaniel Vetter 
33859e71ee7SDaniel Vetter 	flags |= DRM_MODE_PROP_OBJECT;
33959e71ee7SDaniel Vetter 
34059e71ee7SDaniel Vetter 	if (WARN_ON(!(flags & DRM_MODE_PROP_ATOMIC)))
34159e71ee7SDaniel Vetter 		return NULL;
34259e71ee7SDaniel Vetter 
34359e71ee7SDaniel Vetter 	property = drm_property_create(dev, flags, name, 1);
34459e71ee7SDaniel Vetter 	if (!property)
34559e71ee7SDaniel Vetter 		return NULL;
34659e71ee7SDaniel Vetter 
34759e71ee7SDaniel Vetter 	property->values[0] = type;
34859e71ee7SDaniel Vetter 
34959e71ee7SDaniel Vetter 	return property;
35059e71ee7SDaniel Vetter }
35159e71ee7SDaniel Vetter EXPORT_SYMBOL(drm_property_create_object);
35259e71ee7SDaniel Vetter 
35359e71ee7SDaniel Vetter /**
35459e71ee7SDaniel Vetter  * drm_property_create_bool - create a new boolean property type
35559e71ee7SDaniel Vetter  * @dev: drm device
35659e71ee7SDaniel Vetter  * @flags: flags specifying the property type
35759e71ee7SDaniel Vetter  * @name: name of the property
35859e71ee7SDaniel Vetter  *
35959e71ee7SDaniel Vetter  * This creates a new generic drm property which can then be attached to a drm
3606a8a66edSDaniel Vetter  * object with drm_object_attach_property(). The returned property object must
3616a8a66edSDaniel Vetter  * be freed with drm_property_destroy(), which is done automatically when
3626a8a66edSDaniel Vetter  * calling drm_mode_config_cleanup().
36359e71ee7SDaniel Vetter  *
36459e71ee7SDaniel Vetter  * This is implemented as a ranged property with only {0, 1} as valid values.
36559e71ee7SDaniel Vetter  *
36659e71ee7SDaniel Vetter  * Returns:
36759e71ee7SDaniel Vetter  * A pointer to the newly created property on success, NULL on failure.
36859e71ee7SDaniel Vetter  */
36951abc976SVille Syrjälä struct drm_property *drm_property_create_bool(struct drm_device *dev,
37051abc976SVille Syrjälä 					      u32 flags, const char *name)
37159e71ee7SDaniel Vetter {
37259e71ee7SDaniel Vetter 	return drm_property_create_range(dev, flags, name, 0, 1);
37359e71ee7SDaniel Vetter }
37459e71ee7SDaniel Vetter EXPORT_SYMBOL(drm_property_create_bool);
37559e71ee7SDaniel Vetter 
37659e71ee7SDaniel Vetter /**
37759e71ee7SDaniel Vetter  * drm_property_add_enum - add a possible value to an enumeration property
37859e71ee7SDaniel Vetter  * @property: enumeration property to change
37959e71ee7SDaniel Vetter  * @value: value of the new enumeration
38059e71ee7SDaniel Vetter  * @name: symbolic name of the new enumeration
38159e71ee7SDaniel Vetter  *
38259e71ee7SDaniel Vetter  * This functions adds enumerations to a property.
38359e71ee7SDaniel Vetter  *
38459e71ee7SDaniel Vetter  * It's use is deprecated, drivers should use one of the more specific helpers
38559e71ee7SDaniel Vetter  * to directly create the property with all enumerations already attached.
38659e71ee7SDaniel Vetter  *
38759e71ee7SDaniel Vetter  * Returns:
38859e71ee7SDaniel Vetter  * Zero on success, error code on failure.
38959e71ee7SDaniel Vetter  */
39030e9db6dSVille Syrjälä int drm_property_add_enum(struct drm_property *property,
39159e71ee7SDaniel Vetter 			  uint64_t value, const char *name)
39259e71ee7SDaniel Vetter {
39359e71ee7SDaniel Vetter 	struct drm_property_enum *prop_enum;
39430e9db6dSVille Syrjälä 	int index = 0;
39559e71ee7SDaniel Vetter 
3965ebbb5b4SVille Syrjälä 	if (WARN_ON(strlen(name) >= DRM_PROP_NAME_LEN))
3975ebbb5b4SVille Syrjälä 		return -EINVAL;
3985ebbb5b4SVille Syrjälä 
3991371f260SVille Syrjälä 	if (WARN_ON(!drm_property_type_is(property, DRM_MODE_PROP_ENUM) &&
4001371f260SVille Syrjälä 		    !drm_property_type_is(property, DRM_MODE_PROP_BITMASK)))
40159e71ee7SDaniel Vetter 		return -EINVAL;
40259e71ee7SDaniel Vetter 
40359e71ee7SDaniel Vetter 	/*
40459e71ee7SDaniel Vetter 	 * Bitmask enum properties have the additional constraint of values
40559e71ee7SDaniel Vetter 	 * from 0 to 63
40659e71ee7SDaniel Vetter 	 */
4078c6c2fe2SVille Syrjälä 	if (WARN_ON(drm_property_type_is(property, DRM_MODE_PROP_BITMASK) &&
4088c6c2fe2SVille Syrjälä 		    value > 63))
40959e71ee7SDaniel Vetter 		return -EINVAL;
41059e71ee7SDaniel Vetter 
41159e71ee7SDaniel Vetter 	list_for_each_entry(prop_enum, &property->enum_list, head) {
4126f881d04SVille Syrjälä 		if (WARN_ON(prop_enum->value == value))
4136f881d04SVille Syrjälä 			return -EINVAL;
41430e9db6dSVille Syrjälä 		index++;
41559e71ee7SDaniel Vetter 	}
41659e71ee7SDaniel Vetter 
41730e9db6dSVille Syrjälä 	if (WARN_ON(index >= property->num_values))
41830e9db6dSVille Syrjälä 		return -EINVAL;
41930e9db6dSVille Syrjälä 
42059e71ee7SDaniel Vetter 	prop_enum = kzalloc(sizeof(struct drm_property_enum), GFP_KERNEL);
42159e71ee7SDaniel Vetter 	if (!prop_enum)
42259e71ee7SDaniel Vetter 		return -ENOMEM;
42359e71ee7SDaniel Vetter 
42459e71ee7SDaniel Vetter 	strncpy(prop_enum->name, name, DRM_PROP_NAME_LEN);
42559e71ee7SDaniel Vetter 	prop_enum->name[DRM_PROP_NAME_LEN-1] = '\0';
42659e71ee7SDaniel Vetter 	prop_enum->value = value;
42759e71ee7SDaniel Vetter 
42859e71ee7SDaniel Vetter 	property->values[index] = value;
42959e71ee7SDaniel Vetter 	list_add_tail(&prop_enum->head, &property->enum_list);
43059e71ee7SDaniel Vetter 	return 0;
43159e71ee7SDaniel Vetter }
43259e71ee7SDaniel Vetter EXPORT_SYMBOL(drm_property_add_enum);
43359e71ee7SDaniel Vetter 
43459e71ee7SDaniel Vetter /**
43559e71ee7SDaniel Vetter  * drm_property_destroy - destroy a drm property
43659e71ee7SDaniel Vetter  * @dev: drm device
437*0ae865efSCai Huoqing  * @property: property to destroy
43859e71ee7SDaniel Vetter  *
43959e71ee7SDaniel Vetter  * This function frees a property including any attached resources like
44059e71ee7SDaniel Vetter  * enumeration values.
44159e71ee7SDaniel Vetter  */
44259e71ee7SDaniel Vetter void drm_property_destroy(struct drm_device *dev, struct drm_property *property)
44359e71ee7SDaniel Vetter {
44459e71ee7SDaniel Vetter 	struct drm_property_enum *prop_enum, *pt;
44559e71ee7SDaniel Vetter 
44659e71ee7SDaniel Vetter 	list_for_each_entry_safe(prop_enum, pt, &property->enum_list, head) {
44759e71ee7SDaniel Vetter 		list_del(&prop_enum->head);
44859e71ee7SDaniel Vetter 		kfree(prop_enum);
44959e71ee7SDaniel Vetter 	}
45059e71ee7SDaniel Vetter 
45159e71ee7SDaniel Vetter 	if (property->num_values)
45259e71ee7SDaniel Vetter 		kfree(property->values);
45359e71ee7SDaniel Vetter 	drm_mode_object_unregister(dev, &property->base);
45459e71ee7SDaniel Vetter 	list_del(&property->head);
45559e71ee7SDaniel Vetter 	kfree(property);
45659e71ee7SDaniel Vetter }
45759e71ee7SDaniel Vetter EXPORT_SYMBOL(drm_property_destroy);
45859e71ee7SDaniel Vetter 
45959e71ee7SDaniel Vetter int drm_mode_getproperty_ioctl(struct drm_device *dev,
46059e71ee7SDaniel Vetter 			       void *data, struct drm_file *file_priv)
46159e71ee7SDaniel Vetter {
46259e71ee7SDaniel Vetter 	struct drm_mode_get_property *out_resp = data;
46359e71ee7SDaniel Vetter 	struct drm_property *property;
46459e71ee7SDaniel Vetter 	int enum_count = 0;
46559e71ee7SDaniel Vetter 	int value_count = 0;
466eb8eb02eSDaniel Vetter 	int i, copied;
46759e71ee7SDaniel Vetter 	struct drm_property_enum *prop_enum;
46859e71ee7SDaniel Vetter 	struct drm_mode_property_enum __user *enum_ptr;
46959e71ee7SDaniel Vetter 	uint64_t __user *values_ptr;
47059e71ee7SDaniel Vetter 
47159e71ee7SDaniel Vetter 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
47269fdf420SChris Wilson 		return -EOPNOTSUPP;
47359e71ee7SDaniel Vetter 
474418da172SKeith Packard 	property = drm_property_find(dev, file_priv, out_resp->prop_id);
475eb8eb02eSDaniel Vetter 	if (!property)
476eb8eb02eSDaniel Vetter 		return -ENOENT;
47759e71ee7SDaniel Vetter 
47859e71ee7SDaniel Vetter 	strncpy(out_resp->name, property->name, DRM_PROP_NAME_LEN);
47959e71ee7SDaniel Vetter 	out_resp->name[DRM_PROP_NAME_LEN-1] = 0;
48059e71ee7SDaniel Vetter 	out_resp->flags = property->flags;
48159e71ee7SDaniel Vetter 
482eb8eb02eSDaniel Vetter 	value_count = property->num_values;
483eb8eb02eSDaniel Vetter 	values_ptr = u64_to_user_ptr(out_resp->values_ptr);
484eb8eb02eSDaniel Vetter 
48559e71ee7SDaniel Vetter 	for (i = 0; i < value_count; i++) {
486eb8eb02eSDaniel Vetter 		if (i < out_resp->count_values &&
487eb8eb02eSDaniel Vetter 		    put_user(property->values[i], values_ptr + i)) {
488eb8eb02eSDaniel Vetter 			return -EFAULT;
48959e71ee7SDaniel Vetter 		}
49059e71ee7SDaniel Vetter 	}
49159e71ee7SDaniel Vetter 	out_resp->count_values = value_count;
49259e71ee7SDaniel Vetter 
493eb8eb02eSDaniel Vetter 	copied = 0;
494eb8eb02eSDaniel Vetter 	enum_ptr = u64_to_user_ptr(out_resp->enum_blob_ptr);
495eb8eb02eSDaniel Vetter 
49659e71ee7SDaniel Vetter 	if (drm_property_type_is(property, DRM_MODE_PROP_ENUM) ||
49759e71ee7SDaniel Vetter 	    drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) {
49859e71ee7SDaniel Vetter 		list_for_each_entry(prop_enum, &property->enum_list, head) {
499eb8eb02eSDaniel Vetter 			enum_count++;
5008cb68c83SDaniel Vetter 			if (out_resp->count_enum_blobs < enum_count)
501eb8eb02eSDaniel Vetter 				continue;
50259e71ee7SDaniel Vetter 
503eb8eb02eSDaniel Vetter 			if (copy_to_user(&enum_ptr[copied].value,
504eb8eb02eSDaniel Vetter 					 &prop_enum->value, sizeof(uint64_t)))
505eb8eb02eSDaniel Vetter 				return -EFAULT;
50659e71ee7SDaniel Vetter 
50759e71ee7SDaniel Vetter 			if (copy_to_user(&enum_ptr[copied].name,
508eb8eb02eSDaniel Vetter 					 &prop_enum->name, DRM_PROP_NAME_LEN))
509eb8eb02eSDaniel Vetter 				return -EFAULT;
51059e71ee7SDaniel Vetter 			copied++;
51159e71ee7SDaniel Vetter 		}
51259e71ee7SDaniel Vetter 		out_resp->count_enum_blobs = enum_count;
51359e71ee7SDaniel Vetter 	}
51459e71ee7SDaniel Vetter 
51559e71ee7SDaniel Vetter 	/*
51659e71ee7SDaniel Vetter 	 * NOTE: The idea seems to have been to use this to read all the blob
51759e71ee7SDaniel Vetter 	 * property values. But nothing ever added them to the corresponding
51859e71ee7SDaniel Vetter 	 * list, userspace always used the special-purpose get_blob ioctl to
51959e71ee7SDaniel Vetter 	 * read the value for a blob property. It also doesn't make a lot of
52059e71ee7SDaniel Vetter 	 * sense to return values here when everything else is just metadata for
52159e71ee7SDaniel Vetter 	 * the property itself.
52259e71ee7SDaniel Vetter 	 */
52359e71ee7SDaniel Vetter 	if (drm_property_type_is(property, DRM_MODE_PROP_BLOB))
52459e71ee7SDaniel Vetter 		out_resp->count_enum_blobs = 0;
525eb8eb02eSDaniel Vetter 
526eb8eb02eSDaniel Vetter 	return 0;
52759e71ee7SDaniel Vetter }
52859e71ee7SDaniel Vetter 
52959e71ee7SDaniel Vetter static void drm_property_free_blob(struct kref *kref)
53059e71ee7SDaniel Vetter {
53159e71ee7SDaniel Vetter 	struct drm_property_blob *blob =
53259e71ee7SDaniel Vetter 		container_of(kref, struct drm_property_blob, base.refcount);
53359e71ee7SDaniel Vetter 
53459e71ee7SDaniel Vetter 	mutex_lock(&blob->dev->mode_config.blob_lock);
53559e71ee7SDaniel Vetter 	list_del(&blob->head_global);
53659e71ee7SDaniel Vetter 	mutex_unlock(&blob->dev->mode_config.blob_lock);
53759e71ee7SDaniel Vetter 
53859e71ee7SDaniel Vetter 	drm_mode_object_unregister(blob->dev, &blob->base);
53959e71ee7SDaniel Vetter 
540718b5406SMichel Dänzer 	kvfree(blob);
54159e71ee7SDaniel Vetter }
54259e71ee7SDaniel Vetter 
54359e71ee7SDaniel Vetter /**
54459e71ee7SDaniel Vetter  * drm_property_create_blob - Create new blob property
54559e71ee7SDaniel Vetter  * @dev: DRM device to create property for
54659e71ee7SDaniel Vetter  * @length: Length to allocate for blob data
54759e71ee7SDaniel Vetter  * @data: If specified, copies data into blob
54859e71ee7SDaniel Vetter  *
549c8458c7eSDaniel Vetter  * Creates a new blob property for a specified DRM device, optionally
550c8458c7eSDaniel Vetter  * copying data. Note that blob properties are meant to be invariant, hence the
551c8458c7eSDaniel Vetter  * data must be filled out before the blob is used as the value of any property.
552c8458c7eSDaniel Vetter  *
55359e71ee7SDaniel Vetter  * Returns:
55459e71ee7SDaniel Vetter  * New blob property with a single reference on success, or an ERR_PTR
55559e71ee7SDaniel Vetter  * value on failure.
55659e71ee7SDaniel Vetter  */
55759e71ee7SDaniel Vetter struct drm_property_blob *
55859e71ee7SDaniel Vetter drm_property_create_blob(struct drm_device *dev, size_t length,
55959e71ee7SDaniel Vetter 			 const void *data)
56059e71ee7SDaniel Vetter {
56159e71ee7SDaniel Vetter 	struct drm_property_blob *blob;
56259e71ee7SDaniel Vetter 	int ret;
56359e71ee7SDaniel Vetter 
5645bf8bec3SDaniel Vetter 	if (!length || length > INT_MAX - sizeof(struct drm_property_blob))
56559e71ee7SDaniel Vetter 		return ERR_PTR(-EINVAL);
56659e71ee7SDaniel Vetter 
567718b5406SMichel Dänzer 	blob = kvzalloc(sizeof(struct drm_property_blob)+length, GFP_KERNEL);
56859e71ee7SDaniel Vetter 	if (!blob)
56959e71ee7SDaniel Vetter 		return ERR_PTR(-ENOMEM);
57059e71ee7SDaniel Vetter 
57159e71ee7SDaniel Vetter 	/* This must be explicitly initialised, so we can safely call list_del
57259e71ee7SDaniel Vetter 	 * on it in the removal handler, even if it isn't in a file list. */
57359e71ee7SDaniel Vetter 	INIT_LIST_HEAD(&blob->head_file);
5749c60583cSVille Syrjälä 	blob->data = (void *)blob + sizeof(*blob);
57559e71ee7SDaniel Vetter 	blob->length = length;
57659e71ee7SDaniel Vetter 	blob->dev = dev;
57759e71ee7SDaniel Vetter 
57859e71ee7SDaniel Vetter 	if (data)
57959e71ee7SDaniel Vetter 		memcpy(blob->data, data, length);
58059e71ee7SDaniel Vetter 
5812135ea7aSThierry Reding 	ret = __drm_mode_object_add(dev, &blob->base, DRM_MODE_OBJECT_BLOB,
58259e71ee7SDaniel Vetter 				    true, drm_property_free_blob);
58359e71ee7SDaniel Vetter 	if (ret) {
584718b5406SMichel Dänzer 		kvfree(blob);
58559e71ee7SDaniel Vetter 		return ERR_PTR(-EINVAL);
58659e71ee7SDaniel Vetter 	}
58759e71ee7SDaniel Vetter 
58859e71ee7SDaniel Vetter 	mutex_lock(&dev->mode_config.blob_lock);
58959e71ee7SDaniel Vetter 	list_add_tail(&blob->head_global,
59059e71ee7SDaniel Vetter 	              &dev->mode_config.property_blob_list);
59159e71ee7SDaniel Vetter 	mutex_unlock(&dev->mode_config.blob_lock);
59259e71ee7SDaniel Vetter 
59359e71ee7SDaniel Vetter 	return blob;
59459e71ee7SDaniel Vetter }
59559e71ee7SDaniel Vetter EXPORT_SYMBOL(drm_property_create_blob);
59659e71ee7SDaniel Vetter 
59759e71ee7SDaniel Vetter /**
5986472e509SThierry Reding  * drm_property_blob_put - release a blob property reference
5996472e509SThierry Reding  * @blob: DRM blob property
60059e71ee7SDaniel Vetter  *
6016472e509SThierry Reding  * Releases a reference to a blob property. May free the object.
60259e71ee7SDaniel Vetter  */
6036472e509SThierry Reding void drm_property_blob_put(struct drm_property_blob *blob)
60459e71ee7SDaniel Vetter {
60559e71ee7SDaniel Vetter 	if (!blob)
60659e71ee7SDaniel Vetter 		return;
60759e71ee7SDaniel Vetter 
608020a218fSThierry Reding 	drm_mode_object_put(&blob->base);
60959e71ee7SDaniel Vetter }
6106472e509SThierry Reding EXPORT_SYMBOL(drm_property_blob_put);
61159e71ee7SDaniel Vetter 
61259e71ee7SDaniel Vetter void drm_property_destroy_user_blobs(struct drm_device *dev,
61359e71ee7SDaniel Vetter 				     struct drm_file *file_priv)
61459e71ee7SDaniel Vetter {
61559e71ee7SDaniel Vetter 	struct drm_property_blob *blob, *bt;
61659e71ee7SDaniel Vetter 
61759e71ee7SDaniel Vetter 	/*
61859e71ee7SDaniel Vetter 	 * When the file gets released that means no one else can access the
61959e71ee7SDaniel Vetter 	 * blob list any more, so no need to grab dev->blob_lock.
62059e71ee7SDaniel Vetter 	 */
62159e71ee7SDaniel Vetter 	list_for_each_entry_safe(blob, bt, &file_priv->blobs, head_file) {
62259e71ee7SDaniel Vetter 		list_del_init(&blob->head_file);
6236472e509SThierry Reding 		drm_property_blob_put(blob);
62459e71ee7SDaniel Vetter 	}
62559e71ee7SDaniel Vetter }
62659e71ee7SDaniel Vetter 
62759e71ee7SDaniel Vetter /**
6286472e509SThierry Reding  * drm_property_blob_get - acquire blob property reference
6296472e509SThierry Reding  * @blob: DRM blob property
630c8458c7eSDaniel Vetter  *
6316472e509SThierry Reding  * Acquires a reference to an existing blob property. Returns @blob, which
632c8458c7eSDaniel Vetter  * allows this to be used as a shorthand in assignments.
63359e71ee7SDaniel Vetter  */
6346472e509SThierry Reding struct drm_property_blob *drm_property_blob_get(struct drm_property_blob *blob)
63559e71ee7SDaniel Vetter {
636020a218fSThierry Reding 	drm_mode_object_get(&blob->base);
63759e71ee7SDaniel Vetter 	return blob;
63859e71ee7SDaniel Vetter }
6396472e509SThierry Reding EXPORT_SYMBOL(drm_property_blob_get);
64059e71ee7SDaniel Vetter 
64159e71ee7SDaniel Vetter /**
64259e71ee7SDaniel Vetter  * drm_property_lookup_blob - look up a blob property and take a reference
64359e71ee7SDaniel Vetter  * @dev: drm device
64459e71ee7SDaniel Vetter  * @id: id of the blob property
64559e71ee7SDaniel Vetter  *
64659e71ee7SDaniel Vetter  * If successful, this takes an additional reference to the blob property.
6474cf1d871SBhaskar Chowdhury  * callers need to make sure to eventually unreferenced the returned property
6486472e509SThierry Reding  * again, using drm_property_blob_put().
649c8458c7eSDaniel Vetter  *
650c8458c7eSDaniel Vetter  * Return:
651c8458c7eSDaniel Vetter  * NULL on failure, pointer to the blob on success.
65259e71ee7SDaniel Vetter  */
65359e71ee7SDaniel Vetter struct drm_property_blob *drm_property_lookup_blob(struct drm_device *dev,
65459e71ee7SDaniel Vetter 					           uint32_t id)
65559e71ee7SDaniel Vetter {
65659e71ee7SDaniel Vetter 	struct drm_mode_object *obj;
65759e71ee7SDaniel Vetter 	struct drm_property_blob *blob = NULL;
65859e71ee7SDaniel Vetter 
659418da172SKeith Packard 	obj = __drm_mode_object_find(dev, NULL, id, DRM_MODE_OBJECT_BLOB);
66059e71ee7SDaniel Vetter 	if (obj)
66159e71ee7SDaniel Vetter 		blob = obj_to_blob(obj);
66259e71ee7SDaniel Vetter 	return blob;
66359e71ee7SDaniel Vetter }
66459e71ee7SDaniel Vetter EXPORT_SYMBOL(drm_property_lookup_blob);
66559e71ee7SDaniel Vetter 
66659e71ee7SDaniel Vetter /**
667c8458c7eSDaniel Vetter  * drm_property_replace_global_blob - replace existing blob property
66859e71ee7SDaniel Vetter  * @dev: drm device
66959e71ee7SDaniel Vetter  * @replace: location of blob property pointer to be replaced
67059e71ee7SDaniel Vetter  * @length: length of data for new blob, or 0 for no data
67159e71ee7SDaniel Vetter  * @data: content for new blob, or NULL for no data
67259e71ee7SDaniel Vetter  * @obj_holds_id: optional object for property holding blob ID
67359e71ee7SDaniel Vetter  * @prop_holds_id: optional property holding blob ID
67459e71ee7SDaniel Vetter  * @return 0 on success or error on failure
67559e71ee7SDaniel Vetter  *
676c8458c7eSDaniel Vetter  * This function will replace a global property in the blob list, optionally
677c8458c7eSDaniel Vetter  * updating a property which holds the ID of that property.
67859e71ee7SDaniel Vetter  *
67959e71ee7SDaniel Vetter  * If length is 0 or data is NULL, no new blob will be created, and the holding
68059e71ee7SDaniel Vetter  * property, if specified, will be set to 0.
68159e71ee7SDaniel Vetter  *
68259e71ee7SDaniel Vetter  * Access to the replace pointer is assumed to be protected by the caller, e.g.
68359e71ee7SDaniel Vetter  * by holding the relevant modesetting object lock for its parent.
68459e71ee7SDaniel Vetter  *
68559e71ee7SDaniel Vetter  * For example, a drm_connector has a 'PATH' property, which contains the ID
68659e71ee7SDaniel Vetter  * of a blob property with the value of the MST path information. Calling this
68759e71ee7SDaniel Vetter  * function with replace pointing to the connector's path_blob_ptr, length and
68859e71ee7SDaniel Vetter  * data set for the new path information, obj_holds_id set to the connector's
68959e71ee7SDaniel Vetter  * base object, and prop_holds_id set to the path property name, will perform
69059e71ee7SDaniel Vetter  * a completely atomic update. The access to path_blob_ptr is protected by the
69159e71ee7SDaniel Vetter  * caller holding a lock on the connector.
69259e71ee7SDaniel Vetter  */
69359e71ee7SDaniel Vetter int drm_property_replace_global_blob(struct drm_device *dev,
69459e71ee7SDaniel Vetter 				     struct drm_property_blob **replace,
69559e71ee7SDaniel Vetter 				     size_t length,
69659e71ee7SDaniel Vetter 				     const void *data,
69759e71ee7SDaniel Vetter 				     struct drm_mode_object *obj_holds_id,
69859e71ee7SDaniel Vetter 				     struct drm_property *prop_holds_id)
69959e71ee7SDaniel Vetter {
70059e71ee7SDaniel Vetter 	struct drm_property_blob *new_blob = NULL;
70159e71ee7SDaniel Vetter 	struct drm_property_blob *old_blob = NULL;
70259e71ee7SDaniel Vetter 	int ret;
70359e71ee7SDaniel Vetter 
70459e71ee7SDaniel Vetter 	WARN_ON(replace == NULL);
70559e71ee7SDaniel Vetter 
70659e71ee7SDaniel Vetter 	old_blob = *replace;
70759e71ee7SDaniel Vetter 
70859e71ee7SDaniel Vetter 	if (length && data) {
70959e71ee7SDaniel Vetter 		new_blob = drm_property_create_blob(dev, length, data);
71059e71ee7SDaniel Vetter 		if (IS_ERR(new_blob))
71159e71ee7SDaniel Vetter 			return PTR_ERR(new_blob);
71259e71ee7SDaniel Vetter 	}
71359e71ee7SDaniel Vetter 
71459e71ee7SDaniel Vetter 	if (obj_holds_id) {
71559e71ee7SDaniel Vetter 		ret = drm_object_property_set_value(obj_holds_id,
71659e71ee7SDaniel Vetter 						    prop_holds_id,
71759e71ee7SDaniel Vetter 						    new_blob ?
71859e71ee7SDaniel Vetter 						        new_blob->base.id : 0);
71959e71ee7SDaniel Vetter 		if (ret != 0)
72059e71ee7SDaniel Vetter 			goto err_created;
72159e71ee7SDaniel Vetter 	}
72259e71ee7SDaniel Vetter 
7236472e509SThierry Reding 	drm_property_blob_put(old_blob);
72459e71ee7SDaniel Vetter 	*replace = new_blob;
72559e71ee7SDaniel Vetter 
72659e71ee7SDaniel Vetter 	return 0;
72759e71ee7SDaniel Vetter 
72859e71ee7SDaniel Vetter err_created:
7296472e509SThierry Reding 	drm_property_blob_put(new_blob);
73059e71ee7SDaniel Vetter 	return ret;
73159e71ee7SDaniel Vetter }
73259e71ee7SDaniel Vetter EXPORT_SYMBOL(drm_property_replace_global_blob);
73359e71ee7SDaniel Vetter 
7345f057ffdSPeter Rosin /**
7355f057ffdSPeter Rosin  * drm_property_replace_blob - replace a blob property
7365f057ffdSPeter Rosin  * @blob: a pointer to the member blob to be replaced
7375f057ffdSPeter Rosin  * @new_blob: the new blob to replace with
7385f057ffdSPeter Rosin  *
7395f057ffdSPeter Rosin  * Return: true if the blob was in fact replaced.
7405f057ffdSPeter Rosin  */
7415f057ffdSPeter Rosin bool drm_property_replace_blob(struct drm_property_blob **blob,
7425f057ffdSPeter Rosin 			       struct drm_property_blob *new_blob)
7435f057ffdSPeter Rosin {
7445f057ffdSPeter Rosin 	struct drm_property_blob *old_blob = *blob;
7455f057ffdSPeter Rosin 
7465f057ffdSPeter Rosin 	if (old_blob == new_blob)
7475f057ffdSPeter Rosin 		return false;
7485f057ffdSPeter Rosin 
7495f057ffdSPeter Rosin 	drm_property_blob_put(old_blob);
7505f057ffdSPeter Rosin 	if (new_blob)
7515f057ffdSPeter Rosin 		drm_property_blob_get(new_blob);
7525f057ffdSPeter Rosin 	*blob = new_blob;
7535f057ffdSPeter Rosin 	return true;
7545f057ffdSPeter Rosin }
7555f057ffdSPeter Rosin EXPORT_SYMBOL(drm_property_replace_blob);
7565f057ffdSPeter Rosin 
75759e71ee7SDaniel Vetter int drm_mode_getblob_ioctl(struct drm_device *dev,
75859e71ee7SDaniel Vetter 			   void *data, struct drm_file *file_priv)
75959e71ee7SDaniel Vetter {
76059e71ee7SDaniel Vetter 	struct drm_mode_get_blob *out_resp = data;
76159e71ee7SDaniel Vetter 	struct drm_property_blob *blob;
76259e71ee7SDaniel Vetter 	int ret = 0;
76359e71ee7SDaniel Vetter 
76459e71ee7SDaniel Vetter 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
76569fdf420SChris Wilson 		return -EOPNOTSUPP;
76659e71ee7SDaniel Vetter 
76759e71ee7SDaniel Vetter 	blob = drm_property_lookup_blob(dev, out_resp->blob_id);
76859e71ee7SDaniel Vetter 	if (!blob)
76959e71ee7SDaniel Vetter 		return -ENOENT;
77059e71ee7SDaniel Vetter 
77159e71ee7SDaniel Vetter 	if (out_resp->length == blob->length) {
77275df6247SChris Wilson 		if (copy_to_user(u64_to_user_ptr(out_resp->data),
77375df6247SChris Wilson 				 blob->data,
77475df6247SChris Wilson 				 blob->length)) {
77559e71ee7SDaniel Vetter 			ret = -EFAULT;
77659e71ee7SDaniel Vetter 			goto unref;
77759e71ee7SDaniel Vetter 		}
77859e71ee7SDaniel Vetter 	}
77959e71ee7SDaniel Vetter 	out_resp->length = blob->length;
78059e71ee7SDaniel Vetter unref:
7816472e509SThierry Reding 	drm_property_blob_put(blob);
78259e71ee7SDaniel Vetter 
78359e71ee7SDaniel Vetter 	return ret;
78459e71ee7SDaniel Vetter }
78559e71ee7SDaniel Vetter 
78659e71ee7SDaniel Vetter int drm_mode_createblob_ioctl(struct drm_device *dev,
78759e71ee7SDaniel Vetter 			      void *data, struct drm_file *file_priv)
78859e71ee7SDaniel Vetter {
78959e71ee7SDaniel Vetter 	struct drm_mode_create_blob *out_resp = data;
79059e71ee7SDaniel Vetter 	struct drm_property_blob *blob;
79159e71ee7SDaniel Vetter 	int ret = 0;
79259e71ee7SDaniel Vetter 
79359e71ee7SDaniel Vetter 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
79469fdf420SChris Wilson 		return -EOPNOTSUPP;
79559e71ee7SDaniel Vetter 
79659e71ee7SDaniel Vetter 	blob = drm_property_create_blob(dev, out_resp->length, NULL);
79759e71ee7SDaniel Vetter 	if (IS_ERR(blob))
79859e71ee7SDaniel Vetter 		return PTR_ERR(blob);
79959e71ee7SDaniel Vetter 
80075df6247SChris Wilson 	if (copy_from_user(blob->data,
80175df6247SChris Wilson 			   u64_to_user_ptr(out_resp->data),
80275df6247SChris Wilson 			   out_resp->length)) {
80359e71ee7SDaniel Vetter 		ret = -EFAULT;
80459e71ee7SDaniel Vetter 		goto out_blob;
80559e71ee7SDaniel Vetter 	}
80659e71ee7SDaniel Vetter 
80759e71ee7SDaniel Vetter 	/* Dropping the lock between create_blob and our access here is safe
80859e71ee7SDaniel Vetter 	 * as only the same file_priv can remove the blob; at this point, it is
80959e71ee7SDaniel Vetter 	 * not associated with any file_priv. */
81059e71ee7SDaniel Vetter 	mutex_lock(&dev->mode_config.blob_lock);
81159e71ee7SDaniel Vetter 	out_resp->blob_id = blob->base.id;
81259e71ee7SDaniel Vetter 	list_add_tail(&blob->head_file, &file_priv->blobs);
81359e71ee7SDaniel Vetter 	mutex_unlock(&dev->mode_config.blob_lock);
81459e71ee7SDaniel Vetter 
81559e71ee7SDaniel Vetter 	return 0;
81659e71ee7SDaniel Vetter 
81759e71ee7SDaniel Vetter out_blob:
8186472e509SThierry Reding 	drm_property_blob_put(blob);
81959e71ee7SDaniel Vetter 	return ret;
82059e71ee7SDaniel Vetter }
82159e71ee7SDaniel Vetter 
82259e71ee7SDaniel Vetter int drm_mode_destroyblob_ioctl(struct drm_device *dev,
82359e71ee7SDaniel Vetter 			       void *data, struct drm_file *file_priv)
82459e71ee7SDaniel Vetter {
82559e71ee7SDaniel Vetter 	struct drm_mode_destroy_blob *out_resp = data;
82659e71ee7SDaniel Vetter 	struct drm_property_blob *blob = NULL, *bt;
82759e71ee7SDaniel Vetter 	bool found = false;
82859e71ee7SDaniel Vetter 	int ret = 0;
82959e71ee7SDaniel Vetter 
83059e71ee7SDaniel Vetter 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
83169fdf420SChris Wilson 		return -EOPNOTSUPP;
83259e71ee7SDaniel Vetter 
83359e71ee7SDaniel Vetter 	blob = drm_property_lookup_blob(dev, out_resp->blob_id);
83459e71ee7SDaniel Vetter 	if (!blob)
83559e71ee7SDaniel Vetter 		return -ENOENT;
83659e71ee7SDaniel Vetter 
83759e71ee7SDaniel Vetter 	mutex_lock(&dev->mode_config.blob_lock);
83859e71ee7SDaniel Vetter 	/* Ensure the property was actually created by this user. */
83959e71ee7SDaniel Vetter 	list_for_each_entry(bt, &file_priv->blobs, head_file) {
84059e71ee7SDaniel Vetter 		if (bt == blob) {
84159e71ee7SDaniel Vetter 			found = true;
84259e71ee7SDaniel Vetter 			break;
84359e71ee7SDaniel Vetter 		}
84459e71ee7SDaniel Vetter 	}
84559e71ee7SDaniel Vetter 
84659e71ee7SDaniel Vetter 	if (!found) {
84759e71ee7SDaniel Vetter 		ret = -EPERM;
84859e71ee7SDaniel Vetter 		goto err;
84959e71ee7SDaniel Vetter 	}
85059e71ee7SDaniel Vetter 
85159e71ee7SDaniel Vetter 	/* We must drop head_file here, because we may not be the last
85259e71ee7SDaniel Vetter 	 * reference on the blob. */
85359e71ee7SDaniel Vetter 	list_del_init(&blob->head_file);
85459e71ee7SDaniel Vetter 	mutex_unlock(&dev->mode_config.blob_lock);
85559e71ee7SDaniel Vetter 
85659e71ee7SDaniel Vetter 	/* One reference from lookup, and one from the filp. */
8576472e509SThierry Reding 	drm_property_blob_put(blob);
8586472e509SThierry Reding 	drm_property_blob_put(blob);
85959e71ee7SDaniel Vetter 
86059e71ee7SDaniel Vetter 	return 0;
86159e71ee7SDaniel Vetter 
86259e71ee7SDaniel Vetter err:
86359e71ee7SDaniel Vetter 	mutex_unlock(&dev->mode_config.blob_lock);
8646472e509SThierry Reding 	drm_property_blob_put(blob);
86559e71ee7SDaniel Vetter 
86659e71ee7SDaniel Vetter 	return ret;
86759e71ee7SDaniel Vetter }
86859e71ee7SDaniel Vetter 
86959e71ee7SDaniel Vetter /* Some properties could refer to dynamic refcnt'd objects, or things that
87059e71ee7SDaniel Vetter  * need special locking to handle lifetime issues (ie. to ensure the prop
87159e71ee7SDaniel Vetter  * value doesn't become invalid part way through the property update due to
87259e71ee7SDaniel Vetter  * race).  The value returned by reference via 'obj' should be passed back
87359e71ee7SDaniel Vetter  * to drm_property_change_valid_put() after the property is set (and the
8741e55a53aSMatt Roper  * object to which the property is attached has a chance to take its own
87559e71ee7SDaniel Vetter  * reference).
87659e71ee7SDaniel Vetter  */
87759e71ee7SDaniel Vetter bool drm_property_change_valid_get(struct drm_property *property,
87859e71ee7SDaniel Vetter 				   uint64_t value, struct drm_mode_object **ref)
87959e71ee7SDaniel Vetter {
88059e71ee7SDaniel Vetter 	int i;
88159e71ee7SDaniel Vetter 
88259e71ee7SDaniel Vetter 	if (property->flags & DRM_MODE_PROP_IMMUTABLE)
88359e71ee7SDaniel Vetter 		return false;
88459e71ee7SDaniel Vetter 
88559e71ee7SDaniel Vetter 	*ref = NULL;
88659e71ee7SDaniel Vetter 
88759e71ee7SDaniel Vetter 	if (drm_property_type_is(property, DRM_MODE_PROP_RANGE)) {
88859e71ee7SDaniel Vetter 		if (value < property->values[0] || value > property->values[1])
88959e71ee7SDaniel Vetter 			return false;
89059e71ee7SDaniel Vetter 		return true;
89159e71ee7SDaniel Vetter 	} else if (drm_property_type_is(property, DRM_MODE_PROP_SIGNED_RANGE)) {
89259e71ee7SDaniel Vetter 		int64_t svalue = U642I64(value);
89359e71ee7SDaniel Vetter 
89459e71ee7SDaniel Vetter 		if (svalue < U642I64(property->values[0]) ||
89559e71ee7SDaniel Vetter 				svalue > U642I64(property->values[1]))
89659e71ee7SDaniel Vetter 			return false;
89759e71ee7SDaniel Vetter 		return true;
89859e71ee7SDaniel Vetter 	} else if (drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) {
89959e71ee7SDaniel Vetter 		uint64_t valid_mask = 0;
90059e71ee7SDaniel Vetter 
90159e71ee7SDaniel Vetter 		for (i = 0; i < property->num_values; i++)
90259e71ee7SDaniel Vetter 			valid_mask |= (1ULL << property->values[i]);
90359e71ee7SDaniel Vetter 		return !(value & ~valid_mask);
90430c06570SMaarten Lankhorst 	} else if (drm_property_type_is(property, DRM_MODE_PROP_BLOB)) {
90530c06570SMaarten Lankhorst 		struct drm_property_blob *blob;
90630c06570SMaarten Lankhorst 
90730c06570SMaarten Lankhorst 		if (value == 0)
90830c06570SMaarten Lankhorst 			return true;
90930c06570SMaarten Lankhorst 
91030c06570SMaarten Lankhorst 		blob = drm_property_lookup_blob(property->dev, value);
91130c06570SMaarten Lankhorst 		if (blob) {
91230c06570SMaarten Lankhorst 			*ref = &blob->base;
91330c06570SMaarten Lankhorst 			return true;
91430c06570SMaarten Lankhorst 		} else {
91530c06570SMaarten Lankhorst 			return false;
91630c06570SMaarten Lankhorst 		}
91730c06570SMaarten Lankhorst 	} else if (drm_property_type_is(property, DRM_MODE_PROP_OBJECT)) {
91859e71ee7SDaniel Vetter 		/* a zero value for an object property translates to null: */
91959e71ee7SDaniel Vetter 		if (value == 0)
92059e71ee7SDaniel Vetter 			return true;
92159e71ee7SDaniel Vetter 
922418da172SKeith Packard 		*ref = __drm_mode_object_find(property->dev, NULL, value,
92359e71ee7SDaniel Vetter 					      property->values[0]);
92459e71ee7SDaniel Vetter 		return *ref != NULL;
92559e71ee7SDaniel Vetter 	}
92659e71ee7SDaniel Vetter 
92759e71ee7SDaniel Vetter 	for (i = 0; i < property->num_values; i++)
92859e71ee7SDaniel Vetter 		if (property->values[i] == value)
92959e71ee7SDaniel Vetter 			return true;
93059e71ee7SDaniel Vetter 	return false;
93159e71ee7SDaniel Vetter }
93259e71ee7SDaniel Vetter 
93359e71ee7SDaniel Vetter void drm_property_change_valid_put(struct drm_property *property,
93459e71ee7SDaniel Vetter 		struct drm_mode_object *ref)
93559e71ee7SDaniel Vetter {
93659e71ee7SDaniel Vetter 	if (!ref)
93759e71ee7SDaniel Vetter 		return;
93859e71ee7SDaniel Vetter 
93930c06570SMaarten Lankhorst 	if (drm_property_type_is(property, DRM_MODE_PROP_OBJECT)) {
940020a218fSThierry Reding 		drm_mode_object_put(ref);
94130c06570SMaarten Lankhorst 	} else if (drm_property_type_is(property, DRM_MODE_PROP_BLOB))
9426472e509SThierry Reding 		drm_property_blob_put(obj_to_blob(ref));
94359e71ee7SDaniel Vetter }
944