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 37*a85cb24fSFranç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 45*a85cb24fSFrançois Tigeot * tables, color correction matrices or large structures) a property can instead 46*a85cb24fSFranç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 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 */ 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 94*a85cb24fSFranç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 */ 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 */ 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 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 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; 445*a85cb24fSFranç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 4531dedbd3bSFrançois Tigeot property = drm_property_find(dev, out_resp->prop_id); 454*a85cb24fSFrançois Tigeot if (!property) 455*a85cb24fSFranç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 461*a85cb24fSFrançois Tigeot value_count = property->num_values; 462*a85cb24fSFrançois Tigeot values_ptr = u64_to_user_ptr(out_resp->values_ptr); 463*a85cb24fSFrançois Tigeot 4641dedbd3bSFrançois Tigeot for (i = 0; i < value_count; i++) { 465*a85cb24fSFrançois Tigeot if (i < out_resp->count_values && 466*a85cb24fSFrançois Tigeot put_user(property->values[i], values_ptr + i)) { 467*a85cb24fSFrançois Tigeot return -EFAULT; 4681dedbd3bSFrançois Tigeot } 4691dedbd3bSFrançois Tigeot } 4701dedbd3bSFrançois Tigeot out_resp->count_values = value_count; 4711dedbd3bSFrançois Tigeot 472*a85cb24fSFrançois Tigeot copied = 0; 473*a85cb24fSFrançois Tigeot enum_ptr = u64_to_user_ptr(out_resp->enum_blob_ptr); 474*a85cb24fSFranç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) { 478*a85cb24fSFrançois Tigeot enum_count++; 479*a85cb24fSFrançois Tigeot if (out_resp->count_enum_blobs < enum_count) 480*a85cb24fSFrançois Tigeot continue; 4811dedbd3bSFrançois Tigeot 482*a85cb24fSFrançois Tigeot if (copy_to_user(&enum_ptr[copied].value, 483*a85cb24fSFrançois Tigeot &prop_enum->value, sizeof(uint64_t))) 484*a85cb24fSFrançois Tigeot return -EFAULT; 4851dedbd3bSFrançois Tigeot 4861dedbd3bSFrançois Tigeot if (copy_to_user(&enum_ptr[copied].name, 487*a85cb24fSFrançois Tigeot &prop_enum->name, DRM_PROP_NAME_LEN)) 488*a85cb24fSFranç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; 504*a85cb24fSFrançois Tigeot 505*a85cb24fSFrançois Tigeot return 0; 5061dedbd3bSFrançois Tigeot } 5071dedbd3bSFrançois Tigeot 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 * 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 559*a85cb24fSFranç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 /** 576*a85cb24fSFrançois Tigeot * drm_property_blob_put - release a blob property reference 577*a85cb24fSFrançois Tigeot * @blob: DRM blob property 5781dedbd3bSFrançois Tigeot * 579*a85cb24fSFrançois Tigeot * Releases a reference to a blob property. May free the object. 5801dedbd3bSFrançois Tigeot */ 581*a85cb24fSFranç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 586*a85cb24fSFrançois Tigeot drm_mode_object_put(&blob->base); 5871dedbd3bSFrançois Tigeot } 588*a85cb24fSFrançois Tigeot EXPORT_SYMBOL(drm_property_blob_put); 5891dedbd3bSFrançois Tigeot 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); 601*a85cb24fSFrançois Tigeot drm_property_blob_put(blob); 6021dedbd3bSFrançois Tigeot } 6031dedbd3bSFrançois Tigeot } 6041dedbd3bSFrançois Tigeot 6051dedbd3bSFrançois Tigeot /** 606*a85cb24fSFrançois Tigeot * drm_property_blob_get - acquire blob property reference 607*a85cb24fSFrançois Tigeot * @blob: DRM blob property 6081dedbd3bSFrançois Tigeot * 609*a85cb24fSFranç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 */ 612*a85cb24fSFrançois Tigeot struct drm_property_blob *drm_property_blob_get(struct drm_property_blob *blob) 6131dedbd3bSFrançois Tigeot { 614*a85cb24fSFrançois Tigeot drm_mode_object_get(&blob->base); 6151dedbd3bSFrançois Tigeot return blob; 6161dedbd3bSFrançois Tigeot } 617*a85cb24fSFranç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 626*a85cb24fSFranç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 */ 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 6371dedbd3bSFrançois Tigeot obj = __drm_mode_object_find(dev, 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 */ 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 701*a85cb24fSFranç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: 707*a85cb24fSFranç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 7121dedbd3bSFrançois Tigeot int drm_mode_getblob_ioctl(struct drm_device *dev, 7131dedbd3bSFrançois Tigeot void *data, struct drm_file *file_priv) 7141dedbd3bSFrançois Tigeot { 7151dedbd3bSFrançois Tigeot struct drm_mode_get_blob *out_resp = data; 7161dedbd3bSFrançois Tigeot struct drm_property_blob *blob; 7171dedbd3bSFrançois Tigeot int ret = 0; 7181dedbd3bSFrançois Tigeot 7191dedbd3bSFrançois Tigeot if (!drm_core_check_feature(dev, DRIVER_MODESET)) 7201dedbd3bSFrançois Tigeot return -EINVAL; 7211dedbd3bSFrançois Tigeot 7221dedbd3bSFrançois Tigeot blob = drm_property_lookup_blob(dev, out_resp->blob_id); 7231dedbd3bSFrançois Tigeot if (!blob) 7241dedbd3bSFrançois Tigeot return -ENOENT; 7251dedbd3bSFrançois Tigeot 7261dedbd3bSFrançois Tigeot if (out_resp->length == blob->length) { 7274be47400SFrançois Tigeot if (copy_to_user(u64_to_user_ptr(out_resp->data), 7284be47400SFrançois Tigeot blob->data, 7294be47400SFrançois Tigeot blob->length)) { 7301dedbd3bSFrançois Tigeot ret = -EFAULT; 7311dedbd3bSFrançois Tigeot goto unref; 7321dedbd3bSFrançois Tigeot } 7331dedbd3bSFrançois Tigeot } 7341dedbd3bSFrançois Tigeot out_resp->length = blob->length; 7351dedbd3bSFrançois Tigeot unref: 736*a85cb24fSFrançois Tigeot drm_property_blob_put(blob); 7371dedbd3bSFrançois Tigeot 7381dedbd3bSFrançois Tigeot return ret; 7391dedbd3bSFrançois Tigeot } 7401dedbd3bSFrançois Tigeot 7411dedbd3bSFrançois Tigeot int drm_mode_createblob_ioctl(struct drm_device *dev, 7421dedbd3bSFrançois Tigeot void *data, struct drm_file *file_priv) 7431dedbd3bSFrançois Tigeot { 7441dedbd3bSFrançois Tigeot struct drm_mode_create_blob *out_resp = data; 7451dedbd3bSFrançois Tigeot struct drm_property_blob *blob; 7461dedbd3bSFrançois Tigeot int ret = 0; 7471dedbd3bSFrançois Tigeot 7481dedbd3bSFrançois Tigeot if (!drm_core_check_feature(dev, DRIVER_MODESET)) 7491dedbd3bSFrançois Tigeot return -EINVAL; 7501dedbd3bSFrançois Tigeot 7511dedbd3bSFrançois Tigeot blob = drm_property_create_blob(dev, out_resp->length, NULL); 7521dedbd3bSFrançois Tigeot if (IS_ERR(blob)) 7531dedbd3bSFrançois Tigeot return PTR_ERR(blob); 7541dedbd3bSFrançois Tigeot 7554be47400SFrançois Tigeot if (copy_from_user(blob->data, 7564be47400SFrançois Tigeot u64_to_user_ptr(out_resp->data), 7574be47400SFrançois Tigeot out_resp->length)) { 7581dedbd3bSFrançois Tigeot ret = -EFAULT; 7591dedbd3bSFrançois Tigeot goto out_blob; 7601dedbd3bSFrançois Tigeot } 7611dedbd3bSFrançois Tigeot 7621dedbd3bSFrançois Tigeot /* Dropping the lock between create_blob and our access here is safe 7631dedbd3bSFrançois Tigeot * as only the same file_priv can remove the blob; at this point, it is 7641dedbd3bSFrançois Tigeot * not associated with any file_priv. */ 7651dedbd3bSFrançois Tigeot mutex_lock(&dev->mode_config.blob_lock); 7661dedbd3bSFrançois Tigeot out_resp->blob_id = blob->base.id; 7671dedbd3bSFrançois Tigeot list_add_tail(&blob->head_file, &file_priv->blobs); 7681dedbd3bSFrançois Tigeot mutex_unlock(&dev->mode_config.blob_lock); 7691dedbd3bSFrançois Tigeot 7701dedbd3bSFrançois Tigeot return 0; 7711dedbd3bSFrançois Tigeot 7721dedbd3bSFrançois Tigeot out_blob: 773*a85cb24fSFrançois Tigeot drm_property_blob_put(blob); 7741dedbd3bSFrançois Tigeot return ret; 7751dedbd3bSFrançois Tigeot } 7761dedbd3bSFrançois Tigeot 7771dedbd3bSFrançois Tigeot int drm_mode_destroyblob_ioctl(struct drm_device *dev, 7781dedbd3bSFrançois Tigeot void *data, struct drm_file *file_priv) 7791dedbd3bSFrançois Tigeot { 7801dedbd3bSFrançois Tigeot struct drm_mode_destroy_blob *out_resp = data; 7811dedbd3bSFrançois Tigeot struct drm_property_blob *blob = NULL, *bt; 7821dedbd3bSFrançois Tigeot bool found = false; 7831dedbd3bSFrançois Tigeot int ret = 0; 7841dedbd3bSFrançois Tigeot 7851dedbd3bSFrançois Tigeot if (!drm_core_check_feature(dev, DRIVER_MODESET)) 7861dedbd3bSFrançois Tigeot return -EINVAL; 7871dedbd3bSFrançois Tigeot 7881dedbd3bSFrançois Tigeot blob = drm_property_lookup_blob(dev, out_resp->blob_id); 7891dedbd3bSFrançois Tigeot if (!blob) 7901dedbd3bSFrançois Tigeot return -ENOENT; 7911dedbd3bSFrançois Tigeot 7921dedbd3bSFrançois Tigeot mutex_lock(&dev->mode_config.blob_lock); 7931dedbd3bSFrançois Tigeot /* Ensure the property was actually created by this user. */ 7941dedbd3bSFrançois Tigeot list_for_each_entry(bt, &file_priv->blobs, head_file) { 7951dedbd3bSFrançois Tigeot if (bt == blob) { 7961dedbd3bSFrançois Tigeot found = true; 7971dedbd3bSFrançois Tigeot break; 7981dedbd3bSFrançois Tigeot } 7991dedbd3bSFrançois Tigeot } 8001dedbd3bSFrançois Tigeot 8011dedbd3bSFrançois Tigeot if (!found) { 8021dedbd3bSFrançois Tigeot ret = -EPERM; 8031dedbd3bSFrançois Tigeot goto err; 8041dedbd3bSFrançois Tigeot } 8051dedbd3bSFrançois Tigeot 8061dedbd3bSFrançois Tigeot /* We must drop head_file here, because we may not be the last 8071dedbd3bSFrançois Tigeot * reference on the blob. */ 8081dedbd3bSFrançois Tigeot list_del_init(&blob->head_file); 8091dedbd3bSFrançois Tigeot mutex_unlock(&dev->mode_config.blob_lock); 8101dedbd3bSFrançois Tigeot 8111dedbd3bSFrançois Tigeot /* One reference from lookup, and one from the filp. */ 812*a85cb24fSFrançois Tigeot drm_property_blob_put(blob); 813*a85cb24fSFrançois Tigeot drm_property_blob_put(blob); 8141dedbd3bSFrançois Tigeot 8151dedbd3bSFrançois Tigeot return 0; 8161dedbd3bSFrançois Tigeot 8171dedbd3bSFrançois Tigeot err: 8181dedbd3bSFrançois Tigeot mutex_unlock(&dev->mode_config.blob_lock); 819*a85cb24fSFrançois Tigeot drm_property_blob_put(blob); 8201dedbd3bSFrançois Tigeot 8211dedbd3bSFrançois Tigeot return ret; 8221dedbd3bSFrançois Tigeot } 8231dedbd3bSFrançois Tigeot 8241dedbd3bSFrançois Tigeot /* Some properties could refer to dynamic refcnt'd objects, or things that 8251dedbd3bSFrançois Tigeot * need special locking to handle lifetime issues (ie. to ensure the prop 8261dedbd3bSFrançois Tigeot * value doesn't become invalid part way through the property update due to 8271dedbd3bSFrançois Tigeot * race). The value returned by reference via 'obj' should be passed back 8281dedbd3bSFrançois Tigeot * to drm_property_change_valid_put() after the property is set (and the 8291dedbd3bSFrançois Tigeot * object to which the property is attached has a chance to take it's own 8301dedbd3bSFrançois Tigeot * reference). 8311dedbd3bSFrançois Tigeot */ 8321dedbd3bSFrançois Tigeot bool drm_property_change_valid_get(struct drm_property *property, 8331dedbd3bSFrançois Tigeot uint64_t value, struct drm_mode_object **ref) 8341dedbd3bSFrançois Tigeot { 8351dedbd3bSFrançois Tigeot int i; 8361dedbd3bSFrançois Tigeot 8371dedbd3bSFrançois Tigeot if (property->flags & DRM_MODE_PROP_IMMUTABLE) 8381dedbd3bSFrançois Tigeot return false; 8391dedbd3bSFrançois Tigeot 8401dedbd3bSFrançois Tigeot *ref = NULL; 8411dedbd3bSFrançois Tigeot 8421dedbd3bSFrançois Tigeot if (drm_property_type_is(property, DRM_MODE_PROP_RANGE)) { 8431dedbd3bSFrançois Tigeot if (value < property->values[0] || value > property->values[1]) 8441dedbd3bSFrançois Tigeot return false; 8451dedbd3bSFrançois Tigeot return true; 8461dedbd3bSFrançois Tigeot } else if (drm_property_type_is(property, DRM_MODE_PROP_SIGNED_RANGE)) { 8471dedbd3bSFrançois Tigeot int64_t svalue = U642I64(value); 8481dedbd3bSFrançois Tigeot 8491dedbd3bSFrançois Tigeot if (svalue < U642I64(property->values[0]) || 8501dedbd3bSFrançois Tigeot svalue > U642I64(property->values[1])) 8511dedbd3bSFrançois Tigeot return false; 8521dedbd3bSFrançois Tigeot return true; 8531dedbd3bSFrançois Tigeot } else if (drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) { 8541dedbd3bSFrançois Tigeot uint64_t valid_mask = 0; 8551dedbd3bSFrançois Tigeot 8561dedbd3bSFrançois Tigeot for (i = 0; i < property->num_values; i++) 8571dedbd3bSFrançois Tigeot valid_mask |= (1ULL << property->values[i]); 8581dedbd3bSFrançois Tigeot return !(value & ~valid_mask); 8594be47400SFrançois Tigeot } else if (drm_property_type_is(property, DRM_MODE_PROP_BLOB)) { 8604be47400SFrançois Tigeot struct drm_property_blob *blob; 8614be47400SFrançois Tigeot 8624be47400SFrançois Tigeot if (value == 0) 8634be47400SFrançois Tigeot return true; 8644be47400SFrançois Tigeot 8654be47400SFrançois Tigeot blob = drm_property_lookup_blob(property->dev, value); 8664be47400SFrançois Tigeot if (blob) { 8674be47400SFrançois Tigeot *ref = &blob->base; 8684be47400SFrançois Tigeot return true; 8694be47400SFrançois Tigeot } else { 8704be47400SFrançois Tigeot return false; 8714be47400SFrançois Tigeot } 8724be47400SFrançois Tigeot } else if (drm_property_type_is(property, DRM_MODE_PROP_OBJECT)) { 8731dedbd3bSFrançois Tigeot /* a zero value for an object property translates to null: */ 8741dedbd3bSFrançois Tigeot if (value == 0) 8751dedbd3bSFrançois Tigeot return true; 8761dedbd3bSFrançois Tigeot 8771dedbd3bSFrançois Tigeot *ref = __drm_mode_object_find(property->dev, value, 8781dedbd3bSFrançois Tigeot property->values[0]); 8791dedbd3bSFrançois Tigeot return *ref != NULL; 8801dedbd3bSFrançois Tigeot } 8811dedbd3bSFrançois Tigeot 8821dedbd3bSFrançois Tigeot for (i = 0; i < property->num_values; i++) 8831dedbd3bSFrançois Tigeot if (property->values[i] == value) 8841dedbd3bSFrançois Tigeot return true; 8851dedbd3bSFrançois Tigeot return false; 8861dedbd3bSFrançois Tigeot } 8871dedbd3bSFrançois Tigeot 8881dedbd3bSFrançois Tigeot void drm_property_change_valid_put(struct drm_property *property, 8891dedbd3bSFrançois Tigeot struct drm_mode_object *ref) 8901dedbd3bSFrançois Tigeot { 8911dedbd3bSFrançois Tigeot if (!ref) 8921dedbd3bSFrançois Tigeot return; 8931dedbd3bSFrançois Tigeot 8944be47400SFrançois Tigeot if (drm_property_type_is(property, DRM_MODE_PROP_OBJECT)) { 895*a85cb24fSFrançois Tigeot drm_mode_object_put(ref); 8964be47400SFrançois Tigeot } else if (drm_property_type_is(property, DRM_MODE_PROP_BLOB)) 897*a85cb24fSFrançois Tigeot drm_property_blob_put(obj_to_blob(ref)); 8981dedbd3bSFrançois Tigeot } 899