blob: e7e92429d10f9e36d80d48e5f8a0004e4eb0284e [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}
Lespiau, Damiened7951d2013-05-10 12:36:42 +0000253EXPORT_SYMBOL(drm_get_connector_status_name);
Dave Airlief453ba02008-11-07 14:05:41 -0800254
255/**
Daniel Vetter065a50ed2012-12-02 00:09:18 +0100256 * drm_mode_object_get - allocate a new modeset identifier
Dave Airlief453ba02008-11-07 14:05:41 -0800257 * @dev: DRM device
Daniel Vetter065a50ed2012-12-02 00:09:18 +0100258 * @obj: object pointer, used to generate unique ID
259 * @obj_type: object type
Dave Airlief453ba02008-11-07 14:05:41 -0800260 *
Dave Airlief453ba02008-11-07 14:05:41 -0800261 * Create a unique identifier based on @ptr in @dev's identifier space. Used
262 * for tracking modes, CRTCs and connectors.
263 *
264 * RETURNS:
265 * New unique (relative to other objects in @dev) integer identifier for the
266 * object.
267 */
268static int drm_mode_object_get(struct drm_device *dev,
269 struct drm_mode_object *obj, uint32_t obj_type)
270{
Dave Airlief453ba02008-11-07 14:05:41 -0800271 int ret;
272
Jesse Barnesad2563c2009-01-19 17:21:45 +1000273 mutex_lock(&dev->mode_config.idr_mutex);
Tejun Heo2e928812013-02-27 17:04:08 -0800274 ret = idr_alloc(&dev->mode_config.crtc_idr, obj, 1, 0, GFP_KERNEL);
275 if (ret >= 0) {
Daniel Vetter4b096ac2012-12-10 21:19:18 +0100276 /*
277 * Set up the object linking under the protection of the idr
278 * lock so that other users can't see inconsistent state.
279 */
Tejun Heo2e928812013-02-27 17:04:08 -0800280 obj->id = ret;
Daniel Vetter4b096ac2012-12-10 21:19:18 +0100281 obj->type = obj_type;
282 }
Jesse Barnesad2563c2009-01-19 17:21:45 +1000283 mutex_unlock(&dev->mode_config.idr_mutex);
Daniel Vetter4b096ac2012-12-10 21:19:18 +0100284
Tejun Heo2e928812013-02-27 17:04:08 -0800285 return ret < 0 ? ret : 0;
Dave Airlief453ba02008-11-07 14:05:41 -0800286}
287
288/**
Daniel Vetter065a50ed2012-12-02 00:09:18 +0100289 * drm_mode_object_put - free a modeset identifer
Dave Airlief453ba02008-11-07 14:05:41 -0800290 * @dev: DRM device
Daniel Vetter065a50ed2012-12-02 00:09:18 +0100291 * @object: object to free
Dave Airlief453ba02008-11-07 14:05:41 -0800292 *
Dave Airlief453ba02008-11-07 14:05:41 -0800293 * Free @id from @dev's unique identifier pool.
294 */
295static void drm_mode_object_put(struct drm_device *dev,
296 struct drm_mode_object *object)
297{
Jesse Barnesad2563c2009-01-19 17:21:45 +1000298 mutex_lock(&dev->mode_config.idr_mutex);
Dave Airlief453ba02008-11-07 14:05:41 -0800299 idr_remove(&dev->mode_config.crtc_idr, object->id);
Jesse Barnesad2563c2009-01-19 17:21:45 +1000300 mutex_unlock(&dev->mode_config.idr_mutex);
Dave Airlief453ba02008-11-07 14:05:41 -0800301}
302
Daniel Vetter786b99e2012-12-02 21:53:40 +0100303/**
304 * drm_mode_object_find - look up a drm object with static lifetime
305 * @dev: drm device
306 * @id: id of the mode object
307 * @type: type of the mode object
308 *
309 * Note that framebuffers cannot be looked up with this functions - since those
310 * are reference counted, they need special treatment.
311 */
Daniel Vetter7a9c9062009-09-15 22:57:31 +0200312struct drm_mode_object *drm_mode_object_find(struct drm_device *dev,
313 uint32_t id, uint32_t type)
Dave Airlief453ba02008-11-07 14:05:41 -0800314{
Jesse Barnesad2563c2009-01-19 17:21:45 +1000315 struct drm_mode_object *obj = NULL;
Dave Airlief453ba02008-11-07 14:05:41 -0800316
Daniel Vetter786b99e2012-12-02 21:53:40 +0100317 /* Framebuffers are reference counted and need their own lookup
318 * function.*/
319 WARN_ON(type == DRM_MODE_OBJECT_FB);
320
Jesse Barnesad2563c2009-01-19 17:21:45 +1000321 mutex_lock(&dev->mode_config.idr_mutex);
Dave Airlief453ba02008-11-07 14:05:41 -0800322 obj = idr_find(&dev->mode_config.crtc_idr, id);
323 if (!obj || (obj->type != type) || (obj->id != id))
Jesse Barnesad2563c2009-01-19 17:21:45 +1000324 obj = NULL;
325 mutex_unlock(&dev->mode_config.idr_mutex);
Dave Airlief453ba02008-11-07 14:05:41 -0800326
327 return obj;
328}
329EXPORT_SYMBOL(drm_mode_object_find);
330
331/**
Dave Airlief453ba02008-11-07 14:05:41 -0800332 * drm_framebuffer_init - initialize a framebuffer
333 * @dev: DRM device
Daniel Vetter065a50ed2012-12-02 00:09:18 +0100334 * @fb: framebuffer to be initialized
335 * @funcs: ... with these functions
Dave Airlief453ba02008-11-07 14:05:41 -0800336 *
Dave Airlief453ba02008-11-07 14:05:41 -0800337 * Allocates an ID for the framebuffer's parent mode object, sets its mode
338 * functions & device file and adds it to the master fd list.
339 *
Daniel Vetter4b096ac2012-12-10 21:19:18 +0100340 * IMPORTANT:
341 * This functions publishes the fb and makes it available for concurrent access
342 * by other users. Which means by this point the fb _must_ be fully set up -
343 * since all the fb attributes are invariant over its lifetime, no further
344 * locking but only correct reference counting is required.
345 *
Dave Airlief453ba02008-11-07 14:05:41 -0800346 * RETURNS:
André Goddard Rosaaf901ca2009-11-14 13:09:05 -0200347 * Zero on success, error code on failure.
Dave Airlief453ba02008-11-07 14:05:41 -0800348 */
349int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb,
350 const struct drm_framebuffer_funcs *funcs)
351{
352 int ret;
353
Daniel Vetter4b096ac2012-12-10 21:19:18 +0100354 mutex_lock(&dev->mode_config.fb_lock);
Rob Clarkf7eff602012-09-05 21:48:38 +0000355 kref_init(&fb->refcount);
Daniel Vetter4b096ac2012-12-10 21:19:18 +0100356 INIT_LIST_HEAD(&fb->filp_head);
357 fb->dev = dev;
358 fb->funcs = funcs;
Rob Clarkf7eff602012-09-05 21:48:38 +0000359
Dave Airlief453ba02008-11-07 14:05:41 -0800360 ret = drm_mode_object_get(dev, &fb->base, DRM_MODE_OBJECT_FB);
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +0200361 if (ret)
Daniel Vetter4b096ac2012-12-10 21:19:18 +0100362 goto out;
Dave Airlief453ba02008-11-07 14:05:41 -0800363
Daniel Vetter2b677e82012-12-10 21:16:05 +0100364 /* Grab the idr reference. */
365 drm_framebuffer_reference(fb);
366
Dave Airlief453ba02008-11-07 14:05:41 -0800367 dev->mode_config.num_fb++;
368 list_add(&fb->head, &dev->mode_config.fb_list);
Daniel Vetter4b096ac2012-12-10 21:19:18 +0100369out:
370 mutex_unlock(&dev->mode_config.fb_lock);
Dave Airlief453ba02008-11-07 14:05:41 -0800371
372 return 0;
373}
374EXPORT_SYMBOL(drm_framebuffer_init);
375
Rob Clarkf7eff602012-09-05 21:48:38 +0000376static void drm_framebuffer_free(struct kref *kref)
377{
378 struct drm_framebuffer *fb =
379 container_of(kref, struct drm_framebuffer, refcount);
380 fb->funcs->destroy(fb);
381}
382
Daniel Vetter2b677e82012-12-10 21:16:05 +0100383static struct drm_framebuffer *__drm_framebuffer_lookup(struct drm_device *dev,
384 uint32_t id)
385{
386 struct drm_mode_object *obj = NULL;
387 struct drm_framebuffer *fb;
388
389 mutex_lock(&dev->mode_config.idr_mutex);
390 obj = idr_find(&dev->mode_config.crtc_idr, id);
391 if (!obj || (obj->type != DRM_MODE_OBJECT_FB) || (obj->id != id))
392 fb = NULL;
393 else
394 fb = obj_to_fb(obj);
395 mutex_unlock(&dev->mode_config.idr_mutex);
396
397 return fb;
398}
399
Rob Clarkf7eff602012-09-05 21:48:38 +0000400/**
Daniel Vetter786b99e2012-12-02 21:53:40 +0100401 * drm_framebuffer_lookup - look up a drm framebuffer and grab a reference
402 * @dev: drm device
403 * @id: id of the fb object
404 *
405 * If successful, this grabs an additional reference to the framebuffer -
406 * callers need to make sure to eventually unreference the returned framebuffer
407 * again.
408 */
409struct drm_framebuffer *drm_framebuffer_lookup(struct drm_device *dev,
410 uint32_t id)
411{
Daniel Vetter786b99e2012-12-02 21:53:40 +0100412 struct drm_framebuffer *fb;
413
414 mutex_lock(&dev->mode_config.fb_lock);
Daniel Vetter2b677e82012-12-10 21:16:05 +0100415 fb = __drm_framebuffer_lookup(dev, id);
Daniel Vetter786b99e2012-12-02 21:53:40 +0100416 if (fb)
archit taneja9131d3d2013-04-10 08:59:39 +0000417 drm_framebuffer_reference(fb);
Daniel Vetter786b99e2012-12-02 21:53:40 +0100418 mutex_unlock(&dev->mode_config.fb_lock);
419
420 return fb;
421}
422EXPORT_SYMBOL(drm_framebuffer_lookup);
423
424/**
Rob Clarkf7eff602012-09-05 21:48:38 +0000425 * drm_framebuffer_unreference - unref a framebuffer
Daniel Vetter065a50ed2012-12-02 00:09:18 +0100426 * @fb: framebuffer to unref
427 *
428 * This functions decrements the fb's refcount and frees it if it drops to zero.
Rob Clarkf7eff602012-09-05 21:48:38 +0000429 */
430void drm_framebuffer_unreference(struct drm_framebuffer *fb)
431{
Rob Clarkf7eff602012-09-05 21:48:38 +0000432 DRM_DEBUG("FB ID: %d\n", fb->base.id);
Rob Clarkf7eff602012-09-05 21:48:38 +0000433 kref_put(&fb->refcount, drm_framebuffer_free);
434}
435EXPORT_SYMBOL(drm_framebuffer_unreference);
436
437/**
438 * drm_framebuffer_reference - incr the fb refcnt
Daniel Vetter065a50ed2012-12-02 00:09:18 +0100439 * @fb: framebuffer
Rob Clarkf7eff602012-09-05 21:48:38 +0000440 */
441void drm_framebuffer_reference(struct drm_framebuffer *fb)
442{
443 DRM_DEBUG("FB ID: %d\n", fb->base.id);
444 kref_get(&fb->refcount);
445}
446EXPORT_SYMBOL(drm_framebuffer_reference);
447
Daniel Vetter2b677e82012-12-10 21:16:05 +0100448static void drm_framebuffer_free_bug(struct kref *kref)
449{
450 BUG();
451}
452
Daniel Vetter6c2a7532012-12-11 00:59:24 +0100453static void __drm_framebuffer_unreference(struct drm_framebuffer *fb)
454{
455 DRM_DEBUG("FB ID: %d\n", fb->base.id);
456 kref_put(&fb->refcount, drm_framebuffer_free_bug);
457}
458
Daniel Vetter2b677e82012-12-10 21:16:05 +0100459/* dev->mode_config.fb_lock must be held! */
460static void __drm_framebuffer_unregister(struct drm_device *dev,
461 struct drm_framebuffer *fb)
462{
463 mutex_lock(&dev->mode_config.idr_mutex);
464 idr_remove(&dev->mode_config.crtc_idr, fb->base.id);
465 mutex_unlock(&dev->mode_config.idr_mutex);
466
467 fb->base.id = 0;
468
Daniel Vetter6c2a7532012-12-11 00:59:24 +0100469 __drm_framebuffer_unreference(fb);
Daniel Vetter2b677e82012-12-10 21:16:05 +0100470}
471
Dave Airlief453ba02008-11-07 14:05:41 -0800472/**
Daniel Vetter36206362012-12-10 20:42:17 +0100473 * drm_framebuffer_unregister_private - unregister a private fb from the lookup idr
474 * @fb: fb to unregister
475 *
476 * Drivers need to call this when cleaning up driver-private framebuffers, e.g.
477 * those used for fbdev. Note that the caller must hold a reference of it's own,
478 * i.e. the object may not be destroyed through this call (since it'll lead to a
479 * locking inversion).
480 */
481void drm_framebuffer_unregister_private(struct drm_framebuffer *fb)
482{
Daniel Vetter2b677e82012-12-10 21:16:05 +0100483 struct drm_device *dev = fb->dev;
484
485 mutex_lock(&dev->mode_config.fb_lock);
486 /* Mark fb as reaped and drop idr ref. */
487 __drm_framebuffer_unregister(dev, fb);
488 mutex_unlock(&dev->mode_config.fb_lock);
Daniel Vetter36206362012-12-10 20:42:17 +0100489}
490EXPORT_SYMBOL(drm_framebuffer_unregister_private);
491
492/**
Dave Airlief453ba02008-11-07 14:05:41 -0800493 * drm_framebuffer_cleanup - remove a framebuffer object
494 * @fb: framebuffer to remove
495 *
Daniel Vetter36206362012-12-10 20:42:17 +0100496 * Cleanup references to a user-created framebuffer. This function is intended
497 * to be used from the drivers ->destroy callback.
498 *
499 * Note that this function does not remove the fb from active usuage - if it is
500 * still used anywhere, hilarity can ensue since userspace could call getfb on
501 * the id and get back -EINVAL. Obviously no concern at driver unload time.
502 *
503 * Also, the framebuffer will not be removed from the lookup idr - for
504 * user-created framebuffers this will happen in in the rmfb ioctl. For
505 * driver-private objects (e.g. for fbdev) drivers need to explicitly call
506 * drm_framebuffer_unregister_private.
Dave Airlief453ba02008-11-07 14:05:41 -0800507 */
508void drm_framebuffer_cleanup(struct drm_framebuffer *fb)
509{
510 struct drm_device *dev = fb->dev;
Daniel Vetter8faf6b12012-12-01 23:43:11 +0100511
Daniel Vetter4b096ac2012-12-10 21:19:18 +0100512 mutex_lock(&dev->mode_config.fb_lock);
Rob Clarkf7eff602012-09-05 21:48:38 +0000513 list_del(&fb->head);
514 dev->mode_config.num_fb--;
Daniel Vetter4b096ac2012-12-10 21:19:18 +0100515 mutex_unlock(&dev->mode_config.fb_lock);
Rob Clarkf7eff602012-09-05 21:48:38 +0000516}
517EXPORT_SYMBOL(drm_framebuffer_cleanup);
518
519/**
520 * drm_framebuffer_remove - remove and unreference a framebuffer object
521 * @fb: framebuffer to remove
522 *
Rob Clarkf7eff602012-09-05 21:48:38 +0000523 * Scans all the CRTCs and planes in @dev's mode_config. If they're
Daniel Vetter36206362012-12-10 20:42:17 +0100524 * using @fb, removes it, setting it to NULL. Then drops the reference to the
Daniel Vetterb62584e2012-12-11 16:51:35 +0100525 * passed-in framebuffer. Might take the modeset locks.
526 *
527 * Note that this function optimizes the cleanup away if the caller holds the
528 * last reference to the framebuffer. It is also guaranteed to not take the
529 * modeset locks in this case.
Rob Clarkf7eff602012-09-05 21:48:38 +0000530 */
531void drm_framebuffer_remove(struct drm_framebuffer *fb)
532{
533 struct drm_device *dev = fb->dev;
Dave Airlief453ba02008-11-07 14:05:41 -0800534 struct drm_crtc *crtc;
Jesse Barnes8cf5c912011-11-14 14:51:27 -0800535 struct drm_plane *plane;
Dave Airlie5ef5f722009-08-17 13:11:23 +1000536 struct drm_mode_set set;
537 int ret;
Dave Airlief453ba02008-11-07 14:05:41 -0800538
Daniel Vetter4b096ac2012-12-10 21:19:18 +0100539 WARN_ON(!list_empty(&fb->filp_head));
Daniel Vetter8faf6b12012-12-01 23:43:11 +0100540
Daniel Vetterb62584e2012-12-11 16:51:35 +0100541 /*
542 * drm ABI mandates that we remove any deleted framebuffers from active
543 * useage. But since most sane clients only remove framebuffers they no
544 * longer need, try to optimize this away.
545 *
546 * Since we're holding a reference ourselves, observing a refcount of 1
547 * means that we're the last holder and can skip it. Also, the refcount
548 * can never increase from 1 again, so we don't need any barriers or
549 * locks.
550 *
551 * Note that userspace could try to race with use and instate a new
552 * usage _after_ we've cleared all current ones. End result will be an
553 * in-use fb with fb-id == 0. Userspace is allowed to shoot its own foot
554 * in this manner.
555 */
556 if (atomic_read(&fb->refcount.refcount) > 1) {
557 drm_modeset_lock_all(dev);
558 /* remove from any CRTC */
559 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
560 if (crtc->fb == fb) {
561 /* should turn off the crtc */
562 memset(&set, 0, sizeof(struct drm_mode_set));
563 set.crtc = crtc;
564 set.fb = NULL;
565 ret = drm_mode_set_config_internal(&set);
566 if (ret)
567 DRM_ERROR("failed to reset crtc %p when fb was deleted\n", crtc);
568 }
Dave Airlie5ef5f722009-08-17 13:11:23 +1000569 }
Dave Airlief453ba02008-11-07 14:05:41 -0800570
Daniel Vetterb62584e2012-12-11 16:51:35 +0100571 list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
572 if (plane->fb == fb) {
573 /* should turn off the crtc */
574 ret = plane->funcs->disable_plane(plane);
575 if (ret)
576 DRM_ERROR("failed to disable plane with busy fb\n");
577 /* disconnect the plane from the fb and crtc: */
578 __drm_framebuffer_unreference(plane->fb);
579 plane->fb = NULL;
580 plane->crtc = NULL;
581 }
Jesse Barnes8cf5c912011-11-14 14:51:27 -0800582 }
Daniel Vetterb62584e2012-12-11 16:51:35 +0100583 drm_modeset_unlock_all(dev);
Jesse Barnes8cf5c912011-11-14 14:51:27 -0800584 }
585
Rob Clarkf7eff602012-09-05 21:48:38 +0000586 drm_framebuffer_unreference(fb);
Dave Airlief453ba02008-11-07 14:05:41 -0800587}
Rob Clarkf7eff602012-09-05 21:48:38 +0000588EXPORT_SYMBOL(drm_framebuffer_remove);
Dave Airlief453ba02008-11-07 14:05:41 -0800589
590/**
591 * drm_crtc_init - Initialise a new CRTC object
592 * @dev: DRM device
593 * @crtc: CRTC object to init
594 * @funcs: callbacks for the new CRTC
595 *
Dave Airlief453ba02008-11-07 14:05:41 -0800596 * Inits a new object created as base part of an driver crtc object.
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +0200597 *
598 * RETURNS:
599 * Zero on success, error code on failure.
Dave Airlief453ba02008-11-07 14:05:41 -0800600 */
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +0200601int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
Dave Airlief453ba02008-11-07 14:05:41 -0800602 const struct drm_crtc_funcs *funcs)
603{
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +0200604 int ret;
605
Dave Airlief453ba02008-11-07 14:05:41 -0800606 crtc->dev = dev;
607 crtc->funcs = funcs;
Rob Clark7c80e122012-09-04 16:35:56 +0000608 crtc->invert_dimensions = false;
Dave Airlief453ba02008-11-07 14:05:41 -0800609
Daniel Vetter84849902012-12-02 00:28:11 +0100610 drm_modeset_lock_all(dev);
Daniel Vetter29494c12012-12-02 02:18:25 +0100611 mutex_init(&crtc->mutex);
612 mutex_lock_nest_lock(&crtc->mutex, &dev->mode_config.mutex);
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +0200613
614 ret = drm_mode_object_get(dev, &crtc->base, DRM_MODE_OBJECT_CRTC);
615 if (ret)
616 goto out;
Dave Airlief453ba02008-11-07 14:05:41 -0800617
Paulo Zanonibffd9de02012-05-15 18:09:05 -0300618 crtc->base.properties = &crtc->properties;
619
Dave Airlief453ba02008-11-07 14:05:41 -0800620 list_add_tail(&crtc->head, &dev->mode_config.crtc_list);
621 dev->mode_config.num_crtc++;
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +0200622
623 out:
Daniel Vetter84849902012-12-02 00:28:11 +0100624 drm_modeset_unlock_all(dev);
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +0200625
626 return ret;
Dave Airlief453ba02008-11-07 14:05:41 -0800627}
628EXPORT_SYMBOL(drm_crtc_init);
629
630/**
631 * drm_crtc_cleanup - Cleans up the core crtc usage.
632 * @crtc: CRTC to cleanup
633 *
Dave Airlief453ba02008-11-07 14:05:41 -0800634 * Cleanup @crtc. Removes from drm modesetting space
635 * does NOT free object, caller does that.
636 */
637void drm_crtc_cleanup(struct drm_crtc *crtc)
638{
639 struct drm_device *dev = crtc->dev;
640
Sachin Kamat9e1c1562012-11-19 09:44:56 +0000641 kfree(crtc->gamma_store);
642 crtc->gamma_store = NULL;
Dave Airlief453ba02008-11-07 14:05:41 -0800643
644 drm_mode_object_put(dev, &crtc->base);
645 list_del(&crtc->head);
646 dev->mode_config.num_crtc--;
647}
648EXPORT_SYMBOL(drm_crtc_cleanup);
649
650/**
651 * drm_mode_probed_add - add a mode to a connector's probed mode list
652 * @connector: connector the new mode
653 * @mode: mode data
654 *
Dave Airlief453ba02008-11-07 14:05:41 -0800655 * Add @mode to @connector's mode list for later use.
656 */
657void drm_mode_probed_add(struct drm_connector *connector,
658 struct drm_display_mode *mode)
659{
660 list_add(&mode->head, &connector->probed_modes);
661}
662EXPORT_SYMBOL(drm_mode_probed_add);
663
664/**
665 * drm_mode_remove - remove and free a mode
666 * @connector: connector list to modify
667 * @mode: mode to remove
668 *
Dave Airlief453ba02008-11-07 14:05:41 -0800669 * Remove @mode from @connector's mode list, then free it.
670 */
671void drm_mode_remove(struct drm_connector *connector,
672 struct drm_display_mode *mode)
673{
674 list_del(&mode->head);
Sascha Hauer554f1d72012-02-01 11:38:19 +0100675 drm_mode_destroy(connector->dev, mode);
Dave Airlief453ba02008-11-07 14:05:41 -0800676}
677EXPORT_SYMBOL(drm_mode_remove);
678
679/**
680 * drm_connector_init - Init a preallocated connector
681 * @dev: DRM device
682 * @connector: the connector to init
683 * @funcs: callbacks for this connector
Daniel Vetter065a50ed2012-12-02 00:09:18 +0100684 * @connector_type: user visible type of the connector
Dave Airlief453ba02008-11-07 14:05:41 -0800685 *
Dave Airlief453ba02008-11-07 14:05:41 -0800686 * Initialises a preallocated connector. Connectors should be
687 * subclassed as part of driver connector objects.
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +0200688 *
689 * RETURNS:
690 * Zero on success, error code on failure.
Dave Airlief453ba02008-11-07 14:05:41 -0800691 */
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +0200692int drm_connector_init(struct drm_device *dev,
693 struct drm_connector *connector,
694 const struct drm_connector_funcs *funcs,
695 int connector_type)
Dave Airlief453ba02008-11-07 14:05:41 -0800696{
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +0200697 int ret;
698
Daniel Vetter84849902012-12-02 00:28:11 +0100699 drm_modeset_lock_all(dev);
Dave Airlief453ba02008-11-07 14:05:41 -0800700
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +0200701 ret = drm_mode_object_get(dev, &connector->base, DRM_MODE_OBJECT_CONNECTOR);
702 if (ret)
703 goto out;
704
Paulo Zanoni7e3bdf42012-05-15 18:09:01 -0300705 connector->base.properties = &connector->properties;
Dave Airlief453ba02008-11-07 14:05:41 -0800706 connector->dev = dev;
707 connector->funcs = funcs;
Dave Airlief453ba02008-11-07 14:05:41 -0800708 connector->connector_type = connector_type;
709 connector->connector_type_id =
710 ++drm_connector_enum_list[connector_type].count; /* TODO */
Dave Airlief453ba02008-11-07 14:05:41 -0800711 INIT_LIST_HEAD(&connector->probed_modes);
712 INIT_LIST_HEAD(&connector->modes);
713 connector->edid_blob_ptr = NULL;
Daniel Vetter5e2cb2f2012-10-23 18:23:35 +0000714 connector->status = connector_status_unknown;
Dave Airlief453ba02008-11-07 14:05:41 -0800715
716 list_add_tail(&connector->head, &dev->mode_config.connector_list);
717 dev->mode_config.num_connector++;
718
Thomas Hellstroma7331e52011-10-22 10:36:19 +0200719 if (connector_type != DRM_MODE_CONNECTOR_VIRTUAL)
Rob Clark58495562012-10-11 20:50:56 -0500720 drm_object_attach_property(&connector->base,
Thomas Hellstroma7331e52011-10-22 10:36:19 +0200721 dev->mode_config.edid_property,
722 0);
Dave Airlief453ba02008-11-07 14:05:41 -0800723
Rob Clark58495562012-10-11 20:50:56 -0500724 drm_object_attach_property(&connector->base,
Dave Airlief453ba02008-11-07 14:05:41 -0800725 dev->mode_config.dpms_property, 0);
726
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +0200727 out:
Daniel Vetter84849902012-12-02 00:28:11 +0100728 drm_modeset_unlock_all(dev);
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +0200729
730 return ret;
Dave Airlief453ba02008-11-07 14:05:41 -0800731}
732EXPORT_SYMBOL(drm_connector_init);
733
734/**
735 * drm_connector_cleanup - cleans up an initialised connector
736 * @connector: connector to cleanup
737 *
Dave Airlief453ba02008-11-07 14:05:41 -0800738 * Cleans up the connector but doesn't free the object.
739 */
740void drm_connector_cleanup(struct drm_connector *connector)
741{
742 struct drm_device *dev = connector->dev;
743 struct drm_display_mode *mode, *t;
744
745 list_for_each_entry_safe(mode, t, &connector->probed_modes, head)
746 drm_mode_remove(connector, mode);
747
748 list_for_each_entry_safe(mode, t, &connector->modes, head)
749 drm_mode_remove(connector, mode);
750
Dave Airlief453ba02008-11-07 14:05:41 -0800751 drm_mode_object_put(dev, &connector->base);
752 list_del(&connector->head);
Joonyoung Shim6380c502011-08-27 02:06:21 +0000753 dev->mode_config.num_connector--;
Dave Airlief453ba02008-11-07 14:05:41 -0800754}
755EXPORT_SYMBOL(drm_connector_cleanup);
756
Dave Airliecbc7e222012-02-20 14:16:40 +0000757void drm_connector_unplug_all(struct drm_device *dev)
758{
759 struct drm_connector *connector;
760
761 /* taking the mode config mutex ends up in a clash with sysfs */
762 list_for_each_entry(connector, &dev->mode_config.connector_list, head)
763 drm_sysfs_connector_remove(connector);
764
765}
766EXPORT_SYMBOL(drm_connector_unplug_all);
767
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +0200768int drm_encoder_init(struct drm_device *dev,
Dave Airliecbc7e222012-02-20 14:16:40 +0000769 struct drm_encoder *encoder,
770 const struct drm_encoder_funcs *funcs,
771 int encoder_type)
Dave Airlief453ba02008-11-07 14:05:41 -0800772{
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +0200773 int ret;
774
Daniel Vetter84849902012-12-02 00:28:11 +0100775 drm_modeset_lock_all(dev);
Dave Airlief453ba02008-11-07 14:05:41 -0800776
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +0200777 ret = drm_mode_object_get(dev, &encoder->base, DRM_MODE_OBJECT_ENCODER);
778 if (ret)
779 goto out;
Dave Airlief453ba02008-11-07 14:05:41 -0800780
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +0200781 encoder->dev = dev;
Dave Airlief453ba02008-11-07 14:05:41 -0800782 encoder->encoder_type = encoder_type;
783 encoder->funcs = funcs;
784
785 list_add_tail(&encoder->head, &dev->mode_config.encoder_list);
786 dev->mode_config.num_encoder++;
787
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +0200788 out:
Daniel Vetter84849902012-12-02 00:28:11 +0100789 drm_modeset_unlock_all(dev);
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +0200790
791 return ret;
Dave Airlief453ba02008-11-07 14:05:41 -0800792}
793EXPORT_SYMBOL(drm_encoder_init);
794
795void drm_encoder_cleanup(struct drm_encoder *encoder)
796{
797 struct drm_device *dev = encoder->dev;
Daniel Vetter84849902012-12-02 00:28:11 +0100798 drm_modeset_lock_all(dev);
Dave Airlief453ba02008-11-07 14:05:41 -0800799 drm_mode_object_put(dev, &encoder->base);
800 list_del(&encoder->head);
Joonyoung Shim6380c502011-08-27 02:06:21 +0000801 dev->mode_config.num_encoder--;
Daniel Vetter84849902012-12-02 00:28:11 +0100802 drm_modeset_unlock_all(dev);
Dave Airlief453ba02008-11-07 14:05:41 -0800803}
804EXPORT_SYMBOL(drm_encoder_cleanup);
805
Jesse Barnes8cf5c912011-11-14 14:51:27 -0800806int drm_plane_init(struct drm_device *dev, struct drm_plane *plane,
807 unsigned long possible_crtcs,
808 const struct drm_plane_funcs *funcs,
Rob Clark0a7eb242011-12-13 20:19:36 -0600809 const uint32_t *formats, uint32_t format_count,
810 bool priv)
Jesse Barnes8cf5c912011-11-14 14:51:27 -0800811{
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +0200812 int ret;
813
Daniel Vetter84849902012-12-02 00:28:11 +0100814 drm_modeset_lock_all(dev);
Jesse Barnes8cf5c912011-11-14 14:51:27 -0800815
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +0200816 ret = drm_mode_object_get(dev, &plane->base, DRM_MODE_OBJECT_PLANE);
817 if (ret)
818 goto out;
819
Rob Clark4d939142012-05-17 02:23:27 -0600820 plane->base.properties = &plane->properties;
Jesse Barnes8cf5c912011-11-14 14:51:27 -0800821 plane->dev = dev;
Jesse Barnes8cf5c912011-11-14 14:51:27 -0800822 plane->funcs = funcs;
823 plane->format_types = kmalloc(sizeof(uint32_t) * format_count,
824 GFP_KERNEL);
825 if (!plane->format_types) {
826 DRM_DEBUG_KMS("out of memory when allocating plane\n");
827 drm_mode_object_put(dev, &plane->base);
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +0200828 ret = -ENOMEM;
829 goto out;
Jesse Barnes8cf5c912011-11-14 14:51:27 -0800830 }
831
Jesse Barnes308e5bc2011-11-14 14:51:28 -0800832 memcpy(plane->format_types, formats, format_count * sizeof(uint32_t));
Jesse Barnes8cf5c912011-11-14 14:51:27 -0800833 plane->format_count = format_count;
834 plane->possible_crtcs = possible_crtcs;
835
Rob Clark0a7eb242011-12-13 20:19:36 -0600836 /* private planes are not exposed to userspace, but depending on
837 * display hardware, might be convenient to allow sharing programming
838 * for the scanout engine with the crtc implementation.
839 */
840 if (!priv) {
841 list_add_tail(&plane->head, &dev->mode_config.plane_list);
842 dev->mode_config.num_plane++;
843 } else {
844 INIT_LIST_HEAD(&plane->head);
845 }
Jesse Barnes8cf5c912011-11-14 14:51:27 -0800846
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +0200847 out:
Daniel Vetter84849902012-12-02 00:28:11 +0100848 drm_modeset_unlock_all(dev);
Jesse Barnes8cf5c912011-11-14 14:51:27 -0800849
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +0200850 return ret;
Jesse Barnes8cf5c912011-11-14 14:51:27 -0800851}
852EXPORT_SYMBOL(drm_plane_init);
853
854void drm_plane_cleanup(struct drm_plane *plane)
855{
856 struct drm_device *dev = plane->dev;
857
Daniel Vetter84849902012-12-02 00:28:11 +0100858 drm_modeset_lock_all(dev);
Jesse Barnes8cf5c912011-11-14 14:51:27 -0800859 kfree(plane->format_types);
860 drm_mode_object_put(dev, &plane->base);
Rob Clark0a7eb242011-12-13 20:19:36 -0600861 /* if not added to a list, it must be a private plane */
862 if (!list_empty(&plane->head)) {
863 list_del(&plane->head);
864 dev->mode_config.num_plane--;
865 }
Daniel Vetter84849902012-12-02 00:28:11 +0100866 drm_modeset_unlock_all(dev);
Jesse Barnes8cf5c912011-11-14 14:51:27 -0800867}
868EXPORT_SYMBOL(drm_plane_cleanup);
869
Dave Airlief453ba02008-11-07 14:05:41 -0800870/**
871 * drm_mode_create - create a new display mode
872 * @dev: DRM device
873 *
Dave Airlief453ba02008-11-07 14:05:41 -0800874 * Create a new drm_display_mode, give it an ID, and return it.
875 *
876 * RETURNS:
877 * Pointer to new mode on success, NULL on error.
878 */
879struct drm_display_mode *drm_mode_create(struct drm_device *dev)
880{
881 struct drm_display_mode *nmode;
882
883 nmode = kzalloc(sizeof(struct drm_display_mode), GFP_KERNEL);
884 if (!nmode)
885 return NULL;
886
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +0200887 if (drm_mode_object_get(dev, &nmode->base, DRM_MODE_OBJECT_MODE)) {
888 kfree(nmode);
889 return NULL;
890 }
891
Dave Airlief453ba02008-11-07 14:05:41 -0800892 return nmode;
893}
894EXPORT_SYMBOL(drm_mode_create);
895
896/**
897 * drm_mode_destroy - remove a mode
898 * @dev: DRM device
899 * @mode: mode to remove
900 *
Dave Airlief453ba02008-11-07 14:05:41 -0800901 * Free @mode's unique identifier, then free it.
902 */
903void drm_mode_destroy(struct drm_device *dev, struct drm_display_mode *mode)
904{
Ville Syrjäläee34ab52012-03-13 12:35:43 +0200905 if (!mode)
906 return;
907
Dave Airlief453ba02008-11-07 14:05:41 -0800908 drm_mode_object_put(dev, &mode->base);
909
910 kfree(mode);
911}
912EXPORT_SYMBOL(drm_mode_destroy);
913
914static int drm_mode_create_standard_connector_properties(struct drm_device *dev)
915{
916 struct drm_property *edid;
917 struct drm_property *dpms;
Dave Airlief453ba02008-11-07 14:05:41 -0800918
919 /*
920 * Standard properties (apply to all connectors)
921 */
922 edid = drm_property_create(dev, DRM_MODE_PROP_BLOB |
923 DRM_MODE_PROP_IMMUTABLE,
924 "EDID", 0);
925 dev->mode_config.edid_property = edid;
926
Sascha Hauer4a67d392012-02-06 10:58:17 +0100927 dpms = drm_property_create_enum(dev, 0,
928 "DPMS", drm_dpms_enum_list,
929 ARRAY_SIZE(drm_dpms_enum_list));
Dave Airlief453ba02008-11-07 14:05:41 -0800930 dev->mode_config.dpms_property = dpms;
931
932 return 0;
933}
934
935/**
936 * drm_mode_create_dvi_i_properties - create DVI-I specific connector properties
937 * @dev: DRM device
938 *
939 * Called by a driver the first time a DVI-I connector is made.
940 */
941int drm_mode_create_dvi_i_properties(struct drm_device *dev)
942{
943 struct drm_property *dvi_i_selector;
944 struct drm_property *dvi_i_subconnector;
Dave Airlief453ba02008-11-07 14:05:41 -0800945
946 if (dev->mode_config.dvi_i_select_subconnector_property)
947 return 0;
948
949 dvi_i_selector =
Sascha Hauer4a67d392012-02-06 10:58:17 +0100950 drm_property_create_enum(dev, 0,
Dave Airlief453ba02008-11-07 14:05:41 -0800951 "select subconnector",
Sascha Hauer4a67d392012-02-06 10:58:17 +0100952 drm_dvi_i_select_enum_list,
Dave Airlief453ba02008-11-07 14:05:41 -0800953 ARRAY_SIZE(drm_dvi_i_select_enum_list));
Dave Airlief453ba02008-11-07 14:05:41 -0800954 dev->mode_config.dvi_i_select_subconnector_property = dvi_i_selector;
955
Sascha Hauer4a67d392012-02-06 10:58:17 +0100956 dvi_i_subconnector = drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE,
Dave Airlief453ba02008-11-07 14:05:41 -0800957 "subconnector",
Sascha Hauer4a67d392012-02-06 10:58:17 +0100958 drm_dvi_i_subconnector_enum_list,
Dave Airlief453ba02008-11-07 14:05:41 -0800959 ARRAY_SIZE(drm_dvi_i_subconnector_enum_list));
Dave Airlief453ba02008-11-07 14:05:41 -0800960 dev->mode_config.dvi_i_subconnector_property = dvi_i_subconnector;
961
962 return 0;
963}
964EXPORT_SYMBOL(drm_mode_create_dvi_i_properties);
965
966/**
967 * drm_create_tv_properties - create TV specific connector properties
968 * @dev: DRM device
969 * @num_modes: number of different TV formats (modes) supported
970 * @modes: array of pointers to strings containing name of each format
971 *
972 * Called by a driver's TV initialization routine, this function creates
973 * the TV specific connector properties for a given device. Caller is
974 * responsible for allocating a list of format names and passing them to
975 * this routine.
976 */
977int drm_mode_create_tv_properties(struct drm_device *dev, int num_modes,
978 char *modes[])
979{
980 struct drm_property *tv_selector;
981 struct drm_property *tv_subconnector;
982 int i;
983
984 if (dev->mode_config.tv_select_subconnector_property)
985 return 0;
986
987 /*
988 * Basic connector properties
989 */
Sascha Hauer4a67d392012-02-06 10:58:17 +0100990 tv_selector = drm_property_create_enum(dev, 0,
Dave Airlief453ba02008-11-07 14:05:41 -0800991 "select subconnector",
Sascha Hauer4a67d392012-02-06 10:58:17 +0100992 drm_tv_select_enum_list,
Dave Airlief453ba02008-11-07 14:05:41 -0800993 ARRAY_SIZE(drm_tv_select_enum_list));
Dave Airlief453ba02008-11-07 14:05:41 -0800994 dev->mode_config.tv_select_subconnector_property = tv_selector;
995
996 tv_subconnector =
Sascha Hauer4a67d392012-02-06 10:58:17 +0100997 drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE,
998 "subconnector",
999 drm_tv_subconnector_enum_list,
Dave Airlief453ba02008-11-07 14:05:41 -08001000 ARRAY_SIZE(drm_tv_subconnector_enum_list));
Dave Airlief453ba02008-11-07 14:05:41 -08001001 dev->mode_config.tv_subconnector_property = tv_subconnector;
1002
1003 /*
1004 * Other, TV specific properties: margins & TV modes.
1005 */
1006 dev->mode_config.tv_left_margin_property =
Sascha Hauerd9bc3c02012-02-06 10:58:18 +01001007 drm_property_create_range(dev, 0, "left margin", 0, 100);
Dave Airlief453ba02008-11-07 14:05:41 -08001008
1009 dev->mode_config.tv_right_margin_property =
Sascha Hauerd9bc3c02012-02-06 10:58:18 +01001010 drm_property_create_range(dev, 0, "right margin", 0, 100);
Dave Airlief453ba02008-11-07 14:05:41 -08001011
1012 dev->mode_config.tv_top_margin_property =
Sascha Hauerd9bc3c02012-02-06 10:58:18 +01001013 drm_property_create_range(dev, 0, "top margin", 0, 100);
Dave Airlief453ba02008-11-07 14:05:41 -08001014
1015 dev->mode_config.tv_bottom_margin_property =
Sascha Hauerd9bc3c02012-02-06 10:58:18 +01001016 drm_property_create_range(dev, 0, "bottom margin", 0, 100);
Dave Airlief453ba02008-11-07 14:05:41 -08001017
1018 dev->mode_config.tv_mode_property =
1019 drm_property_create(dev, DRM_MODE_PROP_ENUM,
1020 "mode", num_modes);
1021 for (i = 0; i < num_modes; i++)
1022 drm_property_add_enum(dev->mode_config.tv_mode_property, i,
1023 i, modes[i]);
1024
Francisco Jerezb6b79022009-08-02 04:19:20 +02001025 dev->mode_config.tv_brightness_property =
Sascha Hauerd9bc3c02012-02-06 10:58:18 +01001026 drm_property_create_range(dev, 0, "brightness", 0, 100);
Francisco Jerezb6b79022009-08-02 04:19:20 +02001027
1028 dev->mode_config.tv_contrast_property =
Sascha Hauerd9bc3c02012-02-06 10:58:18 +01001029 drm_property_create_range(dev, 0, "contrast", 0, 100);
Francisco Jerezb6b79022009-08-02 04:19:20 +02001030
1031 dev->mode_config.tv_flicker_reduction_property =
Sascha Hauerd9bc3c02012-02-06 10:58:18 +01001032 drm_property_create_range(dev, 0, "flicker reduction", 0, 100);
Francisco Jerezb6b79022009-08-02 04:19:20 +02001033
Francisco Jereza75f0232009-08-12 02:30:10 +02001034 dev->mode_config.tv_overscan_property =
Sascha Hauerd9bc3c02012-02-06 10:58:18 +01001035 drm_property_create_range(dev, 0, "overscan", 0, 100);
Francisco Jereza75f0232009-08-12 02:30:10 +02001036
1037 dev->mode_config.tv_saturation_property =
Sascha Hauerd9bc3c02012-02-06 10:58:18 +01001038 drm_property_create_range(dev, 0, "saturation", 0, 100);
Francisco Jereza75f0232009-08-12 02:30:10 +02001039
1040 dev->mode_config.tv_hue_property =
Sascha Hauerd9bc3c02012-02-06 10:58:18 +01001041 drm_property_create_range(dev, 0, "hue", 0, 100);
Francisco Jereza75f0232009-08-12 02:30:10 +02001042
Dave Airlief453ba02008-11-07 14:05:41 -08001043 return 0;
1044}
1045EXPORT_SYMBOL(drm_mode_create_tv_properties);
1046
1047/**
1048 * drm_mode_create_scaling_mode_property - create scaling mode property
1049 * @dev: DRM device
1050 *
1051 * Called by a driver the first time it's needed, must be attached to desired
1052 * connectors.
1053 */
1054int drm_mode_create_scaling_mode_property(struct drm_device *dev)
1055{
1056 struct drm_property *scaling_mode;
Dave Airlief453ba02008-11-07 14:05:41 -08001057
1058 if (dev->mode_config.scaling_mode_property)
1059 return 0;
1060
1061 scaling_mode =
Sascha Hauer4a67d392012-02-06 10:58:17 +01001062 drm_property_create_enum(dev, 0, "scaling mode",
1063 drm_scaling_mode_enum_list,
Dave Airlief453ba02008-11-07 14:05:41 -08001064 ARRAY_SIZE(drm_scaling_mode_enum_list));
Dave Airlief453ba02008-11-07 14:05:41 -08001065
1066 dev->mode_config.scaling_mode_property = scaling_mode;
1067
1068 return 0;
1069}
1070EXPORT_SYMBOL(drm_mode_create_scaling_mode_property);
1071
1072/**
1073 * drm_mode_create_dithering_property - create dithering property
1074 * @dev: DRM device
1075 *
1076 * Called by a driver the first time it's needed, must be attached to desired
1077 * connectors.
1078 */
1079int drm_mode_create_dithering_property(struct drm_device *dev)
1080{
1081 struct drm_property *dithering_mode;
Dave Airlief453ba02008-11-07 14:05:41 -08001082
1083 if (dev->mode_config.dithering_mode_property)
1084 return 0;
1085
1086 dithering_mode =
Sascha Hauer4a67d392012-02-06 10:58:17 +01001087 drm_property_create_enum(dev, 0, "dithering",
1088 drm_dithering_mode_enum_list,
Dave Airlief453ba02008-11-07 14:05:41 -08001089 ARRAY_SIZE(drm_dithering_mode_enum_list));
Dave Airlief453ba02008-11-07 14:05:41 -08001090 dev->mode_config.dithering_mode_property = dithering_mode;
1091
1092 return 0;
1093}
1094EXPORT_SYMBOL(drm_mode_create_dithering_property);
1095
1096/**
Jakob Bornecrantz884840a2009-12-03 23:25:47 +00001097 * drm_mode_create_dirty_property - create dirty property
1098 * @dev: DRM device
1099 *
1100 * Called by a driver the first time it's needed, must be attached to desired
1101 * connectors.
1102 */
1103int drm_mode_create_dirty_info_property(struct drm_device *dev)
1104{
1105 struct drm_property *dirty_info;
Jakob Bornecrantz884840a2009-12-03 23:25:47 +00001106
1107 if (dev->mode_config.dirty_info_property)
1108 return 0;
1109
1110 dirty_info =
Sascha Hauer4a67d392012-02-06 10:58:17 +01001111 drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE,
Jakob Bornecrantz884840a2009-12-03 23:25:47 +00001112 "dirty",
Sascha Hauer4a67d392012-02-06 10:58:17 +01001113 drm_dirty_info_enum_list,
Jakob Bornecrantz884840a2009-12-03 23:25:47 +00001114 ARRAY_SIZE(drm_dirty_info_enum_list));
Jakob Bornecrantz884840a2009-12-03 23:25:47 +00001115 dev->mode_config.dirty_info_property = dirty_info;
1116
1117 return 0;
1118}
1119EXPORT_SYMBOL(drm_mode_create_dirty_info_property);
1120
Ville Syrjäläea9cbb02013-04-25 20:09:20 +03001121static int drm_mode_group_init(struct drm_device *dev, struct drm_mode_group *group)
Dave Airlief453ba02008-11-07 14:05:41 -08001122{
1123 uint32_t total_objects = 0;
1124
1125 total_objects += dev->mode_config.num_crtc;
1126 total_objects += dev->mode_config.num_connector;
1127 total_objects += dev->mode_config.num_encoder;
1128
Dave Airlief453ba02008-11-07 14:05:41 -08001129 group->id_list = kzalloc(total_objects * sizeof(uint32_t), GFP_KERNEL);
1130 if (!group->id_list)
1131 return -ENOMEM;
1132
1133 group->num_crtcs = 0;
1134 group->num_connectors = 0;
1135 group->num_encoders = 0;
1136 return 0;
1137}
1138
1139int drm_mode_group_init_legacy_group(struct drm_device *dev,
1140 struct drm_mode_group *group)
1141{
1142 struct drm_crtc *crtc;
1143 struct drm_encoder *encoder;
1144 struct drm_connector *connector;
1145 int ret;
1146
1147 if ((ret = drm_mode_group_init(dev, group)))
1148 return ret;
1149
1150 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
1151 group->id_list[group->num_crtcs++] = crtc->base.id;
1152
1153 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head)
1154 group->id_list[group->num_crtcs + group->num_encoders++] =
1155 encoder->base.id;
1156
1157 list_for_each_entry(connector, &dev->mode_config.connector_list, head)
1158 group->id_list[group->num_crtcs + group->num_encoders +
1159 group->num_connectors++] = connector->base.id;
1160
1161 return 0;
1162}
Dave Airlie9c1dfc52012-03-20 06:59:29 +00001163EXPORT_SYMBOL(drm_mode_group_init_legacy_group);
Dave Airlief453ba02008-11-07 14:05:41 -08001164
1165/**
Dave Airlief453ba02008-11-07 14:05:41 -08001166 * drm_crtc_convert_to_umode - convert a drm_display_mode into a modeinfo
1167 * @out: drm_mode_modeinfo struct to return to the user
1168 * @in: drm_display_mode to use
1169 *
Dave Airlief453ba02008-11-07 14:05:41 -08001170 * Convert a drm_display_mode into a drm_mode_modeinfo structure to return to
1171 * the user.
1172 */
Ville Syrjälä93bbf6d2012-03-13 12:35:47 +02001173static void drm_crtc_convert_to_umode(struct drm_mode_modeinfo *out,
1174 const struct drm_display_mode *in)
Dave Airlief453ba02008-11-07 14:05:41 -08001175{
Ville Syrjäläe36fae32012-03-13 12:35:40 +02001176 WARN(in->hdisplay > USHRT_MAX || in->hsync_start > USHRT_MAX ||
1177 in->hsync_end > USHRT_MAX || in->htotal > USHRT_MAX ||
1178 in->hskew > USHRT_MAX || in->vdisplay > USHRT_MAX ||
1179 in->vsync_start > USHRT_MAX || in->vsync_end > USHRT_MAX ||
1180 in->vtotal > USHRT_MAX || in->vscan > USHRT_MAX,
1181 "timing values too large for mode info\n");
1182
Dave Airlief453ba02008-11-07 14:05:41 -08001183 out->clock = in->clock;
1184 out->hdisplay = in->hdisplay;
1185 out->hsync_start = in->hsync_start;
1186 out->hsync_end = in->hsync_end;
1187 out->htotal = in->htotal;
1188 out->hskew = in->hskew;
1189 out->vdisplay = in->vdisplay;
1190 out->vsync_start = in->vsync_start;
1191 out->vsync_end = in->vsync_end;
1192 out->vtotal = in->vtotal;
1193 out->vscan = in->vscan;
1194 out->vrefresh = in->vrefresh;
1195 out->flags = in->flags;
1196 out->type = in->type;
1197 strncpy(out->name, in->name, DRM_DISPLAY_MODE_LEN);
1198 out->name[DRM_DISPLAY_MODE_LEN-1] = 0;
1199}
1200
1201/**
1202 * drm_crtc_convert_to_umode - convert a modeinfo into a drm_display_mode
1203 * @out: drm_display_mode to return to the user
1204 * @in: drm_mode_modeinfo to use
1205 *
Dave Airlief453ba02008-11-07 14:05:41 -08001206 * Convert a drm_mode_modeinfo into a drm_display_mode structure to return to
1207 * the caller.
Ville Syrjälä90367bf2012-03-13 12:35:44 +02001208 *
1209 * RETURNS:
1210 * Zero on success, errno on failure.
Dave Airlief453ba02008-11-07 14:05:41 -08001211 */
Ville Syrjälä93bbf6d2012-03-13 12:35:47 +02001212static int drm_crtc_convert_umode(struct drm_display_mode *out,
1213 const struct drm_mode_modeinfo *in)
Dave Airlief453ba02008-11-07 14:05:41 -08001214{
Ville Syrjälä90367bf2012-03-13 12:35:44 +02001215 if (in->clock > INT_MAX || in->vrefresh > INT_MAX)
1216 return -ERANGE;
1217
Dave Airlief453ba02008-11-07 14:05:41 -08001218 out->clock = in->clock;
1219 out->hdisplay = in->hdisplay;
1220 out->hsync_start = in->hsync_start;
1221 out->hsync_end = in->hsync_end;
1222 out->htotal = in->htotal;
1223 out->hskew = in->hskew;
1224 out->vdisplay = in->vdisplay;
1225 out->vsync_start = in->vsync_start;
1226 out->vsync_end = in->vsync_end;
1227 out->vtotal = in->vtotal;
1228 out->vscan = in->vscan;
1229 out->vrefresh = in->vrefresh;
1230 out->flags = in->flags;
1231 out->type = in->type;
1232 strncpy(out->name, in->name, DRM_DISPLAY_MODE_LEN);
1233 out->name[DRM_DISPLAY_MODE_LEN-1] = 0;
Ville Syrjälä90367bf2012-03-13 12:35:44 +02001234
1235 return 0;
Dave Airlief453ba02008-11-07 14:05:41 -08001236}
1237
1238/**
1239 * drm_mode_getresources - get graphics configuration
Daniel Vetter065a50ed2012-12-02 00:09:18 +01001240 * @dev: drm device for the ioctl
1241 * @data: data pointer for the ioctl
1242 * @file_priv: drm file for the ioctl call
Dave Airlief453ba02008-11-07 14:05:41 -08001243 *
Dave Airlief453ba02008-11-07 14:05:41 -08001244 * Construct a set of configuration description structures and return
1245 * them to the user, including CRTC, connector and framebuffer configuration.
1246 *
1247 * Called by the user via ioctl.
1248 *
1249 * RETURNS:
1250 * Zero on success, errno on failure.
1251 */
1252int drm_mode_getresources(struct drm_device *dev, void *data,
1253 struct drm_file *file_priv)
1254{
1255 struct drm_mode_card_res *card_res = data;
1256 struct list_head *lh;
1257 struct drm_framebuffer *fb;
1258 struct drm_connector *connector;
1259 struct drm_crtc *crtc;
1260 struct drm_encoder *encoder;
1261 int ret = 0;
1262 int connector_count = 0;
1263 int crtc_count = 0;
1264 int fb_count = 0;
1265 int encoder_count = 0;
1266 int copied = 0, i;
1267 uint32_t __user *fb_id;
1268 uint32_t __user *crtc_id;
1269 uint32_t __user *connector_id;
1270 uint32_t __user *encoder_id;
1271 struct drm_mode_group *mode_group;
1272
Dave Airliefb3b06c2011-02-08 13:55:21 +10001273 if (!drm_core_check_feature(dev, DRIVER_MODESET))
1274 return -EINVAL;
1275
Dave Airlief453ba02008-11-07 14:05:41 -08001276
Daniel Vetter4b096ac2012-12-10 21:19:18 +01001277 mutex_lock(&file_priv->fbs_lock);
Dave Airlief453ba02008-11-07 14:05:41 -08001278 /*
1279 * For the non-control nodes we need to limit the list of resources
1280 * by IDs in the group list for this node
1281 */
1282 list_for_each(lh, &file_priv->fbs)
1283 fb_count++;
1284
Daniel Vetter4b096ac2012-12-10 21:19:18 +01001285 /* handle this in 4 parts */
1286 /* FBs */
1287 if (card_res->count_fbs >= fb_count) {
1288 copied = 0;
1289 fb_id = (uint32_t __user *)(unsigned long)card_res->fb_id_ptr;
1290 list_for_each_entry(fb, &file_priv->fbs, filp_head) {
1291 if (put_user(fb->base.id, fb_id + copied)) {
1292 mutex_unlock(&file_priv->fbs_lock);
1293 return -EFAULT;
1294 }
1295 copied++;
1296 }
1297 }
1298 card_res->count_fbs = fb_count;
1299 mutex_unlock(&file_priv->fbs_lock);
1300
1301 drm_modeset_lock_all(dev);
Dave Airlief453ba02008-11-07 14:05:41 -08001302 mode_group = &file_priv->master->minor->mode_group;
1303 if (file_priv->master->minor->type == DRM_MINOR_CONTROL) {
1304
1305 list_for_each(lh, &dev->mode_config.crtc_list)
1306 crtc_count++;
1307
1308 list_for_each(lh, &dev->mode_config.connector_list)
1309 connector_count++;
1310
1311 list_for_each(lh, &dev->mode_config.encoder_list)
1312 encoder_count++;
1313 } else {
1314
1315 crtc_count = mode_group->num_crtcs;
1316 connector_count = mode_group->num_connectors;
1317 encoder_count = mode_group->num_encoders;
1318 }
1319
1320 card_res->max_height = dev->mode_config.max_height;
1321 card_res->min_height = dev->mode_config.min_height;
1322 card_res->max_width = dev->mode_config.max_width;
1323 card_res->min_width = dev->mode_config.min_width;
1324
Dave Airlief453ba02008-11-07 14:05:41 -08001325 /* CRTCs */
1326 if (card_res->count_crtcs >= crtc_count) {
1327 copied = 0;
1328 crtc_id = (uint32_t __user *)(unsigned long)card_res->crtc_id_ptr;
1329 if (file_priv->master->minor->type == DRM_MINOR_CONTROL) {
1330 list_for_each_entry(crtc, &dev->mode_config.crtc_list,
1331 head) {
Jerome Glisse94401062010-07-15 15:43:25 -04001332 DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id);
Dave Airlief453ba02008-11-07 14:05:41 -08001333 if (put_user(crtc->base.id, crtc_id + copied)) {
1334 ret = -EFAULT;
1335 goto out;
1336 }
1337 copied++;
1338 }
1339 } else {
1340 for (i = 0; i < mode_group->num_crtcs; i++) {
1341 if (put_user(mode_group->id_list[i],
1342 crtc_id + copied)) {
1343 ret = -EFAULT;
1344 goto out;
1345 }
1346 copied++;
1347 }
1348 }
1349 }
1350 card_res->count_crtcs = crtc_count;
1351
1352 /* Encoders */
1353 if (card_res->count_encoders >= encoder_count) {
1354 copied = 0;
1355 encoder_id = (uint32_t __user *)(unsigned long)card_res->encoder_id_ptr;
1356 if (file_priv->master->minor->type == DRM_MINOR_CONTROL) {
1357 list_for_each_entry(encoder,
1358 &dev->mode_config.encoder_list,
1359 head) {
Jerome Glisse94401062010-07-15 15:43:25 -04001360 DRM_DEBUG_KMS("[ENCODER:%d:%s]\n", encoder->base.id,
1361 drm_get_encoder_name(encoder));
Dave Airlief453ba02008-11-07 14:05:41 -08001362 if (put_user(encoder->base.id, encoder_id +
1363 copied)) {
1364 ret = -EFAULT;
1365 goto out;
1366 }
1367 copied++;
1368 }
1369 } else {
1370 for (i = mode_group->num_crtcs; i < mode_group->num_crtcs + mode_group->num_encoders; i++) {
1371 if (put_user(mode_group->id_list[i],
1372 encoder_id + copied)) {
1373 ret = -EFAULT;
1374 goto out;
1375 }
1376 copied++;
1377 }
1378
1379 }
1380 }
1381 card_res->count_encoders = encoder_count;
1382
1383 /* Connectors */
1384 if (card_res->count_connectors >= connector_count) {
1385 copied = 0;
1386 connector_id = (uint32_t __user *)(unsigned long)card_res->connector_id_ptr;
1387 if (file_priv->master->minor->type == DRM_MINOR_CONTROL) {
1388 list_for_each_entry(connector,
1389 &dev->mode_config.connector_list,
1390 head) {
Jerome Glisse94401062010-07-15 15:43:25 -04001391 DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
1392 connector->base.id,
1393 drm_get_connector_name(connector));
Dave Airlief453ba02008-11-07 14:05:41 -08001394 if (put_user(connector->base.id,
1395 connector_id + copied)) {
1396 ret = -EFAULT;
1397 goto out;
1398 }
1399 copied++;
1400 }
1401 } else {
1402 int start = mode_group->num_crtcs +
1403 mode_group->num_encoders;
1404 for (i = start; i < start + mode_group->num_connectors; i++) {
1405 if (put_user(mode_group->id_list[i],
1406 connector_id + copied)) {
1407 ret = -EFAULT;
1408 goto out;
1409 }
1410 copied++;
1411 }
1412 }
1413 }
1414 card_res->count_connectors = connector_count;
1415
Jerome Glisse94401062010-07-15 15:43:25 -04001416 DRM_DEBUG_KMS("CRTC[%d] CONNECTORS[%d] ENCODERS[%d]\n", card_res->count_crtcs,
Dave Airlief453ba02008-11-07 14:05:41 -08001417 card_res->count_connectors, card_res->count_encoders);
1418
1419out:
Daniel Vetter84849902012-12-02 00:28:11 +01001420 drm_modeset_unlock_all(dev);
Dave Airlief453ba02008-11-07 14:05:41 -08001421 return ret;
1422}
1423
1424/**
1425 * drm_mode_getcrtc - get CRTC configuration
Daniel Vetter065a50ed2012-12-02 00:09:18 +01001426 * @dev: drm device for the ioctl
1427 * @data: data pointer for the ioctl
1428 * @file_priv: drm file for the ioctl call
Dave Airlief453ba02008-11-07 14:05:41 -08001429 *
Dave Airlief453ba02008-11-07 14:05:41 -08001430 * Construct a CRTC configuration structure to return to the user.
1431 *
1432 * Called by the user via ioctl.
1433 *
1434 * RETURNS:
1435 * Zero on success, errno on failure.
1436 */
1437int drm_mode_getcrtc(struct drm_device *dev,
1438 void *data, struct drm_file *file_priv)
1439{
1440 struct drm_mode_crtc *crtc_resp = data;
1441 struct drm_crtc *crtc;
1442 struct drm_mode_object *obj;
1443 int ret = 0;
1444
Dave Airliefb3b06c2011-02-08 13:55:21 +10001445 if (!drm_core_check_feature(dev, DRIVER_MODESET))
1446 return -EINVAL;
1447
Daniel Vetter84849902012-12-02 00:28:11 +01001448 drm_modeset_lock_all(dev);
Dave Airlief453ba02008-11-07 14:05:41 -08001449
1450 obj = drm_mode_object_find(dev, crtc_resp->crtc_id,
1451 DRM_MODE_OBJECT_CRTC);
1452 if (!obj) {
1453 ret = -EINVAL;
1454 goto out;
1455 }
1456 crtc = obj_to_crtc(obj);
1457
1458 crtc_resp->x = crtc->x;
1459 crtc_resp->y = crtc->y;
1460 crtc_resp->gamma_size = crtc->gamma_size;
1461 if (crtc->fb)
1462 crtc_resp->fb_id = crtc->fb->base.id;
1463 else
1464 crtc_resp->fb_id = 0;
1465
1466 if (crtc->enabled) {
1467
1468 drm_crtc_convert_to_umode(&crtc_resp->mode, &crtc->mode);
1469 crtc_resp->mode_valid = 1;
1470
1471 } else {
1472 crtc_resp->mode_valid = 0;
1473 }
1474
1475out:
Daniel Vetter84849902012-12-02 00:28:11 +01001476 drm_modeset_unlock_all(dev);
Dave Airlief453ba02008-11-07 14:05:41 -08001477 return ret;
1478}
1479
1480/**
1481 * drm_mode_getconnector - get connector configuration
Daniel Vetter065a50ed2012-12-02 00:09:18 +01001482 * @dev: drm device for the ioctl
1483 * @data: data pointer for the ioctl
1484 * @file_priv: drm file for the ioctl call
Dave Airlief453ba02008-11-07 14:05:41 -08001485 *
Dave Airlief453ba02008-11-07 14:05:41 -08001486 * Construct a connector configuration structure to return to the user.
1487 *
1488 * Called by the user via ioctl.
1489 *
1490 * RETURNS:
1491 * Zero on success, errno on failure.
1492 */
1493int drm_mode_getconnector(struct drm_device *dev, void *data,
1494 struct drm_file *file_priv)
1495{
1496 struct drm_mode_get_connector *out_resp = data;
1497 struct drm_mode_object *obj;
1498 struct drm_connector *connector;
1499 struct drm_display_mode *mode;
1500 int mode_count = 0;
1501 int props_count = 0;
1502 int encoders_count = 0;
1503 int ret = 0;
1504 int copied = 0;
1505 int i;
1506 struct drm_mode_modeinfo u_mode;
1507 struct drm_mode_modeinfo __user *mode_ptr;
1508 uint32_t __user *prop_ptr;
1509 uint64_t __user *prop_values;
1510 uint32_t __user *encoder_ptr;
1511
Dave Airliefb3b06c2011-02-08 13:55:21 +10001512 if (!drm_core_check_feature(dev, DRIVER_MODESET))
1513 return -EINVAL;
1514
Dave Airlief453ba02008-11-07 14:05:41 -08001515 memset(&u_mode, 0, sizeof(struct drm_mode_modeinfo));
1516
Jerome Glisse94401062010-07-15 15:43:25 -04001517 DRM_DEBUG_KMS("[CONNECTOR:%d:?]\n", out_resp->connector_id);
Dave Airlief453ba02008-11-07 14:05:41 -08001518
Daniel Vetter7b240562012-12-12 00:35:33 +01001519 mutex_lock(&dev->mode_config.mutex);
Dave Airlief453ba02008-11-07 14:05:41 -08001520
1521 obj = drm_mode_object_find(dev, out_resp->connector_id,
1522 DRM_MODE_OBJECT_CONNECTOR);
1523 if (!obj) {
1524 ret = -EINVAL;
1525 goto out;
1526 }
1527 connector = obj_to_connector(obj);
1528
Paulo Zanoni7f88a9b2012-05-15 18:09:04 -03001529 props_count = connector->properties.count;
Dave Airlief453ba02008-11-07 14:05:41 -08001530
1531 for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
1532 if (connector->encoder_ids[i] != 0) {
1533 encoders_count++;
1534 }
1535 }
1536
1537 if (out_resp->count_modes == 0) {
1538 connector->funcs->fill_modes(connector,
1539 dev->mode_config.max_width,
1540 dev->mode_config.max_height);
1541 }
1542
1543 /* delayed so we get modes regardless of pre-fill_modes state */
1544 list_for_each_entry(mode, &connector->modes, head)
1545 mode_count++;
1546
1547 out_resp->connector_id = connector->base.id;
1548 out_resp->connector_type = connector->connector_type;
1549 out_resp->connector_type_id = connector->connector_type_id;
1550 out_resp->mm_width = connector->display_info.width_mm;
1551 out_resp->mm_height = connector->display_info.height_mm;
1552 out_resp->subpixel = connector->display_info.subpixel_order;
1553 out_resp->connection = connector->status;
1554 if (connector->encoder)
1555 out_resp->encoder_id = connector->encoder->base.id;
1556 else
1557 out_resp->encoder_id = 0;
1558
1559 /*
1560 * This ioctl is called twice, once to determine how much space is
1561 * needed, and the 2nd time to fill it.
1562 */
1563 if ((out_resp->count_modes >= mode_count) && mode_count) {
1564 copied = 0;
Ville Syrjälä81f6c7f2011-12-20 00:06:42 +02001565 mode_ptr = (struct drm_mode_modeinfo __user *)(unsigned long)out_resp->modes_ptr;
Dave Airlief453ba02008-11-07 14:05:41 -08001566 list_for_each_entry(mode, &connector->modes, head) {
1567 drm_crtc_convert_to_umode(&u_mode, mode);
1568 if (copy_to_user(mode_ptr + copied,
1569 &u_mode, sizeof(u_mode))) {
1570 ret = -EFAULT;
1571 goto out;
1572 }
1573 copied++;
1574 }
1575 }
1576 out_resp->count_modes = mode_count;
1577
1578 if ((out_resp->count_props >= props_count) && props_count) {
1579 copied = 0;
Ville Syrjälä81f6c7f2011-12-20 00:06:42 +02001580 prop_ptr = (uint32_t __user *)(unsigned long)(out_resp->props_ptr);
1581 prop_values = (uint64_t __user *)(unsigned long)(out_resp->prop_values_ptr);
Paulo Zanoni7f88a9b2012-05-15 18:09:04 -03001582 for (i = 0; i < connector->properties.count; i++) {
1583 if (put_user(connector->properties.ids[i],
1584 prop_ptr + copied)) {
1585 ret = -EFAULT;
1586 goto out;
Dave Airlief453ba02008-11-07 14:05:41 -08001587 }
Paulo Zanoni7f88a9b2012-05-15 18:09:04 -03001588
1589 if (put_user(connector->properties.values[i],
1590 prop_values + copied)) {
1591 ret = -EFAULT;
1592 goto out;
1593 }
1594 copied++;
Dave Airlief453ba02008-11-07 14:05:41 -08001595 }
1596 }
1597 out_resp->count_props = props_count;
1598
1599 if ((out_resp->count_encoders >= encoders_count) && encoders_count) {
1600 copied = 0;
Ville Syrjälä81f6c7f2011-12-20 00:06:42 +02001601 encoder_ptr = (uint32_t __user *)(unsigned long)(out_resp->encoders_ptr);
Dave Airlief453ba02008-11-07 14:05:41 -08001602 for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
1603 if (connector->encoder_ids[i] != 0) {
1604 if (put_user(connector->encoder_ids[i],
1605 encoder_ptr + copied)) {
1606 ret = -EFAULT;
1607 goto out;
1608 }
1609 copied++;
1610 }
1611 }
1612 }
1613 out_resp->count_encoders = encoders_count;
1614
1615out:
Daniel Vetter7b240562012-12-12 00:35:33 +01001616 mutex_unlock(&dev->mode_config.mutex);
1617
Dave Airlief453ba02008-11-07 14:05:41 -08001618 return ret;
1619}
1620
1621int drm_mode_getencoder(struct drm_device *dev, void *data,
1622 struct drm_file *file_priv)
1623{
1624 struct drm_mode_get_encoder *enc_resp = data;
1625 struct drm_mode_object *obj;
1626 struct drm_encoder *encoder;
1627 int ret = 0;
1628
Dave Airliefb3b06c2011-02-08 13:55:21 +10001629 if (!drm_core_check_feature(dev, DRIVER_MODESET))
1630 return -EINVAL;
1631
Daniel Vetter84849902012-12-02 00:28:11 +01001632 drm_modeset_lock_all(dev);
Dave Airlief453ba02008-11-07 14:05:41 -08001633 obj = drm_mode_object_find(dev, enc_resp->encoder_id,
1634 DRM_MODE_OBJECT_ENCODER);
1635 if (!obj) {
1636 ret = -EINVAL;
1637 goto out;
1638 }
1639 encoder = obj_to_encoder(obj);
1640
1641 if (encoder->crtc)
1642 enc_resp->crtc_id = encoder->crtc->base.id;
1643 else
1644 enc_resp->crtc_id = 0;
1645 enc_resp->encoder_type = encoder->encoder_type;
1646 enc_resp->encoder_id = encoder->base.id;
1647 enc_resp->possible_crtcs = encoder->possible_crtcs;
1648 enc_resp->possible_clones = encoder->possible_clones;
1649
1650out:
Daniel Vetter84849902012-12-02 00:28:11 +01001651 drm_modeset_unlock_all(dev);
Dave Airlief453ba02008-11-07 14:05:41 -08001652 return ret;
1653}
1654
1655/**
Jesse Barnes8cf5c912011-11-14 14:51:27 -08001656 * drm_mode_getplane_res - get plane info
1657 * @dev: DRM device
1658 * @data: ioctl data
1659 * @file_priv: DRM file info
1660 *
1661 * Return an plane count and set of IDs.
1662 */
1663int drm_mode_getplane_res(struct drm_device *dev, void *data,
1664 struct drm_file *file_priv)
1665{
1666 struct drm_mode_get_plane_res *plane_resp = data;
1667 struct drm_mode_config *config;
1668 struct drm_plane *plane;
1669 uint32_t __user *plane_ptr;
1670 int copied = 0, ret = 0;
1671
1672 if (!drm_core_check_feature(dev, DRIVER_MODESET))
1673 return -EINVAL;
1674
Daniel Vetter84849902012-12-02 00:28:11 +01001675 drm_modeset_lock_all(dev);
Jesse Barnes8cf5c912011-11-14 14:51:27 -08001676 config = &dev->mode_config;
1677
1678 /*
1679 * This ioctl is called twice, once to determine how much space is
1680 * needed, and the 2nd time to fill it.
1681 */
1682 if (config->num_plane &&
1683 (plane_resp->count_planes >= config->num_plane)) {
Ville Syrjälä81f6c7f2011-12-20 00:06:42 +02001684 plane_ptr = (uint32_t __user *)(unsigned long)plane_resp->plane_id_ptr;
Jesse Barnes8cf5c912011-11-14 14:51:27 -08001685
1686 list_for_each_entry(plane, &config->plane_list, head) {
1687 if (put_user(plane->base.id, plane_ptr + copied)) {
1688 ret = -EFAULT;
1689 goto out;
1690 }
1691 copied++;
1692 }
1693 }
1694 plane_resp->count_planes = config->num_plane;
1695
1696out:
Daniel Vetter84849902012-12-02 00:28:11 +01001697 drm_modeset_unlock_all(dev);
Jesse Barnes8cf5c912011-11-14 14:51:27 -08001698 return ret;
1699}
1700
1701/**
1702 * drm_mode_getplane - get plane info
1703 * @dev: DRM device
1704 * @data: ioctl data
1705 * @file_priv: DRM file info
1706 *
1707 * Return plane info, including formats supported, gamma size, any
1708 * current fb, etc.
1709 */
1710int drm_mode_getplane(struct drm_device *dev, void *data,
1711 struct drm_file *file_priv)
1712{
1713 struct drm_mode_get_plane *plane_resp = data;
1714 struct drm_mode_object *obj;
1715 struct drm_plane *plane;
1716 uint32_t __user *format_ptr;
1717 int ret = 0;
1718
1719 if (!drm_core_check_feature(dev, DRIVER_MODESET))
1720 return -EINVAL;
1721
Daniel Vetter84849902012-12-02 00:28:11 +01001722 drm_modeset_lock_all(dev);
Jesse Barnes8cf5c912011-11-14 14:51:27 -08001723 obj = drm_mode_object_find(dev, plane_resp->plane_id,
1724 DRM_MODE_OBJECT_PLANE);
1725 if (!obj) {
1726 ret = -ENOENT;
1727 goto out;
1728 }
1729 plane = obj_to_plane(obj);
1730
1731 if (plane->crtc)
1732 plane_resp->crtc_id = plane->crtc->base.id;
1733 else
1734 plane_resp->crtc_id = 0;
1735
1736 if (plane->fb)
1737 plane_resp->fb_id = plane->fb->base.id;
1738 else
1739 plane_resp->fb_id = 0;
1740
1741 plane_resp->plane_id = plane->base.id;
1742 plane_resp->possible_crtcs = plane->possible_crtcs;
1743 plane_resp->gamma_size = plane->gamma_size;
1744
1745 /*
1746 * This ioctl is called twice, once to determine how much space is
1747 * needed, and the 2nd time to fill it.
1748 */
1749 if (plane->format_count &&
1750 (plane_resp->count_format_types >= plane->format_count)) {
Ville Syrjälä81f6c7f2011-12-20 00:06:42 +02001751 format_ptr = (uint32_t __user *)(unsigned long)plane_resp->format_type_ptr;
Jesse Barnes8cf5c912011-11-14 14:51:27 -08001752 if (copy_to_user(format_ptr,
1753 plane->format_types,
1754 sizeof(uint32_t) * plane->format_count)) {
1755 ret = -EFAULT;
1756 goto out;
1757 }
1758 }
1759 plane_resp->count_format_types = plane->format_count;
1760
1761out:
Daniel Vetter84849902012-12-02 00:28:11 +01001762 drm_modeset_unlock_all(dev);
Jesse Barnes8cf5c912011-11-14 14:51:27 -08001763 return ret;
1764}
1765
1766/**
1767 * drm_mode_setplane - set up or tear down an plane
1768 * @dev: DRM device
1769 * @data: ioctl data*
Daniel Vetter065a50ed2012-12-02 00:09:18 +01001770 * @file_priv: DRM file info
Jesse Barnes8cf5c912011-11-14 14:51:27 -08001771 *
1772 * Set plane info, including placement, fb, scaling, and other factors.
1773 * Or pass a NULL fb to disable.
1774 */
1775int drm_mode_setplane(struct drm_device *dev, void *data,
1776 struct drm_file *file_priv)
1777{
1778 struct drm_mode_set_plane *plane_req = data;
1779 struct drm_mode_object *obj;
1780 struct drm_plane *plane;
1781 struct drm_crtc *crtc;
Daniel Vetter6c2a7532012-12-11 00:59:24 +01001782 struct drm_framebuffer *fb = NULL, *old_fb = NULL;
Jesse Barnes8cf5c912011-11-14 14:51:27 -08001783 int ret = 0;
Ville Syrjälä42ef8782011-12-20 00:06:44 +02001784 unsigned int fb_width, fb_height;
Ville Syrjälä62443be2011-12-20 00:06:47 +02001785 int i;
Jesse Barnes8cf5c912011-11-14 14:51:27 -08001786
1787 if (!drm_core_check_feature(dev, DRIVER_MODESET))
1788 return -EINVAL;
1789
Jesse Barnes8cf5c912011-11-14 14:51:27 -08001790 /*
1791 * First, find the plane, crtc, and fb objects. If not available,
1792 * we don't bother to call the driver.
1793 */
1794 obj = drm_mode_object_find(dev, plane_req->plane_id,
1795 DRM_MODE_OBJECT_PLANE);
1796 if (!obj) {
1797 DRM_DEBUG_KMS("Unknown plane ID %d\n",
1798 plane_req->plane_id);
Daniel Vetter6c2a7532012-12-11 00:59:24 +01001799 return -ENOENT;
Jesse Barnes8cf5c912011-11-14 14:51:27 -08001800 }
1801 plane = obj_to_plane(obj);
1802
1803 /* No fb means shut it down */
1804 if (!plane_req->fb_id) {
Daniel Vetter6c2a7532012-12-11 00:59:24 +01001805 drm_modeset_lock_all(dev);
1806 old_fb = plane->fb;
Jesse Barnes8cf5c912011-11-14 14:51:27 -08001807 plane->funcs->disable_plane(plane);
Ville Syrjäläe5e3b442011-12-20 00:06:43 +02001808 plane->crtc = NULL;
1809 plane->fb = NULL;
Daniel Vetter6c2a7532012-12-11 00:59:24 +01001810 drm_modeset_unlock_all(dev);
Jesse Barnes8cf5c912011-11-14 14:51:27 -08001811 goto out;
1812 }
1813
1814 obj = drm_mode_object_find(dev, plane_req->crtc_id,
1815 DRM_MODE_OBJECT_CRTC);
1816 if (!obj) {
1817 DRM_DEBUG_KMS("Unknown crtc ID %d\n",
1818 plane_req->crtc_id);
1819 ret = -ENOENT;
1820 goto out;
1821 }
1822 crtc = obj_to_crtc(obj);
1823
Daniel Vetter786b99e2012-12-02 21:53:40 +01001824 fb = drm_framebuffer_lookup(dev, plane_req->fb_id);
1825 if (!fb) {
Jesse Barnes8cf5c912011-11-14 14:51:27 -08001826 DRM_DEBUG_KMS("Unknown framebuffer ID %d\n",
1827 plane_req->fb_id);
1828 ret = -ENOENT;
1829 goto out;
1830 }
Jesse Barnes8cf5c912011-11-14 14:51:27 -08001831
Ville Syrjälä62443be2011-12-20 00:06:47 +02001832 /* Check whether this plane supports the fb pixel format. */
1833 for (i = 0; i < plane->format_count; i++)
1834 if (fb->pixel_format == plane->format_types[i])
1835 break;
1836 if (i == plane->format_count) {
1837 DRM_DEBUG_KMS("Invalid pixel format 0x%08x\n", fb->pixel_format);
1838 ret = -EINVAL;
1839 goto out;
1840 }
1841
Ville Syrjälä42ef8782011-12-20 00:06:44 +02001842 fb_width = fb->width << 16;
1843 fb_height = fb->height << 16;
1844
1845 /* Make sure source coordinates are inside the fb. */
1846 if (plane_req->src_w > fb_width ||
1847 plane_req->src_x > fb_width - plane_req->src_w ||
1848 plane_req->src_h > fb_height ||
1849 plane_req->src_y > fb_height - plane_req->src_h) {
1850 DRM_DEBUG_KMS("Invalid source coordinates "
1851 "%u.%06ux%u.%06u+%u.%06u+%u.%06u\n",
1852 plane_req->src_w >> 16,
1853 ((plane_req->src_w & 0xffff) * 15625) >> 10,
1854 plane_req->src_h >> 16,
1855 ((plane_req->src_h & 0xffff) * 15625) >> 10,
1856 plane_req->src_x >> 16,
1857 ((plane_req->src_x & 0xffff) * 15625) >> 10,
1858 plane_req->src_y >> 16,
1859 ((plane_req->src_y & 0xffff) * 15625) >> 10);
1860 ret = -ENOSPC;
1861 goto out;
1862 }
1863
Ville Syrjälä687a0402011-12-20 00:06:45 +02001864 /* Give drivers some help against integer overflows */
1865 if (plane_req->crtc_w > INT_MAX ||
1866 plane_req->crtc_x > INT_MAX - (int32_t) plane_req->crtc_w ||
1867 plane_req->crtc_h > INT_MAX ||
1868 plane_req->crtc_y > INT_MAX - (int32_t) plane_req->crtc_h) {
1869 DRM_DEBUG_KMS("Invalid CRTC coordinates %ux%u+%d+%d\n",
1870 plane_req->crtc_w, plane_req->crtc_h,
1871 plane_req->crtc_x, plane_req->crtc_y);
1872 ret = -ERANGE;
1873 goto out;
1874 }
1875
Daniel Vetter6c2a7532012-12-11 00:59:24 +01001876 drm_modeset_lock_all(dev);
Jesse Barnes8cf5c912011-11-14 14:51:27 -08001877 ret = plane->funcs->update_plane(plane, crtc, fb,
1878 plane_req->crtc_x, plane_req->crtc_y,
1879 plane_req->crtc_w, plane_req->crtc_h,
1880 plane_req->src_x, plane_req->src_y,
1881 plane_req->src_w, plane_req->src_h);
1882 if (!ret) {
Daniel Vetter6c2a7532012-12-11 00:59:24 +01001883 old_fb = plane->fb;
Jesse Barnes8cf5c912011-11-14 14:51:27 -08001884 plane->crtc = crtc;
1885 plane->fb = fb;
Daniel Vetter35f8bad2013-02-15 21:21:37 +01001886 fb = NULL;
Jesse Barnes8cf5c912011-11-14 14:51:27 -08001887 }
Daniel Vetter6c2a7532012-12-11 00:59:24 +01001888 drm_modeset_unlock_all(dev);
Jesse Barnes8cf5c912011-11-14 14:51:27 -08001889
1890out:
Daniel Vetter6c2a7532012-12-11 00:59:24 +01001891 if (fb)
1892 drm_framebuffer_unreference(fb);
1893 if (old_fb)
1894 drm_framebuffer_unreference(old_fb);
Jesse Barnes8cf5c912011-11-14 14:51:27 -08001895
1896 return ret;
1897}
1898
1899/**
Daniel Vetter2d13b672012-12-11 13:47:23 +01001900 * drm_mode_set_config_internal - helper to call ->set_config
1901 * @set: modeset config to set
1902 *
1903 * This is a little helper to wrap internal calls to the ->set_config driver
1904 * interface. The only thing it adds is correct refcounting dance.
1905 */
1906int drm_mode_set_config_internal(struct drm_mode_set *set)
1907{
1908 struct drm_crtc *crtc = set->crtc;
Daniel Vetterb0d12322012-12-11 01:07:12 +01001909 struct drm_framebuffer *fb, *old_fb;
1910 int ret;
Daniel Vetter2d13b672012-12-11 13:47:23 +01001911
Daniel Vetterb0d12322012-12-11 01:07:12 +01001912 old_fb = crtc->fb;
1913 fb = set->fb;
1914
1915 ret = crtc->funcs->set_config(set);
1916 if (ret == 0) {
1917 if (old_fb)
1918 drm_framebuffer_unreference(old_fb);
1919 if (fb)
1920 drm_framebuffer_reference(fb);
1921 }
1922
1923 return ret;
Daniel Vetter2d13b672012-12-11 13:47:23 +01001924}
1925EXPORT_SYMBOL(drm_mode_set_config_internal);
1926
1927/**
Dave Airlief453ba02008-11-07 14:05:41 -08001928 * drm_mode_setcrtc - set CRTC configuration
Daniel Vetter065a50ed2012-12-02 00:09:18 +01001929 * @dev: drm device for the ioctl
1930 * @data: data pointer for the ioctl
1931 * @file_priv: drm file for the ioctl call
Dave Airlief453ba02008-11-07 14:05:41 -08001932 *
Dave Airlief453ba02008-11-07 14:05:41 -08001933 * Build a new CRTC configuration based on user request.
1934 *
1935 * Called by the user via ioctl.
1936 *
1937 * RETURNS:
1938 * Zero on success, errno on failure.
1939 */
1940int drm_mode_setcrtc(struct drm_device *dev, void *data,
1941 struct drm_file *file_priv)
1942{
1943 struct drm_mode_config *config = &dev->mode_config;
1944 struct drm_mode_crtc *crtc_req = data;
1945 struct drm_mode_object *obj;
Ville Syrjälä6653cc82012-03-13 12:35:38 +02001946 struct drm_crtc *crtc;
Dave Airlief453ba02008-11-07 14:05:41 -08001947 struct drm_connector **connector_set = NULL, *connector;
1948 struct drm_framebuffer *fb = NULL;
1949 struct drm_display_mode *mode = NULL;
1950 struct drm_mode_set set;
1951 uint32_t __user *set_connectors_ptr;
Laurent Pinchart4a1b0712012-05-17 13:27:21 +02001952 int ret;
Dave Airlief453ba02008-11-07 14:05:41 -08001953 int i;
1954
Dave Airliefb3b06c2011-02-08 13:55:21 +10001955 if (!drm_core_check_feature(dev, DRIVER_MODESET))
1956 return -EINVAL;
1957
Ville Syrjälä1d97e912012-03-13 12:35:41 +02001958 /* For some reason crtc x/y offsets are signed internally. */
1959 if (crtc_req->x > INT_MAX || crtc_req->y > INT_MAX)
1960 return -ERANGE;
1961
Daniel Vetter84849902012-12-02 00:28:11 +01001962 drm_modeset_lock_all(dev);
Dave Airlief453ba02008-11-07 14:05:41 -08001963 obj = drm_mode_object_find(dev, crtc_req->crtc_id,
1964 DRM_MODE_OBJECT_CRTC);
1965 if (!obj) {
Zhao Yakui58367ed2009-07-20 13:48:07 +08001966 DRM_DEBUG_KMS("Unknown CRTC ID %d\n", crtc_req->crtc_id);
Dave Airlief453ba02008-11-07 14:05:41 -08001967 ret = -EINVAL;
1968 goto out;
1969 }
1970 crtc = obj_to_crtc(obj);
Jerome Glisse94401062010-07-15 15:43:25 -04001971 DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id);
Dave Airlief453ba02008-11-07 14:05:41 -08001972
1973 if (crtc_req->mode_valid) {
Rob Clark7c80e122012-09-04 16:35:56 +00001974 int hdisplay, vdisplay;
Dave Airlief453ba02008-11-07 14:05:41 -08001975 /* If we have a mode we need a framebuffer. */
1976 /* If we pass -1, set the mode with the currently bound fb */
1977 if (crtc_req->fb_id == -1) {
Ville Syrjälä6653cc82012-03-13 12:35:38 +02001978 if (!crtc->fb) {
1979 DRM_DEBUG_KMS("CRTC doesn't have current FB\n");
1980 ret = -EINVAL;
1981 goto out;
Dave Airlief453ba02008-11-07 14:05:41 -08001982 }
Ville Syrjälä6653cc82012-03-13 12:35:38 +02001983 fb = crtc->fb;
Daniel Vetterb0d12322012-12-11 01:07:12 +01001984 /* Make refcounting symmetric with the lookup path. */
1985 drm_framebuffer_reference(fb);
Dave Airlief453ba02008-11-07 14:05:41 -08001986 } else {
Daniel Vetter786b99e2012-12-02 21:53:40 +01001987 fb = drm_framebuffer_lookup(dev, crtc_req->fb_id);
1988 if (!fb) {
Zhao Yakui58367ed2009-07-20 13:48:07 +08001989 DRM_DEBUG_KMS("Unknown FB ID%d\n",
1990 crtc_req->fb_id);
Dave Airlief453ba02008-11-07 14:05:41 -08001991 ret = -EINVAL;
1992 goto out;
1993 }
Dave Airlief453ba02008-11-07 14:05:41 -08001994 }
1995
1996 mode = drm_mode_create(dev);
Ville Syrjäläee34ab52012-03-13 12:35:43 +02001997 if (!mode) {
1998 ret = -ENOMEM;
1999 goto out;
2000 }
2001
Ville Syrjälä90367bf2012-03-13 12:35:44 +02002002 ret = drm_crtc_convert_umode(mode, &crtc_req->mode);
2003 if (ret) {
2004 DRM_DEBUG_KMS("Invalid mode\n");
2005 goto out;
2006 }
2007
Dave Airlief453ba02008-11-07 14:05:41 -08002008 drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
Ville Syrjälä5f61bb42012-03-13 12:35:45 +02002009
Rob Clark7c80e122012-09-04 16:35:56 +00002010 hdisplay = mode->hdisplay;
2011 vdisplay = mode->vdisplay;
2012
2013 if (crtc->invert_dimensions)
2014 swap(hdisplay, vdisplay);
2015
2016 if (hdisplay > fb->width ||
2017 vdisplay > fb->height ||
2018 crtc_req->x > fb->width - hdisplay ||
2019 crtc_req->y > fb->height - vdisplay) {
2020 DRM_DEBUG_KMS("Invalid fb size %ux%u for CRTC viewport %ux%u+%d+%d%s.\n",
2021 fb->width, fb->height,
2022 hdisplay, vdisplay, crtc_req->x, crtc_req->y,
2023 crtc->invert_dimensions ? " (inverted)" : "");
Ville Syrjälä5f61bb42012-03-13 12:35:45 +02002024 ret = -ENOSPC;
2025 goto out;
2026 }
Dave Airlief453ba02008-11-07 14:05:41 -08002027 }
2028
2029 if (crtc_req->count_connectors == 0 && mode) {
Zhao Yakui58367ed2009-07-20 13:48:07 +08002030 DRM_DEBUG_KMS("Count connectors is 0 but mode set\n");
Dave Airlief453ba02008-11-07 14:05:41 -08002031 ret = -EINVAL;
2032 goto out;
2033 }
2034
Jakob Bornecrantz7781de72009-08-03 13:43:58 +01002035 if (crtc_req->count_connectors > 0 && (!mode || !fb)) {
Zhao Yakui58367ed2009-07-20 13:48:07 +08002036 DRM_DEBUG_KMS("Count connectors is %d but no mode or fb set\n",
Dave Airlief453ba02008-11-07 14:05:41 -08002037 crtc_req->count_connectors);
2038 ret = -EINVAL;
2039 goto out;
2040 }
2041
2042 if (crtc_req->count_connectors > 0) {
2043 u32 out_id;
2044
2045 /* Avoid unbounded kernel memory allocation */
2046 if (crtc_req->count_connectors > config->num_connector) {
2047 ret = -EINVAL;
2048 goto out;
2049 }
2050
2051 connector_set = kmalloc(crtc_req->count_connectors *
2052 sizeof(struct drm_connector *),
2053 GFP_KERNEL);
2054 if (!connector_set) {
2055 ret = -ENOMEM;
2056 goto out;
2057 }
2058
2059 for (i = 0; i < crtc_req->count_connectors; i++) {
Ville Syrjälä81f6c7f2011-12-20 00:06:42 +02002060 set_connectors_ptr = (uint32_t __user *)(unsigned long)crtc_req->set_connectors_ptr;
Dave Airlief453ba02008-11-07 14:05:41 -08002061 if (get_user(out_id, &set_connectors_ptr[i])) {
2062 ret = -EFAULT;
2063 goto out;
2064 }
2065
2066 obj = drm_mode_object_find(dev, out_id,
2067 DRM_MODE_OBJECT_CONNECTOR);
2068 if (!obj) {
Zhao Yakui58367ed2009-07-20 13:48:07 +08002069 DRM_DEBUG_KMS("Connector id %d unknown\n",
2070 out_id);
Dave Airlief453ba02008-11-07 14:05:41 -08002071 ret = -EINVAL;
2072 goto out;
2073 }
2074 connector = obj_to_connector(obj);
Jerome Glisse94401062010-07-15 15:43:25 -04002075 DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
2076 connector->base.id,
2077 drm_get_connector_name(connector));
Dave Airlief453ba02008-11-07 14:05:41 -08002078
2079 connector_set[i] = connector;
2080 }
2081 }
2082
2083 set.crtc = crtc;
2084 set.x = crtc_req->x;
2085 set.y = crtc_req->y;
2086 set.mode = mode;
2087 set.connectors = connector_set;
2088 set.num_connectors = crtc_req->count_connectors;
Dave Airlie5ef5f722009-08-17 13:11:23 +10002089 set.fb = fb;
Daniel Vetter2d13b672012-12-11 13:47:23 +01002090 ret = drm_mode_set_config_internal(&set);
Dave Airlief453ba02008-11-07 14:05:41 -08002091
2092out:
Daniel Vetterb0d12322012-12-11 01:07:12 +01002093 if (fb)
2094 drm_framebuffer_unreference(fb);
2095
Dave Airlief453ba02008-11-07 14:05:41 -08002096 kfree(connector_set);
Ville Syrjäläee34ab52012-03-13 12:35:43 +02002097 drm_mode_destroy(dev, mode);
Daniel Vetter84849902012-12-02 00:28:11 +01002098 drm_modeset_unlock_all(dev);
Dave Airlief453ba02008-11-07 14:05:41 -08002099 return ret;
2100}
2101
2102int drm_mode_cursor_ioctl(struct drm_device *dev,
2103 void *data, struct drm_file *file_priv)
2104{
2105 struct drm_mode_cursor *req = data;
2106 struct drm_mode_object *obj;
2107 struct drm_crtc *crtc;
2108 int ret = 0;
2109
Dave Airliefb3b06c2011-02-08 13:55:21 +10002110 if (!drm_core_check_feature(dev, DRIVER_MODESET))
2111 return -EINVAL;
2112
Jakob Bornecrantz7c4eaca2012-08-16 08:29:03 +00002113 if (!req->flags || (~DRM_MODE_CURSOR_FLAGS & req->flags))
Dave Airlief453ba02008-11-07 14:05:41 -08002114 return -EINVAL;
Dave Airlief453ba02008-11-07 14:05:41 -08002115
Jakob Bornecrantze0c84632008-12-19 14:50:50 +10002116 obj = drm_mode_object_find(dev, req->crtc_id, DRM_MODE_OBJECT_CRTC);
Dave Airlief453ba02008-11-07 14:05:41 -08002117 if (!obj) {
Zhao Yakui58367ed2009-07-20 13:48:07 +08002118 DRM_DEBUG_KMS("Unknown CRTC ID %d\n", req->crtc_id);
Daniel Vetterdac35662012-12-02 15:24:10 +01002119 return -EINVAL;
Dave Airlief453ba02008-11-07 14:05:41 -08002120 }
2121 crtc = obj_to_crtc(obj);
2122
Daniel Vetterdac35662012-12-02 15:24:10 +01002123 mutex_lock(&crtc->mutex);
Dave Airlief453ba02008-11-07 14:05:41 -08002124 if (req->flags & DRM_MODE_CURSOR_BO) {
2125 if (!crtc->funcs->cursor_set) {
Dave Airlief453ba02008-11-07 14:05:41 -08002126 ret = -ENXIO;
2127 goto out;
2128 }
2129 /* Turns off the cursor if handle is 0 */
2130 ret = crtc->funcs->cursor_set(crtc, file_priv, req->handle,
2131 req->width, req->height);
2132 }
2133
2134 if (req->flags & DRM_MODE_CURSOR_MOVE) {
2135 if (crtc->funcs->cursor_move) {
2136 ret = crtc->funcs->cursor_move(crtc, req->x, req->y);
2137 } else {
Dave Airlief453ba02008-11-07 14:05:41 -08002138 ret = -EFAULT;
2139 goto out;
2140 }
2141 }
2142out:
Daniel Vetterdac35662012-12-02 15:24:10 +01002143 mutex_unlock(&crtc->mutex);
2144
Dave Airlief453ba02008-11-07 14:05:41 -08002145 return ret;
2146}
2147
Jesse Barnes308e5bc2011-11-14 14:51:28 -08002148/* Original addfb only supported RGB formats, so figure out which one */
2149uint32_t drm_mode_legacy_fb_format(uint32_t bpp, uint32_t depth)
2150{
2151 uint32_t fmt;
2152
2153 switch (bpp) {
2154 case 8:
Ville Syrjäläd84f0312013-01-31 19:43:38 +02002155 fmt = DRM_FORMAT_C8;
Jesse Barnes308e5bc2011-11-14 14:51:28 -08002156 break;
2157 case 16:
2158 if (depth == 15)
Ville Syrjälä04b39242011-11-17 18:05:13 +02002159 fmt = DRM_FORMAT_XRGB1555;
Jesse Barnes308e5bc2011-11-14 14:51:28 -08002160 else
Ville Syrjälä04b39242011-11-17 18:05:13 +02002161 fmt = DRM_FORMAT_RGB565;
Jesse Barnes308e5bc2011-11-14 14:51:28 -08002162 break;
2163 case 24:
Ville Syrjälä04b39242011-11-17 18:05:13 +02002164 fmt = DRM_FORMAT_RGB888;
Jesse Barnes308e5bc2011-11-14 14:51:28 -08002165 break;
2166 case 32:
2167 if (depth == 24)
Ville Syrjälä04b39242011-11-17 18:05:13 +02002168 fmt = DRM_FORMAT_XRGB8888;
Jesse Barnes308e5bc2011-11-14 14:51:28 -08002169 else if (depth == 30)
Ville Syrjälä04b39242011-11-17 18:05:13 +02002170 fmt = DRM_FORMAT_XRGB2101010;
Jesse Barnes308e5bc2011-11-14 14:51:28 -08002171 else
Ville Syrjälä04b39242011-11-17 18:05:13 +02002172 fmt = DRM_FORMAT_ARGB8888;
Jesse Barnes308e5bc2011-11-14 14:51:28 -08002173 break;
2174 default:
Ville Syrjälä04b39242011-11-17 18:05:13 +02002175 DRM_ERROR("bad bpp, assuming x8r8g8b8 pixel format\n");
2176 fmt = DRM_FORMAT_XRGB8888;
Jesse Barnes308e5bc2011-11-14 14:51:28 -08002177 break;
2178 }
2179
2180 return fmt;
2181}
2182EXPORT_SYMBOL(drm_mode_legacy_fb_format);
2183
Dave Airlief453ba02008-11-07 14:05:41 -08002184/**
2185 * drm_mode_addfb - add an FB to the graphics configuration
Daniel Vetter065a50ed2012-12-02 00:09:18 +01002186 * @dev: drm device for the ioctl
2187 * @data: data pointer for the ioctl
2188 * @file_priv: drm file for the ioctl call
Dave Airlief453ba02008-11-07 14:05:41 -08002189 *
Dave Airlief453ba02008-11-07 14:05:41 -08002190 * Add a new FB to the specified CRTC, given a user request.
2191 *
2192 * Called by the user via ioctl.
2193 *
2194 * RETURNS:
2195 * Zero on success, errno on failure.
2196 */
2197int drm_mode_addfb(struct drm_device *dev,
2198 void *data, struct drm_file *file_priv)
2199{
Jesse Barnes308e5bc2011-11-14 14:51:28 -08002200 struct drm_mode_fb_cmd *or = data;
2201 struct drm_mode_fb_cmd2 r = {};
2202 struct drm_mode_config *config = &dev->mode_config;
2203 struct drm_framebuffer *fb;
2204 int ret = 0;
2205
2206 /* Use new struct with format internally */
2207 r.fb_id = or->fb_id;
2208 r.width = or->width;
2209 r.height = or->height;
2210 r.pitches[0] = or->pitch;
2211 r.pixel_format = drm_mode_legacy_fb_format(or->bpp, or->depth);
2212 r.handles[0] = or->handle;
2213
2214 if (!drm_core_check_feature(dev, DRIVER_MODESET))
2215 return -EINVAL;
2216
Jesse Barnesacb4b992011-11-07 12:03:23 -08002217 if ((config->min_width > r.width) || (r.width > config->max_width))
Jesse Barnes308e5bc2011-11-14 14:51:28 -08002218 return -EINVAL;
Jesse Barnesacb4b992011-11-07 12:03:23 -08002219
2220 if ((config->min_height > r.height) || (r.height > config->max_height))
Jesse Barnes308e5bc2011-11-14 14:51:28 -08002221 return -EINVAL;
Jesse Barnes308e5bc2011-11-14 14:51:28 -08002222
Jesse Barnes308e5bc2011-11-14 14:51:28 -08002223 fb = dev->mode_config.funcs->fb_create(dev, file_priv, &r);
2224 if (IS_ERR(fb)) {
Dave Airlie1aa1b112012-05-01 17:38:35 +01002225 DRM_DEBUG_KMS("could not create framebuffer\n");
Daniel Vetter4b096ac2012-12-10 21:19:18 +01002226 return PTR_ERR(fb);
Jesse Barnes308e5bc2011-11-14 14:51:28 -08002227 }
2228
Daniel Vetter4b096ac2012-12-10 21:19:18 +01002229 mutex_lock(&file_priv->fbs_lock);
Jesse Barnes308e5bc2011-11-14 14:51:28 -08002230 or->fb_id = fb->base.id;
2231 list_add(&fb->filp_head, &file_priv->fbs);
2232 DRM_DEBUG_KMS("[FB:%d]\n", fb->base.id);
Daniel Vetter4b096ac2012-12-10 21:19:18 +01002233 mutex_unlock(&file_priv->fbs_lock);
Daniel Vetter4b096ac2012-12-10 21:19:18 +01002234
Jesse Barnes308e5bc2011-11-14 14:51:28 -08002235 return ret;
2236}
2237
Ville Syrjäläcff91b62012-05-24 20:54:00 +03002238static int format_check(const struct drm_mode_fb_cmd2 *r)
Ville Syrjälä935b5972011-12-20 00:06:48 +02002239{
2240 uint32_t format = r->pixel_format & ~DRM_FORMAT_BIG_ENDIAN;
2241
2242 switch (format) {
2243 case DRM_FORMAT_C8:
2244 case DRM_FORMAT_RGB332:
2245 case DRM_FORMAT_BGR233:
2246 case DRM_FORMAT_XRGB4444:
2247 case DRM_FORMAT_XBGR4444:
2248 case DRM_FORMAT_RGBX4444:
2249 case DRM_FORMAT_BGRX4444:
2250 case DRM_FORMAT_ARGB4444:
2251 case DRM_FORMAT_ABGR4444:
2252 case DRM_FORMAT_RGBA4444:
2253 case DRM_FORMAT_BGRA4444:
2254 case DRM_FORMAT_XRGB1555:
2255 case DRM_FORMAT_XBGR1555:
2256 case DRM_FORMAT_RGBX5551:
2257 case DRM_FORMAT_BGRX5551:
2258 case DRM_FORMAT_ARGB1555:
2259 case DRM_FORMAT_ABGR1555:
2260 case DRM_FORMAT_RGBA5551:
2261 case DRM_FORMAT_BGRA5551:
2262 case DRM_FORMAT_RGB565:
2263 case DRM_FORMAT_BGR565:
2264 case DRM_FORMAT_RGB888:
2265 case DRM_FORMAT_BGR888:
2266 case DRM_FORMAT_XRGB8888:
2267 case DRM_FORMAT_XBGR8888:
2268 case DRM_FORMAT_RGBX8888:
2269 case DRM_FORMAT_BGRX8888:
2270 case DRM_FORMAT_ARGB8888:
2271 case DRM_FORMAT_ABGR8888:
2272 case DRM_FORMAT_RGBA8888:
2273 case DRM_FORMAT_BGRA8888:
2274 case DRM_FORMAT_XRGB2101010:
2275 case DRM_FORMAT_XBGR2101010:
2276 case DRM_FORMAT_RGBX1010102:
2277 case DRM_FORMAT_BGRX1010102:
2278 case DRM_FORMAT_ARGB2101010:
2279 case DRM_FORMAT_ABGR2101010:
2280 case DRM_FORMAT_RGBA1010102:
2281 case DRM_FORMAT_BGRA1010102:
2282 case DRM_FORMAT_YUYV:
2283 case DRM_FORMAT_YVYU:
2284 case DRM_FORMAT_UYVY:
2285 case DRM_FORMAT_VYUY:
2286 case DRM_FORMAT_AYUV:
2287 case DRM_FORMAT_NV12:
2288 case DRM_FORMAT_NV21:
2289 case DRM_FORMAT_NV16:
2290 case DRM_FORMAT_NV61:
Laurent Pinchartba623f62012-05-18 23:47:40 +02002291 case DRM_FORMAT_NV24:
2292 case DRM_FORMAT_NV42:
Ville Syrjälä935b5972011-12-20 00:06:48 +02002293 case DRM_FORMAT_YUV410:
2294 case DRM_FORMAT_YVU410:
2295 case DRM_FORMAT_YUV411:
2296 case DRM_FORMAT_YVU411:
2297 case DRM_FORMAT_YUV420:
2298 case DRM_FORMAT_YVU420:
2299 case DRM_FORMAT_YUV422:
2300 case DRM_FORMAT_YVU422:
2301 case DRM_FORMAT_YUV444:
2302 case DRM_FORMAT_YVU444:
2303 return 0;
2304 default:
2305 return -EINVAL;
2306 }
2307}
2308
Ville Syrjäläcff91b62012-05-24 20:54:00 +03002309static int framebuffer_check(const struct drm_mode_fb_cmd2 *r)
Ville Syrjäläd1b45d52012-04-05 21:35:18 +03002310{
2311 int ret, hsub, vsub, num_planes, i;
2312
2313 ret = format_check(r);
2314 if (ret) {
Dave Airlie1aa1b112012-05-01 17:38:35 +01002315 DRM_DEBUG_KMS("bad framebuffer format 0x%08x\n", r->pixel_format);
Ville Syrjäläd1b45d52012-04-05 21:35:18 +03002316 return ret;
2317 }
2318
2319 hsub = drm_format_horz_chroma_subsampling(r->pixel_format);
2320 vsub = drm_format_vert_chroma_subsampling(r->pixel_format);
2321 num_planes = drm_format_num_planes(r->pixel_format);
2322
2323 if (r->width == 0 || r->width % hsub) {
Dave Airlie1aa1b112012-05-01 17:38:35 +01002324 DRM_DEBUG_KMS("bad framebuffer width %u\n", r->height);
Ville Syrjäläd1b45d52012-04-05 21:35:18 +03002325 return -EINVAL;
2326 }
2327
2328 if (r->height == 0 || r->height % vsub) {
Dave Airlie1aa1b112012-05-01 17:38:35 +01002329 DRM_DEBUG_KMS("bad framebuffer height %u\n", r->height);
Ville Syrjäläd1b45d52012-04-05 21:35:18 +03002330 return -EINVAL;
2331 }
2332
2333 for (i = 0; i < num_planes; i++) {
2334 unsigned int width = r->width / (i != 0 ? hsub : 1);
Ville Syrjäläb180b5d2012-10-25 18:05:04 +00002335 unsigned int height = r->height / (i != 0 ? vsub : 1);
2336 unsigned int cpp = drm_format_plane_cpp(r->pixel_format, i);
Ville Syrjäläd1b45d52012-04-05 21:35:18 +03002337
2338 if (!r->handles[i]) {
Dave Airlie1aa1b112012-05-01 17:38:35 +01002339 DRM_DEBUG_KMS("no buffer object handle for plane %d\n", i);
Ville Syrjäläd1b45d52012-04-05 21:35:18 +03002340 return -EINVAL;
2341 }
2342
Ville Syrjäläb180b5d2012-10-25 18:05:04 +00002343 if ((uint64_t) width * cpp > UINT_MAX)
2344 return -ERANGE;
2345
2346 if ((uint64_t) height * r->pitches[i] + r->offsets[i] > UINT_MAX)
2347 return -ERANGE;
2348
2349 if (r->pitches[i] < width * cpp) {
Dave Airlie1aa1b112012-05-01 17:38:35 +01002350 DRM_DEBUG_KMS("bad pitch %u for plane %d\n", r->pitches[i], i);
Ville Syrjäläd1b45d52012-04-05 21:35:18 +03002351 return -EINVAL;
2352 }
2353 }
2354
2355 return 0;
2356}
2357
Jesse Barnes308e5bc2011-11-14 14:51:28 -08002358/**
2359 * drm_mode_addfb2 - add an FB to the graphics configuration
Daniel Vetter065a50ed2012-12-02 00:09:18 +01002360 * @dev: drm device for the ioctl
2361 * @data: data pointer for the ioctl
2362 * @file_priv: drm file for the ioctl call
Jesse Barnes308e5bc2011-11-14 14:51:28 -08002363 *
Jesse Barnes308e5bc2011-11-14 14:51:28 -08002364 * Add a new FB to the specified CRTC, given a user request with format.
2365 *
2366 * Called by the user via ioctl.
2367 *
2368 * RETURNS:
2369 * Zero on success, errno on failure.
2370 */
2371int drm_mode_addfb2(struct drm_device *dev,
2372 void *data, struct drm_file *file_priv)
2373{
2374 struct drm_mode_fb_cmd2 *r = data;
Dave Airlief453ba02008-11-07 14:05:41 -08002375 struct drm_mode_config *config = &dev->mode_config;
2376 struct drm_framebuffer *fb;
Laurent Pinchart4a1b0712012-05-17 13:27:21 +02002377 int ret;
Dave Airlief453ba02008-11-07 14:05:41 -08002378
Dave Airliefb3b06c2011-02-08 13:55:21 +10002379 if (!drm_core_check_feature(dev, DRIVER_MODESET))
2380 return -EINVAL;
2381
Ville Syrjäläe3cc3522012-11-08 09:09:42 +00002382 if (r->flags & ~DRM_MODE_FB_INTERLACED) {
2383 DRM_DEBUG_KMS("bad framebuffer flags 0x%08x\n", r->flags);
2384 return -EINVAL;
2385 }
2386
Dave Airlief453ba02008-11-07 14:05:41 -08002387 if ((config->min_width > r->width) || (r->width > config->max_width)) {
Dave Airlie1aa1b112012-05-01 17:38:35 +01002388 DRM_DEBUG_KMS("bad framebuffer width %d, should be >= %d && <= %d\n",
Jesse Barnes8cf5c912011-11-14 14:51:27 -08002389 r->width, config->min_width, config->max_width);
Dave Airlief453ba02008-11-07 14:05:41 -08002390 return -EINVAL;
2391 }
2392 if ((config->min_height > r->height) || (r->height > config->max_height)) {
Dave Airlie1aa1b112012-05-01 17:38:35 +01002393 DRM_DEBUG_KMS("bad framebuffer height %d, should be >= %d && <= %d\n",
Jesse Barnes8cf5c912011-11-14 14:51:27 -08002394 r->height, config->min_height, config->max_height);
Dave Airlief453ba02008-11-07 14:05:41 -08002395 return -EINVAL;
2396 }
2397
Ville Syrjäläd1b45d52012-04-05 21:35:18 +03002398 ret = framebuffer_check(r);
2399 if (ret)
Ville Syrjälä935b5972011-12-20 00:06:48 +02002400 return ret;
Ville Syrjälä935b5972011-12-20 00:06:48 +02002401
Dave Airlief453ba02008-11-07 14:05:41 -08002402 fb = dev->mode_config.funcs->fb_create(dev, file_priv, r);
Chris Wilsoncce13ff2010-08-08 13:36:38 +01002403 if (IS_ERR(fb)) {
Dave Airlie1aa1b112012-05-01 17:38:35 +01002404 DRM_DEBUG_KMS("could not create framebuffer\n");
Daniel Vetter4b096ac2012-12-10 21:19:18 +01002405 return PTR_ERR(fb);
Dave Airlief453ba02008-11-07 14:05:41 -08002406 }
2407
Daniel Vetter4b096ac2012-12-10 21:19:18 +01002408 mutex_lock(&file_priv->fbs_lock);
Jakob Bornecrantze0c84632008-12-19 14:50:50 +10002409 r->fb_id = fb->base.id;
Dave Airlief453ba02008-11-07 14:05:41 -08002410 list_add(&fb->filp_head, &file_priv->fbs);
Jerome Glisse94401062010-07-15 15:43:25 -04002411 DRM_DEBUG_KMS("[FB:%d]\n", fb->base.id);
Daniel Vetter4b096ac2012-12-10 21:19:18 +01002412 mutex_unlock(&file_priv->fbs_lock);
Dave Airlief453ba02008-11-07 14:05:41 -08002413
Daniel Vetter4b096ac2012-12-10 21:19:18 +01002414
Dave Airlief453ba02008-11-07 14:05:41 -08002415 return ret;
2416}
2417
2418/**
2419 * drm_mode_rmfb - remove an FB from the configuration
Daniel Vetter065a50ed2012-12-02 00:09:18 +01002420 * @dev: drm device for the ioctl
2421 * @data: data pointer for the ioctl
2422 * @file_priv: drm file for the ioctl call
Dave Airlief453ba02008-11-07 14:05:41 -08002423 *
Dave Airlief453ba02008-11-07 14:05:41 -08002424 * Remove the FB specified by the user.
2425 *
2426 * Called by the user via ioctl.
2427 *
2428 * RETURNS:
2429 * Zero on success, errno on failure.
2430 */
2431int drm_mode_rmfb(struct drm_device *dev,
2432 void *data, struct drm_file *file_priv)
2433{
Dave Airlief453ba02008-11-07 14:05:41 -08002434 struct drm_framebuffer *fb = NULL;
2435 struct drm_framebuffer *fbl = NULL;
2436 uint32_t *id = data;
Dave Airlief453ba02008-11-07 14:05:41 -08002437 int found = 0;
2438
Dave Airliefb3b06c2011-02-08 13:55:21 +10002439 if (!drm_core_check_feature(dev, DRIVER_MODESET))
2440 return -EINVAL;
2441
Daniel Vetter4b096ac2012-12-10 21:19:18 +01002442 mutex_lock(&file_priv->fbs_lock);
Daniel Vetter2b677e82012-12-10 21:16:05 +01002443 mutex_lock(&dev->mode_config.fb_lock);
2444 fb = __drm_framebuffer_lookup(dev, *id);
2445 if (!fb)
2446 goto fail_lookup;
2447
Dave Airlief453ba02008-11-07 14:05:41 -08002448 list_for_each_entry(fbl, &file_priv->fbs, filp_head)
2449 if (fb == fbl)
2450 found = 1;
Daniel Vetter2b677e82012-12-10 21:16:05 +01002451 if (!found)
2452 goto fail_lookup;
2453
2454 /* Mark fb as reaped, we still have a ref from fpriv->fbs. */
2455 __drm_framebuffer_unregister(dev, fb);
Dave Airlief453ba02008-11-07 14:05:41 -08002456
Daniel Vetter4b096ac2012-12-10 21:19:18 +01002457 list_del_init(&fb->filp_head);
Daniel Vetter2b677e82012-12-10 21:16:05 +01002458 mutex_unlock(&dev->mode_config.fb_lock);
Daniel Vetter4b096ac2012-12-10 21:19:18 +01002459 mutex_unlock(&file_priv->fbs_lock);
Dave Airlief453ba02008-11-07 14:05:41 -08002460
Daniel Vetter4b096ac2012-12-10 21:19:18 +01002461 drm_framebuffer_remove(fb);
Daniel Vetter4b096ac2012-12-10 21:19:18 +01002462
Daniel Vetter2b677e82012-12-10 21:16:05 +01002463 return 0;
2464
2465fail_lookup:
2466 mutex_unlock(&dev->mode_config.fb_lock);
2467 mutex_unlock(&file_priv->fbs_lock);
2468
2469 return -EINVAL;
Dave Airlief453ba02008-11-07 14:05:41 -08002470}
2471
2472/**
2473 * drm_mode_getfb - get FB info
Daniel Vetter065a50ed2012-12-02 00:09:18 +01002474 * @dev: drm device for the ioctl
2475 * @data: data pointer for the ioctl
2476 * @file_priv: drm file for the ioctl call
Dave Airlief453ba02008-11-07 14:05:41 -08002477 *
Dave Airlief453ba02008-11-07 14:05:41 -08002478 * Lookup the FB given its ID and return info about it.
2479 *
2480 * Called by the user via ioctl.
2481 *
2482 * RETURNS:
2483 * Zero on success, errno on failure.
2484 */
2485int drm_mode_getfb(struct drm_device *dev,
2486 void *data, struct drm_file *file_priv)
2487{
2488 struct drm_mode_fb_cmd *r = data;
Dave Airlief453ba02008-11-07 14:05:41 -08002489 struct drm_framebuffer *fb;
Daniel Vetter58c0dca2012-12-13 23:06:08 +01002490 int ret;
Dave Airlief453ba02008-11-07 14:05:41 -08002491
Dave Airliefb3b06c2011-02-08 13:55:21 +10002492 if (!drm_core_check_feature(dev, DRIVER_MODESET))
2493 return -EINVAL;
2494
Daniel Vetter786b99e2012-12-02 21:53:40 +01002495 fb = drm_framebuffer_lookup(dev, r->fb_id);
Daniel Vetter58c0dca2012-12-13 23:06:08 +01002496 if (!fb)
2497 return -EINVAL;
Dave Airlief453ba02008-11-07 14:05:41 -08002498
2499 r->height = fb->height;
2500 r->width = fb->width;
2501 r->depth = fb->depth;
2502 r->bpp = fb->bits_per_pixel;
Ville Syrjälä01f2c772011-12-20 00:06:49 +02002503 r->pitch = fb->pitches[0];
Daniel Vetteraf26ef32012-12-13 23:07:50 +01002504 if (fb->funcs->create_handle)
2505 ret = fb->funcs->create_handle(fb, file_priv, &r->handle);
2506 else
2507 ret = -ENODEV;
Dave Airlief453ba02008-11-07 14:05:41 -08002508
Daniel Vetter58c0dca2012-12-13 23:06:08 +01002509 drm_framebuffer_unreference(fb);
2510
Dave Airlief453ba02008-11-07 14:05:41 -08002511 return ret;
2512}
2513
Jakob Bornecrantz884840a2009-12-03 23:25:47 +00002514int drm_mode_dirtyfb_ioctl(struct drm_device *dev,
2515 void *data, struct drm_file *file_priv)
2516{
2517 struct drm_clip_rect __user *clips_ptr;
2518 struct drm_clip_rect *clips = NULL;
2519 struct drm_mode_fb_dirty_cmd *r = data;
Jakob Bornecrantz884840a2009-12-03 23:25:47 +00002520 struct drm_framebuffer *fb;
2521 unsigned flags;
2522 int num_clips;
Laurent Pinchart4a1b0712012-05-17 13:27:21 +02002523 int ret;
Jakob Bornecrantz884840a2009-12-03 23:25:47 +00002524
Dave Airliefb3b06c2011-02-08 13:55:21 +10002525 if (!drm_core_check_feature(dev, DRIVER_MODESET))
2526 return -EINVAL;
2527
Daniel Vetter786b99e2012-12-02 21:53:40 +01002528 fb = drm_framebuffer_lookup(dev, r->fb_id);
Daniel Vetter4ccf0972012-12-11 00:38:18 +01002529 if (!fb)
2530 return -EINVAL;
Jakob Bornecrantz884840a2009-12-03 23:25:47 +00002531
2532 num_clips = r->num_clips;
Ville Syrjälä81f6c7f2011-12-20 00:06:42 +02002533 clips_ptr = (struct drm_clip_rect __user *)(unsigned long)r->clips_ptr;
Jakob Bornecrantz884840a2009-12-03 23:25:47 +00002534
2535 if (!num_clips != !clips_ptr) {
2536 ret = -EINVAL;
2537 goto out_err1;
2538 }
2539
2540 flags = DRM_MODE_FB_DIRTY_FLAGS & r->flags;
2541
2542 /* If userspace annotates copy, clips must come in pairs */
2543 if (flags & DRM_MODE_FB_DIRTY_ANNOTATE_COPY && (num_clips % 2)) {
2544 ret = -EINVAL;
2545 goto out_err1;
2546 }
2547
2548 if (num_clips && clips_ptr) {
Xi Wanga5cd3352011-11-23 01:12:01 -05002549 if (num_clips < 0 || num_clips > DRM_MODE_FB_DIRTY_MAX_CLIPS) {
2550 ret = -EINVAL;
2551 goto out_err1;
2552 }
Jakob Bornecrantz884840a2009-12-03 23:25:47 +00002553 clips = kzalloc(num_clips * sizeof(*clips), GFP_KERNEL);
2554 if (!clips) {
2555 ret = -ENOMEM;
2556 goto out_err1;
2557 }
2558
2559 ret = copy_from_user(clips, clips_ptr,
2560 num_clips * sizeof(*clips));
Dan Carpentere902a352010-06-04 12:23:21 +02002561 if (ret) {
2562 ret = -EFAULT;
Jakob Bornecrantz884840a2009-12-03 23:25:47 +00002563 goto out_err2;
Dan Carpentere902a352010-06-04 12:23:21 +02002564 }
Jakob Bornecrantz884840a2009-12-03 23:25:47 +00002565 }
2566
2567 if (fb->funcs->dirty) {
Daniel Vetter4ccf0972012-12-11 00:38:18 +01002568 drm_modeset_lock_all(dev);
Thomas Hellstrom02b00162010-10-05 12:43:02 +02002569 ret = fb->funcs->dirty(fb, file_priv, flags, r->color,
2570 clips, num_clips);
Daniel Vetter4ccf0972012-12-11 00:38:18 +01002571 drm_modeset_unlock_all(dev);
Jakob Bornecrantz884840a2009-12-03 23:25:47 +00002572 } else {
2573 ret = -ENOSYS;
Jakob Bornecrantz884840a2009-12-03 23:25:47 +00002574 }
2575
2576out_err2:
2577 kfree(clips);
2578out_err1:
Daniel Vetter4ccf0972012-12-11 00:38:18 +01002579 drm_framebuffer_unreference(fb);
2580
Jakob Bornecrantz884840a2009-12-03 23:25:47 +00002581 return ret;
2582}
2583
2584
Dave Airlief453ba02008-11-07 14:05:41 -08002585/**
2586 * drm_fb_release - remove and free the FBs on this file
Daniel Vetter065a50ed2012-12-02 00:09:18 +01002587 * @priv: drm file for the ioctl
Dave Airlief453ba02008-11-07 14:05:41 -08002588 *
Dave Airlief453ba02008-11-07 14:05:41 -08002589 * Destroy all the FBs associated with @filp.
2590 *
2591 * Called by the user via ioctl.
2592 *
2593 * RETURNS:
2594 * Zero on success, errno on failure.
2595 */
Kristian Høgsbergea39f832009-02-12 14:37:56 -05002596void drm_fb_release(struct drm_file *priv)
Dave Airlief453ba02008-11-07 14:05:41 -08002597{
Dave Airlief453ba02008-11-07 14:05:41 -08002598 struct drm_device *dev = priv->minor->dev;
2599 struct drm_framebuffer *fb, *tfb;
2600
Daniel Vetter4b096ac2012-12-10 21:19:18 +01002601 mutex_lock(&priv->fbs_lock);
Dave Airlief453ba02008-11-07 14:05:41 -08002602 list_for_each_entry_safe(fb, tfb, &priv->fbs, filp_head) {
Daniel Vetter2b677e82012-12-10 21:16:05 +01002603
2604 mutex_lock(&dev->mode_config.fb_lock);
2605 /* Mark fb as reaped, we still have a ref from fpriv->fbs. */
2606 __drm_framebuffer_unregister(dev, fb);
2607 mutex_unlock(&dev->mode_config.fb_lock);
2608
Daniel Vetter4b096ac2012-12-10 21:19:18 +01002609 list_del_init(&fb->filp_head);
Daniel Vetter2b677e82012-12-10 21:16:05 +01002610
2611 /* This will also drop the fpriv->fbs reference. */
Rob Clarkf7eff602012-09-05 21:48:38 +00002612 drm_framebuffer_remove(fb);
Dave Airlief453ba02008-11-07 14:05:41 -08002613 }
Daniel Vetter4b096ac2012-12-10 21:19:18 +01002614 mutex_unlock(&priv->fbs_lock);
Dave Airlief453ba02008-11-07 14:05:41 -08002615}
2616
Dave Airlief453ba02008-11-07 14:05:41 -08002617struct drm_property *drm_property_create(struct drm_device *dev, int flags,
2618 const char *name, int num_values)
2619{
2620 struct drm_property *property = NULL;
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +02002621 int ret;
Dave Airlief453ba02008-11-07 14:05:41 -08002622
2623 property = kzalloc(sizeof(struct drm_property), GFP_KERNEL);
2624 if (!property)
2625 return NULL;
2626
2627 if (num_values) {
2628 property->values = kzalloc(sizeof(uint64_t)*num_values, GFP_KERNEL);
2629 if (!property->values)
2630 goto fail;
2631 }
2632
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +02002633 ret = drm_mode_object_get(dev, &property->base, DRM_MODE_OBJECT_PROPERTY);
2634 if (ret)
2635 goto fail;
2636
Dave Airlief453ba02008-11-07 14:05:41 -08002637 property->flags = flags;
2638 property->num_values = num_values;
2639 INIT_LIST_HEAD(&property->enum_blob_list);
2640
Vinson Lee471dd2e2011-11-10 11:55:40 -08002641 if (name) {
Dave Airlief453ba02008-11-07 14:05:41 -08002642 strncpy(property->name, name, DRM_PROP_NAME_LEN);
Vinson Lee471dd2e2011-11-10 11:55:40 -08002643 property->name[DRM_PROP_NAME_LEN-1] = '\0';
2644 }
Dave Airlief453ba02008-11-07 14:05:41 -08002645
2646 list_add_tail(&property->head, &dev->mode_config.property_list);
2647 return property;
2648fail:
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +02002649 kfree(property->values);
Dave Airlief453ba02008-11-07 14:05:41 -08002650 kfree(property);
2651 return NULL;
2652}
2653EXPORT_SYMBOL(drm_property_create);
2654
Sascha Hauer4a67d392012-02-06 10:58:17 +01002655struct drm_property *drm_property_create_enum(struct drm_device *dev, int flags,
2656 const char *name,
2657 const struct drm_prop_enum_list *props,
2658 int num_values)
2659{
2660 struct drm_property *property;
2661 int i, ret;
2662
2663 flags |= DRM_MODE_PROP_ENUM;
2664
2665 property = drm_property_create(dev, flags, name, num_values);
2666 if (!property)
2667 return NULL;
2668
2669 for (i = 0; i < num_values; i++) {
2670 ret = drm_property_add_enum(property, i,
2671 props[i].type,
2672 props[i].name);
2673 if (ret) {
2674 drm_property_destroy(dev, property);
2675 return NULL;
2676 }
2677 }
2678
2679 return property;
2680}
2681EXPORT_SYMBOL(drm_property_create_enum);
2682
Rob Clark49e27542012-05-17 02:23:26 -06002683struct drm_property *drm_property_create_bitmask(struct drm_device *dev,
2684 int flags, const char *name,
2685 const struct drm_prop_enum_list *props,
2686 int num_values)
2687{
2688 struct drm_property *property;
2689 int i, ret;
2690
2691 flags |= DRM_MODE_PROP_BITMASK;
2692
2693 property = drm_property_create(dev, flags, name, num_values);
2694 if (!property)
2695 return NULL;
2696
2697 for (i = 0; i < num_values; i++) {
2698 ret = drm_property_add_enum(property, i,
2699 props[i].type,
2700 props[i].name);
2701 if (ret) {
2702 drm_property_destroy(dev, property);
2703 return NULL;
2704 }
2705 }
2706
2707 return property;
2708}
2709EXPORT_SYMBOL(drm_property_create_bitmask);
2710
Sascha Hauerd9bc3c02012-02-06 10:58:18 +01002711struct drm_property *drm_property_create_range(struct drm_device *dev, int flags,
2712 const char *name,
2713 uint64_t min, uint64_t max)
2714{
2715 struct drm_property *property;
2716
2717 flags |= DRM_MODE_PROP_RANGE;
2718
2719 property = drm_property_create(dev, flags, name, 2);
2720 if (!property)
2721 return NULL;
2722
2723 property->values[0] = min;
2724 property->values[1] = max;
2725
2726 return property;
2727}
2728EXPORT_SYMBOL(drm_property_create_range);
2729
Dave Airlief453ba02008-11-07 14:05:41 -08002730int drm_property_add_enum(struct drm_property *property, int index,
2731 uint64_t value, const char *name)
2732{
2733 struct drm_property_enum *prop_enum;
2734
Rob Clark49e27542012-05-17 02:23:26 -06002735 if (!(property->flags & (DRM_MODE_PROP_ENUM | DRM_MODE_PROP_BITMASK)))
2736 return -EINVAL;
2737
2738 /*
2739 * Bitmask enum properties have the additional constraint of values
2740 * from 0 to 63
2741 */
2742 if ((property->flags & DRM_MODE_PROP_BITMASK) && (value > 63))
Dave Airlief453ba02008-11-07 14:05:41 -08002743 return -EINVAL;
2744
2745 if (!list_empty(&property->enum_blob_list)) {
2746 list_for_each_entry(prop_enum, &property->enum_blob_list, head) {
2747 if (prop_enum->value == value) {
2748 strncpy(prop_enum->name, name, DRM_PROP_NAME_LEN);
2749 prop_enum->name[DRM_PROP_NAME_LEN-1] = '\0';
2750 return 0;
2751 }
2752 }
2753 }
2754
2755 prop_enum = kzalloc(sizeof(struct drm_property_enum), GFP_KERNEL);
2756 if (!prop_enum)
2757 return -ENOMEM;
2758
2759 strncpy(prop_enum->name, name, DRM_PROP_NAME_LEN);
2760 prop_enum->name[DRM_PROP_NAME_LEN-1] = '\0';
2761 prop_enum->value = value;
2762
2763 property->values[index] = value;
2764 list_add_tail(&prop_enum->head, &property->enum_blob_list);
2765 return 0;
2766}
2767EXPORT_SYMBOL(drm_property_add_enum);
2768
2769void drm_property_destroy(struct drm_device *dev, struct drm_property *property)
2770{
2771 struct drm_property_enum *prop_enum, *pt;
2772
2773 list_for_each_entry_safe(prop_enum, pt, &property->enum_blob_list, head) {
2774 list_del(&prop_enum->head);
2775 kfree(prop_enum);
2776 }
2777
2778 if (property->num_values)
2779 kfree(property->values);
2780 drm_mode_object_put(dev, &property->base);
2781 list_del(&property->head);
2782 kfree(property);
2783}
2784EXPORT_SYMBOL(drm_property_destroy);
2785
Paulo Zanonic5431882012-05-15 18:09:02 -03002786void drm_object_attach_property(struct drm_mode_object *obj,
2787 struct drm_property *property,
2788 uint64_t init_val)
2789{
Paulo Zanoni7f88a9b2012-05-15 18:09:04 -03002790 int count = obj->properties->count;
Paulo Zanonic5431882012-05-15 18:09:02 -03002791
Paulo Zanoni7f88a9b2012-05-15 18:09:04 -03002792 if (count == DRM_OBJECT_MAX_PROPERTY) {
2793 WARN(1, "Failed to attach object property (type: 0x%x). Please "
2794 "increase DRM_OBJECT_MAX_PROPERTY by 1 for each time "
2795 "you see this message on the same object type.\n",
2796 obj->type);
2797 return;
Paulo Zanonic5431882012-05-15 18:09:02 -03002798 }
2799
Paulo Zanoni7f88a9b2012-05-15 18:09:04 -03002800 obj->properties->ids[count] = property->base.id;
2801 obj->properties->values[count] = init_val;
2802 obj->properties->count++;
Paulo Zanonic5431882012-05-15 18:09:02 -03002803}
2804EXPORT_SYMBOL(drm_object_attach_property);
2805
2806int drm_object_property_set_value(struct drm_mode_object *obj,
2807 struct drm_property *property, uint64_t val)
2808{
2809 int i;
2810
Paulo Zanoni7f88a9b2012-05-15 18:09:04 -03002811 for (i = 0; i < obj->properties->count; i++) {
Paulo Zanonic5431882012-05-15 18:09:02 -03002812 if (obj->properties->ids[i] == property->base.id) {
2813 obj->properties->values[i] = val;
2814 return 0;
2815 }
2816 }
2817
2818 return -EINVAL;
2819}
2820EXPORT_SYMBOL(drm_object_property_set_value);
2821
2822int drm_object_property_get_value(struct drm_mode_object *obj,
2823 struct drm_property *property, uint64_t *val)
2824{
2825 int i;
2826
Paulo Zanoni7f88a9b2012-05-15 18:09:04 -03002827 for (i = 0; i < obj->properties->count; i++) {
Paulo Zanonic5431882012-05-15 18:09:02 -03002828 if (obj->properties->ids[i] == property->base.id) {
2829 *val = obj->properties->values[i];
2830 return 0;
2831 }
2832 }
2833
2834 return -EINVAL;
2835}
2836EXPORT_SYMBOL(drm_object_property_get_value);
2837
Dave Airlief453ba02008-11-07 14:05:41 -08002838int drm_mode_getproperty_ioctl(struct drm_device *dev,
2839 void *data, struct drm_file *file_priv)
2840{
2841 struct drm_mode_object *obj;
2842 struct drm_mode_get_property *out_resp = data;
2843 struct drm_property *property;
2844 int enum_count = 0;
2845 int blob_count = 0;
2846 int value_count = 0;
2847 int ret = 0, i;
2848 int copied;
2849 struct drm_property_enum *prop_enum;
2850 struct drm_mode_property_enum __user *enum_ptr;
2851 struct drm_property_blob *prop_blob;
Ville Syrjälä81f6c7f2011-12-20 00:06:42 +02002852 uint32_t __user *blob_id_ptr;
Dave Airlief453ba02008-11-07 14:05:41 -08002853 uint64_t __user *values_ptr;
2854 uint32_t __user *blob_length_ptr;
2855
Dave Airliefb3b06c2011-02-08 13:55:21 +10002856 if (!drm_core_check_feature(dev, DRIVER_MODESET))
2857 return -EINVAL;
2858
Daniel Vetter84849902012-12-02 00:28:11 +01002859 drm_modeset_lock_all(dev);
Dave Airlief453ba02008-11-07 14:05:41 -08002860 obj = drm_mode_object_find(dev, out_resp->prop_id, DRM_MODE_OBJECT_PROPERTY);
2861 if (!obj) {
2862 ret = -EINVAL;
2863 goto done;
2864 }
2865 property = obj_to_property(obj);
2866
Rob Clark49e27542012-05-17 02:23:26 -06002867 if (property->flags & (DRM_MODE_PROP_ENUM | DRM_MODE_PROP_BITMASK)) {
Dave Airlief453ba02008-11-07 14:05:41 -08002868 list_for_each_entry(prop_enum, &property->enum_blob_list, head)
2869 enum_count++;
2870 } else if (property->flags & DRM_MODE_PROP_BLOB) {
2871 list_for_each_entry(prop_blob, &property->enum_blob_list, head)
2872 blob_count++;
2873 }
2874
2875 value_count = property->num_values;
2876
2877 strncpy(out_resp->name, property->name, DRM_PROP_NAME_LEN);
2878 out_resp->name[DRM_PROP_NAME_LEN-1] = 0;
2879 out_resp->flags = property->flags;
2880
2881 if ((out_resp->count_values >= value_count) && value_count) {
Ville Syrjälä81f6c7f2011-12-20 00:06:42 +02002882 values_ptr = (uint64_t __user *)(unsigned long)out_resp->values_ptr;
Dave Airlief453ba02008-11-07 14:05:41 -08002883 for (i = 0; i < value_count; i++) {
2884 if (copy_to_user(values_ptr + i, &property->values[i], sizeof(uint64_t))) {
2885 ret = -EFAULT;
2886 goto done;
2887 }
2888 }
2889 }
2890 out_resp->count_values = value_count;
2891
Rob Clark49e27542012-05-17 02:23:26 -06002892 if (property->flags & (DRM_MODE_PROP_ENUM | DRM_MODE_PROP_BITMASK)) {
Dave Airlief453ba02008-11-07 14:05:41 -08002893 if ((out_resp->count_enum_blobs >= enum_count) && enum_count) {
2894 copied = 0;
Ville Syrjälä81f6c7f2011-12-20 00:06:42 +02002895 enum_ptr = (struct drm_mode_property_enum __user *)(unsigned long)out_resp->enum_blob_ptr;
Dave Airlief453ba02008-11-07 14:05:41 -08002896 list_for_each_entry(prop_enum, &property->enum_blob_list, head) {
2897
2898 if (copy_to_user(&enum_ptr[copied].value, &prop_enum->value, sizeof(uint64_t))) {
2899 ret = -EFAULT;
2900 goto done;
2901 }
2902
2903 if (copy_to_user(&enum_ptr[copied].name,
2904 &prop_enum->name, DRM_PROP_NAME_LEN)) {
2905 ret = -EFAULT;
2906 goto done;
2907 }
2908 copied++;
2909 }
2910 }
2911 out_resp->count_enum_blobs = enum_count;
2912 }
2913
2914 if (property->flags & DRM_MODE_PROP_BLOB) {
2915 if ((out_resp->count_enum_blobs >= blob_count) && blob_count) {
2916 copied = 0;
Ville Syrjälä81f6c7f2011-12-20 00:06:42 +02002917 blob_id_ptr = (uint32_t __user *)(unsigned long)out_resp->enum_blob_ptr;
2918 blob_length_ptr = (uint32_t __user *)(unsigned long)out_resp->values_ptr;
Dave Airlief453ba02008-11-07 14:05:41 -08002919
2920 list_for_each_entry(prop_blob, &property->enum_blob_list, head) {
2921 if (put_user(prop_blob->base.id, blob_id_ptr + copied)) {
2922 ret = -EFAULT;
2923 goto done;
2924 }
2925
2926 if (put_user(prop_blob->length, blob_length_ptr + copied)) {
2927 ret = -EFAULT;
2928 goto done;
2929 }
2930
2931 copied++;
2932 }
2933 }
2934 out_resp->count_enum_blobs = blob_count;
2935 }
2936done:
Daniel Vetter84849902012-12-02 00:28:11 +01002937 drm_modeset_unlock_all(dev);
Dave Airlief453ba02008-11-07 14:05:41 -08002938 return ret;
2939}
2940
2941static struct drm_property_blob *drm_property_create_blob(struct drm_device *dev, int length,
2942 void *data)
2943{
2944 struct drm_property_blob *blob;
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +02002945 int ret;
Dave Airlief453ba02008-11-07 14:05:41 -08002946
2947 if (!length || !data)
2948 return NULL;
2949
2950 blob = kzalloc(sizeof(struct drm_property_blob)+length, GFP_KERNEL);
2951 if (!blob)
2952 return NULL;
2953
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +02002954 ret = drm_mode_object_get(dev, &blob->base, DRM_MODE_OBJECT_BLOB);
2955 if (ret) {
2956 kfree(blob);
2957 return NULL;
2958 }
2959
Dave Airlief453ba02008-11-07 14:05:41 -08002960 blob->length = length;
2961
2962 memcpy(blob->data, data, length);
2963
Dave Airlief453ba02008-11-07 14:05:41 -08002964 list_add_tail(&blob->head, &dev->mode_config.property_blob_list);
2965 return blob;
2966}
2967
2968static void drm_property_destroy_blob(struct drm_device *dev,
2969 struct drm_property_blob *blob)
2970{
2971 drm_mode_object_put(dev, &blob->base);
2972 list_del(&blob->head);
2973 kfree(blob);
2974}
2975
2976int drm_mode_getblob_ioctl(struct drm_device *dev,
2977 void *data, struct drm_file *file_priv)
2978{
2979 struct drm_mode_object *obj;
2980 struct drm_mode_get_blob *out_resp = data;
2981 struct drm_property_blob *blob;
2982 int ret = 0;
Ville Syrjälä81f6c7f2011-12-20 00:06:42 +02002983 void __user *blob_ptr;
Dave Airlief453ba02008-11-07 14:05:41 -08002984
Dave Airliefb3b06c2011-02-08 13:55:21 +10002985 if (!drm_core_check_feature(dev, DRIVER_MODESET))
2986 return -EINVAL;
2987
Daniel Vetter84849902012-12-02 00:28:11 +01002988 drm_modeset_lock_all(dev);
Dave Airlief453ba02008-11-07 14:05:41 -08002989 obj = drm_mode_object_find(dev, out_resp->blob_id, DRM_MODE_OBJECT_BLOB);
2990 if (!obj) {
2991 ret = -EINVAL;
2992 goto done;
2993 }
2994 blob = obj_to_blob(obj);
2995
2996 if (out_resp->length == blob->length) {
Ville Syrjälä81f6c7f2011-12-20 00:06:42 +02002997 blob_ptr = (void __user *)(unsigned long)out_resp->data;
Dave Airlief453ba02008-11-07 14:05:41 -08002998 if (copy_to_user(blob_ptr, blob->data, blob->length)){
2999 ret = -EFAULT;
3000 goto done;
3001 }
3002 }
3003 out_resp->length = blob->length;
3004
3005done:
Daniel Vetter84849902012-12-02 00:28:11 +01003006 drm_modeset_unlock_all(dev);
Dave Airlief453ba02008-11-07 14:05:41 -08003007 return ret;
3008}
3009
3010int drm_mode_connector_update_edid_property(struct drm_connector *connector,
3011 struct edid *edid)
3012{
3013 struct drm_device *dev = connector->dev;
Laurent Pinchart4a1b0712012-05-17 13:27:21 +02003014 int ret, size;
Dave Airlief453ba02008-11-07 14:05:41 -08003015
3016 if (connector->edid_blob_ptr)
3017 drm_property_destroy_blob(dev, connector->edid_blob_ptr);
3018
3019 /* Delete edid, when there is none. */
3020 if (!edid) {
3021 connector->edid_blob_ptr = NULL;
Rob Clark58495562012-10-11 20:50:56 -05003022 ret = drm_object_property_set_value(&connector->base, dev->mode_config.edid_property, 0);
Dave Airlief453ba02008-11-07 14:05:41 -08003023 return ret;
3024 }
3025
Adam Jackson7466f4c2010-03-29 21:43:23 +00003026 size = EDID_LENGTH * (1 + edid->extensions);
3027 connector->edid_blob_ptr = drm_property_create_blob(connector->dev,
3028 size, edid);
Sachin Kamate655d122012-11-19 09:44:57 +00003029 if (!connector->edid_blob_ptr)
3030 return -EINVAL;
Dave Airlief453ba02008-11-07 14:05:41 -08003031
Rob Clark58495562012-10-11 20:50:56 -05003032 ret = drm_object_property_set_value(&connector->base,
Dave Airlief453ba02008-11-07 14:05:41 -08003033 dev->mode_config.edid_property,
3034 connector->edid_blob_ptr->base.id);
3035
3036 return ret;
3037}
3038EXPORT_SYMBOL(drm_mode_connector_update_edid_property);
3039
Paulo Zanoni26a34812012-05-15 18:08:59 -03003040static bool drm_property_change_is_valid(struct drm_property *property,
Ville Syrjälä592c20e2012-05-24 20:53:58 +03003041 uint64_t value)
Paulo Zanoni26a34812012-05-15 18:08:59 -03003042{
3043 if (property->flags & DRM_MODE_PROP_IMMUTABLE)
3044 return false;
3045 if (property->flags & DRM_MODE_PROP_RANGE) {
3046 if (value < property->values[0] || value > property->values[1])
3047 return false;
3048 return true;
Rob Clark49e27542012-05-17 02:23:26 -06003049 } else if (property->flags & DRM_MODE_PROP_BITMASK) {
3050 int i;
Ville Syrjälä592c20e2012-05-24 20:53:58 +03003051 uint64_t valid_mask = 0;
Rob Clark49e27542012-05-17 02:23:26 -06003052 for (i = 0; i < property->num_values; i++)
3053 valid_mask |= (1ULL << property->values[i]);
3054 return !(value & ~valid_mask);
Ville Syrjäläc4a56752012-10-25 18:05:06 +00003055 } else if (property->flags & DRM_MODE_PROP_BLOB) {
3056 /* Only the driver knows */
3057 return true;
Paulo Zanoni26a34812012-05-15 18:08:59 -03003058 } else {
3059 int i;
3060 for (i = 0; i < property->num_values; i++)
3061 if (property->values[i] == value)
3062 return true;
3063 return false;
3064 }
3065}
3066
Dave Airlief453ba02008-11-07 14:05:41 -08003067int drm_mode_connector_property_set_ioctl(struct drm_device *dev,
3068 void *data, struct drm_file *file_priv)
3069{
Paulo Zanoni0057d8d2012-05-15 18:09:03 -03003070 struct drm_mode_connector_set_property *conn_set_prop = data;
3071 struct drm_mode_obj_set_property obj_set_prop = {
3072 .value = conn_set_prop->value,
3073 .prop_id = conn_set_prop->prop_id,
3074 .obj_id = conn_set_prop->connector_id,
3075 .obj_type = DRM_MODE_OBJECT_CONNECTOR
3076 };
Dave Airlief453ba02008-11-07 14:05:41 -08003077
Paulo Zanoni0057d8d2012-05-15 18:09:03 -03003078 /* It does all the locking and checking we need */
3079 return drm_mode_obj_set_property_ioctl(dev, &obj_set_prop, file_priv);
Dave Airlief453ba02008-11-07 14:05:41 -08003080}
3081
Paulo Zanonic5431882012-05-15 18:09:02 -03003082static int drm_mode_connector_set_obj_prop(struct drm_mode_object *obj,
3083 struct drm_property *property,
3084 uint64_t value)
3085{
3086 int ret = -EINVAL;
3087 struct drm_connector *connector = obj_to_connector(obj);
3088
3089 /* Do DPMS ourselves */
3090 if (property == connector->dev->mode_config.dpms_property) {
3091 if (connector->funcs->dpms)
3092 (*connector->funcs->dpms)(connector, (int)value);
3093 ret = 0;
3094 } else if (connector->funcs->set_property)
3095 ret = connector->funcs->set_property(connector, property, value);
3096
3097 /* store the property value if successful */
3098 if (!ret)
Rob Clark58495562012-10-11 20:50:56 -05003099 drm_object_property_set_value(&connector->base, property, value);
Paulo Zanonic5431882012-05-15 18:09:02 -03003100 return ret;
3101}
3102
Paulo Zanonibffd9de02012-05-15 18:09:05 -03003103static int drm_mode_crtc_set_obj_prop(struct drm_mode_object *obj,
3104 struct drm_property *property,
3105 uint64_t value)
3106{
3107 int ret = -EINVAL;
3108 struct drm_crtc *crtc = obj_to_crtc(obj);
3109
3110 if (crtc->funcs->set_property)
3111 ret = crtc->funcs->set_property(crtc, property, value);
3112 if (!ret)
3113 drm_object_property_set_value(obj, property, value);
3114
3115 return ret;
3116}
3117
Rob Clark4d939142012-05-17 02:23:27 -06003118static int drm_mode_plane_set_obj_prop(struct drm_mode_object *obj,
3119 struct drm_property *property,
3120 uint64_t value)
3121{
3122 int ret = -EINVAL;
3123 struct drm_plane *plane = obj_to_plane(obj);
3124
3125 if (plane->funcs->set_property)
3126 ret = plane->funcs->set_property(plane, property, value);
3127 if (!ret)
3128 drm_object_property_set_value(obj, property, value);
3129
3130 return ret;
3131}
3132
Paulo Zanonic5431882012-05-15 18:09:02 -03003133int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data,
3134 struct drm_file *file_priv)
3135{
3136 struct drm_mode_obj_get_properties *arg = data;
3137 struct drm_mode_object *obj;
3138 int ret = 0;
3139 int i;
3140 int copied = 0;
3141 int props_count = 0;
3142 uint32_t __user *props_ptr;
3143 uint64_t __user *prop_values_ptr;
3144
3145 if (!drm_core_check_feature(dev, DRIVER_MODESET))
3146 return -EINVAL;
3147
Daniel Vetter84849902012-12-02 00:28:11 +01003148 drm_modeset_lock_all(dev);
Paulo Zanonic5431882012-05-15 18:09:02 -03003149
3150 obj = drm_mode_object_find(dev, arg->obj_id, arg->obj_type);
3151 if (!obj) {
3152 ret = -EINVAL;
3153 goto out;
3154 }
3155 if (!obj->properties) {
3156 ret = -EINVAL;
3157 goto out;
3158 }
3159
Paulo Zanoni7f88a9b2012-05-15 18:09:04 -03003160 props_count = obj->properties->count;
Paulo Zanonic5431882012-05-15 18:09:02 -03003161
3162 /* This ioctl is called twice, once to determine how much space is
3163 * needed, and the 2nd time to fill it. */
3164 if ((arg->count_props >= props_count) && props_count) {
3165 copied = 0;
3166 props_ptr = (uint32_t __user *)(unsigned long)(arg->props_ptr);
3167 prop_values_ptr = (uint64_t __user *)(unsigned long)
3168 (arg->prop_values_ptr);
3169 for (i = 0; i < props_count; i++) {
3170 if (put_user(obj->properties->ids[i],
3171 props_ptr + copied)) {
3172 ret = -EFAULT;
3173 goto out;
3174 }
3175 if (put_user(obj->properties->values[i],
3176 prop_values_ptr + copied)) {
3177 ret = -EFAULT;
3178 goto out;
3179 }
3180 copied++;
3181 }
3182 }
3183 arg->count_props = props_count;
3184out:
Daniel Vetter84849902012-12-02 00:28:11 +01003185 drm_modeset_unlock_all(dev);
Paulo Zanonic5431882012-05-15 18:09:02 -03003186 return ret;
3187}
3188
3189int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data,
3190 struct drm_file *file_priv)
3191{
3192 struct drm_mode_obj_set_property *arg = data;
3193 struct drm_mode_object *arg_obj;
3194 struct drm_mode_object *prop_obj;
3195 struct drm_property *property;
3196 int ret = -EINVAL;
3197 int i;
3198
3199 if (!drm_core_check_feature(dev, DRIVER_MODESET))
3200 return -EINVAL;
3201
Daniel Vetter84849902012-12-02 00:28:11 +01003202 drm_modeset_lock_all(dev);
Paulo Zanonic5431882012-05-15 18:09:02 -03003203
3204 arg_obj = drm_mode_object_find(dev, arg->obj_id, arg->obj_type);
3205 if (!arg_obj)
3206 goto out;
3207 if (!arg_obj->properties)
3208 goto out;
3209
Paulo Zanoni7f88a9b2012-05-15 18:09:04 -03003210 for (i = 0; i < arg_obj->properties->count; i++)
Paulo Zanonic5431882012-05-15 18:09:02 -03003211 if (arg_obj->properties->ids[i] == arg->prop_id)
3212 break;
3213
Paulo Zanoni7f88a9b2012-05-15 18:09:04 -03003214 if (i == arg_obj->properties->count)
Paulo Zanonic5431882012-05-15 18:09:02 -03003215 goto out;
3216
3217 prop_obj = drm_mode_object_find(dev, arg->prop_id,
3218 DRM_MODE_OBJECT_PROPERTY);
3219 if (!prop_obj)
3220 goto out;
3221 property = obj_to_property(prop_obj);
3222
3223 if (!drm_property_change_is_valid(property, arg->value))
3224 goto out;
3225
3226 switch (arg_obj->type) {
3227 case DRM_MODE_OBJECT_CONNECTOR:
3228 ret = drm_mode_connector_set_obj_prop(arg_obj, property,
3229 arg->value);
3230 break;
Paulo Zanonibffd9de02012-05-15 18:09:05 -03003231 case DRM_MODE_OBJECT_CRTC:
3232 ret = drm_mode_crtc_set_obj_prop(arg_obj, property, arg->value);
3233 break;
Rob Clark4d939142012-05-17 02:23:27 -06003234 case DRM_MODE_OBJECT_PLANE:
3235 ret = drm_mode_plane_set_obj_prop(arg_obj, property, arg->value);
3236 break;
Paulo Zanonic5431882012-05-15 18:09:02 -03003237 }
3238
3239out:
Daniel Vetter84849902012-12-02 00:28:11 +01003240 drm_modeset_unlock_all(dev);
Paulo Zanonic5431882012-05-15 18:09:02 -03003241 return ret;
3242}
3243
Dave Airlief453ba02008-11-07 14:05:41 -08003244int drm_mode_connector_attach_encoder(struct drm_connector *connector,
3245 struct drm_encoder *encoder)
3246{
3247 int i;
3248
3249 for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
3250 if (connector->encoder_ids[i] == 0) {
3251 connector->encoder_ids[i] = encoder->base.id;
3252 return 0;
3253 }
3254 }
3255 return -ENOMEM;
3256}
3257EXPORT_SYMBOL(drm_mode_connector_attach_encoder);
3258
3259void drm_mode_connector_detach_encoder(struct drm_connector *connector,
3260 struct drm_encoder *encoder)
3261{
3262 int i;
3263 for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
3264 if (connector->encoder_ids[i] == encoder->base.id) {
3265 connector->encoder_ids[i] = 0;
3266 if (connector->encoder == encoder)
3267 connector->encoder = NULL;
3268 break;
3269 }
3270 }
3271}
3272EXPORT_SYMBOL(drm_mode_connector_detach_encoder);
3273
Sascha Hauer4cae5b82012-02-01 11:38:23 +01003274int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc,
Dave Airlief453ba02008-11-07 14:05:41 -08003275 int gamma_size)
3276{
3277 crtc->gamma_size = gamma_size;
3278
3279 crtc->gamma_store = kzalloc(gamma_size * sizeof(uint16_t) * 3, GFP_KERNEL);
3280 if (!crtc->gamma_store) {
3281 crtc->gamma_size = 0;
Sascha Hauer4cae5b82012-02-01 11:38:23 +01003282 return -ENOMEM;
Dave Airlief453ba02008-11-07 14:05:41 -08003283 }
3284
Sascha Hauer4cae5b82012-02-01 11:38:23 +01003285 return 0;
Dave Airlief453ba02008-11-07 14:05:41 -08003286}
3287EXPORT_SYMBOL(drm_mode_crtc_set_gamma_size);
3288
3289int drm_mode_gamma_set_ioctl(struct drm_device *dev,
3290 void *data, struct drm_file *file_priv)
3291{
3292 struct drm_mode_crtc_lut *crtc_lut = data;
3293 struct drm_mode_object *obj;
3294 struct drm_crtc *crtc;
3295 void *r_base, *g_base, *b_base;
3296 int size;
3297 int ret = 0;
3298
Dave Airliefb3b06c2011-02-08 13:55:21 +10003299 if (!drm_core_check_feature(dev, DRIVER_MODESET))
3300 return -EINVAL;
3301
Daniel Vetter84849902012-12-02 00:28:11 +01003302 drm_modeset_lock_all(dev);
Dave Airlief453ba02008-11-07 14:05:41 -08003303 obj = drm_mode_object_find(dev, crtc_lut->crtc_id, DRM_MODE_OBJECT_CRTC);
3304 if (!obj) {
3305 ret = -EINVAL;
3306 goto out;
3307 }
3308 crtc = obj_to_crtc(obj);
3309
Laurent Pinchartebe0f242012-05-17 13:27:24 +02003310 if (crtc->funcs->gamma_set == NULL) {
3311 ret = -ENOSYS;
3312 goto out;
3313 }
3314
Dave Airlief453ba02008-11-07 14:05:41 -08003315 /* memcpy into gamma store */
3316 if (crtc_lut->gamma_size != crtc->gamma_size) {
3317 ret = -EINVAL;
3318 goto out;
3319 }
3320
3321 size = crtc_lut->gamma_size * (sizeof(uint16_t));
3322 r_base = crtc->gamma_store;
3323 if (copy_from_user(r_base, (void __user *)(unsigned long)crtc_lut->red, size)) {
3324 ret = -EFAULT;
3325 goto out;
3326 }
3327
3328 g_base = r_base + size;
3329 if (copy_from_user(g_base, (void __user *)(unsigned long)crtc_lut->green, size)) {
3330 ret = -EFAULT;
3331 goto out;
3332 }
3333
3334 b_base = g_base + size;
3335 if (copy_from_user(b_base, (void __user *)(unsigned long)crtc_lut->blue, size)) {
3336 ret = -EFAULT;
3337 goto out;
3338 }
3339
James Simmons72034252010-08-03 01:33:19 +01003340 crtc->funcs->gamma_set(crtc, r_base, g_base, b_base, 0, crtc->gamma_size);
Dave Airlief453ba02008-11-07 14:05:41 -08003341
3342out:
Daniel Vetter84849902012-12-02 00:28:11 +01003343 drm_modeset_unlock_all(dev);
Dave Airlief453ba02008-11-07 14:05:41 -08003344 return ret;
3345
3346}
3347
3348int drm_mode_gamma_get_ioctl(struct drm_device *dev,
3349 void *data, struct drm_file *file_priv)
3350{
3351 struct drm_mode_crtc_lut *crtc_lut = data;
3352 struct drm_mode_object *obj;
3353 struct drm_crtc *crtc;
3354 void *r_base, *g_base, *b_base;
3355 int size;
3356 int ret = 0;
3357
Dave Airliefb3b06c2011-02-08 13:55:21 +10003358 if (!drm_core_check_feature(dev, DRIVER_MODESET))
3359 return -EINVAL;
3360
Daniel Vetter84849902012-12-02 00:28:11 +01003361 drm_modeset_lock_all(dev);
Dave Airlief453ba02008-11-07 14:05:41 -08003362 obj = drm_mode_object_find(dev, crtc_lut->crtc_id, DRM_MODE_OBJECT_CRTC);
3363 if (!obj) {
3364 ret = -EINVAL;
3365 goto out;
3366 }
3367 crtc = obj_to_crtc(obj);
3368
3369 /* memcpy into gamma store */
3370 if (crtc_lut->gamma_size != crtc->gamma_size) {
3371 ret = -EINVAL;
3372 goto out;
3373 }
3374
3375 size = crtc_lut->gamma_size * (sizeof(uint16_t));
3376 r_base = crtc->gamma_store;
3377 if (copy_to_user((void __user *)(unsigned long)crtc_lut->red, r_base, size)) {
3378 ret = -EFAULT;
3379 goto out;
3380 }
3381
3382 g_base = r_base + size;
3383 if (copy_to_user((void __user *)(unsigned long)crtc_lut->green, g_base, size)) {
3384 ret = -EFAULT;
3385 goto out;
3386 }
3387
3388 b_base = g_base + size;
3389 if (copy_to_user((void __user *)(unsigned long)crtc_lut->blue, b_base, size)) {
3390 ret = -EFAULT;
3391 goto out;
3392 }
3393out:
Daniel Vetter84849902012-12-02 00:28:11 +01003394 drm_modeset_unlock_all(dev);
Dave Airlief453ba02008-11-07 14:05:41 -08003395 return ret;
3396}
Kristian Høgsbergd91d8a32009-11-17 12:43:55 -05003397
3398int drm_mode_page_flip_ioctl(struct drm_device *dev,
3399 void *data, struct drm_file *file_priv)
3400{
3401 struct drm_mode_crtc_page_flip *page_flip = data;
3402 struct drm_mode_object *obj;
3403 struct drm_crtc *crtc;
Daniel Vetterb0d12322012-12-11 01:07:12 +01003404 struct drm_framebuffer *fb = NULL, *old_fb = NULL;
Kristian Høgsbergd91d8a32009-11-17 12:43:55 -05003405 struct drm_pending_vblank_event *e = NULL;
3406 unsigned long flags;
Rob Clark7c80e122012-09-04 16:35:56 +00003407 int hdisplay, vdisplay;
Kristian Høgsbergd91d8a32009-11-17 12:43:55 -05003408 int ret = -EINVAL;
3409
3410 if (page_flip->flags & ~DRM_MODE_PAGE_FLIP_FLAGS ||
3411 page_flip->reserved != 0)
3412 return -EINVAL;
3413
Kristian Høgsbergd91d8a32009-11-17 12:43:55 -05003414 obj = drm_mode_object_find(dev, page_flip->crtc_id, DRM_MODE_OBJECT_CRTC);
3415 if (!obj)
Daniel Vetterb4d5e7d2012-12-11 16:59:31 +01003416 return -EINVAL;
Kristian Høgsbergd91d8a32009-11-17 12:43:55 -05003417 crtc = obj_to_crtc(obj);
3418
Daniel Vetterb4d5e7d2012-12-11 16:59:31 +01003419 mutex_lock(&crtc->mutex);
Chris Wilson90c1efd2010-07-17 20:23:26 +01003420 if (crtc->fb == NULL) {
3421 /* The framebuffer is currently unbound, presumably
3422 * due to a hotplug event, that userspace has not
3423 * yet discovered.
3424 */
3425 ret = -EBUSY;
3426 goto out;
3427 }
3428
Kristian Høgsbergd91d8a32009-11-17 12:43:55 -05003429 if (crtc->funcs->page_flip == NULL)
3430 goto out;
3431
Daniel Vetter786b99e2012-12-02 21:53:40 +01003432 fb = drm_framebuffer_lookup(dev, page_flip->fb_id);
3433 if (!fb)
Kristian Høgsbergd91d8a32009-11-17 12:43:55 -05003434 goto out;
Kristian Høgsbergd91d8a32009-11-17 12:43:55 -05003435
Rob Clark7c80e122012-09-04 16:35:56 +00003436 hdisplay = crtc->mode.hdisplay;
3437 vdisplay = crtc->mode.vdisplay;
3438
3439 if (crtc->invert_dimensions)
3440 swap(hdisplay, vdisplay);
3441
3442 if (hdisplay > fb->width ||
3443 vdisplay > fb->height ||
3444 crtc->x > fb->width - hdisplay ||
3445 crtc->y > fb->height - vdisplay) {
3446 DRM_DEBUG_KMS("Invalid fb size %ux%u for CRTC viewport %ux%u+%d+%d%s.\n",
3447 fb->width, fb->height, hdisplay, vdisplay, crtc->x, crtc->y,
3448 crtc->invert_dimensions ? " (inverted)" : "");
Ville Syrjälä5f61bb42012-03-13 12:35:45 +02003449 ret = -ENOSPC;
3450 goto out;
3451 }
3452
Laurent Pinchart909d9cd2013-04-22 01:38:46 +02003453 if (crtc->fb->pixel_format != fb->pixel_format) {
3454 DRM_DEBUG_KMS("Page flip is not allowed to change frame buffer format.\n");
3455 ret = -EINVAL;
3456 goto out;
3457 }
3458
Kristian Høgsbergd91d8a32009-11-17 12:43:55 -05003459 if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) {
3460 ret = -ENOMEM;
3461 spin_lock_irqsave(&dev->event_lock, flags);
3462 if (file_priv->event_space < sizeof e->event) {
3463 spin_unlock_irqrestore(&dev->event_lock, flags);
3464 goto out;
3465 }
3466 file_priv->event_space -= sizeof e->event;
3467 spin_unlock_irqrestore(&dev->event_lock, flags);
3468
3469 e = kzalloc(sizeof *e, GFP_KERNEL);
3470 if (e == NULL) {
3471 spin_lock_irqsave(&dev->event_lock, flags);
3472 file_priv->event_space += sizeof e->event;
3473 spin_unlock_irqrestore(&dev->event_lock, flags);
3474 goto out;
3475 }
3476
Jesse Barnes7bd4d7b2009-11-19 10:50:22 -08003477 e->event.base.type = DRM_EVENT_FLIP_COMPLETE;
Kristian Høgsbergd91d8a32009-11-17 12:43:55 -05003478 e->event.base.length = sizeof e->event;
3479 e->event.user_data = page_flip->user_data;
3480 e->base.event = &e->event.base;
3481 e->base.file_priv = file_priv;
3482 e->base.destroy =
3483 (void (*) (struct drm_pending_event *)) kfree;
3484 }
3485
Daniel Vetterb0d12322012-12-11 01:07:12 +01003486 old_fb = crtc->fb;
Kristian Høgsbergd91d8a32009-11-17 12:43:55 -05003487 ret = crtc->funcs->page_flip(crtc, fb, e);
3488 if (ret) {
Joonyoung Shimaef6a7e2012-04-18 13:47:02 +09003489 if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) {
3490 spin_lock_irqsave(&dev->event_lock, flags);
3491 file_priv->event_space += sizeof e->event;
3492 spin_unlock_irqrestore(&dev->event_lock, flags);
3493 kfree(e);
3494 }
Daniel Vetterb0d12322012-12-11 01:07:12 +01003495 /* Keep the old fb, don't unref it. */
3496 old_fb = NULL;
3497 } else {
Thierry Reding8cf1e982013-02-13 16:08:33 +01003498 /*
3499 * Warn if the driver hasn't properly updated the crtc->fb
3500 * field to reflect that the new framebuffer is now used.
3501 * Failing to do so will screw with the reference counting
3502 * on framebuffers.
3503 */
3504 WARN_ON(crtc->fb != fb);
Daniel Vetterb0d12322012-12-11 01:07:12 +01003505 /* Unref only the old framebuffer. */
3506 fb = NULL;
Kristian Høgsbergd91d8a32009-11-17 12:43:55 -05003507 }
3508
3509out:
Daniel Vetterb0d12322012-12-11 01:07:12 +01003510 if (fb)
3511 drm_framebuffer_unreference(fb);
3512 if (old_fb)
3513 drm_framebuffer_unreference(old_fb);
Daniel Vetterb4d5e7d2012-12-11 16:59:31 +01003514 mutex_unlock(&crtc->mutex);
3515
Kristian Høgsbergd91d8a32009-11-17 12:43:55 -05003516 return ret;
3517}
Chris Wilsoneb033552011-01-24 15:11:08 +00003518
3519void drm_mode_config_reset(struct drm_device *dev)
3520{
3521 struct drm_crtc *crtc;
3522 struct drm_encoder *encoder;
3523 struct drm_connector *connector;
3524
3525 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
3526 if (crtc->funcs->reset)
3527 crtc->funcs->reset(crtc);
3528
3529 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head)
3530 if (encoder->funcs->reset)
3531 encoder->funcs->reset(encoder);
3532
Daniel Vetter5e2cb2f2012-10-23 18:23:35 +00003533 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
3534 connector->status = connector_status_unknown;
3535
Chris Wilsoneb033552011-01-24 15:11:08 +00003536 if (connector->funcs->reset)
3537 connector->funcs->reset(connector);
Daniel Vetter5e2cb2f2012-10-23 18:23:35 +00003538 }
Chris Wilsoneb033552011-01-24 15:11:08 +00003539}
3540EXPORT_SYMBOL(drm_mode_config_reset);
Dave Airlieff72145b2011-02-07 12:16:14 +10003541
3542int drm_mode_create_dumb_ioctl(struct drm_device *dev,
3543 void *data, struct drm_file *file_priv)
3544{
3545 struct drm_mode_create_dumb *args = data;
3546
3547 if (!dev->driver->dumb_create)
3548 return -ENOSYS;
3549 return dev->driver->dumb_create(file_priv, dev, args);
3550}
3551
3552int drm_mode_mmap_dumb_ioctl(struct drm_device *dev,
3553 void *data, struct drm_file *file_priv)
3554{
3555 struct drm_mode_map_dumb *args = data;
3556
3557 /* call driver ioctl to get mmap offset */
3558 if (!dev->driver->dumb_map_offset)
3559 return -ENOSYS;
3560
3561 return dev->driver->dumb_map_offset(file_priv, dev, args->handle, &args->offset);
3562}
3563
3564int drm_mode_destroy_dumb_ioctl(struct drm_device *dev,
3565 void *data, struct drm_file *file_priv)
3566{
3567 struct drm_mode_destroy_dumb *args = data;
3568
3569 if (!dev->driver->dumb_destroy)
3570 return -ENOSYS;
3571
3572 return dev->driver->dumb_destroy(file_priv, dev, args->handle);
3573}
Dave Airlie248dbc22011-11-29 20:02:54 +00003574
3575/*
3576 * Just need to support RGB formats here for compat with code that doesn't
3577 * use pixel formats directly yet.
3578 */
3579void drm_fb_get_bpp_depth(uint32_t format, unsigned int *depth,
3580 int *bpp)
3581{
3582 switch (format) {
Ville Syrjäläc51a6bc2013-01-31 19:43:37 +02003583 case DRM_FORMAT_C8:
Ville Syrjälä04b39242011-11-17 18:05:13 +02003584 case DRM_FORMAT_RGB332:
3585 case DRM_FORMAT_BGR233:
Dave Airlie248dbc22011-11-29 20:02:54 +00003586 *depth = 8;
3587 *bpp = 8;
3588 break;
Ville Syrjälä04b39242011-11-17 18:05:13 +02003589 case DRM_FORMAT_XRGB1555:
3590 case DRM_FORMAT_XBGR1555:
3591 case DRM_FORMAT_RGBX5551:
3592 case DRM_FORMAT_BGRX5551:
3593 case DRM_FORMAT_ARGB1555:
3594 case DRM_FORMAT_ABGR1555:
3595 case DRM_FORMAT_RGBA5551:
3596 case DRM_FORMAT_BGRA5551:
Dave Airlie248dbc22011-11-29 20:02:54 +00003597 *depth = 15;
3598 *bpp = 16;
3599 break;
Ville Syrjälä04b39242011-11-17 18:05:13 +02003600 case DRM_FORMAT_RGB565:
3601 case DRM_FORMAT_BGR565:
Dave Airlie248dbc22011-11-29 20:02:54 +00003602 *depth = 16;
3603 *bpp = 16;
3604 break;
Ville Syrjälä04b39242011-11-17 18:05:13 +02003605 case DRM_FORMAT_RGB888:
3606 case DRM_FORMAT_BGR888:
3607 *depth = 24;
3608 *bpp = 24;
3609 break;
3610 case DRM_FORMAT_XRGB8888:
3611 case DRM_FORMAT_XBGR8888:
3612 case DRM_FORMAT_RGBX8888:
3613 case DRM_FORMAT_BGRX8888:
Dave Airlie248dbc22011-11-29 20:02:54 +00003614 *depth = 24;
3615 *bpp = 32;
3616 break;
Ville Syrjälä04b39242011-11-17 18:05:13 +02003617 case DRM_FORMAT_XRGB2101010:
3618 case DRM_FORMAT_XBGR2101010:
3619 case DRM_FORMAT_RGBX1010102:
3620 case DRM_FORMAT_BGRX1010102:
3621 case DRM_FORMAT_ARGB2101010:
3622 case DRM_FORMAT_ABGR2101010:
3623 case DRM_FORMAT_RGBA1010102:
3624 case DRM_FORMAT_BGRA1010102:
Dave Airlie248dbc22011-11-29 20:02:54 +00003625 *depth = 30;
3626 *bpp = 32;
3627 break;
Ville Syrjälä04b39242011-11-17 18:05:13 +02003628 case DRM_FORMAT_ARGB8888:
3629 case DRM_FORMAT_ABGR8888:
3630 case DRM_FORMAT_RGBA8888:
3631 case DRM_FORMAT_BGRA8888:
Dave Airlie248dbc22011-11-29 20:02:54 +00003632 *depth = 32;
3633 *bpp = 32;
3634 break;
3635 default:
3636 DRM_DEBUG_KMS("unsupported pixel format\n");
3637 *depth = 0;
3638 *bpp = 0;
3639 break;
3640 }
3641}
3642EXPORT_SYMBOL(drm_fb_get_bpp_depth);
Ville Syrjälä141670e2012-04-05 21:35:15 +03003643
3644/**
3645 * drm_format_num_planes - get the number of planes for format
3646 * @format: pixel format (DRM_FORMAT_*)
3647 *
3648 * RETURNS:
3649 * The number of planes used by the specified pixel format.
3650 */
3651int drm_format_num_planes(uint32_t format)
3652{
3653 switch (format) {
3654 case DRM_FORMAT_YUV410:
3655 case DRM_FORMAT_YVU410:
3656 case DRM_FORMAT_YUV411:
3657 case DRM_FORMAT_YVU411:
3658 case DRM_FORMAT_YUV420:
3659 case DRM_FORMAT_YVU420:
3660 case DRM_FORMAT_YUV422:
3661 case DRM_FORMAT_YVU422:
3662 case DRM_FORMAT_YUV444:
3663 case DRM_FORMAT_YVU444:
3664 return 3;
3665 case DRM_FORMAT_NV12:
3666 case DRM_FORMAT_NV21:
3667 case DRM_FORMAT_NV16:
3668 case DRM_FORMAT_NV61:
Laurent Pinchartba623f62012-05-18 23:47:40 +02003669 case DRM_FORMAT_NV24:
3670 case DRM_FORMAT_NV42:
Ville Syrjälä141670e2012-04-05 21:35:15 +03003671 return 2;
3672 default:
3673 return 1;
3674 }
3675}
3676EXPORT_SYMBOL(drm_format_num_planes);
Ville Syrjälä5a86bd52012-04-05 21:35:16 +03003677
3678/**
3679 * drm_format_plane_cpp - determine the bytes per pixel value
3680 * @format: pixel format (DRM_FORMAT_*)
3681 * @plane: plane index
3682 *
3683 * RETURNS:
3684 * The bytes per pixel value for the specified plane.
3685 */
3686int drm_format_plane_cpp(uint32_t format, int plane)
3687{
3688 unsigned int depth;
3689 int bpp;
3690
3691 if (plane >= drm_format_num_planes(format))
3692 return 0;
3693
3694 switch (format) {
3695 case DRM_FORMAT_YUYV:
3696 case DRM_FORMAT_YVYU:
3697 case DRM_FORMAT_UYVY:
3698 case DRM_FORMAT_VYUY:
3699 return 2;
3700 case DRM_FORMAT_NV12:
3701 case DRM_FORMAT_NV21:
3702 case DRM_FORMAT_NV16:
3703 case DRM_FORMAT_NV61:
Laurent Pinchartba623f62012-05-18 23:47:40 +02003704 case DRM_FORMAT_NV24:
3705 case DRM_FORMAT_NV42:
Ville Syrjälä5a86bd52012-04-05 21:35:16 +03003706 return plane ? 2 : 1;
3707 case DRM_FORMAT_YUV410:
3708 case DRM_FORMAT_YVU410:
3709 case DRM_FORMAT_YUV411:
3710 case DRM_FORMAT_YVU411:
3711 case DRM_FORMAT_YUV420:
3712 case DRM_FORMAT_YVU420:
3713 case DRM_FORMAT_YUV422:
3714 case DRM_FORMAT_YVU422:
3715 case DRM_FORMAT_YUV444:
3716 case DRM_FORMAT_YVU444:
3717 return 1;
3718 default:
3719 drm_fb_get_bpp_depth(format, &depth, &bpp);
3720 return bpp >> 3;
3721 }
3722}
3723EXPORT_SYMBOL(drm_format_plane_cpp);
Ville Syrjälä01b68b02012-04-05 21:35:17 +03003724
3725/**
3726 * drm_format_horz_chroma_subsampling - get the horizontal chroma subsampling factor
3727 * @format: pixel format (DRM_FORMAT_*)
3728 *
3729 * RETURNS:
3730 * The horizontal chroma subsampling factor for the
3731 * specified pixel format.
3732 */
3733int drm_format_horz_chroma_subsampling(uint32_t format)
3734{
3735 switch (format) {
3736 case DRM_FORMAT_YUV411:
3737 case DRM_FORMAT_YVU411:
3738 case DRM_FORMAT_YUV410:
3739 case DRM_FORMAT_YVU410:
3740 return 4;
3741 case DRM_FORMAT_YUYV:
3742 case DRM_FORMAT_YVYU:
3743 case DRM_FORMAT_UYVY:
3744 case DRM_FORMAT_VYUY:
3745 case DRM_FORMAT_NV12:
3746 case DRM_FORMAT_NV21:
3747 case DRM_FORMAT_NV16:
3748 case DRM_FORMAT_NV61:
3749 case DRM_FORMAT_YUV422:
3750 case DRM_FORMAT_YVU422:
3751 case DRM_FORMAT_YUV420:
3752 case DRM_FORMAT_YVU420:
3753 return 2;
3754 default:
3755 return 1;
3756 }
3757}
3758EXPORT_SYMBOL(drm_format_horz_chroma_subsampling);
3759
3760/**
3761 * drm_format_vert_chroma_subsampling - get the vertical chroma subsampling factor
3762 * @format: pixel format (DRM_FORMAT_*)
3763 *
3764 * RETURNS:
3765 * The vertical chroma subsampling factor for the
3766 * specified pixel format.
3767 */
3768int drm_format_vert_chroma_subsampling(uint32_t format)
3769{
3770 switch (format) {
3771 case DRM_FORMAT_YUV410:
3772 case DRM_FORMAT_YVU410:
3773 return 4;
3774 case DRM_FORMAT_YUV420:
3775 case DRM_FORMAT_YVU420:
3776 case DRM_FORMAT_NV12:
3777 case DRM_FORMAT_NV21:
3778 return 2;
3779 default:
3780 return 1;
3781 }
3782}
3783EXPORT_SYMBOL(drm_format_vert_chroma_subsampling);
Laurent Pinchart87d24fc2013-04-15 15:37:16 +02003784
3785/**
3786 * drm_mode_config_init - initialize DRM mode_configuration structure
3787 * @dev: DRM device
3788 *
3789 * Initialize @dev's mode_config structure, used for tracking the graphics
3790 * configuration of @dev.
3791 *
3792 * Since this initializes the modeset locks, no locking is possible. Which is no
3793 * problem, since this should happen single threaded at init time. It is the
3794 * driver's problem to ensure this guarantee.
3795 *
3796 */
3797void drm_mode_config_init(struct drm_device *dev)
3798{
3799 mutex_init(&dev->mode_config.mutex);
3800 mutex_init(&dev->mode_config.idr_mutex);
3801 mutex_init(&dev->mode_config.fb_lock);
3802 INIT_LIST_HEAD(&dev->mode_config.fb_list);
3803 INIT_LIST_HEAD(&dev->mode_config.crtc_list);
3804 INIT_LIST_HEAD(&dev->mode_config.connector_list);
3805 INIT_LIST_HEAD(&dev->mode_config.encoder_list);
3806 INIT_LIST_HEAD(&dev->mode_config.property_list);
3807 INIT_LIST_HEAD(&dev->mode_config.property_blob_list);
3808 INIT_LIST_HEAD(&dev->mode_config.plane_list);
3809 idr_init(&dev->mode_config.crtc_idr);
3810
3811 drm_modeset_lock_all(dev);
3812 drm_mode_create_standard_connector_properties(dev);
3813 drm_modeset_unlock_all(dev);
3814
3815 /* Just to be sure */
3816 dev->mode_config.num_fb = 0;
3817 dev->mode_config.num_connector = 0;
3818 dev->mode_config.num_crtc = 0;
3819 dev->mode_config.num_encoder = 0;
3820}
3821EXPORT_SYMBOL(drm_mode_config_init);
3822
3823/**
3824 * drm_mode_config_cleanup - free up DRM mode_config info
3825 * @dev: DRM device
3826 *
3827 * Free up all the connectors and CRTCs associated with this DRM device, then
3828 * free up the framebuffers and associated buffer objects.
3829 *
3830 * Note that since this /should/ happen single-threaded at driver/device
3831 * teardown time, no locking is required. It's the driver's job to ensure that
3832 * this guarantee actually holds true.
3833 *
3834 * FIXME: cleanup any dangling user buffer objects too
3835 */
3836void drm_mode_config_cleanup(struct drm_device *dev)
3837{
3838 struct drm_connector *connector, *ot;
3839 struct drm_crtc *crtc, *ct;
3840 struct drm_encoder *encoder, *enct;
3841 struct drm_framebuffer *fb, *fbt;
3842 struct drm_property *property, *pt;
3843 struct drm_property_blob *blob, *bt;
3844 struct drm_plane *plane, *plt;
3845
3846 list_for_each_entry_safe(encoder, enct, &dev->mode_config.encoder_list,
3847 head) {
3848 encoder->funcs->destroy(encoder);
3849 }
3850
3851 list_for_each_entry_safe(connector, ot,
3852 &dev->mode_config.connector_list, head) {
3853 connector->funcs->destroy(connector);
3854 }
3855
3856 list_for_each_entry_safe(property, pt, &dev->mode_config.property_list,
3857 head) {
3858 drm_property_destroy(dev, property);
3859 }
3860
3861 list_for_each_entry_safe(blob, bt, &dev->mode_config.property_blob_list,
3862 head) {
3863 drm_property_destroy_blob(dev, blob);
3864 }
3865
3866 /*
3867 * Single-threaded teardown context, so it's not required to grab the
3868 * fb_lock to protect against concurrent fb_list access. Contrary, it
3869 * would actually deadlock with the drm_framebuffer_cleanup function.
3870 *
3871 * Also, if there are any framebuffers left, that's a driver leak now,
3872 * so politely WARN about this.
3873 */
3874 WARN_ON(!list_empty(&dev->mode_config.fb_list));
3875 list_for_each_entry_safe(fb, fbt, &dev->mode_config.fb_list, head) {
3876 drm_framebuffer_remove(fb);
3877 }
3878
3879 list_for_each_entry_safe(plane, plt, &dev->mode_config.plane_list,
3880 head) {
3881 plane->funcs->destroy(plane);
3882 }
3883
3884 list_for_each_entry_safe(crtc, ct, &dev->mode_config.crtc_list, head) {
3885 crtc->funcs->destroy(crtc);
3886 }
3887
3888 idr_destroy(&dev->mode_config.crtc_idr);
3889}
3890EXPORT_SYMBOL(drm_mode_config_cleanup);