xref: /dragonfly/sys/dev/drm/drm_property.c (revision 3f2dd94a)
11dedbd3bSFrançois Tigeot /*
21dedbd3bSFrançois Tigeot  * Copyright (c) 2016 Intel Corporation
31dedbd3bSFrançois Tigeot  *
41dedbd3bSFrançois Tigeot  * Permission to use, copy, modify, distribute, and sell this software and its
51dedbd3bSFrançois Tigeot  * documentation for any purpose is hereby granted without fee, provided that
61dedbd3bSFrançois Tigeot  * the above copyright notice appear in all copies and that both that copyright
71dedbd3bSFrançois Tigeot  * notice and this permission notice appear in supporting documentation, and
81dedbd3bSFrançois Tigeot  * that the name of the copyright holders not be used in advertising or
91dedbd3bSFrançois Tigeot  * publicity pertaining to distribution of the software without specific,
101dedbd3bSFrançois Tigeot  * written prior permission.  The copyright holders make no representations
111dedbd3bSFrançois Tigeot  * about the suitability of this software for any purpose.  It is provided "as
121dedbd3bSFrançois Tigeot  * is" without express or implied warranty.
131dedbd3bSFrançois Tigeot  *
141dedbd3bSFrançois Tigeot  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
151dedbd3bSFrançois Tigeot  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
161dedbd3bSFrançois Tigeot  * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
171dedbd3bSFrançois Tigeot  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
181dedbd3bSFrançois Tigeot  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
191dedbd3bSFrançois Tigeot  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
201dedbd3bSFrançois Tigeot  * OF THIS SOFTWARE.
211dedbd3bSFrançois Tigeot  */
221dedbd3bSFrançois Tigeot 
231dedbd3bSFrançois Tigeot #include <linux/export.h>
241dedbd3bSFrançois Tigeot #include <drm/drmP.h>
251dedbd3bSFrançois Tigeot #include <drm/drm_property.h>
261dedbd3bSFrançois Tigeot 
271dedbd3bSFrançois Tigeot #include "drm_crtc_internal.h"
281dedbd3bSFrançois Tigeot 
291dedbd3bSFrançois Tigeot /**
301dedbd3bSFrançois Tigeot  * DOC: overview
311dedbd3bSFrançois Tigeot  *
321dedbd3bSFrançois Tigeot  * Properties as represented by &drm_property are used to extend the modeset
331dedbd3bSFrançois Tigeot  * interface exposed to userspace. For the atomic modeset IOCTL properties are
341dedbd3bSFrançois Tigeot  * even the only way to transport metadata about the desired new modeset
351dedbd3bSFrançois Tigeot  * configuration from userspace to the kernel. Properties have a well-defined
361dedbd3bSFrançois Tigeot  * value range, which is enforced by the drm core. See the documentation of the
37a85cb24fSFrançois Tigeot  * flags member of &struct drm_property for an overview of the different
381dedbd3bSFrançois Tigeot  * property types and ranges.
391dedbd3bSFrançois Tigeot  *
401dedbd3bSFrançois Tigeot  * Properties don't store the current value directly, but need to be
411dedbd3bSFrançois Tigeot  * instatiated by attaching them to a &drm_mode_object with
421dedbd3bSFrançois Tigeot  * drm_object_attach_property().
431dedbd3bSFrançois Tigeot  *
441dedbd3bSFrançois Tigeot  * Property values are only 64bit. To support bigger piles of data (like gamma
45a85cb24fSFrançois Tigeot  * tables, color correction matrices or large structures) a property can instead
46a85cb24fSFrançois Tigeot  * point at a &drm_property_blob with that additional data.
471dedbd3bSFrançois Tigeot  *
481dedbd3bSFrançois Tigeot  * Properties are defined by their symbolic name, userspace must keep a
491dedbd3bSFrançois Tigeot  * per-object mapping from those names to the property ID used in the atomic
501dedbd3bSFrançois Tigeot  * IOCTL and in the get/set property IOCTL.
511dedbd3bSFrançois Tigeot  */
521dedbd3bSFrançois Tigeot 
drm_property_type_valid(struct drm_property * property)531dedbd3bSFrançois Tigeot static bool drm_property_type_valid(struct drm_property *property)
541dedbd3bSFrançois Tigeot {
551dedbd3bSFrançois Tigeot 	if (property->flags & DRM_MODE_PROP_EXTENDED_TYPE)
561dedbd3bSFrançois Tigeot 		return !(property->flags & DRM_MODE_PROP_LEGACY_TYPE);
571dedbd3bSFrançois Tigeot 	return !!(property->flags & DRM_MODE_PROP_LEGACY_TYPE);
581dedbd3bSFrançois Tigeot }
591dedbd3bSFrançois Tigeot 
601dedbd3bSFrançois Tigeot /**
611dedbd3bSFrançois Tigeot  * drm_property_create - create a new property type
621dedbd3bSFrançois Tigeot  * @dev: drm device
631dedbd3bSFrançois Tigeot  * @flags: flags specifying the property type
641dedbd3bSFrançois Tigeot  * @name: name of the property
651dedbd3bSFrançois Tigeot  * @num_values: number of pre-defined values
661dedbd3bSFrançois Tigeot  *
671dedbd3bSFrançois Tigeot  * This creates a new generic drm property which can then be attached to a drm
684be47400SFrançois Tigeot  * object with drm_object_attach_property(). The returned property object must
694be47400SFrançois Tigeot  * be freed with drm_property_destroy(), which is done automatically when
704be47400SFrançois Tigeot  * calling drm_mode_config_cleanup().
711dedbd3bSFrançois Tigeot  *
721dedbd3bSFrançois Tigeot  * Returns:
731dedbd3bSFrançois Tigeot  * A pointer to the newly created property on success, NULL on failure.
741dedbd3bSFrançois Tigeot  */
drm_property_create(struct drm_device * dev,int flags,const char * name,int num_values)751dedbd3bSFrançois Tigeot struct drm_property *drm_property_create(struct drm_device *dev, int flags,
761dedbd3bSFrançois Tigeot 					 const char *name, int num_values)
771dedbd3bSFrançois Tigeot {
781dedbd3bSFrançois Tigeot 	struct drm_property *property = NULL;
791dedbd3bSFrançois Tigeot 	int ret;
801dedbd3bSFrançois Tigeot 
811dedbd3bSFrançois Tigeot 	property = kzalloc(sizeof(struct drm_property), GFP_KERNEL);
821dedbd3bSFrançois Tigeot 	if (!property)
831dedbd3bSFrançois Tigeot 		return NULL;
841dedbd3bSFrançois Tigeot 
851dedbd3bSFrançois Tigeot 	property->dev = dev;
861dedbd3bSFrançois Tigeot 
871dedbd3bSFrançois Tigeot 	if (num_values) {
881dedbd3bSFrançois Tigeot 		property->values = kcalloc(num_values, sizeof(uint64_t),
891dedbd3bSFrançois Tigeot 					   GFP_KERNEL);
901dedbd3bSFrançois Tigeot 		if (!property->values)
911dedbd3bSFrançois Tigeot 			goto fail;
921dedbd3bSFrançois Tigeot 	}
931dedbd3bSFrançois Tigeot 
94a85cb24fSFrançois Tigeot 	ret = drm_mode_object_add(dev, &property->base, DRM_MODE_OBJECT_PROPERTY);
951dedbd3bSFrançois Tigeot 	if (ret)
961dedbd3bSFrançois Tigeot 		goto fail;
971dedbd3bSFrançois Tigeot 
981dedbd3bSFrançois Tigeot 	property->flags = flags;
991dedbd3bSFrançois Tigeot 	property->num_values = num_values;
1001dedbd3bSFrançois Tigeot 	INIT_LIST_HEAD(&property->enum_list);
1011dedbd3bSFrançois Tigeot 
1021dedbd3bSFrançois Tigeot 	if (name) {
1031dedbd3bSFrançois Tigeot 		strncpy(property->name, name, DRM_PROP_NAME_LEN);
1041dedbd3bSFrançois Tigeot 		property->name[DRM_PROP_NAME_LEN-1] = '\0';
1051dedbd3bSFrançois Tigeot 	}
1061dedbd3bSFrançois Tigeot 
1071dedbd3bSFrançois Tigeot 	list_add_tail(&property->head, &dev->mode_config.property_list);
1081dedbd3bSFrançois Tigeot 
1091dedbd3bSFrançois Tigeot 	WARN_ON(!drm_property_type_valid(property));
1101dedbd3bSFrançois Tigeot 
1111dedbd3bSFrançois Tigeot 	return property;
1121dedbd3bSFrançois Tigeot fail:
1131dedbd3bSFrançois Tigeot 	kfree(property->values);
1141dedbd3bSFrançois Tigeot 	kfree(property);
1151dedbd3bSFrançois Tigeot 	return NULL;
1161dedbd3bSFrançois Tigeot }
1171dedbd3bSFrançois Tigeot EXPORT_SYMBOL(drm_property_create);
1181dedbd3bSFrançois Tigeot 
1191dedbd3bSFrançois Tigeot /**
1201dedbd3bSFrançois Tigeot  * drm_property_create_enum - create a new enumeration property type
1211dedbd3bSFrançois Tigeot  * @dev: drm device
1221dedbd3bSFrançois Tigeot  * @flags: flags specifying the property type
1231dedbd3bSFrançois Tigeot  * @name: name of the property
1241dedbd3bSFrançois Tigeot  * @props: enumeration lists with property values
1251dedbd3bSFrançois Tigeot  * @num_values: number of pre-defined values
1261dedbd3bSFrançois Tigeot  *
1271dedbd3bSFrançois Tigeot  * This creates a new generic drm property which can then be attached to a drm
1284be47400SFrançois Tigeot  * object with drm_object_attach_property(). The returned property object must
1294be47400SFrançois Tigeot  * be freed with drm_property_destroy(), which is done automatically when
1304be47400SFrançois Tigeot  * calling drm_mode_config_cleanup().
1311dedbd3bSFrançois Tigeot  *
1321dedbd3bSFrançois Tigeot  * Userspace is only allowed to set one of the predefined values for enumeration
1331dedbd3bSFrançois Tigeot  * properties.
1341dedbd3bSFrançois Tigeot  *
1351dedbd3bSFrançois Tigeot  * Returns:
1361dedbd3bSFrançois Tigeot  * A pointer to the newly created property on success, NULL on failure.
1371dedbd3bSFrançois Tigeot  */
drm_property_create_enum(struct drm_device * dev,int flags,const char * name,const struct drm_prop_enum_list * props,int num_values)1381dedbd3bSFrançois Tigeot struct drm_property *drm_property_create_enum(struct drm_device *dev, int flags,
1391dedbd3bSFrançois Tigeot 					 const char *name,
1401dedbd3bSFrançois Tigeot 					 const struct drm_prop_enum_list *props,
1411dedbd3bSFrançois Tigeot 					 int num_values)
1421dedbd3bSFrançois Tigeot {
1431dedbd3bSFrançois Tigeot 	struct drm_property *property;
1441dedbd3bSFrançois Tigeot 	int i, ret;
1451dedbd3bSFrançois Tigeot 
1461dedbd3bSFrançois Tigeot 	flags |= DRM_MODE_PROP_ENUM;
1471dedbd3bSFrançois Tigeot 
1481dedbd3bSFrançois Tigeot 	property = drm_property_create(dev, flags, name, num_values);
1491dedbd3bSFrançois Tigeot 	if (!property)
1501dedbd3bSFrançois Tigeot 		return NULL;
1511dedbd3bSFrançois Tigeot 
1521dedbd3bSFrançois Tigeot 	for (i = 0; i < num_values; i++) {
1531dedbd3bSFrançois Tigeot 		ret = drm_property_add_enum(property, i,
1541dedbd3bSFrançois Tigeot 				      props[i].type,
1551dedbd3bSFrançois Tigeot 				      props[i].name);
1561dedbd3bSFrançois Tigeot 		if (ret) {
1571dedbd3bSFrançois Tigeot 			drm_property_destroy(dev, property);
1581dedbd3bSFrançois Tigeot 			return NULL;
1591dedbd3bSFrançois Tigeot 		}
1601dedbd3bSFrançois Tigeot 	}
1611dedbd3bSFrançois Tigeot 
1621dedbd3bSFrançois Tigeot 	return property;
1631dedbd3bSFrançois Tigeot }
1641dedbd3bSFrançois Tigeot EXPORT_SYMBOL(drm_property_create_enum);
1651dedbd3bSFrançois Tigeot 
1661dedbd3bSFrançois Tigeot /**
1671dedbd3bSFrançois Tigeot  * drm_property_create_bitmask - create a new bitmask property type
1681dedbd3bSFrançois Tigeot  * @dev: drm device
1691dedbd3bSFrançois Tigeot  * @flags: flags specifying the property type
1701dedbd3bSFrançois Tigeot  * @name: name of the property
1711dedbd3bSFrançois Tigeot  * @props: enumeration lists with property bitflags
1721dedbd3bSFrançois Tigeot  * @num_props: size of the @props array
1731dedbd3bSFrançois Tigeot  * @supported_bits: bitmask of all supported enumeration values
1741dedbd3bSFrançois Tigeot  *
1751dedbd3bSFrançois Tigeot  * This creates a new bitmask drm property which can then be attached to a drm
1764be47400SFrançois Tigeot  * object with drm_object_attach_property(). The returned property object must
1774be47400SFrançois Tigeot  * be freed with drm_property_destroy(), which is done automatically when
1784be47400SFrançois Tigeot  * calling drm_mode_config_cleanup().
1791dedbd3bSFrançois Tigeot  *
1801dedbd3bSFrançois Tigeot  * Compared to plain enumeration properties userspace is allowed to set any
1811dedbd3bSFrançois Tigeot  * or'ed together combination of the predefined property bitflag values
1821dedbd3bSFrançois Tigeot  *
1831dedbd3bSFrançois Tigeot  * Returns:
1841dedbd3bSFrançois Tigeot  * A pointer to the newly created property on success, NULL on failure.
1851dedbd3bSFrançois Tigeot  */
drm_property_create_bitmask(struct drm_device * dev,int flags,const char * name,const struct drm_prop_enum_list * props,int num_props,uint64_t supported_bits)1861dedbd3bSFrançois Tigeot struct drm_property *drm_property_create_bitmask(struct drm_device *dev,
1871dedbd3bSFrançois Tigeot 					 int flags, const char *name,
1881dedbd3bSFrançois Tigeot 					 const struct drm_prop_enum_list *props,
1891dedbd3bSFrançois Tigeot 					 int num_props,
1901dedbd3bSFrançois Tigeot 					 uint64_t supported_bits)
1911dedbd3bSFrançois Tigeot {
1921dedbd3bSFrançois Tigeot 	struct drm_property *property;
1931dedbd3bSFrançois Tigeot 	int i, ret, index = 0;
1941dedbd3bSFrançois Tigeot 	int num_values = hweight64(supported_bits);
1951dedbd3bSFrançois Tigeot 
1961dedbd3bSFrançois Tigeot 	flags |= DRM_MODE_PROP_BITMASK;
1971dedbd3bSFrançois Tigeot 
1981dedbd3bSFrançois Tigeot 	property = drm_property_create(dev, flags, name, num_values);
1991dedbd3bSFrançois Tigeot 	if (!property)
2001dedbd3bSFrançois Tigeot 		return NULL;
2011dedbd3bSFrançois Tigeot 	for (i = 0; i < num_props; i++) {
2021dedbd3bSFrançois Tigeot 		if (!(supported_bits & (1ULL << props[i].type)))
2031dedbd3bSFrançois Tigeot 			continue;
2041dedbd3bSFrançois Tigeot 
2051dedbd3bSFrançois Tigeot 		if (WARN_ON(index >= num_values)) {
2061dedbd3bSFrançois Tigeot 			drm_property_destroy(dev, property);
2071dedbd3bSFrançois Tigeot 			return NULL;
2081dedbd3bSFrançois Tigeot 		}
2091dedbd3bSFrançois Tigeot 
2101dedbd3bSFrançois Tigeot 		ret = drm_property_add_enum(property, index++,
2111dedbd3bSFrançois Tigeot 				      props[i].type,
2121dedbd3bSFrançois Tigeot 				      props[i].name);
2131dedbd3bSFrançois Tigeot 		if (ret) {
2141dedbd3bSFrançois Tigeot 			drm_property_destroy(dev, property);
2151dedbd3bSFrançois Tigeot 			return NULL;
2161dedbd3bSFrançois Tigeot 		}
2171dedbd3bSFrançois Tigeot 	}
2181dedbd3bSFrançois Tigeot 
2191dedbd3bSFrançois Tigeot 	return property;
2201dedbd3bSFrançois Tigeot }
2211dedbd3bSFrançois Tigeot EXPORT_SYMBOL(drm_property_create_bitmask);
2221dedbd3bSFrançois Tigeot 
property_create_range(struct drm_device * dev,int flags,const char * name,uint64_t min,uint64_t max)2231dedbd3bSFrançois Tigeot static struct drm_property *property_create_range(struct drm_device *dev,
2241dedbd3bSFrançois Tigeot 					 int flags, const char *name,
2251dedbd3bSFrançois Tigeot 					 uint64_t min, uint64_t max)
2261dedbd3bSFrançois Tigeot {
2271dedbd3bSFrançois Tigeot 	struct drm_property *property;
2281dedbd3bSFrançois Tigeot 
2291dedbd3bSFrançois Tigeot 	property = drm_property_create(dev, flags, name, 2);
2301dedbd3bSFrançois Tigeot 	if (!property)
2311dedbd3bSFrançois Tigeot 		return NULL;
2321dedbd3bSFrançois Tigeot 
2331dedbd3bSFrançois Tigeot 	property->values[0] = min;
2341dedbd3bSFrançois Tigeot 	property->values[1] = max;
2351dedbd3bSFrançois Tigeot 
2361dedbd3bSFrançois Tigeot 	return property;
2371dedbd3bSFrançois Tigeot }
2381dedbd3bSFrançois Tigeot 
2391dedbd3bSFrançois Tigeot /**
2401dedbd3bSFrançois Tigeot  * drm_property_create_range - create a new unsigned ranged property type
2411dedbd3bSFrançois Tigeot  * @dev: drm device
2421dedbd3bSFrançois Tigeot  * @flags: flags specifying the property type
2431dedbd3bSFrançois Tigeot  * @name: name of the property
2441dedbd3bSFrançois Tigeot  * @min: minimum value of the property
2451dedbd3bSFrançois Tigeot  * @max: maximum value of the property
2461dedbd3bSFrançois Tigeot  *
2471dedbd3bSFrançois Tigeot  * This creates a new generic drm property which can then be attached to a drm
2484be47400SFrançois Tigeot  * object with drm_object_attach_property(). The returned property object must
2494be47400SFrançois Tigeot  * be freed with drm_property_destroy(), which is done automatically when
2504be47400SFrançois Tigeot  * calling drm_mode_config_cleanup().
2511dedbd3bSFrançois Tigeot  *
2521dedbd3bSFrançois Tigeot  * Userspace is allowed to set any unsigned integer value in the (min, max)
2531dedbd3bSFrançois Tigeot  * range inclusive.
2541dedbd3bSFrançois Tigeot  *
2551dedbd3bSFrançois Tigeot  * Returns:
2561dedbd3bSFrançois Tigeot  * A pointer to the newly created property on success, NULL on failure.
2571dedbd3bSFrançois Tigeot  */
drm_property_create_range(struct drm_device * dev,int flags,const char * name,uint64_t min,uint64_t max)2581dedbd3bSFrançois Tigeot struct drm_property *drm_property_create_range(struct drm_device *dev, int flags,
2591dedbd3bSFrançois Tigeot 					 const char *name,
2601dedbd3bSFrançois Tigeot 					 uint64_t min, uint64_t max)
2611dedbd3bSFrançois Tigeot {
2621dedbd3bSFrançois Tigeot 	return property_create_range(dev, DRM_MODE_PROP_RANGE | flags,
2631dedbd3bSFrançois Tigeot 			name, min, max);
2641dedbd3bSFrançois Tigeot }
2651dedbd3bSFrançois Tigeot EXPORT_SYMBOL(drm_property_create_range);
2661dedbd3bSFrançois Tigeot 
2671dedbd3bSFrançois Tigeot /**
2681dedbd3bSFrançois Tigeot  * drm_property_create_signed_range - create a new signed ranged property type
2691dedbd3bSFrançois Tigeot  * @dev: drm device
2701dedbd3bSFrançois Tigeot  * @flags: flags specifying the property type
2711dedbd3bSFrançois Tigeot  * @name: name of the property
2721dedbd3bSFrançois Tigeot  * @min: minimum value of the property
2731dedbd3bSFrançois Tigeot  * @max: maximum value of the property
2741dedbd3bSFrançois Tigeot  *
2751dedbd3bSFrançois Tigeot  * This creates a new generic drm property which can then be attached to a drm
2764be47400SFrançois Tigeot  * object with drm_object_attach_property(). The returned property object must
2774be47400SFrançois Tigeot  * be freed with drm_property_destroy(), which is done automatically when
2784be47400SFrançois Tigeot  * calling drm_mode_config_cleanup().
2791dedbd3bSFrançois Tigeot  *
2801dedbd3bSFrançois Tigeot  * Userspace is allowed to set any signed integer value in the (min, max)
2811dedbd3bSFrançois Tigeot  * range inclusive.
2821dedbd3bSFrançois Tigeot  *
2831dedbd3bSFrançois Tigeot  * Returns:
2841dedbd3bSFrançois Tigeot  * A pointer to the newly created property on success, NULL on failure.
2851dedbd3bSFrançois Tigeot  */
drm_property_create_signed_range(struct drm_device * dev,int flags,const char * name,int64_t min,int64_t max)2861dedbd3bSFrançois Tigeot struct drm_property *drm_property_create_signed_range(struct drm_device *dev,
2871dedbd3bSFrançois Tigeot 					 int flags, const char *name,
2881dedbd3bSFrançois Tigeot 					 int64_t min, int64_t max)
2891dedbd3bSFrançois Tigeot {
2901dedbd3bSFrançois Tigeot 	return property_create_range(dev, DRM_MODE_PROP_SIGNED_RANGE | flags,
2911dedbd3bSFrançois Tigeot 			name, I642U64(min), I642U64(max));
2921dedbd3bSFrançois Tigeot }
2931dedbd3bSFrançois Tigeot EXPORT_SYMBOL(drm_property_create_signed_range);
2941dedbd3bSFrançois Tigeot 
2951dedbd3bSFrançois Tigeot /**
2961dedbd3bSFrançois Tigeot  * drm_property_create_object - create a new object property type
2971dedbd3bSFrançois Tigeot  * @dev: drm device
2981dedbd3bSFrançois Tigeot  * @flags: flags specifying the property type
2991dedbd3bSFrançois Tigeot  * @name: name of the property
3001dedbd3bSFrançois Tigeot  * @type: object type from DRM_MODE_OBJECT_* defines
3011dedbd3bSFrançois Tigeot  *
3021dedbd3bSFrançois Tigeot  * This creates a new generic drm property which can then be attached to a drm
3034be47400SFrançois Tigeot  * object with drm_object_attach_property(). The returned property object must
3044be47400SFrançois Tigeot  * be freed with drm_property_destroy(), which is done automatically when
3054be47400SFrançois Tigeot  * calling drm_mode_config_cleanup().
3061dedbd3bSFrançois Tigeot  *
3071dedbd3bSFrançois Tigeot  * Userspace is only allowed to set this to any property value of the given
3081dedbd3bSFrançois Tigeot  * @type. Only useful for atomic properties, which is enforced.
3091dedbd3bSFrançois Tigeot  *
3101dedbd3bSFrançois Tigeot  * Returns:
3111dedbd3bSFrançois Tigeot  * A pointer to the newly created property on success, NULL on failure.
3121dedbd3bSFrançois Tigeot  */
drm_property_create_object(struct drm_device * dev,int flags,const char * name,uint32_t type)3131dedbd3bSFrançois Tigeot struct drm_property *drm_property_create_object(struct drm_device *dev,
3141dedbd3bSFrançois Tigeot 						int flags, const char *name,
3151dedbd3bSFrançois Tigeot 						uint32_t type)
3161dedbd3bSFrançois Tigeot {
3171dedbd3bSFrançois Tigeot 	struct drm_property *property;
3181dedbd3bSFrançois Tigeot 
3191dedbd3bSFrançois Tigeot 	flags |= DRM_MODE_PROP_OBJECT;
3201dedbd3bSFrançois Tigeot 
3211dedbd3bSFrançois Tigeot 	if (WARN_ON(!(flags & DRM_MODE_PROP_ATOMIC)))
3221dedbd3bSFrançois Tigeot 		return NULL;
3231dedbd3bSFrançois Tigeot 
3241dedbd3bSFrançois Tigeot 	property = drm_property_create(dev, flags, name, 1);
3251dedbd3bSFrançois Tigeot 	if (!property)
3261dedbd3bSFrançois Tigeot 		return NULL;
3271dedbd3bSFrançois Tigeot 
3281dedbd3bSFrançois Tigeot 	property->values[0] = type;
3291dedbd3bSFrançois Tigeot 
3301dedbd3bSFrançois Tigeot 	return property;
3311dedbd3bSFrançois Tigeot }
3321dedbd3bSFrançois Tigeot EXPORT_SYMBOL(drm_property_create_object);
3331dedbd3bSFrançois Tigeot 
3341dedbd3bSFrançois Tigeot /**
3351dedbd3bSFrançois Tigeot  * drm_property_create_bool - create a new boolean property type
3361dedbd3bSFrançois Tigeot  * @dev: drm device
3371dedbd3bSFrançois Tigeot  * @flags: flags specifying the property type
3381dedbd3bSFrançois Tigeot  * @name: name of the property
3391dedbd3bSFrançois Tigeot  *
3401dedbd3bSFrançois Tigeot  * This creates a new generic drm property which can then be attached to a drm
3414be47400SFrançois Tigeot  * object with drm_object_attach_property(). The returned property object must
3424be47400SFrançois Tigeot  * be freed with drm_property_destroy(), which is done automatically when
3434be47400SFrançois Tigeot  * calling drm_mode_config_cleanup().
3441dedbd3bSFrançois Tigeot  *
3451dedbd3bSFrançois Tigeot  * This is implemented as a ranged property with only {0, 1} as valid values.
3461dedbd3bSFrançois Tigeot  *
3471dedbd3bSFrançois Tigeot  * Returns:
3481dedbd3bSFrançois Tigeot  * A pointer to the newly created property on success, NULL on failure.
3491dedbd3bSFrançois Tigeot  */
drm_property_create_bool(struct drm_device * dev,int flags,const char * name)3501dedbd3bSFrançois Tigeot struct drm_property *drm_property_create_bool(struct drm_device *dev, int flags,
3511dedbd3bSFrançois Tigeot 					      const char *name)
3521dedbd3bSFrançois Tigeot {
3531dedbd3bSFrançois Tigeot 	return drm_property_create_range(dev, flags, name, 0, 1);
3541dedbd3bSFrançois Tigeot }
3551dedbd3bSFrançois Tigeot EXPORT_SYMBOL(drm_property_create_bool);
3561dedbd3bSFrançois Tigeot 
3571dedbd3bSFrançois Tigeot /**
3581dedbd3bSFrançois Tigeot  * drm_property_add_enum - add a possible value to an enumeration property
3591dedbd3bSFrançois Tigeot  * @property: enumeration property to change
3601dedbd3bSFrançois Tigeot  * @index: index of the new enumeration
3611dedbd3bSFrançois Tigeot  * @value: value of the new enumeration
3621dedbd3bSFrançois Tigeot  * @name: symbolic name of the new enumeration
3631dedbd3bSFrançois Tigeot  *
3641dedbd3bSFrançois Tigeot  * This functions adds enumerations to a property.
3651dedbd3bSFrançois Tigeot  *
3661dedbd3bSFrançois Tigeot  * It's use is deprecated, drivers should use one of the more specific helpers
3671dedbd3bSFrançois Tigeot  * to directly create the property with all enumerations already attached.
3681dedbd3bSFrançois Tigeot  *
3691dedbd3bSFrançois Tigeot  * Returns:
3701dedbd3bSFrançois Tigeot  * Zero on success, error code on failure.
3711dedbd3bSFrançois Tigeot  */
drm_property_add_enum(struct drm_property * property,int index,uint64_t value,const char * name)3721dedbd3bSFrançois Tigeot int drm_property_add_enum(struct drm_property *property, int index,
3731dedbd3bSFrançois Tigeot 			  uint64_t value, const char *name)
3741dedbd3bSFrançois Tigeot {
3751dedbd3bSFrançois Tigeot 	struct drm_property_enum *prop_enum;
3761dedbd3bSFrançois Tigeot 
3771dedbd3bSFrançois Tigeot 	if (!(drm_property_type_is(property, DRM_MODE_PROP_ENUM) ||
3781dedbd3bSFrançois Tigeot 			drm_property_type_is(property, DRM_MODE_PROP_BITMASK)))
3791dedbd3bSFrançois Tigeot 		return -EINVAL;
3801dedbd3bSFrançois Tigeot 
3811dedbd3bSFrançois Tigeot 	/*
3821dedbd3bSFrançois Tigeot 	 * Bitmask enum properties have the additional constraint of values
3831dedbd3bSFrançois Tigeot 	 * from 0 to 63
3841dedbd3bSFrançois Tigeot 	 */
3851dedbd3bSFrançois Tigeot 	if (drm_property_type_is(property, DRM_MODE_PROP_BITMASK) &&
3861dedbd3bSFrançois Tigeot 			(value > 63))
3871dedbd3bSFrançois Tigeot 		return -EINVAL;
3881dedbd3bSFrançois Tigeot 
3891dedbd3bSFrançois Tigeot 	if (!list_empty(&property->enum_list)) {
3901dedbd3bSFrançois Tigeot 		list_for_each_entry(prop_enum, &property->enum_list, head) {
3911dedbd3bSFrançois Tigeot 			if (prop_enum->value == value) {
3921dedbd3bSFrançois Tigeot 				strncpy(prop_enum->name, name, DRM_PROP_NAME_LEN);
3931dedbd3bSFrançois Tigeot 				prop_enum->name[DRM_PROP_NAME_LEN-1] = '\0';
3941dedbd3bSFrançois Tigeot 				return 0;
3951dedbd3bSFrançois Tigeot 			}
3961dedbd3bSFrançois Tigeot 		}
3971dedbd3bSFrançois Tigeot 	}
3981dedbd3bSFrançois Tigeot 
3991dedbd3bSFrançois Tigeot 	prop_enum = kzalloc(sizeof(struct drm_property_enum), GFP_KERNEL);
4001dedbd3bSFrançois Tigeot 	if (!prop_enum)
4011dedbd3bSFrançois Tigeot 		return -ENOMEM;
4021dedbd3bSFrançois Tigeot 
4031dedbd3bSFrançois Tigeot 	strncpy(prop_enum->name, name, DRM_PROP_NAME_LEN);
4041dedbd3bSFrançois Tigeot 	prop_enum->name[DRM_PROP_NAME_LEN-1] = '\0';
4051dedbd3bSFrançois Tigeot 	prop_enum->value = value;
4061dedbd3bSFrançois Tigeot 
4071dedbd3bSFrançois Tigeot 	property->values[index] = value;
4081dedbd3bSFrançois Tigeot 	list_add_tail(&prop_enum->head, &property->enum_list);
4091dedbd3bSFrançois Tigeot 	return 0;
4101dedbd3bSFrançois Tigeot }
4111dedbd3bSFrançois Tigeot EXPORT_SYMBOL(drm_property_add_enum);
4121dedbd3bSFrançois Tigeot 
4131dedbd3bSFrançois Tigeot /**
4141dedbd3bSFrançois Tigeot  * drm_property_destroy - destroy a drm property
4151dedbd3bSFrançois Tigeot  * @dev: drm device
4161dedbd3bSFrançois Tigeot  * @property: property to destry
4171dedbd3bSFrançois Tigeot  *
4181dedbd3bSFrançois Tigeot  * This function frees a property including any attached resources like
4191dedbd3bSFrançois Tigeot  * enumeration values.
4201dedbd3bSFrançois Tigeot  */
drm_property_destroy(struct drm_device * dev,struct drm_property * property)4211dedbd3bSFrançois Tigeot void drm_property_destroy(struct drm_device *dev, struct drm_property *property)
4221dedbd3bSFrançois Tigeot {
4231dedbd3bSFrançois Tigeot 	struct drm_property_enum *prop_enum, *pt;
4241dedbd3bSFrançois Tigeot 
4251dedbd3bSFrançois Tigeot 	list_for_each_entry_safe(prop_enum, pt, &property->enum_list, head) {
4261dedbd3bSFrançois Tigeot 		list_del(&prop_enum->head);
4271dedbd3bSFrançois Tigeot 		kfree(prop_enum);
4281dedbd3bSFrançois Tigeot 	}
4291dedbd3bSFrançois Tigeot 
4301dedbd3bSFrançois Tigeot 	if (property->num_values)
4311dedbd3bSFrançois Tigeot 		kfree(property->values);
4321dedbd3bSFrançois Tigeot 	drm_mode_object_unregister(dev, &property->base);
4331dedbd3bSFrançois Tigeot 	list_del(&property->head);
4341dedbd3bSFrançois Tigeot 	kfree(property);
4351dedbd3bSFrançois Tigeot }
4361dedbd3bSFrançois Tigeot EXPORT_SYMBOL(drm_property_destroy);
4371dedbd3bSFrançois Tigeot 
drm_mode_getproperty_ioctl(struct drm_device * dev,void * data,struct drm_file * file_priv)4381dedbd3bSFrançois Tigeot int drm_mode_getproperty_ioctl(struct drm_device *dev,
4391dedbd3bSFrançois Tigeot 			       void *data, struct drm_file *file_priv)
4401dedbd3bSFrançois Tigeot {
4411dedbd3bSFrançois Tigeot 	struct drm_mode_get_property *out_resp = data;
4421dedbd3bSFrançois Tigeot 	struct drm_property *property;
4431dedbd3bSFrançois Tigeot 	int enum_count = 0;
4441dedbd3bSFrançois Tigeot 	int value_count = 0;
445a85cb24fSFrançois Tigeot 	int i, copied;
4461dedbd3bSFrançois Tigeot 	struct drm_property_enum *prop_enum;
4471dedbd3bSFrançois Tigeot 	struct drm_mode_property_enum __user *enum_ptr;
4481dedbd3bSFrançois Tigeot 	uint64_t __user *values_ptr;
4491dedbd3bSFrançois Tigeot 
4501dedbd3bSFrançois Tigeot 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
4511dedbd3bSFrançois Tigeot 		return -EINVAL;
4521dedbd3bSFrançois Tigeot 
453*3f2dd94aSFrançois Tigeot 	property = drm_property_find(dev, file_priv, out_resp->prop_id);
454a85cb24fSFrançois Tigeot 	if (!property)
455a85cb24fSFrançois Tigeot 		return -ENOENT;
4561dedbd3bSFrançois Tigeot 
4571dedbd3bSFrançois Tigeot 	strncpy(out_resp->name, property->name, DRM_PROP_NAME_LEN);
4581dedbd3bSFrançois Tigeot 	out_resp->name[DRM_PROP_NAME_LEN-1] = 0;
4591dedbd3bSFrançois Tigeot 	out_resp->flags = property->flags;
4601dedbd3bSFrançois Tigeot 
461a85cb24fSFrançois Tigeot 	value_count = property->num_values;
462a85cb24fSFrançois Tigeot 	values_ptr = u64_to_user_ptr(out_resp->values_ptr);
463a85cb24fSFrançois Tigeot 
4641dedbd3bSFrançois Tigeot 	for (i = 0; i < value_count; i++) {
465a85cb24fSFrançois Tigeot 		if (i < out_resp->count_values &&
466a85cb24fSFrançois Tigeot 		    put_user(property->values[i], values_ptr + i)) {
467a85cb24fSFrançois Tigeot 			return -EFAULT;
4681dedbd3bSFrançois Tigeot 		}
4691dedbd3bSFrançois Tigeot 	}
4701dedbd3bSFrançois Tigeot 	out_resp->count_values = value_count;
4711dedbd3bSFrançois Tigeot 
472a85cb24fSFrançois Tigeot 	copied = 0;
473a85cb24fSFrançois Tigeot 	enum_ptr = u64_to_user_ptr(out_resp->enum_blob_ptr);
474a85cb24fSFrançois Tigeot 
4751dedbd3bSFrançois Tigeot 	if (drm_property_type_is(property, DRM_MODE_PROP_ENUM) ||
4761dedbd3bSFrançois Tigeot 	    drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) {
4771dedbd3bSFrançois Tigeot 		list_for_each_entry(prop_enum, &property->enum_list, head) {
478a85cb24fSFrançois Tigeot 			enum_count++;
479a85cb24fSFrançois Tigeot 			if (out_resp->count_enum_blobs < enum_count)
480a85cb24fSFrançois Tigeot 				continue;
4811dedbd3bSFrançois Tigeot 
482a85cb24fSFrançois Tigeot 			if (copy_to_user(&enum_ptr[copied].value,
483a85cb24fSFrançois Tigeot 					 &prop_enum->value, sizeof(uint64_t)))
484a85cb24fSFrançois Tigeot 				return -EFAULT;
4851dedbd3bSFrançois Tigeot 
4861dedbd3bSFrançois Tigeot 			if (copy_to_user(&enum_ptr[copied].name,
487a85cb24fSFrançois Tigeot 					 &prop_enum->name, DRM_PROP_NAME_LEN))
488a85cb24fSFrançois Tigeot 				return -EFAULT;
4891dedbd3bSFrançois Tigeot 			copied++;
4901dedbd3bSFrançois Tigeot 		}
4911dedbd3bSFrançois Tigeot 		out_resp->count_enum_blobs = enum_count;
4921dedbd3bSFrançois Tigeot 	}
4931dedbd3bSFrançois Tigeot 
4941dedbd3bSFrançois Tigeot 	/*
4951dedbd3bSFrançois Tigeot 	 * NOTE: The idea seems to have been to use this to read all the blob
4961dedbd3bSFrançois Tigeot 	 * property values. But nothing ever added them to the corresponding
4971dedbd3bSFrançois Tigeot 	 * list, userspace always used the special-purpose get_blob ioctl to
4981dedbd3bSFrançois Tigeot 	 * read the value for a blob property. It also doesn't make a lot of
4991dedbd3bSFrançois Tigeot 	 * sense to return values here when everything else is just metadata for
5001dedbd3bSFrançois Tigeot 	 * the property itself.
5011dedbd3bSFrançois Tigeot 	 */
5021dedbd3bSFrançois Tigeot 	if (drm_property_type_is(property, DRM_MODE_PROP_BLOB))
5031dedbd3bSFrançois Tigeot 		out_resp->count_enum_blobs = 0;
504a85cb24fSFrançois Tigeot 
505a85cb24fSFrançois Tigeot 	return 0;
5061dedbd3bSFrançois Tigeot }
5071dedbd3bSFrançois Tigeot 
drm_property_free_blob(struct kref * kref)5081dedbd3bSFrançois Tigeot static void drm_property_free_blob(struct kref *kref)
5091dedbd3bSFrançois Tigeot {
5101dedbd3bSFrançois Tigeot 	struct drm_property_blob *blob =
5111dedbd3bSFrançois Tigeot 		container_of(kref, struct drm_property_blob, base.refcount);
5121dedbd3bSFrançois Tigeot 
5131dedbd3bSFrançois Tigeot 	mutex_lock(&blob->dev->mode_config.blob_lock);
5141dedbd3bSFrançois Tigeot 	list_del(&blob->head_global);
5151dedbd3bSFrançois Tigeot 	mutex_unlock(&blob->dev->mode_config.blob_lock);
5161dedbd3bSFrançois Tigeot 
5171dedbd3bSFrançois Tigeot 	drm_mode_object_unregister(blob->dev, &blob->base);
5181dedbd3bSFrançois Tigeot 
5191dedbd3bSFrançois Tigeot 	kfree(blob);
5201dedbd3bSFrançois Tigeot }
5211dedbd3bSFrançois Tigeot 
5221dedbd3bSFrançois Tigeot /**
5231dedbd3bSFrançois Tigeot  * drm_property_create_blob - Create new blob property
5241dedbd3bSFrançois Tigeot  * @dev: DRM device to create property for
5251dedbd3bSFrançois Tigeot  * @length: Length to allocate for blob data
5261dedbd3bSFrançois Tigeot  * @data: If specified, copies data into blob
5271dedbd3bSFrançois Tigeot  *
5281dedbd3bSFrançois Tigeot  * Creates a new blob property for a specified DRM device, optionally
5291dedbd3bSFrançois Tigeot  * copying data. Note that blob properties are meant to be invariant, hence the
5301dedbd3bSFrançois Tigeot  * data must be filled out before the blob is used as the value of any property.
5311dedbd3bSFrançois Tigeot  *
5321dedbd3bSFrançois Tigeot  * Returns:
5331dedbd3bSFrançois Tigeot  * New blob property with a single reference on success, or an ERR_PTR
5341dedbd3bSFrançois Tigeot  * value on failure.
5351dedbd3bSFrançois Tigeot  */
5361dedbd3bSFrançois Tigeot struct drm_property_blob *
drm_property_create_blob(struct drm_device * dev,size_t length,const void * data)5371dedbd3bSFrançois Tigeot drm_property_create_blob(struct drm_device *dev, size_t length,
5381dedbd3bSFrançois Tigeot 			 const void *data)
5391dedbd3bSFrançois Tigeot {
5401dedbd3bSFrançois Tigeot 	struct drm_property_blob *blob;
5411dedbd3bSFrançois Tigeot 	int ret;
5421dedbd3bSFrançois Tigeot 
5431dedbd3bSFrançois Tigeot 	if (!length || length > ULONG_MAX - sizeof(struct drm_property_blob))
5441dedbd3bSFrançois Tigeot 		return ERR_PTR(-EINVAL);
5451dedbd3bSFrançois Tigeot 
5461dedbd3bSFrançois Tigeot 	blob = kzalloc(sizeof(struct drm_property_blob)+length, GFP_KERNEL);
5471dedbd3bSFrançois Tigeot 	if (!blob)
5481dedbd3bSFrançois Tigeot 		return ERR_PTR(-ENOMEM);
5491dedbd3bSFrançois Tigeot 
5501dedbd3bSFrançois Tigeot 	/* This must be explicitly initialised, so we can safely call list_del
5511dedbd3bSFrançois Tigeot 	 * on it in the removal handler, even if it isn't in a file list. */
5521dedbd3bSFrançois Tigeot 	INIT_LIST_HEAD(&blob->head_file);
5531dedbd3bSFrançois Tigeot 	blob->length = length;
5541dedbd3bSFrançois Tigeot 	blob->dev = dev;
5551dedbd3bSFrançois Tigeot 
5561dedbd3bSFrançois Tigeot 	if (data)
5571dedbd3bSFrançois Tigeot 		memcpy(blob->data, data, length);
5581dedbd3bSFrançois Tigeot 
559a85cb24fSFrançois Tigeot 	ret = __drm_mode_object_add(dev, &blob->base, DRM_MODE_OBJECT_BLOB,
5601dedbd3bSFrançois Tigeot 				    true, drm_property_free_blob);
5611dedbd3bSFrançois Tigeot 	if (ret) {
5621dedbd3bSFrançois Tigeot 		kfree(blob);
5631dedbd3bSFrançois Tigeot 		return ERR_PTR(-EINVAL);
5641dedbd3bSFrançois Tigeot 	}
5651dedbd3bSFrançois Tigeot 
5661dedbd3bSFrançois Tigeot 	mutex_lock(&dev->mode_config.blob_lock);
5671dedbd3bSFrançois Tigeot 	list_add_tail(&blob->head_global,
5681dedbd3bSFrançois Tigeot 	              &dev->mode_config.property_blob_list);
5691dedbd3bSFrançois Tigeot 	mutex_unlock(&dev->mode_config.blob_lock);
5701dedbd3bSFrançois Tigeot 
5711dedbd3bSFrançois Tigeot 	return blob;
5721dedbd3bSFrançois Tigeot }
5731dedbd3bSFrançois Tigeot EXPORT_SYMBOL(drm_property_create_blob);
5741dedbd3bSFrançois Tigeot 
5751dedbd3bSFrançois Tigeot /**
576a85cb24fSFrançois Tigeot  * drm_property_blob_put - release a blob property reference
577a85cb24fSFrançois Tigeot  * @blob: DRM blob property
5781dedbd3bSFrançois Tigeot  *
579a85cb24fSFrançois Tigeot  * Releases a reference to a blob property. May free the object.
5801dedbd3bSFrançois Tigeot  */
drm_property_blob_put(struct drm_property_blob * blob)581a85cb24fSFrançois Tigeot void drm_property_blob_put(struct drm_property_blob *blob)
5821dedbd3bSFrançois Tigeot {
5831dedbd3bSFrançois Tigeot 	if (!blob)
5841dedbd3bSFrançois Tigeot 		return;
5851dedbd3bSFrançois Tigeot 
586a85cb24fSFrançois Tigeot 	drm_mode_object_put(&blob->base);
5871dedbd3bSFrançois Tigeot }
588a85cb24fSFrançois Tigeot EXPORT_SYMBOL(drm_property_blob_put);
5891dedbd3bSFrançois Tigeot 
drm_property_destroy_user_blobs(struct drm_device * dev,struct drm_file * file_priv)5901dedbd3bSFrançois Tigeot void drm_property_destroy_user_blobs(struct drm_device *dev,
5911dedbd3bSFrançois Tigeot 				     struct drm_file *file_priv)
5921dedbd3bSFrançois Tigeot {
5931dedbd3bSFrançois Tigeot 	struct drm_property_blob *blob, *bt;
5941dedbd3bSFrançois Tigeot 
5951dedbd3bSFrançois Tigeot 	/*
5961dedbd3bSFrançois Tigeot 	 * When the file gets released that means no one else can access the
5971dedbd3bSFrançois Tigeot 	 * blob list any more, so no need to grab dev->blob_lock.
5981dedbd3bSFrançois Tigeot 	 */
5991dedbd3bSFrançois Tigeot 	list_for_each_entry_safe(blob, bt, &file_priv->blobs, head_file) {
6001dedbd3bSFrançois Tigeot 		list_del_init(&blob->head_file);
601a85cb24fSFrançois Tigeot 		drm_property_blob_put(blob);
6021dedbd3bSFrançois Tigeot 	}
6031dedbd3bSFrançois Tigeot }
6041dedbd3bSFrançois Tigeot 
6051dedbd3bSFrançois Tigeot /**
606a85cb24fSFrançois Tigeot  * drm_property_blob_get - acquire blob property reference
607a85cb24fSFrançois Tigeot  * @blob: DRM blob property
6081dedbd3bSFrançois Tigeot  *
609a85cb24fSFrançois Tigeot  * Acquires a reference to an existing blob property. Returns @blob, which
6101dedbd3bSFrançois Tigeot  * allows this to be used as a shorthand in assignments.
6111dedbd3bSFrançois Tigeot  */
drm_property_blob_get(struct drm_property_blob * blob)612a85cb24fSFrançois Tigeot struct drm_property_blob *drm_property_blob_get(struct drm_property_blob *blob)
6131dedbd3bSFrançois Tigeot {
614a85cb24fSFrançois Tigeot 	drm_mode_object_get(&blob->base);
6151dedbd3bSFrançois Tigeot 	return blob;
6161dedbd3bSFrançois Tigeot }
617a85cb24fSFrançois Tigeot EXPORT_SYMBOL(drm_property_blob_get);
6181dedbd3bSFrançois Tigeot 
6191dedbd3bSFrançois Tigeot /**
6201dedbd3bSFrançois Tigeot  * drm_property_lookup_blob - look up a blob property and take a reference
6211dedbd3bSFrançois Tigeot  * @dev: drm device
6221dedbd3bSFrançois Tigeot  * @id: id of the blob property
6231dedbd3bSFrançois Tigeot  *
6241dedbd3bSFrançois Tigeot  * If successful, this takes an additional reference to the blob property.
6251dedbd3bSFrançois Tigeot  * callers need to make sure to eventually unreference the returned property
626a85cb24fSFrançois Tigeot  * again, using drm_property_blob_put().
6271dedbd3bSFrançois Tigeot  *
6281dedbd3bSFrançois Tigeot  * Return:
6291dedbd3bSFrançois Tigeot  * NULL on failure, pointer to the blob on success.
6301dedbd3bSFrançois Tigeot  */
drm_property_lookup_blob(struct drm_device * dev,uint32_t id)6311dedbd3bSFrançois Tigeot struct drm_property_blob *drm_property_lookup_blob(struct drm_device *dev,
6321dedbd3bSFrançois Tigeot 					           uint32_t id)
6331dedbd3bSFrançois Tigeot {
6341dedbd3bSFrançois Tigeot 	struct drm_mode_object *obj;
6351dedbd3bSFrançois Tigeot 	struct drm_property_blob *blob = NULL;
6361dedbd3bSFrançois Tigeot 
637*3f2dd94aSFrançois Tigeot 	obj = __drm_mode_object_find(dev, NULL, id, DRM_MODE_OBJECT_BLOB);
6381dedbd3bSFrançois Tigeot 	if (obj)
6391dedbd3bSFrançois Tigeot 		blob = obj_to_blob(obj);
6401dedbd3bSFrançois Tigeot 	return blob;
6411dedbd3bSFrançois Tigeot }
6421dedbd3bSFrançois Tigeot EXPORT_SYMBOL(drm_property_lookup_blob);
6431dedbd3bSFrançois Tigeot 
6441dedbd3bSFrançois Tigeot /**
6451dedbd3bSFrançois Tigeot  * drm_property_replace_global_blob - replace existing blob property
6461dedbd3bSFrançois Tigeot  * @dev: drm device
6471dedbd3bSFrançois Tigeot  * @replace: location of blob property pointer to be replaced
6481dedbd3bSFrançois Tigeot  * @length: length of data for new blob, or 0 for no data
6491dedbd3bSFrançois Tigeot  * @data: content for new blob, or NULL for no data
6501dedbd3bSFrançois Tigeot  * @obj_holds_id: optional object for property holding blob ID
6511dedbd3bSFrançois Tigeot  * @prop_holds_id: optional property holding blob ID
6521dedbd3bSFrançois Tigeot  * @return 0 on success or error on failure
6531dedbd3bSFrançois Tigeot  *
6541dedbd3bSFrançois Tigeot  * This function will replace a global property in the blob list, optionally
6551dedbd3bSFrançois Tigeot  * updating a property which holds the ID of that property.
6561dedbd3bSFrançois Tigeot  *
6571dedbd3bSFrançois Tigeot  * If length is 0 or data is NULL, no new blob will be created, and the holding
6581dedbd3bSFrançois Tigeot  * property, if specified, will be set to 0.
6591dedbd3bSFrançois Tigeot  *
6601dedbd3bSFrançois Tigeot  * Access to the replace pointer is assumed to be protected by the caller, e.g.
6611dedbd3bSFrançois Tigeot  * by holding the relevant modesetting object lock for its parent.
6621dedbd3bSFrançois Tigeot  *
6631dedbd3bSFrançois Tigeot  * For example, a drm_connector has a 'PATH' property, which contains the ID
6641dedbd3bSFrançois Tigeot  * of a blob property with the value of the MST path information. Calling this
6651dedbd3bSFrançois Tigeot  * function with replace pointing to the connector's path_blob_ptr, length and
6661dedbd3bSFrançois Tigeot  * data set for the new path information, obj_holds_id set to the connector's
6671dedbd3bSFrançois Tigeot  * base object, and prop_holds_id set to the path property name, will perform
6681dedbd3bSFrançois Tigeot  * a completely atomic update. The access to path_blob_ptr is protected by the
6691dedbd3bSFrançois Tigeot  * caller holding a lock on the connector.
6701dedbd3bSFrançois Tigeot  */
drm_property_replace_global_blob(struct drm_device * dev,struct drm_property_blob ** replace,size_t length,const void * data,struct drm_mode_object * obj_holds_id,struct drm_property * prop_holds_id)6711dedbd3bSFrançois Tigeot int drm_property_replace_global_blob(struct drm_device *dev,
6721dedbd3bSFrançois Tigeot 				     struct drm_property_blob **replace,
6731dedbd3bSFrançois Tigeot 				     size_t length,
6741dedbd3bSFrançois Tigeot 				     const void *data,
6751dedbd3bSFrançois Tigeot 				     struct drm_mode_object *obj_holds_id,
6761dedbd3bSFrançois Tigeot 				     struct drm_property *prop_holds_id)
6771dedbd3bSFrançois Tigeot {
6781dedbd3bSFrançois Tigeot 	struct drm_property_blob *new_blob = NULL;
6791dedbd3bSFrançois Tigeot 	struct drm_property_blob *old_blob = NULL;
6801dedbd3bSFrançois Tigeot 	int ret;
6811dedbd3bSFrançois Tigeot 
6821dedbd3bSFrançois Tigeot 	WARN_ON(replace == NULL);
6831dedbd3bSFrançois Tigeot 
6841dedbd3bSFrançois Tigeot 	old_blob = *replace;
6851dedbd3bSFrançois Tigeot 
6861dedbd3bSFrançois Tigeot 	if (length && data) {
6871dedbd3bSFrançois Tigeot 		new_blob = drm_property_create_blob(dev, length, data);
6881dedbd3bSFrançois Tigeot 		if (IS_ERR(new_blob))
6891dedbd3bSFrançois Tigeot 			return PTR_ERR(new_blob);
6901dedbd3bSFrançois Tigeot 	}
6911dedbd3bSFrançois Tigeot 
6921dedbd3bSFrançois Tigeot 	if (obj_holds_id) {
6931dedbd3bSFrançois Tigeot 		ret = drm_object_property_set_value(obj_holds_id,
6941dedbd3bSFrançois Tigeot 						    prop_holds_id,
6951dedbd3bSFrançois Tigeot 						    new_blob ?
6961dedbd3bSFrançois Tigeot 						        new_blob->base.id : 0);
6971dedbd3bSFrançois Tigeot 		if (ret != 0)
6981dedbd3bSFrançois Tigeot 			goto err_created;
6991dedbd3bSFrançois Tigeot 	}
7001dedbd3bSFrançois Tigeot 
701a85cb24fSFrançois Tigeot 	drm_property_blob_put(old_blob);
7021dedbd3bSFrançois Tigeot 	*replace = new_blob;
7031dedbd3bSFrançois Tigeot 
7041dedbd3bSFrançois Tigeot 	return 0;
7051dedbd3bSFrançois Tigeot 
7061dedbd3bSFrançois Tigeot err_created:
707a85cb24fSFrançois Tigeot 	drm_property_blob_put(new_blob);
7081dedbd3bSFrançois Tigeot 	return ret;
7091dedbd3bSFrançois Tigeot }
7101dedbd3bSFrançois Tigeot EXPORT_SYMBOL(drm_property_replace_global_blob);
7111dedbd3bSFrançois Tigeot 
712*3f2dd94aSFrançois Tigeot /**
713*3f2dd94aSFrançois Tigeot  * drm_property_replace_blob - replace a blob property
714*3f2dd94aSFrançois Tigeot  * @blob: a pointer to the member blob to be replaced
715*3f2dd94aSFrançois Tigeot  * @new_blob: the new blob to replace with
716*3f2dd94aSFrançois Tigeot  *
717*3f2dd94aSFrançois Tigeot  * Return: true if the blob was in fact replaced.
718*3f2dd94aSFrançois Tigeot  */
drm_property_replace_blob(struct drm_property_blob ** blob,struct drm_property_blob * new_blob)719*3f2dd94aSFrançois Tigeot bool drm_property_replace_blob(struct drm_property_blob **blob,
720*3f2dd94aSFrançois Tigeot 			       struct drm_property_blob *new_blob)
721*3f2dd94aSFrançois Tigeot {
722*3f2dd94aSFrançois Tigeot 	struct drm_property_blob *old_blob = *blob;
723*3f2dd94aSFrançois Tigeot 
724*3f2dd94aSFrançois Tigeot 	if (old_blob == new_blob)
725*3f2dd94aSFrançois Tigeot 		return false;
726*3f2dd94aSFrançois Tigeot 
727*3f2dd94aSFrançois Tigeot 	drm_property_blob_put(old_blob);
728*3f2dd94aSFrançois Tigeot 	if (new_blob)
729*3f2dd94aSFrançois Tigeot 		drm_property_blob_get(new_blob);
730*3f2dd94aSFrançois Tigeot 	*blob = new_blob;
731*3f2dd94aSFrançois Tigeot 	return true;
732*3f2dd94aSFrançois Tigeot }
733*3f2dd94aSFrançois Tigeot EXPORT_SYMBOL(drm_property_replace_blob);
734*3f2dd94aSFrançois Tigeot 
drm_mode_getblob_ioctl(struct drm_device * dev,void * data,struct drm_file * file_priv)7351dedbd3bSFrançois Tigeot int drm_mode_getblob_ioctl(struct drm_device *dev,
7361dedbd3bSFrançois Tigeot 			   void *data, struct drm_file *file_priv)
7371dedbd3bSFrançois Tigeot {
7381dedbd3bSFrançois Tigeot 	struct drm_mode_get_blob *out_resp = data;
7391dedbd3bSFrançois Tigeot 	struct drm_property_blob *blob;
7401dedbd3bSFrançois Tigeot 	int ret = 0;
7411dedbd3bSFrançois Tigeot 
7421dedbd3bSFrançois Tigeot 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
7431dedbd3bSFrançois Tigeot 		return -EINVAL;
7441dedbd3bSFrançois Tigeot 
7451dedbd3bSFrançois Tigeot 	blob = drm_property_lookup_blob(dev, out_resp->blob_id);
7461dedbd3bSFrançois Tigeot 	if (!blob)
7471dedbd3bSFrançois Tigeot 		return -ENOENT;
7481dedbd3bSFrançois Tigeot 
7491dedbd3bSFrançois Tigeot 	if (out_resp->length == blob->length) {
7504be47400SFrançois Tigeot 		if (copy_to_user(u64_to_user_ptr(out_resp->data),
7514be47400SFrançois Tigeot 				 blob->data,
7524be47400SFrançois Tigeot 				 blob->length)) {
7531dedbd3bSFrançois Tigeot 			ret = -EFAULT;
7541dedbd3bSFrançois Tigeot 			goto unref;
7551dedbd3bSFrançois Tigeot 		}
7561dedbd3bSFrançois Tigeot 	}
7571dedbd3bSFrançois Tigeot 	out_resp->length = blob->length;
7581dedbd3bSFrançois Tigeot unref:
759a85cb24fSFrançois Tigeot 	drm_property_blob_put(blob);
7601dedbd3bSFrançois Tigeot 
7611dedbd3bSFrançois Tigeot 	return ret;
7621dedbd3bSFrançois Tigeot }
7631dedbd3bSFrançois Tigeot 
drm_mode_createblob_ioctl(struct drm_device * dev,void * data,struct drm_file * file_priv)7641dedbd3bSFrançois Tigeot int drm_mode_createblob_ioctl(struct drm_device *dev,
7651dedbd3bSFrançois Tigeot 			      void *data, struct drm_file *file_priv)
7661dedbd3bSFrançois Tigeot {
7671dedbd3bSFrançois Tigeot 	struct drm_mode_create_blob *out_resp = data;
7681dedbd3bSFrançois Tigeot 	struct drm_property_blob *blob;
7691dedbd3bSFrançois Tigeot 	int ret = 0;
7701dedbd3bSFrançois Tigeot 
7711dedbd3bSFrançois Tigeot 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
7721dedbd3bSFrançois Tigeot 		return -EINVAL;
7731dedbd3bSFrançois Tigeot 
7741dedbd3bSFrançois Tigeot 	blob = drm_property_create_blob(dev, out_resp->length, NULL);
7751dedbd3bSFrançois Tigeot 	if (IS_ERR(blob))
7761dedbd3bSFrançois Tigeot 		return PTR_ERR(blob);
7771dedbd3bSFrançois Tigeot 
7784be47400SFrançois Tigeot 	if (copy_from_user(blob->data,
7794be47400SFrançois Tigeot 			   u64_to_user_ptr(out_resp->data),
7804be47400SFrançois Tigeot 			   out_resp->length)) {
7811dedbd3bSFrançois Tigeot 		ret = -EFAULT;
7821dedbd3bSFrançois Tigeot 		goto out_blob;
7831dedbd3bSFrançois Tigeot 	}
7841dedbd3bSFrançois Tigeot 
7851dedbd3bSFrançois Tigeot 	/* Dropping the lock between create_blob and our access here is safe
7861dedbd3bSFrançois Tigeot 	 * as only the same file_priv can remove the blob; at this point, it is
7871dedbd3bSFrançois Tigeot 	 * not associated with any file_priv. */
7881dedbd3bSFrançois Tigeot 	mutex_lock(&dev->mode_config.blob_lock);
7891dedbd3bSFrançois Tigeot 	out_resp->blob_id = blob->base.id;
7901dedbd3bSFrançois Tigeot 	list_add_tail(&blob->head_file, &file_priv->blobs);
7911dedbd3bSFrançois Tigeot 	mutex_unlock(&dev->mode_config.blob_lock);
7921dedbd3bSFrançois Tigeot 
7931dedbd3bSFrançois Tigeot 	return 0;
7941dedbd3bSFrançois Tigeot 
7951dedbd3bSFrançois Tigeot out_blob:
796a85cb24fSFrançois Tigeot 	drm_property_blob_put(blob);
7971dedbd3bSFrançois Tigeot 	return ret;
7981dedbd3bSFrançois Tigeot }
7991dedbd3bSFrançois Tigeot 
drm_mode_destroyblob_ioctl(struct drm_device * dev,void * data,struct drm_file * file_priv)8001dedbd3bSFrançois Tigeot int drm_mode_destroyblob_ioctl(struct drm_device *dev,
8011dedbd3bSFrançois Tigeot 			       void *data, struct drm_file *file_priv)
8021dedbd3bSFrançois Tigeot {
8031dedbd3bSFrançois Tigeot 	struct drm_mode_destroy_blob *out_resp = data;
8041dedbd3bSFrançois Tigeot 	struct drm_property_blob *blob = NULL, *bt;
8051dedbd3bSFrançois Tigeot 	bool found = false;
8061dedbd3bSFrançois Tigeot 	int ret = 0;
8071dedbd3bSFrançois Tigeot 
8081dedbd3bSFrançois Tigeot 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
8091dedbd3bSFrançois Tigeot 		return -EINVAL;
8101dedbd3bSFrançois Tigeot 
8111dedbd3bSFrançois Tigeot 	blob = drm_property_lookup_blob(dev, out_resp->blob_id);
8121dedbd3bSFrançois Tigeot 	if (!blob)
8131dedbd3bSFrançois Tigeot 		return -ENOENT;
8141dedbd3bSFrançois Tigeot 
8151dedbd3bSFrançois Tigeot 	mutex_lock(&dev->mode_config.blob_lock);
8161dedbd3bSFrançois Tigeot 	/* Ensure the property was actually created by this user. */
8171dedbd3bSFrançois Tigeot 	list_for_each_entry(bt, &file_priv->blobs, head_file) {
8181dedbd3bSFrançois Tigeot 		if (bt == blob) {
8191dedbd3bSFrançois Tigeot 			found = true;
8201dedbd3bSFrançois Tigeot 			break;
8211dedbd3bSFrançois Tigeot 		}
8221dedbd3bSFrançois Tigeot 	}
8231dedbd3bSFrançois Tigeot 
8241dedbd3bSFrançois Tigeot 	if (!found) {
8251dedbd3bSFrançois Tigeot 		ret = -EPERM;
8261dedbd3bSFrançois Tigeot 		goto err;
8271dedbd3bSFrançois Tigeot 	}
8281dedbd3bSFrançois Tigeot 
8291dedbd3bSFrançois Tigeot 	/* We must drop head_file here, because we may not be the last
8301dedbd3bSFrançois Tigeot 	 * reference on the blob. */
8311dedbd3bSFrançois Tigeot 	list_del_init(&blob->head_file);
8321dedbd3bSFrançois Tigeot 	mutex_unlock(&dev->mode_config.blob_lock);
8331dedbd3bSFrançois Tigeot 
8341dedbd3bSFrançois Tigeot 	/* One reference from lookup, and one from the filp. */
835a85cb24fSFrançois Tigeot 	drm_property_blob_put(blob);
836a85cb24fSFrançois Tigeot 	drm_property_blob_put(blob);
8371dedbd3bSFrançois Tigeot 
8381dedbd3bSFrançois Tigeot 	return 0;
8391dedbd3bSFrançois Tigeot 
8401dedbd3bSFrançois Tigeot err:
8411dedbd3bSFrançois Tigeot 	mutex_unlock(&dev->mode_config.blob_lock);
842a85cb24fSFrançois Tigeot 	drm_property_blob_put(blob);
8431dedbd3bSFrançois Tigeot 
8441dedbd3bSFrançois Tigeot 	return ret;
8451dedbd3bSFrançois Tigeot }
8461dedbd3bSFrançois Tigeot 
8471dedbd3bSFrançois Tigeot /* Some properties could refer to dynamic refcnt'd objects, or things that
8481dedbd3bSFrançois Tigeot  * need special locking to handle lifetime issues (ie. to ensure the prop
8491dedbd3bSFrançois Tigeot  * value doesn't become invalid part way through the property update due to
8501dedbd3bSFrançois Tigeot  * race).  The value returned by reference via 'obj' should be passed back
8511dedbd3bSFrançois Tigeot  * to drm_property_change_valid_put() after the property is set (and the
8521dedbd3bSFrançois Tigeot  * object to which the property is attached has a chance to take it's own
8531dedbd3bSFrançois Tigeot  * reference).
8541dedbd3bSFrançois Tigeot  */
drm_property_change_valid_get(struct drm_property * property,uint64_t value,struct drm_mode_object ** ref)8551dedbd3bSFrançois Tigeot bool drm_property_change_valid_get(struct drm_property *property,
8561dedbd3bSFrançois Tigeot 				   uint64_t value, struct drm_mode_object **ref)
8571dedbd3bSFrançois Tigeot {
8581dedbd3bSFrançois Tigeot 	int i;
8591dedbd3bSFrançois Tigeot 
8601dedbd3bSFrançois Tigeot 	if (property->flags & DRM_MODE_PROP_IMMUTABLE)
8611dedbd3bSFrançois Tigeot 		return false;
8621dedbd3bSFrançois Tigeot 
8631dedbd3bSFrançois Tigeot 	*ref = NULL;
8641dedbd3bSFrançois Tigeot 
8651dedbd3bSFrançois Tigeot 	if (drm_property_type_is(property, DRM_MODE_PROP_RANGE)) {
8661dedbd3bSFrançois Tigeot 		if (value < property->values[0] || value > property->values[1])
8671dedbd3bSFrançois Tigeot 			return false;
8681dedbd3bSFrançois Tigeot 		return true;
8691dedbd3bSFrançois Tigeot 	} else if (drm_property_type_is(property, DRM_MODE_PROP_SIGNED_RANGE)) {
8701dedbd3bSFrançois Tigeot 		int64_t svalue = U642I64(value);
8711dedbd3bSFrançois Tigeot 
8721dedbd3bSFrançois Tigeot 		if (svalue < U642I64(property->values[0]) ||
8731dedbd3bSFrançois Tigeot 				svalue > U642I64(property->values[1]))
8741dedbd3bSFrançois Tigeot 			return false;
8751dedbd3bSFrançois Tigeot 		return true;
8761dedbd3bSFrançois Tigeot 	} else if (drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) {
8771dedbd3bSFrançois Tigeot 		uint64_t valid_mask = 0;
8781dedbd3bSFrançois Tigeot 
8791dedbd3bSFrançois Tigeot 		for (i = 0; i < property->num_values; i++)
8801dedbd3bSFrançois Tigeot 			valid_mask |= (1ULL << property->values[i]);
8811dedbd3bSFrançois Tigeot 		return !(value & ~valid_mask);
8824be47400SFrançois Tigeot 	} else if (drm_property_type_is(property, DRM_MODE_PROP_BLOB)) {
8834be47400SFrançois Tigeot 		struct drm_property_blob *blob;
8844be47400SFrançois Tigeot 
8854be47400SFrançois Tigeot 		if (value == 0)
8864be47400SFrançois Tigeot 			return true;
8874be47400SFrançois Tigeot 
8884be47400SFrançois Tigeot 		blob = drm_property_lookup_blob(property->dev, value);
8894be47400SFrançois Tigeot 		if (blob) {
8904be47400SFrançois Tigeot 			*ref = &blob->base;
8914be47400SFrançois Tigeot 			return true;
8924be47400SFrançois Tigeot 		} else {
8934be47400SFrançois Tigeot 			return false;
8944be47400SFrançois Tigeot 		}
8954be47400SFrançois Tigeot 	} else if (drm_property_type_is(property, DRM_MODE_PROP_OBJECT)) {
8961dedbd3bSFrançois Tigeot 		/* a zero value for an object property translates to null: */
8971dedbd3bSFrançois Tigeot 		if (value == 0)
8981dedbd3bSFrançois Tigeot 			return true;
8991dedbd3bSFrançois Tigeot 
900*3f2dd94aSFrançois Tigeot 		*ref = __drm_mode_object_find(property->dev, NULL, value,
9011dedbd3bSFrançois Tigeot 					      property->values[0]);
9021dedbd3bSFrançois Tigeot 		return *ref != NULL;
9031dedbd3bSFrançois Tigeot 	}
9041dedbd3bSFrançois Tigeot 
9051dedbd3bSFrançois Tigeot 	for (i = 0; i < property->num_values; i++)
9061dedbd3bSFrançois Tigeot 		if (property->values[i] == value)
9071dedbd3bSFrançois Tigeot 			return true;
9081dedbd3bSFrançois Tigeot 	return false;
9091dedbd3bSFrançois Tigeot }
9101dedbd3bSFrançois Tigeot 
drm_property_change_valid_put(struct drm_property * property,struct drm_mode_object * ref)9111dedbd3bSFrançois Tigeot void drm_property_change_valid_put(struct drm_property *property,
9121dedbd3bSFrançois Tigeot 		struct drm_mode_object *ref)
9131dedbd3bSFrançois Tigeot {
9141dedbd3bSFrançois Tigeot 	if (!ref)
9151dedbd3bSFrançois Tigeot 		return;
9161dedbd3bSFrançois Tigeot 
9174be47400SFrançois Tigeot 	if (drm_property_type_is(property, DRM_MODE_PROP_OBJECT)) {
918a85cb24fSFrançois Tigeot 		drm_mode_object_put(ref);
9194be47400SFrançois Tigeot 	} else if (drm_property_type_is(property, DRM_MODE_PROP_BLOB))
920a85cb24fSFrançois Tigeot 		drm_property_blob_put(obj_to_blob(ref));
9211dedbd3bSFrançois Tigeot }
922