162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright (c) 2016 Intel Corporation 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Permission to use, copy, modify, distribute, and sell this software and its 562306a36Sopenharmony_ci * documentation for any purpose is hereby granted without fee, provided that 662306a36Sopenharmony_ci * the above copyright notice appear in all copies and that both that copyright 762306a36Sopenharmony_ci * notice and this permission notice appear in supporting documentation, and 862306a36Sopenharmony_ci * that the name of the copyright holders not be used in advertising or 962306a36Sopenharmony_ci * publicity pertaining to distribution of the software without specific, 1062306a36Sopenharmony_ci * written prior permission. The copyright holders make no representations 1162306a36Sopenharmony_ci * about the suitability of this software for any purpose. It is provided "as 1262306a36Sopenharmony_ci * is" without express or implied warranty. 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 1562306a36Sopenharmony_ci * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 1662306a36Sopenharmony_ci * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 1762306a36Sopenharmony_ci * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 1862306a36Sopenharmony_ci * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 1962306a36Sopenharmony_ci * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 2062306a36Sopenharmony_ci * OF THIS SOFTWARE. 2162306a36Sopenharmony_ci */ 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#include <linux/export.h> 2462306a36Sopenharmony_ci#include <linux/uaccess.h> 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#include <drm/drm_crtc.h> 2762306a36Sopenharmony_ci#include <drm/drm_drv.h> 2862306a36Sopenharmony_ci#include <drm/drm_file.h> 2962306a36Sopenharmony_ci#include <drm/drm_framebuffer.h> 3062306a36Sopenharmony_ci#include <drm/drm_property.h> 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci#include "drm_crtc_internal.h" 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci/** 3562306a36Sopenharmony_ci * DOC: overview 3662306a36Sopenharmony_ci * 3762306a36Sopenharmony_ci * Properties as represented by &drm_property are used to extend the modeset 3862306a36Sopenharmony_ci * interface exposed to userspace. For the atomic modeset IOCTL properties are 3962306a36Sopenharmony_ci * even the only way to transport metadata about the desired new modeset 4062306a36Sopenharmony_ci * configuration from userspace to the kernel. Properties have a well-defined 4162306a36Sopenharmony_ci * value range, which is enforced by the drm core. See the documentation of the 4262306a36Sopenharmony_ci * flags member of &struct drm_property for an overview of the different 4362306a36Sopenharmony_ci * property types and ranges. 4462306a36Sopenharmony_ci * 4562306a36Sopenharmony_ci * Properties don't store the current value directly, but need to be 4662306a36Sopenharmony_ci * instantiated by attaching them to a &drm_mode_object with 4762306a36Sopenharmony_ci * drm_object_attach_property(). 4862306a36Sopenharmony_ci * 4962306a36Sopenharmony_ci * Property values are only 64bit. To support bigger piles of data (like gamma 5062306a36Sopenharmony_ci * tables, color correction matrices or large structures) a property can instead 5162306a36Sopenharmony_ci * point at a &drm_property_blob with that additional data. 5262306a36Sopenharmony_ci * 5362306a36Sopenharmony_ci * Properties are defined by their symbolic name, userspace must keep a 5462306a36Sopenharmony_ci * per-object mapping from those names to the property ID used in the atomic 5562306a36Sopenharmony_ci * IOCTL and in the get/set property IOCTL. 5662306a36Sopenharmony_ci */ 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_cistatic bool drm_property_flags_valid(u32 flags) 5962306a36Sopenharmony_ci{ 6062306a36Sopenharmony_ci u32 legacy_type = flags & DRM_MODE_PROP_LEGACY_TYPE; 6162306a36Sopenharmony_ci u32 ext_type = flags & DRM_MODE_PROP_EXTENDED_TYPE; 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci /* Reject undefined/deprecated flags */ 6462306a36Sopenharmony_ci if (flags & ~(DRM_MODE_PROP_LEGACY_TYPE | 6562306a36Sopenharmony_ci DRM_MODE_PROP_EXTENDED_TYPE | 6662306a36Sopenharmony_ci DRM_MODE_PROP_IMMUTABLE | 6762306a36Sopenharmony_ci DRM_MODE_PROP_ATOMIC)) 6862306a36Sopenharmony_ci return false; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci /* We want either a legacy type or an extended type, but not both */ 7162306a36Sopenharmony_ci if (!legacy_type == !ext_type) 7262306a36Sopenharmony_ci return false; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci /* Only one legacy type at a time please */ 7562306a36Sopenharmony_ci if (legacy_type && !is_power_of_2(legacy_type)) 7662306a36Sopenharmony_ci return false; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci return true; 7962306a36Sopenharmony_ci} 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci/** 8262306a36Sopenharmony_ci * drm_property_create - create a new property type 8362306a36Sopenharmony_ci * @dev: drm device 8462306a36Sopenharmony_ci * @flags: flags specifying the property type 8562306a36Sopenharmony_ci * @name: name of the property 8662306a36Sopenharmony_ci * @num_values: number of pre-defined values 8762306a36Sopenharmony_ci * 8862306a36Sopenharmony_ci * This creates a new generic drm property which can then be attached to a drm 8962306a36Sopenharmony_ci * object with drm_object_attach_property(). The returned property object must 9062306a36Sopenharmony_ci * be freed with drm_property_destroy(), which is done automatically when 9162306a36Sopenharmony_ci * calling drm_mode_config_cleanup(). 9262306a36Sopenharmony_ci * 9362306a36Sopenharmony_ci * Returns: 9462306a36Sopenharmony_ci * A pointer to the newly created property on success, NULL on failure. 9562306a36Sopenharmony_ci */ 9662306a36Sopenharmony_cistruct drm_property *drm_property_create(struct drm_device *dev, 9762306a36Sopenharmony_ci u32 flags, const char *name, 9862306a36Sopenharmony_ci int num_values) 9962306a36Sopenharmony_ci{ 10062306a36Sopenharmony_ci struct drm_property *property = NULL; 10162306a36Sopenharmony_ci int ret; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci if (WARN_ON(!drm_property_flags_valid(flags))) 10462306a36Sopenharmony_ci return NULL; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci if (WARN_ON(strlen(name) >= DRM_PROP_NAME_LEN)) 10762306a36Sopenharmony_ci return NULL; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci property = kzalloc(sizeof(struct drm_property), GFP_KERNEL); 11062306a36Sopenharmony_ci if (!property) 11162306a36Sopenharmony_ci return NULL; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci property->dev = dev; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci if (num_values) { 11662306a36Sopenharmony_ci property->values = kcalloc(num_values, sizeof(uint64_t), 11762306a36Sopenharmony_ci GFP_KERNEL); 11862306a36Sopenharmony_ci if (!property->values) 11962306a36Sopenharmony_ci goto fail; 12062306a36Sopenharmony_ci } 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci ret = drm_mode_object_add(dev, &property->base, DRM_MODE_OBJECT_PROPERTY); 12362306a36Sopenharmony_ci if (ret) 12462306a36Sopenharmony_ci goto fail; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci property->flags = flags; 12762306a36Sopenharmony_ci property->num_values = num_values; 12862306a36Sopenharmony_ci INIT_LIST_HEAD(&property->enum_list); 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci strscpy_pad(property->name, name, DRM_PROP_NAME_LEN); 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci list_add_tail(&property->head, &dev->mode_config.property_list); 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci return property; 13562306a36Sopenharmony_cifail: 13662306a36Sopenharmony_ci kfree(property->values); 13762306a36Sopenharmony_ci kfree(property); 13862306a36Sopenharmony_ci return NULL; 13962306a36Sopenharmony_ci} 14062306a36Sopenharmony_ciEXPORT_SYMBOL(drm_property_create); 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci/** 14362306a36Sopenharmony_ci * drm_property_create_enum - create a new enumeration property type 14462306a36Sopenharmony_ci * @dev: drm device 14562306a36Sopenharmony_ci * @flags: flags specifying the property type 14662306a36Sopenharmony_ci * @name: name of the property 14762306a36Sopenharmony_ci * @props: enumeration lists with property values 14862306a36Sopenharmony_ci * @num_values: number of pre-defined values 14962306a36Sopenharmony_ci * 15062306a36Sopenharmony_ci * This creates a new generic drm property which can then be attached to a drm 15162306a36Sopenharmony_ci * object with drm_object_attach_property(). The returned property object must 15262306a36Sopenharmony_ci * be freed with drm_property_destroy(), which is done automatically when 15362306a36Sopenharmony_ci * calling drm_mode_config_cleanup(). 15462306a36Sopenharmony_ci * 15562306a36Sopenharmony_ci * Userspace is only allowed to set one of the predefined values for enumeration 15662306a36Sopenharmony_ci * properties. 15762306a36Sopenharmony_ci * 15862306a36Sopenharmony_ci * Returns: 15962306a36Sopenharmony_ci * A pointer to the newly created property on success, NULL on failure. 16062306a36Sopenharmony_ci */ 16162306a36Sopenharmony_cistruct drm_property *drm_property_create_enum(struct drm_device *dev, 16262306a36Sopenharmony_ci u32 flags, const char *name, 16362306a36Sopenharmony_ci const struct drm_prop_enum_list *props, 16462306a36Sopenharmony_ci int num_values) 16562306a36Sopenharmony_ci{ 16662306a36Sopenharmony_ci struct drm_property *property; 16762306a36Sopenharmony_ci int i, ret; 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci flags |= DRM_MODE_PROP_ENUM; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci property = drm_property_create(dev, flags, name, num_values); 17262306a36Sopenharmony_ci if (!property) 17362306a36Sopenharmony_ci return NULL; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci for (i = 0; i < num_values; i++) { 17662306a36Sopenharmony_ci ret = drm_property_add_enum(property, 17762306a36Sopenharmony_ci props[i].type, 17862306a36Sopenharmony_ci props[i].name); 17962306a36Sopenharmony_ci if (ret) { 18062306a36Sopenharmony_ci drm_property_destroy(dev, property); 18162306a36Sopenharmony_ci return NULL; 18262306a36Sopenharmony_ci } 18362306a36Sopenharmony_ci } 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci return property; 18662306a36Sopenharmony_ci} 18762306a36Sopenharmony_ciEXPORT_SYMBOL(drm_property_create_enum); 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci/** 19062306a36Sopenharmony_ci * drm_property_create_bitmask - create a new bitmask property type 19162306a36Sopenharmony_ci * @dev: drm device 19262306a36Sopenharmony_ci * @flags: flags specifying the property type 19362306a36Sopenharmony_ci * @name: name of the property 19462306a36Sopenharmony_ci * @props: enumeration lists with property bitflags 19562306a36Sopenharmony_ci * @num_props: size of the @props array 19662306a36Sopenharmony_ci * @supported_bits: bitmask of all supported enumeration values 19762306a36Sopenharmony_ci * 19862306a36Sopenharmony_ci * This creates a new bitmask drm property which can then be attached to a drm 19962306a36Sopenharmony_ci * object with drm_object_attach_property(). The returned property object must 20062306a36Sopenharmony_ci * be freed with drm_property_destroy(), which is done automatically when 20162306a36Sopenharmony_ci * calling drm_mode_config_cleanup(). 20262306a36Sopenharmony_ci * 20362306a36Sopenharmony_ci * Compared to plain enumeration properties userspace is allowed to set any 20462306a36Sopenharmony_ci * or'ed together combination of the predefined property bitflag values 20562306a36Sopenharmony_ci * 20662306a36Sopenharmony_ci * Returns: 20762306a36Sopenharmony_ci * A pointer to the newly created property on success, NULL on failure. 20862306a36Sopenharmony_ci */ 20962306a36Sopenharmony_cistruct drm_property *drm_property_create_bitmask(struct drm_device *dev, 21062306a36Sopenharmony_ci u32 flags, const char *name, 21162306a36Sopenharmony_ci const struct drm_prop_enum_list *props, 21262306a36Sopenharmony_ci int num_props, 21362306a36Sopenharmony_ci uint64_t supported_bits) 21462306a36Sopenharmony_ci{ 21562306a36Sopenharmony_ci struct drm_property *property; 21662306a36Sopenharmony_ci int i, ret; 21762306a36Sopenharmony_ci int num_values = hweight64(supported_bits); 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci flags |= DRM_MODE_PROP_BITMASK; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci property = drm_property_create(dev, flags, name, num_values); 22262306a36Sopenharmony_ci if (!property) 22362306a36Sopenharmony_ci return NULL; 22462306a36Sopenharmony_ci for (i = 0; i < num_props; i++) { 22562306a36Sopenharmony_ci if (!(supported_bits & (1ULL << props[i].type))) 22662306a36Sopenharmony_ci continue; 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci ret = drm_property_add_enum(property, 22962306a36Sopenharmony_ci props[i].type, 23062306a36Sopenharmony_ci props[i].name); 23162306a36Sopenharmony_ci if (ret) { 23262306a36Sopenharmony_ci drm_property_destroy(dev, property); 23362306a36Sopenharmony_ci return NULL; 23462306a36Sopenharmony_ci } 23562306a36Sopenharmony_ci } 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci return property; 23862306a36Sopenharmony_ci} 23962306a36Sopenharmony_ciEXPORT_SYMBOL(drm_property_create_bitmask); 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_cistatic struct drm_property *property_create_range(struct drm_device *dev, 24262306a36Sopenharmony_ci u32 flags, const char *name, 24362306a36Sopenharmony_ci uint64_t min, uint64_t max) 24462306a36Sopenharmony_ci{ 24562306a36Sopenharmony_ci struct drm_property *property; 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci property = drm_property_create(dev, flags, name, 2); 24862306a36Sopenharmony_ci if (!property) 24962306a36Sopenharmony_ci return NULL; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci property->values[0] = min; 25262306a36Sopenharmony_ci property->values[1] = max; 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci return property; 25562306a36Sopenharmony_ci} 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci/** 25862306a36Sopenharmony_ci * drm_property_create_range - create a new unsigned ranged property type 25962306a36Sopenharmony_ci * @dev: drm device 26062306a36Sopenharmony_ci * @flags: flags specifying the property type 26162306a36Sopenharmony_ci * @name: name of the property 26262306a36Sopenharmony_ci * @min: minimum value of the property 26362306a36Sopenharmony_ci * @max: maximum value of the property 26462306a36Sopenharmony_ci * 26562306a36Sopenharmony_ci * This creates a new generic drm property which can then be attached to a drm 26662306a36Sopenharmony_ci * object with drm_object_attach_property(). The returned property object must 26762306a36Sopenharmony_ci * be freed with drm_property_destroy(), which is done automatically when 26862306a36Sopenharmony_ci * calling drm_mode_config_cleanup(). 26962306a36Sopenharmony_ci * 27062306a36Sopenharmony_ci * Userspace is allowed to set any unsigned integer value in the (min, max) 27162306a36Sopenharmony_ci * range inclusive. 27262306a36Sopenharmony_ci * 27362306a36Sopenharmony_ci * Returns: 27462306a36Sopenharmony_ci * A pointer to the newly created property on success, NULL on failure. 27562306a36Sopenharmony_ci */ 27662306a36Sopenharmony_cistruct drm_property *drm_property_create_range(struct drm_device *dev, 27762306a36Sopenharmony_ci u32 flags, const char *name, 27862306a36Sopenharmony_ci uint64_t min, uint64_t max) 27962306a36Sopenharmony_ci{ 28062306a36Sopenharmony_ci return property_create_range(dev, DRM_MODE_PROP_RANGE | flags, 28162306a36Sopenharmony_ci name, min, max); 28262306a36Sopenharmony_ci} 28362306a36Sopenharmony_ciEXPORT_SYMBOL(drm_property_create_range); 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci/** 28662306a36Sopenharmony_ci * drm_property_create_signed_range - create a new signed ranged property type 28762306a36Sopenharmony_ci * @dev: drm device 28862306a36Sopenharmony_ci * @flags: flags specifying the property type 28962306a36Sopenharmony_ci * @name: name of the property 29062306a36Sopenharmony_ci * @min: minimum value of the property 29162306a36Sopenharmony_ci * @max: maximum value of the property 29262306a36Sopenharmony_ci * 29362306a36Sopenharmony_ci * This creates a new generic drm property which can then be attached to a drm 29462306a36Sopenharmony_ci * object with drm_object_attach_property(). The returned property object must 29562306a36Sopenharmony_ci * be freed with drm_property_destroy(), which is done automatically when 29662306a36Sopenharmony_ci * calling drm_mode_config_cleanup(). 29762306a36Sopenharmony_ci * 29862306a36Sopenharmony_ci * Userspace is allowed to set any signed integer value in the (min, max) 29962306a36Sopenharmony_ci * range inclusive. 30062306a36Sopenharmony_ci * 30162306a36Sopenharmony_ci * Returns: 30262306a36Sopenharmony_ci * A pointer to the newly created property on success, NULL on failure. 30362306a36Sopenharmony_ci */ 30462306a36Sopenharmony_cistruct drm_property *drm_property_create_signed_range(struct drm_device *dev, 30562306a36Sopenharmony_ci u32 flags, const char *name, 30662306a36Sopenharmony_ci int64_t min, int64_t max) 30762306a36Sopenharmony_ci{ 30862306a36Sopenharmony_ci return property_create_range(dev, DRM_MODE_PROP_SIGNED_RANGE | flags, 30962306a36Sopenharmony_ci name, I642U64(min), I642U64(max)); 31062306a36Sopenharmony_ci} 31162306a36Sopenharmony_ciEXPORT_SYMBOL(drm_property_create_signed_range); 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci/** 31462306a36Sopenharmony_ci * drm_property_create_object - create a new object property type 31562306a36Sopenharmony_ci * @dev: drm device 31662306a36Sopenharmony_ci * @flags: flags specifying the property type 31762306a36Sopenharmony_ci * @name: name of the property 31862306a36Sopenharmony_ci * @type: object type from DRM_MODE_OBJECT_* defines 31962306a36Sopenharmony_ci * 32062306a36Sopenharmony_ci * This creates a new generic drm property which can then be attached to a drm 32162306a36Sopenharmony_ci * object with drm_object_attach_property(). The returned property object must 32262306a36Sopenharmony_ci * be freed with drm_property_destroy(), which is done automatically when 32362306a36Sopenharmony_ci * calling drm_mode_config_cleanup(). 32462306a36Sopenharmony_ci * 32562306a36Sopenharmony_ci * Userspace is only allowed to set this to any property value of the given 32662306a36Sopenharmony_ci * @type. Only useful for atomic properties, which is enforced. 32762306a36Sopenharmony_ci * 32862306a36Sopenharmony_ci * Returns: 32962306a36Sopenharmony_ci * A pointer to the newly created property on success, NULL on failure. 33062306a36Sopenharmony_ci */ 33162306a36Sopenharmony_cistruct drm_property *drm_property_create_object(struct drm_device *dev, 33262306a36Sopenharmony_ci u32 flags, const char *name, 33362306a36Sopenharmony_ci uint32_t type) 33462306a36Sopenharmony_ci{ 33562306a36Sopenharmony_ci struct drm_property *property; 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci flags |= DRM_MODE_PROP_OBJECT; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci if (WARN_ON(!(flags & DRM_MODE_PROP_ATOMIC))) 34062306a36Sopenharmony_ci return NULL; 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci property = drm_property_create(dev, flags, name, 1); 34362306a36Sopenharmony_ci if (!property) 34462306a36Sopenharmony_ci return NULL; 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci property->values[0] = type; 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci return property; 34962306a36Sopenharmony_ci} 35062306a36Sopenharmony_ciEXPORT_SYMBOL(drm_property_create_object); 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci/** 35362306a36Sopenharmony_ci * drm_property_create_bool - create a new boolean property type 35462306a36Sopenharmony_ci * @dev: drm device 35562306a36Sopenharmony_ci * @flags: flags specifying the property type 35662306a36Sopenharmony_ci * @name: name of the property 35762306a36Sopenharmony_ci * 35862306a36Sopenharmony_ci * This creates a new generic drm property which can then be attached to a drm 35962306a36Sopenharmony_ci * object with drm_object_attach_property(). The returned property object must 36062306a36Sopenharmony_ci * be freed with drm_property_destroy(), which is done automatically when 36162306a36Sopenharmony_ci * calling drm_mode_config_cleanup(). 36262306a36Sopenharmony_ci * 36362306a36Sopenharmony_ci * This is implemented as a ranged property with only {0, 1} as valid values. 36462306a36Sopenharmony_ci * 36562306a36Sopenharmony_ci * Returns: 36662306a36Sopenharmony_ci * A pointer to the newly created property on success, NULL on failure. 36762306a36Sopenharmony_ci */ 36862306a36Sopenharmony_cistruct drm_property *drm_property_create_bool(struct drm_device *dev, 36962306a36Sopenharmony_ci u32 flags, const char *name) 37062306a36Sopenharmony_ci{ 37162306a36Sopenharmony_ci return drm_property_create_range(dev, flags, name, 0, 1); 37262306a36Sopenharmony_ci} 37362306a36Sopenharmony_ciEXPORT_SYMBOL(drm_property_create_bool); 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci/** 37662306a36Sopenharmony_ci * drm_property_add_enum - add a possible value to an enumeration property 37762306a36Sopenharmony_ci * @property: enumeration property to change 37862306a36Sopenharmony_ci * @value: value of the new enumeration 37962306a36Sopenharmony_ci * @name: symbolic name of the new enumeration 38062306a36Sopenharmony_ci * 38162306a36Sopenharmony_ci * This functions adds enumerations to a property. 38262306a36Sopenharmony_ci * 38362306a36Sopenharmony_ci * It's use is deprecated, drivers should use one of the more specific helpers 38462306a36Sopenharmony_ci * to directly create the property with all enumerations already attached. 38562306a36Sopenharmony_ci * 38662306a36Sopenharmony_ci * Returns: 38762306a36Sopenharmony_ci * Zero on success, error code on failure. 38862306a36Sopenharmony_ci */ 38962306a36Sopenharmony_ciint drm_property_add_enum(struct drm_property *property, 39062306a36Sopenharmony_ci uint64_t value, const char *name) 39162306a36Sopenharmony_ci{ 39262306a36Sopenharmony_ci struct drm_property_enum *prop_enum; 39362306a36Sopenharmony_ci int index = 0; 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci if (WARN_ON(strlen(name) >= DRM_PROP_NAME_LEN)) 39662306a36Sopenharmony_ci return -EINVAL; 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci if (WARN_ON(!drm_property_type_is(property, DRM_MODE_PROP_ENUM) && 39962306a36Sopenharmony_ci !drm_property_type_is(property, DRM_MODE_PROP_BITMASK))) 40062306a36Sopenharmony_ci return -EINVAL; 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci /* 40362306a36Sopenharmony_ci * Bitmask enum properties have the additional constraint of values 40462306a36Sopenharmony_ci * from 0 to 63 40562306a36Sopenharmony_ci */ 40662306a36Sopenharmony_ci if (WARN_ON(drm_property_type_is(property, DRM_MODE_PROP_BITMASK) && 40762306a36Sopenharmony_ci value > 63)) 40862306a36Sopenharmony_ci return -EINVAL; 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci list_for_each_entry(prop_enum, &property->enum_list, head) { 41162306a36Sopenharmony_ci if (WARN_ON(prop_enum->value == value)) 41262306a36Sopenharmony_ci return -EINVAL; 41362306a36Sopenharmony_ci index++; 41462306a36Sopenharmony_ci } 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci if (WARN_ON(index >= property->num_values)) 41762306a36Sopenharmony_ci return -EINVAL; 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci prop_enum = kzalloc(sizeof(struct drm_property_enum), GFP_KERNEL); 42062306a36Sopenharmony_ci if (!prop_enum) 42162306a36Sopenharmony_ci return -ENOMEM; 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci strscpy_pad(prop_enum->name, name, DRM_PROP_NAME_LEN); 42462306a36Sopenharmony_ci prop_enum->value = value; 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci property->values[index] = value; 42762306a36Sopenharmony_ci list_add_tail(&prop_enum->head, &property->enum_list); 42862306a36Sopenharmony_ci return 0; 42962306a36Sopenharmony_ci} 43062306a36Sopenharmony_ciEXPORT_SYMBOL(drm_property_add_enum); 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci/** 43362306a36Sopenharmony_ci * drm_property_destroy - destroy a drm property 43462306a36Sopenharmony_ci * @dev: drm device 43562306a36Sopenharmony_ci * @property: property to destroy 43662306a36Sopenharmony_ci * 43762306a36Sopenharmony_ci * This function frees a property including any attached resources like 43862306a36Sopenharmony_ci * enumeration values. 43962306a36Sopenharmony_ci */ 44062306a36Sopenharmony_civoid drm_property_destroy(struct drm_device *dev, struct drm_property *property) 44162306a36Sopenharmony_ci{ 44262306a36Sopenharmony_ci struct drm_property_enum *prop_enum, *pt; 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci list_for_each_entry_safe(prop_enum, pt, &property->enum_list, head) { 44562306a36Sopenharmony_ci list_del(&prop_enum->head); 44662306a36Sopenharmony_ci kfree(prop_enum); 44762306a36Sopenharmony_ci } 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci if (property->num_values) 45062306a36Sopenharmony_ci kfree(property->values); 45162306a36Sopenharmony_ci drm_mode_object_unregister(dev, &property->base); 45262306a36Sopenharmony_ci list_del(&property->head); 45362306a36Sopenharmony_ci kfree(property); 45462306a36Sopenharmony_ci} 45562306a36Sopenharmony_ciEXPORT_SYMBOL(drm_property_destroy); 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ciint drm_mode_getproperty_ioctl(struct drm_device *dev, 45862306a36Sopenharmony_ci void *data, struct drm_file *file_priv) 45962306a36Sopenharmony_ci{ 46062306a36Sopenharmony_ci struct drm_mode_get_property *out_resp = data; 46162306a36Sopenharmony_ci struct drm_property *property; 46262306a36Sopenharmony_ci int enum_count = 0; 46362306a36Sopenharmony_ci int value_count = 0; 46462306a36Sopenharmony_ci int i, copied; 46562306a36Sopenharmony_ci struct drm_property_enum *prop_enum; 46662306a36Sopenharmony_ci struct drm_mode_property_enum __user *enum_ptr; 46762306a36Sopenharmony_ci uint64_t __user *values_ptr; 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci if (!drm_core_check_feature(dev, DRIVER_MODESET)) 47062306a36Sopenharmony_ci return -EOPNOTSUPP; 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci property = drm_property_find(dev, file_priv, out_resp->prop_id); 47362306a36Sopenharmony_ci if (!property) 47462306a36Sopenharmony_ci return -ENOENT; 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci strscpy_pad(out_resp->name, property->name, DRM_PROP_NAME_LEN); 47762306a36Sopenharmony_ci out_resp->flags = property->flags; 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci value_count = property->num_values; 48062306a36Sopenharmony_ci values_ptr = u64_to_user_ptr(out_resp->values_ptr); 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci for (i = 0; i < value_count; i++) { 48362306a36Sopenharmony_ci if (i < out_resp->count_values && 48462306a36Sopenharmony_ci put_user(property->values[i], values_ptr + i)) { 48562306a36Sopenharmony_ci return -EFAULT; 48662306a36Sopenharmony_ci } 48762306a36Sopenharmony_ci } 48862306a36Sopenharmony_ci out_resp->count_values = value_count; 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci copied = 0; 49162306a36Sopenharmony_ci enum_ptr = u64_to_user_ptr(out_resp->enum_blob_ptr); 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci if (drm_property_type_is(property, DRM_MODE_PROP_ENUM) || 49462306a36Sopenharmony_ci drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) { 49562306a36Sopenharmony_ci list_for_each_entry(prop_enum, &property->enum_list, head) { 49662306a36Sopenharmony_ci enum_count++; 49762306a36Sopenharmony_ci if (out_resp->count_enum_blobs < enum_count) 49862306a36Sopenharmony_ci continue; 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci if (copy_to_user(&enum_ptr[copied].value, 50162306a36Sopenharmony_ci &prop_enum->value, sizeof(uint64_t))) 50262306a36Sopenharmony_ci return -EFAULT; 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci if (copy_to_user(&enum_ptr[copied].name, 50562306a36Sopenharmony_ci &prop_enum->name, DRM_PROP_NAME_LEN)) 50662306a36Sopenharmony_ci return -EFAULT; 50762306a36Sopenharmony_ci copied++; 50862306a36Sopenharmony_ci } 50962306a36Sopenharmony_ci out_resp->count_enum_blobs = enum_count; 51062306a36Sopenharmony_ci } 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci /* 51362306a36Sopenharmony_ci * NOTE: The idea seems to have been to use this to read all the blob 51462306a36Sopenharmony_ci * property values. But nothing ever added them to the corresponding 51562306a36Sopenharmony_ci * list, userspace always used the special-purpose get_blob ioctl to 51662306a36Sopenharmony_ci * read the value for a blob property. It also doesn't make a lot of 51762306a36Sopenharmony_ci * sense to return values here when everything else is just metadata for 51862306a36Sopenharmony_ci * the property itself. 51962306a36Sopenharmony_ci */ 52062306a36Sopenharmony_ci if (drm_property_type_is(property, DRM_MODE_PROP_BLOB)) 52162306a36Sopenharmony_ci out_resp->count_enum_blobs = 0; 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci return 0; 52462306a36Sopenharmony_ci} 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_cistatic void drm_property_free_blob(struct kref *kref) 52762306a36Sopenharmony_ci{ 52862306a36Sopenharmony_ci struct drm_property_blob *blob = 52962306a36Sopenharmony_ci container_of(kref, struct drm_property_blob, base.refcount); 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci mutex_lock(&blob->dev->mode_config.blob_lock); 53262306a36Sopenharmony_ci list_del(&blob->head_global); 53362306a36Sopenharmony_ci mutex_unlock(&blob->dev->mode_config.blob_lock); 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci drm_mode_object_unregister(blob->dev, &blob->base); 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci kvfree(blob); 53862306a36Sopenharmony_ci} 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci/** 54162306a36Sopenharmony_ci * drm_property_create_blob - Create new blob property 54262306a36Sopenharmony_ci * @dev: DRM device to create property for 54362306a36Sopenharmony_ci * @length: Length to allocate for blob data 54462306a36Sopenharmony_ci * @data: If specified, copies data into blob 54562306a36Sopenharmony_ci * 54662306a36Sopenharmony_ci * Creates a new blob property for a specified DRM device, optionally 54762306a36Sopenharmony_ci * copying data. Note that blob properties are meant to be invariant, hence the 54862306a36Sopenharmony_ci * data must be filled out before the blob is used as the value of any property. 54962306a36Sopenharmony_ci * 55062306a36Sopenharmony_ci * Returns: 55162306a36Sopenharmony_ci * New blob property with a single reference on success, or an ERR_PTR 55262306a36Sopenharmony_ci * value on failure. 55362306a36Sopenharmony_ci */ 55462306a36Sopenharmony_cistruct drm_property_blob * 55562306a36Sopenharmony_cidrm_property_create_blob(struct drm_device *dev, size_t length, 55662306a36Sopenharmony_ci const void *data) 55762306a36Sopenharmony_ci{ 55862306a36Sopenharmony_ci struct drm_property_blob *blob; 55962306a36Sopenharmony_ci int ret; 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci if (!length || length > INT_MAX - sizeof(struct drm_property_blob)) 56262306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci blob = kvzalloc(sizeof(struct drm_property_blob)+length, GFP_KERNEL); 56562306a36Sopenharmony_ci if (!blob) 56662306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci /* This must be explicitly initialised, so we can safely call list_del 56962306a36Sopenharmony_ci * on it in the removal handler, even if it isn't in a file list. */ 57062306a36Sopenharmony_ci INIT_LIST_HEAD(&blob->head_file); 57162306a36Sopenharmony_ci blob->data = (void *)blob + sizeof(*blob); 57262306a36Sopenharmony_ci blob->length = length; 57362306a36Sopenharmony_ci blob->dev = dev; 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci if (data) 57662306a36Sopenharmony_ci memcpy(blob->data, data, length); 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci ret = __drm_mode_object_add(dev, &blob->base, DRM_MODE_OBJECT_BLOB, 57962306a36Sopenharmony_ci true, drm_property_free_blob); 58062306a36Sopenharmony_ci if (ret) { 58162306a36Sopenharmony_ci kvfree(blob); 58262306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 58362306a36Sopenharmony_ci } 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci mutex_lock(&dev->mode_config.blob_lock); 58662306a36Sopenharmony_ci list_add_tail(&blob->head_global, 58762306a36Sopenharmony_ci &dev->mode_config.property_blob_list); 58862306a36Sopenharmony_ci mutex_unlock(&dev->mode_config.blob_lock); 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci return blob; 59162306a36Sopenharmony_ci} 59262306a36Sopenharmony_ciEXPORT_SYMBOL(drm_property_create_blob); 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci/** 59562306a36Sopenharmony_ci * drm_property_blob_put - release a blob property reference 59662306a36Sopenharmony_ci * @blob: DRM blob property 59762306a36Sopenharmony_ci * 59862306a36Sopenharmony_ci * Releases a reference to a blob property. May free the object. 59962306a36Sopenharmony_ci */ 60062306a36Sopenharmony_civoid drm_property_blob_put(struct drm_property_blob *blob) 60162306a36Sopenharmony_ci{ 60262306a36Sopenharmony_ci if (!blob) 60362306a36Sopenharmony_ci return; 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci drm_mode_object_put(&blob->base); 60662306a36Sopenharmony_ci} 60762306a36Sopenharmony_ciEXPORT_SYMBOL(drm_property_blob_put); 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_civoid drm_property_destroy_user_blobs(struct drm_device *dev, 61062306a36Sopenharmony_ci struct drm_file *file_priv) 61162306a36Sopenharmony_ci{ 61262306a36Sopenharmony_ci struct drm_property_blob *blob, *bt; 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci /* 61562306a36Sopenharmony_ci * When the file gets released that means no one else can access the 61662306a36Sopenharmony_ci * blob list any more, so no need to grab dev->blob_lock. 61762306a36Sopenharmony_ci */ 61862306a36Sopenharmony_ci list_for_each_entry_safe(blob, bt, &file_priv->blobs, head_file) { 61962306a36Sopenharmony_ci list_del_init(&blob->head_file); 62062306a36Sopenharmony_ci drm_property_blob_put(blob); 62162306a36Sopenharmony_ci } 62262306a36Sopenharmony_ci} 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci/** 62562306a36Sopenharmony_ci * drm_property_blob_get - acquire blob property reference 62662306a36Sopenharmony_ci * @blob: DRM blob property 62762306a36Sopenharmony_ci * 62862306a36Sopenharmony_ci * Acquires a reference to an existing blob property. Returns @blob, which 62962306a36Sopenharmony_ci * allows this to be used as a shorthand in assignments. 63062306a36Sopenharmony_ci */ 63162306a36Sopenharmony_cistruct drm_property_blob *drm_property_blob_get(struct drm_property_blob *blob) 63262306a36Sopenharmony_ci{ 63362306a36Sopenharmony_ci drm_mode_object_get(&blob->base); 63462306a36Sopenharmony_ci return blob; 63562306a36Sopenharmony_ci} 63662306a36Sopenharmony_ciEXPORT_SYMBOL(drm_property_blob_get); 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci/** 63962306a36Sopenharmony_ci * drm_property_lookup_blob - look up a blob property and take a reference 64062306a36Sopenharmony_ci * @dev: drm device 64162306a36Sopenharmony_ci * @id: id of the blob property 64262306a36Sopenharmony_ci * 64362306a36Sopenharmony_ci * If successful, this takes an additional reference to the blob property. 64462306a36Sopenharmony_ci * callers need to make sure to eventually unreferenced the returned property 64562306a36Sopenharmony_ci * again, using drm_property_blob_put(). 64662306a36Sopenharmony_ci * 64762306a36Sopenharmony_ci * Return: 64862306a36Sopenharmony_ci * NULL on failure, pointer to the blob on success. 64962306a36Sopenharmony_ci */ 65062306a36Sopenharmony_cistruct drm_property_blob *drm_property_lookup_blob(struct drm_device *dev, 65162306a36Sopenharmony_ci uint32_t id) 65262306a36Sopenharmony_ci{ 65362306a36Sopenharmony_ci struct drm_mode_object *obj; 65462306a36Sopenharmony_ci struct drm_property_blob *blob = NULL; 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci obj = __drm_mode_object_find(dev, NULL, id, DRM_MODE_OBJECT_BLOB); 65762306a36Sopenharmony_ci if (obj) 65862306a36Sopenharmony_ci blob = obj_to_blob(obj); 65962306a36Sopenharmony_ci return blob; 66062306a36Sopenharmony_ci} 66162306a36Sopenharmony_ciEXPORT_SYMBOL(drm_property_lookup_blob); 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci/** 66462306a36Sopenharmony_ci * drm_property_replace_global_blob - replace existing blob property 66562306a36Sopenharmony_ci * @dev: drm device 66662306a36Sopenharmony_ci * @replace: location of blob property pointer to be replaced 66762306a36Sopenharmony_ci * @length: length of data for new blob, or 0 for no data 66862306a36Sopenharmony_ci * @data: content for new blob, or NULL for no data 66962306a36Sopenharmony_ci * @obj_holds_id: optional object for property holding blob ID 67062306a36Sopenharmony_ci * @prop_holds_id: optional property holding blob ID 67162306a36Sopenharmony_ci * @return 0 on success or error on failure 67262306a36Sopenharmony_ci * 67362306a36Sopenharmony_ci * This function will replace a global property in the blob list, optionally 67462306a36Sopenharmony_ci * updating a property which holds the ID of that property. 67562306a36Sopenharmony_ci * 67662306a36Sopenharmony_ci * If length is 0 or data is NULL, no new blob will be created, and the holding 67762306a36Sopenharmony_ci * property, if specified, will be set to 0. 67862306a36Sopenharmony_ci * 67962306a36Sopenharmony_ci * Access to the replace pointer is assumed to be protected by the caller, e.g. 68062306a36Sopenharmony_ci * by holding the relevant modesetting object lock for its parent. 68162306a36Sopenharmony_ci * 68262306a36Sopenharmony_ci * For example, a drm_connector has a 'PATH' property, which contains the ID 68362306a36Sopenharmony_ci * of a blob property with the value of the MST path information. Calling this 68462306a36Sopenharmony_ci * function with replace pointing to the connector's path_blob_ptr, length and 68562306a36Sopenharmony_ci * data set for the new path information, obj_holds_id set to the connector's 68662306a36Sopenharmony_ci * base object, and prop_holds_id set to the path property name, will perform 68762306a36Sopenharmony_ci * a completely atomic update. The access to path_blob_ptr is protected by the 68862306a36Sopenharmony_ci * caller holding a lock on the connector. 68962306a36Sopenharmony_ci */ 69062306a36Sopenharmony_ciint drm_property_replace_global_blob(struct drm_device *dev, 69162306a36Sopenharmony_ci struct drm_property_blob **replace, 69262306a36Sopenharmony_ci size_t length, 69362306a36Sopenharmony_ci const void *data, 69462306a36Sopenharmony_ci struct drm_mode_object *obj_holds_id, 69562306a36Sopenharmony_ci struct drm_property *prop_holds_id) 69662306a36Sopenharmony_ci{ 69762306a36Sopenharmony_ci struct drm_property_blob *new_blob = NULL; 69862306a36Sopenharmony_ci struct drm_property_blob *old_blob = NULL; 69962306a36Sopenharmony_ci int ret; 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci WARN_ON(replace == NULL); 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci old_blob = *replace; 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci if (length && data) { 70662306a36Sopenharmony_ci new_blob = drm_property_create_blob(dev, length, data); 70762306a36Sopenharmony_ci if (IS_ERR(new_blob)) 70862306a36Sopenharmony_ci return PTR_ERR(new_blob); 70962306a36Sopenharmony_ci } 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci if (obj_holds_id) { 71262306a36Sopenharmony_ci ret = drm_object_property_set_value(obj_holds_id, 71362306a36Sopenharmony_ci prop_holds_id, 71462306a36Sopenharmony_ci new_blob ? 71562306a36Sopenharmony_ci new_blob->base.id : 0); 71662306a36Sopenharmony_ci if (ret != 0) 71762306a36Sopenharmony_ci goto err_created; 71862306a36Sopenharmony_ci } 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci drm_property_blob_put(old_blob); 72162306a36Sopenharmony_ci *replace = new_blob; 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci return 0; 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_cierr_created: 72662306a36Sopenharmony_ci drm_property_blob_put(new_blob); 72762306a36Sopenharmony_ci return ret; 72862306a36Sopenharmony_ci} 72962306a36Sopenharmony_ciEXPORT_SYMBOL(drm_property_replace_global_blob); 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci/** 73262306a36Sopenharmony_ci * drm_property_replace_blob - replace a blob property 73362306a36Sopenharmony_ci * @blob: a pointer to the member blob to be replaced 73462306a36Sopenharmony_ci * @new_blob: the new blob to replace with 73562306a36Sopenharmony_ci * 73662306a36Sopenharmony_ci * Return: true if the blob was in fact replaced. 73762306a36Sopenharmony_ci */ 73862306a36Sopenharmony_cibool drm_property_replace_blob(struct drm_property_blob **blob, 73962306a36Sopenharmony_ci struct drm_property_blob *new_blob) 74062306a36Sopenharmony_ci{ 74162306a36Sopenharmony_ci struct drm_property_blob *old_blob = *blob; 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_ci if (old_blob == new_blob) 74462306a36Sopenharmony_ci return false; 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci drm_property_blob_put(old_blob); 74762306a36Sopenharmony_ci if (new_blob) 74862306a36Sopenharmony_ci drm_property_blob_get(new_blob); 74962306a36Sopenharmony_ci *blob = new_blob; 75062306a36Sopenharmony_ci return true; 75162306a36Sopenharmony_ci} 75262306a36Sopenharmony_ciEXPORT_SYMBOL(drm_property_replace_blob); 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ciint drm_mode_getblob_ioctl(struct drm_device *dev, 75562306a36Sopenharmony_ci void *data, struct drm_file *file_priv) 75662306a36Sopenharmony_ci{ 75762306a36Sopenharmony_ci struct drm_mode_get_blob *out_resp = data; 75862306a36Sopenharmony_ci struct drm_property_blob *blob; 75962306a36Sopenharmony_ci int ret = 0; 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci if (!drm_core_check_feature(dev, DRIVER_MODESET)) 76262306a36Sopenharmony_ci return -EOPNOTSUPP; 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci blob = drm_property_lookup_blob(dev, out_resp->blob_id); 76562306a36Sopenharmony_ci if (!blob) 76662306a36Sopenharmony_ci return -ENOENT; 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci if (out_resp->length == blob->length) { 76962306a36Sopenharmony_ci if (copy_to_user(u64_to_user_ptr(out_resp->data), 77062306a36Sopenharmony_ci blob->data, 77162306a36Sopenharmony_ci blob->length)) { 77262306a36Sopenharmony_ci ret = -EFAULT; 77362306a36Sopenharmony_ci goto unref; 77462306a36Sopenharmony_ci } 77562306a36Sopenharmony_ci } 77662306a36Sopenharmony_ci out_resp->length = blob->length; 77762306a36Sopenharmony_ciunref: 77862306a36Sopenharmony_ci drm_property_blob_put(blob); 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci return ret; 78162306a36Sopenharmony_ci} 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ciint drm_mode_createblob_ioctl(struct drm_device *dev, 78462306a36Sopenharmony_ci void *data, struct drm_file *file_priv) 78562306a36Sopenharmony_ci{ 78662306a36Sopenharmony_ci struct drm_mode_create_blob *out_resp = data; 78762306a36Sopenharmony_ci struct drm_property_blob *blob; 78862306a36Sopenharmony_ci int ret = 0; 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci if (!drm_core_check_feature(dev, DRIVER_MODESET)) 79162306a36Sopenharmony_ci return -EOPNOTSUPP; 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci blob = drm_property_create_blob(dev, out_resp->length, NULL); 79462306a36Sopenharmony_ci if (IS_ERR(blob)) 79562306a36Sopenharmony_ci return PTR_ERR(blob); 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_ci if (copy_from_user(blob->data, 79862306a36Sopenharmony_ci u64_to_user_ptr(out_resp->data), 79962306a36Sopenharmony_ci out_resp->length)) { 80062306a36Sopenharmony_ci ret = -EFAULT; 80162306a36Sopenharmony_ci goto out_blob; 80262306a36Sopenharmony_ci } 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci /* Dropping the lock between create_blob and our access here is safe 80562306a36Sopenharmony_ci * as only the same file_priv can remove the blob; at this point, it is 80662306a36Sopenharmony_ci * not associated with any file_priv. */ 80762306a36Sopenharmony_ci mutex_lock(&dev->mode_config.blob_lock); 80862306a36Sopenharmony_ci out_resp->blob_id = blob->base.id; 80962306a36Sopenharmony_ci list_add_tail(&blob->head_file, &file_priv->blobs); 81062306a36Sopenharmony_ci mutex_unlock(&dev->mode_config.blob_lock); 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci return 0; 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ciout_blob: 81562306a36Sopenharmony_ci drm_property_blob_put(blob); 81662306a36Sopenharmony_ci return ret; 81762306a36Sopenharmony_ci} 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ciint drm_mode_destroyblob_ioctl(struct drm_device *dev, 82062306a36Sopenharmony_ci void *data, struct drm_file *file_priv) 82162306a36Sopenharmony_ci{ 82262306a36Sopenharmony_ci struct drm_mode_destroy_blob *out_resp = data; 82362306a36Sopenharmony_ci struct drm_property_blob *blob = NULL, *bt; 82462306a36Sopenharmony_ci bool found = false; 82562306a36Sopenharmony_ci int ret = 0; 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci if (!drm_core_check_feature(dev, DRIVER_MODESET)) 82862306a36Sopenharmony_ci return -EOPNOTSUPP; 82962306a36Sopenharmony_ci 83062306a36Sopenharmony_ci blob = drm_property_lookup_blob(dev, out_resp->blob_id); 83162306a36Sopenharmony_ci if (!blob) 83262306a36Sopenharmony_ci return -ENOENT; 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ci mutex_lock(&dev->mode_config.blob_lock); 83562306a36Sopenharmony_ci /* Ensure the property was actually created by this user. */ 83662306a36Sopenharmony_ci list_for_each_entry(bt, &file_priv->blobs, head_file) { 83762306a36Sopenharmony_ci if (bt == blob) { 83862306a36Sopenharmony_ci found = true; 83962306a36Sopenharmony_ci break; 84062306a36Sopenharmony_ci } 84162306a36Sopenharmony_ci } 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_ci if (!found) { 84462306a36Sopenharmony_ci ret = -EPERM; 84562306a36Sopenharmony_ci goto err; 84662306a36Sopenharmony_ci } 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_ci /* We must drop head_file here, because we may not be the last 84962306a36Sopenharmony_ci * reference on the blob. */ 85062306a36Sopenharmony_ci list_del_init(&blob->head_file); 85162306a36Sopenharmony_ci mutex_unlock(&dev->mode_config.blob_lock); 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci /* One reference from lookup, and one from the filp. */ 85462306a36Sopenharmony_ci drm_property_blob_put(blob); 85562306a36Sopenharmony_ci drm_property_blob_put(blob); 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ci return 0; 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_cierr: 86062306a36Sopenharmony_ci mutex_unlock(&dev->mode_config.blob_lock); 86162306a36Sopenharmony_ci drm_property_blob_put(blob); 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ci return ret; 86462306a36Sopenharmony_ci} 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_ci/* Some properties could refer to dynamic refcnt'd objects, or things that 86762306a36Sopenharmony_ci * need special locking to handle lifetime issues (ie. to ensure the prop 86862306a36Sopenharmony_ci * value doesn't become invalid part way through the property update due to 86962306a36Sopenharmony_ci * race). The value returned by reference via 'obj' should be passed back 87062306a36Sopenharmony_ci * to drm_property_change_valid_put() after the property is set (and the 87162306a36Sopenharmony_ci * object to which the property is attached has a chance to take its own 87262306a36Sopenharmony_ci * reference). 87362306a36Sopenharmony_ci */ 87462306a36Sopenharmony_cibool drm_property_change_valid_get(struct drm_property *property, 87562306a36Sopenharmony_ci uint64_t value, struct drm_mode_object **ref) 87662306a36Sopenharmony_ci{ 87762306a36Sopenharmony_ci int i; 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_ci if (property->flags & DRM_MODE_PROP_IMMUTABLE) 88062306a36Sopenharmony_ci return false; 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ci *ref = NULL; 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_ci if (drm_property_type_is(property, DRM_MODE_PROP_RANGE)) { 88562306a36Sopenharmony_ci if (value < property->values[0] || value > property->values[1]) 88662306a36Sopenharmony_ci return false; 88762306a36Sopenharmony_ci return true; 88862306a36Sopenharmony_ci } else if (drm_property_type_is(property, DRM_MODE_PROP_SIGNED_RANGE)) { 88962306a36Sopenharmony_ci int64_t svalue = U642I64(value); 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_ci if (svalue < U642I64(property->values[0]) || 89262306a36Sopenharmony_ci svalue > U642I64(property->values[1])) 89362306a36Sopenharmony_ci return false; 89462306a36Sopenharmony_ci return true; 89562306a36Sopenharmony_ci } else if (drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) { 89662306a36Sopenharmony_ci uint64_t valid_mask = 0; 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_ci for (i = 0; i < property->num_values; i++) 89962306a36Sopenharmony_ci valid_mask |= (1ULL << property->values[i]); 90062306a36Sopenharmony_ci return !(value & ~valid_mask); 90162306a36Sopenharmony_ci } else if (drm_property_type_is(property, DRM_MODE_PROP_BLOB)) { 90262306a36Sopenharmony_ci struct drm_property_blob *blob; 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_ci if (value == 0) 90562306a36Sopenharmony_ci return true; 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_ci blob = drm_property_lookup_blob(property->dev, value); 90862306a36Sopenharmony_ci if (blob) { 90962306a36Sopenharmony_ci *ref = &blob->base; 91062306a36Sopenharmony_ci return true; 91162306a36Sopenharmony_ci } else { 91262306a36Sopenharmony_ci return false; 91362306a36Sopenharmony_ci } 91462306a36Sopenharmony_ci } else if (drm_property_type_is(property, DRM_MODE_PROP_OBJECT)) { 91562306a36Sopenharmony_ci /* a zero value for an object property translates to null: */ 91662306a36Sopenharmony_ci if (value == 0) 91762306a36Sopenharmony_ci return true; 91862306a36Sopenharmony_ci 91962306a36Sopenharmony_ci *ref = __drm_mode_object_find(property->dev, NULL, value, 92062306a36Sopenharmony_ci property->values[0]); 92162306a36Sopenharmony_ci return *ref != NULL; 92262306a36Sopenharmony_ci } 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_ci for (i = 0; i < property->num_values; i++) 92562306a36Sopenharmony_ci if (property->values[i] == value) 92662306a36Sopenharmony_ci return true; 92762306a36Sopenharmony_ci return false; 92862306a36Sopenharmony_ci} 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_civoid drm_property_change_valid_put(struct drm_property *property, 93162306a36Sopenharmony_ci struct drm_mode_object *ref) 93262306a36Sopenharmony_ci{ 93362306a36Sopenharmony_ci if (!ref) 93462306a36Sopenharmony_ci return; 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_ci if (drm_property_type_is(property, DRM_MODE_PROP_OBJECT)) { 93762306a36Sopenharmony_ci drm_mode_object_put(ref); 93862306a36Sopenharmony_ci } else if (drm_property_type_is(property, DRM_MODE_PROP_BLOB)) 93962306a36Sopenharmony_ci drm_property_blob_put(obj_to_blob(ref)); 94062306a36Sopenharmony_ci} 941