1 /*
2 * Copyright (c) 2006-2008 Intel Corporation
3 * Copyright (c) 2007 Dave Airlie <airlied@linux.ie>
4 * Copyright (c) 2008 Red Hat Inc.
5 *
6 * DRM core CRTC related functions
7 *
8 * Permission to use, copy, modify, distribute, and sell this software and its
9 * documentation for any purpose is hereby granted without fee, provided that
10 * the above copyright notice appear in all copies and that both that copyright
11 * notice and this permission notice appear in supporting documentation, and
12 * that the name of the copyright holders not be used in advertising or
13 * publicity pertaining to distribution of the software without specific,
14 * written prior permission. The copyright holders make no representations
15 * about the suitability of this software for any purpose. It is provided "as
16 * is" without express or implied warranty.
17 *
18 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
19 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
20 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
21 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
22 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
23 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
24 * OF THIS SOFTWARE.
25 *
26 * Authors:
27 * Keith Packard
28 * Eric Anholt <eric@anholt.net>
29 * Dave Airlie <airlied@linux.ie>
30 * Jesse Barnes <jesse.barnes@intel.com>
31 */
32 #include <sys/cdefs.h>
33 #include <dev/drm2/drmP.h>
34 #include <dev/drm2/drm_crtc.h>
35 #include <dev/drm2/drm_edid.h>
36 #include <dev/drm2/drm_fourcc.h>
37
38 static void drm_property_destroy_blob(struct drm_device *dev,
39 struct drm_property_blob *blob);
40
41 /* Avoid boilerplate. I'm tired of typing. */
42 #define DRM_ENUM_NAME_FN(fnname, list) \
43 char *fnname(int val) \
44 { \
45 int i; \
46 for (i = 0; i < ARRAY_SIZE(list); i++) { \
47 if (list[i].type == val) \
48 return list[i].name; \
49 } \
50 return "(unknown)"; \
51 }
52
53 /*
54 * Global properties
55 */
56 static struct drm_prop_enum_list drm_dpms_enum_list[] =
57 { { DRM_MODE_DPMS_ON, "On" },
58 { DRM_MODE_DPMS_STANDBY, "Standby" },
59 { DRM_MODE_DPMS_SUSPEND, "Suspend" },
60 { DRM_MODE_DPMS_OFF, "Off" }
61 };
62
63 DRM_ENUM_NAME_FN(drm_get_dpms_name, drm_dpms_enum_list)
64
65 /*
66 * Optional properties
67 */
68 static struct drm_prop_enum_list drm_scaling_mode_enum_list[] =
69 {
70 { DRM_MODE_SCALE_NONE, "None" },
71 { DRM_MODE_SCALE_FULLSCREEN, "Full" },
72 { DRM_MODE_SCALE_CENTER, "Center" },
73 { DRM_MODE_SCALE_ASPECT, "Full aspect" },
74 };
75
76 static struct drm_prop_enum_list drm_dithering_mode_enum_list[] =
77 {
78 { DRM_MODE_DITHERING_OFF, "Off" },
79 { DRM_MODE_DITHERING_ON, "On" },
80 { DRM_MODE_DITHERING_AUTO, "Automatic" },
81 };
82
83 /*
84 * Non-global properties, but "required" for certain connectors.
85 */
86 static struct drm_prop_enum_list drm_dvi_i_select_enum_list[] =
87 {
88 { DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" }, /* DVI-I and TV-out */
89 { DRM_MODE_SUBCONNECTOR_DVID, "DVI-D" }, /* DVI-I */
90 { DRM_MODE_SUBCONNECTOR_DVIA, "DVI-A" }, /* DVI-I */
91 };
92
93 DRM_ENUM_NAME_FN(drm_get_dvi_i_select_name, drm_dvi_i_select_enum_list)
94
95 static struct drm_prop_enum_list drm_dvi_i_subconnector_enum_list[] =
96 {
97 { DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" }, /* DVI-I and TV-out */
98 { DRM_MODE_SUBCONNECTOR_DVID, "DVI-D" }, /* DVI-I */
99 { DRM_MODE_SUBCONNECTOR_DVIA, "DVI-A" }, /* DVI-I */
100 };
101
102 DRM_ENUM_NAME_FN(drm_get_dvi_i_subconnector_name,
103 drm_dvi_i_subconnector_enum_list)
104
105 static struct drm_prop_enum_list drm_tv_select_enum_list[] =
106 {
107 { DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" }, /* DVI-I and TV-out */
108 { DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */
109 { DRM_MODE_SUBCONNECTOR_SVIDEO, "SVIDEO" }, /* TV-out */
110 { DRM_MODE_SUBCONNECTOR_Component, "Component" }, /* TV-out */
111 { DRM_MODE_SUBCONNECTOR_SCART, "SCART" }, /* TV-out */
112 };
113
114 DRM_ENUM_NAME_FN(drm_get_tv_select_name, drm_tv_select_enum_list)
115
116 static struct drm_prop_enum_list drm_tv_subconnector_enum_list[] =
117 {
118 { DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" }, /* DVI-I and TV-out */
119 { DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */
120 { DRM_MODE_SUBCONNECTOR_SVIDEO, "SVIDEO" }, /* TV-out */
121 { DRM_MODE_SUBCONNECTOR_Component, "Component" }, /* TV-out */
122 { DRM_MODE_SUBCONNECTOR_SCART, "SCART" }, /* TV-out */
123 };
124
125 DRM_ENUM_NAME_FN(drm_get_tv_subconnector_name,
126 drm_tv_subconnector_enum_list)
127
128 static struct drm_prop_enum_list drm_dirty_info_enum_list[] = {
129 { DRM_MODE_DIRTY_OFF, "Off" },
130 { DRM_MODE_DIRTY_ON, "On" },
131 { DRM_MODE_DIRTY_ANNOTATE, "Annotate" },
132 };
133
134 DRM_ENUM_NAME_FN(drm_get_dirty_info_name,
135 drm_dirty_info_enum_list)
136
137 struct drm_conn_prop_enum_list {
138 int type;
139 char *name;
140 int count;
141 };
142
143 /*
144 * Connector and encoder types.
145 */
146 static struct drm_conn_prop_enum_list drm_connector_enum_list[] =
147 { { DRM_MODE_CONNECTOR_Unknown, "Unknown", 0 },
148 { DRM_MODE_CONNECTOR_VGA, "VGA", 0 },
149 { DRM_MODE_CONNECTOR_DVII, "DVI-I", 0 },
150 { DRM_MODE_CONNECTOR_DVID, "DVI-D", 0 },
151 { DRM_MODE_CONNECTOR_DVIA, "DVI-A", 0 },
152 { DRM_MODE_CONNECTOR_Composite, "Composite", 0 },
153 { DRM_MODE_CONNECTOR_SVIDEO, "SVIDEO", 0 },
154 { DRM_MODE_CONNECTOR_LVDS, "LVDS", 0 },
155 { DRM_MODE_CONNECTOR_Component, "Component", 0 },
156 { DRM_MODE_CONNECTOR_9PinDIN, "DIN", 0 },
157 { DRM_MODE_CONNECTOR_DisplayPort, "DP", 0 },
158 { DRM_MODE_CONNECTOR_HDMIA, "HDMI-A", 0 },
159 { DRM_MODE_CONNECTOR_HDMIB, "HDMI-B", 0 },
160 { DRM_MODE_CONNECTOR_TV, "TV", 0 },
161 { DRM_MODE_CONNECTOR_eDP, "eDP", 0 },
162 { DRM_MODE_CONNECTOR_VIRTUAL, "Virtual", 0},
163 };
164
165 static struct drm_prop_enum_list drm_encoder_enum_list[] =
166 { { DRM_MODE_ENCODER_NONE, "None" },
167 { DRM_MODE_ENCODER_DAC, "DAC" },
168 { DRM_MODE_ENCODER_TMDS, "TMDS" },
169 { DRM_MODE_ENCODER_LVDS, "LVDS" },
170 { DRM_MODE_ENCODER_TVDAC, "TV" },
171 { DRM_MODE_ENCODER_VIRTUAL, "Virtual" },
172 };
173
drm_get_encoder_name(struct drm_encoder * encoder)174 char *drm_get_encoder_name(struct drm_encoder *encoder)
175 {
176 static char buf[32];
177
178 snprintf(buf, 32, "%s-%d",
179 drm_encoder_enum_list[encoder->encoder_type].name,
180 encoder->base.id);
181 return buf;
182 }
183 EXPORT_SYMBOL(drm_get_encoder_name);
184
drm_get_connector_name(struct drm_connector * connector)185 char *drm_get_connector_name(struct drm_connector *connector)
186 {
187 static char buf[32];
188
189 snprintf(buf, 32, "%s-%d",
190 drm_connector_enum_list[connector->connector_type].name,
191 connector->connector_type_id);
192 return buf;
193 }
194 EXPORT_SYMBOL(drm_get_connector_name);
195
drm_get_connector_status_name(enum drm_connector_status status)196 char *drm_get_connector_status_name(enum drm_connector_status status)
197 {
198 if (status == connector_status_connected)
199 return "connected";
200 else if (status == connector_status_disconnected)
201 return "disconnected";
202 else
203 return "unknown";
204 }
205
206 /**
207 * drm_mode_object_get - allocate a new identifier
208 * @dev: DRM device
209 * @ptr: object pointer, used to generate unique ID
210 * @type: object type
211 *
212 * LOCKING:
213 *
214 * Create a unique identifier based on @ptr in @dev's identifier space. Used
215 * for tracking modes, CRTCs and connectors.
216 *
217 * RETURNS:
218 * New unique (relative to other objects in @dev) integer identifier for the
219 * object.
220 */
drm_mode_object_get(struct drm_device * dev,struct drm_mode_object * obj,uint32_t obj_type)221 static int drm_mode_object_get(struct drm_device *dev,
222 struct drm_mode_object *obj, uint32_t obj_type)
223 {
224 int new_id = 0;
225 int ret;
226
227 ret = drm_gem_name_create(&dev->mode_config.crtc_names, obj, &new_id);
228 if (ret)
229 return ret;
230
231 obj->id = new_id;
232 obj->type = obj_type;
233 return 0;
234 }
235
236 /**
237 * drm_mode_object_put - free an identifer
238 * @dev: DRM device
239 * @id: ID to free
240 *
241 * LOCKING:
242 * Caller must hold DRM mode_config lock.
243 *
244 * Free @id from @dev's unique identifier pool.
245 */
drm_mode_object_put(struct drm_device * dev,struct drm_mode_object * object)246 static void drm_mode_object_put(struct drm_device *dev,
247 struct drm_mode_object *object)
248 {
249
250 drm_gem_names_remove(&dev->mode_config.crtc_names, object->id);
251 }
252
drm_mode_object_find(struct drm_device * dev,uint32_t id,uint32_t type)253 struct drm_mode_object *drm_mode_object_find(struct drm_device *dev,
254 uint32_t id, uint32_t type)
255 {
256 struct drm_mode_object *obj = NULL;
257
258 obj = drm_gem_name_ref(&dev->mode_config.crtc_names, id, NULL);
259 if (!obj || (obj->type != type) || (obj->id != id))
260 obj = NULL;
261
262 return obj;
263 }
264 EXPORT_SYMBOL(drm_mode_object_find);
265
266 /**
267 * drm_framebuffer_init - initialize a framebuffer
268 * @dev: DRM device
269 *
270 * LOCKING:
271 * Caller must hold mode config lock.
272 *
273 * Allocates an ID for the framebuffer's parent mode object, sets its mode
274 * functions & device file and adds it to the master fd list.
275 *
276 * RETURNS:
277 * Zero on success, error code on failure.
278 */
drm_framebuffer_init(struct drm_device * dev,struct drm_framebuffer * fb,const struct drm_framebuffer_funcs * funcs)279 int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb,
280 const struct drm_framebuffer_funcs *funcs)
281 {
282 int ret;
283
284 refcount_init(&fb->refcount, 1);
285
286 ret = drm_mode_object_get(dev, &fb->base, DRM_MODE_OBJECT_FB);
287 if (ret)
288 return ret;
289
290 fb->dev = dev;
291 fb->funcs = funcs;
292 dev->mode_config.num_fb++;
293 list_add(&fb->head, &dev->mode_config.fb_list);
294
295 return 0;
296 }
297 EXPORT_SYMBOL(drm_framebuffer_init);
298
drm_framebuffer_free(struct drm_framebuffer * fb)299 static void drm_framebuffer_free(struct drm_framebuffer *fb)
300 {
301 fb->funcs->destroy(fb);
302 }
303
304 /**
305 * drm_framebuffer_unreference - unref a framebuffer
306 *
307 * LOCKING:
308 * Caller must hold mode config lock.
309 */
drm_framebuffer_unreference(struct drm_framebuffer * fb)310 void drm_framebuffer_unreference(struct drm_framebuffer *fb)
311 {
312 struct drm_device *dev = fb->dev;
313 DRM_DEBUG("FB ID: %d\n", fb->base.id);
314 if (!sx_xlocked(&dev->mode_config.mutex))
315 DRM_WARNING("%s: dev->mode_config.mutex not locked\n", __func__);
316 if (refcount_release(&fb->refcount))
317 drm_framebuffer_free(fb);
318 }
319 EXPORT_SYMBOL(drm_framebuffer_unreference);
320
321 /**
322 * drm_framebuffer_reference - incr the fb refcnt
323 */
drm_framebuffer_reference(struct drm_framebuffer * fb)324 void drm_framebuffer_reference(struct drm_framebuffer *fb)
325 {
326 DRM_DEBUG("FB ID: %d\n", fb->base.id);
327 refcount_acquire(&fb->refcount);
328 }
329 EXPORT_SYMBOL(drm_framebuffer_reference);
330
331 /**
332 * drm_framebuffer_cleanup - remove a framebuffer object
333 * @fb: framebuffer to remove
334 *
335 * LOCKING:
336 * Caller must hold mode config lock.
337 *
338 * Scans all the CRTCs in @dev's mode_config. If they're using @fb, removes
339 * it, setting it to NULL.
340 */
drm_framebuffer_cleanup(struct drm_framebuffer * fb)341 void drm_framebuffer_cleanup(struct drm_framebuffer *fb)
342 {
343 struct drm_device *dev = fb->dev;
344 /*
345 * This could be moved to drm_framebuffer_remove(), but for
346 * debugging is nice to keep around the list of fb's that are
347 * no longer associated w/ a drm_file but are not unreferenced
348 * yet. (i915 and omapdrm have debugfs files which will show
349 * this.)
350 */
351 drm_mode_object_put(dev, &fb->base);
352 list_del(&fb->head);
353 dev->mode_config.num_fb--;
354 }
355 EXPORT_SYMBOL(drm_framebuffer_cleanup);
356
357 /**
358 * drm_framebuffer_remove - remove and unreference a framebuffer object
359 * @fb: framebuffer to remove
360 *
361 * LOCKING:
362 * Caller must hold mode config lock.
363 *
364 * Scans all the CRTCs and planes in @dev's mode_config. If they're
365 * using @fb, removes it, setting it to NULL.
366 */
drm_framebuffer_remove(struct drm_framebuffer * fb)367 void drm_framebuffer_remove(struct drm_framebuffer *fb)
368 {
369 struct drm_device *dev = fb->dev;
370 struct drm_crtc *crtc;
371 struct drm_plane *plane;
372 struct drm_mode_set set;
373 int ret;
374
375 /* remove from any CRTC */
376 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
377 if (crtc->fb == fb) {
378 /* should turn off the crtc */
379 memset(&set, 0, sizeof(struct drm_mode_set));
380 set.crtc = crtc;
381 set.fb = NULL;
382 ret = crtc->funcs->set_config(&set);
383 if (ret)
384 DRM_ERROR("failed to reset crtc %p when fb was deleted\n", crtc);
385 }
386 }
387
388 list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
389 if (plane->fb == fb) {
390 /* should turn off the crtc */
391 ret = plane->funcs->disable_plane(plane);
392 if (ret)
393 DRM_ERROR("failed to disable plane with busy fb\n");
394 /* disconnect the plane from the fb and crtc: */
395 plane->fb = NULL;
396 plane->crtc = NULL;
397 }
398 }
399
400 list_del(&fb->filp_head);
401
402 drm_framebuffer_unreference(fb);
403 }
404 EXPORT_SYMBOL(drm_framebuffer_remove);
405
406 /**
407 * drm_crtc_init - Initialise a new CRTC object
408 * @dev: DRM device
409 * @crtc: CRTC object to init
410 * @funcs: callbacks for the new CRTC
411 *
412 * LOCKING:
413 * Takes mode_config lock.
414 *
415 * Inits a new object created as base part of an driver crtc object.
416 *
417 * RETURNS:
418 * Zero on success, error code on failure.
419 */
drm_crtc_init(struct drm_device * dev,struct drm_crtc * crtc,const struct drm_crtc_funcs * funcs)420 int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
421 const struct drm_crtc_funcs *funcs)
422 {
423 int ret;
424
425 crtc->dev = dev;
426 crtc->funcs = funcs;
427 crtc->invert_dimensions = false;
428
429 sx_xlock(&dev->mode_config.mutex);
430
431 ret = drm_mode_object_get(dev, &crtc->base, DRM_MODE_OBJECT_CRTC);
432 if (ret)
433 goto out;
434
435 crtc->base.properties = &crtc->properties;
436
437 list_add_tail(&crtc->head, &dev->mode_config.crtc_list);
438 dev->mode_config.num_crtc++;
439
440 out:
441 sx_xunlock(&dev->mode_config.mutex);
442
443 return ret;
444 }
445 EXPORT_SYMBOL(drm_crtc_init);
446
447 /**
448 * drm_crtc_cleanup - Cleans up the core crtc usage.
449 * @crtc: CRTC to cleanup
450 *
451 * LOCKING:
452 * Caller must hold mode config lock.
453 *
454 * Cleanup @crtc. Removes from drm modesetting space
455 * does NOT free object, caller does that.
456 */
drm_crtc_cleanup(struct drm_crtc * crtc)457 void drm_crtc_cleanup(struct drm_crtc *crtc)
458 {
459 struct drm_device *dev = crtc->dev;
460
461 free(crtc->gamma_store, DRM_MEM_KMS);
462 crtc->gamma_store = NULL;
463
464 drm_mode_object_put(dev, &crtc->base);
465 list_del(&crtc->head);
466 dev->mode_config.num_crtc--;
467 }
468 EXPORT_SYMBOL(drm_crtc_cleanup);
469
470 /**
471 * drm_mode_probed_add - add a mode to a connector's probed mode list
472 * @connector: connector the new mode
473 * @mode: mode data
474 *
475 * LOCKING:
476 * Caller must hold mode config lock.
477 *
478 * Add @mode to @connector's mode list for later use.
479 */
drm_mode_probed_add(struct drm_connector * connector,struct drm_display_mode * mode)480 void drm_mode_probed_add(struct drm_connector *connector,
481 struct drm_display_mode *mode)
482 {
483 list_add(&mode->head, &connector->probed_modes);
484 }
485 EXPORT_SYMBOL(drm_mode_probed_add);
486
487 /**
488 * drm_mode_remove - remove and free a mode
489 * @connector: connector list to modify
490 * @mode: mode to remove
491 *
492 * LOCKING:
493 * Caller must hold mode config lock.
494 *
495 * Remove @mode from @connector's mode list, then free it.
496 */
drm_mode_remove(struct drm_connector * connector,struct drm_display_mode * mode)497 void drm_mode_remove(struct drm_connector *connector,
498 struct drm_display_mode *mode)
499 {
500 list_del(&mode->head);
501 drm_mode_destroy(connector->dev, mode);
502 }
503 EXPORT_SYMBOL(drm_mode_remove);
504
505 /**
506 * drm_connector_init - Init a preallocated connector
507 * @dev: DRM device
508 * @connector: the connector to init
509 * @funcs: callbacks for this connector
510 * @name: user visible name of the connector
511 *
512 * LOCKING:
513 * Takes mode config lock.
514 *
515 * Initialises a preallocated connector. Connectors should be
516 * subclassed as part of driver connector objects.
517 *
518 * RETURNS:
519 * Zero on success, error code on failure.
520 */
drm_connector_init(struct drm_device * dev,struct drm_connector * connector,const struct drm_connector_funcs * funcs,int connector_type)521 int drm_connector_init(struct drm_device *dev,
522 struct drm_connector *connector,
523 const struct drm_connector_funcs *funcs,
524 int connector_type)
525 {
526 int ret;
527
528 sx_xlock(&dev->mode_config.mutex);
529
530 ret = drm_mode_object_get(dev, &connector->base, DRM_MODE_OBJECT_CONNECTOR);
531 if (ret)
532 goto out;
533
534 connector->base.properties = &connector->properties;
535 connector->dev = dev;
536 connector->funcs = funcs;
537 connector->connector_type = connector_type;
538 connector->connector_type_id =
539 ++drm_connector_enum_list[connector_type].count; /* TODO */
540 INIT_LIST_HEAD(&connector->user_modes);
541 INIT_LIST_HEAD(&connector->probed_modes);
542 INIT_LIST_HEAD(&connector->modes);
543 connector->edid_blob_ptr = NULL;
544 connector->status = connector_status_unknown;
545
546 list_add_tail(&connector->head, &dev->mode_config.connector_list);
547 dev->mode_config.num_connector++;
548
549 if (connector_type != DRM_MODE_CONNECTOR_VIRTUAL)
550 drm_object_attach_property(&connector->base,
551 dev->mode_config.edid_property,
552 0);
553
554 drm_object_attach_property(&connector->base,
555 dev->mode_config.dpms_property, 0);
556
557 out:
558 sx_xunlock(&dev->mode_config.mutex);
559
560 return ret;
561 }
562 EXPORT_SYMBOL(drm_connector_init);
563
564 /**
565 * drm_connector_cleanup - cleans up an initialised connector
566 * @connector: connector to cleanup
567 *
568 * LOCKING:
569 * Takes mode config lock.
570 *
571 * Cleans up the connector but doesn't free the object.
572 */
drm_connector_cleanup(struct drm_connector * connector)573 void drm_connector_cleanup(struct drm_connector *connector)
574 {
575 struct drm_device *dev = connector->dev;
576 struct drm_display_mode *mode, *t;
577
578 list_for_each_entry_safe(mode, t, &connector->probed_modes, head)
579 drm_mode_remove(connector, mode);
580
581 list_for_each_entry_safe(mode, t, &connector->modes, head)
582 drm_mode_remove(connector, mode);
583
584 list_for_each_entry_safe(mode, t, &connector->user_modes, head)
585 drm_mode_remove(connector, mode);
586
587 sx_xlock(&dev->mode_config.mutex);
588 drm_mode_object_put(dev, &connector->base);
589 list_del(&connector->head);
590 dev->mode_config.num_connector--;
591 sx_xunlock(&dev->mode_config.mutex);
592 }
593 EXPORT_SYMBOL(drm_connector_cleanup);
594
drm_connector_unplug_all(struct drm_device * dev)595 void drm_connector_unplug_all(struct drm_device *dev)
596 {
597 #ifdef FREEBSD_NOTYET
598 struct drm_connector *connector;
599
600 /* taking the mode config mutex ends up in a clash with sysfs */
601 list_for_each_entry(connector, &dev->mode_config.connector_list, head)
602 drm_sysfs_connector_remove(connector);
603 #endif /* FREEBSD_NOTYET */
604
605 }
606 EXPORT_SYMBOL(drm_connector_unplug_all);
607
drm_encoder_init(struct drm_device * dev,struct drm_encoder * encoder,const struct drm_encoder_funcs * funcs,int encoder_type)608 int drm_encoder_init(struct drm_device *dev,
609 struct drm_encoder *encoder,
610 const struct drm_encoder_funcs *funcs,
611 int encoder_type)
612 {
613 int ret;
614
615 sx_xlock(&dev->mode_config.mutex);
616
617 ret = drm_mode_object_get(dev, &encoder->base, DRM_MODE_OBJECT_ENCODER);
618 if (ret)
619 goto out;
620
621 encoder->dev = dev;
622 encoder->encoder_type = encoder_type;
623 encoder->funcs = funcs;
624
625 list_add_tail(&encoder->head, &dev->mode_config.encoder_list);
626 dev->mode_config.num_encoder++;
627
628 out:
629 sx_xunlock(&dev->mode_config.mutex);
630
631 return ret;
632 }
633 EXPORT_SYMBOL(drm_encoder_init);
634
drm_encoder_cleanup(struct drm_encoder * encoder)635 void drm_encoder_cleanup(struct drm_encoder *encoder)
636 {
637 struct drm_device *dev = encoder->dev;
638 sx_xlock(&dev->mode_config.mutex);
639 drm_mode_object_put(dev, &encoder->base);
640 list_del(&encoder->head);
641 dev->mode_config.num_encoder--;
642 sx_xunlock(&dev->mode_config.mutex);
643 }
644 EXPORT_SYMBOL(drm_encoder_cleanup);
645
drm_plane_init(struct drm_device * dev,struct drm_plane * plane,unsigned long possible_crtcs,const struct drm_plane_funcs * funcs,const uint32_t * formats,uint32_t format_count,bool priv)646 int drm_plane_init(struct drm_device *dev, struct drm_plane *plane,
647 unsigned long possible_crtcs,
648 const struct drm_plane_funcs *funcs,
649 const uint32_t *formats, uint32_t format_count,
650 bool priv)
651 {
652 int ret;
653
654 sx_xlock(&dev->mode_config.mutex);
655
656 ret = drm_mode_object_get(dev, &plane->base, DRM_MODE_OBJECT_PLANE);
657 if (ret)
658 goto out;
659
660 plane->base.properties = &plane->properties;
661 plane->dev = dev;
662 plane->funcs = funcs;
663 plane->format_types = malloc(sizeof(uint32_t) * format_count,
664 DRM_MEM_KMS, M_WAITOK);
665 memcpy(plane->format_types, formats, format_count * sizeof(uint32_t));
666 plane->format_count = format_count;
667 plane->possible_crtcs = possible_crtcs;
668
669 /* private planes are not exposed to userspace, but depending on
670 * display hardware, might be convenient to allow sharing programming
671 * for the scanout engine with the crtc implementation.
672 */
673 if (!priv) {
674 list_add_tail(&plane->head, &dev->mode_config.plane_list);
675 dev->mode_config.num_plane++;
676 } else {
677 INIT_LIST_HEAD(&plane->head);
678 }
679
680 out:
681 sx_xunlock(&dev->mode_config.mutex);
682
683 return ret;
684 }
685 EXPORT_SYMBOL(drm_plane_init);
686
drm_plane_cleanup(struct drm_plane * plane)687 void drm_plane_cleanup(struct drm_plane *plane)
688 {
689 struct drm_device *dev = plane->dev;
690
691 sx_xlock(&dev->mode_config.mutex);
692 free(plane->format_types, DRM_MEM_KMS);
693 drm_mode_object_put(dev, &plane->base);
694 /* if not added to a list, it must be a private plane */
695 if (!list_empty(&plane->head)) {
696 list_del(&plane->head);
697 dev->mode_config.num_plane--;
698 }
699 sx_xunlock(&dev->mode_config.mutex);
700 }
701 EXPORT_SYMBOL(drm_plane_cleanup);
702
703 /**
704 * drm_mode_create - create a new display mode
705 * @dev: DRM device
706 *
707 * LOCKING:
708 * Caller must hold DRM mode_config lock.
709 *
710 * Create a new drm_display_mode, give it an ID, and return it.
711 *
712 * RETURNS:
713 * Pointer to new mode on success, NULL on error.
714 */
drm_mode_create(struct drm_device * dev)715 struct drm_display_mode *drm_mode_create(struct drm_device *dev)
716 {
717 struct drm_display_mode *nmode;
718
719 nmode = malloc(sizeof(struct drm_display_mode), DRM_MEM_KMS,
720 M_WAITOK | M_ZERO);
721
722 if (drm_mode_object_get(dev, &nmode->base, DRM_MODE_OBJECT_MODE)) {
723 free(nmode, DRM_MEM_KMS);
724 return NULL;
725 }
726
727 return nmode;
728 }
729 EXPORT_SYMBOL(drm_mode_create);
730
731 /**
732 * drm_mode_destroy - remove a mode
733 * @dev: DRM device
734 * @mode: mode to remove
735 *
736 * LOCKING:
737 * Caller must hold mode config lock.
738 *
739 * Free @mode's unique identifier, then free it.
740 */
drm_mode_destroy(struct drm_device * dev,struct drm_display_mode * mode)741 void drm_mode_destroy(struct drm_device *dev, struct drm_display_mode *mode)
742 {
743 if (!mode)
744 return;
745
746 drm_mode_object_put(dev, &mode->base);
747
748 free(mode, DRM_MEM_KMS);
749 }
750 EXPORT_SYMBOL(drm_mode_destroy);
751
drm_mode_create_standard_connector_properties(struct drm_device * dev)752 static int drm_mode_create_standard_connector_properties(struct drm_device *dev)
753 {
754 struct drm_property *edid;
755 struct drm_property *dpms;
756
757 /*
758 * Standard properties (apply to all connectors)
759 */
760 edid = drm_property_create(dev, DRM_MODE_PROP_BLOB |
761 DRM_MODE_PROP_IMMUTABLE,
762 "EDID", 0);
763 dev->mode_config.edid_property = edid;
764
765 dpms = drm_property_create_enum(dev, 0,
766 "DPMS", drm_dpms_enum_list,
767 ARRAY_SIZE(drm_dpms_enum_list));
768 dev->mode_config.dpms_property = dpms;
769
770 return 0;
771 }
772
773 /**
774 * drm_mode_create_dvi_i_properties - create DVI-I specific connector properties
775 * @dev: DRM device
776 *
777 * Called by a driver the first time a DVI-I connector is made.
778 */
drm_mode_create_dvi_i_properties(struct drm_device * dev)779 int drm_mode_create_dvi_i_properties(struct drm_device *dev)
780 {
781 struct drm_property *dvi_i_selector;
782 struct drm_property *dvi_i_subconnector;
783
784 if (dev->mode_config.dvi_i_select_subconnector_property)
785 return 0;
786
787 dvi_i_selector =
788 drm_property_create_enum(dev, 0,
789 "select subconnector",
790 drm_dvi_i_select_enum_list,
791 ARRAY_SIZE(drm_dvi_i_select_enum_list));
792 dev->mode_config.dvi_i_select_subconnector_property = dvi_i_selector;
793
794 dvi_i_subconnector = drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE,
795 "subconnector",
796 drm_dvi_i_subconnector_enum_list,
797 ARRAY_SIZE(drm_dvi_i_subconnector_enum_list));
798 dev->mode_config.dvi_i_subconnector_property = dvi_i_subconnector;
799
800 return 0;
801 }
802 EXPORT_SYMBOL(drm_mode_create_dvi_i_properties);
803
804 /**
805 * drm_create_tv_properties - create TV specific connector properties
806 * @dev: DRM device
807 * @num_modes: number of different TV formats (modes) supported
808 * @modes: array of pointers to strings containing name of each format
809 *
810 * Called by a driver's TV initialization routine, this function creates
811 * the TV specific connector properties for a given device. Caller is
812 * responsible for allocating a list of format names and passing them to
813 * this routine.
814 */
drm_mode_create_tv_properties(struct drm_device * dev,int num_modes,char * modes[])815 int drm_mode_create_tv_properties(struct drm_device *dev, int num_modes,
816 char *modes[])
817 {
818 struct drm_property *tv_selector;
819 struct drm_property *tv_subconnector;
820 int i;
821
822 if (dev->mode_config.tv_select_subconnector_property)
823 return 0;
824
825 /*
826 * Basic connector properties
827 */
828 tv_selector = drm_property_create_enum(dev, 0,
829 "select subconnector",
830 drm_tv_select_enum_list,
831 ARRAY_SIZE(drm_tv_select_enum_list));
832 dev->mode_config.tv_select_subconnector_property = tv_selector;
833
834 tv_subconnector =
835 drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE,
836 "subconnector",
837 drm_tv_subconnector_enum_list,
838 ARRAY_SIZE(drm_tv_subconnector_enum_list));
839 dev->mode_config.tv_subconnector_property = tv_subconnector;
840
841 /*
842 * Other, TV specific properties: margins & TV modes.
843 */
844 dev->mode_config.tv_left_margin_property =
845 drm_property_create_range(dev, 0, "left margin", 0, 100);
846
847 dev->mode_config.tv_right_margin_property =
848 drm_property_create_range(dev, 0, "right margin", 0, 100);
849
850 dev->mode_config.tv_top_margin_property =
851 drm_property_create_range(dev, 0, "top margin", 0, 100);
852
853 dev->mode_config.tv_bottom_margin_property =
854 drm_property_create_range(dev, 0, "bottom margin", 0, 100);
855
856 dev->mode_config.tv_mode_property =
857 drm_property_create(dev, DRM_MODE_PROP_ENUM,
858 "mode", num_modes);
859 for (i = 0; i < num_modes; i++)
860 drm_property_add_enum(dev->mode_config.tv_mode_property, i,
861 i, modes[i]);
862
863 dev->mode_config.tv_brightness_property =
864 drm_property_create_range(dev, 0, "brightness", 0, 100);
865
866 dev->mode_config.tv_contrast_property =
867 drm_property_create_range(dev, 0, "contrast", 0, 100);
868
869 dev->mode_config.tv_flicker_reduction_property =
870 drm_property_create_range(dev, 0, "flicker reduction", 0, 100);
871
872 dev->mode_config.tv_overscan_property =
873 drm_property_create_range(dev, 0, "overscan", 0, 100);
874
875 dev->mode_config.tv_saturation_property =
876 drm_property_create_range(dev, 0, "saturation", 0, 100);
877
878 dev->mode_config.tv_hue_property =
879 drm_property_create_range(dev, 0, "hue", 0, 100);
880
881 return 0;
882 }
883 EXPORT_SYMBOL(drm_mode_create_tv_properties);
884
885 /**
886 * drm_mode_create_scaling_mode_property - create scaling mode property
887 * @dev: DRM device
888 *
889 * Called by a driver the first time it's needed, must be attached to desired
890 * connectors.
891 */
drm_mode_create_scaling_mode_property(struct drm_device * dev)892 int drm_mode_create_scaling_mode_property(struct drm_device *dev)
893 {
894 struct drm_property *scaling_mode;
895
896 if (dev->mode_config.scaling_mode_property)
897 return 0;
898
899 scaling_mode =
900 drm_property_create_enum(dev, 0, "scaling mode",
901 drm_scaling_mode_enum_list,
902 ARRAY_SIZE(drm_scaling_mode_enum_list));
903
904 dev->mode_config.scaling_mode_property = scaling_mode;
905
906 return 0;
907 }
908 EXPORT_SYMBOL(drm_mode_create_scaling_mode_property);
909
910 /**
911 * drm_mode_create_dithering_property - create dithering property
912 * @dev: DRM device
913 *
914 * Called by a driver the first time it's needed, must be attached to desired
915 * connectors.
916 */
drm_mode_create_dithering_property(struct drm_device * dev)917 int drm_mode_create_dithering_property(struct drm_device *dev)
918 {
919 struct drm_property *dithering_mode;
920
921 if (dev->mode_config.dithering_mode_property)
922 return 0;
923
924 dithering_mode =
925 drm_property_create_enum(dev, 0, "dithering",
926 drm_dithering_mode_enum_list,
927 ARRAY_SIZE(drm_dithering_mode_enum_list));
928 dev->mode_config.dithering_mode_property = dithering_mode;
929
930 return 0;
931 }
932 EXPORT_SYMBOL(drm_mode_create_dithering_property);
933
934 /**
935 * drm_mode_create_dirty_property - create dirty property
936 * @dev: DRM device
937 *
938 * Called by a driver the first time it's needed, must be attached to desired
939 * connectors.
940 */
drm_mode_create_dirty_info_property(struct drm_device * dev)941 int drm_mode_create_dirty_info_property(struct drm_device *dev)
942 {
943 struct drm_property *dirty_info;
944
945 if (dev->mode_config.dirty_info_property)
946 return 0;
947
948 dirty_info =
949 drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE,
950 "dirty",
951 drm_dirty_info_enum_list,
952 ARRAY_SIZE(drm_dirty_info_enum_list));
953 dev->mode_config.dirty_info_property = dirty_info;
954
955 return 0;
956 }
957 EXPORT_SYMBOL(drm_mode_create_dirty_info_property);
958
959 /**
960 * drm_mode_config_init - initialize DRM mode_configuration structure
961 * @dev: DRM device
962 *
963 * LOCKING:
964 * None, should happen single threaded at init time.
965 *
966 * Initialize @dev's mode_config structure, used for tracking the graphics
967 * configuration of @dev.
968 */
drm_mode_config_init(struct drm_device * dev)969 void drm_mode_config_init(struct drm_device *dev)
970 {
971 sx_init(&dev->mode_config.mutex, "kmslk");
972 INIT_LIST_HEAD(&dev->mode_config.fb_list);
973 INIT_LIST_HEAD(&dev->mode_config.crtc_list);
974 INIT_LIST_HEAD(&dev->mode_config.connector_list);
975 INIT_LIST_HEAD(&dev->mode_config.encoder_list);
976 INIT_LIST_HEAD(&dev->mode_config.property_list);
977 INIT_LIST_HEAD(&dev->mode_config.property_blob_list);
978 INIT_LIST_HEAD(&dev->mode_config.plane_list);
979 drm_gem_names_init(&dev->mode_config.crtc_names);
980
981 sx_xlock(&dev->mode_config.mutex);
982 drm_mode_create_standard_connector_properties(dev);
983 sx_xunlock(&dev->mode_config.mutex);
984
985 /* Just to be sure */
986 dev->mode_config.num_fb = 0;
987 dev->mode_config.num_connector = 0;
988 dev->mode_config.num_crtc = 0;
989 dev->mode_config.num_encoder = 0;
990 }
991 EXPORT_SYMBOL(drm_mode_config_init);
992
drm_mode_group_init(struct drm_device * dev,struct drm_mode_group * group)993 int drm_mode_group_init(struct drm_device *dev, struct drm_mode_group *group)
994 {
995 uint32_t total_objects = 0;
996
997 total_objects += dev->mode_config.num_crtc;
998 total_objects += dev->mode_config.num_connector;
999 total_objects += dev->mode_config.num_encoder;
1000
1001 group->id_list = malloc(total_objects * sizeof(uint32_t),
1002 DRM_MEM_KMS, M_WAITOK | M_ZERO);
1003 group->num_crtcs = 0;
1004 group->num_connectors = 0;
1005 group->num_encoders = 0;
1006 return 0;
1007 }
1008
drm_mode_group_free(struct drm_mode_group * group)1009 void drm_mode_group_free(struct drm_mode_group *group)
1010 {
1011 free(group->id_list, DRM_MEM_KMS);
1012 group->id_list = NULL;
1013 }
1014
drm_mode_group_init_legacy_group(struct drm_device * dev,struct drm_mode_group * group)1015 int drm_mode_group_init_legacy_group(struct drm_device *dev,
1016 struct drm_mode_group *group)
1017 {
1018 struct drm_crtc *crtc;
1019 struct drm_encoder *encoder;
1020 struct drm_connector *connector;
1021 int ret;
1022
1023 if ((ret = drm_mode_group_init(dev, group)))
1024 return ret;
1025
1026 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
1027 group->id_list[group->num_crtcs++] = crtc->base.id;
1028
1029 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head)
1030 group->id_list[group->num_crtcs + group->num_encoders++] =
1031 encoder->base.id;
1032
1033 list_for_each_entry(connector, &dev->mode_config.connector_list, head)
1034 group->id_list[group->num_crtcs + group->num_encoders +
1035 group->num_connectors++] = connector->base.id;
1036
1037 return 0;
1038 }
1039 EXPORT_SYMBOL(drm_mode_group_init_legacy_group);
1040
1041 /**
1042 * drm_mode_config_cleanup - free up DRM mode_config info
1043 * @dev: DRM device
1044 *
1045 * LOCKING:
1046 * Caller must hold mode config lock.
1047 *
1048 * Free up all the connectors and CRTCs associated with this DRM device, then
1049 * free up the framebuffers and associated buffer objects.
1050 *
1051 * FIXME: cleanup any dangling user buffer objects too
1052 */
drm_mode_config_cleanup(struct drm_device * dev)1053 void drm_mode_config_cleanup(struct drm_device *dev)
1054 {
1055 struct drm_connector *connector, *ot;
1056 struct drm_crtc *crtc, *ct;
1057 struct drm_encoder *encoder, *enct;
1058 struct drm_framebuffer *fb, *fbt;
1059 struct drm_property *property, *pt;
1060 struct drm_property_blob *blob, *bt;
1061 struct drm_plane *plane, *plt;
1062
1063 list_for_each_entry_safe(encoder, enct, &dev->mode_config.encoder_list,
1064 head) {
1065 encoder->funcs->destroy(encoder);
1066 }
1067
1068 list_for_each_entry_safe(connector, ot,
1069 &dev->mode_config.connector_list, head) {
1070 connector->funcs->destroy(connector);
1071 }
1072
1073 list_for_each_entry_safe(property, pt, &dev->mode_config.property_list,
1074 head) {
1075 drm_property_destroy(dev, property);
1076 }
1077
1078 list_for_each_entry_safe(blob, bt, &dev->mode_config.property_blob_list,
1079 head) {
1080 drm_property_destroy_blob(dev, blob);
1081 }
1082
1083 list_for_each_entry_safe(fb, fbt, &dev->mode_config.fb_list, head) {
1084 drm_framebuffer_remove(fb);
1085 }
1086
1087 list_for_each_entry_safe(plane, plt, &dev->mode_config.plane_list,
1088 head) {
1089 plane->funcs->destroy(plane);
1090 }
1091
1092 list_for_each_entry_safe(crtc, ct, &dev->mode_config.crtc_list, head) {
1093 crtc->funcs->destroy(crtc);
1094 }
1095
1096 drm_gem_names_fini(&dev->mode_config.crtc_names);
1097 }
1098 EXPORT_SYMBOL(drm_mode_config_cleanup);
1099
1100 /**
1101 * drm_crtc_convert_to_umode - convert a drm_display_mode into a modeinfo
1102 * @out: drm_mode_modeinfo struct to return to the user
1103 * @in: drm_display_mode to use
1104 *
1105 * LOCKING:
1106 * None.
1107 *
1108 * Convert a drm_display_mode into a drm_mode_modeinfo structure to return to
1109 * the user.
1110 */
drm_crtc_convert_to_umode(struct drm_mode_modeinfo * out,const struct drm_display_mode * in)1111 static void drm_crtc_convert_to_umode(struct drm_mode_modeinfo *out,
1112 const struct drm_display_mode *in)
1113 {
1114 if (in->hdisplay > USHRT_MAX || in->hsync_start > USHRT_MAX ||
1115 in->hsync_end > USHRT_MAX || in->htotal > USHRT_MAX ||
1116 in->hskew > USHRT_MAX || in->vdisplay > USHRT_MAX ||
1117 in->vsync_start > USHRT_MAX || in->vsync_end > USHRT_MAX ||
1118 in->vtotal > USHRT_MAX || in->vscan > USHRT_MAX)
1119 DRM_WARNING("timing values too large for mode info\n");
1120
1121 out->clock = in->clock;
1122 out->hdisplay = in->hdisplay;
1123 out->hsync_start = in->hsync_start;
1124 out->hsync_end = in->hsync_end;
1125 out->htotal = in->htotal;
1126 out->hskew = in->hskew;
1127 out->vdisplay = in->vdisplay;
1128 out->vsync_start = in->vsync_start;
1129 out->vsync_end = in->vsync_end;
1130 out->vtotal = in->vtotal;
1131 out->vscan = in->vscan;
1132 out->vrefresh = in->vrefresh;
1133 out->flags = in->flags;
1134 out->type = in->type;
1135 strncpy(out->name, in->name, DRM_DISPLAY_MODE_LEN);
1136 out->name[DRM_DISPLAY_MODE_LEN-1] = 0;
1137 }
1138
1139 /**
1140 * drm_crtc_convert_to_umode - convert a modeinfo into a drm_display_mode
1141 * @out: drm_display_mode to return to the user
1142 * @in: drm_mode_modeinfo to use
1143 *
1144 * LOCKING:
1145 * None.
1146 *
1147 * Convert a drm_mode_modeinfo into a drm_display_mode structure to return to
1148 * the caller.
1149 *
1150 * RETURNS:
1151 * Zero on success, errno on failure.
1152 */
drm_crtc_convert_umode(struct drm_display_mode * out,const struct drm_mode_modeinfo * in)1153 static int drm_crtc_convert_umode(struct drm_display_mode *out,
1154 const struct drm_mode_modeinfo *in)
1155 {
1156 if (in->clock > INT_MAX || in->vrefresh > INT_MAX)
1157 return -ERANGE;
1158
1159 out->clock = in->clock;
1160 out->hdisplay = in->hdisplay;
1161 out->hsync_start = in->hsync_start;
1162 out->hsync_end = in->hsync_end;
1163 out->htotal = in->htotal;
1164 out->hskew = in->hskew;
1165 out->vdisplay = in->vdisplay;
1166 out->vsync_start = in->vsync_start;
1167 out->vsync_end = in->vsync_end;
1168 out->vtotal = in->vtotal;
1169 out->vscan = in->vscan;
1170 out->vrefresh = in->vrefresh;
1171 out->flags = in->flags;
1172 out->type = in->type;
1173 strncpy(out->name, in->name, DRM_DISPLAY_MODE_LEN);
1174 out->name[DRM_DISPLAY_MODE_LEN-1] = 0;
1175
1176 return 0;
1177 }
1178
1179 /**
1180 * drm_mode_getresources - get graphics configuration
1181 * @inode: inode from the ioctl
1182 * @filp: file * from the ioctl
1183 * @cmd: cmd from ioctl
1184 * @arg: arg from ioctl
1185 *
1186 * LOCKING:
1187 * Takes mode config lock.
1188 *
1189 * Construct a set of configuration description structures and return
1190 * them to the user, including CRTC, connector and framebuffer configuration.
1191 *
1192 * Called by the user via ioctl.
1193 *
1194 * RETURNS:
1195 * Zero on success, errno on failure.
1196 */
drm_mode_getresources(struct drm_device * dev,void * data,struct drm_file * file_priv)1197 int drm_mode_getresources(struct drm_device *dev, void *data,
1198 struct drm_file *file_priv)
1199 {
1200 struct drm_mode_card_res *card_res = data;
1201 struct list_head *lh;
1202 struct drm_framebuffer *fb;
1203 struct drm_connector *connector;
1204 struct drm_crtc *crtc;
1205 struct drm_encoder *encoder;
1206 int ret = 0;
1207 int connector_count = 0;
1208 int crtc_count = 0;
1209 int fb_count = 0;
1210 int encoder_count = 0;
1211 int copied = 0, i;
1212 uint32_t __user *fb_id;
1213 uint32_t __user *crtc_id;
1214 uint32_t __user *connector_id;
1215 uint32_t __user *encoder_id;
1216 struct drm_mode_group *mode_group;
1217
1218 if (!drm_core_check_feature(dev, DRIVER_MODESET))
1219 return -EINVAL;
1220
1221 sx_xlock(&dev->mode_config.mutex);
1222
1223 /*
1224 * For the non-control nodes we need to limit the list of resources
1225 * by IDs in the group list for this node
1226 */
1227 list_for_each(lh, &file_priv->fbs)
1228 fb_count++;
1229
1230 mode_group = &file_priv->master->minor->mode_group;
1231 if (file_priv->master->minor->type == DRM_MINOR_CONTROL) {
1232
1233 list_for_each(lh, &dev->mode_config.crtc_list)
1234 crtc_count++;
1235
1236 list_for_each(lh, &dev->mode_config.connector_list)
1237 connector_count++;
1238
1239 list_for_each(lh, &dev->mode_config.encoder_list)
1240 encoder_count++;
1241 } else {
1242
1243 crtc_count = mode_group->num_crtcs;
1244 connector_count = mode_group->num_connectors;
1245 encoder_count = mode_group->num_encoders;
1246 }
1247
1248 card_res->max_height = dev->mode_config.max_height;
1249 card_res->min_height = dev->mode_config.min_height;
1250 card_res->max_width = dev->mode_config.max_width;
1251 card_res->min_width = dev->mode_config.min_width;
1252
1253 /* handle this in 4 parts */
1254 /* FBs */
1255 if (card_res->count_fbs >= fb_count) {
1256 copied = 0;
1257 fb_id = (uint32_t __user *)(unsigned long)card_res->fb_id_ptr;
1258 list_for_each_entry(fb, &file_priv->fbs, filp_head) {
1259 if (put_user(fb->base.id, fb_id + copied)) {
1260 ret = -EFAULT;
1261 goto out;
1262 }
1263 copied++;
1264 }
1265 }
1266 card_res->count_fbs = fb_count;
1267
1268 /* CRTCs */
1269 if (card_res->count_crtcs >= crtc_count) {
1270 copied = 0;
1271 crtc_id = (uint32_t __user *)(unsigned long)card_res->crtc_id_ptr;
1272 if (file_priv->master->minor->type == DRM_MINOR_CONTROL) {
1273 list_for_each_entry(crtc, &dev->mode_config.crtc_list,
1274 head) {
1275 DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id);
1276 if (put_user(crtc->base.id, crtc_id + copied)) {
1277 ret = -EFAULT;
1278 goto out;
1279 }
1280 copied++;
1281 }
1282 } else {
1283 for (i = 0; i < mode_group->num_crtcs; i++) {
1284 if (put_user(mode_group->id_list[i],
1285 crtc_id + copied)) {
1286 ret = -EFAULT;
1287 goto out;
1288 }
1289 copied++;
1290 }
1291 }
1292 }
1293 card_res->count_crtcs = crtc_count;
1294
1295 /* Encoders */
1296 if (card_res->count_encoders >= encoder_count) {
1297 copied = 0;
1298 encoder_id = (uint32_t __user *)(unsigned long)card_res->encoder_id_ptr;
1299 if (file_priv->master->minor->type == DRM_MINOR_CONTROL) {
1300 list_for_each_entry(encoder,
1301 &dev->mode_config.encoder_list,
1302 head) {
1303 DRM_DEBUG_KMS("[ENCODER:%d:%s]\n", encoder->base.id,
1304 drm_get_encoder_name(encoder));
1305 if (put_user(encoder->base.id, encoder_id +
1306 copied)) {
1307 ret = -EFAULT;
1308 goto out;
1309 }
1310 copied++;
1311 }
1312 } else {
1313 for (i = mode_group->num_crtcs; i < mode_group->num_crtcs + mode_group->num_encoders; i++) {
1314 if (put_user(mode_group->id_list[i],
1315 encoder_id + copied)) {
1316 ret = -EFAULT;
1317 goto out;
1318 }
1319 copied++;
1320 }
1321
1322 }
1323 }
1324 card_res->count_encoders = encoder_count;
1325
1326 /* Connectors */
1327 if (card_res->count_connectors >= connector_count) {
1328 copied = 0;
1329 connector_id = (uint32_t __user *)(unsigned long)card_res->connector_id_ptr;
1330 if (file_priv->master->minor->type == DRM_MINOR_CONTROL) {
1331 list_for_each_entry(connector,
1332 &dev->mode_config.connector_list,
1333 head) {
1334 DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
1335 connector->base.id,
1336 drm_get_connector_name(connector));
1337 if (put_user(connector->base.id,
1338 connector_id + copied)) {
1339 ret = -EFAULT;
1340 goto out;
1341 }
1342 copied++;
1343 }
1344 } else {
1345 int start = mode_group->num_crtcs +
1346 mode_group->num_encoders;
1347 for (i = start; i < start + mode_group->num_connectors; i++) {
1348 if (put_user(mode_group->id_list[i],
1349 connector_id + copied)) {
1350 ret = -EFAULT;
1351 goto out;
1352 }
1353 copied++;
1354 }
1355 }
1356 }
1357 card_res->count_connectors = connector_count;
1358
1359 DRM_DEBUG_KMS("CRTC[%d] CONNECTORS[%d] ENCODERS[%d]\n", card_res->count_crtcs,
1360 card_res->count_connectors, card_res->count_encoders);
1361
1362 out:
1363 sx_xunlock(&dev->mode_config.mutex);
1364 return ret;
1365 }
1366
1367 /**
1368 * drm_mode_getcrtc - get CRTC configuration
1369 * @inode: inode from the ioctl
1370 * @filp: file * from the ioctl
1371 * @cmd: cmd from ioctl
1372 * @arg: arg from ioctl
1373 *
1374 * LOCKING:
1375 * Takes mode config lock.
1376 *
1377 * Construct a CRTC configuration structure to return to the user.
1378 *
1379 * Called by the user via ioctl.
1380 *
1381 * RETURNS:
1382 * Zero on success, errno on failure.
1383 */
drm_mode_getcrtc(struct drm_device * dev,void * data,struct drm_file * file_priv)1384 int drm_mode_getcrtc(struct drm_device *dev,
1385 void *data, struct drm_file *file_priv)
1386 {
1387 struct drm_mode_crtc *crtc_resp = data;
1388 struct drm_crtc *crtc;
1389 struct drm_mode_object *obj;
1390 int ret = 0;
1391
1392 if (!drm_core_check_feature(dev, DRIVER_MODESET))
1393 return -EINVAL;
1394
1395 sx_xlock(&dev->mode_config.mutex);
1396
1397 obj = drm_mode_object_find(dev, crtc_resp->crtc_id,
1398 DRM_MODE_OBJECT_CRTC);
1399 if (!obj) {
1400 ret = -EINVAL;
1401 goto out;
1402 }
1403 crtc = obj_to_crtc(obj);
1404
1405 crtc_resp->x = crtc->x;
1406 crtc_resp->y = crtc->y;
1407 crtc_resp->gamma_size = crtc->gamma_size;
1408 if (crtc->fb)
1409 crtc_resp->fb_id = crtc->fb->base.id;
1410 else
1411 crtc_resp->fb_id = 0;
1412
1413 if (crtc->enabled) {
1414
1415 drm_crtc_convert_to_umode(&crtc_resp->mode, &crtc->mode);
1416 crtc_resp->mode_valid = 1;
1417
1418 } else {
1419 crtc_resp->mode_valid = 0;
1420 }
1421
1422 out:
1423 sx_xunlock(&dev->mode_config.mutex);
1424 return ret;
1425 }
1426
1427 /**
1428 * drm_mode_getconnector - get connector configuration
1429 * @inode: inode from the ioctl
1430 * @filp: file * from the ioctl
1431 * @cmd: cmd from ioctl
1432 * @arg: arg from ioctl
1433 *
1434 * LOCKING:
1435 * Takes mode config lock.
1436 *
1437 * Construct a connector configuration structure to return to the user.
1438 *
1439 * Called by the user via ioctl.
1440 *
1441 * RETURNS:
1442 * Zero on success, errno on failure.
1443 */
drm_mode_getconnector(struct drm_device * dev,void * data,struct drm_file * file_priv)1444 int drm_mode_getconnector(struct drm_device *dev, void *data,
1445 struct drm_file *file_priv)
1446 {
1447 struct drm_mode_get_connector *out_resp = data;
1448 struct drm_mode_object *obj;
1449 struct drm_connector *connector;
1450 struct drm_display_mode *mode;
1451 int mode_count = 0;
1452 int props_count = 0;
1453 int encoders_count = 0;
1454 int ret = 0;
1455 int copied = 0;
1456 int i;
1457 struct drm_mode_modeinfo u_mode;
1458 struct drm_mode_modeinfo __user *mode_ptr;
1459 uint32_t __user *prop_ptr;
1460 uint64_t __user *prop_values;
1461 uint32_t __user *encoder_ptr;
1462
1463 if (!drm_core_check_feature(dev, DRIVER_MODESET))
1464 return -EINVAL;
1465
1466 memset(&u_mode, 0, sizeof(struct drm_mode_modeinfo));
1467
1468 DRM_DEBUG_KMS("[CONNECTOR:%d:?]\n", out_resp->connector_id);
1469
1470 sx_xlock(&dev->mode_config.mutex);
1471
1472 obj = drm_mode_object_find(dev, out_resp->connector_id,
1473 DRM_MODE_OBJECT_CONNECTOR);
1474 if (!obj) {
1475 ret = -EINVAL;
1476 goto out;
1477 }
1478 connector = obj_to_connector(obj);
1479
1480 props_count = connector->properties.count;
1481
1482 for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
1483 if (connector->encoder_ids[i] != 0) {
1484 encoders_count++;
1485 }
1486 }
1487
1488 if (out_resp->count_modes == 0) {
1489 connector->funcs->fill_modes(connector,
1490 dev->mode_config.max_width,
1491 dev->mode_config.max_height);
1492 }
1493
1494 /* delayed so we get modes regardless of pre-fill_modes state */
1495 list_for_each_entry(mode, &connector->modes, head)
1496 mode_count++;
1497
1498 out_resp->connector_id = connector->base.id;
1499 out_resp->connector_type = connector->connector_type;
1500 out_resp->connector_type_id = connector->connector_type_id;
1501 out_resp->mm_width = connector->display_info.width_mm;
1502 out_resp->mm_height = connector->display_info.height_mm;
1503 out_resp->subpixel = connector->display_info.subpixel_order;
1504 out_resp->connection = connector->status;
1505 if (connector->encoder)
1506 out_resp->encoder_id = connector->encoder->base.id;
1507 else
1508 out_resp->encoder_id = 0;
1509
1510 /*
1511 * This ioctl is called twice, once to determine how much space is
1512 * needed, and the 2nd time to fill it.
1513 */
1514 if ((out_resp->count_modes >= mode_count) && mode_count) {
1515 copied = 0;
1516 mode_ptr = (struct drm_mode_modeinfo __user *)(unsigned long)out_resp->modes_ptr;
1517 list_for_each_entry(mode, &connector->modes, head) {
1518 drm_crtc_convert_to_umode(&u_mode, mode);
1519 if (copy_to_user(mode_ptr + copied,
1520 &u_mode, sizeof(u_mode))) {
1521 ret = -EFAULT;
1522 goto out;
1523 }
1524 copied++;
1525 }
1526 }
1527 out_resp->count_modes = mode_count;
1528
1529 if ((out_resp->count_props >= props_count) && props_count) {
1530 copied = 0;
1531 prop_ptr = (uint32_t __user *)(unsigned long)(out_resp->props_ptr);
1532 prop_values = (uint64_t __user *)(unsigned long)(out_resp->prop_values_ptr);
1533 for (i = 0; i < connector->properties.count; i++) {
1534 if (put_user(connector->properties.ids[i],
1535 prop_ptr + copied)) {
1536 ret = -EFAULT;
1537 goto out;
1538 }
1539
1540 if (put_user(connector->properties.values[i],
1541 prop_values + copied)) {
1542 ret = -EFAULT;
1543 goto out;
1544 }
1545 copied++;
1546 }
1547 }
1548 out_resp->count_props = props_count;
1549
1550 if ((out_resp->count_encoders >= encoders_count) && encoders_count) {
1551 copied = 0;
1552 encoder_ptr = (uint32_t __user *)(unsigned long)(out_resp->encoders_ptr);
1553 for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
1554 if (connector->encoder_ids[i] != 0) {
1555 if (put_user(connector->encoder_ids[i],
1556 encoder_ptr + copied)) {
1557 ret = -EFAULT;
1558 goto out;
1559 }
1560 copied++;
1561 }
1562 }
1563 }
1564 out_resp->count_encoders = encoders_count;
1565
1566 out:
1567 sx_xunlock(&dev->mode_config.mutex);
1568 return ret;
1569 }
1570
drm_mode_getencoder(struct drm_device * dev,void * data,struct drm_file * file_priv)1571 int drm_mode_getencoder(struct drm_device *dev, void *data,
1572 struct drm_file *file_priv)
1573 {
1574 struct drm_mode_get_encoder *enc_resp = data;
1575 struct drm_mode_object *obj;
1576 struct drm_encoder *encoder;
1577 int ret = 0;
1578
1579 if (!drm_core_check_feature(dev, DRIVER_MODESET))
1580 return -EINVAL;
1581
1582 sx_xlock(&dev->mode_config.mutex);
1583 obj = drm_mode_object_find(dev, enc_resp->encoder_id,
1584 DRM_MODE_OBJECT_ENCODER);
1585 if (!obj) {
1586 ret = -EINVAL;
1587 goto out;
1588 }
1589 encoder = obj_to_encoder(obj);
1590
1591 if (encoder->crtc)
1592 enc_resp->crtc_id = encoder->crtc->base.id;
1593 else
1594 enc_resp->crtc_id = 0;
1595 enc_resp->encoder_type = encoder->encoder_type;
1596 enc_resp->encoder_id = encoder->base.id;
1597 enc_resp->possible_crtcs = encoder->possible_crtcs;
1598 enc_resp->possible_clones = encoder->possible_clones;
1599
1600 out:
1601 sx_xunlock(&dev->mode_config.mutex);
1602 return ret;
1603 }
1604
1605 /**
1606 * drm_mode_getplane_res - get plane info
1607 * @dev: DRM device
1608 * @data: ioctl data
1609 * @file_priv: DRM file info
1610 *
1611 * LOCKING:
1612 * Takes mode config lock.
1613 *
1614 * Return an plane count and set of IDs.
1615 */
drm_mode_getplane_res(struct drm_device * dev,void * data,struct drm_file * file_priv)1616 int drm_mode_getplane_res(struct drm_device *dev, void *data,
1617 struct drm_file *file_priv)
1618 {
1619 struct drm_mode_get_plane_res *plane_resp = data;
1620 struct drm_mode_config *config;
1621 struct drm_plane *plane;
1622 uint32_t __user *plane_ptr;
1623 int copied = 0, ret = 0;
1624
1625 if (!drm_core_check_feature(dev, DRIVER_MODESET))
1626 return -EINVAL;
1627
1628 sx_xlock(&dev->mode_config.mutex);
1629 config = &dev->mode_config;
1630
1631 /*
1632 * This ioctl is called twice, once to determine how much space is
1633 * needed, and the 2nd time to fill it.
1634 */
1635 if (config->num_plane &&
1636 (plane_resp->count_planes >= config->num_plane)) {
1637 plane_ptr = (uint32_t __user *)(unsigned long)plane_resp->plane_id_ptr;
1638
1639 list_for_each_entry(plane, &config->plane_list, head) {
1640 if (put_user(plane->base.id, plane_ptr + copied)) {
1641 ret = -EFAULT;
1642 goto out;
1643 }
1644 copied++;
1645 }
1646 }
1647 plane_resp->count_planes = config->num_plane;
1648
1649 out:
1650 sx_xunlock(&dev->mode_config.mutex);
1651 return ret;
1652 }
1653
1654 /**
1655 * drm_mode_getplane - get plane info
1656 * @dev: DRM device
1657 * @data: ioctl data
1658 * @file_priv: DRM file info
1659 *
1660 * LOCKING:
1661 * Takes mode config lock.
1662 *
1663 * Return plane info, including formats supported, gamma size, any
1664 * current fb, etc.
1665 */
drm_mode_getplane(struct drm_device * dev,void * data,struct drm_file * file_priv)1666 int drm_mode_getplane(struct drm_device *dev, void *data,
1667 struct drm_file *file_priv)
1668 {
1669 struct drm_mode_get_plane *plane_resp = data;
1670 struct drm_mode_object *obj;
1671 struct drm_plane *plane;
1672 uint32_t __user *format_ptr;
1673 int ret = 0;
1674
1675 if (!drm_core_check_feature(dev, DRIVER_MODESET))
1676 return -EINVAL;
1677
1678 sx_xlock(&dev->mode_config.mutex);
1679 obj = drm_mode_object_find(dev, plane_resp->plane_id,
1680 DRM_MODE_OBJECT_PLANE);
1681 if (!obj) {
1682 ret = -ENOENT;
1683 goto out;
1684 }
1685 plane = obj_to_plane(obj);
1686
1687 if (plane->crtc)
1688 plane_resp->crtc_id = plane->crtc->base.id;
1689 else
1690 plane_resp->crtc_id = 0;
1691
1692 if (plane->fb)
1693 plane_resp->fb_id = plane->fb->base.id;
1694 else
1695 plane_resp->fb_id = 0;
1696
1697 plane_resp->plane_id = plane->base.id;
1698 plane_resp->possible_crtcs = plane->possible_crtcs;
1699 plane_resp->gamma_size = plane->gamma_size;
1700
1701 /*
1702 * This ioctl is called twice, once to determine how much space is
1703 * needed, and the 2nd time to fill it.
1704 */
1705 if (plane->format_count &&
1706 (plane_resp->count_format_types >= plane->format_count)) {
1707 format_ptr = (uint32_t __user *)(unsigned long)plane_resp->format_type_ptr;
1708 if (copy_to_user(format_ptr,
1709 plane->format_types,
1710 sizeof(uint32_t) * plane->format_count)) {
1711 ret = -EFAULT;
1712 goto out;
1713 }
1714 }
1715 plane_resp->count_format_types = plane->format_count;
1716
1717 out:
1718 sx_xunlock(&dev->mode_config.mutex);
1719 return ret;
1720 }
1721
1722 /**
1723 * drm_mode_setplane - set up or tear down an plane
1724 * @dev: DRM device
1725 * @data: ioctl data*
1726 * @file_prive: DRM file info
1727 *
1728 * LOCKING:
1729 * Takes mode config lock.
1730 *
1731 * Set plane info, including placement, fb, scaling, and other factors.
1732 * Or pass a NULL fb to disable.
1733 */
drm_mode_setplane(struct drm_device * dev,void * data,struct drm_file * file_priv)1734 int drm_mode_setplane(struct drm_device *dev, void *data,
1735 struct drm_file *file_priv)
1736 {
1737 struct drm_mode_set_plane *plane_req = data;
1738 struct drm_mode_object *obj;
1739 struct drm_plane *plane;
1740 struct drm_crtc *crtc;
1741 struct drm_framebuffer *fb;
1742 int ret = 0;
1743 unsigned int fb_width, fb_height;
1744 int i;
1745
1746 if (!drm_core_check_feature(dev, DRIVER_MODESET))
1747 return -EINVAL;
1748
1749 sx_xlock(&dev->mode_config.mutex);
1750
1751 /*
1752 * First, find the plane, crtc, and fb objects. If not available,
1753 * we don't bother to call the driver.
1754 */
1755 obj = drm_mode_object_find(dev, plane_req->plane_id,
1756 DRM_MODE_OBJECT_PLANE);
1757 if (!obj) {
1758 DRM_DEBUG_KMS("Unknown plane ID %d\n",
1759 plane_req->plane_id);
1760 ret = -ENOENT;
1761 goto out;
1762 }
1763 plane = obj_to_plane(obj);
1764
1765 /* No fb means shut it down */
1766 if (!plane_req->fb_id) {
1767 plane->funcs->disable_plane(plane);
1768 plane->crtc = NULL;
1769 plane->fb = NULL;
1770 goto out;
1771 }
1772
1773 obj = drm_mode_object_find(dev, plane_req->crtc_id,
1774 DRM_MODE_OBJECT_CRTC);
1775 if (!obj) {
1776 DRM_DEBUG_KMS("Unknown crtc ID %d\n",
1777 plane_req->crtc_id);
1778 ret = -ENOENT;
1779 goto out;
1780 }
1781 crtc = obj_to_crtc(obj);
1782
1783 obj = drm_mode_object_find(dev, plane_req->fb_id,
1784 DRM_MODE_OBJECT_FB);
1785 if (!obj) {
1786 DRM_DEBUG_KMS("Unknown framebuffer ID %d\n",
1787 plane_req->fb_id);
1788 ret = -ENOENT;
1789 goto out;
1790 }
1791 fb = obj_to_fb(obj);
1792
1793 /* Check whether this plane supports the fb pixel format. */
1794 for (i = 0; i < plane->format_count; i++)
1795 if (fb->pixel_format == plane->format_types[i])
1796 break;
1797 if (i == plane->format_count) {
1798 DRM_DEBUG_KMS("Invalid pixel format 0x%08x\n", fb->pixel_format);
1799 ret = -EINVAL;
1800 goto out;
1801 }
1802
1803 fb_width = fb->width << 16;
1804 fb_height = fb->height << 16;
1805
1806 /* Make sure source coordinates are inside the fb. */
1807 if (plane_req->src_w > fb_width ||
1808 plane_req->src_x > fb_width - plane_req->src_w ||
1809 plane_req->src_h > fb_height ||
1810 plane_req->src_y > fb_height - plane_req->src_h) {
1811 DRM_DEBUG_KMS("Invalid source coordinates "
1812 "%u.%06ux%u.%06u+%u.%06u+%u.%06u\n",
1813 plane_req->src_w >> 16,
1814 ((plane_req->src_w & 0xffff) * 15625) >> 10,
1815 plane_req->src_h >> 16,
1816 ((plane_req->src_h & 0xffff) * 15625) >> 10,
1817 plane_req->src_x >> 16,
1818 ((plane_req->src_x & 0xffff) * 15625) >> 10,
1819 plane_req->src_y >> 16,
1820 ((plane_req->src_y & 0xffff) * 15625) >> 10);
1821 ret = -ENOSPC;
1822 goto out;
1823 }
1824
1825 /* Give drivers some help against integer overflows */
1826 if (plane_req->crtc_w > INT_MAX ||
1827 plane_req->crtc_x > INT_MAX - (int32_t) plane_req->crtc_w ||
1828 plane_req->crtc_h > INT_MAX ||
1829 plane_req->crtc_y > INT_MAX - (int32_t) plane_req->crtc_h) {
1830 DRM_DEBUG_KMS("Invalid CRTC coordinates %ux%u+%d+%d\n",
1831 plane_req->crtc_w, plane_req->crtc_h,
1832 plane_req->crtc_x, plane_req->crtc_y);
1833 ret = -ERANGE;
1834 goto out;
1835 }
1836
1837 ret = plane->funcs->update_plane(plane, crtc, fb,
1838 plane_req->crtc_x, plane_req->crtc_y,
1839 plane_req->crtc_w, plane_req->crtc_h,
1840 plane_req->src_x, plane_req->src_y,
1841 plane_req->src_w, plane_req->src_h);
1842 if (!ret) {
1843 plane->crtc = crtc;
1844 plane->fb = fb;
1845 }
1846
1847 out:
1848 sx_xunlock(&dev->mode_config.mutex);
1849
1850 return ret;
1851 }
1852
1853 /**
1854 * drm_mode_setcrtc - set CRTC configuration
1855 * @inode: inode from the ioctl
1856 * @filp: file * from the ioctl
1857 * @cmd: cmd from ioctl
1858 * @arg: arg from ioctl
1859 *
1860 * LOCKING:
1861 * Takes mode config lock.
1862 *
1863 * Build a new CRTC configuration based on user request.
1864 *
1865 * Called by the user via ioctl.
1866 *
1867 * RETURNS:
1868 * Zero on success, errno on failure.
1869 */
drm_mode_setcrtc(struct drm_device * dev,void * data,struct drm_file * file_priv)1870 int drm_mode_setcrtc(struct drm_device *dev, void *data,
1871 struct drm_file *file_priv)
1872 {
1873 struct drm_mode_config *config = &dev->mode_config;
1874 struct drm_mode_crtc *crtc_req = data;
1875 struct drm_mode_object *obj;
1876 struct drm_crtc *crtc;
1877 struct drm_connector **connector_set = NULL, *connector;
1878 struct drm_framebuffer *fb = NULL;
1879 struct drm_display_mode *mode = NULL;
1880 struct drm_mode_set set;
1881 uint32_t __user *set_connectors_ptr;
1882 int ret;
1883 int i;
1884
1885 if (!drm_core_check_feature(dev, DRIVER_MODESET))
1886 return -EINVAL;
1887
1888 /* For some reason crtc x/y offsets are signed internally. */
1889 if (crtc_req->x > INT_MAX || crtc_req->y > INT_MAX)
1890 return -ERANGE;
1891
1892 sx_xlock(&dev->mode_config.mutex);
1893 obj = drm_mode_object_find(dev, crtc_req->crtc_id,
1894 DRM_MODE_OBJECT_CRTC);
1895 if (!obj) {
1896 DRM_DEBUG_KMS("Unknown CRTC ID %d\n", crtc_req->crtc_id);
1897 ret = -EINVAL;
1898 goto out;
1899 }
1900 crtc = obj_to_crtc(obj);
1901 DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id);
1902
1903 if (crtc_req->mode_valid) {
1904 int hdisplay, vdisplay;
1905 /* If we have a mode we need a framebuffer. */
1906 /* If we pass -1, set the mode with the currently bound fb */
1907 if (crtc_req->fb_id == -1) {
1908 if (!crtc->fb) {
1909 DRM_DEBUG_KMS("CRTC doesn't have current FB\n");
1910 ret = -EINVAL;
1911 goto out;
1912 }
1913 fb = crtc->fb;
1914 } else {
1915 obj = drm_mode_object_find(dev, crtc_req->fb_id,
1916 DRM_MODE_OBJECT_FB);
1917 if (!obj) {
1918 DRM_DEBUG_KMS("Unknown FB ID%d\n",
1919 crtc_req->fb_id);
1920 ret = -EINVAL;
1921 goto out;
1922 }
1923 fb = obj_to_fb(obj);
1924 }
1925
1926 mode = drm_mode_create(dev);
1927 if (!mode) {
1928 ret = -ENOMEM;
1929 goto out;
1930 }
1931
1932 ret = drm_crtc_convert_umode(mode, &crtc_req->mode);
1933 if (ret) {
1934 DRM_DEBUG_KMS("Invalid mode\n");
1935 goto out;
1936 }
1937
1938 drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
1939
1940 hdisplay = mode->hdisplay;
1941 vdisplay = mode->vdisplay;
1942
1943 if (crtc->invert_dimensions) {
1944 int tmp;
1945 tmp = vdisplay;
1946 vdisplay = hdisplay;
1947 hdisplay = tmp;
1948 }
1949
1950 if (hdisplay > fb->width ||
1951 vdisplay > fb->height ||
1952 crtc_req->x > fb->width - hdisplay ||
1953 crtc_req->y > fb->height - vdisplay) {
1954 DRM_DEBUG_KMS("Invalid fb size %ux%u for CRTC viewport %ux%u+%d+%d%s.\n",
1955 fb->width, fb->height,
1956 hdisplay, vdisplay, crtc_req->x, crtc_req->y,
1957 crtc->invert_dimensions ? " (inverted)" : "");
1958 ret = -ENOSPC;
1959 goto out;
1960 }
1961 }
1962
1963 if (crtc_req->count_connectors == 0 && mode) {
1964 DRM_DEBUG_KMS("Count connectors is 0 but mode set\n");
1965 ret = -EINVAL;
1966 goto out;
1967 }
1968
1969 if (crtc_req->count_connectors > 0 && (!mode || !fb)) {
1970 DRM_DEBUG_KMS("Count connectors is %d but no mode or fb set\n",
1971 crtc_req->count_connectors);
1972 ret = -EINVAL;
1973 goto out;
1974 }
1975
1976 if (crtc_req->count_connectors > 0) {
1977 u32 out_id;
1978
1979 /* Avoid unbounded kernel memory allocation */
1980 if (crtc_req->count_connectors > config->num_connector) {
1981 ret = -EINVAL;
1982 goto out;
1983 }
1984
1985 connector_set = malloc(crtc_req->count_connectors *
1986 sizeof(struct drm_connector *),
1987 DRM_MEM_KMS, M_WAITOK);
1988
1989 for (i = 0; i < crtc_req->count_connectors; i++) {
1990 set_connectors_ptr = (uint32_t __user *)(unsigned long)crtc_req->set_connectors_ptr;
1991 if (get_user(out_id, &set_connectors_ptr[i])) {
1992 ret = -EFAULT;
1993 goto out;
1994 }
1995
1996 obj = drm_mode_object_find(dev, out_id,
1997 DRM_MODE_OBJECT_CONNECTOR);
1998 if (!obj) {
1999 DRM_DEBUG_KMS("Connector id %d unknown\n",
2000 out_id);
2001 ret = -EINVAL;
2002 goto out;
2003 }
2004 connector = obj_to_connector(obj);
2005 DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
2006 connector->base.id,
2007 drm_get_connector_name(connector));
2008
2009 connector_set[i] = connector;
2010 }
2011 }
2012
2013 set.crtc = crtc;
2014 set.x = crtc_req->x;
2015 set.y = crtc_req->y;
2016 set.mode = mode;
2017 set.connectors = connector_set;
2018 set.num_connectors = crtc_req->count_connectors;
2019 set.fb = fb;
2020 ret = crtc->funcs->set_config(&set);
2021
2022 out:
2023 free(connector_set, DRM_MEM_KMS);
2024 drm_mode_destroy(dev, mode);
2025 sx_xunlock(&dev->mode_config.mutex);
2026 return ret;
2027 }
2028
drm_mode_cursor_ioctl(struct drm_device * dev,void * data,struct drm_file * file_priv)2029 int drm_mode_cursor_ioctl(struct drm_device *dev,
2030 void *data, struct drm_file *file_priv)
2031 {
2032 struct drm_mode_cursor *req = data;
2033 struct drm_mode_object *obj;
2034 struct drm_crtc *crtc;
2035 int ret = 0;
2036
2037 if (!drm_core_check_feature(dev, DRIVER_MODESET))
2038 return -EINVAL;
2039
2040 if (!req->flags || (~DRM_MODE_CURSOR_FLAGS & req->flags))
2041 return -EINVAL;
2042
2043 sx_xlock(&dev->mode_config.mutex);
2044 obj = drm_mode_object_find(dev, req->crtc_id, DRM_MODE_OBJECT_CRTC);
2045 if (!obj) {
2046 DRM_DEBUG_KMS("Unknown CRTC ID %d\n", req->crtc_id);
2047 ret = -EINVAL;
2048 goto out;
2049 }
2050 crtc = obj_to_crtc(obj);
2051
2052 if (req->flags & DRM_MODE_CURSOR_BO) {
2053 if (!crtc->funcs->cursor_set) {
2054 ret = -ENXIO;
2055 goto out;
2056 }
2057 /* Turns off the cursor if handle is 0 */
2058 ret = crtc->funcs->cursor_set(crtc, file_priv, req->handle,
2059 req->width, req->height);
2060 }
2061
2062 if (req->flags & DRM_MODE_CURSOR_MOVE) {
2063 if (crtc->funcs->cursor_move) {
2064 ret = crtc->funcs->cursor_move(crtc, req->x, req->y);
2065 } else {
2066 ret = -EFAULT;
2067 goto out;
2068 }
2069 }
2070 out:
2071 sx_xunlock(&dev->mode_config.mutex);
2072 return ret;
2073 }
2074
2075 /* Original addfb only supported RGB formats, so figure out which one */
drm_mode_legacy_fb_format(uint32_t bpp,uint32_t depth)2076 uint32_t drm_mode_legacy_fb_format(uint32_t bpp, uint32_t depth)
2077 {
2078 uint32_t fmt;
2079
2080 switch (bpp) {
2081 case 8:
2082 fmt = DRM_FORMAT_C8;
2083 break;
2084 case 16:
2085 if (depth == 15)
2086 fmt = DRM_FORMAT_XRGB1555;
2087 else
2088 fmt = DRM_FORMAT_RGB565;
2089 break;
2090 case 24:
2091 fmt = DRM_FORMAT_RGB888;
2092 break;
2093 case 32:
2094 if (depth == 24)
2095 fmt = DRM_FORMAT_XRGB8888;
2096 else if (depth == 30)
2097 fmt = DRM_FORMAT_XRGB2101010;
2098 else
2099 fmt = DRM_FORMAT_ARGB8888;
2100 break;
2101 default:
2102 DRM_ERROR("bad bpp, assuming x8r8g8b8 pixel format\n");
2103 fmt = DRM_FORMAT_XRGB8888;
2104 break;
2105 }
2106
2107 return fmt;
2108 }
2109 EXPORT_SYMBOL(drm_mode_legacy_fb_format);
2110
2111 /**
2112 * drm_mode_addfb - add an FB to the graphics configuration
2113 * @inode: inode from the ioctl
2114 * @filp: file * from the ioctl
2115 * @cmd: cmd from ioctl
2116 * @arg: arg from ioctl
2117 *
2118 * LOCKING:
2119 * Takes mode config lock.
2120 *
2121 * Add a new FB to the specified CRTC, given a user request.
2122 *
2123 * Called by the user via ioctl.
2124 *
2125 * RETURNS:
2126 * Zero on success, errno on failure.
2127 */
drm_mode_addfb(struct drm_device * dev,void * data,struct drm_file * file_priv)2128 int drm_mode_addfb(struct drm_device *dev,
2129 void *data, struct drm_file *file_priv)
2130 {
2131 struct drm_mode_fb_cmd *or = data;
2132 struct drm_mode_fb_cmd2 r = {};
2133 struct drm_mode_config *config = &dev->mode_config;
2134 struct drm_framebuffer *fb;
2135 int ret = 0;
2136
2137 /* Use new struct with format internally */
2138 r.fb_id = or->fb_id;
2139 r.width = or->width;
2140 r.height = or->height;
2141 r.pitches[0] = or->pitch;
2142 r.pixel_format = drm_mode_legacy_fb_format(or->bpp, or->depth);
2143 r.handles[0] = or->handle;
2144
2145 if (!drm_core_check_feature(dev, DRIVER_MODESET))
2146 return -EINVAL;
2147
2148 if ((config->min_width > r.width) || (r.width > config->max_width))
2149 return -EINVAL;
2150
2151 if ((config->min_height > r.height) || (r.height > config->max_height))
2152 return -EINVAL;
2153
2154 sx_xlock(&dev->mode_config.mutex);
2155
2156 /* TODO check buffer is sufficiently large */
2157 /* TODO setup destructor callback */
2158
2159 ret = dev->mode_config.funcs->fb_create(dev, file_priv, &r, &fb);
2160 if (ret != 0) {
2161 DRM_DEBUG_KMS("could not create framebuffer\n");
2162 goto out;
2163 }
2164
2165 or->fb_id = fb->base.id;
2166 list_add(&fb->filp_head, &file_priv->fbs);
2167 DRM_DEBUG_KMS("[FB:%d]\n", fb->base.id);
2168
2169 out:
2170 sx_xunlock(&dev->mode_config.mutex);
2171 return ret;
2172 }
2173
format_check(const struct drm_mode_fb_cmd2 * r)2174 static int format_check(const struct drm_mode_fb_cmd2 *r)
2175 {
2176 uint32_t format = r->pixel_format & ~DRM_FORMAT_BIG_ENDIAN;
2177
2178 switch (format) {
2179 case DRM_FORMAT_C8:
2180 case DRM_FORMAT_RGB332:
2181 case DRM_FORMAT_BGR233:
2182 case DRM_FORMAT_XRGB4444:
2183 case DRM_FORMAT_XBGR4444:
2184 case DRM_FORMAT_RGBX4444:
2185 case DRM_FORMAT_BGRX4444:
2186 case DRM_FORMAT_ARGB4444:
2187 case DRM_FORMAT_ABGR4444:
2188 case DRM_FORMAT_RGBA4444:
2189 case DRM_FORMAT_BGRA4444:
2190 case DRM_FORMAT_XRGB1555:
2191 case DRM_FORMAT_XBGR1555:
2192 case DRM_FORMAT_RGBX5551:
2193 case DRM_FORMAT_BGRX5551:
2194 case DRM_FORMAT_ARGB1555:
2195 case DRM_FORMAT_ABGR1555:
2196 case DRM_FORMAT_RGBA5551:
2197 case DRM_FORMAT_BGRA5551:
2198 case DRM_FORMAT_RGB565:
2199 case DRM_FORMAT_BGR565:
2200 case DRM_FORMAT_RGB888:
2201 case DRM_FORMAT_BGR888:
2202 case DRM_FORMAT_XRGB8888:
2203 case DRM_FORMAT_XBGR8888:
2204 case DRM_FORMAT_RGBX8888:
2205 case DRM_FORMAT_BGRX8888:
2206 case DRM_FORMAT_ARGB8888:
2207 case DRM_FORMAT_ABGR8888:
2208 case DRM_FORMAT_RGBA8888:
2209 case DRM_FORMAT_BGRA8888:
2210 case DRM_FORMAT_XRGB2101010:
2211 case DRM_FORMAT_XBGR2101010:
2212 case DRM_FORMAT_RGBX1010102:
2213 case DRM_FORMAT_BGRX1010102:
2214 case DRM_FORMAT_ARGB2101010:
2215 case DRM_FORMAT_ABGR2101010:
2216 case DRM_FORMAT_RGBA1010102:
2217 case DRM_FORMAT_BGRA1010102:
2218 case DRM_FORMAT_YUYV:
2219 case DRM_FORMAT_YVYU:
2220 case DRM_FORMAT_UYVY:
2221 case DRM_FORMAT_VYUY:
2222 case DRM_FORMAT_AYUV:
2223 case DRM_FORMAT_NV12:
2224 case DRM_FORMAT_NV21:
2225 case DRM_FORMAT_NV16:
2226 case DRM_FORMAT_NV61:
2227 case DRM_FORMAT_NV24:
2228 case DRM_FORMAT_NV42:
2229 case DRM_FORMAT_YUV410:
2230 case DRM_FORMAT_YVU410:
2231 case DRM_FORMAT_YUV411:
2232 case DRM_FORMAT_YVU411:
2233 case DRM_FORMAT_YUV420:
2234 case DRM_FORMAT_YVU420:
2235 case DRM_FORMAT_YUV422:
2236 case DRM_FORMAT_YVU422:
2237 case DRM_FORMAT_YUV444:
2238 case DRM_FORMAT_YVU444:
2239 return 0;
2240 default:
2241 return -EINVAL;
2242 }
2243 }
2244
framebuffer_check(const struct drm_mode_fb_cmd2 * r)2245 static int framebuffer_check(const struct drm_mode_fb_cmd2 *r)
2246 {
2247 int ret, hsub, vsub, num_planes, i;
2248
2249 ret = format_check(r);
2250 if (ret) {
2251 DRM_DEBUG_KMS("bad framebuffer format 0x%08x\n", r->pixel_format);
2252 return ret;
2253 }
2254
2255 hsub = drm_format_horz_chroma_subsampling(r->pixel_format);
2256 vsub = drm_format_vert_chroma_subsampling(r->pixel_format);
2257 num_planes = drm_format_num_planes(r->pixel_format);
2258
2259 if (r->width == 0 || r->width % hsub) {
2260 DRM_DEBUG_KMS("bad framebuffer width %u\n", r->height);
2261 return -EINVAL;
2262 }
2263
2264 if (r->height == 0 || r->height % vsub) {
2265 DRM_DEBUG_KMS("bad framebuffer height %u\n", r->height);
2266 return -EINVAL;
2267 }
2268
2269 for (i = 0; i < num_planes; i++) {
2270 unsigned int width = r->width / (i != 0 ? hsub : 1);
2271 unsigned int height = r->height / (i != 0 ? vsub : 1);
2272 unsigned int cpp = drm_format_plane_cpp(r->pixel_format, i);
2273
2274 if (!r->handles[i]) {
2275 DRM_DEBUG_KMS("no buffer object handle for plane %d\n", i);
2276 return -EINVAL;
2277 }
2278
2279 if ((uint64_t) width * cpp > UINT_MAX)
2280 return -ERANGE;
2281
2282 if ((uint64_t) height * r->pitches[i] + r->offsets[i] > UINT_MAX)
2283 return -ERANGE;
2284
2285 if (r->pitches[i] < width * cpp) {
2286 DRM_DEBUG_KMS("bad pitch %u for plane %d\n", r->pitches[i], i);
2287 return -EINVAL;
2288 }
2289 }
2290
2291 return 0;
2292 }
2293
2294 /**
2295 * drm_mode_addfb2 - add an FB to the graphics configuration
2296 * @inode: inode from the ioctl
2297 * @filp: file * from the ioctl
2298 * @cmd: cmd from ioctl
2299 * @arg: arg from ioctl
2300 *
2301 * LOCKING:
2302 * Takes mode config lock.
2303 *
2304 * Add a new FB to the specified CRTC, given a user request with format.
2305 *
2306 * Called by the user via ioctl.
2307 *
2308 * RETURNS:
2309 * Zero on success, errno on failure.
2310 */
drm_mode_addfb2(struct drm_device * dev,void * data,struct drm_file * file_priv)2311 int drm_mode_addfb2(struct drm_device *dev,
2312 void *data, struct drm_file *file_priv)
2313 {
2314 struct drm_mode_fb_cmd2 *r = data;
2315 struct drm_mode_config *config = &dev->mode_config;
2316 struct drm_framebuffer *fb;
2317 int ret;
2318
2319 if (!drm_core_check_feature(dev, DRIVER_MODESET))
2320 return -EINVAL;
2321
2322 if (r->flags & ~DRM_MODE_FB_INTERLACED) {
2323 DRM_DEBUG_KMS("bad framebuffer flags 0x%08x\n", r->flags);
2324 return -EINVAL;
2325 }
2326
2327 if ((config->min_width > r->width) || (r->width > config->max_width)) {
2328 DRM_DEBUG_KMS("bad framebuffer width %d, should be >= %d && <= %d\n",
2329 r->width, config->min_width, config->max_width);
2330 return -EINVAL;
2331 }
2332 if ((config->min_height > r->height) || (r->height > config->max_height)) {
2333 DRM_DEBUG_KMS("bad framebuffer height %d, should be >= %d && <= %d\n",
2334 r->height, config->min_height, config->max_height);
2335 return -EINVAL;
2336 }
2337
2338 ret = framebuffer_check(r);
2339 if (ret)
2340 return ret;
2341
2342 sx_xlock(&dev->mode_config.mutex);
2343
2344 ret = dev->mode_config.funcs->fb_create(dev, file_priv, r, &fb);
2345 if (ret != 0) {
2346 DRM_DEBUG_KMS("could not create framebuffer\n");
2347 goto out;
2348 }
2349
2350 r->fb_id = fb->base.id;
2351 list_add(&fb->filp_head, &file_priv->fbs);
2352 DRM_DEBUG_KMS("[FB:%d]\n", fb->base.id);
2353
2354 out:
2355 sx_xunlock(&dev->mode_config.mutex);
2356 return ret;
2357 }
2358
2359 /**
2360 * drm_mode_rmfb - remove an FB from the configuration
2361 * @inode: inode from the ioctl
2362 * @filp: file * from the ioctl
2363 * @cmd: cmd from ioctl
2364 * @arg: arg from ioctl
2365 *
2366 * LOCKING:
2367 * Takes mode config lock.
2368 *
2369 * Remove the FB specified by the user.
2370 *
2371 * Called by the user via ioctl.
2372 *
2373 * RETURNS:
2374 * Zero on success, errno on failure.
2375 */
drm_mode_rmfb(struct drm_device * dev,void * data,struct drm_file * file_priv)2376 int drm_mode_rmfb(struct drm_device *dev,
2377 void *data, struct drm_file *file_priv)
2378 {
2379 struct drm_mode_object *obj;
2380 struct drm_framebuffer *fb = NULL;
2381 struct drm_framebuffer *fbl = NULL;
2382 uint32_t *id = data;
2383 int ret = 0;
2384 int found = 0;
2385
2386 if (!drm_core_check_feature(dev, DRIVER_MODESET))
2387 return -EINVAL;
2388
2389 sx_xlock(&dev->mode_config.mutex);
2390 obj = drm_mode_object_find(dev, *id, DRM_MODE_OBJECT_FB);
2391 /* TODO check that we really get a framebuffer back. */
2392 if (!obj) {
2393 ret = -EINVAL;
2394 goto out;
2395 }
2396 fb = obj_to_fb(obj);
2397
2398 list_for_each_entry(fbl, &file_priv->fbs, filp_head)
2399 if (fb == fbl)
2400 found = 1;
2401
2402 if (!found) {
2403 ret = -EINVAL;
2404 goto out;
2405 }
2406
2407 drm_framebuffer_remove(fb);
2408
2409 out:
2410 sx_xunlock(&dev->mode_config.mutex);
2411 return ret;
2412 }
2413
2414 /**
2415 * drm_mode_getfb - get FB info
2416 * @inode: inode from the ioctl
2417 * @filp: file * from the ioctl
2418 * @cmd: cmd from ioctl
2419 * @arg: arg from ioctl
2420 *
2421 * LOCKING:
2422 * Takes mode config lock.
2423 *
2424 * Lookup the FB given its ID and return info about it.
2425 *
2426 * Called by the user via ioctl.
2427 *
2428 * RETURNS:
2429 * Zero on success, errno on failure.
2430 */
drm_mode_getfb(struct drm_device * dev,void * data,struct drm_file * file_priv)2431 int drm_mode_getfb(struct drm_device *dev,
2432 void *data, struct drm_file *file_priv)
2433 {
2434 struct drm_mode_fb_cmd *r = data;
2435 struct drm_mode_object *obj;
2436 struct drm_framebuffer *fb;
2437 int ret = 0;
2438
2439 if (!drm_core_check_feature(dev, DRIVER_MODESET))
2440 return -EINVAL;
2441
2442 sx_xlock(&dev->mode_config.mutex);
2443 obj = drm_mode_object_find(dev, r->fb_id, DRM_MODE_OBJECT_FB);
2444 if (!obj) {
2445 ret = -EINVAL;
2446 goto out;
2447 }
2448 fb = obj_to_fb(obj);
2449
2450 r->height = fb->height;
2451 r->width = fb->width;
2452 r->depth = fb->depth;
2453 r->bpp = fb->bits_per_pixel;
2454 r->pitch = fb->pitches[0];
2455 r->handle = 0;
2456 fb->funcs->create_handle(fb, file_priv, &r->handle);
2457
2458 out:
2459 sx_xunlock(&dev->mode_config.mutex);
2460 return ret;
2461 }
2462
drm_mode_dirtyfb_ioctl(struct drm_device * dev,void * data,struct drm_file * file_priv)2463 int drm_mode_dirtyfb_ioctl(struct drm_device *dev,
2464 void *data, struct drm_file *file_priv)
2465 {
2466 struct drm_clip_rect __user *clips_ptr;
2467 struct drm_clip_rect *clips = NULL;
2468 struct drm_mode_fb_dirty_cmd *r = data;
2469 struct drm_mode_object *obj;
2470 struct drm_framebuffer *fb;
2471 unsigned flags;
2472 int num_clips;
2473 int ret;
2474
2475 if (!drm_core_check_feature(dev, DRIVER_MODESET))
2476 return -EINVAL;
2477
2478 sx_xlock(&dev->mode_config.mutex);
2479 obj = drm_mode_object_find(dev, r->fb_id, DRM_MODE_OBJECT_FB);
2480 if (!obj) {
2481 ret = -EINVAL;
2482 goto out_err1;
2483 }
2484 fb = obj_to_fb(obj);
2485
2486 num_clips = r->num_clips;
2487 clips_ptr = (struct drm_clip_rect __user *)(unsigned long)r->clips_ptr;
2488
2489 if (!num_clips != !clips_ptr) {
2490 ret = -EINVAL;
2491 goto out_err1;
2492 }
2493
2494 flags = DRM_MODE_FB_DIRTY_FLAGS & r->flags;
2495
2496 /* If userspace annotates copy, clips must come in pairs */
2497 if (flags & DRM_MODE_FB_DIRTY_ANNOTATE_COPY && (num_clips % 2)) {
2498 ret = -EINVAL;
2499 goto out_err1;
2500 }
2501
2502 if (num_clips && clips_ptr) {
2503 if (num_clips < 0 || num_clips > DRM_MODE_FB_DIRTY_MAX_CLIPS) {
2504 ret = -EINVAL;
2505 goto out_err1;
2506 }
2507 clips = malloc(num_clips * sizeof(*clips), DRM_MEM_KMS,
2508 M_WAITOK | M_ZERO);
2509 ret = copy_from_user(clips, clips_ptr,
2510 num_clips * sizeof(*clips));
2511 if (ret) {
2512 ret = -EFAULT;
2513 goto out_err2;
2514 }
2515 }
2516
2517 if (fb->funcs->dirty) {
2518 ret = fb->funcs->dirty(fb, file_priv, flags, r->color,
2519 clips, num_clips);
2520 } else {
2521 ret = -ENOSYS;
2522 goto out_err2;
2523 }
2524
2525 out_err2:
2526 free(clips, DRM_MEM_KMS);
2527 out_err1:
2528 sx_xunlock(&dev->mode_config.mutex);
2529 return ret;
2530 }
2531
2532
2533 /**
2534 * drm_fb_release - remove and free the FBs on this file
2535 * @filp: file * from the ioctl
2536 *
2537 * LOCKING:
2538 * Takes mode config lock.
2539 *
2540 * Destroy all the FBs associated with @filp.
2541 *
2542 * Called by the user via ioctl.
2543 *
2544 * RETURNS:
2545 * Zero on success, errno on failure.
2546 */
drm_fb_release(struct drm_file * priv)2547 void drm_fb_release(struct drm_file *priv)
2548 {
2549 struct drm_device *dev = priv->minor->dev;
2550 struct drm_framebuffer *fb, *tfb;
2551
2552 sx_xlock(&dev->mode_config.mutex);
2553 list_for_each_entry_safe(fb, tfb, &priv->fbs, filp_head) {
2554 drm_framebuffer_remove(fb);
2555 }
2556 sx_xunlock(&dev->mode_config.mutex);
2557 }
2558
2559 /**
2560 * drm_mode_attachmode - add a mode to the user mode list
2561 * @dev: DRM device
2562 * @connector: connector to add the mode to
2563 * @mode: mode to add
2564 *
2565 * Add @mode to @connector's user mode list.
2566 */
drm_mode_attachmode(struct drm_device * dev,struct drm_connector * connector,struct drm_display_mode * mode)2567 static void drm_mode_attachmode(struct drm_device *dev,
2568 struct drm_connector *connector,
2569 struct drm_display_mode *mode)
2570 {
2571 list_add_tail(&mode->head, &connector->user_modes);
2572 }
2573
drm_mode_attachmode_crtc(struct drm_device * dev,struct drm_crtc * crtc,const struct drm_display_mode * mode)2574 int drm_mode_attachmode_crtc(struct drm_device *dev, struct drm_crtc *crtc,
2575 const struct drm_display_mode *mode)
2576 {
2577 struct drm_connector *connector;
2578 int ret = 0;
2579 struct drm_display_mode *dup_mode, *next;
2580 DRM_LIST_HEAD(list);
2581
2582 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
2583 if (!connector->encoder)
2584 continue;
2585 if (connector->encoder->crtc == crtc) {
2586 dup_mode = drm_mode_duplicate(dev, mode);
2587 if (!dup_mode) {
2588 ret = -ENOMEM;
2589 goto out;
2590 }
2591 list_add_tail(&dup_mode->head, &list);
2592 }
2593 }
2594
2595 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
2596 if (!connector->encoder)
2597 continue;
2598 if (connector->encoder->crtc == crtc)
2599 list_move_tail(list.next, &connector->user_modes);
2600 }
2601
2602 MPASS(!list_empty(&list));
2603
2604 out:
2605 list_for_each_entry_safe(dup_mode, next, &list, head)
2606 drm_mode_destroy(dev, dup_mode);
2607
2608 return ret;
2609 }
2610 EXPORT_SYMBOL(drm_mode_attachmode_crtc);
2611
drm_mode_detachmode(struct drm_device * dev,struct drm_connector * connector,struct drm_display_mode * mode)2612 static int drm_mode_detachmode(struct drm_device *dev,
2613 struct drm_connector *connector,
2614 struct drm_display_mode *mode)
2615 {
2616 int found = 0;
2617 int ret = 0;
2618 struct drm_display_mode *match_mode, *t;
2619
2620 list_for_each_entry_safe(match_mode, t, &connector->user_modes, head) {
2621 if (drm_mode_equal(match_mode, mode)) {
2622 list_del(&match_mode->head);
2623 drm_mode_destroy(dev, match_mode);
2624 found = 1;
2625 break;
2626 }
2627 }
2628
2629 if (!found)
2630 ret = -EINVAL;
2631
2632 return ret;
2633 }
2634
drm_mode_detachmode_crtc(struct drm_device * dev,struct drm_display_mode * mode)2635 int drm_mode_detachmode_crtc(struct drm_device *dev, struct drm_display_mode *mode)
2636 {
2637 struct drm_connector *connector;
2638
2639 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
2640 drm_mode_detachmode(dev, connector, mode);
2641 }
2642 return 0;
2643 }
2644 EXPORT_SYMBOL(drm_mode_detachmode_crtc);
2645
2646 /**
2647 * drm_fb_attachmode - Attach a user mode to an connector
2648 * @inode: inode from the ioctl
2649 * @filp: file * from the ioctl
2650 * @cmd: cmd from ioctl
2651 * @arg: arg from ioctl
2652 *
2653 * This attaches a user specified mode to an connector.
2654 * Called by the user via ioctl.
2655 *
2656 * RETURNS:
2657 * Zero on success, errno on failure.
2658 */
drm_mode_attachmode_ioctl(struct drm_device * dev,void * data,struct drm_file * file_priv)2659 int drm_mode_attachmode_ioctl(struct drm_device *dev,
2660 void *data, struct drm_file *file_priv)
2661 {
2662 struct drm_mode_mode_cmd *mode_cmd = data;
2663 struct drm_connector *connector;
2664 struct drm_display_mode *mode;
2665 struct drm_mode_object *obj;
2666 struct drm_mode_modeinfo *umode = &mode_cmd->mode;
2667 int ret;
2668
2669 if (!drm_core_check_feature(dev, DRIVER_MODESET))
2670 return -EINVAL;
2671
2672 sx_xlock(&dev->mode_config.mutex);
2673
2674 obj = drm_mode_object_find(dev, mode_cmd->connector_id, DRM_MODE_OBJECT_CONNECTOR);
2675 if (!obj) {
2676 ret = -EINVAL;
2677 goto out;
2678 }
2679 connector = obj_to_connector(obj);
2680
2681 mode = drm_mode_create(dev);
2682 if (!mode) {
2683 ret = -ENOMEM;
2684 goto out;
2685 }
2686
2687 ret = drm_crtc_convert_umode(mode, umode);
2688 if (ret) {
2689 DRM_DEBUG_KMS("Invalid mode\n");
2690 drm_mode_destroy(dev, mode);
2691 goto out;
2692 }
2693
2694 drm_mode_attachmode(dev, connector, mode);
2695 out:
2696 sx_xunlock(&dev->mode_config.mutex);
2697 return ret;
2698 }
2699
2700
2701 /**
2702 * drm_fb_detachmode - Detach a user specified mode from an connector
2703 * @inode: inode from the ioctl
2704 * @filp: file * from the ioctl
2705 * @cmd: cmd from ioctl
2706 * @arg: arg from ioctl
2707 *
2708 * Called by the user via ioctl.
2709 *
2710 * RETURNS:
2711 * Zero on success, errno on failure.
2712 */
drm_mode_detachmode_ioctl(struct drm_device * dev,void * data,struct drm_file * file_priv)2713 int drm_mode_detachmode_ioctl(struct drm_device *dev,
2714 void *data, struct drm_file *file_priv)
2715 {
2716 struct drm_mode_object *obj;
2717 struct drm_mode_mode_cmd *mode_cmd = data;
2718 struct drm_connector *connector;
2719 struct drm_display_mode mode;
2720 struct drm_mode_modeinfo *umode = &mode_cmd->mode;
2721 int ret;
2722
2723 if (!drm_core_check_feature(dev, DRIVER_MODESET))
2724 return -EINVAL;
2725
2726 sx_xlock(&dev->mode_config.mutex);
2727
2728 obj = drm_mode_object_find(dev, mode_cmd->connector_id, DRM_MODE_OBJECT_CONNECTOR);
2729 if (!obj) {
2730 ret = -EINVAL;
2731 goto out;
2732 }
2733 connector = obj_to_connector(obj);
2734
2735 ret = drm_crtc_convert_umode(&mode, umode);
2736 if (ret) {
2737 DRM_DEBUG_KMS("Invalid mode\n");
2738 goto out;
2739 }
2740
2741 ret = drm_mode_detachmode(dev, connector, &mode);
2742 out:
2743 sx_xunlock(&dev->mode_config.mutex);
2744 return ret;
2745 }
2746
drm_property_create(struct drm_device * dev,int flags,const char * name,int num_values)2747 struct drm_property *drm_property_create(struct drm_device *dev, int flags,
2748 const char *name, int num_values)
2749 {
2750 struct drm_property *property = NULL;
2751 int ret;
2752
2753 property = malloc(sizeof(struct drm_property), DRM_MEM_KMS,
2754 M_WAITOK | M_ZERO);
2755
2756 if (num_values)
2757 property->values = malloc(sizeof(uint64_t)*num_values, DRM_MEM_KMS,
2758 M_WAITOK | M_ZERO);
2759
2760 ret = drm_mode_object_get(dev, &property->base, DRM_MODE_OBJECT_PROPERTY);
2761 if (ret)
2762 goto fail;
2763
2764 property->flags = flags;
2765 property->num_values = num_values;
2766 INIT_LIST_HEAD(&property->enum_blob_list);
2767
2768 if (name) {
2769 strncpy(property->name, name, DRM_PROP_NAME_LEN);
2770 property->name[DRM_PROP_NAME_LEN-1] = '\0';
2771 }
2772
2773 list_add_tail(&property->head, &dev->mode_config.property_list);
2774 return property;
2775 fail:
2776 free(property->values, DRM_MEM_KMS);
2777 free(property, DRM_MEM_KMS);
2778 return NULL;
2779 }
2780 EXPORT_SYMBOL(drm_property_create);
2781
drm_property_create_enum(struct drm_device * dev,int flags,const char * name,const struct drm_prop_enum_list * props,int num_values)2782 struct drm_property *drm_property_create_enum(struct drm_device *dev, int flags,
2783 const char *name,
2784 const struct drm_prop_enum_list *props,
2785 int num_values)
2786 {
2787 struct drm_property *property;
2788 int i, ret;
2789
2790 flags |= DRM_MODE_PROP_ENUM;
2791
2792 property = drm_property_create(dev, flags, name, num_values);
2793 if (!property)
2794 return NULL;
2795
2796 for (i = 0; i < num_values; i++) {
2797 ret = drm_property_add_enum(property, i,
2798 props[i].type,
2799 props[i].name);
2800 if (ret) {
2801 drm_property_destroy(dev, property);
2802 return NULL;
2803 }
2804 }
2805
2806 return property;
2807 }
2808 EXPORT_SYMBOL(drm_property_create_enum);
2809
drm_property_create_bitmask(struct drm_device * dev,int flags,const char * name,const struct drm_prop_enum_list * props,int num_values)2810 struct drm_property *drm_property_create_bitmask(struct drm_device *dev,
2811 int flags, const char *name,
2812 const struct drm_prop_enum_list *props,
2813 int num_values)
2814 {
2815 struct drm_property *property;
2816 int i, ret;
2817
2818 flags |= DRM_MODE_PROP_BITMASK;
2819
2820 property = drm_property_create(dev, flags, name, num_values);
2821 if (!property)
2822 return NULL;
2823
2824 for (i = 0; i < num_values; i++) {
2825 ret = drm_property_add_enum(property, i,
2826 props[i].type,
2827 props[i].name);
2828 if (ret) {
2829 drm_property_destroy(dev, property);
2830 return NULL;
2831 }
2832 }
2833
2834 return property;
2835 }
2836 EXPORT_SYMBOL(drm_property_create_bitmask);
2837
drm_property_create_range(struct drm_device * dev,int flags,const char * name,uint64_t min,uint64_t max)2838 struct drm_property *drm_property_create_range(struct drm_device *dev, int flags,
2839 const char *name,
2840 uint64_t min, uint64_t max)
2841 {
2842 struct drm_property *property;
2843
2844 flags |= DRM_MODE_PROP_RANGE;
2845
2846 property = drm_property_create(dev, flags, name, 2);
2847 if (!property)
2848 return NULL;
2849
2850 property->values[0] = min;
2851 property->values[1] = max;
2852
2853 return property;
2854 }
2855 EXPORT_SYMBOL(drm_property_create_range);
2856
drm_property_add_enum(struct drm_property * property,int index,uint64_t value,const char * name)2857 int drm_property_add_enum(struct drm_property *property, int index,
2858 uint64_t value, const char *name)
2859 {
2860 struct drm_property_enum *prop_enum;
2861
2862 if (!(property->flags & (DRM_MODE_PROP_ENUM | DRM_MODE_PROP_BITMASK)))
2863 return -EINVAL;
2864
2865 /*
2866 * Bitmask enum properties have the additional constraint of values
2867 * from 0 to 63
2868 */
2869 if ((property->flags & DRM_MODE_PROP_BITMASK) && (value > 63))
2870 return -EINVAL;
2871
2872 if (!list_empty(&property->enum_blob_list)) {
2873 list_for_each_entry(prop_enum, &property->enum_blob_list, head) {
2874 if (prop_enum->value == value) {
2875 strncpy(prop_enum->name, name, DRM_PROP_NAME_LEN);
2876 prop_enum->name[DRM_PROP_NAME_LEN-1] = '\0';
2877 return 0;
2878 }
2879 }
2880 }
2881
2882 prop_enum = malloc(sizeof(struct drm_property_enum), DRM_MEM_KMS,
2883 M_WAITOK | M_ZERO);
2884 strncpy(prop_enum->name, name, DRM_PROP_NAME_LEN);
2885 prop_enum->name[DRM_PROP_NAME_LEN-1] = '\0';
2886 prop_enum->value = value;
2887
2888 property->values[index] = value;
2889 list_add_tail(&prop_enum->head, &property->enum_blob_list);
2890 return 0;
2891 }
2892 EXPORT_SYMBOL(drm_property_add_enum);
2893
drm_property_destroy(struct drm_device * dev,struct drm_property * property)2894 void drm_property_destroy(struct drm_device *dev, struct drm_property *property)
2895 {
2896 struct drm_property_enum *prop_enum, *pt;
2897
2898 list_for_each_entry_safe(prop_enum, pt, &property->enum_blob_list, head) {
2899 list_del(&prop_enum->head);
2900 free(prop_enum, DRM_MEM_KMS);
2901 }
2902
2903 if (property->num_values)
2904 free(property->values, DRM_MEM_KMS);
2905 drm_mode_object_put(dev, &property->base);
2906 list_del(&property->head);
2907 free(property, DRM_MEM_KMS);
2908 }
2909 EXPORT_SYMBOL(drm_property_destroy);
2910
drm_object_attach_property(struct drm_mode_object * obj,struct drm_property * property,uint64_t init_val)2911 void drm_object_attach_property(struct drm_mode_object *obj,
2912 struct drm_property *property,
2913 uint64_t init_val)
2914 {
2915 int count = obj->properties->count;
2916
2917 if (count == DRM_OBJECT_MAX_PROPERTY) {
2918 DRM_WARNING("Failed to attach object property (type: 0x%x). Please "
2919 "increase DRM_OBJECT_MAX_PROPERTY by 1 for each time "
2920 "you see this message on the same object type.\n",
2921 obj->type);
2922 return;
2923 }
2924
2925 obj->properties->ids[count] = property->base.id;
2926 obj->properties->values[count] = init_val;
2927 obj->properties->count++;
2928 }
2929 EXPORT_SYMBOL(drm_object_attach_property);
2930
drm_object_property_set_value(struct drm_mode_object * obj,struct drm_property * property,uint64_t val)2931 int drm_object_property_set_value(struct drm_mode_object *obj,
2932 struct drm_property *property, uint64_t val)
2933 {
2934 int i;
2935
2936 for (i = 0; i < obj->properties->count; i++) {
2937 if (obj->properties->ids[i] == property->base.id) {
2938 obj->properties->values[i] = val;
2939 return 0;
2940 }
2941 }
2942
2943 return -EINVAL;
2944 }
2945 EXPORT_SYMBOL(drm_object_property_set_value);
2946
drm_object_property_get_value(struct drm_mode_object * obj,struct drm_property * property,uint64_t * val)2947 int drm_object_property_get_value(struct drm_mode_object *obj,
2948 struct drm_property *property, uint64_t *val)
2949 {
2950 int i;
2951
2952 for (i = 0; i < obj->properties->count; i++) {
2953 if (obj->properties->ids[i] == property->base.id) {
2954 *val = obj->properties->values[i];
2955 return 0;
2956 }
2957 }
2958
2959 return -EINVAL;
2960 }
2961 EXPORT_SYMBOL(drm_object_property_get_value);
2962
drm_mode_getproperty_ioctl(struct drm_device * dev,void * data,struct drm_file * file_priv)2963 int drm_mode_getproperty_ioctl(struct drm_device *dev,
2964 void *data, struct drm_file *file_priv)
2965 {
2966 struct drm_mode_object *obj;
2967 struct drm_mode_get_property *out_resp = data;
2968 struct drm_property *property;
2969 int enum_count = 0;
2970 int blob_count = 0;
2971 int value_count = 0;
2972 int ret = 0, i;
2973 int copied;
2974 struct drm_property_enum *prop_enum;
2975 struct drm_mode_property_enum __user *enum_ptr;
2976 struct drm_property_blob *prop_blob;
2977 uint32_t __user *blob_id_ptr;
2978 uint64_t __user *values_ptr;
2979 uint32_t __user *blob_length_ptr;
2980
2981 if (!drm_core_check_feature(dev, DRIVER_MODESET))
2982 return -EINVAL;
2983
2984 sx_xlock(&dev->mode_config.mutex);
2985 obj = drm_mode_object_find(dev, out_resp->prop_id, DRM_MODE_OBJECT_PROPERTY);
2986 if (!obj) {
2987 ret = -EINVAL;
2988 goto done;
2989 }
2990 property = obj_to_property(obj);
2991
2992 if (property->flags & (DRM_MODE_PROP_ENUM | DRM_MODE_PROP_BITMASK)) {
2993 list_for_each_entry(prop_enum, &property->enum_blob_list, head)
2994 enum_count++;
2995 } else if (property->flags & DRM_MODE_PROP_BLOB) {
2996 list_for_each_entry(prop_blob, &property->enum_blob_list, head)
2997 blob_count++;
2998 }
2999
3000 value_count = property->num_values;
3001
3002 strncpy(out_resp->name, property->name, DRM_PROP_NAME_LEN);
3003 out_resp->name[DRM_PROP_NAME_LEN-1] = 0;
3004 out_resp->flags = property->flags;
3005
3006 if ((out_resp->count_values >= value_count) && value_count) {
3007 values_ptr = (uint64_t __user *)(unsigned long)out_resp->values_ptr;
3008 for (i = 0; i < value_count; i++) {
3009 if (copy_to_user(values_ptr + i, &property->values[i], sizeof(uint64_t))) {
3010 ret = -EFAULT;
3011 goto done;
3012 }
3013 }
3014 }
3015 out_resp->count_values = value_count;
3016
3017 if (property->flags & (DRM_MODE_PROP_ENUM | DRM_MODE_PROP_BITMASK)) {
3018 if ((out_resp->count_enum_blobs >= enum_count) && enum_count) {
3019 copied = 0;
3020 enum_ptr = (struct drm_mode_property_enum __user *)(unsigned long)out_resp->enum_blob_ptr;
3021 list_for_each_entry(prop_enum, &property->enum_blob_list, head) {
3022
3023 if (copy_to_user(&enum_ptr[copied].value, &prop_enum->value, sizeof(uint64_t))) {
3024 ret = -EFAULT;
3025 goto done;
3026 }
3027
3028 if (copy_to_user(&enum_ptr[copied].name,
3029 &prop_enum->name, DRM_PROP_NAME_LEN)) {
3030 ret = -EFAULT;
3031 goto done;
3032 }
3033 copied++;
3034 }
3035 }
3036 out_resp->count_enum_blobs = enum_count;
3037 }
3038
3039 if (property->flags & DRM_MODE_PROP_BLOB) {
3040 if ((out_resp->count_enum_blobs >= blob_count) && blob_count) {
3041 copied = 0;
3042 blob_id_ptr = (uint32_t __user *)(unsigned long)out_resp->enum_blob_ptr;
3043 blob_length_ptr = (uint32_t __user *)(unsigned long)out_resp->values_ptr;
3044
3045 list_for_each_entry(prop_blob, &property->enum_blob_list, head) {
3046 if (put_user(prop_blob->base.id, blob_id_ptr + copied)) {
3047 ret = -EFAULT;
3048 goto done;
3049 }
3050
3051 if (put_user(prop_blob->length, blob_length_ptr + copied)) {
3052 ret = -EFAULT;
3053 goto done;
3054 }
3055
3056 copied++;
3057 }
3058 }
3059 out_resp->count_enum_blobs = blob_count;
3060 }
3061 done:
3062 sx_xunlock(&dev->mode_config.mutex);
3063 return ret;
3064 }
3065
drm_property_create_blob(struct drm_device * dev,int length,void * data)3066 static struct drm_property_blob *drm_property_create_blob(struct drm_device *dev, int length,
3067 void *data)
3068 {
3069 struct drm_property_blob *blob;
3070 int ret;
3071
3072 if (!length || !data)
3073 return NULL;
3074
3075 blob = malloc(sizeof(struct drm_property_blob)+length, DRM_MEM_KMS,
3076 M_WAITOK | M_ZERO);
3077 ret = drm_mode_object_get(dev, &blob->base, DRM_MODE_OBJECT_BLOB);
3078 if (ret) {
3079 free(blob, DRM_MEM_KMS);
3080 return NULL;
3081 }
3082
3083 blob->length = length;
3084
3085 memcpy(blob->data, data, length);
3086
3087 list_add_tail(&blob->head, &dev->mode_config.property_blob_list);
3088 return blob;
3089 }
3090
drm_property_destroy_blob(struct drm_device * dev,struct drm_property_blob * blob)3091 static void drm_property_destroy_blob(struct drm_device *dev,
3092 struct drm_property_blob *blob)
3093 {
3094 drm_mode_object_put(dev, &blob->base);
3095 list_del(&blob->head);
3096 free(blob, DRM_MEM_KMS);
3097 }
3098
drm_mode_getblob_ioctl(struct drm_device * dev,void * data,struct drm_file * file_priv)3099 int drm_mode_getblob_ioctl(struct drm_device *dev,
3100 void *data, struct drm_file *file_priv)
3101 {
3102 struct drm_mode_object *obj;
3103 struct drm_mode_get_blob *out_resp = data;
3104 struct drm_property_blob *blob;
3105 int ret = 0;
3106 void __user *blob_ptr;
3107
3108 if (!drm_core_check_feature(dev, DRIVER_MODESET))
3109 return -EINVAL;
3110
3111 sx_xlock(&dev->mode_config.mutex);
3112 obj = drm_mode_object_find(dev, out_resp->blob_id, DRM_MODE_OBJECT_BLOB);
3113 if (!obj) {
3114 ret = -EINVAL;
3115 goto done;
3116 }
3117 blob = obj_to_blob(obj);
3118
3119 if (out_resp->length == blob->length) {
3120 blob_ptr = (void __user *)(unsigned long)out_resp->data;
3121 if (copy_to_user(blob_ptr, blob->data, blob->length)){
3122 ret = -EFAULT;
3123 goto done;
3124 }
3125 }
3126 out_resp->length = blob->length;
3127
3128 done:
3129 sx_xunlock(&dev->mode_config.mutex);
3130 return ret;
3131 }
3132
drm_mode_connector_update_edid_property(struct drm_connector * connector,struct edid * edid)3133 int drm_mode_connector_update_edid_property(struct drm_connector *connector,
3134 struct edid *edid)
3135 {
3136 struct drm_device *dev = connector->dev;
3137 int ret, size;
3138
3139 if (connector->edid_blob_ptr)
3140 drm_property_destroy_blob(dev, connector->edid_blob_ptr);
3141
3142 /* Delete edid, when there is none. */
3143 if (!edid) {
3144 connector->edid_blob_ptr = NULL;
3145 ret = drm_object_property_set_value(&connector->base, dev->mode_config.edid_property, 0);
3146 return ret;
3147 }
3148
3149 size = EDID_LENGTH * (1 + edid->extensions);
3150 connector->edid_blob_ptr = drm_property_create_blob(connector->dev,
3151 size, edid);
3152 if (!connector->edid_blob_ptr)
3153 return -EINVAL;
3154
3155 ret = drm_object_property_set_value(&connector->base,
3156 dev->mode_config.edid_property,
3157 connector->edid_blob_ptr->base.id);
3158
3159 return ret;
3160 }
3161 EXPORT_SYMBOL(drm_mode_connector_update_edid_property);
3162
drm_property_change_is_valid(struct drm_property * property,uint64_t value)3163 static bool drm_property_change_is_valid(struct drm_property *property,
3164 uint64_t value)
3165 {
3166 if (property->flags & DRM_MODE_PROP_IMMUTABLE)
3167 return false;
3168 if (property->flags & DRM_MODE_PROP_RANGE) {
3169 if (value < property->values[0] || value > property->values[1])
3170 return false;
3171 return true;
3172 } else if (property->flags & DRM_MODE_PROP_BITMASK) {
3173 int i;
3174 uint64_t valid_mask = 0;
3175 for (i = 0; i < property->num_values; i++)
3176 valid_mask |= (1ULL << property->values[i]);
3177 return !(value & ~valid_mask);
3178 } else if (property->flags & DRM_MODE_PROP_BLOB) {
3179 /* Only the driver knows */
3180 return true;
3181 } else {
3182 int i;
3183 for (i = 0; i < property->num_values; i++)
3184 if (property->values[i] == value)
3185 return true;
3186 return false;
3187 }
3188 }
3189
drm_mode_connector_property_set_ioctl(struct drm_device * dev,void * data,struct drm_file * file_priv)3190 int drm_mode_connector_property_set_ioctl(struct drm_device *dev,
3191 void *data, struct drm_file *file_priv)
3192 {
3193 struct drm_mode_connector_set_property *conn_set_prop = data;
3194 struct drm_mode_obj_set_property obj_set_prop = {
3195 .value = conn_set_prop->value,
3196 .prop_id = conn_set_prop->prop_id,
3197 .obj_id = conn_set_prop->connector_id,
3198 .obj_type = DRM_MODE_OBJECT_CONNECTOR
3199 };
3200
3201 /* It does all the locking and checking we need */
3202 return drm_mode_obj_set_property_ioctl(dev, &obj_set_prop, file_priv);
3203 }
3204
drm_mode_connector_set_obj_prop(struct drm_mode_object * obj,struct drm_property * property,uint64_t value)3205 static int drm_mode_connector_set_obj_prop(struct drm_mode_object *obj,
3206 struct drm_property *property,
3207 uint64_t value)
3208 {
3209 int ret = -EINVAL;
3210 struct drm_connector *connector = obj_to_connector(obj);
3211
3212 /* Do DPMS ourselves */
3213 if (property == connector->dev->mode_config.dpms_property) {
3214 if (connector->funcs->dpms)
3215 (*connector->funcs->dpms)(connector, (int)value);
3216 ret = 0;
3217 } else if (connector->funcs->set_property)
3218 ret = connector->funcs->set_property(connector, property, value);
3219
3220 /* store the property value if successful */
3221 if (!ret)
3222 drm_object_property_set_value(&connector->base, property, value);
3223 return ret;
3224 }
3225
drm_mode_crtc_set_obj_prop(struct drm_mode_object * obj,struct drm_property * property,uint64_t value)3226 static int drm_mode_crtc_set_obj_prop(struct drm_mode_object *obj,
3227 struct drm_property *property,
3228 uint64_t value)
3229 {
3230 int ret = -EINVAL;
3231 struct drm_crtc *crtc = obj_to_crtc(obj);
3232
3233 if (crtc->funcs->set_property)
3234 ret = crtc->funcs->set_property(crtc, property, value);
3235 if (!ret)
3236 drm_object_property_set_value(obj, property, value);
3237
3238 return ret;
3239 }
3240
drm_mode_plane_set_obj_prop(struct drm_mode_object * obj,struct drm_property * property,uint64_t value)3241 static int drm_mode_plane_set_obj_prop(struct drm_mode_object *obj,
3242 struct drm_property *property,
3243 uint64_t value)
3244 {
3245 int ret = -EINVAL;
3246 struct drm_plane *plane = obj_to_plane(obj);
3247
3248 if (plane->funcs->set_property)
3249 ret = plane->funcs->set_property(plane, property, value);
3250 if (!ret)
3251 drm_object_property_set_value(obj, property, value);
3252
3253 return ret;
3254 }
3255
drm_mode_obj_get_properties_ioctl(struct drm_device * dev,void * data,struct drm_file * file_priv)3256 int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data,
3257 struct drm_file *file_priv)
3258 {
3259 struct drm_mode_obj_get_properties *arg = data;
3260 struct drm_mode_object *obj;
3261 int ret = 0;
3262 int i;
3263 int copied = 0;
3264 int props_count = 0;
3265 uint32_t __user *props_ptr;
3266 uint64_t __user *prop_values_ptr;
3267
3268 if (!drm_core_check_feature(dev, DRIVER_MODESET))
3269 return -EINVAL;
3270
3271 sx_xlock(&dev->mode_config.mutex);
3272
3273 obj = drm_mode_object_find(dev, arg->obj_id, arg->obj_type);
3274 if (!obj) {
3275 ret = -EINVAL;
3276 goto out;
3277 }
3278 if (!obj->properties) {
3279 ret = -EINVAL;
3280 goto out;
3281 }
3282
3283 props_count = obj->properties->count;
3284
3285 /* This ioctl is called twice, once to determine how much space is
3286 * needed, and the 2nd time to fill it. */
3287 if ((arg->count_props >= props_count) && props_count) {
3288 copied = 0;
3289 props_ptr = (uint32_t __user *)(unsigned long)(arg->props_ptr);
3290 prop_values_ptr = (uint64_t __user *)(unsigned long)
3291 (arg->prop_values_ptr);
3292 for (i = 0; i < props_count; i++) {
3293 if (put_user(obj->properties->ids[i],
3294 props_ptr + copied)) {
3295 ret = -EFAULT;
3296 goto out;
3297 }
3298 if (put_user(obj->properties->values[i],
3299 prop_values_ptr + copied)) {
3300 ret = -EFAULT;
3301 goto out;
3302 }
3303 copied++;
3304 }
3305 }
3306 arg->count_props = props_count;
3307 out:
3308 sx_xunlock(&dev->mode_config.mutex);
3309 return ret;
3310 }
3311
drm_mode_obj_set_property_ioctl(struct drm_device * dev,void * data,struct drm_file * file_priv)3312 int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data,
3313 struct drm_file *file_priv)
3314 {
3315 struct drm_mode_obj_set_property *arg = data;
3316 struct drm_mode_object *arg_obj;
3317 struct drm_mode_object *prop_obj;
3318 struct drm_property *property;
3319 int ret = -EINVAL;
3320 int i;
3321
3322 if (!drm_core_check_feature(dev, DRIVER_MODESET))
3323 return -EINVAL;
3324
3325 sx_xlock(&dev->mode_config.mutex);
3326
3327 arg_obj = drm_mode_object_find(dev, arg->obj_id, arg->obj_type);
3328 if (!arg_obj)
3329 goto out;
3330 if (!arg_obj->properties)
3331 goto out;
3332
3333 for (i = 0; i < arg_obj->properties->count; i++)
3334 if (arg_obj->properties->ids[i] == arg->prop_id)
3335 break;
3336
3337 if (i == arg_obj->properties->count)
3338 goto out;
3339
3340 prop_obj = drm_mode_object_find(dev, arg->prop_id,
3341 DRM_MODE_OBJECT_PROPERTY);
3342 if (!prop_obj)
3343 goto out;
3344 property = obj_to_property(prop_obj);
3345
3346 if (!drm_property_change_is_valid(property, arg->value))
3347 goto out;
3348
3349 switch (arg_obj->type) {
3350 case DRM_MODE_OBJECT_CONNECTOR:
3351 ret = drm_mode_connector_set_obj_prop(arg_obj, property,
3352 arg->value);
3353 break;
3354 case DRM_MODE_OBJECT_CRTC:
3355 ret = drm_mode_crtc_set_obj_prop(arg_obj, property, arg->value);
3356 break;
3357 case DRM_MODE_OBJECT_PLANE:
3358 ret = drm_mode_plane_set_obj_prop(arg_obj, property, arg->value);
3359 break;
3360 }
3361
3362 out:
3363 sx_xunlock(&dev->mode_config.mutex);
3364 return ret;
3365 }
3366
drm_mode_connector_attach_encoder(struct drm_connector * connector,struct drm_encoder * encoder)3367 int drm_mode_connector_attach_encoder(struct drm_connector *connector,
3368 struct drm_encoder *encoder)
3369 {
3370 int i;
3371
3372 for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
3373 if (connector->encoder_ids[i] == 0) {
3374 connector->encoder_ids[i] = encoder->base.id;
3375 return 0;
3376 }
3377 }
3378 return -ENOMEM;
3379 }
3380 EXPORT_SYMBOL(drm_mode_connector_attach_encoder);
3381
drm_mode_connector_detach_encoder(struct drm_connector * connector,struct drm_encoder * encoder)3382 void drm_mode_connector_detach_encoder(struct drm_connector *connector,
3383 struct drm_encoder *encoder)
3384 {
3385 int i;
3386 for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
3387 if (connector->encoder_ids[i] == encoder->base.id) {
3388 connector->encoder_ids[i] = 0;
3389 if (connector->encoder == encoder)
3390 connector->encoder = NULL;
3391 break;
3392 }
3393 }
3394 }
3395 EXPORT_SYMBOL(drm_mode_connector_detach_encoder);
3396
drm_mode_crtc_set_gamma_size(struct drm_crtc * crtc,int gamma_size)3397 int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc,
3398 int gamma_size)
3399 {
3400 crtc->gamma_size = gamma_size;
3401
3402 crtc->gamma_store = malloc(gamma_size * sizeof(uint16_t) * 3,
3403 DRM_MEM_KMS, M_WAITOK | M_ZERO);
3404
3405 return 0;
3406 }
3407 EXPORT_SYMBOL(drm_mode_crtc_set_gamma_size);
3408
drm_mode_gamma_set_ioctl(struct drm_device * dev,void * data,struct drm_file * file_priv)3409 int drm_mode_gamma_set_ioctl(struct drm_device *dev,
3410 void *data, struct drm_file *file_priv)
3411 {
3412 struct drm_mode_crtc_lut *crtc_lut = data;
3413 struct drm_mode_object *obj;
3414 struct drm_crtc *crtc;
3415 void *r_base, *g_base, *b_base;
3416 int size;
3417 int ret = 0;
3418
3419 if (!drm_core_check_feature(dev, DRIVER_MODESET))
3420 return -EINVAL;
3421
3422 sx_xlock(&dev->mode_config.mutex);
3423 obj = drm_mode_object_find(dev, crtc_lut->crtc_id, DRM_MODE_OBJECT_CRTC);
3424 if (!obj) {
3425 ret = -EINVAL;
3426 goto out;
3427 }
3428 crtc = obj_to_crtc(obj);
3429
3430 if (crtc->funcs->gamma_set == NULL) {
3431 ret = -ENOSYS;
3432 goto out;
3433 }
3434
3435 /* memcpy into gamma store */
3436 if (crtc_lut->gamma_size != crtc->gamma_size) {
3437 ret = -EINVAL;
3438 goto out;
3439 }
3440
3441 size = crtc_lut->gamma_size * (sizeof(uint16_t));
3442 r_base = crtc->gamma_store;
3443 if (copy_from_user(r_base, (void __user *)(unsigned long)crtc_lut->red, size)) {
3444 ret = -EFAULT;
3445 goto out;
3446 }
3447
3448 g_base = (char *)r_base + size;
3449 if (copy_from_user(g_base, (void __user *)(unsigned long)crtc_lut->green, size)) {
3450 ret = -EFAULT;
3451 goto out;
3452 }
3453
3454 b_base = (char *)g_base + size;
3455 if (copy_from_user(b_base, (void __user *)(unsigned long)crtc_lut->blue, size)) {
3456 ret = -EFAULT;
3457 goto out;
3458 }
3459
3460 crtc->funcs->gamma_set(crtc, r_base, g_base, b_base, 0, crtc->gamma_size);
3461
3462 out:
3463 sx_xunlock(&dev->mode_config.mutex);
3464 return ret;
3465
3466 }
3467
drm_mode_gamma_get_ioctl(struct drm_device * dev,void * data,struct drm_file * file_priv)3468 int drm_mode_gamma_get_ioctl(struct drm_device *dev,
3469 void *data, struct drm_file *file_priv)
3470 {
3471 struct drm_mode_crtc_lut *crtc_lut = data;
3472 struct drm_mode_object *obj;
3473 struct drm_crtc *crtc;
3474 void *r_base, *g_base, *b_base;
3475 int size;
3476 int ret = 0;
3477
3478 if (!drm_core_check_feature(dev, DRIVER_MODESET))
3479 return -EINVAL;
3480
3481 sx_xlock(&dev->mode_config.mutex);
3482 obj = drm_mode_object_find(dev, crtc_lut->crtc_id, DRM_MODE_OBJECT_CRTC);
3483 if (!obj) {
3484 ret = -EINVAL;
3485 goto out;
3486 }
3487 crtc = obj_to_crtc(obj);
3488
3489 /* memcpy into gamma store */
3490 if (crtc_lut->gamma_size != crtc->gamma_size) {
3491 ret = -EINVAL;
3492 goto out;
3493 }
3494
3495 size = crtc_lut->gamma_size * (sizeof(uint16_t));
3496 r_base = crtc->gamma_store;
3497 if (copy_to_user((void __user *)(unsigned long)crtc_lut->red, r_base, size)) {
3498 ret = -EFAULT;
3499 goto out;
3500 }
3501
3502 g_base = (char *)r_base + size;
3503 if (copy_to_user((void __user *)(unsigned long)crtc_lut->green, g_base, size)) {
3504 ret = -EFAULT;
3505 goto out;
3506 }
3507
3508 b_base = (char *)g_base + size;
3509 if (copy_to_user((void __user *)(unsigned long)crtc_lut->blue, b_base, size)) {
3510 ret = -EFAULT;
3511 goto out;
3512 }
3513 out:
3514 sx_xunlock(&dev->mode_config.mutex);
3515 return ret;
3516 }
3517
3518 static void
free_vblank_event(void * arg)3519 free_vblank_event(void *arg)
3520 {
3521
3522 free(arg, DRM_MEM_KMS);
3523 }
3524
drm_mode_page_flip_ioctl(struct drm_device * dev,void * data,struct drm_file * file_priv)3525 int drm_mode_page_flip_ioctl(struct drm_device *dev,
3526 void *data, struct drm_file *file_priv)
3527 {
3528 struct drm_mode_crtc_page_flip *page_flip = data;
3529 struct drm_mode_object *obj;
3530 struct drm_crtc *crtc;
3531 struct drm_framebuffer *fb;
3532 struct drm_pending_vblank_event *e = NULL;
3533 #ifdef __linux__
3534 unsigned long flags;
3535 #endif
3536 int hdisplay, vdisplay;
3537 int ret = -EINVAL;
3538
3539 if (page_flip->flags & ~DRM_MODE_PAGE_FLIP_FLAGS ||
3540 page_flip->reserved != 0)
3541 return -EINVAL;
3542
3543 sx_xlock(&dev->mode_config.mutex);
3544 obj = drm_mode_object_find(dev, page_flip->crtc_id, DRM_MODE_OBJECT_CRTC);
3545 if (!obj)
3546 goto out;
3547 crtc = obj_to_crtc(obj);
3548
3549 if (crtc->fb == NULL) {
3550 /* The framebuffer is currently unbound, presumably
3551 * due to a hotplug event, that userspace has not
3552 * yet discovered.
3553 */
3554 ret = -EBUSY;
3555 goto out;
3556 }
3557
3558 if (crtc->funcs->page_flip == NULL)
3559 goto out;
3560
3561 obj = drm_mode_object_find(dev, page_flip->fb_id, DRM_MODE_OBJECT_FB);
3562 if (!obj)
3563 goto out;
3564 fb = obj_to_fb(obj);
3565
3566 hdisplay = crtc->mode.hdisplay;
3567 vdisplay = crtc->mode.vdisplay;
3568
3569 if (crtc->invert_dimensions) {
3570 int tmp;
3571 tmp = vdisplay;
3572 vdisplay = hdisplay;
3573 hdisplay = tmp;
3574 }
3575
3576 if (hdisplay > fb->width ||
3577 vdisplay > fb->height ||
3578 crtc->x > fb->width - hdisplay ||
3579 crtc->y > fb->height - vdisplay) {
3580 DRM_DEBUG_KMS("Invalid fb size %ux%u for CRTC viewport %ux%u+%d+%d%s.\n",
3581 fb->width, fb->height, hdisplay, vdisplay, crtc->x, crtc->y,
3582 crtc->invert_dimensions ? " (inverted)" : "");
3583 ret = -ENOSPC;
3584 goto out;
3585 }
3586
3587 if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) {
3588 ret = -ENOMEM;
3589 mtx_lock(&dev->event_lock);
3590 if (file_priv->event_space < sizeof e->event) {
3591 mtx_unlock(&dev->event_lock);
3592 goto out;
3593 }
3594 file_priv->event_space -= sizeof e->event;
3595 mtx_unlock(&dev->event_lock);
3596
3597 e = malloc(sizeof *e, DRM_MEM_KMS, M_WAITOK | M_ZERO);
3598 e->event.base.type = DRM_EVENT_FLIP_COMPLETE;
3599 e->event.base.length = sizeof e->event;
3600 e->event.user_data = page_flip->user_data;
3601 e->base.event = &e->event.base;
3602 e->base.file_priv = file_priv;
3603 e->base.destroy =
3604 (void (*) (struct drm_pending_event *)) free_vblank_event;
3605 }
3606
3607 ret = crtc->funcs->page_flip(crtc, fb, e);
3608 if (ret) {
3609 if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) {
3610 mtx_lock(&dev->event_lock);
3611 file_priv->event_space += sizeof e->event;
3612 mtx_unlock(&dev->event_lock);
3613 free(e, DRM_MEM_KMS);
3614 }
3615 }
3616
3617 out:
3618 sx_xunlock(&dev->mode_config.mutex);
3619 return ret;
3620 }
3621
drm_mode_config_reset(struct drm_device * dev)3622 void drm_mode_config_reset(struct drm_device *dev)
3623 {
3624 struct drm_crtc *crtc;
3625 struct drm_encoder *encoder;
3626 struct drm_connector *connector;
3627
3628 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
3629 if (crtc->funcs->reset)
3630 crtc->funcs->reset(crtc);
3631
3632 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head)
3633 if (encoder->funcs->reset)
3634 encoder->funcs->reset(encoder);
3635
3636 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
3637 connector->status = connector_status_unknown;
3638
3639 if (connector->funcs->reset)
3640 connector->funcs->reset(connector);
3641 }
3642 }
3643 EXPORT_SYMBOL(drm_mode_config_reset);
3644
drm_mode_create_dumb_ioctl(struct drm_device * dev,void * data,struct drm_file * file_priv)3645 int drm_mode_create_dumb_ioctl(struct drm_device *dev,
3646 void *data, struct drm_file *file_priv)
3647 {
3648 struct drm_mode_create_dumb *args = data;
3649
3650 if (!dev->driver->dumb_create)
3651 return -ENOSYS;
3652 return dev->driver->dumb_create(file_priv, dev, args);
3653 }
3654
drm_mode_mmap_dumb_ioctl(struct drm_device * dev,void * data,struct drm_file * file_priv)3655 int drm_mode_mmap_dumb_ioctl(struct drm_device *dev,
3656 void *data, struct drm_file *file_priv)
3657 {
3658 struct drm_mode_map_dumb *args = data;
3659
3660 /* call driver ioctl to get mmap offset */
3661 if (!dev->driver->dumb_map_offset)
3662 return -ENOSYS;
3663
3664 return dev->driver->dumb_map_offset(file_priv, dev, args->handle, &args->offset);
3665 }
3666
drm_mode_destroy_dumb_ioctl(struct drm_device * dev,void * data,struct drm_file * file_priv)3667 int drm_mode_destroy_dumb_ioctl(struct drm_device *dev,
3668 void *data, struct drm_file *file_priv)
3669 {
3670 struct drm_mode_destroy_dumb *args = data;
3671
3672 if (!dev->driver->dumb_destroy)
3673 return -ENOSYS;
3674
3675 return dev->driver->dumb_destroy(file_priv, dev, args->handle);
3676 }
3677
3678 /*
3679 * Just need to support RGB formats here for compat with code that doesn't
3680 * use pixel formats directly yet.
3681 */
drm_fb_get_bpp_depth(uint32_t format,unsigned int * depth,int * bpp)3682 void drm_fb_get_bpp_depth(uint32_t format, unsigned int *depth,
3683 int *bpp)
3684 {
3685 switch (format) {
3686 case DRM_FORMAT_C8:
3687 case DRM_FORMAT_RGB332:
3688 case DRM_FORMAT_BGR233:
3689 *depth = 8;
3690 *bpp = 8;
3691 break;
3692 case DRM_FORMAT_XRGB1555:
3693 case DRM_FORMAT_XBGR1555:
3694 case DRM_FORMAT_RGBX5551:
3695 case DRM_FORMAT_BGRX5551:
3696 case DRM_FORMAT_ARGB1555:
3697 case DRM_FORMAT_ABGR1555:
3698 case DRM_FORMAT_RGBA5551:
3699 case DRM_FORMAT_BGRA5551:
3700 *depth = 15;
3701 *bpp = 16;
3702 break;
3703 case DRM_FORMAT_RGB565:
3704 case DRM_FORMAT_BGR565:
3705 *depth = 16;
3706 *bpp = 16;
3707 break;
3708 case DRM_FORMAT_RGB888:
3709 case DRM_FORMAT_BGR888:
3710 *depth = 24;
3711 *bpp = 24;
3712 break;
3713 case DRM_FORMAT_XRGB8888:
3714 case DRM_FORMAT_XBGR8888:
3715 case DRM_FORMAT_RGBX8888:
3716 case DRM_FORMAT_BGRX8888:
3717 *depth = 24;
3718 *bpp = 32;
3719 break;
3720 case DRM_FORMAT_XRGB2101010:
3721 case DRM_FORMAT_XBGR2101010:
3722 case DRM_FORMAT_RGBX1010102:
3723 case DRM_FORMAT_BGRX1010102:
3724 case DRM_FORMAT_ARGB2101010:
3725 case DRM_FORMAT_ABGR2101010:
3726 case DRM_FORMAT_RGBA1010102:
3727 case DRM_FORMAT_BGRA1010102:
3728 *depth = 30;
3729 *bpp = 32;
3730 break;
3731 case DRM_FORMAT_ARGB8888:
3732 case DRM_FORMAT_ABGR8888:
3733 case DRM_FORMAT_RGBA8888:
3734 case DRM_FORMAT_BGRA8888:
3735 *depth = 32;
3736 *bpp = 32;
3737 break;
3738 default:
3739 DRM_DEBUG_KMS("unsupported pixel format\n");
3740 *depth = 0;
3741 *bpp = 0;
3742 break;
3743 }
3744 }
3745 EXPORT_SYMBOL(drm_fb_get_bpp_depth);
3746
3747 /**
3748 * drm_format_num_planes - get the number of planes for format
3749 * @format: pixel format (DRM_FORMAT_*)
3750 *
3751 * RETURNS:
3752 * The number of planes used by the specified pixel format.
3753 */
drm_format_num_planes(uint32_t format)3754 int drm_format_num_planes(uint32_t format)
3755 {
3756 switch (format) {
3757 case DRM_FORMAT_YUV410:
3758 case DRM_FORMAT_YVU410:
3759 case DRM_FORMAT_YUV411:
3760 case DRM_FORMAT_YVU411:
3761 case DRM_FORMAT_YUV420:
3762 case DRM_FORMAT_YVU420:
3763 case DRM_FORMAT_YUV422:
3764 case DRM_FORMAT_YVU422:
3765 case DRM_FORMAT_YUV444:
3766 case DRM_FORMAT_YVU444:
3767 return 3;
3768 case DRM_FORMAT_NV12:
3769 case DRM_FORMAT_NV21:
3770 case DRM_FORMAT_NV16:
3771 case DRM_FORMAT_NV61:
3772 case DRM_FORMAT_NV24:
3773 case DRM_FORMAT_NV42:
3774 return 2;
3775 default:
3776 return 1;
3777 }
3778 }
3779 EXPORT_SYMBOL(drm_format_num_planes);
3780
3781 /**
3782 * drm_format_plane_cpp - determine the bytes per pixel value
3783 * @format: pixel format (DRM_FORMAT_*)
3784 * @plane: plane index
3785 *
3786 * RETURNS:
3787 * The bytes per pixel value for the specified plane.
3788 */
drm_format_plane_cpp(uint32_t format,int plane)3789 int drm_format_plane_cpp(uint32_t format, int plane)
3790 {
3791 unsigned int depth;
3792 int bpp;
3793
3794 if (plane >= drm_format_num_planes(format))
3795 return 0;
3796
3797 switch (format) {
3798 case DRM_FORMAT_YUYV:
3799 case DRM_FORMAT_YVYU:
3800 case DRM_FORMAT_UYVY:
3801 case DRM_FORMAT_VYUY:
3802 return 2;
3803 case DRM_FORMAT_NV12:
3804 case DRM_FORMAT_NV21:
3805 case DRM_FORMAT_NV16:
3806 case DRM_FORMAT_NV61:
3807 case DRM_FORMAT_NV24:
3808 case DRM_FORMAT_NV42:
3809 return plane ? 2 : 1;
3810 case DRM_FORMAT_YUV410:
3811 case DRM_FORMAT_YVU410:
3812 case DRM_FORMAT_YUV411:
3813 case DRM_FORMAT_YVU411:
3814 case DRM_FORMAT_YUV420:
3815 case DRM_FORMAT_YVU420:
3816 case DRM_FORMAT_YUV422:
3817 case DRM_FORMAT_YVU422:
3818 case DRM_FORMAT_YUV444:
3819 case DRM_FORMAT_YVU444:
3820 return 1;
3821 default:
3822 drm_fb_get_bpp_depth(format, &depth, &bpp);
3823 return bpp >> 3;
3824 }
3825 }
3826 EXPORT_SYMBOL(drm_format_plane_cpp);
3827
3828 /**
3829 * drm_format_horz_chroma_subsampling - get the horizontal chroma subsampling factor
3830 * @format: pixel format (DRM_FORMAT_*)
3831 *
3832 * RETURNS:
3833 * The horizontal chroma subsampling factor for the
3834 * specified pixel format.
3835 */
drm_format_horz_chroma_subsampling(uint32_t format)3836 int drm_format_horz_chroma_subsampling(uint32_t format)
3837 {
3838 switch (format) {
3839 case DRM_FORMAT_YUV411:
3840 case DRM_FORMAT_YVU411:
3841 case DRM_FORMAT_YUV410:
3842 case DRM_FORMAT_YVU410:
3843 return 4;
3844 case DRM_FORMAT_YUYV:
3845 case DRM_FORMAT_YVYU:
3846 case DRM_FORMAT_UYVY:
3847 case DRM_FORMAT_VYUY:
3848 case DRM_FORMAT_NV12:
3849 case DRM_FORMAT_NV21:
3850 case DRM_FORMAT_NV16:
3851 case DRM_FORMAT_NV61:
3852 case DRM_FORMAT_YUV422:
3853 case DRM_FORMAT_YVU422:
3854 case DRM_FORMAT_YUV420:
3855 case DRM_FORMAT_YVU420:
3856 return 2;
3857 default:
3858 return 1;
3859 }
3860 }
3861 EXPORT_SYMBOL(drm_format_horz_chroma_subsampling);
3862
3863 /**
3864 * drm_format_vert_chroma_subsampling - get the vertical chroma subsampling factor
3865 * @format: pixel format (DRM_FORMAT_*)
3866 *
3867 * RETURNS:
3868 * The vertical chroma subsampling factor for the
3869 * specified pixel format.
3870 */
drm_format_vert_chroma_subsampling(uint32_t format)3871 int drm_format_vert_chroma_subsampling(uint32_t format)
3872 {
3873 switch (format) {
3874 case DRM_FORMAT_YUV410:
3875 case DRM_FORMAT_YVU410:
3876 return 4;
3877 case DRM_FORMAT_YUV420:
3878 case DRM_FORMAT_YVU420:
3879 case DRM_FORMAT_NV12:
3880 case DRM_FORMAT_NV21:
3881 return 2;
3882 default:
3883 return 1;
3884 }
3885 }
3886 EXPORT_SYMBOL(drm_format_vert_chroma_subsampling);
3887