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