blob: d7c449f0b1107269152b9de031393350964c3c7b [file] [log] [blame]
Dave Airlief453ba02008-11-07 14:05:41 -08001/*
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 <linux/list.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090033#include <linux/slab.h>
Paul Gortmaker2d1a8a42011-08-30 18:16:33 -040034#include <linux/export.h>
David Howells760285e2012-10-02 18:01:07 +010035#include <drm/drmP.h>
36#include <drm/drm_crtc.h>
37#include <drm/drm_edid.h>
38#include <drm/drm_fourcc.h>
Dave Airlief453ba02008-11-07 14:05:41 -080039
Daniel Vetter84849902012-12-02 00:28:11 +010040/**
41 * drm_modeset_lock_all - take all modeset locks
42 * @dev: drm device
43 *
44 * This function takes all modeset locks, suitable where a more fine-grained
45 * scheme isn't (yet) implemented.
46 */
47void drm_modeset_lock_all(struct drm_device *dev)
48{
Daniel Vetter29494c12012-12-02 02:18:25 +010049 struct drm_crtc *crtc;
50
Daniel Vetter84849902012-12-02 00:28:11 +010051 mutex_lock(&dev->mode_config.mutex);
Daniel Vetter29494c12012-12-02 02:18:25 +010052
53 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
54 mutex_lock_nest_lock(&crtc->mutex, &dev->mode_config.mutex);
Daniel Vetter84849902012-12-02 00:28:11 +010055}
56EXPORT_SYMBOL(drm_modeset_lock_all);
57
58/**
59 * drm_modeset_unlock_all - drop all modeset locks
60 * @dev: device
61 */
62void drm_modeset_unlock_all(struct drm_device *dev)
63{
Daniel Vetter29494c12012-12-02 02:18:25 +010064 struct drm_crtc *crtc;
65
66 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
67 mutex_unlock(&crtc->mutex);
68
Daniel Vetter84849902012-12-02 00:28:11 +010069 mutex_unlock(&dev->mode_config.mutex);
70}
71EXPORT_SYMBOL(drm_modeset_unlock_all);
72
Daniel Vetter6aed8ec2013-01-20 17:32:21 +010073/**
74 * drm_warn_on_modeset_not_all_locked - check that all modeset locks are locked
75 * @dev: device
76 */
77void drm_warn_on_modeset_not_all_locked(struct drm_device *dev)
78{
79 struct drm_crtc *crtc;
80
Daniel Vettera9b054e2013-05-02 09:43:05 +020081 /* Locking is currently fubar in the panic handler. */
82 if (oops_in_progress)
83 return;
84
Daniel Vetter6aed8ec2013-01-20 17:32:21 +010085 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
86 WARN_ON(!mutex_is_locked(&crtc->mutex));
87
88 WARN_ON(!mutex_is_locked(&dev->mode_config.mutex));
89}
90EXPORT_SYMBOL(drm_warn_on_modeset_not_all_locked);
91
Dave Airlief453ba02008-11-07 14:05:41 -080092/* Avoid boilerplate. I'm tired of typing. */
93#define DRM_ENUM_NAME_FN(fnname, list) \
94 char *fnname(int val) \
95 { \
96 int i; \
97 for (i = 0; i < ARRAY_SIZE(list); i++) { \
98 if (list[i].type == val) \
99 return list[i].name; \
100 } \
101 return "(unknown)"; \
102 }
103
104/*
105 * Global properties
106 */
107static struct drm_prop_enum_list drm_dpms_enum_list[] =
108{ { DRM_MODE_DPMS_ON, "On" },
109 { DRM_MODE_DPMS_STANDBY, "Standby" },
110 { DRM_MODE_DPMS_SUSPEND, "Suspend" },
111 { DRM_MODE_DPMS_OFF, "Off" }
112};
113
114DRM_ENUM_NAME_FN(drm_get_dpms_name, drm_dpms_enum_list)
115
116/*
117 * Optional properties
118 */
119static struct drm_prop_enum_list drm_scaling_mode_enum_list[] =
120{
Jesse Barnes53bd8382009-07-01 10:04:40 -0700121 { DRM_MODE_SCALE_NONE, "None" },
122 { DRM_MODE_SCALE_FULLSCREEN, "Full" },
123 { DRM_MODE_SCALE_CENTER, "Center" },
124 { DRM_MODE_SCALE_ASPECT, "Full aspect" },
Dave Airlief453ba02008-11-07 14:05:41 -0800125};
126
127static struct drm_prop_enum_list drm_dithering_mode_enum_list[] =
128{
129 { DRM_MODE_DITHERING_OFF, "Off" },
130 { DRM_MODE_DITHERING_ON, "On" },
Ben Skeggs92897b52010-07-16 15:09:17 +1000131 { DRM_MODE_DITHERING_AUTO, "Automatic" },
Dave Airlief453ba02008-11-07 14:05:41 -0800132};
133
134/*
135 * Non-global properties, but "required" for certain connectors.
136 */
137static struct drm_prop_enum_list drm_dvi_i_select_enum_list[] =
138{
139 { DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" }, /* DVI-I and TV-out */
140 { DRM_MODE_SUBCONNECTOR_DVID, "DVI-D" }, /* DVI-I */
141 { DRM_MODE_SUBCONNECTOR_DVIA, "DVI-A" }, /* DVI-I */
142};
143
144DRM_ENUM_NAME_FN(drm_get_dvi_i_select_name, drm_dvi_i_select_enum_list)
145
146static struct drm_prop_enum_list drm_dvi_i_subconnector_enum_list[] =
147{
148 { DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" }, /* DVI-I and TV-out */
149 { DRM_MODE_SUBCONNECTOR_DVID, "DVI-D" }, /* DVI-I */
150 { DRM_MODE_SUBCONNECTOR_DVIA, "DVI-A" }, /* DVI-I */
151};
152
153DRM_ENUM_NAME_FN(drm_get_dvi_i_subconnector_name,
154 drm_dvi_i_subconnector_enum_list)
155
156static struct drm_prop_enum_list drm_tv_select_enum_list[] =
157{
158 { DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" }, /* DVI-I and TV-out */
159 { DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */
160 { DRM_MODE_SUBCONNECTOR_SVIDEO, "SVIDEO" }, /* TV-out */
161 { DRM_MODE_SUBCONNECTOR_Component, "Component" }, /* TV-out */
Francisco Jerezaeaa1ad2009-08-02 04:19:19 +0200162 { DRM_MODE_SUBCONNECTOR_SCART, "SCART" }, /* TV-out */
Dave Airlief453ba02008-11-07 14:05:41 -0800163};
164
165DRM_ENUM_NAME_FN(drm_get_tv_select_name, drm_tv_select_enum_list)
166
167static struct drm_prop_enum_list drm_tv_subconnector_enum_list[] =
168{
169 { DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" }, /* DVI-I and TV-out */
170 { DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */
171 { DRM_MODE_SUBCONNECTOR_SVIDEO, "SVIDEO" }, /* TV-out */
172 { DRM_MODE_SUBCONNECTOR_Component, "Component" }, /* TV-out */
Francisco Jerezaeaa1ad2009-08-02 04:19:19 +0200173 { DRM_MODE_SUBCONNECTOR_SCART, "SCART" }, /* TV-out */
Dave Airlief453ba02008-11-07 14:05:41 -0800174};
175
176DRM_ENUM_NAME_FN(drm_get_tv_subconnector_name,
177 drm_tv_subconnector_enum_list)
178
Jakob Bornecrantz884840a2009-12-03 23:25:47 +0000179static struct drm_prop_enum_list drm_dirty_info_enum_list[] = {
180 { DRM_MODE_DIRTY_OFF, "Off" },
181 { DRM_MODE_DIRTY_ON, "On" },
182 { DRM_MODE_DIRTY_ANNOTATE, "Annotate" },
183};
184
Dave Airlief453ba02008-11-07 14:05:41 -0800185struct drm_conn_prop_enum_list {
186 int type;
187 char *name;
188 int count;
189};
190
191/*
192 * Connector and encoder types.
193 */
194static struct drm_conn_prop_enum_list drm_connector_enum_list[] =
195{ { DRM_MODE_CONNECTOR_Unknown, "Unknown", 0 },
196 { DRM_MODE_CONNECTOR_VGA, "VGA", 0 },
197 { DRM_MODE_CONNECTOR_DVII, "DVI-I", 0 },
198 { DRM_MODE_CONNECTOR_DVID, "DVI-D", 0 },
199 { DRM_MODE_CONNECTOR_DVIA, "DVI-A", 0 },
200 { DRM_MODE_CONNECTOR_Composite, "Composite", 0 },
201 { DRM_MODE_CONNECTOR_SVIDEO, "SVIDEO", 0 },
202 { DRM_MODE_CONNECTOR_LVDS, "LVDS", 0 },
203 { DRM_MODE_CONNECTOR_Component, "Component", 0 },
Alex Deuchere76116c2010-12-08 19:09:42 -0500204 { DRM_MODE_CONNECTOR_9PinDIN, "DIN", 0 },
205 { DRM_MODE_CONNECTOR_DisplayPort, "DP", 0 },
206 { DRM_MODE_CONNECTOR_HDMIA, "HDMI-A", 0 },
207 { DRM_MODE_CONNECTOR_HDMIB, "HDMI-B", 0 },
Francisco Jerez74bd3c22009-08-02 04:19:18 +0200208 { DRM_MODE_CONNECTOR_TV, "TV", 0 },
Alex Deuchere76116c2010-12-08 19:09:42 -0500209 { DRM_MODE_CONNECTOR_eDP, "eDP", 0 },
Thomas Hellstroma7331e52011-10-22 10:36:19 +0200210 { DRM_MODE_CONNECTOR_VIRTUAL, "Virtual", 0},
Dave Airlief453ba02008-11-07 14:05:41 -0800211};
212
213static struct drm_prop_enum_list drm_encoder_enum_list[] =
214{ { DRM_MODE_ENCODER_NONE, "None" },
215 { DRM_MODE_ENCODER_DAC, "DAC" },
216 { DRM_MODE_ENCODER_TMDS, "TMDS" },
217 { DRM_MODE_ENCODER_LVDS, "LVDS" },
218 { DRM_MODE_ENCODER_TVDAC, "TV" },
Thomas Hellstroma7331e52011-10-22 10:36:19 +0200219 { DRM_MODE_ENCODER_VIRTUAL, "Virtual" },
Dave Airlief453ba02008-11-07 14:05:41 -0800220};
221
222char *drm_get_encoder_name(struct drm_encoder *encoder)
223{
224 static char buf[32];
225
226 snprintf(buf, 32, "%s-%d",
227 drm_encoder_enum_list[encoder->encoder_type].name,
228 encoder->base.id);
229 return buf;
230}
Dave Airlie13a81952009-09-07 15:45:33 +1000231EXPORT_SYMBOL(drm_get_encoder_name);
Dave Airlief453ba02008-11-07 14:05:41 -0800232
233char *drm_get_connector_name(struct drm_connector *connector)
234{
235 static char buf[32];
236
237 snprintf(buf, 32, "%s-%d",
238 drm_connector_enum_list[connector->connector_type].name,
239 connector->connector_type_id);
240 return buf;
241}
242EXPORT_SYMBOL(drm_get_connector_name);
243
244char *drm_get_connector_status_name(enum drm_connector_status status)
245{
246 if (status == connector_status_connected)
247 return "connected";
248 else if (status == connector_status_disconnected)
249 return "disconnected";
250 else
251 return "unknown";
252}
253
254/**
Daniel Vetter065a50ed2012-12-02 00:09:18 +0100255 * drm_mode_object_get - allocate a new modeset identifier
Dave Airlief453ba02008-11-07 14:05:41 -0800256 * @dev: DRM device
Daniel Vetter065a50ed2012-12-02 00:09:18 +0100257 * @obj: object pointer, used to generate unique ID
258 * @obj_type: object type
Dave Airlief453ba02008-11-07 14:05:41 -0800259 *
Dave Airlief453ba02008-11-07 14:05:41 -0800260 * Create a unique identifier based on @ptr in @dev's identifier space. Used
261 * for tracking modes, CRTCs and connectors.
262 *
263 * RETURNS:
264 * New unique (relative to other objects in @dev) integer identifier for the
265 * object.
266 */
267static int drm_mode_object_get(struct drm_device *dev,
268 struct drm_mode_object *obj, uint32_t obj_type)
269{
Dave Airlief453ba02008-11-07 14:05:41 -0800270 int ret;
271
Jesse Barnesad2563c2009-01-19 17:21:45 +1000272 mutex_lock(&dev->mode_config.idr_mutex);
Tejun Heo2e928812013-02-27 17:04:08 -0800273 ret = idr_alloc(&dev->mode_config.crtc_idr, obj, 1, 0, GFP_KERNEL);
274 if (ret >= 0) {
Daniel Vetter4b096ac2012-12-10 21:19:18 +0100275 /*
276 * Set up the object linking under the protection of the idr
277 * lock so that other users can't see inconsistent state.
278 */
Tejun Heo2e928812013-02-27 17:04:08 -0800279 obj->id = ret;
Daniel Vetter4b096ac2012-12-10 21:19:18 +0100280 obj->type = obj_type;
281 }
Jesse Barnesad2563c2009-01-19 17:21:45 +1000282 mutex_unlock(&dev->mode_config.idr_mutex);
Daniel Vetter4b096ac2012-12-10 21:19:18 +0100283
Tejun Heo2e928812013-02-27 17:04:08 -0800284 return ret < 0 ? ret : 0;
Dave Airlief453ba02008-11-07 14:05:41 -0800285}
286
287/**
Daniel Vetter065a50ed2012-12-02 00:09:18 +0100288 * drm_mode_object_put - free a modeset identifer
Dave Airlief453ba02008-11-07 14:05:41 -0800289 * @dev: DRM device
Daniel Vetter065a50ed2012-12-02 00:09:18 +0100290 * @object: object to free
Dave Airlief453ba02008-11-07 14:05:41 -0800291 *
Dave Airlief453ba02008-11-07 14:05:41 -0800292 * Free @id from @dev's unique identifier pool.
293 */
294static void drm_mode_object_put(struct drm_device *dev,
295 struct drm_mode_object *object)
296{
Jesse Barnesad2563c2009-01-19 17:21:45 +1000297 mutex_lock(&dev->mode_config.idr_mutex);
Dave Airlief453ba02008-11-07 14:05:41 -0800298 idr_remove(&dev->mode_config.crtc_idr, object->id);
Jesse Barnesad2563c2009-01-19 17:21:45 +1000299 mutex_unlock(&dev->mode_config.idr_mutex);
Dave Airlief453ba02008-11-07 14:05:41 -0800300}
301
Daniel Vetter786b99e2012-12-02 21:53:40 +0100302/**
303 * drm_mode_object_find - look up a drm object with static lifetime
304 * @dev: drm device
305 * @id: id of the mode object
306 * @type: type of the mode object
307 *
308 * Note that framebuffers cannot be looked up with this functions - since those
309 * are reference counted, they need special treatment.
310 */
Daniel Vetter7a9c9062009-09-15 22:57:31 +0200311struct drm_mode_object *drm_mode_object_find(struct drm_device *dev,
312 uint32_t id, uint32_t type)
Dave Airlief453ba02008-11-07 14:05:41 -0800313{
Jesse Barnesad2563c2009-01-19 17:21:45 +1000314 struct drm_mode_object *obj = NULL;
Dave Airlief453ba02008-11-07 14:05:41 -0800315
Daniel Vetter786b99e2012-12-02 21:53:40 +0100316 /* Framebuffers are reference counted and need their own lookup
317 * function.*/
318 WARN_ON(type == DRM_MODE_OBJECT_FB);
319
Jesse Barnesad2563c2009-01-19 17:21:45 +1000320 mutex_lock(&dev->mode_config.idr_mutex);
Dave Airlief453ba02008-11-07 14:05:41 -0800321 obj = idr_find(&dev->mode_config.crtc_idr, id);
322 if (!obj || (obj->type != type) || (obj->id != id))
Jesse Barnesad2563c2009-01-19 17:21:45 +1000323 obj = NULL;
324 mutex_unlock(&dev->mode_config.idr_mutex);
Dave Airlief453ba02008-11-07 14:05:41 -0800325
326 return obj;
327}
328EXPORT_SYMBOL(drm_mode_object_find);
329
330/**
Dave Airlief453ba02008-11-07 14:05:41 -0800331 * drm_framebuffer_init - initialize a framebuffer
332 * @dev: DRM device
Daniel Vetter065a50ed2012-12-02 00:09:18 +0100333 * @fb: framebuffer to be initialized
334 * @funcs: ... with these functions
Dave Airlief453ba02008-11-07 14:05:41 -0800335 *
Dave Airlief453ba02008-11-07 14:05:41 -0800336 * Allocates an ID for the framebuffer's parent mode object, sets its mode
337 * functions & device file and adds it to the master fd list.
338 *
Daniel Vetter4b096ac2012-12-10 21:19:18 +0100339 * IMPORTANT:
340 * This functions publishes the fb and makes it available for concurrent access
341 * by other users. Which means by this point the fb _must_ be fully set up -
342 * since all the fb attributes are invariant over its lifetime, no further
343 * locking but only correct reference counting is required.
344 *
Dave Airlief453ba02008-11-07 14:05:41 -0800345 * RETURNS:
André Goddard Rosaaf901ca2009-11-14 13:09:05 -0200346 * Zero on success, error code on failure.
Dave Airlief453ba02008-11-07 14:05:41 -0800347 */
348int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb,
349 const struct drm_framebuffer_funcs *funcs)
350{
351 int ret;
352
Daniel Vetter4b096ac2012-12-10 21:19:18 +0100353 mutex_lock(&dev->mode_config.fb_lock);
Rob Clarkf7eff602012-09-05 21:48:38 +0000354 kref_init(&fb->refcount);
Daniel Vetter4b096ac2012-12-10 21:19:18 +0100355 INIT_LIST_HEAD(&fb->filp_head);
356 fb->dev = dev;
357 fb->funcs = funcs;
Rob Clarkf7eff602012-09-05 21:48:38 +0000358
Dave Airlief453ba02008-11-07 14:05:41 -0800359 ret = drm_mode_object_get(dev, &fb->base, DRM_MODE_OBJECT_FB);
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +0200360 if (ret)
Daniel Vetter4b096ac2012-12-10 21:19:18 +0100361 goto out;
Dave Airlief453ba02008-11-07 14:05:41 -0800362
Daniel Vetter2b677e82012-12-10 21:16:05 +0100363 /* Grab the idr reference. */
364 drm_framebuffer_reference(fb);
365
Dave Airlief453ba02008-11-07 14:05:41 -0800366 dev->mode_config.num_fb++;
367 list_add(&fb->head, &dev->mode_config.fb_list);
Daniel Vetter4b096ac2012-12-10 21:19:18 +0100368out:
369 mutex_unlock(&dev->mode_config.fb_lock);
Dave Airlief453ba02008-11-07 14:05:41 -0800370
371 return 0;
372}
373EXPORT_SYMBOL(drm_framebuffer_init);
374
Rob Clarkf7eff602012-09-05 21:48:38 +0000375static void drm_framebuffer_free(struct kref *kref)
376{
377 struct drm_framebuffer *fb =
378 container_of(kref, struct drm_framebuffer, refcount);
379 fb->funcs->destroy(fb);
380}
381
Daniel Vetter2b677e82012-12-10 21:16:05 +0100382static struct drm_framebuffer *__drm_framebuffer_lookup(struct drm_device *dev,
383 uint32_t id)
384{
385 struct drm_mode_object *obj = NULL;
386 struct drm_framebuffer *fb;
387
388 mutex_lock(&dev->mode_config.idr_mutex);
389 obj = idr_find(&dev->mode_config.crtc_idr, id);
390 if (!obj || (obj->type != DRM_MODE_OBJECT_FB) || (obj->id != id))
391 fb = NULL;
392 else
393 fb = obj_to_fb(obj);
394 mutex_unlock(&dev->mode_config.idr_mutex);
395
396 return fb;
397}
398
Rob Clarkf7eff602012-09-05 21:48:38 +0000399/**
Daniel Vetter786b99e2012-12-02 21:53:40 +0100400 * drm_framebuffer_lookup - look up a drm framebuffer and grab a reference
401 * @dev: drm device
402 * @id: id of the fb object
403 *
404 * If successful, this grabs an additional reference to the framebuffer -
405 * callers need to make sure to eventually unreference the returned framebuffer
406 * again.
407 */
408struct drm_framebuffer *drm_framebuffer_lookup(struct drm_device *dev,
409 uint32_t id)
410{
Daniel Vetter786b99e2012-12-02 21:53:40 +0100411 struct drm_framebuffer *fb;
412
413 mutex_lock(&dev->mode_config.fb_lock);
Daniel Vetter2b677e82012-12-10 21:16:05 +0100414 fb = __drm_framebuffer_lookup(dev, id);
Daniel Vetter786b99e2012-12-02 21:53:40 +0100415 if (fb)
archit taneja9131d3d2013-04-10 08:59:39 +0000416 drm_framebuffer_reference(fb);
Daniel Vetter786b99e2012-12-02 21:53:40 +0100417 mutex_unlock(&dev->mode_config.fb_lock);
418
419 return fb;
420}
421EXPORT_SYMBOL(drm_framebuffer_lookup);
422
423/**
Rob Clarkf7eff602012-09-05 21:48:38 +0000424 * drm_framebuffer_unreference - unref a framebuffer
Daniel Vetter065a50ed2012-12-02 00:09:18 +0100425 * @fb: framebuffer to unref
426 *
427 * This functions decrements the fb's refcount and frees it if it drops to zero.
Rob Clarkf7eff602012-09-05 21:48:38 +0000428 */
429void drm_framebuffer_unreference(struct drm_framebuffer *fb)
430{
Rob Clarkf7eff602012-09-05 21:48:38 +0000431 DRM_DEBUG("FB ID: %d\n", fb->base.id);
Rob Clarkf7eff602012-09-05 21:48:38 +0000432 kref_put(&fb->refcount, drm_framebuffer_free);
433}
434EXPORT_SYMBOL(drm_framebuffer_unreference);
435
436/**
437 * drm_framebuffer_reference - incr the fb refcnt
Daniel Vetter065a50ed2012-12-02 00:09:18 +0100438 * @fb: framebuffer
Rob Clarkf7eff602012-09-05 21:48:38 +0000439 */
440void drm_framebuffer_reference(struct drm_framebuffer *fb)
441{
442 DRM_DEBUG("FB ID: %d\n", fb->base.id);
443 kref_get(&fb->refcount);
444}
445EXPORT_SYMBOL(drm_framebuffer_reference);
446
Daniel Vetter2b677e82012-12-10 21:16:05 +0100447static void drm_framebuffer_free_bug(struct kref *kref)
448{
449 BUG();
450}
451
Daniel Vetter6c2a7532012-12-11 00:59:24 +0100452static void __drm_framebuffer_unreference(struct drm_framebuffer *fb)
453{
454 DRM_DEBUG("FB ID: %d\n", fb->base.id);
455 kref_put(&fb->refcount, drm_framebuffer_free_bug);
456}
457
Daniel Vetter2b677e82012-12-10 21:16:05 +0100458/* dev->mode_config.fb_lock must be held! */
459static void __drm_framebuffer_unregister(struct drm_device *dev,
460 struct drm_framebuffer *fb)
461{
462 mutex_lock(&dev->mode_config.idr_mutex);
463 idr_remove(&dev->mode_config.crtc_idr, fb->base.id);
464 mutex_unlock(&dev->mode_config.idr_mutex);
465
466 fb->base.id = 0;
467
Daniel Vetter6c2a7532012-12-11 00:59:24 +0100468 __drm_framebuffer_unreference(fb);
Daniel Vetter2b677e82012-12-10 21:16:05 +0100469}
470
Dave Airlief453ba02008-11-07 14:05:41 -0800471/**
Daniel Vetter36206362012-12-10 20:42:17 +0100472 * drm_framebuffer_unregister_private - unregister a private fb from the lookup idr
473 * @fb: fb to unregister
474 *
475 * Drivers need to call this when cleaning up driver-private framebuffers, e.g.
476 * those used for fbdev. Note that the caller must hold a reference of it's own,
477 * i.e. the object may not be destroyed through this call (since it'll lead to a
478 * locking inversion).
479 */
480void drm_framebuffer_unregister_private(struct drm_framebuffer *fb)
481{
Daniel Vetter2b677e82012-12-10 21:16:05 +0100482 struct drm_device *dev = fb->dev;
483
484 mutex_lock(&dev->mode_config.fb_lock);
485 /* Mark fb as reaped and drop idr ref. */
486 __drm_framebuffer_unregister(dev, fb);
487 mutex_unlock(&dev->mode_config.fb_lock);
Daniel Vetter36206362012-12-10 20:42:17 +0100488}
489EXPORT_SYMBOL(drm_framebuffer_unregister_private);
490
491/**
Dave Airlief453ba02008-11-07 14:05:41 -0800492 * drm_framebuffer_cleanup - remove a framebuffer object
493 * @fb: framebuffer to remove
494 *
Daniel Vetter36206362012-12-10 20:42:17 +0100495 * Cleanup references to a user-created framebuffer. This function is intended
496 * to be used from the drivers ->destroy callback.
497 *
498 * Note that this function does not remove the fb from active usuage - if it is
499 * still used anywhere, hilarity can ensue since userspace could call getfb on
500 * the id and get back -EINVAL. Obviously no concern at driver unload time.
501 *
502 * Also, the framebuffer will not be removed from the lookup idr - for
503 * user-created framebuffers this will happen in in the rmfb ioctl. For
504 * driver-private objects (e.g. for fbdev) drivers need to explicitly call
505 * drm_framebuffer_unregister_private.
Dave Airlief453ba02008-11-07 14:05:41 -0800506 */
507void drm_framebuffer_cleanup(struct drm_framebuffer *fb)
508{
509 struct drm_device *dev = fb->dev;
Daniel Vetter8faf6b12012-12-01 23:43:11 +0100510
Daniel Vetter4b096ac2012-12-10 21:19:18 +0100511 mutex_lock(&dev->mode_config.fb_lock);
Rob Clarkf7eff602012-09-05 21:48:38 +0000512 list_del(&fb->head);
513 dev->mode_config.num_fb--;
Daniel Vetter4b096ac2012-12-10 21:19:18 +0100514 mutex_unlock(&dev->mode_config.fb_lock);
Rob Clarkf7eff602012-09-05 21:48:38 +0000515}
516EXPORT_SYMBOL(drm_framebuffer_cleanup);
517
518/**
519 * drm_framebuffer_remove - remove and unreference a framebuffer object
520 * @fb: framebuffer to remove
521 *
Rob Clarkf7eff602012-09-05 21:48:38 +0000522 * Scans all the CRTCs and planes in @dev's mode_config. If they're
Daniel Vetter36206362012-12-10 20:42:17 +0100523 * using @fb, removes it, setting it to NULL. Then drops the reference to the
Daniel Vetterb62584e2012-12-11 16:51:35 +0100524 * passed-in framebuffer. Might take the modeset locks.
525 *
526 * Note that this function optimizes the cleanup away if the caller holds the
527 * last reference to the framebuffer. It is also guaranteed to not take the
528 * modeset locks in this case.
Rob Clarkf7eff602012-09-05 21:48:38 +0000529 */
530void drm_framebuffer_remove(struct drm_framebuffer *fb)
531{
532 struct drm_device *dev = fb->dev;
Dave Airlief453ba02008-11-07 14:05:41 -0800533 struct drm_crtc *crtc;
Jesse Barnes8cf5c912011-11-14 14:51:27 -0800534 struct drm_plane *plane;
Dave Airlie5ef5f722009-08-17 13:11:23 +1000535 struct drm_mode_set set;
536 int ret;
Dave Airlief453ba02008-11-07 14:05:41 -0800537
Daniel Vetter4b096ac2012-12-10 21:19:18 +0100538 WARN_ON(!list_empty(&fb->filp_head));
Daniel Vetter8faf6b12012-12-01 23:43:11 +0100539
Daniel Vetterb62584e2012-12-11 16:51:35 +0100540 /*
541 * drm ABI mandates that we remove any deleted framebuffers from active
542 * useage. But since most sane clients only remove framebuffers they no
543 * longer need, try to optimize this away.
544 *
545 * Since we're holding a reference ourselves, observing a refcount of 1
546 * means that we're the last holder and can skip it. Also, the refcount
547 * can never increase from 1 again, so we don't need any barriers or
548 * locks.
549 *
550 * Note that userspace could try to race with use and instate a new
551 * usage _after_ we've cleared all current ones. End result will be an
552 * in-use fb with fb-id == 0. Userspace is allowed to shoot its own foot
553 * in this manner.
554 */
555 if (atomic_read(&fb->refcount.refcount) > 1) {
556 drm_modeset_lock_all(dev);
557 /* remove from any CRTC */
558 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
559 if (crtc->fb == fb) {
560 /* should turn off the crtc */
561 memset(&set, 0, sizeof(struct drm_mode_set));
562 set.crtc = crtc;
563 set.fb = NULL;
564 ret = drm_mode_set_config_internal(&set);
565 if (ret)
566 DRM_ERROR("failed to reset crtc %p when fb was deleted\n", crtc);
567 }
Dave Airlie5ef5f722009-08-17 13:11:23 +1000568 }
Dave Airlief453ba02008-11-07 14:05:41 -0800569
Daniel Vetterb62584e2012-12-11 16:51:35 +0100570 list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
571 if (plane->fb == fb) {
572 /* should turn off the crtc */
573 ret = plane->funcs->disable_plane(plane);
574 if (ret)
575 DRM_ERROR("failed to disable plane with busy fb\n");
576 /* disconnect the plane from the fb and crtc: */
577 __drm_framebuffer_unreference(plane->fb);
578 plane->fb = NULL;
579 plane->crtc = NULL;
580 }
Jesse Barnes8cf5c912011-11-14 14:51:27 -0800581 }
Daniel Vetterb62584e2012-12-11 16:51:35 +0100582 drm_modeset_unlock_all(dev);
Jesse Barnes8cf5c912011-11-14 14:51:27 -0800583 }
584
Rob Clarkf7eff602012-09-05 21:48:38 +0000585 drm_framebuffer_unreference(fb);
Dave Airlief453ba02008-11-07 14:05:41 -0800586}
Rob Clarkf7eff602012-09-05 21:48:38 +0000587EXPORT_SYMBOL(drm_framebuffer_remove);
Dave Airlief453ba02008-11-07 14:05:41 -0800588
589/**
590 * drm_crtc_init - Initialise a new CRTC object
591 * @dev: DRM device
592 * @crtc: CRTC object to init
593 * @funcs: callbacks for the new CRTC
594 *
Dave Airlief453ba02008-11-07 14:05:41 -0800595 * Inits a new object created as base part of an driver crtc object.
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +0200596 *
597 * RETURNS:
598 * Zero on success, error code on failure.
Dave Airlief453ba02008-11-07 14:05:41 -0800599 */
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +0200600int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
Dave Airlief453ba02008-11-07 14:05:41 -0800601 const struct drm_crtc_funcs *funcs)
602{
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +0200603 int ret;
604
Dave Airlief453ba02008-11-07 14:05:41 -0800605 crtc->dev = dev;
606 crtc->funcs = funcs;
Rob Clark7c80e122012-09-04 16:35:56 +0000607 crtc->invert_dimensions = false;
Dave Airlief453ba02008-11-07 14:05:41 -0800608
Daniel Vetter84849902012-12-02 00:28:11 +0100609 drm_modeset_lock_all(dev);
Daniel Vetter29494c12012-12-02 02:18:25 +0100610 mutex_init(&crtc->mutex);
611 mutex_lock_nest_lock(&crtc->mutex, &dev->mode_config.mutex);
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +0200612
613 ret = drm_mode_object_get(dev, &crtc->base, DRM_MODE_OBJECT_CRTC);
614 if (ret)
615 goto out;
Dave Airlief453ba02008-11-07 14:05:41 -0800616
Paulo Zanonibffd9de02012-05-15 18:09:05 -0300617 crtc->base.properties = &crtc->properties;
618
Dave Airlief453ba02008-11-07 14:05:41 -0800619 list_add_tail(&crtc->head, &dev->mode_config.crtc_list);
620 dev->mode_config.num_crtc++;
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +0200621
622 out:
Daniel Vetter84849902012-12-02 00:28:11 +0100623 drm_modeset_unlock_all(dev);
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +0200624
625 return ret;
Dave Airlief453ba02008-11-07 14:05:41 -0800626}
627EXPORT_SYMBOL(drm_crtc_init);
628
629/**
630 * drm_crtc_cleanup - Cleans up the core crtc usage.
631 * @crtc: CRTC to cleanup
632 *
Dave Airlief453ba02008-11-07 14:05:41 -0800633 * Cleanup @crtc. Removes from drm modesetting space
634 * does NOT free object, caller does that.
635 */
636void drm_crtc_cleanup(struct drm_crtc *crtc)
637{
638 struct drm_device *dev = crtc->dev;
639
Sachin Kamat9e1c1562012-11-19 09:44:56 +0000640 kfree(crtc->gamma_store);
641 crtc->gamma_store = NULL;
Dave Airlief453ba02008-11-07 14:05:41 -0800642
643 drm_mode_object_put(dev, &crtc->base);
644 list_del(&crtc->head);
645 dev->mode_config.num_crtc--;
646}
647EXPORT_SYMBOL(drm_crtc_cleanup);
648
649/**
650 * drm_mode_probed_add - add a mode to a connector's probed mode list
651 * @connector: connector the new mode
652 * @mode: mode data
653 *
Dave Airlief453ba02008-11-07 14:05:41 -0800654 * Add @mode to @connector's mode list for later use.
655 */
656void drm_mode_probed_add(struct drm_connector *connector,
657 struct drm_display_mode *mode)
658{
659 list_add(&mode->head, &connector->probed_modes);
660}
661EXPORT_SYMBOL(drm_mode_probed_add);
662
663/**
664 * drm_mode_remove - remove and free a mode
665 * @connector: connector list to modify
666 * @mode: mode to remove
667 *
Dave Airlief453ba02008-11-07 14:05:41 -0800668 * Remove @mode from @connector's mode list, then free it.
669 */
670void drm_mode_remove(struct drm_connector *connector,
671 struct drm_display_mode *mode)
672{
673 list_del(&mode->head);
Sascha Hauer554f1d72012-02-01 11:38:19 +0100674 drm_mode_destroy(connector->dev, mode);
Dave Airlief453ba02008-11-07 14:05:41 -0800675}
676EXPORT_SYMBOL(drm_mode_remove);
677
678/**
679 * drm_connector_init - Init a preallocated connector
680 * @dev: DRM device
681 * @connector: the connector to init
682 * @funcs: callbacks for this connector
Daniel Vetter065a50ed2012-12-02 00:09:18 +0100683 * @connector_type: user visible type of the connector
Dave Airlief453ba02008-11-07 14:05:41 -0800684 *
Dave Airlief453ba02008-11-07 14:05:41 -0800685 * Initialises a preallocated connector. Connectors should be
686 * subclassed as part of driver connector objects.
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +0200687 *
688 * RETURNS:
689 * Zero on success, error code on failure.
Dave Airlief453ba02008-11-07 14:05:41 -0800690 */
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +0200691int drm_connector_init(struct drm_device *dev,
692 struct drm_connector *connector,
693 const struct drm_connector_funcs *funcs,
694 int connector_type)
Dave Airlief453ba02008-11-07 14:05:41 -0800695{
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +0200696 int ret;
697
Daniel Vetter84849902012-12-02 00:28:11 +0100698 drm_modeset_lock_all(dev);
Dave Airlief453ba02008-11-07 14:05:41 -0800699
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +0200700 ret = drm_mode_object_get(dev, &connector->base, DRM_MODE_OBJECT_CONNECTOR);
701 if (ret)
702 goto out;
703
Paulo Zanoni7e3bdf42012-05-15 18:09:01 -0300704 connector->base.properties = &connector->properties;
Dave Airlief453ba02008-11-07 14:05:41 -0800705 connector->dev = dev;
706 connector->funcs = funcs;
Dave Airlief453ba02008-11-07 14:05:41 -0800707 connector->connector_type = connector_type;
708 connector->connector_type_id =
709 ++drm_connector_enum_list[connector_type].count; /* TODO */
Dave Airlief453ba02008-11-07 14:05:41 -0800710 INIT_LIST_HEAD(&connector->probed_modes);
711 INIT_LIST_HEAD(&connector->modes);
712 connector->edid_blob_ptr = NULL;
Daniel Vetter5e2cb2f2012-10-23 18:23:35 +0000713 connector->status = connector_status_unknown;
Dave Airlief453ba02008-11-07 14:05:41 -0800714
715 list_add_tail(&connector->head, &dev->mode_config.connector_list);
716 dev->mode_config.num_connector++;
717
Thomas Hellstroma7331e52011-10-22 10:36:19 +0200718 if (connector_type != DRM_MODE_CONNECTOR_VIRTUAL)
Rob Clark58495562012-10-11 20:50:56 -0500719 drm_object_attach_property(&connector->base,
Thomas Hellstroma7331e52011-10-22 10:36:19 +0200720 dev->mode_config.edid_property,
721 0);
Dave Airlief453ba02008-11-07 14:05:41 -0800722
Rob Clark58495562012-10-11 20:50:56 -0500723 drm_object_attach_property(&connector->base,
Dave Airlief453ba02008-11-07 14:05:41 -0800724 dev->mode_config.dpms_property, 0);
725
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +0200726 out:
Daniel Vetter84849902012-12-02 00:28:11 +0100727 drm_modeset_unlock_all(dev);
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +0200728
729 return ret;
Dave Airlief453ba02008-11-07 14:05:41 -0800730}
731EXPORT_SYMBOL(drm_connector_init);
732
733/**
734 * drm_connector_cleanup - cleans up an initialised connector
735 * @connector: connector to cleanup
736 *
Dave Airlief453ba02008-11-07 14:05:41 -0800737 * Cleans up the connector but doesn't free the object.
738 */
739void drm_connector_cleanup(struct drm_connector *connector)
740{
741 struct drm_device *dev = connector->dev;
742 struct drm_display_mode *mode, *t;
743
744 list_for_each_entry_safe(mode, t, &connector->probed_modes, head)
745 drm_mode_remove(connector, mode);
746
747 list_for_each_entry_safe(mode, t, &connector->modes, head)
748 drm_mode_remove(connector, mode);
749
Dave Airlief453ba02008-11-07 14:05:41 -0800750 drm_mode_object_put(dev, &connector->base);
751 list_del(&connector->head);
Joonyoung Shim6380c502011-08-27 02:06:21 +0000752 dev->mode_config.num_connector--;
Dave Airlief453ba02008-11-07 14:05:41 -0800753}
754EXPORT_SYMBOL(drm_connector_cleanup);
755
Dave Airliecbc7e222012-02-20 14:16:40 +0000756void drm_connector_unplug_all(struct drm_device *dev)
757{
758 struct drm_connector *connector;
759
760 /* taking the mode config mutex ends up in a clash with sysfs */
761 list_for_each_entry(connector, &dev->mode_config.connector_list, head)
762 drm_sysfs_connector_remove(connector);
763
764}
765EXPORT_SYMBOL(drm_connector_unplug_all);
766
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +0200767int drm_encoder_init(struct drm_device *dev,
Dave Airliecbc7e222012-02-20 14:16:40 +0000768 struct drm_encoder *encoder,
769 const struct drm_encoder_funcs *funcs,
770 int encoder_type)
Dave Airlief453ba02008-11-07 14:05:41 -0800771{
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +0200772 int ret;
773
Daniel Vetter84849902012-12-02 00:28:11 +0100774 drm_modeset_lock_all(dev);
Dave Airlief453ba02008-11-07 14:05:41 -0800775
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +0200776 ret = drm_mode_object_get(dev, &encoder->base, DRM_MODE_OBJECT_ENCODER);
777 if (ret)
778 goto out;
Dave Airlief453ba02008-11-07 14:05:41 -0800779
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +0200780 encoder->dev = dev;
Dave Airlief453ba02008-11-07 14:05:41 -0800781 encoder->encoder_type = encoder_type;
782 encoder->funcs = funcs;
783
784 list_add_tail(&encoder->head, &dev->mode_config.encoder_list);
785 dev->mode_config.num_encoder++;
786
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +0200787 out:
Daniel Vetter84849902012-12-02 00:28:11 +0100788 drm_modeset_unlock_all(dev);
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +0200789
790 return ret;
Dave Airlief453ba02008-11-07 14:05:41 -0800791}
792EXPORT_SYMBOL(drm_encoder_init);
793
794void drm_encoder_cleanup(struct drm_encoder *encoder)
795{
796 struct drm_device *dev = encoder->dev;
Daniel Vetter84849902012-12-02 00:28:11 +0100797 drm_modeset_lock_all(dev);
Dave Airlief453ba02008-11-07 14:05:41 -0800798 drm_mode_object_put(dev, &encoder->base);
799 list_del(&encoder->head);
Joonyoung Shim6380c502011-08-27 02:06:21 +0000800 dev->mode_config.num_encoder--;
Daniel Vetter84849902012-12-02 00:28:11 +0100801 drm_modeset_unlock_all(dev);
Dave Airlief453ba02008-11-07 14:05:41 -0800802}
803EXPORT_SYMBOL(drm_encoder_cleanup);
804
Jesse Barnes8cf5c912011-11-14 14:51:27 -0800805int drm_plane_init(struct drm_device *dev, struct drm_plane *plane,
806 unsigned long possible_crtcs,
807 const struct drm_plane_funcs *funcs,
Rob Clark0a7eb242011-12-13 20:19:36 -0600808 const uint32_t *formats, uint32_t format_count,
809 bool priv)
Jesse Barnes8cf5c912011-11-14 14:51:27 -0800810{
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +0200811 int ret;
812
Daniel Vetter84849902012-12-02 00:28:11 +0100813 drm_modeset_lock_all(dev);
Jesse Barnes8cf5c912011-11-14 14:51:27 -0800814
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +0200815 ret = drm_mode_object_get(dev, &plane->base, DRM_MODE_OBJECT_PLANE);
816 if (ret)
817 goto out;
818
Rob Clark4d939142012-05-17 02:23:27 -0600819 plane->base.properties = &plane->properties;
Jesse Barnes8cf5c912011-11-14 14:51:27 -0800820 plane->dev = dev;
Jesse Barnes8cf5c912011-11-14 14:51:27 -0800821 plane->funcs = funcs;
822 plane->format_types = kmalloc(sizeof(uint32_t) * format_count,
823 GFP_KERNEL);
824 if (!plane->format_types) {
825 DRM_DEBUG_KMS("out of memory when allocating plane\n");
826 drm_mode_object_put(dev, &plane->base);
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +0200827 ret = -ENOMEM;
828 goto out;
Jesse Barnes8cf5c912011-11-14 14:51:27 -0800829 }
830
Jesse Barnes308e5bc2011-11-14 14:51:28 -0800831 memcpy(plane->format_types, formats, format_count * sizeof(uint32_t));
Jesse Barnes8cf5c912011-11-14 14:51:27 -0800832 plane->format_count = format_count;
833 plane->possible_crtcs = possible_crtcs;
834
Rob Clark0a7eb242011-12-13 20:19:36 -0600835 /* private planes are not exposed to userspace, but depending on
836 * display hardware, might be convenient to allow sharing programming
837 * for the scanout engine with the crtc implementation.
838 */
839 if (!priv) {
840 list_add_tail(&plane->head, &dev->mode_config.plane_list);
841 dev->mode_config.num_plane++;
842 } else {
843 INIT_LIST_HEAD(&plane->head);
844 }
Jesse Barnes8cf5c912011-11-14 14:51:27 -0800845
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +0200846 out:
Daniel Vetter84849902012-12-02 00:28:11 +0100847 drm_modeset_unlock_all(dev);
Jesse Barnes8cf5c912011-11-14 14:51:27 -0800848
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +0200849 return ret;
Jesse Barnes8cf5c912011-11-14 14:51:27 -0800850}
851EXPORT_SYMBOL(drm_plane_init);
852
853void drm_plane_cleanup(struct drm_plane *plane)
854{
855 struct drm_device *dev = plane->dev;
856
Daniel Vetter84849902012-12-02 00:28:11 +0100857 drm_modeset_lock_all(dev);
Jesse Barnes8cf5c912011-11-14 14:51:27 -0800858 kfree(plane->format_types);
859 drm_mode_object_put(dev, &plane->base);
Rob Clark0a7eb242011-12-13 20:19:36 -0600860 /* if not added to a list, it must be a private plane */
861 if (!list_empty(&plane->head)) {
862 list_del(&plane->head);
863 dev->mode_config.num_plane--;
864 }
Daniel Vetter84849902012-12-02 00:28:11 +0100865 drm_modeset_unlock_all(dev);
Jesse Barnes8cf5c912011-11-14 14:51:27 -0800866}
867EXPORT_SYMBOL(drm_plane_cleanup);
868
Dave Airlief453ba02008-11-07 14:05:41 -0800869/**
870 * drm_mode_create - create a new display mode
871 * @dev: DRM device
872 *
Dave Airlief453ba02008-11-07 14:05:41 -0800873 * Create a new drm_display_mode, give it an ID, and return it.
874 *
875 * RETURNS:
876 * Pointer to new mode on success, NULL on error.
877 */
878struct drm_display_mode *drm_mode_create(struct drm_device *dev)
879{
880 struct drm_display_mode *nmode;
881
882 nmode = kzalloc(sizeof(struct drm_display_mode), GFP_KERNEL);
883 if (!nmode)
884 return NULL;
885
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +0200886 if (drm_mode_object_get(dev, &nmode->base, DRM_MODE_OBJECT_MODE)) {
887 kfree(nmode);
888 return NULL;
889 }
890
Dave Airlief453ba02008-11-07 14:05:41 -0800891 return nmode;
892}
893EXPORT_SYMBOL(drm_mode_create);
894
895/**
896 * drm_mode_destroy - remove a mode
897 * @dev: DRM device
898 * @mode: mode to remove
899 *
Dave Airlief453ba02008-11-07 14:05:41 -0800900 * Free @mode's unique identifier, then free it.
901 */
902void drm_mode_destroy(struct drm_device *dev, struct drm_display_mode *mode)
903{
Ville Syrjäläee34ab52012-03-13 12:35:43 +0200904 if (!mode)
905 return;
906
Dave Airlief453ba02008-11-07 14:05:41 -0800907 drm_mode_object_put(dev, &mode->base);
908
909 kfree(mode);
910}
911EXPORT_SYMBOL(drm_mode_destroy);
912
913static int drm_mode_create_standard_connector_properties(struct drm_device *dev)
914{
915 struct drm_property *edid;
916 struct drm_property *dpms;
Dave Airlief453ba02008-11-07 14:05:41 -0800917
918 /*
919 * Standard properties (apply to all connectors)
920 */
921 edid = drm_property_create(dev, DRM_MODE_PROP_BLOB |
922 DRM_MODE_PROP_IMMUTABLE,
923 "EDID", 0);
924 dev->mode_config.edid_property = edid;
925
Sascha Hauer4a67d392012-02-06 10:58:17 +0100926 dpms = drm_property_create_enum(dev, 0,
927 "DPMS", drm_dpms_enum_list,
928 ARRAY_SIZE(drm_dpms_enum_list));
Dave Airlief453ba02008-11-07 14:05:41 -0800929 dev->mode_config.dpms_property = dpms;
930
931 return 0;
932}
933
934/**
935 * drm_mode_create_dvi_i_properties - create DVI-I specific connector properties
936 * @dev: DRM device
937 *
938 * Called by a driver the first time a DVI-I connector is made.
939 */
940int drm_mode_create_dvi_i_properties(struct drm_device *dev)
941{
942 struct drm_property *dvi_i_selector;
943 struct drm_property *dvi_i_subconnector;
Dave Airlief453ba02008-11-07 14:05:41 -0800944
945 if (dev->mode_config.dvi_i_select_subconnector_property)
946 return 0;
947
948 dvi_i_selector =
Sascha Hauer4a67d392012-02-06 10:58:17 +0100949 drm_property_create_enum(dev, 0,
Dave Airlief453ba02008-11-07 14:05:41 -0800950 "select subconnector",
Sascha Hauer4a67d392012-02-06 10:58:17 +0100951 drm_dvi_i_select_enum_list,
Dave Airlief453ba02008-11-07 14:05:41 -0800952 ARRAY_SIZE(drm_dvi_i_select_enum_list));
Dave Airlief453ba02008-11-07 14:05:41 -0800953 dev->mode_config.dvi_i_select_subconnector_property = dvi_i_selector;
954
Sascha Hauer4a67d392012-02-06 10:58:17 +0100955 dvi_i_subconnector = drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE,
Dave Airlief453ba02008-11-07 14:05:41 -0800956 "subconnector",
Sascha Hauer4a67d392012-02-06 10:58:17 +0100957 drm_dvi_i_subconnector_enum_list,
Dave Airlief453ba02008-11-07 14:05:41 -0800958 ARRAY_SIZE(drm_dvi_i_subconnector_enum_list));
Dave Airlief453ba02008-11-07 14:05:41 -0800959 dev->mode_config.dvi_i_subconnector_property = dvi_i_subconnector;
960
961 return 0;
962}
963EXPORT_SYMBOL(drm_mode_create_dvi_i_properties);
964
965/**
966 * drm_create_tv_properties - create TV specific connector properties
967 * @dev: DRM device
968 * @num_modes: number of different TV formats (modes) supported
969 * @modes: array of pointers to strings containing name of each format
970 *
971 * Called by a driver's TV initialization routine, this function creates
972 * the TV specific connector properties for a given device. Caller is
973 * responsible for allocating a list of format names and passing them to
974 * this routine.
975 */
976int drm_mode_create_tv_properties(struct drm_device *dev, int num_modes,
977 char *modes[])
978{
979 struct drm_property *tv_selector;
980 struct drm_property *tv_subconnector;
981 int i;
982
983 if (dev->mode_config.tv_select_subconnector_property)
984 return 0;
985
986 /*
987 * Basic connector properties
988 */
Sascha Hauer4a67d392012-02-06 10:58:17 +0100989 tv_selector = drm_property_create_enum(dev, 0,
Dave Airlief453ba02008-11-07 14:05:41 -0800990 "select subconnector",
Sascha Hauer4a67d392012-02-06 10:58:17 +0100991 drm_tv_select_enum_list,
Dave Airlief453ba02008-11-07 14:05:41 -0800992 ARRAY_SIZE(drm_tv_select_enum_list));
Dave Airlief453ba02008-11-07 14:05:41 -0800993 dev->mode_config.tv_select_subconnector_property = tv_selector;
994
995 tv_subconnector =
Sascha Hauer4a67d392012-02-06 10:58:17 +0100996 drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE,
997 "subconnector",
998 drm_tv_subconnector_enum_list,
Dave Airlief453ba02008-11-07 14:05:41 -0800999 ARRAY_SIZE(drm_tv_subconnector_enum_list));
Dave Airlief453ba02008-11-07 14:05:41 -08001000 dev->mode_config.tv_subconnector_property = tv_subconnector;
1001
1002 /*
1003 * Other, TV specific properties: margins & TV modes.
1004 */
1005 dev->mode_config.tv_left_margin_property =
Sascha Hauerd9bc3c02012-02-06 10:58:18 +01001006 drm_property_create_range(dev, 0, "left margin", 0, 100);
Dave Airlief453ba02008-11-07 14:05:41 -08001007
1008 dev->mode_config.tv_right_margin_property =
Sascha Hauerd9bc3c02012-02-06 10:58:18 +01001009 drm_property_create_range(dev, 0, "right margin", 0, 100);
Dave Airlief453ba02008-11-07 14:05:41 -08001010
1011 dev->mode_config.tv_top_margin_property =
Sascha Hauerd9bc3c02012-02-06 10:58:18 +01001012 drm_property_create_range(dev, 0, "top margin", 0, 100);
Dave Airlief453ba02008-11-07 14:05:41 -08001013
1014 dev->mode_config.tv_bottom_margin_property =
Sascha Hauerd9bc3c02012-02-06 10:58:18 +01001015 drm_property_create_range(dev, 0, "bottom margin", 0, 100);
Dave Airlief453ba02008-11-07 14:05:41 -08001016
1017 dev->mode_config.tv_mode_property =
1018 drm_property_create(dev, DRM_MODE_PROP_ENUM,
1019 "mode", num_modes);
1020 for (i = 0; i < num_modes; i++)
1021 drm_property_add_enum(dev->mode_config.tv_mode_property, i,
1022 i, modes[i]);
1023
Francisco Jerezb6b79022009-08-02 04:19:20 +02001024 dev->mode_config.tv_brightness_property =
Sascha Hauerd9bc3c02012-02-06 10:58:18 +01001025 drm_property_create_range(dev, 0, "brightness", 0, 100);
Francisco Jerezb6b79022009-08-02 04:19:20 +02001026
1027 dev->mode_config.tv_contrast_property =
Sascha Hauerd9bc3c02012-02-06 10:58:18 +01001028 drm_property_create_range(dev, 0, "contrast", 0, 100);
Francisco Jerezb6b79022009-08-02 04:19:20 +02001029
1030 dev->mode_config.tv_flicker_reduction_property =
Sascha Hauerd9bc3c02012-02-06 10:58:18 +01001031 drm_property_create_range(dev, 0, "flicker reduction", 0, 100);
Francisco Jerezb6b79022009-08-02 04:19:20 +02001032
Francisco Jereza75f0232009-08-12 02:30:10 +02001033 dev->mode_config.tv_overscan_property =
Sascha Hauerd9bc3c02012-02-06 10:58:18 +01001034 drm_property_create_range(dev, 0, "overscan", 0, 100);
Francisco Jereza75f0232009-08-12 02:30:10 +02001035
1036 dev->mode_config.tv_saturation_property =
Sascha Hauerd9bc3c02012-02-06 10:58:18 +01001037 drm_property_create_range(dev, 0, "saturation", 0, 100);
Francisco Jereza75f0232009-08-12 02:30:10 +02001038
1039 dev->mode_config.tv_hue_property =
Sascha Hauerd9bc3c02012-02-06 10:58:18 +01001040 drm_property_create_range(dev, 0, "hue", 0, 100);
Francisco Jereza75f0232009-08-12 02:30:10 +02001041
Dave Airlief453ba02008-11-07 14:05:41 -08001042 return 0;
1043}
1044EXPORT_SYMBOL(drm_mode_create_tv_properties);
1045
1046/**
1047 * drm_mode_create_scaling_mode_property - create scaling mode property
1048 * @dev: DRM device
1049 *
1050 * Called by a driver the first time it's needed, must be attached to desired
1051 * connectors.
1052 */
1053int drm_mode_create_scaling_mode_property(struct drm_device *dev)
1054{
1055 struct drm_property *scaling_mode;
Dave Airlief453ba02008-11-07 14:05:41 -08001056
1057 if (dev->mode_config.scaling_mode_property)
1058 return 0;
1059
1060 scaling_mode =
Sascha Hauer4a67d392012-02-06 10:58:17 +01001061 drm_property_create_enum(dev, 0, "scaling mode",
1062 drm_scaling_mode_enum_list,
Dave Airlief453ba02008-11-07 14:05:41 -08001063 ARRAY_SIZE(drm_scaling_mode_enum_list));
Dave Airlief453ba02008-11-07 14:05:41 -08001064
1065 dev->mode_config.scaling_mode_property = scaling_mode;
1066
1067 return 0;
1068}
1069EXPORT_SYMBOL(drm_mode_create_scaling_mode_property);
1070
1071/**
1072 * drm_mode_create_dithering_property - create dithering property
1073 * @dev: DRM device
1074 *
1075 * Called by a driver the first time it's needed, must be attached to desired
1076 * connectors.
1077 */
1078int drm_mode_create_dithering_property(struct drm_device *dev)
1079{
1080 struct drm_property *dithering_mode;
Dave Airlief453ba02008-11-07 14:05:41 -08001081
1082 if (dev->mode_config.dithering_mode_property)
1083 return 0;
1084
1085 dithering_mode =
Sascha Hauer4a67d392012-02-06 10:58:17 +01001086 drm_property_create_enum(dev, 0, "dithering",
1087 drm_dithering_mode_enum_list,
Dave Airlief453ba02008-11-07 14:05:41 -08001088 ARRAY_SIZE(drm_dithering_mode_enum_list));
Dave Airlief453ba02008-11-07 14:05:41 -08001089 dev->mode_config.dithering_mode_property = dithering_mode;
1090
1091 return 0;
1092}
1093EXPORT_SYMBOL(drm_mode_create_dithering_property);
1094
1095/**
Jakob Bornecrantz884840a2009-12-03 23:25:47 +00001096 * drm_mode_create_dirty_property - create dirty property
1097 * @dev: DRM device
1098 *
1099 * Called by a driver the first time it's needed, must be attached to desired
1100 * connectors.
1101 */
1102int drm_mode_create_dirty_info_property(struct drm_device *dev)
1103{
1104 struct drm_property *dirty_info;
Jakob Bornecrantz884840a2009-12-03 23:25:47 +00001105
1106 if (dev->mode_config.dirty_info_property)
1107 return 0;
1108
1109 dirty_info =
Sascha Hauer4a67d392012-02-06 10:58:17 +01001110 drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE,
Jakob Bornecrantz884840a2009-12-03 23:25:47 +00001111 "dirty",
Sascha Hauer4a67d392012-02-06 10:58:17 +01001112 drm_dirty_info_enum_list,
Jakob Bornecrantz884840a2009-12-03 23:25:47 +00001113 ARRAY_SIZE(drm_dirty_info_enum_list));
Jakob Bornecrantz884840a2009-12-03 23:25:47 +00001114 dev->mode_config.dirty_info_property = dirty_info;
1115
1116 return 0;
1117}
1118EXPORT_SYMBOL(drm_mode_create_dirty_info_property);
1119
Ville Syrjäläea9cbb02013-04-25 20:09:20 +03001120static int drm_mode_group_init(struct drm_device *dev, struct drm_mode_group *group)
Dave Airlief453ba02008-11-07 14:05:41 -08001121{
1122 uint32_t total_objects = 0;
1123
1124 total_objects += dev->mode_config.num_crtc;
1125 total_objects += dev->mode_config.num_connector;
1126 total_objects += dev->mode_config.num_encoder;
1127
Dave Airlief453ba02008-11-07 14:05:41 -08001128 group->id_list = kzalloc(total_objects * sizeof(uint32_t), GFP_KERNEL);
1129 if (!group->id_list)
1130 return -ENOMEM;
1131
1132 group->num_crtcs = 0;
1133 group->num_connectors = 0;
1134 group->num_encoders = 0;
1135 return 0;
1136}
1137
1138int drm_mode_group_init_legacy_group(struct drm_device *dev,
1139 struct drm_mode_group *group)
1140{
1141 struct drm_crtc *crtc;
1142 struct drm_encoder *encoder;
1143 struct drm_connector *connector;
1144 int ret;
1145
1146 if ((ret = drm_mode_group_init(dev, group)))
1147 return ret;
1148
1149 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
1150 group->id_list[group->num_crtcs++] = crtc->base.id;
1151
1152 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head)
1153 group->id_list[group->num_crtcs + group->num_encoders++] =
1154 encoder->base.id;
1155
1156 list_for_each_entry(connector, &dev->mode_config.connector_list, head)
1157 group->id_list[group->num_crtcs + group->num_encoders +
1158 group->num_connectors++] = connector->base.id;
1159
1160 return 0;
1161}
Dave Airlie9c1dfc52012-03-20 06:59:29 +00001162EXPORT_SYMBOL(drm_mode_group_init_legacy_group);
Dave Airlief453ba02008-11-07 14:05:41 -08001163
1164/**
Dave Airlief453ba02008-11-07 14:05:41 -08001165 * drm_crtc_convert_to_umode - convert a drm_display_mode into a modeinfo
1166 * @out: drm_mode_modeinfo struct to return to the user
1167 * @in: drm_display_mode to use
1168 *
Dave Airlief453ba02008-11-07 14:05:41 -08001169 * Convert a drm_display_mode into a drm_mode_modeinfo structure to return to
1170 * the user.
1171 */
Ville Syrjälä93bbf6d2012-03-13 12:35:47 +02001172static void drm_crtc_convert_to_umode(struct drm_mode_modeinfo *out,
1173 const struct drm_display_mode *in)
Dave Airlief453ba02008-11-07 14:05:41 -08001174{
Ville Syrjäläe36fae32012-03-13 12:35:40 +02001175 WARN(in->hdisplay > USHRT_MAX || in->hsync_start > USHRT_MAX ||
1176 in->hsync_end > USHRT_MAX || in->htotal > USHRT_MAX ||
1177 in->hskew > USHRT_MAX || in->vdisplay > USHRT_MAX ||
1178 in->vsync_start > USHRT_MAX || in->vsync_end > USHRT_MAX ||
1179 in->vtotal > USHRT_MAX || in->vscan > USHRT_MAX,
1180 "timing values too large for mode info\n");
1181
Dave Airlief453ba02008-11-07 14:05:41 -08001182 out->clock = in->clock;
1183 out->hdisplay = in->hdisplay;
1184 out->hsync_start = in->hsync_start;
1185 out->hsync_end = in->hsync_end;
1186 out->htotal = in->htotal;
1187 out->hskew = in->hskew;
1188 out->vdisplay = in->vdisplay;
1189 out->vsync_start = in->vsync_start;
1190 out->vsync_end = in->vsync_end;
1191 out->vtotal = in->vtotal;
1192 out->vscan = in->vscan;
1193 out->vrefresh = in->vrefresh;
1194 out->flags = in->flags;
1195 out->type = in->type;
1196 strncpy(out->name, in->name, DRM_DISPLAY_MODE_LEN);
1197 out->name[DRM_DISPLAY_MODE_LEN-1] = 0;
1198}
1199
1200/**
1201 * drm_crtc_convert_to_umode - convert a modeinfo into a drm_display_mode
1202 * @out: drm_display_mode to return to the user
1203 * @in: drm_mode_modeinfo to use
1204 *
Dave Airlief453ba02008-11-07 14:05:41 -08001205 * Convert a drm_mode_modeinfo into a drm_display_mode structure to return to
1206 * the caller.
Ville Syrjälä90367bf2012-03-13 12:35:44 +02001207 *
1208 * RETURNS:
1209 * Zero on success, errno on failure.
Dave Airlief453ba02008-11-07 14:05:41 -08001210 */
Ville Syrjälä93bbf6d2012-03-13 12:35:47 +02001211static int drm_crtc_convert_umode(struct drm_display_mode *out,
1212 const struct drm_mode_modeinfo *in)
Dave Airlief453ba02008-11-07 14:05:41 -08001213{
Ville Syrjälä90367bf2012-03-13 12:35:44 +02001214 if (in->clock > INT_MAX || in->vrefresh > INT_MAX)
1215 return -ERANGE;
1216
Dave Airlief453ba02008-11-07 14:05:41 -08001217 out->clock = in->clock;
1218 out->hdisplay = in->hdisplay;
1219 out->hsync_start = in->hsync_start;
1220 out->hsync_end = in->hsync_end;
1221 out->htotal = in->htotal;
1222 out->hskew = in->hskew;
1223 out->vdisplay = in->vdisplay;
1224 out->vsync_start = in->vsync_start;
1225 out->vsync_end = in->vsync_end;
1226 out->vtotal = in->vtotal;
1227 out->vscan = in->vscan;
1228 out->vrefresh = in->vrefresh;
1229 out->flags = in->flags;
1230 out->type = in->type;
1231 strncpy(out->name, in->name, DRM_DISPLAY_MODE_LEN);
1232 out->name[DRM_DISPLAY_MODE_LEN-1] = 0;
Ville Syrjälä90367bf2012-03-13 12:35:44 +02001233
1234 return 0;
Dave Airlief453ba02008-11-07 14:05:41 -08001235}
1236
1237/**
1238 * drm_mode_getresources - get graphics configuration
Daniel Vetter065a50ed2012-12-02 00:09:18 +01001239 * @dev: drm device for the ioctl
1240 * @data: data pointer for the ioctl
1241 * @file_priv: drm file for the ioctl call
Dave Airlief453ba02008-11-07 14:05:41 -08001242 *
Dave Airlief453ba02008-11-07 14:05:41 -08001243 * Construct a set of configuration description structures and return
1244 * them to the user, including CRTC, connector and framebuffer configuration.
1245 *
1246 * Called by the user via ioctl.
1247 *
1248 * RETURNS:
1249 * Zero on success, errno on failure.
1250 */
1251int drm_mode_getresources(struct drm_device *dev, void *data,
1252 struct drm_file *file_priv)
1253{
1254 struct drm_mode_card_res *card_res = data;
1255 struct list_head *lh;
1256 struct drm_framebuffer *fb;
1257 struct drm_connector *connector;
1258 struct drm_crtc *crtc;
1259 struct drm_encoder *encoder;
1260 int ret = 0;
1261 int connector_count = 0;
1262 int crtc_count = 0;
1263 int fb_count = 0;
1264 int encoder_count = 0;
1265 int copied = 0, i;
1266 uint32_t __user *fb_id;
1267 uint32_t __user *crtc_id;
1268 uint32_t __user *connector_id;
1269 uint32_t __user *encoder_id;
1270 struct drm_mode_group *mode_group;
1271
Dave Airliefb3b06c2011-02-08 13:55:21 +10001272 if (!drm_core_check_feature(dev, DRIVER_MODESET))
1273 return -EINVAL;
1274
Dave Airlief453ba02008-11-07 14:05:41 -08001275
Daniel Vetter4b096ac2012-12-10 21:19:18 +01001276 mutex_lock(&file_priv->fbs_lock);
Dave Airlief453ba02008-11-07 14:05:41 -08001277 /*
1278 * For the non-control nodes we need to limit the list of resources
1279 * by IDs in the group list for this node
1280 */
1281 list_for_each(lh, &file_priv->fbs)
1282 fb_count++;
1283
Daniel Vetter4b096ac2012-12-10 21:19:18 +01001284 /* handle this in 4 parts */
1285 /* FBs */
1286 if (card_res->count_fbs >= fb_count) {
1287 copied = 0;
1288 fb_id = (uint32_t __user *)(unsigned long)card_res->fb_id_ptr;
1289 list_for_each_entry(fb, &file_priv->fbs, filp_head) {
1290 if (put_user(fb->base.id, fb_id + copied)) {
1291 mutex_unlock(&file_priv->fbs_lock);
1292 return -EFAULT;
1293 }
1294 copied++;
1295 }
1296 }
1297 card_res->count_fbs = fb_count;
1298 mutex_unlock(&file_priv->fbs_lock);
1299
1300 drm_modeset_lock_all(dev);
Dave Airlief453ba02008-11-07 14:05:41 -08001301 mode_group = &file_priv->master->minor->mode_group;
1302 if (file_priv->master->minor->type == DRM_MINOR_CONTROL) {
1303
1304 list_for_each(lh, &dev->mode_config.crtc_list)
1305 crtc_count++;
1306
1307 list_for_each(lh, &dev->mode_config.connector_list)
1308 connector_count++;
1309
1310 list_for_each(lh, &dev->mode_config.encoder_list)
1311 encoder_count++;
1312 } else {
1313
1314 crtc_count = mode_group->num_crtcs;
1315 connector_count = mode_group->num_connectors;
1316 encoder_count = mode_group->num_encoders;
1317 }
1318
1319 card_res->max_height = dev->mode_config.max_height;
1320 card_res->min_height = dev->mode_config.min_height;
1321 card_res->max_width = dev->mode_config.max_width;
1322 card_res->min_width = dev->mode_config.min_width;
1323
Dave Airlief453ba02008-11-07 14:05:41 -08001324 /* CRTCs */
1325 if (card_res->count_crtcs >= crtc_count) {
1326 copied = 0;
1327 crtc_id = (uint32_t __user *)(unsigned long)card_res->crtc_id_ptr;
1328 if (file_priv->master->minor->type == DRM_MINOR_CONTROL) {
1329 list_for_each_entry(crtc, &dev->mode_config.crtc_list,
1330 head) {
Jerome Glisse94401062010-07-15 15:43:25 -04001331 DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id);
Dave Airlief453ba02008-11-07 14:05:41 -08001332 if (put_user(crtc->base.id, crtc_id + copied)) {
1333 ret = -EFAULT;
1334 goto out;
1335 }
1336 copied++;
1337 }
1338 } else {
1339 for (i = 0; i < mode_group->num_crtcs; i++) {
1340 if (put_user(mode_group->id_list[i],
1341 crtc_id + copied)) {
1342 ret = -EFAULT;
1343 goto out;
1344 }
1345 copied++;
1346 }
1347 }
1348 }
1349 card_res->count_crtcs = crtc_count;
1350
1351 /* Encoders */
1352 if (card_res->count_encoders >= encoder_count) {
1353 copied = 0;
1354 encoder_id = (uint32_t __user *)(unsigned long)card_res->encoder_id_ptr;
1355 if (file_priv->master->minor->type == DRM_MINOR_CONTROL) {
1356 list_for_each_entry(encoder,
1357 &dev->mode_config.encoder_list,
1358 head) {
Jerome Glisse94401062010-07-15 15:43:25 -04001359 DRM_DEBUG_KMS("[ENCODER:%d:%s]\n", encoder->base.id,
1360 drm_get_encoder_name(encoder));
Dave Airlief453ba02008-11-07 14:05:41 -08001361 if (put_user(encoder->base.id, encoder_id +
1362 copied)) {
1363 ret = -EFAULT;
1364 goto out;
1365 }
1366 copied++;
1367 }
1368 } else {
1369 for (i = mode_group->num_crtcs; i < mode_group->num_crtcs + mode_group->num_encoders; i++) {
1370 if (put_user(mode_group->id_list[i],
1371 encoder_id + copied)) {
1372 ret = -EFAULT;
1373 goto out;
1374 }
1375 copied++;
1376 }
1377
1378 }
1379 }
1380 card_res->count_encoders = encoder_count;
1381
1382 /* Connectors */
1383 if (card_res->count_connectors >= connector_count) {
1384 copied = 0;
1385 connector_id = (uint32_t __user *)(unsigned long)card_res->connector_id_ptr;
1386 if (file_priv->master->minor->type == DRM_MINOR_CONTROL) {
1387 list_for_each_entry(connector,
1388 &dev->mode_config.connector_list,
1389 head) {
Jerome Glisse94401062010-07-15 15:43:25 -04001390 DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
1391 connector->base.id,
1392 drm_get_connector_name(connector));
Dave Airlief453ba02008-11-07 14:05:41 -08001393 if (put_user(connector->base.id,
1394 connector_id + copied)) {
1395 ret = -EFAULT;
1396 goto out;
1397 }
1398 copied++;
1399 }
1400 } else {
1401 int start = mode_group->num_crtcs +
1402 mode_group->num_encoders;
1403 for (i = start; i < start + mode_group->num_connectors; i++) {
1404 if (put_user(mode_group->id_list[i],
1405 connector_id + copied)) {
1406 ret = -EFAULT;
1407 goto out;
1408 }
1409 copied++;
1410 }
1411 }
1412 }
1413 card_res->count_connectors = connector_count;
1414
Jerome Glisse94401062010-07-15 15:43:25 -04001415 DRM_DEBUG_KMS("CRTC[%d] CONNECTORS[%d] ENCODERS[%d]\n", card_res->count_crtcs,
Dave Airlief453ba02008-11-07 14:05:41 -08001416 card_res->count_connectors, card_res->count_encoders);
1417
1418out:
Daniel Vetter84849902012-12-02 00:28:11 +01001419 drm_modeset_unlock_all(dev);
Dave Airlief453ba02008-11-07 14:05:41 -08001420 return ret;
1421}
1422
1423/**
1424 * drm_mode_getcrtc - get CRTC configuration
Daniel Vetter065a50ed2012-12-02 00:09:18 +01001425 * @dev: drm device for the ioctl
1426 * @data: data pointer for the ioctl
1427 * @file_priv: drm file for the ioctl call
Dave Airlief453ba02008-11-07 14:05:41 -08001428 *
Dave Airlief453ba02008-11-07 14:05:41 -08001429 * Construct a CRTC configuration structure to return to the user.
1430 *
1431 * Called by the user via ioctl.
1432 *
1433 * RETURNS:
1434 * Zero on success, errno on failure.
1435 */
1436int drm_mode_getcrtc(struct drm_device *dev,
1437 void *data, struct drm_file *file_priv)
1438{
1439 struct drm_mode_crtc *crtc_resp = data;
1440 struct drm_crtc *crtc;
1441 struct drm_mode_object *obj;
1442 int ret = 0;
1443
Dave Airliefb3b06c2011-02-08 13:55:21 +10001444 if (!drm_core_check_feature(dev, DRIVER_MODESET))
1445 return -EINVAL;
1446
Daniel Vetter84849902012-12-02 00:28:11 +01001447 drm_modeset_lock_all(dev);
Dave Airlief453ba02008-11-07 14:05:41 -08001448
1449 obj = drm_mode_object_find(dev, crtc_resp->crtc_id,
1450 DRM_MODE_OBJECT_CRTC);
1451 if (!obj) {
1452 ret = -EINVAL;
1453 goto out;
1454 }
1455 crtc = obj_to_crtc(obj);
1456
1457 crtc_resp->x = crtc->x;
1458 crtc_resp->y = crtc->y;
1459 crtc_resp->gamma_size = crtc->gamma_size;
1460 if (crtc->fb)
1461 crtc_resp->fb_id = crtc->fb->base.id;
1462 else
1463 crtc_resp->fb_id = 0;
1464
1465 if (crtc->enabled) {
1466
1467 drm_crtc_convert_to_umode(&crtc_resp->mode, &crtc->mode);
1468 crtc_resp->mode_valid = 1;
1469
1470 } else {
1471 crtc_resp->mode_valid = 0;
1472 }
1473
1474out:
Daniel Vetter84849902012-12-02 00:28:11 +01001475 drm_modeset_unlock_all(dev);
Dave Airlief453ba02008-11-07 14:05:41 -08001476 return ret;
1477}
1478
1479/**
1480 * drm_mode_getconnector - get connector configuration
Daniel Vetter065a50ed2012-12-02 00:09:18 +01001481 * @dev: drm device for the ioctl
1482 * @data: data pointer for the ioctl
1483 * @file_priv: drm file for the ioctl call
Dave Airlief453ba02008-11-07 14:05:41 -08001484 *
Dave Airlief453ba02008-11-07 14:05:41 -08001485 * Construct a connector configuration structure to return to the user.
1486 *
1487 * Called by the user via ioctl.
1488 *
1489 * RETURNS:
1490 * Zero on success, errno on failure.
1491 */
1492int drm_mode_getconnector(struct drm_device *dev, void *data,
1493 struct drm_file *file_priv)
1494{
1495 struct drm_mode_get_connector *out_resp = data;
1496 struct drm_mode_object *obj;
1497 struct drm_connector *connector;
1498 struct drm_display_mode *mode;
1499 int mode_count = 0;
1500 int props_count = 0;
1501 int encoders_count = 0;
1502 int ret = 0;
1503 int copied = 0;
1504 int i;
1505 struct drm_mode_modeinfo u_mode;
1506 struct drm_mode_modeinfo __user *mode_ptr;
1507 uint32_t __user *prop_ptr;
1508 uint64_t __user *prop_values;
1509 uint32_t __user *encoder_ptr;
1510
Dave Airliefb3b06c2011-02-08 13:55:21 +10001511 if (!drm_core_check_feature(dev, DRIVER_MODESET))
1512 return -EINVAL;
1513
Dave Airlief453ba02008-11-07 14:05:41 -08001514 memset(&u_mode, 0, sizeof(struct drm_mode_modeinfo));
1515
Jerome Glisse94401062010-07-15 15:43:25 -04001516 DRM_DEBUG_KMS("[CONNECTOR:%d:?]\n", out_resp->connector_id);
Dave Airlief453ba02008-11-07 14:05:41 -08001517
Daniel Vetter7b240562012-12-12 00:35:33 +01001518 mutex_lock(&dev->mode_config.mutex);
Dave Airlief453ba02008-11-07 14:05:41 -08001519
1520 obj = drm_mode_object_find(dev, out_resp->connector_id,
1521 DRM_MODE_OBJECT_CONNECTOR);
1522 if (!obj) {
1523 ret = -EINVAL;
1524 goto out;
1525 }
1526 connector = obj_to_connector(obj);
1527
Paulo Zanoni7f88a9b2012-05-15 18:09:04 -03001528 props_count = connector->properties.count;
Dave Airlief453ba02008-11-07 14:05:41 -08001529
1530 for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
1531 if (connector->encoder_ids[i] != 0) {
1532 encoders_count++;
1533 }
1534 }
1535
1536 if (out_resp->count_modes == 0) {
1537 connector->funcs->fill_modes(connector,
1538 dev->mode_config.max_width,
1539 dev->mode_config.max_height);
1540 }
1541
1542 /* delayed so we get modes regardless of pre-fill_modes state */
1543 list_for_each_entry(mode, &connector->modes, head)
1544 mode_count++;
1545
1546 out_resp->connector_id = connector->base.id;
1547 out_resp->connector_type = connector->connector_type;
1548 out_resp->connector_type_id = connector->connector_type_id;
1549 out_resp->mm_width = connector->display_info.width_mm;
1550 out_resp->mm_height = connector->display_info.height_mm;
1551 out_resp->subpixel = connector->display_info.subpixel_order;
1552 out_resp->connection = connector->status;
1553 if (connector->encoder)
1554 out_resp->encoder_id = connector->encoder->base.id;
1555 else
1556 out_resp->encoder_id = 0;
1557
1558 /*
1559 * This ioctl is called twice, once to determine how much space is
1560 * needed, and the 2nd time to fill it.
1561 */
1562 if ((out_resp->count_modes >= mode_count) && mode_count) {
1563 copied = 0;
Ville Syrjälä81f6c7f2011-12-20 00:06:42 +02001564 mode_ptr = (struct drm_mode_modeinfo __user *)(unsigned long)out_resp->modes_ptr;
Dave Airlief453ba02008-11-07 14:05:41 -08001565 list_for_each_entry(mode, &connector->modes, head) {
1566 drm_crtc_convert_to_umode(&u_mode, mode);
1567 if (copy_to_user(mode_ptr + copied,
1568 &u_mode, sizeof(u_mode))) {
1569 ret = -EFAULT;
1570 goto out;
1571 }
1572 copied++;
1573 }
1574 }
1575 out_resp->count_modes = mode_count;
1576
1577 if ((out_resp->count_props >= props_count) && props_count) {
1578 copied = 0;
Ville Syrjälä81f6c7f2011-12-20 00:06:42 +02001579 prop_ptr = (uint32_t __user *)(unsigned long)(out_resp->props_ptr);
1580 prop_values = (uint64_t __user *)(unsigned long)(out_resp->prop_values_ptr);
Paulo Zanoni7f88a9b2012-05-15 18:09:04 -03001581 for (i = 0; i < connector->properties.count; i++) {
1582 if (put_user(connector->properties.ids[i],
1583 prop_ptr + copied)) {
1584 ret = -EFAULT;
1585 goto out;
Dave Airlief453ba02008-11-07 14:05:41 -08001586 }
Paulo Zanoni7f88a9b2012-05-15 18:09:04 -03001587
1588 if (put_user(connector->properties.values[i],
1589 prop_values + copied)) {
1590 ret = -EFAULT;
1591 goto out;
1592 }
1593 copied++;
Dave Airlief453ba02008-11-07 14:05:41 -08001594 }
1595 }
1596 out_resp->count_props = props_count;
1597
1598 if ((out_resp->count_encoders >= encoders_count) && encoders_count) {
1599 copied = 0;
Ville Syrjälä81f6c7f2011-12-20 00:06:42 +02001600 encoder_ptr = (uint32_t __user *)(unsigned long)(out_resp->encoders_ptr);
Dave Airlief453ba02008-11-07 14:05:41 -08001601 for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
1602 if (connector->encoder_ids[i] != 0) {
1603 if (put_user(connector->encoder_ids[i],
1604 encoder_ptr + copied)) {
1605 ret = -EFAULT;
1606 goto out;
1607 }
1608 copied++;
1609 }
1610 }
1611 }
1612 out_resp->count_encoders = encoders_count;
1613
1614out:
Daniel Vetter7b240562012-12-12 00:35:33 +01001615 mutex_unlock(&dev->mode_config.mutex);
1616
Dave Airlief453ba02008-11-07 14:05:41 -08001617 return ret;
1618}
1619
1620int drm_mode_getencoder(struct drm_device *dev, void *data,
1621 struct drm_file *file_priv)
1622{
1623 struct drm_mode_get_encoder *enc_resp = data;
1624 struct drm_mode_object *obj;
1625 struct drm_encoder *encoder;
1626 int ret = 0;
1627
Dave Airliefb3b06c2011-02-08 13:55:21 +10001628 if (!drm_core_check_feature(dev, DRIVER_MODESET))
1629 return -EINVAL;
1630
Daniel Vetter84849902012-12-02 00:28:11 +01001631 drm_modeset_lock_all(dev);
Dave Airlief453ba02008-11-07 14:05:41 -08001632 obj = drm_mode_object_find(dev, enc_resp->encoder_id,
1633 DRM_MODE_OBJECT_ENCODER);
1634 if (!obj) {
1635 ret = -EINVAL;
1636 goto out;
1637 }
1638 encoder = obj_to_encoder(obj);
1639
1640 if (encoder->crtc)
1641 enc_resp->crtc_id = encoder->crtc->base.id;
1642 else
1643 enc_resp->crtc_id = 0;
1644 enc_resp->encoder_type = encoder->encoder_type;
1645 enc_resp->encoder_id = encoder->base.id;
1646 enc_resp->possible_crtcs = encoder->possible_crtcs;
1647 enc_resp->possible_clones = encoder->possible_clones;
1648
1649out:
Daniel Vetter84849902012-12-02 00:28:11 +01001650 drm_modeset_unlock_all(dev);
Dave Airlief453ba02008-11-07 14:05:41 -08001651 return ret;
1652}
1653
1654/**
Jesse Barnes8cf5c912011-11-14 14:51:27 -08001655 * drm_mode_getplane_res - get plane info
1656 * @dev: DRM device
1657 * @data: ioctl data
1658 * @file_priv: DRM file info
1659 *
1660 * Return an plane count and set of IDs.
1661 */
1662int drm_mode_getplane_res(struct drm_device *dev, void *data,
1663 struct drm_file *file_priv)
1664{
1665 struct drm_mode_get_plane_res *plane_resp = data;
1666 struct drm_mode_config *config;
1667 struct drm_plane *plane;
1668 uint32_t __user *plane_ptr;
1669 int copied = 0, ret = 0;
1670
1671 if (!drm_core_check_feature(dev, DRIVER_MODESET))
1672 return -EINVAL;
1673
Daniel Vetter84849902012-12-02 00:28:11 +01001674 drm_modeset_lock_all(dev);
Jesse Barnes8cf5c912011-11-14 14:51:27 -08001675 config = &dev->mode_config;
1676
1677 /*
1678 * This ioctl is called twice, once to determine how much space is
1679 * needed, and the 2nd time to fill it.
1680 */
1681 if (config->num_plane &&
1682 (plane_resp->count_planes >= config->num_plane)) {
Ville Syrjälä81f6c7f2011-12-20 00:06:42 +02001683 plane_ptr = (uint32_t __user *)(unsigned long)plane_resp->plane_id_ptr;
Jesse Barnes8cf5c912011-11-14 14:51:27 -08001684
1685 list_for_each_entry(plane, &config->plane_list, head) {
1686 if (put_user(plane->base.id, plane_ptr + copied)) {
1687 ret = -EFAULT;
1688 goto out;
1689 }
1690 copied++;
1691 }
1692 }
1693 plane_resp->count_planes = config->num_plane;
1694
1695out:
Daniel Vetter84849902012-12-02 00:28:11 +01001696 drm_modeset_unlock_all(dev);
Jesse Barnes8cf5c912011-11-14 14:51:27 -08001697 return ret;
1698}
1699
1700/**
1701 * drm_mode_getplane - get plane info
1702 * @dev: DRM device
1703 * @data: ioctl data
1704 * @file_priv: DRM file info
1705 *
1706 * Return plane info, including formats supported, gamma size, any
1707 * current fb, etc.
1708 */
1709int drm_mode_getplane(struct drm_device *dev, void *data,
1710 struct drm_file *file_priv)
1711{
1712 struct drm_mode_get_plane *plane_resp = data;
1713 struct drm_mode_object *obj;
1714 struct drm_plane *plane;
1715 uint32_t __user *format_ptr;
1716 int ret = 0;
1717
1718 if (!drm_core_check_feature(dev, DRIVER_MODESET))
1719 return -EINVAL;
1720
Daniel Vetter84849902012-12-02 00:28:11 +01001721 drm_modeset_lock_all(dev);
Jesse Barnes8cf5c912011-11-14 14:51:27 -08001722 obj = drm_mode_object_find(dev, plane_resp->plane_id,
1723 DRM_MODE_OBJECT_PLANE);
1724 if (!obj) {
1725 ret = -ENOENT;
1726 goto out;
1727 }
1728 plane = obj_to_plane(obj);
1729
1730 if (plane->crtc)
1731 plane_resp->crtc_id = plane->crtc->base.id;
1732 else
1733 plane_resp->crtc_id = 0;
1734
1735 if (plane->fb)
1736 plane_resp->fb_id = plane->fb->base.id;
1737 else
1738 plane_resp->fb_id = 0;
1739
1740 plane_resp->plane_id = plane->base.id;
1741 plane_resp->possible_crtcs = plane->possible_crtcs;
1742 plane_resp->gamma_size = plane->gamma_size;
1743
1744 /*
1745 * This ioctl is called twice, once to determine how much space is
1746 * needed, and the 2nd time to fill it.
1747 */
1748 if (plane->format_count &&
1749 (plane_resp->count_format_types >= plane->format_count)) {
Ville Syrjälä81f6c7f2011-12-20 00:06:42 +02001750 format_ptr = (uint32_t __user *)(unsigned long)plane_resp->format_type_ptr;
Jesse Barnes8cf5c912011-11-14 14:51:27 -08001751 if (copy_to_user(format_ptr,
1752 plane->format_types,
1753 sizeof(uint32_t) * plane->format_count)) {
1754 ret = -EFAULT;
1755 goto out;
1756 }
1757 }
1758 plane_resp->count_format_types = plane->format_count;
1759
1760out:
Daniel Vetter84849902012-12-02 00:28:11 +01001761 drm_modeset_unlock_all(dev);
Jesse Barnes8cf5c912011-11-14 14:51:27 -08001762 return ret;
1763}
1764
1765/**
1766 * drm_mode_setplane - set up or tear down an plane
1767 * @dev: DRM device
1768 * @data: ioctl data*
Daniel Vetter065a50ed2012-12-02 00:09:18 +01001769 * @file_priv: DRM file info
Jesse Barnes8cf5c912011-11-14 14:51:27 -08001770 *
1771 * Set plane info, including placement, fb, scaling, and other factors.
1772 * Or pass a NULL fb to disable.
1773 */
1774int drm_mode_setplane(struct drm_device *dev, void *data,
1775 struct drm_file *file_priv)
1776{
1777 struct drm_mode_set_plane *plane_req = data;
1778 struct drm_mode_object *obj;
1779 struct drm_plane *plane;
1780 struct drm_crtc *crtc;
Daniel Vetter6c2a7532012-12-11 00:59:24 +01001781 struct drm_framebuffer *fb = NULL, *old_fb = NULL;
Jesse Barnes8cf5c912011-11-14 14:51:27 -08001782 int ret = 0;
Ville Syrjälä42ef8782011-12-20 00:06:44 +02001783 unsigned int fb_width, fb_height;
Ville Syrjälä62443be2011-12-20 00:06:47 +02001784 int i;
Jesse Barnes8cf5c912011-11-14 14:51:27 -08001785
1786 if (!drm_core_check_feature(dev, DRIVER_MODESET))
1787 return -EINVAL;
1788
Jesse Barnes8cf5c912011-11-14 14:51:27 -08001789 /*
1790 * First, find the plane, crtc, and fb objects. If not available,
1791 * we don't bother to call the driver.
1792 */
1793 obj = drm_mode_object_find(dev, plane_req->plane_id,
1794 DRM_MODE_OBJECT_PLANE);
1795 if (!obj) {
1796 DRM_DEBUG_KMS("Unknown plane ID %d\n",
1797 plane_req->plane_id);
Daniel Vetter6c2a7532012-12-11 00:59:24 +01001798 return -ENOENT;
Jesse Barnes8cf5c912011-11-14 14:51:27 -08001799 }
1800 plane = obj_to_plane(obj);
1801
1802 /* No fb means shut it down */
1803 if (!plane_req->fb_id) {
Daniel Vetter6c2a7532012-12-11 00:59:24 +01001804 drm_modeset_lock_all(dev);
1805 old_fb = plane->fb;
Jesse Barnes8cf5c912011-11-14 14:51:27 -08001806 plane->funcs->disable_plane(plane);
Ville Syrjäläe5e3b442011-12-20 00:06:43 +02001807 plane->crtc = NULL;
1808 plane->fb = NULL;
Daniel Vetter6c2a7532012-12-11 00:59:24 +01001809 drm_modeset_unlock_all(dev);
Jesse Barnes8cf5c912011-11-14 14:51:27 -08001810 goto out;
1811 }
1812
1813 obj = drm_mode_object_find(dev, plane_req->crtc_id,
1814 DRM_MODE_OBJECT_CRTC);
1815 if (!obj) {
1816 DRM_DEBUG_KMS("Unknown crtc ID %d\n",
1817 plane_req->crtc_id);
1818 ret = -ENOENT;
1819 goto out;
1820 }
1821 crtc = obj_to_crtc(obj);
1822
Daniel Vetter786b99e2012-12-02 21:53:40 +01001823 fb = drm_framebuffer_lookup(dev, plane_req->fb_id);
1824 if (!fb) {
Jesse Barnes8cf5c912011-11-14 14:51:27 -08001825 DRM_DEBUG_KMS("Unknown framebuffer ID %d\n",
1826 plane_req->fb_id);
1827 ret = -ENOENT;
1828 goto out;
1829 }
Jesse Barnes8cf5c912011-11-14 14:51:27 -08001830
Ville Syrjälä62443be2011-12-20 00:06:47 +02001831 /* Check whether this plane supports the fb pixel format. */
1832 for (i = 0; i < plane->format_count; i++)
1833 if (fb->pixel_format == plane->format_types[i])
1834 break;
1835 if (i == plane->format_count) {
1836 DRM_DEBUG_KMS("Invalid pixel format 0x%08x\n", fb->pixel_format);
1837 ret = -EINVAL;
1838 goto out;
1839 }
1840
Ville Syrjälä42ef8782011-12-20 00:06:44 +02001841 fb_width = fb->width << 16;
1842 fb_height = fb->height << 16;
1843
1844 /* Make sure source coordinates are inside the fb. */
1845 if (plane_req->src_w > fb_width ||
1846 plane_req->src_x > fb_width - plane_req->src_w ||
1847 plane_req->src_h > fb_height ||
1848 plane_req->src_y > fb_height - plane_req->src_h) {
1849 DRM_DEBUG_KMS("Invalid source coordinates "
1850 "%u.%06ux%u.%06u+%u.%06u+%u.%06u\n",
1851 plane_req->src_w >> 16,
1852 ((plane_req->src_w & 0xffff) * 15625) >> 10,
1853 plane_req->src_h >> 16,
1854 ((plane_req->src_h & 0xffff) * 15625) >> 10,
1855 plane_req->src_x >> 16,
1856 ((plane_req->src_x & 0xffff) * 15625) >> 10,
1857 plane_req->src_y >> 16,
1858 ((plane_req->src_y & 0xffff) * 15625) >> 10);
1859 ret = -ENOSPC;
1860 goto out;
1861 }
1862
Ville Syrjälä687a0402011-12-20 00:06:45 +02001863 /* Give drivers some help against integer overflows */
1864 if (plane_req->crtc_w > INT_MAX ||
1865 plane_req->crtc_x > INT_MAX - (int32_t) plane_req->crtc_w ||
1866 plane_req->crtc_h > INT_MAX ||
1867 plane_req->crtc_y > INT_MAX - (int32_t) plane_req->crtc_h) {
1868 DRM_DEBUG_KMS("Invalid CRTC coordinates %ux%u+%d+%d\n",
1869 plane_req->crtc_w, plane_req->crtc_h,
1870 plane_req->crtc_x, plane_req->crtc_y);
1871 ret = -ERANGE;
1872 goto out;
1873 }
1874
Daniel Vetter6c2a7532012-12-11 00:59:24 +01001875 drm_modeset_lock_all(dev);
Jesse Barnes8cf5c912011-11-14 14:51:27 -08001876 ret = plane->funcs->update_plane(plane, crtc, fb,
1877 plane_req->crtc_x, plane_req->crtc_y,
1878 plane_req->crtc_w, plane_req->crtc_h,
1879 plane_req->src_x, plane_req->src_y,
1880 plane_req->src_w, plane_req->src_h);
1881 if (!ret) {
Daniel Vetter6c2a7532012-12-11 00:59:24 +01001882 old_fb = plane->fb;
Jesse Barnes8cf5c912011-11-14 14:51:27 -08001883 plane->crtc = crtc;
1884 plane->fb = fb;
Daniel Vetter35f8bad2013-02-15 21:21:37 +01001885 fb = NULL;
Jesse Barnes8cf5c912011-11-14 14:51:27 -08001886 }
Daniel Vetter6c2a7532012-12-11 00:59:24 +01001887 drm_modeset_unlock_all(dev);
Jesse Barnes8cf5c912011-11-14 14:51:27 -08001888
1889out:
Daniel Vetter6c2a7532012-12-11 00:59:24 +01001890 if (fb)
1891 drm_framebuffer_unreference(fb);
1892 if (old_fb)
1893 drm_framebuffer_unreference(old_fb);
Jesse Barnes8cf5c912011-11-14 14:51:27 -08001894
1895 return ret;
1896}
1897
1898/**
Daniel Vetter2d13b672012-12-11 13:47:23 +01001899 * drm_mode_set_config_internal - helper to call ->set_config
1900 * @set: modeset config to set
1901 *
1902 * This is a little helper to wrap internal calls to the ->set_config driver
1903 * interface. The only thing it adds is correct refcounting dance.
1904 */
1905int drm_mode_set_config_internal(struct drm_mode_set *set)
1906{
1907 struct drm_crtc *crtc = set->crtc;
Daniel Vetterb0d12322012-12-11 01:07:12 +01001908 struct drm_framebuffer *fb, *old_fb;
1909 int ret;
Daniel Vetter2d13b672012-12-11 13:47:23 +01001910
Daniel Vetterb0d12322012-12-11 01:07:12 +01001911 old_fb = crtc->fb;
1912 fb = set->fb;
1913
1914 ret = crtc->funcs->set_config(set);
1915 if (ret == 0) {
1916 if (old_fb)
1917 drm_framebuffer_unreference(old_fb);
1918 if (fb)
1919 drm_framebuffer_reference(fb);
1920 }
1921
1922 return ret;
Daniel Vetter2d13b672012-12-11 13:47:23 +01001923}
1924EXPORT_SYMBOL(drm_mode_set_config_internal);
1925
1926/**
Dave Airlief453ba02008-11-07 14:05:41 -08001927 * drm_mode_setcrtc - set CRTC configuration
Daniel Vetter065a50ed2012-12-02 00:09:18 +01001928 * @dev: drm device for the ioctl
1929 * @data: data pointer for the ioctl
1930 * @file_priv: drm file for the ioctl call
Dave Airlief453ba02008-11-07 14:05:41 -08001931 *
Dave Airlief453ba02008-11-07 14:05:41 -08001932 * Build a new CRTC configuration based on user request.
1933 *
1934 * Called by the user via ioctl.
1935 *
1936 * RETURNS:
1937 * Zero on success, errno on failure.
1938 */
1939int drm_mode_setcrtc(struct drm_device *dev, void *data,
1940 struct drm_file *file_priv)
1941{
1942 struct drm_mode_config *config = &dev->mode_config;
1943 struct drm_mode_crtc *crtc_req = data;
1944 struct drm_mode_object *obj;
Ville Syrjälä6653cc82012-03-13 12:35:38 +02001945 struct drm_crtc *crtc;
Dave Airlief453ba02008-11-07 14:05:41 -08001946 struct drm_connector **connector_set = NULL, *connector;
1947 struct drm_framebuffer *fb = NULL;
1948 struct drm_display_mode *mode = NULL;
1949 struct drm_mode_set set;
1950 uint32_t __user *set_connectors_ptr;
Laurent Pinchart4a1b0712012-05-17 13:27:21 +02001951 int ret;
Dave Airlief453ba02008-11-07 14:05:41 -08001952 int i;
1953
Dave Airliefb3b06c2011-02-08 13:55:21 +10001954 if (!drm_core_check_feature(dev, DRIVER_MODESET))
1955 return -EINVAL;
1956
Ville Syrjälä1d97e912012-03-13 12:35:41 +02001957 /* For some reason crtc x/y offsets are signed internally. */
1958 if (crtc_req->x > INT_MAX || crtc_req->y > INT_MAX)
1959 return -ERANGE;
1960
Daniel Vetter84849902012-12-02 00:28:11 +01001961 drm_modeset_lock_all(dev);
Dave Airlief453ba02008-11-07 14:05:41 -08001962 obj = drm_mode_object_find(dev, crtc_req->crtc_id,
1963 DRM_MODE_OBJECT_CRTC);
1964 if (!obj) {
Zhao Yakui58367ed2009-07-20 13:48:07 +08001965 DRM_DEBUG_KMS("Unknown CRTC ID %d\n", crtc_req->crtc_id);
Dave Airlief453ba02008-11-07 14:05:41 -08001966 ret = -EINVAL;
1967 goto out;
1968 }
1969 crtc = obj_to_crtc(obj);
Jerome Glisse94401062010-07-15 15:43:25 -04001970 DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id);
Dave Airlief453ba02008-11-07 14:05:41 -08001971
1972 if (crtc_req->mode_valid) {
Rob Clark7c80e122012-09-04 16:35:56 +00001973 int hdisplay, vdisplay;
Dave Airlief453ba02008-11-07 14:05:41 -08001974 /* If we have a mode we need a framebuffer. */
1975 /* If we pass -1, set the mode with the currently bound fb */
1976 if (crtc_req->fb_id == -1) {
Ville Syrjälä6653cc82012-03-13 12:35:38 +02001977 if (!crtc->fb) {
1978 DRM_DEBUG_KMS("CRTC doesn't have current FB\n");
1979 ret = -EINVAL;
1980 goto out;
Dave Airlief453ba02008-11-07 14:05:41 -08001981 }
Ville Syrjälä6653cc82012-03-13 12:35:38 +02001982 fb = crtc->fb;
Daniel Vetterb0d12322012-12-11 01:07:12 +01001983 /* Make refcounting symmetric with the lookup path. */
1984 drm_framebuffer_reference(fb);
Dave Airlief453ba02008-11-07 14:05:41 -08001985 } else {
Daniel Vetter786b99e2012-12-02 21:53:40 +01001986 fb = drm_framebuffer_lookup(dev, crtc_req->fb_id);
1987 if (!fb) {
Zhao Yakui58367ed2009-07-20 13:48:07 +08001988 DRM_DEBUG_KMS("Unknown FB ID%d\n",
1989 crtc_req->fb_id);
Dave Airlief453ba02008-11-07 14:05:41 -08001990 ret = -EINVAL;
1991 goto out;
1992 }
Dave Airlief453ba02008-11-07 14:05:41 -08001993 }
1994
1995 mode = drm_mode_create(dev);
Ville Syrjäläee34ab52012-03-13 12:35:43 +02001996 if (!mode) {
1997 ret = -ENOMEM;
1998 goto out;
1999 }
2000
Ville Syrjälä90367bf2012-03-13 12:35:44 +02002001 ret = drm_crtc_convert_umode(mode, &crtc_req->mode);
2002 if (ret) {
2003 DRM_DEBUG_KMS("Invalid mode\n");
2004 goto out;
2005 }
2006
Dave Airlief453ba02008-11-07 14:05:41 -08002007 drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
Ville Syrjälä5f61bb42012-03-13 12:35:45 +02002008
Rob Clark7c80e122012-09-04 16:35:56 +00002009 hdisplay = mode->hdisplay;
2010 vdisplay = mode->vdisplay;
2011
2012 if (crtc->invert_dimensions)
2013 swap(hdisplay, vdisplay);
2014
2015 if (hdisplay > fb->width ||
2016 vdisplay > fb->height ||
2017 crtc_req->x > fb->width - hdisplay ||
2018 crtc_req->y > fb->height - vdisplay) {
2019 DRM_DEBUG_KMS("Invalid fb size %ux%u for CRTC viewport %ux%u+%d+%d%s.\n",
2020 fb->width, fb->height,
2021 hdisplay, vdisplay, crtc_req->x, crtc_req->y,
2022 crtc->invert_dimensions ? " (inverted)" : "");
Ville Syrjälä5f61bb42012-03-13 12:35:45 +02002023 ret = -ENOSPC;
2024 goto out;
2025 }
Dave Airlief453ba02008-11-07 14:05:41 -08002026 }
2027
2028 if (crtc_req->count_connectors == 0 && mode) {
Zhao Yakui58367ed2009-07-20 13:48:07 +08002029 DRM_DEBUG_KMS("Count connectors is 0 but mode set\n");
Dave Airlief453ba02008-11-07 14:05:41 -08002030 ret = -EINVAL;
2031 goto out;
2032 }
2033
Jakob Bornecrantz7781de72009-08-03 13:43:58 +01002034 if (crtc_req->count_connectors > 0 && (!mode || !fb)) {
Zhao Yakui58367ed2009-07-20 13:48:07 +08002035 DRM_DEBUG_KMS("Count connectors is %d but no mode or fb set\n",
Dave Airlief453ba02008-11-07 14:05:41 -08002036 crtc_req->count_connectors);
2037 ret = -EINVAL;
2038 goto out;
2039 }
2040
2041 if (crtc_req->count_connectors > 0) {
2042 u32 out_id;
2043
2044 /* Avoid unbounded kernel memory allocation */
2045 if (crtc_req->count_connectors > config->num_connector) {
2046 ret = -EINVAL;
2047 goto out;
2048 }
2049
2050 connector_set = kmalloc(crtc_req->count_connectors *
2051 sizeof(struct drm_connector *),
2052 GFP_KERNEL);
2053 if (!connector_set) {
2054 ret = -ENOMEM;
2055 goto out;
2056 }
2057
2058 for (i = 0; i < crtc_req->count_connectors; i++) {
Ville Syrjälä81f6c7f2011-12-20 00:06:42 +02002059 set_connectors_ptr = (uint32_t __user *)(unsigned long)crtc_req->set_connectors_ptr;
Dave Airlief453ba02008-11-07 14:05:41 -08002060 if (get_user(out_id, &set_connectors_ptr[i])) {
2061 ret = -EFAULT;
2062 goto out;
2063 }
2064
2065 obj = drm_mode_object_find(dev, out_id,
2066 DRM_MODE_OBJECT_CONNECTOR);
2067 if (!obj) {
Zhao Yakui58367ed2009-07-20 13:48:07 +08002068 DRM_DEBUG_KMS("Connector id %d unknown\n",
2069 out_id);
Dave Airlief453ba02008-11-07 14:05:41 -08002070 ret = -EINVAL;
2071 goto out;
2072 }
2073 connector = obj_to_connector(obj);
Jerome Glisse94401062010-07-15 15:43:25 -04002074 DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
2075 connector->base.id,
2076 drm_get_connector_name(connector));
Dave Airlief453ba02008-11-07 14:05:41 -08002077
2078 connector_set[i] = connector;
2079 }
2080 }
2081
2082 set.crtc = crtc;
2083 set.x = crtc_req->x;
2084 set.y = crtc_req->y;
2085 set.mode = mode;
2086 set.connectors = connector_set;
2087 set.num_connectors = crtc_req->count_connectors;
Dave Airlie5ef5f722009-08-17 13:11:23 +10002088 set.fb = fb;
Daniel Vetter2d13b672012-12-11 13:47:23 +01002089 ret = drm_mode_set_config_internal(&set);
Dave Airlief453ba02008-11-07 14:05:41 -08002090
2091out:
Daniel Vetterb0d12322012-12-11 01:07:12 +01002092 if (fb)
2093 drm_framebuffer_unreference(fb);
2094
Dave Airlief453ba02008-11-07 14:05:41 -08002095 kfree(connector_set);
Ville Syrjäläee34ab52012-03-13 12:35:43 +02002096 drm_mode_destroy(dev, mode);
Daniel Vetter84849902012-12-02 00:28:11 +01002097 drm_modeset_unlock_all(dev);
Dave Airlief453ba02008-11-07 14:05:41 -08002098 return ret;
2099}
2100
2101int drm_mode_cursor_ioctl(struct drm_device *dev,
2102 void *data, struct drm_file *file_priv)
2103{
2104 struct drm_mode_cursor *req = data;
2105 struct drm_mode_object *obj;
2106 struct drm_crtc *crtc;
2107 int ret = 0;
2108
Dave Airliefb3b06c2011-02-08 13:55:21 +10002109 if (!drm_core_check_feature(dev, DRIVER_MODESET))
2110 return -EINVAL;
2111
Jakob Bornecrantz7c4eaca2012-08-16 08:29:03 +00002112 if (!req->flags || (~DRM_MODE_CURSOR_FLAGS & req->flags))
Dave Airlief453ba02008-11-07 14:05:41 -08002113 return -EINVAL;
Dave Airlief453ba02008-11-07 14:05:41 -08002114
Jakob Bornecrantze0c84632008-12-19 14:50:50 +10002115 obj = drm_mode_object_find(dev, req->crtc_id, DRM_MODE_OBJECT_CRTC);
Dave Airlief453ba02008-11-07 14:05:41 -08002116 if (!obj) {
Zhao Yakui58367ed2009-07-20 13:48:07 +08002117 DRM_DEBUG_KMS("Unknown CRTC ID %d\n", req->crtc_id);
Daniel Vetterdac35662012-12-02 15:24:10 +01002118 return -EINVAL;
Dave Airlief453ba02008-11-07 14:05:41 -08002119 }
2120 crtc = obj_to_crtc(obj);
2121
Daniel Vetterdac35662012-12-02 15:24:10 +01002122 mutex_lock(&crtc->mutex);
Dave Airlief453ba02008-11-07 14:05:41 -08002123 if (req->flags & DRM_MODE_CURSOR_BO) {
2124 if (!crtc->funcs->cursor_set) {
Dave Airlief453ba02008-11-07 14:05:41 -08002125 ret = -ENXIO;
2126 goto out;
2127 }
2128 /* Turns off the cursor if handle is 0 */
2129 ret = crtc->funcs->cursor_set(crtc, file_priv, req->handle,
2130 req->width, req->height);
2131 }
2132
2133 if (req->flags & DRM_MODE_CURSOR_MOVE) {
2134 if (crtc->funcs->cursor_move) {
2135 ret = crtc->funcs->cursor_move(crtc, req->x, req->y);
2136 } else {
Dave Airlief453ba02008-11-07 14:05:41 -08002137 ret = -EFAULT;
2138 goto out;
2139 }
2140 }
2141out:
Daniel Vetterdac35662012-12-02 15:24:10 +01002142 mutex_unlock(&crtc->mutex);
2143
Dave Airlief453ba02008-11-07 14:05:41 -08002144 return ret;
2145}
2146
Jesse Barnes308e5bc2011-11-14 14:51:28 -08002147/* Original addfb only supported RGB formats, so figure out which one */
2148uint32_t drm_mode_legacy_fb_format(uint32_t bpp, uint32_t depth)
2149{
2150 uint32_t fmt;
2151
2152 switch (bpp) {
2153 case 8:
Ville Syrjäläd84f0312013-01-31 19:43:38 +02002154 fmt = DRM_FORMAT_C8;
Jesse Barnes308e5bc2011-11-14 14:51:28 -08002155 break;
2156 case 16:
2157 if (depth == 15)
Ville Syrjälä04b39242011-11-17 18:05:13 +02002158 fmt = DRM_FORMAT_XRGB1555;
Jesse Barnes308e5bc2011-11-14 14:51:28 -08002159 else
Ville Syrjälä04b39242011-11-17 18:05:13 +02002160 fmt = DRM_FORMAT_RGB565;
Jesse Barnes308e5bc2011-11-14 14:51:28 -08002161 break;
2162 case 24:
Ville Syrjälä04b39242011-11-17 18:05:13 +02002163 fmt = DRM_FORMAT_RGB888;
Jesse Barnes308e5bc2011-11-14 14:51:28 -08002164 break;
2165 case 32:
2166 if (depth == 24)
Ville Syrjälä04b39242011-11-17 18:05:13 +02002167 fmt = DRM_FORMAT_XRGB8888;
Jesse Barnes308e5bc2011-11-14 14:51:28 -08002168 else if (depth == 30)
Ville Syrjälä04b39242011-11-17 18:05:13 +02002169 fmt = DRM_FORMAT_XRGB2101010;
Jesse Barnes308e5bc2011-11-14 14:51:28 -08002170 else
Ville Syrjälä04b39242011-11-17 18:05:13 +02002171 fmt = DRM_FORMAT_ARGB8888;
Jesse Barnes308e5bc2011-11-14 14:51:28 -08002172 break;
2173 default:
Ville Syrjälä04b39242011-11-17 18:05:13 +02002174 DRM_ERROR("bad bpp, assuming x8r8g8b8 pixel format\n");
2175 fmt = DRM_FORMAT_XRGB8888;
Jesse Barnes308e5bc2011-11-14 14:51:28 -08002176 break;
2177 }
2178
2179 return fmt;
2180}
2181EXPORT_SYMBOL(drm_mode_legacy_fb_format);
2182
Dave Airlief453ba02008-11-07 14:05:41 -08002183/**
2184 * drm_mode_addfb - add an FB to the graphics configuration
Daniel Vetter065a50ed2012-12-02 00:09:18 +01002185 * @dev: drm device for the ioctl
2186 * @data: data pointer for the ioctl
2187 * @file_priv: drm file for the ioctl call
Dave Airlief453ba02008-11-07 14:05:41 -08002188 *
Dave Airlief453ba02008-11-07 14:05:41 -08002189 * Add a new FB to the specified CRTC, given a user request.
2190 *
2191 * Called by the user via ioctl.
2192 *
2193 * RETURNS:
2194 * Zero on success, errno on failure.
2195 */
2196int drm_mode_addfb(struct drm_device *dev,
2197 void *data, struct drm_file *file_priv)
2198{
Jesse Barnes308e5bc2011-11-14 14:51:28 -08002199 struct drm_mode_fb_cmd *or = data;
2200 struct drm_mode_fb_cmd2 r = {};
2201 struct drm_mode_config *config = &dev->mode_config;
2202 struct drm_framebuffer *fb;
2203 int ret = 0;
2204
2205 /* Use new struct with format internally */
2206 r.fb_id = or->fb_id;
2207 r.width = or->width;
2208 r.height = or->height;
2209 r.pitches[0] = or->pitch;
2210 r.pixel_format = drm_mode_legacy_fb_format(or->bpp, or->depth);
2211 r.handles[0] = or->handle;
2212
2213 if (!drm_core_check_feature(dev, DRIVER_MODESET))
2214 return -EINVAL;
2215
Jesse Barnesacb4b992011-11-07 12:03:23 -08002216 if ((config->min_width > r.width) || (r.width > config->max_width))
Jesse Barnes308e5bc2011-11-14 14:51:28 -08002217 return -EINVAL;
Jesse Barnesacb4b992011-11-07 12:03:23 -08002218
2219 if ((config->min_height > r.height) || (r.height > config->max_height))
Jesse Barnes308e5bc2011-11-14 14:51:28 -08002220 return -EINVAL;
Jesse Barnes308e5bc2011-11-14 14:51:28 -08002221
Jesse Barnes308e5bc2011-11-14 14:51:28 -08002222 fb = dev->mode_config.funcs->fb_create(dev, file_priv, &r);
2223 if (IS_ERR(fb)) {
Dave Airlie1aa1b112012-05-01 17:38:35 +01002224 DRM_DEBUG_KMS("could not create framebuffer\n");
Daniel Vetter4b096ac2012-12-10 21:19:18 +01002225 return PTR_ERR(fb);
Jesse Barnes308e5bc2011-11-14 14:51:28 -08002226 }
2227
Daniel Vetter4b096ac2012-12-10 21:19:18 +01002228 mutex_lock(&file_priv->fbs_lock);
Jesse Barnes308e5bc2011-11-14 14:51:28 -08002229 or->fb_id = fb->base.id;
2230 list_add(&fb->filp_head, &file_priv->fbs);
2231 DRM_DEBUG_KMS("[FB:%d]\n", fb->base.id);
Daniel Vetter4b096ac2012-12-10 21:19:18 +01002232 mutex_unlock(&file_priv->fbs_lock);
Daniel Vetter4b096ac2012-12-10 21:19:18 +01002233
Jesse Barnes308e5bc2011-11-14 14:51:28 -08002234 return ret;
2235}
2236
Ville Syrjäläcff91b62012-05-24 20:54:00 +03002237static int format_check(const struct drm_mode_fb_cmd2 *r)
Ville Syrjälä935b5972011-12-20 00:06:48 +02002238{
2239 uint32_t format = r->pixel_format & ~DRM_FORMAT_BIG_ENDIAN;
2240
2241 switch (format) {
2242 case DRM_FORMAT_C8:
2243 case DRM_FORMAT_RGB332:
2244 case DRM_FORMAT_BGR233:
2245 case DRM_FORMAT_XRGB4444:
2246 case DRM_FORMAT_XBGR4444:
2247 case DRM_FORMAT_RGBX4444:
2248 case DRM_FORMAT_BGRX4444:
2249 case DRM_FORMAT_ARGB4444:
2250 case DRM_FORMAT_ABGR4444:
2251 case DRM_FORMAT_RGBA4444:
2252 case DRM_FORMAT_BGRA4444:
2253 case DRM_FORMAT_XRGB1555:
2254 case DRM_FORMAT_XBGR1555:
2255 case DRM_FORMAT_RGBX5551:
2256 case DRM_FORMAT_BGRX5551:
2257 case DRM_FORMAT_ARGB1555:
2258 case DRM_FORMAT_ABGR1555:
2259 case DRM_FORMAT_RGBA5551:
2260 case DRM_FORMAT_BGRA5551:
2261 case DRM_FORMAT_RGB565:
2262 case DRM_FORMAT_BGR565:
2263 case DRM_FORMAT_RGB888:
2264 case DRM_FORMAT_BGR888:
2265 case DRM_FORMAT_XRGB8888:
2266 case DRM_FORMAT_XBGR8888:
2267 case DRM_FORMAT_RGBX8888:
2268 case DRM_FORMAT_BGRX8888:
2269 case DRM_FORMAT_ARGB8888:
2270 case DRM_FORMAT_ABGR8888:
2271 case DRM_FORMAT_RGBA8888:
2272 case DRM_FORMAT_BGRA8888:
2273 case DRM_FORMAT_XRGB2101010:
2274 case DRM_FORMAT_XBGR2101010:
2275 case DRM_FORMAT_RGBX1010102:
2276 case DRM_FORMAT_BGRX1010102:
2277 case DRM_FORMAT_ARGB2101010:
2278 case DRM_FORMAT_ABGR2101010:
2279 case DRM_FORMAT_RGBA1010102:
2280 case DRM_FORMAT_BGRA1010102:
2281 case DRM_FORMAT_YUYV:
2282 case DRM_FORMAT_YVYU:
2283 case DRM_FORMAT_UYVY:
2284 case DRM_FORMAT_VYUY:
2285 case DRM_FORMAT_AYUV:
2286 case DRM_FORMAT_NV12:
2287 case DRM_FORMAT_NV21:
2288 case DRM_FORMAT_NV16:
2289 case DRM_FORMAT_NV61:
Laurent Pinchartba623f62012-05-18 23:47:40 +02002290 case DRM_FORMAT_NV24:
2291 case DRM_FORMAT_NV42:
Ville Syrjälä935b5972011-12-20 00:06:48 +02002292 case DRM_FORMAT_YUV410:
2293 case DRM_FORMAT_YVU410:
2294 case DRM_FORMAT_YUV411:
2295 case DRM_FORMAT_YVU411:
2296 case DRM_FORMAT_YUV420:
2297 case DRM_FORMAT_YVU420:
2298 case DRM_FORMAT_YUV422:
2299 case DRM_FORMAT_YVU422:
2300 case DRM_FORMAT_YUV444:
2301 case DRM_FORMAT_YVU444:
2302 return 0;
2303 default:
2304 return -EINVAL;
2305 }
2306}
2307
Ville Syrjäläcff91b62012-05-24 20:54:00 +03002308static int framebuffer_check(const struct drm_mode_fb_cmd2 *r)
Ville Syrjäläd1b45d52012-04-05 21:35:18 +03002309{
2310 int ret, hsub, vsub, num_planes, i;
2311
2312 ret = format_check(r);
2313 if (ret) {
Dave Airlie1aa1b112012-05-01 17:38:35 +01002314 DRM_DEBUG_KMS("bad framebuffer format 0x%08x\n", r->pixel_format);
Ville Syrjäläd1b45d52012-04-05 21:35:18 +03002315 return ret;
2316 }
2317
2318 hsub = drm_format_horz_chroma_subsampling(r->pixel_format);
2319 vsub = drm_format_vert_chroma_subsampling(r->pixel_format);
2320 num_planes = drm_format_num_planes(r->pixel_format);
2321
2322 if (r->width == 0 || r->width % hsub) {
Dave Airlie1aa1b112012-05-01 17:38:35 +01002323 DRM_DEBUG_KMS("bad framebuffer width %u\n", r->height);
Ville Syrjäläd1b45d52012-04-05 21:35:18 +03002324 return -EINVAL;
2325 }
2326
2327 if (r->height == 0 || r->height % vsub) {
Dave Airlie1aa1b112012-05-01 17:38:35 +01002328 DRM_DEBUG_KMS("bad framebuffer height %u\n", r->height);
Ville Syrjäläd1b45d52012-04-05 21:35:18 +03002329 return -EINVAL;
2330 }
2331
2332 for (i = 0; i < num_planes; i++) {
2333 unsigned int width = r->width / (i != 0 ? hsub : 1);
Ville Syrjäläb180b5d2012-10-25 18:05:04 +00002334 unsigned int height = r->height / (i != 0 ? vsub : 1);
2335 unsigned int cpp = drm_format_plane_cpp(r->pixel_format, i);
Ville Syrjäläd1b45d52012-04-05 21:35:18 +03002336
2337 if (!r->handles[i]) {
Dave Airlie1aa1b112012-05-01 17:38:35 +01002338 DRM_DEBUG_KMS("no buffer object handle for plane %d\n", i);
Ville Syrjäläd1b45d52012-04-05 21:35:18 +03002339 return -EINVAL;
2340 }
2341
Ville Syrjäläb180b5d2012-10-25 18:05:04 +00002342 if ((uint64_t) width * cpp > UINT_MAX)
2343 return -ERANGE;
2344
2345 if ((uint64_t) height * r->pitches[i] + r->offsets[i] > UINT_MAX)
2346 return -ERANGE;
2347
2348 if (r->pitches[i] < width * cpp) {
Dave Airlie1aa1b112012-05-01 17:38:35 +01002349 DRM_DEBUG_KMS("bad pitch %u for plane %d\n", r->pitches[i], i);
Ville Syrjäläd1b45d52012-04-05 21:35:18 +03002350 return -EINVAL;
2351 }
2352 }
2353
2354 return 0;
2355}
2356
Jesse Barnes308e5bc2011-11-14 14:51:28 -08002357/**
2358 * drm_mode_addfb2 - add an FB to the graphics configuration
Daniel Vetter065a50ed2012-12-02 00:09:18 +01002359 * @dev: drm device for the ioctl
2360 * @data: data pointer for the ioctl
2361 * @file_priv: drm file for the ioctl call
Jesse Barnes308e5bc2011-11-14 14:51:28 -08002362 *
Jesse Barnes308e5bc2011-11-14 14:51:28 -08002363 * Add a new FB to the specified CRTC, given a user request with format.
2364 *
2365 * Called by the user via ioctl.
2366 *
2367 * RETURNS:
2368 * Zero on success, errno on failure.
2369 */
2370int drm_mode_addfb2(struct drm_device *dev,
2371 void *data, struct drm_file *file_priv)
2372{
2373 struct drm_mode_fb_cmd2 *r = data;
Dave Airlief453ba02008-11-07 14:05:41 -08002374 struct drm_mode_config *config = &dev->mode_config;
2375 struct drm_framebuffer *fb;
Laurent Pinchart4a1b0712012-05-17 13:27:21 +02002376 int ret;
Dave Airlief453ba02008-11-07 14:05:41 -08002377
Dave Airliefb3b06c2011-02-08 13:55:21 +10002378 if (!drm_core_check_feature(dev, DRIVER_MODESET))
2379 return -EINVAL;
2380
Ville Syrjäläe3cc3522012-11-08 09:09:42 +00002381 if (r->flags & ~DRM_MODE_FB_INTERLACED) {
2382 DRM_DEBUG_KMS("bad framebuffer flags 0x%08x\n", r->flags);
2383 return -EINVAL;
2384 }
2385
Dave Airlief453ba02008-11-07 14:05:41 -08002386 if ((config->min_width > r->width) || (r->width > config->max_width)) {
Dave Airlie1aa1b112012-05-01 17:38:35 +01002387 DRM_DEBUG_KMS("bad framebuffer width %d, should be >= %d && <= %d\n",
Jesse Barnes8cf5c912011-11-14 14:51:27 -08002388 r->width, config->min_width, config->max_width);
Dave Airlief453ba02008-11-07 14:05:41 -08002389 return -EINVAL;
2390 }
2391 if ((config->min_height > r->height) || (r->height > config->max_height)) {
Dave Airlie1aa1b112012-05-01 17:38:35 +01002392 DRM_DEBUG_KMS("bad framebuffer height %d, should be >= %d && <= %d\n",
Jesse Barnes8cf5c912011-11-14 14:51:27 -08002393 r->height, config->min_height, config->max_height);
Dave Airlief453ba02008-11-07 14:05:41 -08002394 return -EINVAL;
2395 }
2396
Ville Syrjäläd1b45d52012-04-05 21:35:18 +03002397 ret = framebuffer_check(r);
2398 if (ret)
Ville Syrjälä935b5972011-12-20 00:06:48 +02002399 return ret;
Ville Syrjälä935b5972011-12-20 00:06:48 +02002400
Dave Airlief453ba02008-11-07 14:05:41 -08002401 fb = dev->mode_config.funcs->fb_create(dev, file_priv, r);
Chris Wilsoncce13ff2010-08-08 13:36:38 +01002402 if (IS_ERR(fb)) {
Dave Airlie1aa1b112012-05-01 17:38:35 +01002403 DRM_DEBUG_KMS("could not create framebuffer\n");
Daniel Vetter4b096ac2012-12-10 21:19:18 +01002404 return PTR_ERR(fb);
Dave Airlief453ba02008-11-07 14:05:41 -08002405 }
2406
Daniel Vetter4b096ac2012-12-10 21:19:18 +01002407 mutex_lock(&file_priv->fbs_lock);
Jakob Bornecrantze0c84632008-12-19 14:50:50 +10002408 r->fb_id = fb->base.id;
Dave Airlief453ba02008-11-07 14:05:41 -08002409 list_add(&fb->filp_head, &file_priv->fbs);
Jerome Glisse94401062010-07-15 15:43:25 -04002410 DRM_DEBUG_KMS("[FB:%d]\n", fb->base.id);
Daniel Vetter4b096ac2012-12-10 21:19:18 +01002411 mutex_unlock(&file_priv->fbs_lock);
Dave Airlief453ba02008-11-07 14:05:41 -08002412
Daniel Vetter4b096ac2012-12-10 21:19:18 +01002413
Dave Airlief453ba02008-11-07 14:05:41 -08002414 return ret;
2415}
2416
2417/**
2418 * drm_mode_rmfb - remove an FB from the configuration
Daniel Vetter065a50ed2012-12-02 00:09:18 +01002419 * @dev: drm device for the ioctl
2420 * @data: data pointer for the ioctl
2421 * @file_priv: drm file for the ioctl call
Dave Airlief453ba02008-11-07 14:05:41 -08002422 *
Dave Airlief453ba02008-11-07 14:05:41 -08002423 * Remove the FB specified by the user.
2424 *
2425 * Called by the user via ioctl.
2426 *
2427 * RETURNS:
2428 * Zero on success, errno on failure.
2429 */
2430int drm_mode_rmfb(struct drm_device *dev,
2431 void *data, struct drm_file *file_priv)
2432{
Dave Airlief453ba02008-11-07 14:05:41 -08002433 struct drm_framebuffer *fb = NULL;
2434 struct drm_framebuffer *fbl = NULL;
2435 uint32_t *id = data;
Dave Airlief453ba02008-11-07 14:05:41 -08002436 int found = 0;
2437
Dave Airliefb3b06c2011-02-08 13:55:21 +10002438 if (!drm_core_check_feature(dev, DRIVER_MODESET))
2439 return -EINVAL;
2440
Daniel Vetter4b096ac2012-12-10 21:19:18 +01002441 mutex_lock(&file_priv->fbs_lock);
Daniel Vetter2b677e82012-12-10 21:16:05 +01002442 mutex_lock(&dev->mode_config.fb_lock);
2443 fb = __drm_framebuffer_lookup(dev, *id);
2444 if (!fb)
2445 goto fail_lookup;
2446
Dave Airlief453ba02008-11-07 14:05:41 -08002447 list_for_each_entry(fbl, &file_priv->fbs, filp_head)
2448 if (fb == fbl)
2449 found = 1;
Daniel Vetter2b677e82012-12-10 21:16:05 +01002450 if (!found)
2451 goto fail_lookup;
2452
2453 /* Mark fb as reaped, we still have a ref from fpriv->fbs. */
2454 __drm_framebuffer_unregister(dev, fb);
Dave Airlief453ba02008-11-07 14:05:41 -08002455
Daniel Vetter4b096ac2012-12-10 21:19:18 +01002456 list_del_init(&fb->filp_head);
Daniel Vetter2b677e82012-12-10 21:16:05 +01002457 mutex_unlock(&dev->mode_config.fb_lock);
Daniel Vetter4b096ac2012-12-10 21:19:18 +01002458 mutex_unlock(&file_priv->fbs_lock);
Dave Airlief453ba02008-11-07 14:05:41 -08002459
Daniel Vetter4b096ac2012-12-10 21:19:18 +01002460 drm_framebuffer_remove(fb);
Daniel Vetter4b096ac2012-12-10 21:19:18 +01002461
Daniel Vetter2b677e82012-12-10 21:16:05 +01002462 return 0;
2463
2464fail_lookup:
2465 mutex_unlock(&dev->mode_config.fb_lock);
2466 mutex_unlock(&file_priv->fbs_lock);
2467
2468 return -EINVAL;
Dave Airlief453ba02008-11-07 14:05:41 -08002469}
2470
2471/**
2472 * drm_mode_getfb - get FB info
Daniel Vetter065a50ed2012-12-02 00:09:18 +01002473 * @dev: drm device for the ioctl
2474 * @data: data pointer for the ioctl
2475 * @file_priv: drm file for the ioctl call
Dave Airlief453ba02008-11-07 14:05:41 -08002476 *
Dave Airlief453ba02008-11-07 14:05:41 -08002477 * Lookup the FB given its ID and return info about it.
2478 *
2479 * Called by the user via ioctl.
2480 *
2481 * RETURNS:
2482 * Zero on success, errno on failure.
2483 */
2484int drm_mode_getfb(struct drm_device *dev,
2485 void *data, struct drm_file *file_priv)
2486{
2487 struct drm_mode_fb_cmd *r = data;
Dave Airlief453ba02008-11-07 14:05:41 -08002488 struct drm_framebuffer *fb;
Daniel Vetter58c0dca2012-12-13 23:06:08 +01002489 int ret;
Dave Airlief453ba02008-11-07 14:05:41 -08002490
Dave Airliefb3b06c2011-02-08 13:55:21 +10002491 if (!drm_core_check_feature(dev, DRIVER_MODESET))
2492 return -EINVAL;
2493
Daniel Vetter786b99e2012-12-02 21:53:40 +01002494 fb = drm_framebuffer_lookup(dev, r->fb_id);
Daniel Vetter58c0dca2012-12-13 23:06:08 +01002495 if (!fb)
2496 return -EINVAL;
Dave Airlief453ba02008-11-07 14:05:41 -08002497
2498 r->height = fb->height;
2499 r->width = fb->width;
2500 r->depth = fb->depth;
2501 r->bpp = fb->bits_per_pixel;
Ville Syrjälä01f2c772011-12-20 00:06:49 +02002502 r->pitch = fb->pitches[0];
Daniel Vetteraf26ef32012-12-13 23:07:50 +01002503 if (fb->funcs->create_handle)
2504 ret = fb->funcs->create_handle(fb, file_priv, &r->handle);
2505 else
2506 ret = -ENODEV;
Dave Airlief453ba02008-11-07 14:05:41 -08002507
Daniel Vetter58c0dca2012-12-13 23:06:08 +01002508 drm_framebuffer_unreference(fb);
2509
Dave Airlief453ba02008-11-07 14:05:41 -08002510 return ret;
2511}
2512
Jakob Bornecrantz884840a2009-12-03 23:25:47 +00002513int drm_mode_dirtyfb_ioctl(struct drm_device *dev,
2514 void *data, struct drm_file *file_priv)
2515{
2516 struct drm_clip_rect __user *clips_ptr;
2517 struct drm_clip_rect *clips = NULL;
2518 struct drm_mode_fb_dirty_cmd *r = data;
Jakob Bornecrantz884840a2009-12-03 23:25:47 +00002519 struct drm_framebuffer *fb;
2520 unsigned flags;
2521 int num_clips;
Laurent Pinchart4a1b0712012-05-17 13:27:21 +02002522 int ret;
Jakob Bornecrantz884840a2009-12-03 23:25:47 +00002523
Dave Airliefb3b06c2011-02-08 13:55:21 +10002524 if (!drm_core_check_feature(dev, DRIVER_MODESET))
2525 return -EINVAL;
2526
Daniel Vetter786b99e2012-12-02 21:53:40 +01002527 fb = drm_framebuffer_lookup(dev, r->fb_id);
Daniel Vetter4ccf0972012-12-11 00:38:18 +01002528 if (!fb)
2529 return -EINVAL;
Jakob Bornecrantz884840a2009-12-03 23:25:47 +00002530
2531 num_clips = r->num_clips;
Ville Syrjälä81f6c7f2011-12-20 00:06:42 +02002532 clips_ptr = (struct drm_clip_rect __user *)(unsigned long)r->clips_ptr;
Jakob Bornecrantz884840a2009-12-03 23:25:47 +00002533
2534 if (!num_clips != !clips_ptr) {
2535 ret = -EINVAL;
2536 goto out_err1;
2537 }
2538
2539 flags = DRM_MODE_FB_DIRTY_FLAGS & r->flags;
2540
2541 /* If userspace annotates copy, clips must come in pairs */
2542 if (flags & DRM_MODE_FB_DIRTY_ANNOTATE_COPY && (num_clips % 2)) {
2543 ret = -EINVAL;
2544 goto out_err1;
2545 }
2546
2547 if (num_clips && clips_ptr) {
Xi Wanga5cd3352011-11-23 01:12:01 -05002548 if (num_clips < 0 || num_clips > DRM_MODE_FB_DIRTY_MAX_CLIPS) {
2549 ret = -EINVAL;
2550 goto out_err1;
2551 }
Jakob Bornecrantz884840a2009-12-03 23:25:47 +00002552 clips = kzalloc(num_clips * sizeof(*clips), GFP_KERNEL);
2553 if (!clips) {
2554 ret = -ENOMEM;
2555 goto out_err1;
2556 }
2557
2558 ret = copy_from_user(clips, clips_ptr,
2559 num_clips * sizeof(*clips));
Dan Carpentere902a352010-06-04 12:23:21 +02002560 if (ret) {
2561 ret = -EFAULT;
Jakob Bornecrantz884840a2009-12-03 23:25:47 +00002562 goto out_err2;
Dan Carpentere902a352010-06-04 12:23:21 +02002563 }
Jakob Bornecrantz884840a2009-12-03 23:25:47 +00002564 }
2565
2566 if (fb->funcs->dirty) {
Daniel Vetter4ccf0972012-12-11 00:38:18 +01002567 drm_modeset_lock_all(dev);
Thomas Hellstrom02b00162010-10-05 12:43:02 +02002568 ret = fb->funcs->dirty(fb, file_priv, flags, r->color,
2569 clips, num_clips);
Daniel Vetter4ccf0972012-12-11 00:38:18 +01002570 drm_modeset_unlock_all(dev);
Jakob Bornecrantz884840a2009-12-03 23:25:47 +00002571 } else {
2572 ret = -ENOSYS;
Jakob Bornecrantz884840a2009-12-03 23:25:47 +00002573 }
2574
2575out_err2:
2576 kfree(clips);
2577out_err1:
Daniel Vetter4ccf0972012-12-11 00:38:18 +01002578 drm_framebuffer_unreference(fb);
2579
Jakob Bornecrantz884840a2009-12-03 23:25:47 +00002580 return ret;
2581}
2582
2583
Dave Airlief453ba02008-11-07 14:05:41 -08002584/**
2585 * drm_fb_release - remove and free the FBs on this file
Daniel Vetter065a50ed2012-12-02 00:09:18 +01002586 * @priv: drm file for the ioctl
Dave Airlief453ba02008-11-07 14:05:41 -08002587 *
Dave Airlief453ba02008-11-07 14:05:41 -08002588 * Destroy all the FBs associated with @filp.
2589 *
2590 * Called by the user via ioctl.
2591 *
2592 * RETURNS:
2593 * Zero on success, errno on failure.
2594 */
Kristian Høgsbergea39f832009-02-12 14:37:56 -05002595void drm_fb_release(struct drm_file *priv)
Dave Airlief453ba02008-11-07 14:05:41 -08002596{
Dave Airlief453ba02008-11-07 14:05:41 -08002597 struct drm_device *dev = priv->minor->dev;
2598 struct drm_framebuffer *fb, *tfb;
2599
Daniel Vetter4b096ac2012-12-10 21:19:18 +01002600 mutex_lock(&priv->fbs_lock);
Dave Airlief453ba02008-11-07 14:05:41 -08002601 list_for_each_entry_safe(fb, tfb, &priv->fbs, filp_head) {
Daniel Vetter2b677e82012-12-10 21:16:05 +01002602
2603 mutex_lock(&dev->mode_config.fb_lock);
2604 /* Mark fb as reaped, we still have a ref from fpriv->fbs. */
2605 __drm_framebuffer_unregister(dev, fb);
2606 mutex_unlock(&dev->mode_config.fb_lock);
2607
Daniel Vetter4b096ac2012-12-10 21:19:18 +01002608 list_del_init(&fb->filp_head);
Daniel Vetter2b677e82012-12-10 21:16:05 +01002609
2610 /* This will also drop the fpriv->fbs reference. */
Rob Clarkf7eff602012-09-05 21:48:38 +00002611 drm_framebuffer_remove(fb);
Dave Airlief453ba02008-11-07 14:05:41 -08002612 }
Daniel Vetter4b096ac2012-12-10 21:19:18 +01002613 mutex_unlock(&priv->fbs_lock);
Dave Airlief453ba02008-11-07 14:05:41 -08002614}
2615
Dave Airlief453ba02008-11-07 14:05:41 -08002616struct drm_property *drm_property_create(struct drm_device *dev, int flags,
2617 const char *name, int num_values)
2618{
2619 struct drm_property *property = NULL;
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +02002620 int ret;
Dave Airlief453ba02008-11-07 14:05:41 -08002621
2622 property = kzalloc(sizeof(struct drm_property), GFP_KERNEL);
2623 if (!property)
2624 return NULL;
2625
2626 if (num_values) {
2627 property->values = kzalloc(sizeof(uint64_t)*num_values, GFP_KERNEL);
2628 if (!property->values)
2629 goto fail;
2630 }
2631
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +02002632 ret = drm_mode_object_get(dev, &property->base, DRM_MODE_OBJECT_PROPERTY);
2633 if (ret)
2634 goto fail;
2635
Dave Airlief453ba02008-11-07 14:05:41 -08002636 property->flags = flags;
2637 property->num_values = num_values;
2638 INIT_LIST_HEAD(&property->enum_blob_list);
2639
Vinson Lee471dd2e2011-11-10 11:55:40 -08002640 if (name) {
Dave Airlief453ba02008-11-07 14:05:41 -08002641 strncpy(property->name, name, DRM_PROP_NAME_LEN);
Vinson Lee471dd2e2011-11-10 11:55:40 -08002642 property->name[DRM_PROP_NAME_LEN-1] = '\0';
2643 }
Dave Airlief453ba02008-11-07 14:05:41 -08002644
2645 list_add_tail(&property->head, &dev->mode_config.property_list);
2646 return property;
2647fail:
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +02002648 kfree(property->values);
Dave Airlief453ba02008-11-07 14:05:41 -08002649 kfree(property);
2650 return NULL;
2651}
2652EXPORT_SYMBOL(drm_property_create);
2653
Sascha Hauer4a67d392012-02-06 10:58:17 +01002654struct drm_property *drm_property_create_enum(struct drm_device *dev, int flags,
2655 const char *name,
2656 const struct drm_prop_enum_list *props,
2657 int num_values)
2658{
2659 struct drm_property *property;
2660 int i, ret;
2661
2662 flags |= DRM_MODE_PROP_ENUM;
2663
2664 property = drm_property_create(dev, flags, name, num_values);
2665 if (!property)
2666 return NULL;
2667
2668 for (i = 0; i < num_values; i++) {
2669 ret = drm_property_add_enum(property, i,
2670 props[i].type,
2671 props[i].name);
2672 if (ret) {
2673 drm_property_destroy(dev, property);
2674 return NULL;
2675 }
2676 }
2677
2678 return property;
2679}
2680EXPORT_SYMBOL(drm_property_create_enum);
2681
Rob Clark49e27542012-05-17 02:23:26 -06002682struct drm_property *drm_property_create_bitmask(struct drm_device *dev,
2683 int flags, const char *name,
2684 const struct drm_prop_enum_list *props,
2685 int num_values)
2686{
2687 struct drm_property *property;
2688 int i, ret;
2689
2690 flags |= DRM_MODE_PROP_BITMASK;
2691
2692 property = drm_property_create(dev, flags, name, num_values);
2693 if (!property)
2694 return NULL;
2695
2696 for (i = 0; i < num_values; i++) {
2697 ret = drm_property_add_enum(property, i,
2698 props[i].type,
2699 props[i].name);
2700 if (ret) {
2701 drm_property_destroy(dev, property);
2702 return NULL;
2703 }
2704 }
2705
2706 return property;
2707}
2708EXPORT_SYMBOL(drm_property_create_bitmask);
2709
Sascha Hauerd9bc3c02012-02-06 10:58:18 +01002710struct drm_property *drm_property_create_range(struct drm_device *dev, int flags,
2711 const char *name,
2712 uint64_t min, uint64_t max)
2713{
2714 struct drm_property *property;
2715
2716 flags |= DRM_MODE_PROP_RANGE;
2717
2718 property = drm_property_create(dev, flags, name, 2);
2719 if (!property)
2720 return NULL;
2721
2722 property->values[0] = min;
2723 property->values[1] = max;
2724
2725 return property;
2726}
2727EXPORT_SYMBOL(drm_property_create_range);
2728
Dave Airlief453ba02008-11-07 14:05:41 -08002729int drm_property_add_enum(struct drm_property *property, int index,
2730 uint64_t value, const char *name)
2731{
2732 struct drm_property_enum *prop_enum;
2733
Rob Clark49e27542012-05-17 02:23:26 -06002734 if (!(property->flags & (DRM_MODE_PROP_ENUM | DRM_MODE_PROP_BITMASK)))
2735 return -EINVAL;
2736
2737 /*
2738 * Bitmask enum properties have the additional constraint of values
2739 * from 0 to 63
2740 */
2741 if ((property->flags & DRM_MODE_PROP_BITMASK) && (value > 63))
Dave Airlief453ba02008-11-07 14:05:41 -08002742 return -EINVAL;
2743
2744 if (!list_empty(&property->enum_blob_list)) {
2745 list_for_each_entry(prop_enum, &property->enum_blob_list, head) {
2746 if (prop_enum->value == value) {
2747 strncpy(prop_enum->name, name, DRM_PROP_NAME_LEN);
2748 prop_enum->name[DRM_PROP_NAME_LEN-1] = '\0';
2749 return 0;
2750 }
2751 }
2752 }
2753
2754 prop_enum = kzalloc(sizeof(struct drm_property_enum), GFP_KERNEL);
2755 if (!prop_enum)
2756 return -ENOMEM;
2757
2758 strncpy(prop_enum->name, name, DRM_PROP_NAME_LEN);
2759 prop_enum->name[DRM_PROP_NAME_LEN-1] = '\0';
2760 prop_enum->value = value;
2761
2762 property->values[index] = value;
2763 list_add_tail(&prop_enum->head, &property->enum_blob_list);
2764 return 0;
2765}
2766EXPORT_SYMBOL(drm_property_add_enum);
2767
2768void drm_property_destroy(struct drm_device *dev, struct drm_property *property)
2769{
2770 struct drm_property_enum *prop_enum, *pt;
2771
2772 list_for_each_entry_safe(prop_enum, pt, &property->enum_blob_list, head) {
2773 list_del(&prop_enum->head);
2774 kfree(prop_enum);
2775 }
2776
2777 if (property->num_values)
2778 kfree(property->values);
2779 drm_mode_object_put(dev, &property->base);
2780 list_del(&property->head);
2781 kfree(property);
2782}
2783EXPORT_SYMBOL(drm_property_destroy);
2784
Paulo Zanonic5431882012-05-15 18:09:02 -03002785void drm_object_attach_property(struct drm_mode_object *obj,
2786 struct drm_property *property,
2787 uint64_t init_val)
2788{
Paulo Zanoni7f88a9b2012-05-15 18:09:04 -03002789 int count = obj->properties->count;
Paulo Zanonic5431882012-05-15 18:09:02 -03002790
Paulo Zanoni7f88a9b2012-05-15 18:09:04 -03002791 if (count == DRM_OBJECT_MAX_PROPERTY) {
2792 WARN(1, "Failed to attach object property (type: 0x%x). Please "
2793 "increase DRM_OBJECT_MAX_PROPERTY by 1 for each time "
2794 "you see this message on the same object type.\n",
2795 obj->type);
2796 return;
Paulo Zanonic5431882012-05-15 18:09:02 -03002797 }
2798
Paulo Zanoni7f88a9b2012-05-15 18:09:04 -03002799 obj->properties->ids[count] = property->base.id;
2800 obj->properties->values[count] = init_val;
2801 obj->properties->count++;
Paulo Zanonic5431882012-05-15 18:09:02 -03002802}
2803EXPORT_SYMBOL(drm_object_attach_property);
2804
2805int drm_object_property_set_value(struct drm_mode_object *obj,
2806 struct drm_property *property, uint64_t val)
2807{
2808 int i;
2809
Paulo Zanoni7f88a9b2012-05-15 18:09:04 -03002810 for (i = 0; i < obj->properties->count; i++) {
Paulo Zanonic5431882012-05-15 18:09:02 -03002811 if (obj->properties->ids[i] == property->base.id) {
2812 obj->properties->values[i] = val;
2813 return 0;
2814 }
2815 }
2816
2817 return -EINVAL;
2818}
2819EXPORT_SYMBOL(drm_object_property_set_value);
2820
2821int drm_object_property_get_value(struct drm_mode_object *obj,
2822 struct drm_property *property, uint64_t *val)
2823{
2824 int i;
2825
Paulo Zanoni7f88a9b2012-05-15 18:09:04 -03002826 for (i = 0; i < obj->properties->count; i++) {
Paulo Zanonic5431882012-05-15 18:09:02 -03002827 if (obj->properties->ids[i] == property->base.id) {
2828 *val = obj->properties->values[i];
2829 return 0;
2830 }
2831 }
2832
2833 return -EINVAL;
2834}
2835EXPORT_SYMBOL(drm_object_property_get_value);
2836
Dave Airlief453ba02008-11-07 14:05:41 -08002837int drm_mode_getproperty_ioctl(struct drm_device *dev,
2838 void *data, struct drm_file *file_priv)
2839{
2840 struct drm_mode_object *obj;
2841 struct drm_mode_get_property *out_resp = data;
2842 struct drm_property *property;
2843 int enum_count = 0;
2844 int blob_count = 0;
2845 int value_count = 0;
2846 int ret = 0, i;
2847 int copied;
2848 struct drm_property_enum *prop_enum;
2849 struct drm_mode_property_enum __user *enum_ptr;
2850 struct drm_property_blob *prop_blob;
Ville Syrjälä81f6c7f2011-12-20 00:06:42 +02002851 uint32_t __user *blob_id_ptr;
Dave Airlief453ba02008-11-07 14:05:41 -08002852 uint64_t __user *values_ptr;
2853 uint32_t __user *blob_length_ptr;
2854
Dave Airliefb3b06c2011-02-08 13:55:21 +10002855 if (!drm_core_check_feature(dev, DRIVER_MODESET))
2856 return -EINVAL;
2857
Daniel Vetter84849902012-12-02 00:28:11 +01002858 drm_modeset_lock_all(dev);
Dave Airlief453ba02008-11-07 14:05:41 -08002859 obj = drm_mode_object_find(dev, out_resp->prop_id, DRM_MODE_OBJECT_PROPERTY);
2860 if (!obj) {
2861 ret = -EINVAL;
2862 goto done;
2863 }
2864 property = obj_to_property(obj);
2865
Rob Clark49e27542012-05-17 02:23:26 -06002866 if (property->flags & (DRM_MODE_PROP_ENUM | DRM_MODE_PROP_BITMASK)) {
Dave Airlief453ba02008-11-07 14:05:41 -08002867 list_for_each_entry(prop_enum, &property->enum_blob_list, head)
2868 enum_count++;
2869 } else if (property->flags & DRM_MODE_PROP_BLOB) {
2870 list_for_each_entry(prop_blob, &property->enum_blob_list, head)
2871 blob_count++;
2872 }
2873
2874 value_count = property->num_values;
2875
2876 strncpy(out_resp->name, property->name, DRM_PROP_NAME_LEN);
2877 out_resp->name[DRM_PROP_NAME_LEN-1] = 0;
2878 out_resp->flags = property->flags;
2879
2880 if ((out_resp->count_values >= value_count) && value_count) {
Ville Syrjälä81f6c7f2011-12-20 00:06:42 +02002881 values_ptr = (uint64_t __user *)(unsigned long)out_resp->values_ptr;
Dave Airlief453ba02008-11-07 14:05:41 -08002882 for (i = 0; i < value_count; i++) {
2883 if (copy_to_user(values_ptr + i, &property->values[i], sizeof(uint64_t))) {
2884 ret = -EFAULT;
2885 goto done;
2886 }
2887 }
2888 }
2889 out_resp->count_values = value_count;
2890
Rob Clark49e27542012-05-17 02:23:26 -06002891 if (property->flags & (DRM_MODE_PROP_ENUM | DRM_MODE_PROP_BITMASK)) {
Dave Airlief453ba02008-11-07 14:05:41 -08002892 if ((out_resp->count_enum_blobs >= enum_count) && enum_count) {
2893 copied = 0;
Ville Syrjälä81f6c7f2011-12-20 00:06:42 +02002894 enum_ptr = (struct drm_mode_property_enum __user *)(unsigned long)out_resp->enum_blob_ptr;
Dave Airlief453ba02008-11-07 14:05:41 -08002895 list_for_each_entry(prop_enum, &property->enum_blob_list, head) {
2896
2897 if (copy_to_user(&enum_ptr[copied].value, &prop_enum->value, sizeof(uint64_t))) {
2898 ret = -EFAULT;
2899 goto done;
2900 }
2901
2902 if (copy_to_user(&enum_ptr[copied].name,
2903 &prop_enum->name, DRM_PROP_NAME_LEN)) {
2904 ret = -EFAULT;
2905 goto done;
2906 }
2907 copied++;
2908 }
2909 }
2910 out_resp->count_enum_blobs = enum_count;
2911 }
2912
2913 if (property->flags & DRM_MODE_PROP_BLOB) {
2914 if ((out_resp->count_enum_blobs >= blob_count) && blob_count) {
2915 copied = 0;
Ville Syrjälä81f6c7f2011-12-20 00:06:42 +02002916 blob_id_ptr = (uint32_t __user *)(unsigned long)out_resp->enum_blob_ptr;
2917 blob_length_ptr = (uint32_t __user *)(unsigned long)out_resp->values_ptr;
Dave Airlief453ba02008-11-07 14:05:41 -08002918
2919 list_for_each_entry(prop_blob, &property->enum_blob_list, head) {
2920 if (put_user(prop_blob->base.id, blob_id_ptr + copied)) {
2921 ret = -EFAULT;
2922 goto done;
2923 }
2924
2925 if (put_user(prop_blob->length, blob_length_ptr + copied)) {
2926 ret = -EFAULT;
2927 goto done;
2928 }
2929
2930 copied++;
2931 }
2932 }
2933 out_resp->count_enum_blobs = blob_count;
2934 }
2935done:
Daniel Vetter84849902012-12-02 00:28:11 +01002936 drm_modeset_unlock_all(dev);
Dave Airlief453ba02008-11-07 14:05:41 -08002937 return ret;
2938}
2939
2940static struct drm_property_blob *drm_property_create_blob(struct drm_device *dev, int length,
2941 void *data)
2942{
2943 struct drm_property_blob *blob;
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +02002944 int ret;
Dave Airlief453ba02008-11-07 14:05:41 -08002945
2946 if (!length || !data)
2947 return NULL;
2948
2949 blob = kzalloc(sizeof(struct drm_property_blob)+length, GFP_KERNEL);
2950 if (!blob)
2951 return NULL;
2952
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +02002953 ret = drm_mode_object_get(dev, &blob->base, DRM_MODE_OBJECT_BLOB);
2954 if (ret) {
2955 kfree(blob);
2956 return NULL;
2957 }
2958
Dave Airlief453ba02008-11-07 14:05:41 -08002959 blob->length = length;
2960
2961 memcpy(blob->data, data, length);
2962
Dave Airlief453ba02008-11-07 14:05:41 -08002963 list_add_tail(&blob->head, &dev->mode_config.property_blob_list);
2964 return blob;
2965}
2966
2967static void drm_property_destroy_blob(struct drm_device *dev,
2968 struct drm_property_blob *blob)
2969{
2970 drm_mode_object_put(dev, &blob->base);
2971 list_del(&blob->head);
2972 kfree(blob);
2973}
2974
2975int drm_mode_getblob_ioctl(struct drm_device *dev,
2976 void *data, struct drm_file *file_priv)
2977{
2978 struct drm_mode_object *obj;
2979 struct drm_mode_get_blob *out_resp = data;
2980 struct drm_property_blob *blob;
2981 int ret = 0;
Ville Syrjälä81f6c7f2011-12-20 00:06:42 +02002982 void __user *blob_ptr;
Dave Airlief453ba02008-11-07 14:05:41 -08002983
Dave Airliefb3b06c2011-02-08 13:55:21 +10002984 if (!drm_core_check_feature(dev, DRIVER_MODESET))
2985 return -EINVAL;
2986
Daniel Vetter84849902012-12-02 00:28:11 +01002987 drm_modeset_lock_all(dev);
Dave Airlief453ba02008-11-07 14:05:41 -08002988 obj = drm_mode_object_find(dev, out_resp->blob_id, DRM_MODE_OBJECT_BLOB);
2989 if (!obj) {
2990 ret = -EINVAL;
2991 goto done;
2992 }
2993 blob = obj_to_blob(obj);
2994
2995 if (out_resp->length == blob->length) {
Ville Syrjälä81f6c7f2011-12-20 00:06:42 +02002996 blob_ptr = (void __user *)(unsigned long)out_resp->data;
Dave Airlief453ba02008-11-07 14:05:41 -08002997 if (copy_to_user(blob_ptr, blob->data, blob->length)){
2998 ret = -EFAULT;
2999 goto done;
3000 }
3001 }
3002 out_resp->length = blob->length;
3003
3004done:
Daniel Vetter84849902012-12-02 00:28:11 +01003005 drm_modeset_unlock_all(dev);
Dave Airlief453ba02008-11-07 14:05:41 -08003006 return ret;
3007}
3008
3009int drm_mode_connector_update_edid_property(struct drm_connector *connector,
3010 struct edid *edid)
3011{
3012 struct drm_device *dev = connector->dev;
Laurent Pinchart4a1b0712012-05-17 13:27:21 +02003013 int ret, size;
Dave Airlief453ba02008-11-07 14:05:41 -08003014
3015 if (connector->edid_blob_ptr)
3016 drm_property_destroy_blob(dev, connector->edid_blob_ptr);
3017
3018 /* Delete edid, when there is none. */
3019 if (!edid) {
3020 connector->edid_blob_ptr = NULL;
Rob Clark58495562012-10-11 20:50:56 -05003021 ret = drm_object_property_set_value(&connector->base, dev->mode_config.edid_property, 0);
Dave Airlief453ba02008-11-07 14:05:41 -08003022 return ret;
3023 }
3024
Adam Jackson7466f4c2010-03-29 21:43:23 +00003025 size = EDID_LENGTH * (1 + edid->extensions);
3026 connector->edid_blob_ptr = drm_property_create_blob(connector->dev,
3027 size, edid);
Sachin Kamate655d122012-11-19 09:44:57 +00003028 if (!connector->edid_blob_ptr)
3029 return -EINVAL;
Dave Airlief453ba02008-11-07 14:05:41 -08003030
Rob Clark58495562012-10-11 20:50:56 -05003031 ret = drm_object_property_set_value(&connector->base,
Dave Airlief453ba02008-11-07 14:05:41 -08003032 dev->mode_config.edid_property,
3033 connector->edid_blob_ptr->base.id);
3034
3035 return ret;
3036}
3037EXPORT_SYMBOL(drm_mode_connector_update_edid_property);
3038
Paulo Zanoni26a34812012-05-15 18:08:59 -03003039static bool drm_property_change_is_valid(struct drm_property *property,
Ville Syrjälä592c20e2012-05-24 20:53:58 +03003040 uint64_t value)
Paulo Zanoni26a34812012-05-15 18:08:59 -03003041{
3042 if (property->flags & DRM_MODE_PROP_IMMUTABLE)
3043 return false;
3044 if (property->flags & DRM_MODE_PROP_RANGE) {
3045 if (value < property->values[0] || value > property->values[1])
3046 return false;
3047 return true;
Rob Clark49e27542012-05-17 02:23:26 -06003048 } else if (property->flags & DRM_MODE_PROP_BITMASK) {
3049 int i;
Ville Syrjälä592c20e2012-05-24 20:53:58 +03003050 uint64_t valid_mask = 0;
Rob Clark49e27542012-05-17 02:23:26 -06003051 for (i = 0; i < property->num_values; i++)
3052 valid_mask |= (1ULL << property->values[i]);
3053 return !(value & ~valid_mask);
Ville Syrjäläc4a56752012-10-25 18:05:06 +00003054 } else if (property->flags & DRM_MODE_PROP_BLOB) {
3055 /* Only the driver knows */
3056 return true;
Paulo Zanoni26a34812012-05-15 18:08:59 -03003057 } else {
3058 int i;
3059 for (i = 0; i < property->num_values; i++)
3060 if (property->values[i] == value)
3061 return true;
3062 return false;
3063 }
3064}
3065
Dave Airlief453ba02008-11-07 14:05:41 -08003066int drm_mode_connector_property_set_ioctl(struct drm_device *dev,
3067 void *data, struct drm_file *file_priv)
3068{
Paulo Zanoni0057d8d2012-05-15 18:09:03 -03003069 struct drm_mode_connector_set_property *conn_set_prop = data;
3070 struct drm_mode_obj_set_property obj_set_prop = {
3071 .value = conn_set_prop->value,
3072 .prop_id = conn_set_prop->prop_id,
3073 .obj_id = conn_set_prop->connector_id,
3074 .obj_type = DRM_MODE_OBJECT_CONNECTOR
3075 };
Dave Airlief453ba02008-11-07 14:05:41 -08003076
Paulo Zanoni0057d8d2012-05-15 18:09:03 -03003077 /* It does all the locking and checking we need */
3078 return drm_mode_obj_set_property_ioctl(dev, &obj_set_prop, file_priv);
Dave Airlief453ba02008-11-07 14:05:41 -08003079}
3080
Paulo Zanonic5431882012-05-15 18:09:02 -03003081static int drm_mode_connector_set_obj_prop(struct drm_mode_object *obj,
3082 struct drm_property *property,
3083 uint64_t value)
3084{
3085 int ret = -EINVAL;
3086 struct drm_connector *connector = obj_to_connector(obj);
3087
3088 /* Do DPMS ourselves */
3089 if (property == connector->dev->mode_config.dpms_property) {
3090 if (connector->funcs->dpms)
3091 (*connector->funcs->dpms)(connector, (int)value);
3092 ret = 0;
3093 } else if (connector->funcs->set_property)
3094 ret = connector->funcs->set_property(connector, property, value);
3095
3096 /* store the property value if successful */
3097 if (!ret)
Rob Clark58495562012-10-11 20:50:56 -05003098 drm_object_property_set_value(&connector->base, property, value);
Paulo Zanonic5431882012-05-15 18:09:02 -03003099 return ret;
3100}
3101
Paulo Zanonibffd9de02012-05-15 18:09:05 -03003102static int drm_mode_crtc_set_obj_prop(struct drm_mode_object *obj,
3103 struct drm_property *property,
3104 uint64_t value)
3105{
3106 int ret = -EINVAL;
3107 struct drm_crtc *crtc = obj_to_crtc(obj);
3108
3109 if (crtc->funcs->set_property)
3110 ret = crtc->funcs->set_property(crtc, property, value);
3111 if (!ret)
3112 drm_object_property_set_value(obj, property, value);
3113
3114 return ret;
3115}
3116
Rob Clark4d939142012-05-17 02:23:27 -06003117static int drm_mode_plane_set_obj_prop(struct drm_mode_object *obj,
3118 struct drm_property *property,
3119 uint64_t value)
3120{
3121 int ret = -EINVAL;
3122 struct drm_plane *plane = obj_to_plane(obj);
3123
3124 if (plane->funcs->set_property)
3125 ret = plane->funcs->set_property(plane, property, value);
3126 if (!ret)
3127 drm_object_property_set_value(obj, property, value);
3128
3129 return ret;
3130}
3131
Paulo Zanonic5431882012-05-15 18:09:02 -03003132int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data,
3133 struct drm_file *file_priv)
3134{
3135 struct drm_mode_obj_get_properties *arg = data;
3136 struct drm_mode_object *obj;
3137 int ret = 0;
3138 int i;
3139 int copied = 0;
3140 int props_count = 0;
3141 uint32_t __user *props_ptr;
3142 uint64_t __user *prop_values_ptr;
3143
3144 if (!drm_core_check_feature(dev, DRIVER_MODESET))
3145 return -EINVAL;
3146
Daniel Vetter84849902012-12-02 00:28:11 +01003147 drm_modeset_lock_all(dev);
Paulo Zanonic5431882012-05-15 18:09:02 -03003148
3149 obj = drm_mode_object_find(dev, arg->obj_id, arg->obj_type);
3150 if (!obj) {
3151 ret = -EINVAL;
3152 goto out;
3153 }
3154 if (!obj->properties) {
3155 ret = -EINVAL;
3156 goto out;
3157 }
3158
Paulo Zanoni7f88a9b2012-05-15 18:09:04 -03003159 props_count = obj->properties->count;
Paulo Zanonic5431882012-05-15 18:09:02 -03003160
3161 /* This ioctl is called twice, once to determine how much space is
3162 * needed, and the 2nd time to fill it. */
3163 if ((arg->count_props >= props_count) && props_count) {
3164 copied = 0;
3165 props_ptr = (uint32_t __user *)(unsigned long)(arg->props_ptr);
3166 prop_values_ptr = (uint64_t __user *)(unsigned long)
3167 (arg->prop_values_ptr);
3168 for (i = 0; i < props_count; i++) {
3169 if (put_user(obj->properties->ids[i],
3170 props_ptr + copied)) {
3171 ret = -EFAULT;
3172 goto out;
3173 }
3174 if (put_user(obj->properties->values[i],
3175 prop_values_ptr + copied)) {
3176 ret = -EFAULT;
3177 goto out;
3178 }
3179 copied++;
3180 }
3181 }
3182 arg->count_props = props_count;
3183out:
Daniel Vetter84849902012-12-02 00:28:11 +01003184 drm_modeset_unlock_all(dev);
Paulo Zanonic5431882012-05-15 18:09:02 -03003185 return ret;
3186}
3187
3188int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data,
3189 struct drm_file *file_priv)
3190{
3191 struct drm_mode_obj_set_property *arg = data;
3192 struct drm_mode_object *arg_obj;
3193 struct drm_mode_object *prop_obj;
3194 struct drm_property *property;
3195 int ret = -EINVAL;
3196 int i;
3197
3198 if (!drm_core_check_feature(dev, DRIVER_MODESET))
3199 return -EINVAL;
3200
Daniel Vetter84849902012-12-02 00:28:11 +01003201 drm_modeset_lock_all(dev);
Paulo Zanonic5431882012-05-15 18:09:02 -03003202
3203 arg_obj = drm_mode_object_find(dev, arg->obj_id, arg->obj_type);
3204 if (!arg_obj)
3205 goto out;
3206 if (!arg_obj->properties)
3207 goto out;
3208
Paulo Zanoni7f88a9b2012-05-15 18:09:04 -03003209 for (i = 0; i < arg_obj->properties->count; i++)
Paulo Zanonic5431882012-05-15 18:09:02 -03003210 if (arg_obj->properties->ids[i] == arg->prop_id)
3211 break;
3212
Paulo Zanoni7f88a9b2012-05-15 18:09:04 -03003213 if (i == arg_obj->properties->count)
Paulo Zanonic5431882012-05-15 18:09:02 -03003214 goto out;
3215
3216 prop_obj = drm_mode_object_find(dev, arg->prop_id,
3217 DRM_MODE_OBJECT_PROPERTY);
3218 if (!prop_obj)
3219 goto out;
3220 property = obj_to_property(prop_obj);
3221
3222 if (!drm_property_change_is_valid(property, arg->value))
3223 goto out;
3224
3225 switch (arg_obj->type) {
3226 case DRM_MODE_OBJECT_CONNECTOR:
3227 ret = drm_mode_connector_set_obj_prop(arg_obj, property,
3228 arg->value);
3229 break;
Paulo Zanonibffd9de02012-05-15 18:09:05 -03003230 case DRM_MODE_OBJECT_CRTC:
3231 ret = drm_mode_crtc_set_obj_prop(arg_obj, property, arg->value);
3232 break;
Rob Clark4d939142012-05-17 02:23:27 -06003233 case DRM_MODE_OBJECT_PLANE:
3234 ret = drm_mode_plane_set_obj_prop(arg_obj, property, arg->value);
3235 break;
Paulo Zanonic5431882012-05-15 18:09:02 -03003236 }
3237
3238out:
Daniel Vetter84849902012-12-02 00:28:11 +01003239 drm_modeset_unlock_all(dev);
Paulo Zanonic5431882012-05-15 18:09:02 -03003240 return ret;
3241}
3242
Dave Airlief453ba02008-11-07 14:05:41 -08003243int drm_mode_connector_attach_encoder(struct drm_connector *connector,
3244 struct drm_encoder *encoder)
3245{
3246 int i;
3247
3248 for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
3249 if (connector->encoder_ids[i] == 0) {
3250 connector->encoder_ids[i] = encoder->base.id;
3251 return 0;
3252 }
3253 }
3254 return -ENOMEM;
3255}
3256EXPORT_SYMBOL(drm_mode_connector_attach_encoder);
3257
3258void drm_mode_connector_detach_encoder(struct drm_connector *connector,
3259 struct drm_encoder *encoder)
3260{
3261 int i;
3262 for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
3263 if (connector->encoder_ids[i] == encoder->base.id) {
3264 connector->encoder_ids[i] = 0;
3265 if (connector->encoder == encoder)
3266 connector->encoder = NULL;
3267 break;
3268 }
3269 }
3270}
3271EXPORT_SYMBOL(drm_mode_connector_detach_encoder);
3272
Sascha Hauer4cae5b82012-02-01 11:38:23 +01003273int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc,
Dave Airlief453ba02008-11-07 14:05:41 -08003274 int gamma_size)
3275{
3276 crtc->gamma_size = gamma_size;
3277
3278 crtc->gamma_store = kzalloc(gamma_size * sizeof(uint16_t) * 3, GFP_KERNEL);
3279 if (!crtc->gamma_store) {
3280 crtc->gamma_size = 0;
Sascha Hauer4cae5b82012-02-01 11:38:23 +01003281 return -ENOMEM;
Dave Airlief453ba02008-11-07 14:05:41 -08003282 }
3283
Sascha Hauer4cae5b82012-02-01 11:38:23 +01003284 return 0;
Dave Airlief453ba02008-11-07 14:05:41 -08003285}
3286EXPORT_SYMBOL(drm_mode_crtc_set_gamma_size);
3287
3288int drm_mode_gamma_set_ioctl(struct drm_device *dev,
3289 void *data, struct drm_file *file_priv)
3290{
3291 struct drm_mode_crtc_lut *crtc_lut = data;
3292 struct drm_mode_object *obj;
3293 struct drm_crtc *crtc;
3294 void *r_base, *g_base, *b_base;
3295 int size;
3296 int ret = 0;
3297
Dave Airliefb3b06c2011-02-08 13:55:21 +10003298 if (!drm_core_check_feature(dev, DRIVER_MODESET))
3299 return -EINVAL;
3300
Daniel Vetter84849902012-12-02 00:28:11 +01003301 drm_modeset_lock_all(dev);
Dave Airlief453ba02008-11-07 14:05:41 -08003302 obj = drm_mode_object_find(dev, crtc_lut->crtc_id, DRM_MODE_OBJECT_CRTC);
3303 if (!obj) {
3304 ret = -EINVAL;
3305 goto out;
3306 }
3307 crtc = obj_to_crtc(obj);
3308
Laurent Pinchartebe0f242012-05-17 13:27:24 +02003309 if (crtc->funcs->gamma_set == NULL) {
3310 ret = -ENOSYS;
3311 goto out;
3312 }
3313
Dave Airlief453ba02008-11-07 14:05:41 -08003314 /* memcpy into gamma store */
3315 if (crtc_lut->gamma_size != crtc->gamma_size) {
3316 ret = -EINVAL;
3317 goto out;
3318 }
3319
3320 size = crtc_lut->gamma_size * (sizeof(uint16_t));
3321 r_base = crtc->gamma_store;
3322 if (copy_from_user(r_base, (void __user *)(unsigned long)crtc_lut->red, size)) {
3323 ret = -EFAULT;
3324 goto out;
3325 }
3326
3327 g_base = r_base + size;
3328 if (copy_from_user(g_base, (void __user *)(unsigned long)crtc_lut->green, size)) {
3329 ret = -EFAULT;
3330 goto out;
3331 }
3332
3333 b_base = g_base + size;
3334 if (copy_from_user(b_base, (void __user *)(unsigned long)crtc_lut->blue, size)) {
3335 ret = -EFAULT;
3336 goto out;
3337 }
3338
James Simmons72034252010-08-03 01:33:19 +01003339 crtc->funcs->gamma_set(crtc, r_base, g_base, b_base, 0, crtc->gamma_size);
Dave Airlief453ba02008-11-07 14:05:41 -08003340
3341out:
Daniel Vetter84849902012-12-02 00:28:11 +01003342 drm_modeset_unlock_all(dev);
Dave Airlief453ba02008-11-07 14:05:41 -08003343 return ret;
3344
3345}
3346
3347int drm_mode_gamma_get_ioctl(struct drm_device *dev,
3348 void *data, struct drm_file *file_priv)
3349{
3350 struct drm_mode_crtc_lut *crtc_lut = data;
3351 struct drm_mode_object *obj;
3352 struct drm_crtc *crtc;
3353 void *r_base, *g_base, *b_base;
3354 int size;
3355 int ret = 0;
3356
Dave Airliefb3b06c2011-02-08 13:55:21 +10003357 if (!drm_core_check_feature(dev, DRIVER_MODESET))
3358 return -EINVAL;
3359
Daniel Vetter84849902012-12-02 00:28:11 +01003360 drm_modeset_lock_all(dev);
Dave Airlief453ba02008-11-07 14:05:41 -08003361 obj = drm_mode_object_find(dev, crtc_lut->crtc_id, DRM_MODE_OBJECT_CRTC);
3362 if (!obj) {
3363 ret = -EINVAL;
3364 goto out;
3365 }
3366 crtc = obj_to_crtc(obj);
3367
3368 /* memcpy into gamma store */
3369 if (crtc_lut->gamma_size != crtc->gamma_size) {
3370 ret = -EINVAL;
3371 goto out;
3372 }
3373
3374 size = crtc_lut->gamma_size * (sizeof(uint16_t));
3375 r_base = crtc->gamma_store;
3376 if (copy_to_user((void __user *)(unsigned long)crtc_lut->red, r_base, size)) {
3377 ret = -EFAULT;
3378 goto out;
3379 }
3380
3381 g_base = r_base + size;
3382 if (copy_to_user((void __user *)(unsigned long)crtc_lut->green, g_base, size)) {
3383 ret = -EFAULT;
3384 goto out;
3385 }
3386
3387 b_base = g_base + size;
3388 if (copy_to_user((void __user *)(unsigned long)crtc_lut->blue, b_base, size)) {
3389 ret = -EFAULT;
3390 goto out;
3391 }
3392out:
Daniel Vetter84849902012-12-02 00:28:11 +01003393 drm_modeset_unlock_all(dev);
Dave Airlief453ba02008-11-07 14:05:41 -08003394 return ret;
3395}
Kristian Høgsbergd91d8a32009-11-17 12:43:55 -05003396
3397int drm_mode_page_flip_ioctl(struct drm_device *dev,
3398 void *data, struct drm_file *file_priv)
3399{
3400 struct drm_mode_crtc_page_flip *page_flip = data;
3401 struct drm_mode_object *obj;
3402 struct drm_crtc *crtc;
Daniel Vetterb0d12322012-12-11 01:07:12 +01003403 struct drm_framebuffer *fb = NULL, *old_fb = NULL;
Kristian Høgsbergd91d8a32009-11-17 12:43:55 -05003404 struct drm_pending_vblank_event *e = NULL;
3405 unsigned long flags;
Rob Clark7c80e122012-09-04 16:35:56 +00003406 int hdisplay, vdisplay;
Kristian Høgsbergd91d8a32009-11-17 12:43:55 -05003407 int ret = -EINVAL;
3408
3409 if (page_flip->flags & ~DRM_MODE_PAGE_FLIP_FLAGS ||
3410 page_flip->reserved != 0)
3411 return -EINVAL;
3412
Kristian Høgsbergd91d8a32009-11-17 12:43:55 -05003413 obj = drm_mode_object_find(dev, page_flip->crtc_id, DRM_MODE_OBJECT_CRTC);
3414 if (!obj)
Daniel Vetterb4d5e7d2012-12-11 16:59:31 +01003415 return -EINVAL;
Kristian Høgsbergd91d8a32009-11-17 12:43:55 -05003416 crtc = obj_to_crtc(obj);
3417
Daniel Vetterb4d5e7d2012-12-11 16:59:31 +01003418 mutex_lock(&crtc->mutex);
Chris Wilson90c1efd2010-07-17 20:23:26 +01003419 if (crtc->fb == NULL) {
3420 /* The framebuffer is currently unbound, presumably
3421 * due to a hotplug event, that userspace has not
3422 * yet discovered.
3423 */
3424 ret = -EBUSY;
3425 goto out;
3426 }
3427
Kristian Høgsbergd91d8a32009-11-17 12:43:55 -05003428 if (crtc->funcs->page_flip == NULL)
3429 goto out;
3430
Daniel Vetter786b99e2012-12-02 21:53:40 +01003431 fb = drm_framebuffer_lookup(dev, page_flip->fb_id);
3432 if (!fb)
Kristian Høgsbergd91d8a32009-11-17 12:43:55 -05003433 goto out;
Kristian Høgsbergd91d8a32009-11-17 12:43:55 -05003434
Rob Clark7c80e122012-09-04 16:35:56 +00003435 hdisplay = crtc->mode.hdisplay;
3436 vdisplay = crtc->mode.vdisplay;
3437
3438 if (crtc->invert_dimensions)
3439 swap(hdisplay, vdisplay);
3440
3441 if (hdisplay > fb->width ||
3442 vdisplay > fb->height ||
3443 crtc->x > fb->width - hdisplay ||
3444 crtc->y > fb->height - vdisplay) {
3445 DRM_DEBUG_KMS("Invalid fb size %ux%u for CRTC viewport %ux%u+%d+%d%s.\n",
3446 fb->width, fb->height, hdisplay, vdisplay, crtc->x, crtc->y,
3447 crtc->invert_dimensions ? " (inverted)" : "");
Ville Syrjälä5f61bb42012-03-13 12:35:45 +02003448 ret = -ENOSPC;
3449 goto out;
3450 }
3451
Laurent Pinchart909d9cd2013-04-22 01:38:46 +02003452 if (crtc->fb->pixel_format != fb->pixel_format) {
3453 DRM_DEBUG_KMS("Page flip is not allowed to change frame buffer format.\n");
3454 ret = -EINVAL;
3455 goto out;
3456 }
3457
Kristian Høgsbergd91d8a32009-11-17 12:43:55 -05003458 if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) {
3459 ret = -ENOMEM;
3460 spin_lock_irqsave(&dev->event_lock, flags);
3461 if (file_priv->event_space < sizeof e->event) {
3462 spin_unlock_irqrestore(&dev->event_lock, flags);
3463 goto out;
3464 }
3465 file_priv->event_space -= sizeof e->event;
3466 spin_unlock_irqrestore(&dev->event_lock, flags);
3467
3468 e = kzalloc(sizeof *e, GFP_KERNEL);
3469 if (e == NULL) {
3470 spin_lock_irqsave(&dev->event_lock, flags);
3471 file_priv->event_space += sizeof e->event;
3472 spin_unlock_irqrestore(&dev->event_lock, flags);
3473 goto out;
3474 }
3475
Jesse Barnes7bd4d7b2009-11-19 10:50:22 -08003476 e->event.base.type = DRM_EVENT_FLIP_COMPLETE;
Kristian Høgsbergd91d8a32009-11-17 12:43:55 -05003477 e->event.base.length = sizeof e->event;
3478 e->event.user_data = page_flip->user_data;
3479 e->base.event = &e->event.base;
3480 e->base.file_priv = file_priv;
3481 e->base.destroy =
3482 (void (*) (struct drm_pending_event *)) kfree;
3483 }
3484
Daniel Vetterb0d12322012-12-11 01:07:12 +01003485 old_fb = crtc->fb;
Kristian Høgsbergd91d8a32009-11-17 12:43:55 -05003486 ret = crtc->funcs->page_flip(crtc, fb, e);
3487 if (ret) {
Joonyoung Shimaef6a7e2012-04-18 13:47:02 +09003488 if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) {
3489 spin_lock_irqsave(&dev->event_lock, flags);
3490 file_priv->event_space += sizeof e->event;
3491 spin_unlock_irqrestore(&dev->event_lock, flags);
3492 kfree(e);
3493 }
Daniel Vetterb0d12322012-12-11 01:07:12 +01003494 /* Keep the old fb, don't unref it. */
3495 old_fb = NULL;
3496 } else {
Thierry Reding8cf1e982013-02-13 16:08:33 +01003497 /*
3498 * Warn if the driver hasn't properly updated the crtc->fb
3499 * field to reflect that the new framebuffer is now used.
3500 * Failing to do so will screw with the reference counting
3501 * on framebuffers.
3502 */
3503 WARN_ON(crtc->fb != fb);
Daniel Vetterb0d12322012-12-11 01:07:12 +01003504 /* Unref only the old framebuffer. */
3505 fb = NULL;
Kristian Høgsbergd91d8a32009-11-17 12:43:55 -05003506 }
3507
3508out:
Daniel Vetterb0d12322012-12-11 01:07:12 +01003509 if (fb)
3510 drm_framebuffer_unreference(fb);
3511 if (old_fb)
3512 drm_framebuffer_unreference(old_fb);
Daniel Vetterb4d5e7d2012-12-11 16:59:31 +01003513 mutex_unlock(&crtc->mutex);
3514
Kristian Høgsbergd91d8a32009-11-17 12:43:55 -05003515 return ret;
3516}
Chris Wilsoneb033552011-01-24 15:11:08 +00003517
3518void drm_mode_config_reset(struct drm_device *dev)
3519{
3520 struct drm_crtc *crtc;
3521 struct drm_encoder *encoder;
3522 struct drm_connector *connector;
3523
3524 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
3525 if (crtc->funcs->reset)
3526 crtc->funcs->reset(crtc);
3527
3528 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head)
3529 if (encoder->funcs->reset)
3530 encoder->funcs->reset(encoder);
3531
Daniel Vetter5e2cb2f2012-10-23 18:23:35 +00003532 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
3533 connector->status = connector_status_unknown;
3534
Chris Wilsoneb033552011-01-24 15:11:08 +00003535 if (connector->funcs->reset)
3536 connector->funcs->reset(connector);
Daniel Vetter5e2cb2f2012-10-23 18:23:35 +00003537 }
Chris Wilsoneb033552011-01-24 15:11:08 +00003538}
3539EXPORT_SYMBOL(drm_mode_config_reset);
Dave Airlieff72145b2011-02-07 12:16:14 +10003540
3541int drm_mode_create_dumb_ioctl(struct drm_device *dev,
3542 void *data, struct drm_file *file_priv)
3543{
3544 struct drm_mode_create_dumb *args = data;
3545
3546 if (!dev->driver->dumb_create)
3547 return -ENOSYS;
3548 return dev->driver->dumb_create(file_priv, dev, args);
3549}
3550
3551int drm_mode_mmap_dumb_ioctl(struct drm_device *dev,
3552 void *data, struct drm_file *file_priv)
3553{
3554 struct drm_mode_map_dumb *args = data;
3555
3556 /* call driver ioctl to get mmap offset */
3557 if (!dev->driver->dumb_map_offset)
3558 return -ENOSYS;
3559
3560 return dev->driver->dumb_map_offset(file_priv, dev, args->handle, &args->offset);
3561}
3562
3563int drm_mode_destroy_dumb_ioctl(struct drm_device *dev,
3564 void *data, struct drm_file *file_priv)
3565{
3566 struct drm_mode_destroy_dumb *args = data;
3567
3568 if (!dev->driver->dumb_destroy)
3569 return -ENOSYS;
3570
3571 return dev->driver->dumb_destroy(file_priv, dev, args->handle);
3572}
Dave Airlie248dbc22011-11-29 20:02:54 +00003573
3574/*
3575 * Just need to support RGB formats here for compat with code that doesn't
3576 * use pixel formats directly yet.
3577 */
3578void drm_fb_get_bpp_depth(uint32_t format, unsigned int *depth,
3579 int *bpp)
3580{
3581 switch (format) {
Ville Syrjäläc51a6bc2013-01-31 19:43:37 +02003582 case DRM_FORMAT_C8:
Ville Syrjälä04b39242011-11-17 18:05:13 +02003583 case DRM_FORMAT_RGB332:
3584 case DRM_FORMAT_BGR233:
Dave Airlie248dbc22011-11-29 20:02:54 +00003585 *depth = 8;
3586 *bpp = 8;
3587 break;
Ville Syrjälä04b39242011-11-17 18:05:13 +02003588 case DRM_FORMAT_XRGB1555:
3589 case DRM_FORMAT_XBGR1555:
3590 case DRM_FORMAT_RGBX5551:
3591 case DRM_FORMAT_BGRX5551:
3592 case DRM_FORMAT_ARGB1555:
3593 case DRM_FORMAT_ABGR1555:
3594 case DRM_FORMAT_RGBA5551:
3595 case DRM_FORMAT_BGRA5551:
Dave Airlie248dbc22011-11-29 20:02:54 +00003596 *depth = 15;
3597 *bpp = 16;
3598 break;
Ville Syrjälä04b39242011-11-17 18:05:13 +02003599 case DRM_FORMAT_RGB565:
3600 case DRM_FORMAT_BGR565:
Dave Airlie248dbc22011-11-29 20:02:54 +00003601 *depth = 16;
3602 *bpp = 16;
3603 break;
Ville Syrjälä04b39242011-11-17 18:05:13 +02003604 case DRM_FORMAT_RGB888:
3605 case DRM_FORMAT_BGR888:
3606 *depth = 24;
3607 *bpp = 24;
3608 break;
3609 case DRM_FORMAT_XRGB8888:
3610 case DRM_FORMAT_XBGR8888:
3611 case DRM_FORMAT_RGBX8888:
3612 case DRM_FORMAT_BGRX8888:
Dave Airlie248dbc22011-11-29 20:02:54 +00003613 *depth = 24;
3614 *bpp = 32;
3615 break;
Ville Syrjälä04b39242011-11-17 18:05:13 +02003616 case DRM_FORMAT_XRGB2101010:
3617 case DRM_FORMAT_XBGR2101010:
3618 case DRM_FORMAT_RGBX1010102:
3619 case DRM_FORMAT_BGRX1010102:
3620 case DRM_FORMAT_ARGB2101010:
3621 case DRM_FORMAT_ABGR2101010:
3622 case DRM_FORMAT_RGBA1010102:
3623 case DRM_FORMAT_BGRA1010102:
Dave Airlie248dbc22011-11-29 20:02:54 +00003624 *depth = 30;
3625 *bpp = 32;
3626 break;
Ville Syrjälä04b39242011-11-17 18:05:13 +02003627 case DRM_FORMAT_ARGB8888:
3628 case DRM_FORMAT_ABGR8888:
3629 case DRM_FORMAT_RGBA8888:
3630 case DRM_FORMAT_BGRA8888:
Dave Airlie248dbc22011-11-29 20:02:54 +00003631 *depth = 32;
3632 *bpp = 32;
3633 break;
3634 default:
3635 DRM_DEBUG_KMS("unsupported pixel format\n");
3636 *depth = 0;
3637 *bpp = 0;
3638 break;
3639 }
3640}
3641EXPORT_SYMBOL(drm_fb_get_bpp_depth);
Ville Syrjälä141670e2012-04-05 21:35:15 +03003642
3643/**
3644 * drm_format_num_planes - get the number of planes for format
3645 * @format: pixel format (DRM_FORMAT_*)
3646 *
3647 * RETURNS:
3648 * The number of planes used by the specified pixel format.
3649 */
3650int drm_format_num_planes(uint32_t format)
3651{
3652 switch (format) {
3653 case DRM_FORMAT_YUV410:
3654 case DRM_FORMAT_YVU410:
3655 case DRM_FORMAT_YUV411:
3656 case DRM_FORMAT_YVU411:
3657 case DRM_FORMAT_YUV420:
3658 case DRM_FORMAT_YVU420:
3659 case DRM_FORMAT_YUV422:
3660 case DRM_FORMAT_YVU422:
3661 case DRM_FORMAT_YUV444:
3662 case DRM_FORMAT_YVU444:
3663 return 3;
3664 case DRM_FORMAT_NV12:
3665 case DRM_FORMAT_NV21:
3666 case DRM_FORMAT_NV16:
3667 case DRM_FORMAT_NV61:
Laurent Pinchartba623f62012-05-18 23:47:40 +02003668 case DRM_FORMAT_NV24:
3669 case DRM_FORMAT_NV42:
Ville Syrjälä141670e2012-04-05 21:35:15 +03003670 return 2;
3671 default:
3672 return 1;
3673 }
3674}
3675EXPORT_SYMBOL(drm_format_num_planes);
Ville Syrjälä5a86bd52012-04-05 21:35:16 +03003676
3677/**
3678 * drm_format_plane_cpp - determine the bytes per pixel value
3679 * @format: pixel format (DRM_FORMAT_*)
3680 * @plane: plane index
3681 *
3682 * RETURNS:
3683 * The bytes per pixel value for the specified plane.
3684 */
3685int drm_format_plane_cpp(uint32_t format, int plane)
3686{
3687 unsigned int depth;
3688 int bpp;
3689
3690 if (plane >= drm_format_num_planes(format))
3691 return 0;
3692
3693 switch (format) {
3694 case DRM_FORMAT_YUYV:
3695 case DRM_FORMAT_YVYU:
3696 case DRM_FORMAT_UYVY:
3697 case DRM_FORMAT_VYUY:
3698 return 2;
3699 case DRM_FORMAT_NV12:
3700 case DRM_FORMAT_NV21:
3701 case DRM_FORMAT_NV16:
3702 case DRM_FORMAT_NV61:
Laurent Pinchartba623f62012-05-18 23:47:40 +02003703 case DRM_FORMAT_NV24:
3704 case DRM_FORMAT_NV42:
Ville Syrjälä5a86bd52012-04-05 21:35:16 +03003705 return plane ? 2 : 1;
3706 case DRM_FORMAT_YUV410:
3707 case DRM_FORMAT_YVU410:
3708 case DRM_FORMAT_YUV411:
3709 case DRM_FORMAT_YVU411:
3710 case DRM_FORMAT_YUV420:
3711 case DRM_FORMAT_YVU420:
3712 case DRM_FORMAT_YUV422:
3713 case DRM_FORMAT_YVU422:
3714 case DRM_FORMAT_YUV444:
3715 case DRM_FORMAT_YVU444:
3716 return 1;
3717 default:
3718 drm_fb_get_bpp_depth(format, &depth, &bpp);
3719 return bpp >> 3;
3720 }
3721}
3722EXPORT_SYMBOL(drm_format_plane_cpp);
Ville Syrjälä01b68b02012-04-05 21:35:17 +03003723
3724/**
3725 * drm_format_horz_chroma_subsampling - get the horizontal chroma subsampling factor
3726 * @format: pixel format (DRM_FORMAT_*)
3727 *
3728 * RETURNS:
3729 * The horizontal chroma subsampling factor for the
3730 * specified pixel format.
3731 */
3732int drm_format_horz_chroma_subsampling(uint32_t format)
3733{
3734 switch (format) {
3735 case DRM_FORMAT_YUV411:
3736 case DRM_FORMAT_YVU411:
3737 case DRM_FORMAT_YUV410:
3738 case DRM_FORMAT_YVU410:
3739 return 4;
3740 case DRM_FORMAT_YUYV:
3741 case DRM_FORMAT_YVYU:
3742 case DRM_FORMAT_UYVY:
3743 case DRM_FORMAT_VYUY:
3744 case DRM_FORMAT_NV12:
3745 case DRM_FORMAT_NV21:
3746 case DRM_FORMAT_NV16:
3747 case DRM_FORMAT_NV61:
3748 case DRM_FORMAT_YUV422:
3749 case DRM_FORMAT_YVU422:
3750 case DRM_FORMAT_YUV420:
3751 case DRM_FORMAT_YVU420:
3752 return 2;
3753 default:
3754 return 1;
3755 }
3756}
3757EXPORT_SYMBOL(drm_format_horz_chroma_subsampling);
3758
3759/**
3760 * drm_format_vert_chroma_subsampling - get the vertical chroma subsampling factor
3761 * @format: pixel format (DRM_FORMAT_*)
3762 *
3763 * RETURNS:
3764 * The vertical chroma subsampling factor for the
3765 * specified pixel format.
3766 */
3767int drm_format_vert_chroma_subsampling(uint32_t format)
3768{
3769 switch (format) {
3770 case DRM_FORMAT_YUV410:
3771 case DRM_FORMAT_YVU410:
3772 return 4;
3773 case DRM_FORMAT_YUV420:
3774 case DRM_FORMAT_YVU420:
3775 case DRM_FORMAT_NV12:
3776 case DRM_FORMAT_NV21:
3777 return 2;
3778 default:
3779 return 1;
3780 }
3781}
3782EXPORT_SYMBOL(drm_format_vert_chroma_subsampling);
Laurent Pinchart87d24fc2013-04-15 15:37:16 +02003783
3784/**
3785 * drm_mode_config_init - initialize DRM mode_configuration structure
3786 * @dev: DRM device
3787 *
3788 * Initialize @dev's mode_config structure, used for tracking the graphics
3789 * configuration of @dev.
3790 *
3791 * Since this initializes the modeset locks, no locking is possible. Which is no
3792 * problem, since this should happen single threaded at init time. It is the
3793 * driver's problem to ensure this guarantee.
3794 *
3795 */
3796void drm_mode_config_init(struct drm_device *dev)
3797{
3798 mutex_init(&dev->mode_config.mutex);
3799 mutex_init(&dev->mode_config.idr_mutex);
3800 mutex_init(&dev->mode_config.fb_lock);
3801 INIT_LIST_HEAD(&dev->mode_config.fb_list);
3802 INIT_LIST_HEAD(&dev->mode_config.crtc_list);
3803 INIT_LIST_HEAD(&dev->mode_config.connector_list);
3804 INIT_LIST_HEAD(&dev->mode_config.encoder_list);
3805 INIT_LIST_HEAD(&dev->mode_config.property_list);
3806 INIT_LIST_HEAD(&dev->mode_config.property_blob_list);
3807 INIT_LIST_HEAD(&dev->mode_config.plane_list);
3808 idr_init(&dev->mode_config.crtc_idr);
3809
3810 drm_modeset_lock_all(dev);
3811 drm_mode_create_standard_connector_properties(dev);
3812 drm_modeset_unlock_all(dev);
3813
3814 /* Just to be sure */
3815 dev->mode_config.num_fb = 0;
3816 dev->mode_config.num_connector = 0;
3817 dev->mode_config.num_crtc = 0;
3818 dev->mode_config.num_encoder = 0;
3819}
3820EXPORT_SYMBOL(drm_mode_config_init);
3821
3822/**
3823 * drm_mode_config_cleanup - free up DRM mode_config info
3824 * @dev: DRM device
3825 *
3826 * Free up all the connectors and CRTCs associated with this DRM device, then
3827 * free up the framebuffers and associated buffer objects.
3828 *
3829 * Note that since this /should/ happen single-threaded at driver/device
3830 * teardown time, no locking is required. It's the driver's job to ensure that
3831 * this guarantee actually holds true.
3832 *
3833 * FIXME: cleanup any dangling user buffer objects too
3834 */
3835void drm_mode_config_cleanup(struct drm_device *dev)
3836{
3837 struct drm_connector *connector, *ot;
3838 struct drm_crtc *crtc, *ct;
3839 struct drm_encoder *encoder, *enct;
3840 struct drm_framebuffer *fb, *fbt;
3841 struct drm_property *property, *pt;
3842 struct drm_property_blob *blob, *bt;
3843 struct drm_plane *plane, *plt;
3844
3845 list_for_each_entry_safe(encoder, enct, &dev->mode_config.encoder_list,
3846 head) {
3847 encoder->funcs->destroy(encoder);
3848 }
3849
3850 list_for_each_entry_safe(connector, ot,
3851 &dev->mode_config.connector_list, head) {
3852 connector->funcs->destroy(connector);
3853 }
3854
3855 list_for_each_entry_safe(property, pt, &dev->mode_config.property_list,
3856 head) {
3857 drm_property_destroy(dev, property);
3858 }
3859
3860 list_for_each_entry_safe(blob, bt, &dev->mode_config.property_blob_list,
3861 head) {
3862 drm_property_destroy_blob(dev, blob);
3863 }
3864
3865 /*
3866 * Single-threaded teardown context, so it's not required to grab the
3867 * fb_lock to protect against concurrent fb_list access. Contrary, it
3868 * would actually deadlock with the drm_framebuffer_cleanup function.
3869 *
3870 * Also, if there are any framebuffers left, that's a driver leak now,
3871 * so politely WARN about this.
3872 */
3873 WARN_ON(!list_empty(&dev->mode_config.fb_list));
3874 list_for_each_entry_safe(fb, fbt, &dev->mode_config.fb_list, head) {
3875 drm_framebuffer_remove(fb);
3876 }
3877
3878 list_for_each_entry_safe(plane, plt, &dev->mode_config.plane_list,
3879 head) {
3880 plane->funcs->destroy(plane);
3881 }
3882
3883 list_for_each_entry_safe(crtc, ct, &dev->mode_config.crtc_list, head) {
3884 crtc->funcs->destroy(crtc);
3885 }
3886
3887 idr_destroy(&dev->mode_config.crtc_idr);
3888}
3889EXPORT_SYMBOL(drm_mode_config_cleanup);