1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * Copyright (c) 2016 Intel Corporation
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * Permission to use, copy, modify, distribute, and sell this software and its
5*4882a593Smuzhiyun * documentation for any purpose is hereby granted without fee, provided that
6*4882a593Smuzhiyun * the above copyright notice appear in all copies and that both that copyright
7*4882a593Smuzhiyun * notice and this permission notice appear in supporting documentation, and
8*4882a593Smuzhiyun * that the name of the copyright holders not be used in advertising or
9*4882a593Smuzhiyun * publicity pertaining to distribution of the software without specific,
10*4882a593Smuzhiyun * written prior permission. The copyright holders make no representations
11*4882a593Smuzhiyun * about the suitability of this software for any purpose. It is provided "as
12*4882a593Smuzhiyun * is" without express or implied warranty.
13*4882a593Smuzhiyun *
14*4882a593Smuzhiyun * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15*4882a593Smuzhiyun * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16*4882a593Smuzhiyun * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17*4882a593Smuzhiyun * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18*4882a593Smuzhiyun * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19*4882a593Smuzhiyun * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
20*4882a593Smuzhiyun * OF THIS SOFTWARE.
21*4882a593Smuzhiyun */
22*4882a593Smuzhiyun
23*4882a593Smuzhiyun #include <linux/export.h>
24*4882a593Smuzhiyun #include <linux/uaccess.h>
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun #include <drm/drm_crtc.h>
27*4882a593Smuzhiyun #include <drm/drm_drv.h>
28*4882a593Smuzhiyun #include <drm/drm_file.h>
29*4882a593Smuzhiyun #include <drm/drm_framebuffer.h>
30*4882a593Smuzhiyun #include <drm/drm_property.h>
31*4882a593Smuzhiyun
32*4882a593Smuzhiyun #include "drm_crtc_internal.h"
33*4882a593Smuzhiyun
34*4882a593Smuzhiyun /**
35*4882a593Smuzhiyun * DOC: overview
36*4882a593Smuzhiyun *
37*4882a593Smuzhiyun * Properties as represented by &drm_property are used to extend the modeset
38*4882a593Smuzhiyun * interface exposed to userspace. For the atomic modeset IOCTL properties are
39*4882a593Smuzhiyun * even the only way to transport metadata about the desired new modeset
40*4882a593Smuzhiyun * configuration from userspace to the kernel. Properties have a well-defined
41*4882a593Smuzhiyun * value range, which is enforced by the drm core. See the documentation of the
42*4882a593Smuzhiyun * flags member of &struct drm_property for an overview of the different
43*4882a593Smuzhiyun * property types and ranges.
44*4882a593Smuzhiyun *
45*4882a593Smuzhiyun * Properties don't store the current value directly, but need to be
46*4882a593Smuzhiyun * instatiated by attaching them to a &drm_mode_object with
47*4882a593Smuzhiyun * drm_object_attach_property().
48*4882a593Smuzhiyun *
49*4882a593Smuzhiyun * Property values are only 64bit. To support bigger piles of data (like gamma
50*4882a593Smuzhiyun * tables, color correction matrices or large structures) a property can instead
51*4882a593Smuzhiyun * point at a &drm_property_blob with that additional data.
52*4882a593Smuzhiyun *
53*4882a593Smuzhiyun * Properties are defined by their symbolic name, userspace must keep a
54*4882a593Smuzhiyun * per-object mapping from those names to the property ID used in the atomic
55*4882a593Smuzhiyun * IOCTL and in the get/set property IOCTL.
56*4882a593Smuzhiyun */
57*4882a593Smuzhiyun
drm_property_flags_valid(u32 flags)58*4882a593Smuzhiyun static bool drm_property_flags_valid(u32 flags)
59*4882a593Smuzhiyun {
60*4882a593Smuzhiyun u32 legacy_type = flags & DRM_MODE_PROP_LEGACY_TYPE;
61*4882a593Smuzhiyun u32 ext_type = flags & DRM_MODE_PROP_EXTENDED_TYPE;
62*4882a593Smuzhiyun
63*4882a593Smuzhiyun /* Reject undefined/deprecated flags */
64*4882a593Smuzhiyun if (flags & ~(DRM_MODE_PROP_LEGACY_TYPE |
65*4882a593Smuzhiyun DRM_MODE_PROP_EXTENDED_TYPE |
66*4882a593Smuzhiyun DRM_MODE_PROP_IMMUTABLE |
67*4882a593Smuzhiyun DRM_MODE_PROP_ATOMIC))
68*4882a593Smuzhiyun return false;
69*4882a593Smuzhiyun
70*4882a593Smuzhiyun /* We want either a legacy type or an extended type, but not both */
71*4882a593Smuzhiyun if (!legacy_type == !ext_type)
72*4882a593Smuzhiyun return false;
73*4882a593Smuzhiyun
74*4882a593Smuzhiyun /* Only one legacy type at a time please */
75*4882a593Smuzhiyun if (legacy_type && !is_power_of_2(legacy_type))
76*4882a593Smuzhiyun return false;
77*4882a593Smuzhiyun
78*4882a593Smuzhiyun return true;
79*4882a593Smuzhiyun }
80*4882a593Smuzhiyun
81*4882a593Smuzhiyun /**
82*4882a593Smuzhiyun * drm_property_create - create a new property type
83*4882a593Smuzhiyun * @dev: drm device
84*4882a593Smuzhiyun * @flags: flags specifying the property type
85*4882a593Smuzhiyun * @name: name of the property
86*4882a593Smuzhiyun * @num_values: number of pre-defined values
87*4882a593Smuzhiyun *
88*4882a593Smuzhiyun * This creates a new generic drm property which can then be attached to a drm
89*4882a593Smuzhiyun * object with drm_object_attach_property(). The returned property object must
90*4882a593Smuzhiyun * be freed with drm_property_destroy(), which is done automatically when
91*4882a593Smuzhiyun * calling drm_mode_config_cleanup().
92*4882a593Smuzhiyun *
93*4882a593Smuzhiyun * Returns:
94*4882a593Smuzhiyun * A pointer to the newly created property on success, NULL on failure.
95*4882a593Smuzhiyun */
drm_property_create(struct drm_device * dev,u32 flags,const char * name,int num_values)96*4882a593Smuzhiyun struct drm_property *drm_property_create(struct drm_device *dev,
97*4882a593Smuzhiyun u32 flags, const char *name,
98*4882a593Smuzhiyun int num_values)
99*4882a593Smuzhiyun {
100*4882a593Smuzhiyun struct drm_property *property = NULL;
101*4882a593Smuzhiyun int ret;
102*4882a593Smuzhiyun
103*4882a593Smuzhiyun if (WARN_ON(!drm_property_flags_valid(flags)))
104*4882a593Smuzhiyun return NULL;
105*4882a593Smuzhiyun
106*4882a593Smuzhiyun if (WARN_ON(strlen(name) >= DRM_PROP_NAME_LEN))
107*4882a593Smuzhiyun return NULL;
108*4882a593Smuzhiyun
109*4882a593Smuzhiyun property = kzalloc(sizeof(struct drm_property), GFP_KERNEL);
110*4882a593Smuzhiyun if (!property)
111*4882a593Smuzhiyun return NULL;
112*4882a593Smuzhiyun
113*4882a593Smuzhiyun property->dev = dev;
114*4882a593Smuzhiyun
115*4882a593Smuzhiyun if (num_values) {
116*4882a593Smuzhiyun property->values = kcalloc(num_values, sizeof(uint64_t),
117*4882a593Smuzhiyun GFP_KERNEL);
118*4882a593Smuzhiyun if (!property->values)
119*4882a593Smuzhiyun goto fail;
120*4882a593Smuzhiyun }
121*4882a593Smuzhiyun
122*4882a593Smuzhiyun ret = drm_mode_object_add(dev, &property->base, DRM_MODE_OBJECT_PROPERTY);
123*4882a593Smuzhiyun if (ret)
124*4882a593Smuzhiyun goto fail;
125*4882a593Smuzhiyun
126*4882a593Smuzhiyun property->flags = flags;
127*4882a593Smuzhiyun property->num_values = num_values;
128*4882a593Smuzhiyun INIT_LIST_HEAD(&property->enum_list);
129*4882a593Smuzhiyun
130*4882a593Smuzhiyun strncpy(property->name, name, DRM_PROP_NAME_LEN);
131*4882a593Smuzhiyun property->name[DRM_PROP_NAME_LEN-1] = '\0';
132*4882a593Smuzhiyun
133*4882a593Smuzhiyun list_add_tail(&property->head, &dev->mode_config.property_list);
134*4882a593Smuzhiyun
135*4882a593Smuzhiyun return property;
136*4882a593Smuzhiyun fail:
137*4882a593Smuzhiyun kfree(property->values);
138*4882a593Smuzhiyun kfree(property);
139*4882a593Smuzhiyun return NULL;
140*4882a593Smuzhiyun }
141*4882a593Smuzhiyun EXPORT_SYMBOL(drm_property_create);
142*4882a593Smuzhiyun
143*4882a593Smuzhiyun /**
144*4882a593Smuzhiyun * drm_property_create_enum - create a new enumeration property type
145*4882a593Smuzhiyun * @dev: drm device
146*4882a593Smuzhiyun * @flags: flags specifying the property type
147*4882a593Smuzhiyun * @name: name of the property
148*4882a593Smuzhiyun * @props: enumeration lists with property values
149*4882a593Smuzhiyun * @num_values: number of pre-defined values
150*4882a593Smuzhiyun *
151*4882a593Smuzhiyun * This creates a new generic drm property which can then be attached to a drm
152*4882a593Smuzhiyun * object with drm_object_attach_property(). The returned property object must
153*4882a593Smuzhiyun * be freed with drm_property_destroy(), which is done automatically when
154*4882a593Smuzhiyun * calling drm_mode_config_cleanup().
155*4882a593Smuzhiyun *
156*4882a593Smuzhiyun * Userspace is only allowed to set one of the predefined values for enumeration
157*4882a593Smuzhiyun * properties.
158*4882a593Smuzhiyun *
159*4882a593Smuzhiyun * Returns:
160*4882a593Smuzhiyun * A pointer to the newly created property on success, NULL on failure.
161*4882a593Smuzhiyun */
drm_property_create_enum(struct drm_device * dev,u32 flags,const char * name,const struct drm_prop_enum_list * props,int num_values)162*4882a593Smuzhiyun struct drm_property *drm_property_create_enum(struct drm_device *dev,
163*4882a593Smuzhiyun u32 flags, const char *name,
164*4882a593Smuzhiyun const struct drm_prop_enum_list *props,
165*4882a593Smuzhiyun int num_values)
166*4882a593Smuzhiyun {
167*4882a593Smuzhiyun struct drm_property *property;
168*4882a593Smuzhiyun int i, ret;
169*4882a593Smuzhiyun
170*4882a593Smuzhiyun flags |= DRM_MODE_PROP_ENUM;
171*4882a593Smuzhiyun
172*4882a593Smuzhiyun property = drm_property_create(dev, flags, name, num_values);
173*4882a593Smuzhiyun if (!property)
174*4882a593Smuzhiyun return NULL;
175*4882a593Smuzhiyun
176*4882a593Smuzhiyun for (i = 0; i < num_values; i++) {
177*4882a593Smuzhiyun ret = drm_property_add_enum(property,
178*4882a593Smuzhiyun props[i].type,
179*4882a593Smuzhiyun props[i].name);
180*4882a593Smuzhiyun if (ret) {
181*4882a593Smuzhiyun drm_property_destroy(dev, property);
182*4882a593Smuzhiyun return NULL;
183*4882a593Smuzhiyun }
184*4882a593Smuzhiyun }
185*4882a593Smuzhiyun
186*4882a593Smuzhiyun return property;
187*4882a593Smuzhiyun }
188*4882a593Smuzhiyun EXPORT_SYMBOL(drm_property_create_enum);
189*4882a593Smuzhiyun
190*4882a593Smuzhiyun /**
191*4882a593Smuzhiyun * drm_property_create_bitmask - create a new bitmask property type
192*4882a593Smuzhiyun * @dev: drm device
193*4882a593Smuzhiyun * @flags: flags specifying the property type
194*4882a593Smuzhiyun * @name: name of the property
195*4882a593Smuzhiyun * @props: enumeration lists with property bitflags
196*4882a593Smuzhiyun * @num_props: size of the @props array
197*4882a593Smuzhiyun * @supported_bits: bitmask of all supported enumeration values
198*4882a593Smuzhiyun *
199*4882a593Smuzhiyun * This creates a new bitmask drm property which can then be attached to a drm
200*4882a593Smuzhiyun * object with drm_object_attach_property(). The returned property object must
201*4882a593Smuzhiyun * be freed with drm_property_destroy(), which is done automatically when
202*4882a593Smuzhiyun * calling drm_mode_config_cleanup().
203*4882a593Smuzhiyun *
204*4882a593Smuzhiyun * Compared to plain enumeration properties userspace is allowed to set any
205*4882a593Smuzhiyun * or'ed together combination of the predefined property bitflag values
206*4882a593Smuzhiyun *
207*4882a593Smuzhiyun * Returns:
208*4882a593Smuzhiyun * A pointer to the newly created property on success, NULL on failure.
209*4882a593Smuzhiyun */
drm_property_create_bitmask(struct drm_device * dev,u32 flags,const char * name,const struct drm_prop_enum_list * props,int num_props,uint64_t supported_bits)210*4882a593Smuzhiyun struct drm_property *drm_property_create_bitmask(struct drm_device *dev,
211*4882a593Smuzhiyun u32 flags, const char *name,
212*4882a593Smuzhiyun const struct drm_prop_enum_list *props,
213*4882a593Smuzhiyun int num_props,
214*4882a593Smuzhiyun uint64_t supported_bits)
215*4882a593Smuzhiyun {
216*4882a593Smuzhiyun struct drm_property *property;
217*4882a593Smuzhiyun int i, ret;
218*4882a593Smuzhiyun int num_values = hweight64(supported_bits);
219*4882a593Smuzhiyun
220*4882a593Smuzhiyun flags |= DRM_MODE_PROP_BITMASK;
221*4882a593Smuzhiyun
222*4882a593Smuzhiyun property = drm_property_create(dev, flags, name, num_values);
223*4882a593Smuzhiyun if (!property)
224*4882a593Smuzhiyun return NULL;
225*4882a593Smuzhiyun for (i = 0; i < num_props; i++) {
226*4882a593Smuzhiyun if (!(supported_bits & (1ULL << props[i].type)))
227*4882a593Smuzhiyun continue;
228*4882a593Smuzhiyun
229*4882a593Smuzhiyun ret = drm_property_add_enum(property,
230*4882a593Smuzhiyun props[i].type,
231*4882a593Smuzhiyun props[i].name);
232*4882a593Smuzhiyun if (ret) {
233*4882a593Smuzhiyun drm_property_destroy(dev, property);
234*4882a593Smuzhiyun return NULL;
235*4882a593Smuzhiyun }
236*4882a593Smuzhiyun }
237*4882a593Smuzhiyun
238*4882a593Smuzhiyun return property;
239*4882a593Smuzhiyun }
240*4882a593Smuzhiyun EXPORT_SYMBOL(drm_property_create_bitmask);
241*4882a593Smuzhiyun
property_create_range(struct drm_device * dev,u32 flags,const char * name,uint64_t min,uint64_t max)242*4882a593Smuzhiyun static struct drm_property *property_create_range(struct drm_device *dev,
243*4882a593Smuzhiyun u32 flags, const char *name,
244*4882a593Smuzhiyun uint64_t min, uint64_t max)
245*4882a593Smuzhiyun {
246*4882a593Smuzhiyun struct drm_property *property;
247*4882a593Smuzhiyun
248*4882a593Smuzhiyun property = drm_property_create(dev, flags, name, 2);
249*4882a593Smuzhiyun if (!property)
250*4882a593Smuzhiyun return NULL;
251*4882a593Smuzhiyun
252*4882a593Smuzhiyun property->values[0] = min;
253*4882a593Smuzhiyun property->values[1] = max;
254*4882a593Smuzhiyun
255*4882a593Smuzhiyun return property;
256*4882a593Smuzhiyun }
257*4882a593Smuzhiyun
258*4882a593Smuzhiyun /**
259*4882a593Smuzhiyun * drm_property_create_range - create a new unsigned ranged property type
260*4882a593Smuzhiyun * @dev: drm device
261*4882a593Smuzhiyun * @flags: flags specifying the property type
262*4882a593Smuzhiyun * @name: name of the property
263*4882a593Smuzhiyun * @min: minimum value of the property
264*4882a593Smuzhiyun * @max: maximum value of the property
265*4882a593Smuzhiyun *
266*4882a593Smuzhiyun * This creates a new generic drm property which can then be attached to a drm
267*4882a593Smuzhiyun * object with drm_object_attach_property(). The returned property object must
268*4882a593Smuzhiyun * be freed with drm_property_destroy(), which is done automatically when
269*4882a593Smuzhiyun * calling drm_mode_config_cleanup().
270*4882a593Smuzhiyun *
271*4882a593Smuzhiyun * Userspace is allowed to set any unsigned integer value in the (min, max)
272*4882a593Smuzhiyun * range inclusive.
273*4882a593Smuzhiyun *
274*4882a593Smuzhiyun * Returns:
275*4882a593Smuzhiyun * A pointer to the newly created property on success, NULL on failure.
276*4882a593Smuzhiyun */
drm_property_create_range(struct drm_device * dev,u32 flags,const char * name,uint64_t min,uint64_t max)277*4882a593Smuzhiyun struct drm_property *drm_property_create_range(struct drm_device *dev,
278*4882a593Smuzhiyun u32 flags, const char *name,
279*4882a593Smuzhiyun uint64_t min, uint64_t max)
280*4882a593Smuzhiyun {
281*4882a593Smuzhiyun return property_create_range(dev, DRM_MODE_PROP_RANGE | flags,
282*4882a593Smuzhiyun name, min, max);
283*4882a593Smuzhiyun }
284*4882a593Smuzhiyun EXPORT_SYMBOL(drm_property_create_range);
285*4882a593Smuzhiyun
286*4882a593Smuzhiyun /**
287*4882a593Smuzhiyun * drm_property_create_signed_range - create a new signed ranged property type
288*4882a593Smuzhiyun * @dev: drm device
289*4882a593Smuzhiyun * @flags: flags specifying the property type
290*4882a593Smuzhiyun * @name: name of the property
291*4882a593Smuzhiyun * @min: minimum value of the property
292*4882a593Smuzhiyun * @max: maximum value of the property
293*4882a593Smuzhiyun *
294*4882a593Smuzhiyun * This creates a new generic drm property which can then be attached to a drm
295*4882a593Smuzhiyun * object with drm_object_attach_property(). The returned property object must
296*4882a593Smuzhiyun * be freed with drm_property_destroy(), which is done automatically when
297*4882a593Smuzhiyun * calling drm_mode_config_cleanup().
298*4882a593Smuzhiyun *
299*4882a593Smuzhiyun * Userspace is allowed to set any signed integer value in the (min, max)
300*4882a593Smuzhiyun * range inclusive.
301*4882a593Smuzhiyun *
302*4882a593Smuzhiyun * Returns:
303*4882a593Smuzhiyun * A pointer to the newly created property on success, NULL on failure.
304*4882a593Smuzhiyun */
drm_property_create_signed_range(struct drm_device * dev,u32 flags,const char * name,int64_t min,int64_t max)305*4882a593Smuzhiyun struct drm_property *drm_property_create_signed_range(struct drm_device *dev,
306*4882a593Smuzhiyun u32 flags, const char *name,
307*4882a593Smuzhiyun int64_t min, int64_t max)
308*4882a593Smuzhiyun {
309*4882a593Smuzhiyun return property_create_range(dev, DRM_MODE_PROP_SIGNED_RANGE | flags,
310*4882a593Smuzhiyun name, I642U64(min), I642U64(max));
311*4882a593Smuzhiyun }
312*4882a593Smuzhiyun EXPORT_SYMBOL(drm_property_create_signed_range);
313*4882a593Smuzhiyun
314*4882a593Smuzhiyun /**
315*4882a593Smuzhiyun * drm_property_create_object - create a new object property type
316*4882a593Smuzhiyun * @dev: drm device
317*4882a593Smuzhiyun * @flags: flags specifying the property type
318*4882a593Smuzhiyun * @name: name of the property
319*4882a593Smuzhiyun * @type: object type from DRM_MODE_OBJECT_* defines
320*4882a593Smuzhiyun *
321*4882a593Smuzhiyun * This creates a new generic drm property which can then be attached to a drm
322*4882a593Smuzhiyun * object with drm_object_attach_property(). The returned property object must
323*4882a593Smuzhiyun * be freed with drm_property_destroy(), which is done automatically when
324*4882a593Smuzhiyun * calling drm_mode_config_cleanup().
325*4882a593Smuzhiyun *
326*4882a593Smuzhiyun * Userspace is only allowed to set this to any property value of the given
327*4882a593Smuzhiyun * @type. Only useful for atomic properties, which is enforced.
328*4882a593Smuzhiyun *
329*4882a593Smuzhiyun * Returns:
330*4882a593Smuzhiyun * A pointer to the newly created property on success, NULL on failure.
331*4882a593Smuzhiyun */
drm_property_create_object(struct drm_device * dev,u32 flags,const char * name,uint32_t type)332*4882a593Smuzhiyun struct drm_property *drm_property_create_object(struct drm_device *dev,
333*4882a593Smuzhiyun u32 flags, const char *name,
334*4882a593Smuzhiyun uint32_t type)
335*4882a593Smuzhiyun {
336*4882a593Smuzhiyun struct drm_property *property;
337*4882a593Smuzhiyun
338*4882a593Smuzhiyun flags |= DRM_MODE_PROP_OBJECT;
339*4882a593Smuzhiyun
340*4882a593Smuzhiyun if (WARN_ON(!(flags & DRM_MODE_PROP_ATOMIC)))
341*4882a593Smuzhiyun return NULL;
342*4882a593Smuzhiyun
343*4882a593Smuzhiyun property = drm_property_create(dev, flags, name, 1);
344*4882a593Smuzhiyun if (!property)
345*4882a593Smuzhiyun return NULL;
346*4882a593Smuzhiyun
347*4882a593Smuzhiyun property->values[0] = type;
348*4882a593Smuzhiyun
349*4882a593Smuzhiyun return property;
350*4882a593Smuzhiyun }
351*4882a593Smuzhiyun EXPORT_SYMBOL(drm_property_create_object);
352*4882a593Smuzhiyun
353*4882a593Smuzhiyun /**
354*4882a593Smuzhiyun * drm_property_create_bool - create a new boolean property type
355*4882a593Smuzhiyun * @dev: drm device
356*4882a593Smuzhiyun * @flags: flags specifying the property type
357*4882a593Smuzhiyun * @name: name of the property
358*4882a593Smuzhiyun *
359*4882a593Smuzhiyun * This creates a new generic drm property which can then be attached to a drm
360*4882a593Smuzhiyun * object with drm_object_attach_property(). The returned property object must
361*4882a593Smuzhiyun * be freed with drm_property_destroy(), which is done automatically when
362*4882a593Smuzhiyun * calling drm_mode_config_cleanup().
363*4882a593Smuzhiyun *
364*4882a593Smuzhiyun * This is implemented as a ranged property with only {0, 1} as valid values.
365*4882a593Smuzhiyun *
366*4882a593Smuzhiyun * Returns:
367*4882a593Smuzhiyun * A pointer to the newly created property on success, NULL on failure.
368*4882a593Smuzhiyun */
drm_property_create_bool(struct drm_device * dev,u32 flags,const char * name)369*4882a593Smuzhiyun struct drm_property *drm_property_create_bool(struct drm_device *dev,
370*4882a593Smuzhiyun u32 flags, const char *name)
371*4882a593Smuzhiyun {
372*4882a593Smuzhiyun return drm_property_create_range(dev, flags, name, 0, 1);
373*4882a593Smuzhiyun }
374*4882a593Smuzhiyun EXPORT_SYMBOL(drm_property_create_bool);
375*4882a593Smuzhiyun
376*4882a593Smuzhiyun /**
377*4882a593Smuzhiyun * drm_property_add_enum - add a possible value to an enumeration property
378*4882a593Smuzhiyun * @property: enumeration property to change
379*4882a593Smuzhiyun * @value: value of the new enumeration
380*4882a593Smuzhiyun * @name: symbolic name of the new enumeration
381*4882a593Smuzhiyun *
382*4882a593Smuzhiyun * This functions adds enumerations to a property.
383*4882a593Smuzhiyun *
384*4882a593Smuzhiyun * It's use is deprecated, drivers should use one of the more specific helpers
385*4882a593Smuzhiyun * to directly create the property with all enumerations already attached.
386*4882a593Smuzhiyun *
387*4882a593Smuzhiyun * Returns:
388*4882a593Smuzhiyun * Zero on success, error code on failure.
389*4882a593Smuzhiyun */
drm_property_add_enum(struct drm_property * property,uint64_t value,const char * name)390*4882a593Smuzhiyun int drm_property_add_enum(struct drm_property *property,
391*4882a593Smuzhiyun uint64_t value, const char *name)
392*4882a593Smuzhiyun {
393*4882a593Smuzhiyun struct drm_property_enum *prop_enum;
394*4882a593Smuzhiyun int index = 0;
395*4882a593Smuzhiyun
396*4882a593Smuzhiyun if (WARN_ON(strlen(name) >= DRM_PROP_NAME_LEN))
397*4882a593Smuzhiyun return -EINVAL;
398*4882a593Smuzhiyun
399*4882a593Smuzhiyun if (WARN_ON(!drm_property_type_is(property, DRM_MODE_PROP_ENUM) &&
400*4882a593Smuzhiyun !drm_property_type_is(property, DRM_MODE_PROP_BITMASK)))
401*4882a593Smuzhiyun return -EINVAL;
402*4882a593Smuzhiyun
403*4882a593Smuzhiyun /*
404*4882a593Smuzhiyun * Bitmask enum properties have the additional constraint of values
405*4882a593Smuzhiyun * from 0 to 63
406*4882a593Smuzhiyun */
407*4882a593Smuzhiyun if (WARN_ON(drm_property_type_is(property, DRM_MODE_PROP_BITMASK) &&
408*4882a593Smuzhiyun value > 63))
409*4882a593Smuzhiyun return -EINVAL;
410*4882a593Smuzhiyun
411*4882a593Smuzhiyun list_for_each_entry(prop_enum, &property->enum_list, head) {
412*4882a593Smuzhiyun if (WARN_ON(prop_enum->value == value))
413*4882a593Smuzhiyun return -EINVAL;
414*4882a593Smuzhiyun index++;
415*4882a593Smuzhiyun }
416*4882a593Smuzhiyun
417*4882a593Smuzhiyun if (WARN_ON(index >= property->num_values))
418*4882a593Smuzhiyun return -EINVAL;
419*4882a593Smuzhiyun
420*4882a593Smuzhiyun prop_enum = kzalloc(sizeof(struct drm_property_enum), GFP_KERNEL);
421*4882a593Smuzhiyun if (!prop_enum)
422*4882a593Smuzhiyun return -ENOMEM;
423*4882a593Smuzhiyun
424*4882a593Smuzhiyun strncpy(prop_enum->name, name, DRM_PROP_NAME_LEN);
425*4882a593Smuzhiyun prop_enum->name[DRM_PROP_NAME_LEN-1] = '\0';
426*4882a593Smuzhiyun prop_enum->value = value;
427*4882a593Smuzhiyun
428*4882a593Smuzhiyun property->values[index] = value;
429*4882a593Smuzhiyun list_add_tail(&prop_enum->head, &property->enum_list);
430*4882a593Smuzhiyun return 0;
431*4882a593Smuzhiyun }
432*4882a593Smuzhiyun EXPORT_SYMBOL(drm_property_add_enum);
433*4882a593Smuzhiyun
434*4882a593Smuzhiyun /**
435*4882a593Smuzhiyun * drm_property_destroy - destroy a drm property
436*4882a593Smuzhiyun * @dev: drm device
437*4882a593Smuzhiyun * @property: property to destry
438*4882a593Smuzhiyun *
439*4882a593Smuzhiyun * This function frees a property including any attached resources like
440*4882a593Smuzhiyun * enumeration values.
441*4882a593Smuzhiyun */
drm_property_destroy(struct drm_device * dev,struct drm_property * property)442*4882a593Smuzhiyun void drm_property_destroy(struct drm_device *dev, struct drm_property *property)
443*4882a593Smuzhiyun {
444*4882a593Smuzhiyun struct drm_property_enum *prop_enum, *pt;
445*4882a593Smuzhiyun
446*4882a593Smuzhiyun list_for_each_entry_safe(prop_enum, pt, &property->enum_list, head) {
447*4882a593Smuzhiyun list_del(&prop_enum->head);
448*4882a593Smuzhiyun kfree(prop_enum);
449*4882a593Smuzhiyun }
450*4882a593Smuzhiyun
451*4882a593Smuzhiyun if (property->num_values)
452*4882a593Smuzhiyun kfree(property->values);
453*4882a593Smuzhiyun drm_mode_object_unregister(dev, &property->base);
454*4882a593Smuzhiyun list_del(&property->head);
455*4882a593Smuzhiyun kfree(property);
456*4882a593Smuzhiyun }
457*4882a593Smuzhiyun EXPORT_SYMBOL(drm_property_destroy);
458*4882a593Smuzhiyun
drm_mode_getproperty_ioctl(struct drm_device * dev,void * data,struct drm_file * file_priv)459*4882a593Smuzhiyun int drm_mode_getproperty_ioctl(struct drm_device *dev,
460*4882a593Smuzhiyun void *data, struct drm_file *file_priv)
461*4882a593Smuzhiyun {
462*4882a593Smuzhiyun struct drm_mode_get_property *out_resp = data;
463*4882a593Smuzhiyun struct drm_property *property;
464*4882a593Smuzhiyun int enum_count = 0;
465*4882a593Smuzhiyun int value_count = 0;
466*4882a593Smuzhiyun int i, copied;
467*4882a593Smuzhiyun struct drm_property_enum *prop_enum;
468*4882a593Smuzhiyun struct drm_mode_property_enum __user *enum_ptr;
469*4882a593Smuzhiyun uint64_t __user *values_ptr;
470*4882a593Smuzhiyun
471*4882a593Smuzhiyun if (!drm_core_check_feature(dev, DRIVER_MODESET))
472*4882a593Smuzhiyun return -EOPNOTSUPP;
473*4882a593Smuzhiyun
474*4882a593Smuzhiyun property = drm_property_find(dev, file_priv, out_resp->prop_id);
475*4882a593Smuzhiyun if (!property)
476*4882a593Smuzhiyun return -ENOENT;
477*4882a593Smuzhiyun
478*4882a593Smuzhiyun strncpy(out_resp->name, property->name, DRM_PROP_NAME_LEN);
479*4882a593Smuzhiyun out_resp->name[DRM_PROP_NAME_LEN-1] = 0;
480*4882a593Smuzhiyun out_resp->flags = property->flags;
481*4882a593Smuzhiyun
482*4882a593Smuzhiyun value_count = property->num_values;
483*4882a593Smuzhiyun values_ptr = u64_to_user_ptr(out_resp->values_ptr);
484*4882a593Smuzhiyun
485*4882a593Smuzhiyun for (i = 0; i < value_count; i++) {
486*4882a593Smuzhiyun if (i < out_resp->count_values &&
487*4882a593Smuzhiyun put_user(property->values[i], values_ptr + i)) {
488*4882a593Smuzhiyun return -EFAULT;
489*4882a593Smuzhiyun }
490*4882a593Smuzhiyun }
491*4882a593Smuzhiyun out_resp->count_values = value_count;
492*4882a593Smuzhiyun
493*4882a593Smuzhiyun copied = 0;
494*4882a593Smuzhiyun enum_ptr = u64_to_user_ptr(out_resp->enum_blob_ptr);
495*4882a593Smuzhiyun
496*4882a593Smuzhiyun if (drm_property_type_is(property, DRM_MODE_PROP_ENUM) ||
497*4882a593Smuzhiyun drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) {
498*4882a593Smuzhiyun list_for_each_entry(prop_enum, &property->enum_list, head) {
499*4882a593Smuzhiyun enum_count++;
500*4882a593Smuzhiyun if (out_resp->count_enum_blobs < enum_count)
501*4882a593Smuzhiyun continue;
502*4882a593Smuzhiyun
503*4882a593Smuzhiyun if (copy_to_user(&enum_ptr[copied].value,
504*4882a593Smuzhiyun &prop_enum->value, sizeof(uint64_t)))
505*4882a593Smuzhiyun return -EFAULT;
506*4882a593Smuzhiyun
507*4882a593Smuzhiyun if (copy_to_user(&enum_ptr[copied].name,
508*4882a593Smuzhiyun &prop_enum->name, DRM_PROP_NAME_LEN))
509*4882a593Smuzhiyun return -EFAULT;
510*4882a593Smuzhiyun copied++;
511*4882a593Smuzhiyun }
512*4882a593Smuzhiyun out_resp->count_enum_blobs = enum_count;
513*4882a593Smuzhiyun }
514*4882a593Smuzhiyun
515*4882a593Smuzhiyun /*
516*4882a593Smuzhiyun * NOTE: The idea seems to have been to use this to read all the blob
517*4882a593Smuzhiyun * property values. But nothing ever added them to the corresponding
518*4882a593Smuzhiyun * list, userspace always used the special-purpose get_blob ioctl to
519*4882a593Smuzhiyun * read the value for a blob property. It also doesn't make a lot of
520*4882a593Smuzhiyun * sense to return values here when everything else is just metadata for
521*4882a593Smuzhiyun * the property itself.
522*4882a593Smuzhiyun */
523*4882a593Smuzhiyun if (drm_property_type_is(property, DRM_MODE_PROP_BLOB))
524*4882a593Smuzhiyun out_resp->count_enum_blobs = 0;
525*4882a593Smuzhiyun
526*4882a593Smuzhiyun return 0;
527*4882a593Smuzhiyun }
528*4882a593Smuzhiyun
drm_property_free_blob(struct kref * kref)529*4882a593Smuzhiyun static void drm_property_free_blob(struct kref *kref)
530*4882a593Smuzhiyun {
531*4882a593Smuzhiyun struct drm_property_blob *blob =
532*4882a593Smuzhiyun container_of(kref, struct drm_property_blob, base.refcount);
533*4882a593Smuzhiyun
534*4882a593Smuzhiyun mutex_lock(&blob->dev->mode_config.blob_lock);
535*4882a593Smuzhiyun list_del(&blob->head_global);
536*4882a593Smuzhiyun mutex_unlock(&blob->dev->mode_config.blob_lock);
537*4882a593Smuzhiyun
538*4882a593Smuzhiyun drm_mode_object_unregister(blob->dev, &blob->base);
539*4882a593Smuzhiyun
540*4882a593Smuzhiyun kvfree(blob);
541*4882a593Smuzhiyun }
542*4882a593Smuzhiyun
543*4882a593Smuzhiyun /**
544*4882a593Smuzhiyun * drm_property_create_blob - Create new blob property
545*4882a593Smuzhiyun * @dev: DRM device to create property for
546*4882a593Smuzhiyun * @length: Length to allocate for blob data
547*4882a593Smuzhiyun * @data: If specified, copies data into blob
548*4882a593Smuzhiyun *
549*4882a593Smuzhiyun * Creates a new blob property for a specified DRM device, optionally
550*4882a593Smuzhiyun * copying data. Note that blob properties are meant to be invariant, hence the
551*4882a593Smuzhiyun * data must be filled out before the blob is used as the value of any property.
552*4882a593Smuzhiyun *
553*4882a593Smuzhiyun * Returns:
554*4882a593Smuzhiyun * New blob property with a single reference on success, or an ERR_PTR
555*4882a593Smuzhiyun * value on failure.
556*4882a593Smuzhiyun */
557*4882a593Smuzhiyun struct drm_property_blob *
drm_property_create_blob(struct drm_device * dev,size_t length,const void * data)558*4882a593Smuzhiyun drm_property_create_blob(struct drm_device *dev, size_t length,
559*4882a593Smuzhiyun const void *data)
560*4882a593Smuzhiyun {
561*4882a593Smuzhiyun struct drm_property_blob *blob;
562*4882a593Smuzhiyun int ret;
563*4882a593Smuzhiyun
564*4882a593Smuzhiyun if (!length || length > INT_MAX - sizeof(struct drm_property_blob))
565*4882a593Smuzhiyun return ERR_PTR(-EINVAL);
566*4882a593Smuzhiyun
567*4882a593Smuzhiyun blob = kvzalloc(sizeof(struct drm_property_blob)+length, GFP_KERNEL);
568*4882a593Smuzhiyun if (!blob)
569*4882a593Smuzhiyun return ERR_PTR(-ENOMEM);
570*4882a593Smuzhiyun
571*4882a593Smuzhiyun /* This must be explicitly initialised, so we can safely call list_del
572*4882a593Smuzhiyun * on it in the removal handler, even if it isn't in a file list. */
573*4882a593Smuzhiyun INIT_LIST_HEAD(&blob->head_file);
574*4882a593Smuzhiyun blob->data = (void *)blob + sizeof(*blob);
575*4882a593Smuzhiyun blob->length = length;
576*4882a593Smuzhiyun blob->dev = dev;
577*4882a593Smuzhiyun
578*4882a593Smuzhiyun if (data)
579*4882a593Smuzhiyun memcpy(blob->data, data, length);
580*4882a593Smuzhiyun
581*4882a593Smuzhiyun ret = __drm_mode_object_add(dev, &blob->base, DRM_MODE_OBJECT_BLOB,
582*4882a593Smuzhiyun true, drm_property_free_blob);
583*4882a593Smuzhiyun if (ret) {
584*4882a593Smuzhiyun kvfree(blob);
585*4882a593Smuzhiyun return ERR_PTR(-EINVAL);
586*4882a593Smuzhiyun }
587*4882a593Smuzhiyun
588*4882a593Smuzhiyun mutex_lock(&dev->mode_config.blob_lock);
589*4882a593Smuzhiyun list_add_tail(&blob->head_global,
590*4882a593Smuzhiyun &dev->mode_config.property_blob_list);
591*4882a593Smuzhiyun mutex_unlock(&dev->mode_config.blob_lock);
592*4882a593Smuzhiyun
593*4882a593Smuzhiyun return blob;
594*4882a593Smuzhiyun }
595*4882a593Smuzhiyun EXPORT_SYMBOL(drm_property_create_blob);
596*4882a593Smuzhiyun
597*4882a593Smuzhiyun /**
598*4882a593Smuzhiyun * drm_property_blob_put - release a blob property reference
599*4882a593Smuzhiyun * @blob: DRM blob property
600*4882a593Smuzhiyun *
601*4882a593Smuzhiyun * Releases a reference to a blob property. May free the object.
602*4882a593Smuzhiyun */
drm_property_blob_put(struct drm_property_blob * blob)603*4882a593Smuzhiyun void drm_property_blob_put(struct drm_property_blob *blob)
604*4882a593Smuzhiyun {
605*4882a593Smuzhiyun if (!blob)
606*4882a593Smuzhiyun return;
607*4882a593Smuzhiyun
608*4882a593Smuzhiyun drm_mode_object_put(&blob->base);
609*4882a593Smuzhiyun }
610*4882a593Smuzhiyun EXPORT_SYMBOL(drm_property_blob_put);
611*4882a593Smuzhiyun
drm_property_destroy_user_blobs(struct drm_device * dev,struct drm_file * file_priv)612*4882a593Smuzhiyun void drm_property_destroy_user_blobs(struct drm_device *dev,
613*4882a593Smuzhiyun struct drm_file *file_priv)
614*4882a593Smuzhiyun {
615*4882a593Smuzhiyun struct drm_property_blob *blob, *bt;
616*4882a593Smuzhiyun
617*4882a593Smuzhiyun /*
618*4882a593Smuzhiyun * When the file gets released that means no one else can access the
619*4882a593Smuzhiyun * blob list any more, so no need to grab dev->blob_lock.
620*4882a593Smuzhiyun */
621*4882a593Smuzhiyun list_for_each_entry_safe(blob, bt, &file_priv->blobs, head_file) {
622*4882a593Smuzhiyun list_del_init(&blob->head_file);
623*4882a593Smuzhiyun drm_property_blob_put(blob);
624*4882a593Smuzhiyun }
625*4882a593Smuzhiyun }
626*4882a593Smuzhiyun
627*4882a593Smuzhiyun /**
628*4882a593Smuzhiyun * drm_property_blob_get - acquire blob property reference
629*4882a593Smuzhiyun * @blob: DRM blob property
630*4882a593Smuzhiyun *
631*4882a593Smuzhiyun * Acquires a reference to an existing blob property. Returns @blob, which
632*4882a593Smuzhiyun * allows this to be used as a shorthand in assignments.
633*4882a593Smuzhiyun */
drm_property_blob_get(struct drm_property_blob * blob)634*4882a593Smuzhiyun struct drm_property_blob *drm_property_blob_get(struct drm_property_blob *blob)
635*4882a593Smuzhiyun {
636*4882a593Smuzhiyun drm_mode_object_get(&blob->base);
637*4882a593Smuzhiyun return blob;
638*4882a593Smuzhiyun }
639*4882a593Smuzhiyun EXPORT_SYMBOL(drm_property_blob_get);
640*4882a593Smuzhiyun
641*4882a593Smuzhiyun /**
642*4882a593Smuzhiyun * drm_property_lookup_blob - look up a blob property and take a reference
643*4882a593Smuzhiyun * @dev: drm device
644*4882a593Smuzhiyun * @id: id of the blob property
645*4882a593Smuzhiyun *
646*4882a593Smuzhiyun * If successful, this takes an additional reference to the blob property.
647*4882a593Smuzhiyun * callers need to make sure to eventually unreference the returned property
648*4882a593Smuzhiyun * again, using drm_property_blob_put().
649*4882a593Smuzhiyun *
650*4882a593Smuzhiyun * Return:
651*4882a593Smuzhiyun * NULL on failure, pointer to the blob on success.
652*4882a593Smuzhiyun */
drm_property_lookup_blob(struct drm_device * dev,uint32_t id)653*4882a593Smuzhiyun struct drm_property_blob *drm_property_lookup_blob(struct drm_device *dev,
654*4882a593Smuzhiyun uint32_t id)
655*4882a593Smuzhiyun {
656*4882a593Smuzhiyun struct drm_mode_object *obj;
657*4882a593Smuzhiyun struct drm_property_blob *blob = NULL;
658*4882a593Smuzhiyun
659*4882a593Smuzhiyun obj = __drm_mode_object_find(dev, NULL, id, DRM_MODE_OBJECT_BLOB);
660*4882a593Smuzhiyun if (obj)
661*4882a593Smuzhiyun blob = obj_to_blob(obj);
662*4882a593Smuzhiyun return blob;
663*4882a593Smuzhiyun }
664*4882a593Smuzhiyun EXPORT_SYMBOL(drm_property_lookup_blob);
665*4882a593Smuzhiyun
666*4882a593Smuzhiyun /**
667*4882a593Smuzhiyun * drm_property_replace_global_blob - replace existing blob property
668*4882a593Smuzhiyun * @dev: drm device
669*4882a593Smuzhiyun * @replace: location of blob property pointer to be replaced
670*4882a593Smuzhiyun * @length: length of data for new blob, or 0 for no data
671*4882a593Smuzhiyun * @data: content for new blob, or NULL for no data
672*4882a593Smuzhiyun * @obj_holds_id: optional object for property holding blob ID
673*4882a593Smuzhiyun * @prop_holds_id: optional property holding blob ID
674*4882a593Smuzhiyun * @return 0 on success or error on failure
675*4882a593Smuzhiyun *
676*4882a593Smuzhiyun * This function will replace a global property in the blob list, optionally
677*4882a593Smuzhiyun * updating a property which holds the ID of that property.
678*4882a593Smuzhiyun *
679*4882a593Smuzhiyun * If length is 0 or data is NULL, no new blob will be created, and the holding
680*4882a593Smuzhiyun * property, if specified, will be set to 0.
681*4882a593Smuzhiyun *
682*4882a593Smuzhiyun * Access to the replace pointer is assumed to be protected by the caller, e.g.
683*4882a593Smuzhiyun * by holding the relevant modesetting object lock for its parent.
684*4882a593Smuzhiyun *
685*4882a593Smuzhiyun * For example, a drm_connector has a 'PATH' property, which contains the ID
686*4882a593Smuzhiyun * of a blob property with the value of the MST path information. Calling this
687*4882a593Smuzhiyun * function with replace pointing to the connector's path_blob_ptr, length and
688*4882a593Smuzhiyun * data set for the new path information, obj_holds_id set to the connector's
689*4882a593Smuzhiyun * base object, and prop_holds_id set to the path property name, will perform
690*4882a593Smuzhiyun * a completely atomic update. The access to path_blob_ptr is protected by the
691*4882a593Smuzhiyun * caller holding a lock on the connector.
692*4882a593Smuzhiyun */
drm_property_replace_global_blob(struct drm_device * dev,struct drm_property_blob ** replace,size_t length,const void * data,struct drm_mode_object * obj_holds_id,struct drm_property * prop_holds_id)693*4882a593Smuzhiyun int drm_property_replace_global_blob(struct drm_device *dev,
694*4882a593Smuzhiyun struct drm_property_blob **replace,
695*4882a593Smuzhiyun size_t length,
696*4882a593Smuzhiyun const void *data,
697*4882a593Smuzhiyun struct drm_mode_object *obj_holds_id,
698*4882a593Smuzhiyun struct drm_property *prop_holds_id)
699*4882a593Smuzhiyun {
700*4882a593Smuzhiyun struct drm_property_blob *new_blob = NULL;
701*4882a593Smuzhiyun struct drm_property_blob *old_blob = NULL;
702*4882a593Smuzhiyun int ret;
703*4882a593Smuzhiyun
704*4882a593Smuzhiyun WARN_ON(replace == NULL);
705*4882a593Smuzhiyun
706*4882a593Smuzhiyun old_blob = *replace;
707*4882a593Smuzhiyun
708*4882a593Smuzhiyun if (length && data) {
709*4882a593Smuzhiyun new_blob = drm_property_create_blob(dev, length, data);
710*4882a593Smuzhiyun if (IS_ERR(new_blob))
711*4882a593Smuzhiyun return PTR_ERR(new_blob);
712*4882a593Smuzhiyun }
713*4882a593Smuzhiyun
714*4882a593Smuzhiyun if (obj_holds_id) {
715*4882a593Smuzhiyun ret = drm_object_property_set_value(obj_holds_id,
716*4882a593Smuzhiyun prop_holds_id,
717*4882a593Smuzhiyun new_blob ?
718*4882a593Smuzhiyun new_blob->base.id : 0);
719*4882a593Smuzhiyun if (ret != 0)
720*4882a593Smuzhiyun goto err_created;
721*4882a593Smuzhiyun }
722*4882a593Smuzhiyun
723*4882a593Smuzhiyun drm_property_blob_put(old_blob);
724*4882a593Smuzhiyun *replace = new_blob;
725*4882a593Smuzhiyun
726*4882a593Smuzhiyun return 0;
727*4882a593Smuzhiyun
728*4882a593Smuzhiyun err_created:
729*4882a593Smuzhiyun drm_property_blob_put(new_blob);
730*4882a593Smuzhiyun return ret;
731*4882a593Smuzhiyun }
732*4882a593Smuzhiyun EXPORT_SYMBOL(drm_property_replace_global_blob);
733*4882a593Smuzhiyun
734*4882a593Smuzhiyun /**
735*4882a593Smuzhiyun * drm_property_replace_blob - replace a blob property
736*4882a593Smuzhiyun * @blob: a pointer to the member blob to be replaced
737*4882a593Smuzhiyun * @new_blob: the new blob to replace with
738*4882a593Smuzhiyun *
739*4882a593Smuzhiyun * Return: true if the blob was in fact replaced.
740*4882a593Smuzhiyun */
drm_property_replace_blob(struct drm_property_blob ** blob,struct drm_property_blob * new_blob)741*4882a593Smuzhiyun bool drm_property_replace_blob(struct drm_property_blob **blob,
742*4882a593Smuzhiyun struct drm_property_blob *new_blob)
743*4882a593Smuzhiyun {
744*4882a593Smuzhiyun struct drm_property_blob *old_blob = *blob;
745*4882a593Smuzhiyun
746*4882a593Smuzhiyun if (old_blob == new_blob)
747*4882a593Smuzhiyun return false;
748*4882a593Smuzhiyun
749*4882a593Smuzhiyun drm_property_blob_put(old_blob);
750*4882a593Smuzhiyun if (new_blob)
751*4882a593Smuzhiyun drm_property_blob_get(new_blob);
752*4882a593Smuzhiyun *blob = new_blob;
753*4882a593Smuzhiyun return true;
754*4882a593Smuzhiyun }
755*4882a593Smuzhiyun EXPORT_SYMBOL(drm_property_replace_blob);
756*4882a593Smuzhiyun
drm_mode_getblob_ioctl(struct drm_device * dev,void * data,struct drm_file * file_priv)757*4882a593Smuzhiyun int drm_mode_getblob_ioctl(struct drm_device *dev,
758*4882a593Smuzhiyun void *data, struct drm_file *file_priv)
759*4882a593Smuzhiyun {
760*4882a593Smuzhiyun struct drm_mode_get_blob *out_resp = data;
761*4882a593Smuzhiyun struct drm_property_blob *blob;
762*4882a593Smuzhiyun int ret = 0;
763*4882a593Smuzhiyun
764*4882a593Smuzhiyun if (!drm_core_check_feature(dev, DRIVER_MODESET))
765*4882a593Smuzhiyun return -EOPNOTSUPP;
766*4882a593Smuzhiyun
767*4882a593Smuzhiyun blob = drm_property_lookup_blob(dev, out_resp->blob_id);
768*4882a593Smuzhiyun if (!blob)
769*4882a593Smuzhiyun return -ENOENT;
770*4882a593Smuzhiyun
771*4882a593Smuzhiyun if (out_resp->length == blob->length) {
772*4882a593Smuzhiyun if (copy_to_user(u64_to_user_ptr(out_resp->data),
773*4882a593Smuzhiyun blob->data,
774*4882a593Smuzhiyun blob->length)) {
775*4882a593Smuzhiyun ret = -EFAULT;
776*4882a593Smuzhiyun goto unref;
777*4882a593Smuzhiyun }
778*4882a593Smuzhiyun }
779*4882a593Smuzhiyun out_resp->length = blob->length;
780*4882a593Smuzhiyun unref:
781*4882a593Smuzhiyun drm_property_blob_put(blob);
782*4882a593Smuzhiyun
783*4882a593Smuzhiyun return ret;
784*4882a593Smuzhiyun }
785*4882a593Smuzhiyun
drm_mode_createblob_ioctl(struct drm_device * dev,void * data,struct drm_file * file_priv)786*4882a593Smuzhiyun int drm_mode_createblob_ioctl(struct drm_device *dev,
787*4882a593Smuzhiyun void *data, struct drm_file *file_priv)
788*4882a593Smuzhiyun {
789*4882a593Smuzhiyun struct drm_mode_create_blob *out_resp = data;
790*4882a593Smuzhiyun struct drm_property_blob *blob;
791*4882a593Smuzhiyun int ret = 0;
792*4882a593Smuzhiyun
793*4882a593Smuzhiyun if (!drm_core_check_feature(dev, DRIVER_MODESET))
794*4882a593Smuzhiyun return -EOPNOTSUPP;
795*4882a593Smuzhiyun
796*4882a593Smuzhiyun blob = drm_property_create_blob(dev, out_resp->length, NULL);
797*4882a593Smuzhiyun if (IS_ERR(blob))
798*4882a593Smuzhiyun return PTR_ERR(blob);
799*4882a593Smuzhiyun
800*4882a593Smuzhiyun if (copy_from_user(blob->data,
801*4882a593Smuzhiyun u64_to_user_ptr(out_resp->data),
802*4882a593Smuzhiyun out_resp->length)) {
803*4882a593Smuzhiyun ret = -EFAULT;
804*4882a593Smuzhiyun goto out_blob;
805*4882a593Smuzhiyun }
806*4882a593Smuzhiyun
807*4882a593Smuzhiyun /* Dropping the lock between create_blob and our access here is safe
808*4882a593Smuzhiyun * as only the same file_priv can remove the blob; at this point, it is
809*4882a593Smuzhiyun * not associated with any file_priv. */
810*4882a593Smuzhiyun mutex_lock(&dev->mode_config.blob_lock);
811*4882a593Smuzhiyun out_resp->blob_id = blob->base.id;
812*4882a593Smuzhiyun list_add_tail(&blob->head_file, &file_priv->blobs);
813*4882a593Smuzhiyun mutex_unlock(&dev->mode_config.blob_lock);
814*4882a593Smuzhiyun
815*4882a593Smuzhiyun return 0;
816*4882a593Smuzhiyun
817*4882a593Smuzhiyun out_blob:
818*4882a593Smuzhiyun drm_property_blob_put(blob);
819*4882a593Smuzhiyun return ret;
820*4882a593Smuzhiyun }
821*4882a593Smuzhiyun
drm_mode_destroyblob_ioctl(struct drm_device * dev,void * data,struct drm_file * file_priv)822*4882a593Smuzhiyun int drm_mode_destroyblob_ioctl(struct drm_device *dev,
823*4882a593Smuzhiyun void *data, struct drm_file *file_priv)
824*4882a593Smuzhiyun {
825*4882a593Smuzhiyun struct drm_mode_destroy_blob *out_resp = data;
826*4882a593Smuzhiyun struct drm_property_blob *blob = NULL, *bt;
827*4882a593Smuzhiyun bool found = false;
828*4882a593Smuzhiyun int ret = 0;
829*4882a593Smuzhiyun
830*4882a593Smuzhiyun if (!drm_core_check_feature(dev, DRIVER_MODESET))
831*4882a593Smuzhiyun return -EOPNOTSUPP;
832*4882a593Smuzhiyun
833*4882a593Smuzhiyun blob = drm_property_lookup_blob(dev, out_resp->blob_id);
834*4882a593Smuzhiyun if (!blob)
835*4882a593Smuzhiyun return -ENOENT;
836*4882a593Smuzhiyun
837*4882a593Smuzhiyun mutex_lock(&dev->mode_config.blob_lock);
838*4882a593Smuzhiyun /* Ensure the property was actually created by this user. */
839*4882a593Smuzhiyun list_for_each_entry(bt, &file_priv->blobs, head_file) {
840*4882a593Smuzhiyun if (bt == blob) {
841*4882a593Smuzhiyun found = true;
842*4882a593Smuzhiyun break;
843*4882a593Smuzhiyun }
844*4882a593Smuzhiyun }
845*4882a593Smuzhiyun
846*4882a593Smuzhiyun if (!found) {
847*4882a593Smuzhiyun ret = -EPERM;
848*4882a593Smuzhiyun goto err;
849*4882a593Smuzhiyun }
850*4882a593Smuzhiyun
851*4882a593Smuzhiyun /* We must drop head_file here, because we may not be the last
852*4882a593Smuzhiyun * reference on the blob. */
853*4882a593Smuzhiyun list_del_init(&blob->head_file);
854*4882a593Smuzhiyun mutex_unlock(&dev->mode_config.blob_lock);
855*4882a593Smuzhiyun
856*4882a593Smuzhiyun /* One reference from lookup, and one from the filp. */
857*4882a593Smuzhiyun drm_property_blob_put(blob);
858*4882a593Smuzhiyun drm_property_blob_put(blob);
859*4882a593Smuzhiyun
860*4882a593Smuzhiyun return 0;
861*4882a593Smuzhiyun
862*4882a593Smuzhiyun err:
863*4882a593Smuzhiyun mutex_unlock(&dev->mode_config.blob_lock);
864*4882a593Smuzhiyun drm_property_blob_put(blob);
865*4882a593Smuzhiyun
866*4882a593Smuzhiyun return ret;
867*4882a593Smuzhiyun }
868*4882a593Smuzhiyun
869*4882a593Smuzhiyun /* Some properties could refer to dynamic refcnt'd objects, or things that
870*4882a593Smuzhiyun * need special locking to handle lifetime issues (ie. to ensure the prop
871*4882a593Smuzhiyun * value doesn't become invalid part way through the property update due to
872*4882a593Smuzhiyun * race). The value returned by reference via 'obj' should be passed back
873*4882a593Smuzhiyun * to drm_property_change_valid_put() after the property is set (and the
874*4882a593Smuzhiyun * object to which the property is attached has a chance to take its own
875*4882a593Smuzhiyun * reference).
876*4882a593Smuzhiyun */
drm_property_change_valid_get(struct drm_property * property,uint64_t value,struct drm_mode_object ** ref)877*4882a593Smuzhiyun bool drm_property_change_valid_get(struct drm_property *property,
878*4882a593Smuzhiyun uint64_t value, struct drm_mode_object **ref)
879*4882a593Smuzhiyun {
880*4882a593Smuzhiyun int i;
881*4882a593Smuzhiyun
882*4882a593Smuzhiyun if (property->flags & DRM_MODE_PROP_IMMUTABLE)
883*4882a593Smuzhiyun return false;
884*4882a593Smuzhiyun
885*4882a593Smuzhiyun *ref = NULL;
886*4882a593Smuzhiyun
887*4882a593Smuzhiyun if (drm_property_type_is(property, DRM_MODE_PROP_RANGE)) {
888*4882a593Smuzhiyun if (value < property->values[0] || value > property->values[1])
889*4882a593Smuzhiyun return false;
890*4882a593Smuzhiyun return true;
891*4882a593Smuzhiyun } else if (drm_property_type_is(property, DRM_MODE_PROP_SIGNED_RANGE)) {
892*4882a593Smuzhiyun int64_t svalue = U642I64(value);
893*4882a593Smuzhiyun
894*4882a593Smuzhiyun if (svalue < U642I64(property->values[0]) ||
895*4882a593Smuzhiyun svalue > U642I64(property->values[1]))
896*4882a593Smuzhiyun return false;
897*4882a593Smuzhiyun return true;
898*4882a593Smuzhiyun } else if (drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) {
899*4882a593Smuzhiyun uint64_t valid_mask = 0;
900*4882a593Smuzhiyun
901*4882a593Smuzhiyun for (i = 0; i < property->num_values; i++)
902*4882a593Smuzhiyun valid_mask |= (1ULL << property->values[i]);
903*4882a593Smuzhiyun return !(value & ~valid_mask);
904*4882a593Smuzhiyun } else if (drm_property_type_is(property, DRM_MODE_PROP_BLOB)) {
905*4882a593Smuzhiyun struct drm_property_blob *blob;
906*4882a593Smuzhiyun
907*4882a593Smuzhiyun if (value == 0)
908*4882a593Smuzhiyun return true;
909*4882a593Smuzhiyun
910*4882a593Smuzhiyun blob = drm_property_lookup_blob(property->dev, value);
911*4882a593Smuzhiyun if (blob) {
912*4882a593Smuzhiyun *ref = &blob->base;
913*4882a593Smuzhiyun return true;
914*4882a593Smuzhiyun } else {
915*4882a593Smuzhiyun return false;
916*4882a593Smuzhiyun }
917*4882a593Smuzhiyun } else if (drm_property_type_is(property, DRM_MODE_PROP_OBJECT)) {
918*4882a593Smuzhiyun /* a zero value for an object property translates to null: */
919*4882a593Smuzhiyun if (value == 0)
920*4882a593Smuzhiyun return true;
921*4882a593Smuzhiyun
922*4882a593Smuzhiyun *ref = __drm_mode_object_find(property->dev, NULL, value,
923*4882a593Smuzhiyun property->values[0]);
924*4882a593Smuzhiyun return *ref != NULL;
925*4882a593Smuzhiyun }
926*4882a593Smuzhiyun
927*4882a593Smuzhiyun for (i = 0; i < property->num_values; i++)
928*4882a593Smuzhiyun if (property->values[i] == value)
929*4882a593Smuzhiyun return true;
930*4882a593Smuzhiyun return false;
931*4882a593Smuzhiyun }
932*4882a593Smuzhiyun
drm_property_change_valid_put(struct drm_property * property,struct drm_mode_object * ref)933*4882a593Smuzhiyun void drm_property_change_valid_put(struct drm_property *property,
934*4882a593Smuzhiyun struct drm_mode_object *ref)
935*4882a593Smuzhiyun {
936*4882a593Smuzhiyun if (!ref)
937*4882a593Smuzhiyun return;
938*4882a593Smuzhiyun
939*4882a593Smuzhiyun if (drm_property_type_is(property, DRM_MODE_PROP_OBJECT)) {
940*4882a593Smuzhiyun drm_mode_object_put(ref);
941*4882a593Smuzhiyun } else if (drm_property_type_is(property, DRM_MODE_PROP_BLOB))
942*4882a593Smuzhiyun drm_property_blob_put(obj_to_blob(ref));
943*4882a593Smuzhiyun }
944