blob: 287cd82f9d75f87bda956256f88a945c86271bfe [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
81 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
82 WARN_ON(!mutex_is_locked(&crtc->mutex));
83
84 WARN_ON(!mutex_is_locked(&dev->mode_config.mutex));
85}
86EXPORT_SYMBOL(drm_warn_on_modeset_not_all_locked);
87
Dave Airlief453ba02008-11-07 14:05:41 -080088/* Avoid boilerplate. I'm tired of typing. */
89#define DRM_ENUM_NAME_FN(fnname, list) \
90 char *fnname(int val) \
91 { \
92 int i; \
93 for (i = 0; i < ARRAY_SIZE(list); i++) { \
94 if (list[i].type == val) \
95 return list[i].name; \
96 } \
97 return "(unknown)"; \
98 }
99
100/*
101 * Global properties
102 */
103static struct drm_prop_enum_list drm_dpms_enum_list[] =
104{ { DRM_MODE_DPMS_ON, "On" },
105 { DRM_MODE_DPMS_STANDBY, "Standby" },
106 { DRM_MODE_DPMS_SUSPEND, "Suspend" },
107 { DRM_MODE_DPMS_OFF, "Off" }
108};
109
110DRM_ENUM_NAME_FN(drm_get_dpms_name, drm_dpms_enum_list)
111
112/*
113 * Optional properties
114 */
115static struct drm_prop_enum_list drm_scaling_mode_enum_list[] =
116{
Jesse Barnes53bd8382009-07-01 10:04:40 -0700117 { DRM_MODE_SCALE_NONE, "None" },
118 { DRM_MODE_SCALE_FULLSCREEN, "Full" },
119 { DRM_MODE_SCALE_CENTER, "Center" },
120 { DRM_MODE_SCALE_ASPECT, "Full aspect" },
Dave Airlief453ba02008-11-07 14:05:41 -0800121};
122
123static struct drm_prop_enum_list drm_dithering_mode_enum_list[] =
124{
125 { DRM_MODE_DITHERING_OFF, "Off" },
126 { DRM_MODE_DITHERING_ON, "On" },
Ben Skeggs92897b52010-07-16 15:09:17 +1000127 { DRM_MODE_DITHERING_AUTO, "Automatic" },
Dave Airlief453ba02008-11-07 14:05:41 -0800128};
129
130/*
131 * Non-global properties, but "required" for certain connectors.
132 */
133static struct drm_prop_enum_list drm_dvi_i_select_enum_list[] =
134{
135 { DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" }, /* DVI-I and TV-out */
136 { DRM_MODE_SUBCONNECTOR_DVID, "DVI-D" }, /* DVI-I */
137 { DRM_MODE_SUBCONNECTOR_DVIA, "DVI-A" }, /* DVI-I */
138};
139
140DRM_ENUM_NAME_FN(drm_get_dvi_i_select_name, drm_dvi_i_select_enum_list)
141
142static struct drm_prop_enum_list drm_dvi_i_subconnector_enum_list[] =
143{
144 { DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" }, /* DVI-I and TV-out */
145 { DRM_MODE_SUBCONNECTOR_DVID, "DVI-D" }, /* DVI-I */
146 { DRM_MODE_SUBCONNECTOR_DVIA, "DVI-A" }, /* DVI-I */
147};
148
149DRM_ENUM_NAME_FN(drm_get_dvi_i_subconnector_name,
150 drm_dvi_i_subconnector_enum_list)
151
152static struct drm_prop_enum_list drm_tv_select_enum_list[] =
153{
154 { DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" }, /* DVI-I and TV-out */
155 { DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */
156 { DRM_MODE_SUBCONNECTOR_SVIDEO, "SVIDEO" }, /* TV-out */
157 { DRM_MODE_SUBCONNECTOR_Component, "Component" }, /* TV-out */
Francisco Jerezaeaa1ad2009-08-02 04:19:19 +0200158 { DRM_MODE_SUBCONNECTOR_SCART, "SCART" }, /* TV-out */
Dave Airlief453ba02008-11-07 14:05:41 -0800159};
160
161DRM_ENUM_NAME_FN(drm_get_tv_select_name, drm_tv_select_enum_list)
162
163static struct drm_prop_enum_list drm_tv_subconnector_enum_list[] =
164{
165 { DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" }, /* DVI-I and TV-out */
166 { DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */
167 { DRM_MODE_SUBCONNECTOR_SVIDEO, "SVIDEO" }, /* TV-out */
168 { DRM_MODE_SUBCONNECTOR_Component, "Component" }, /* TV-out */
Francisco Jerezaeaa1ad2009-08-02 04:19:19 +0200169 { DRM_MODE_SUBCONNECTOR_SCART, "SCART" }, /* TV-out */
Dave Airlief453ba02008-11-07 14:05:41 -0800170};
171
172DRM_ENUM_NAME_FN(drm_get_tv_subconnector_name,
173 drm_tv_subconnector_enum_list)
174
Jakob Bornecrantz884840a2009-12-03 23:25:47 +0000175static struct drm_prop_enum_list drm_dirty_info_enum_list[] = {
176 { DRM_MODE_DIRTY_OFF, "Off" },
177 { DRM_MODE_DIRTY_ON, "On" },
178 { DRM_MODE_DIRTY_ANNOTATE, "Annotate" },
179};
180
Dave Airlief453ba02008-11-07 14:05:41 -0800181struct drm_conn_prop_enum_list {
182 int type;
183 char *name;
184 int count;
185};
186
187/*
188 * Connector and encoder types.
189 */
190static struct drm_conn_prop_enum_list drm_connector_enum_list[] =
191{ { DRM_MODE_CONNECTOR_Unknown, "Unknown", 0 },
192 { DRM_MODE_CONNECTOR_VGA, "VGA", 0 },
193 { DRM_MODE_CONNECTOR_DVII, "DVI-I", 0 },
194 { DRM_MODE_CONNECTOR_DVID, "DVI-D", 0 },
195 { DRM_MODE_CONNECTOR_DVIA, "DVI-A", 0 },
196 { DRM_MODE_CONNECTOR_Composite, "Composite", 0 },
197 { DRM_MODE_CONNECTOR_SVIDEO, "SVIDEO", 0 },
198 { DRM_MODE_CONNECTOR_LVDS, "LVDS", 0 },
199 { DRM_MODE_CONNECTOR_Component, "Component", 0 },
Alex Deuchere76116c2010-12-08 19:09:42 -0500200 { DRM_MODE_CONNECTOR_9PinDIN, "DIN", 0 },
201 { DRM_MODE_CONNECTOR_DisplayPort, "DP", 0 },
202 { DRM_MODE_CONNECTOR_HDMIA, "HDMI-A", 0 },
203 { DRM_MODE_CONNECTOR_HDMIB, "HDMI-B", 0 },
Francisco Jerez74bd3c22009-08-02 04:19:18 +0200204 { DRM_MODE_CONNECTOR_TV, "TV", 0 },
Alex Deuchere76116c2010-12-08 19:09:42 -0500205 { DRM_MODE_CONNECTOR_eDP, "eDP", 0 },
Thomas Hellstroma7331e52011-10-22 10:36:19 +0200206 { DRM_MODE_CONNECTOR_VIRTUAL, "Virtual", 0},
Dave Airlief453ba02008-11-07 14:05:41 -0800207};
208
209static struct drm_prop_enum_list drm_encoder_enum_list[] =
210{ { DRM_MODE_ENCODER_NONE, "None" },
211 { DRM_MODE_ENCODER_DAC, "DAC" },
212 { DRM_MODE_ENCODER_TMDS, "TMDS" },
213 { DRM_MODE_ENCODER_LVDS, "LVDS" },
214 { DRM_MODE_ENCODER_TVDAC, "TV" },
Thomas Hellstroma7331e52011-10-22 10:36:19 +0200215 { DRM_MODE_ENCODER_VIRTUAL, "Virtual" },
Dave Airlief453ba02008-11-07 14:05:41 -0800216};
217
218char *drm_get_encoder_name(struct drm_encoder *encoder)
219{
220 static char buf[32];
221
222 snprintf(buf, 32, "%s-%d",
223 drm_encoder_enum_list[encoder->encoder_type].name,
224 encoder->base.id);
225 return buf;
226}
Dave Airlie13a81952009-09-07 15:45:33 +1000227EXPORT_SYMBOL(drm_get_encoder_name);
Dave Airlief453ba02008-11-07 14:05:41 -0800228
229char *drm_get_connector_name(struct drm_connector *connector)
230{
231 static char buf[32];
232
233 snprintf(buf, 32, "%s-%d",
234 drm_connector_enum_list[connector->connector_type].name,
235 connector->connector_type_id);
236 return buf;
237}
238EXPORT_SYMBOL(drm_get_connector_name);
239
240char *drm_get_connector_status_name(enum drm_connector_status status)
241{
242 if (status == connector_status_connected)
243 return "connected";
244 else if (status == connector_status_disconnected)
245 return "disconnected";
246 else
247 return "unknown";
248}
249
250/**
Daniel Vetter065a50ed2012-12-02 00:09:18 +0100251 * drm_mode_object_get - allocate a new modeset identifier
Dave Airlief453ba02008-11-07 14:05:41 -0800252 * @dev: DRM device
Daniel Vetter065a50ed2012-12-02 00:09:18 +0100253 * @obj: object pointer, used to generate unique ID
254 * @obj_type: object type
Dave Airlief453ba02008-11-07 14:05:41 -0800255 *
Dave Airlief453ba02008-11-07 14:05:41 -0800256 * Create a unique identifier based on @ptr in @dev's identifier space. Used
257 * for tracking modes, CRTCs and connectors.
258 *
259 * RETURNS:
260 * New unique (relative to other objects in @dev) integer identifier for the
261 * object.
262 */
263static int drm_mode_object_get(struct drm_device *dev,
264 struct drm_mode_object *obj, uint32_t obj_type)
265{
Dave Airlief453ba02008-11-07 14:05:41 -0800266 int ret;
267
Jesse Barnesad2563c2009-01-19 17:21:45 +1000268 mutex_lock(&dev->mode_config.idr_mutex);
Tejun Heo2e928812013-02-27 17:04:08 -0800269 ret = idr_alloc(&dev->mode_config.crtc_idr, obj, 1, 0, GFP_KERNEL);
270 if (ret >= 0) {
Daniel Vetter4b096ac2012-12-10 21:19:18 +0100271 /*
272 * Set up the object linking under the protection of the idr
273 * lock so that other users can't see inconsistent state.
274 */
Tejun Heo2e928812013-02-27 17:04:08 -0800275 obj->id = ret;
Daniel Vetter4b096ac2012-12-10 21:19:18 +0100276 obj->type = obj_type;
277 }
Jesse Barnesad2563c2009-01-19 17:21:45 +1000278 mutex_unlock(&dev->mode_config.idr_mutex);
Daniel Vetter4b096ac2012-12-10 21:19:18 +0100279
Tejun Heo2e928812013-02-27 17:04:08 -0800280 return ret < 0 ? ret : 0;
Dave Airlief453ba02008-11-07 14:05:41 -0800281}
282
283/**
Daniel Vetter065a50ed2012-12-02 00:09:18 +0100284 * drm_mode_object_put - free a modeset identifer
Dave Airlief453ba02008-11-07 14:05:41 -0800285 * @dev: DRM device
Daniel Vetter065a50ed2012-12-02 00:09:18 +0100286 * @object: object to free
Dave Airlief453ba02008-11-07 14:05:41 -0800287 *
Dave Airlief453ba02008-11-07 14:05:41 -0800288 * Free @id from @dev's unique identifier pool.
289 */
290static void drm_mode_object_put(struct drm_device *dev,
291 struct drm_mode_object *object)
292{
Jesse Barnesad2563c2009-01-19 17:21:45 +1000293 mutex_lock(&dev->mode_config.idr_mutex);
Dave Airlief453ba02008-11-07 14:05:41 -0800294 idr_remove(&dev->mode_config.crtc_idr, object->id);
Jesse Barnesad2563c2009-01-19 17:21:45 +1000295 mutex_unlock(&dev->mode_config.idr_mutex);
Dave Airlief453ba02008-11-07 14:05:41 -0800296}
297
Daniel Vetter786b99e2012-12-02 21:53:40 +0100298/**
299 * drm_mode_object_find - look up a drm object with static lifetime
300 * @dev: drm device
301 * @id: id of the mode object
302 * @type: type of the mode object
303 *
304 * Note that framebuffers cannot be looked up with this functions - since those
305 * are reference counted, they need special treatment.
306 */
Daniel Vetter7a9c9062009-09-15 22:57:31 +0200307struct drm_mode_object *drm_mode_object_find(struct drm_device *dev,
308 uint32_t id, uint32_t type)
Dave Airlief453ba02008-11-07 14:05:41 -0800309{
Jesse Barnesad2563c2009-01-19 17:21:45 +1000310 struct drm_mode_object *obj = NULL;
Dave Airlief453ba02008-11-07 14:05:41 -0800311
Daniel Vetter786b99e2012-12-02 21:53:40 +0100312 /* Framebuffers are reference counted and need their own lookup
313 * function.*/
314 WARN_ON(type == DRM_MODE_OBJECT_FB);
315
Jesse Barnesad2563c2009-01-19 17:21:45 +1000316 mutex_lock(&dev->mode_config.idr_mutex);
Dave Airlief453ba02008-11-07 14:05:41 -0800317 obj = idr_find(&dev->mode_config.crtc_idr, id);
318 if (!obj || (obj->type != type) || (obj->id != id))
Jesse Barnesad2563c2009-01-19 17:21:45 +1000319 obj = NULL;
320 mutex_unlock(&dev->mode_config.idr_mutex);
Dave Airlief453ba02008-11-07 14:05:41 -0800321
322 return obj;
323}
324EXPORT_SYMBOL(drm_mode_object_find);
325
326/**
Dave Airlief453ba02008-11-07 14:05:41 -0800327 * drm_framebuffer_init - initialize a framebuffer
328 * @dev: DRM device
Daniel Vetter065a50ed2012-12-02 00:09:18 +0100329 * @fb: framebuffer to be initialized
330 * @funcs: ... with these functions
Dave Airlief453ba02008-11-07 14:05:41 -0800331 *
Dave Airlief453ba02008-11-07 14:05:41 -0800332 * Allocates an ID for the framebuffer's parent mode object, sets its mode
333 * functions & device file and adds it to the master fd list.
334 *
Daniel Vetter4b096ac2012-12-10 21:19:18 +0100335 * IMPORTANT:
336 * This functions publishes the fb and makes it available for concurrent access
337 * by other users. Which means by this point the fb _must_ be fully set up -
338 * since all the fb attributes are invariant over its lifetime, no further
339 * locking but only correct reference counting is required.
340 *
Dave Airlief453ba02008-11-07 14:05:41 -0800341 * RETURNS:
André Goddard Rosaaf901ca2009-11-14 13:09:05 -0200342 * Zero on success, error code on failure.
Dave Airlief453ba02008-11-07 14:05:41 -0800343 */
344int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb,
345 const struct drm_framebuffer_funcs *funcs)
346{
347 int ret;
348
Daniel Vetter4b096ac2012-12-10 21:19:18 +0100349 mutex_lock(&dev->mode_config.fb_lock);
Rob Clarkf7eff602012-09-05 21:48:38 +0000350 kref_init(&fb->refcount);
Daniel Vetter4b096ac2012-12-10 21:19:18 +0100351 INIT_LIST_HEAD(&fb->filp_head);
352 fb->dev = dev;
353 fb->funcs = funcs;
Rob Clarkf7eff602012-09-05 21:48:38 +0000354
Dave Airlief453ba02008-11-07 14:05:41 -0800355 ret = drm_mode_object_get(dev, &fb->base, DRM_MODE_OBJECT_FB);
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +0200356 if (ret)
Daniel Vetter4b096ac2012-12-10 21:19:18 +0100357 goto out;
Dave Airlief453ba02008-11-07 14:05:41 -0800358
Daniel Vetter2b677e82012-12-10 21:16:05 +0100359 /* Grab the idr reference. */
360 drm_framebuffer_reference(fb);
361
Dave Airlief453ba02008-11-07 14:05:41 -0800362 dev->mode_config.num_fb++;
363 list_add(&fb->head, &dev->mode_config.fb_list);
Daniel Vetter4b096ac2012-12-10 21:19:18 +0100364out:
365 mutex_unlock(&dev->mode_config.fb_lock);
Dave Airlief453ba02008-11-07 14:05:41 -0800366
367 return 0;
368}
369EXPORT_SYMBOL(drm_framebuffer_init);
370
Rob Clarkf7eff602012-09-05 21:48:38 +0000371static void drm_framebuffer_free(struct kref *kref)
372{
373 struct drm_framebuffer *fb =
374 container_of(kref, struct drm_framebuffer, refcount);
375 fb->funcs->destroy(fb);
376}
377
Daniel Vetter2b677e82012-12-10 21:16:05 +0100378static struct drm_framebuffer *__drm_framebuffer_lookup(struct drm_device *dev,
379 uint32_t id)
380{
381 struct drm_mode_object *obj = NULL;
382 struct drm_framebuffer *fb;
383
384 mutex_lock(&dev->mode_config.idr_mutex);
385 obj = idr_find(&dev->mode_config.crtc_idr, id);
386 if (!obj || (obj->type != DRM_MODE_OBJECT_FB) || (obj->id != id))
387 fb = NULL;
388 else
389 fb = obj_to_fb(obj);
390 mutex_unlock(&dev->mode_config.idr_mutex);
391
392 return fb;
393}
394
Rob Clarkf7eff602012-09-05 21:48:38 +0000395/**
Daniel Vetter786b99e2012-12-02 21:53:40 +0100396 * drm_framebuffer_lookup - look up a drm framebuffer and grab a reference
397 * @dev: drm device
398 * @id: id of the fb object
399 *
400 * If successful, this grabs an additional reference to the framebuffer -
401 * callers need to make sure to eventually unreference the returned framebuffer
402 * again.
403 */
404struct drm_framebuffer *drm_framebuffer_lookup(struct drm_device *dev,
405 uint32_t id)
406{
Daniel Vetter786b99e2012-12-02 21:53:40 +0100407 struct drm_framebuffer *fb;
408
409 mutex_lock(&dev->mode_config.fb_lock);
Daniel Vetter2b677e82012-12-10 21:16:05 +0100410 fb = __drm_framebuffer_lookup(dev, id);
Daniel Vetter786b99e2012-12-02 21:53:40 +0100411 if (fb)
archit taneja9131d3d2013-04-10 08:59:39 +0000412 drm_framebuffer_reference(fb);
Daniel Vetter786b99e2012-12-02 21:53:40 +0100413 mutex_unlock(&dev->mode_config.fb_lock);
414
415 return fb;
416}
417EXPORT_SYMBOL(drm_framebuffer_lookup);
418
419/**
Rob Clarkf7eff602012-09-05 21:48:38 +0000420 * drm_framebuffer_unreference - unref a framebuffer
Daniel Vetter065a50ed2012-12-02 00:09:18 +0100421 * @fb: framebuffer to unref
422 *
423 * This functions decrements the fb's refcount and frees it if it drops to zero.
Rob Clarkf7eff602012-09-05 21:48:38 +0000424 */
425void drm_framebuffer_unreference(struct drm_framebuffer *fb)
426{
Rob Clarkf7eff602012-09-05 21:48:38 +0000427 DRM_DEBUG("FB ID: %d\n", fb->base.id);
Rob Clarkf7eff602012-09-05 21:48:38 +0000428 kref_put(&fb->refcount, drm_framebuffer_free);
429}
430EXPORT_SYMBOL(drm_framebuffer_unreference);
431
432/**
433 * drm_framebuffer_reference - incr the fb refcnt
Daniel Vetter065a50ed2012-12-02 00:09:18 +0100434 * @fb: framebuffer
Rob Clarkf7eff602012-09-05 21:48:38 +0000435 */
436void drm_framebuffer_reference(struct drm_framebuffer *fb)
437{
438 DRM_DEBUG("FB ID: %d\n", fb->base.id);
439 kref_get(&fb->refcount);
440}
441EXPORT_SYMBOL(drm_framebuffer_reference);
442
Daniel Vetter2b677e82012-12-10 21:16:05 +0100443static void drm_framebuffer_free_bug(struct kref *kref)
444{
445 BUG();
446}
447
Daniel Vetter6c2a7532012-12-11 00:59:24 +0100448static void __drm_framebuffer_unreference(struct drm_framebuffer *fb)
449{
450 DRM_DEBUG("FB ID: %d\n", fb->base.id);
451 kref_put(&fb->refcount, drm_framebuffer_free_bug);
452}
453
Daniel Vetter2b677e82012-12-10 21:16:05 +0100454/* dev->mode_config.fb_lock must be held! */
455static void __drm_framebuffer_unregister(struct drm_device *dev,
456 struct drm_framebuffer *fb)
457{
458 mutex_lock(&dev->mode_config.idr_mutex);
459 idr_remove(&dev->mode_config.crtc_idr, fb->base.id);
460 mutex_unlock(&dev->mode_config.idr_mutex);
461
462 fb->base.id = 0;
463
Daniel Vetter6c2a7532012-12-11 00:59:24 +0100464 __drm_framebuffer_unreference(fb);
Daniel Vetter2b677e82012-12-10 21:16:05 +0100465}
466
Dave Airlief453ba02008-11-07 14:05:41 -0800467/**
Daniel Vetter36206362012-12-10 20:42:17 +0100468 * drm_framebuffer_unregister_private - unregister a private fb from the lookup idr
469 * @fb: fb to unregister
470 *
471 * Drivers need to call this when cleaning up driver-private framebuffers, e.g.
472 * those used for fbdev. Note that the caller must hold a reference of it's own,
473 * i.e. the object may not be destroyed through this call (since it'll lead to a
474 * locking inversion).
475 */
476void drm_framebuffer_unregister_private(struct drm_framebuffer *fb)
477{
Daniel Vetter2b677e82012-12-10 21:16:05 +0100478 struct drm_device *dev = fb->dev;
479
480 mutex_lock(&dev->mode_config.fb_lock);
481 /* Mark fb as reaped and drop idr ref. */
482 __drm_framebuffer_unregister(dev, fb);
483 mutex_unlock(&dev->mode_config.fb_lock);
Daniel Vetter36206362012-12-10 20:42:17 +0100484}
485EXPORT_SYMBOL(drm_framebuffer_unregister_private);
486
487/**
Dave Airlief453ba02008-11-07 14:05:41 -0800488 * drm_framebuffer_cleanup - remove a framebuffer object
489 * @fb: framebuffer to remove
490 *
Daniel Vetter36206362012-12-10 20:42:17 +0100491 * Cleanup references to a user-created framebuffer. This function is intended
492 * to be used from the drivers ->destroy callback.
493 *
494 * Note that this function does not remove the fb from active usuage - if it is
495 * still used anywhere, hilarity can ensue since userspace could call getfb on
496 * the id and get back -EINVAL. Obviously no concern at driver unload time.
497 *
498 * Also, the framebuffer will not be removed from the lookup idr - for
499 * user-created framebuffers this will happen in in the rmfb ioctl. For
500 * driver-private objects (e.g. for fbdev) drivers need to explicitly call
501 * drm_framebuffer_unregister_private.
Dave Airlief453ba02008-11-07 14:05:41 -0800502 */
503void drm_framebuffer_cleanup(struct drm_framebuffer *fb)
504{
505 struct drm_device *dev = fb->dev;
Daniel Vetter8faf6b12012-12-01 23:43:11 +0100506
Daniel Vetter4b096ac2012-12-10 21:19:18 +0100507 mutex_lock(&dev->mode_config.fb_lock);
Rob Clarkf7eff602012-09-05 21:48:38 +0000508 list_del(&fb->head);
509 dev->mode_config.num_fb--;
Daniel Vetter4b096ac2012-12-10 21:19:18 +0100510 mutex_unlock(&dev->mode_config.fb_lock);
Rob Clarkf7eff602012-09-05 21:48:38 +0000511}
512EXPORT_SYMBOL(drm_framebuffer_cleanup);
513
514/**
515 * drm_framebuffer_remove - remove and unreference a framebuffer object
516 * @fb: framebuffer to remove
517 *
Rob Clarkf7eff602012-09-05 21:48:38 +0000518 * Scans all the CRTCs and planes in @dev's mode_config. If they're
Daniel Vetter36206362012-12-10 20:42:17 +0100519 * using @fb, removes it, setting it to NULL. Then drops the reference to the
Daniel Vetterb62584e2012-12-11 16:51:35 +0100520 * passed-in framebuffer. Might take the modeset locks.
521 *
522 * Note that this function optimizes the cleanup away if the caller holds the
523 * last reference to the framebuffer. It is also guaranteed to not take the
524 * modeset locks in this case.
Rob Clarkf7eff602012-09-05 21:48:38 +0000525 */
526void drm_framebuffer_remove(struct drm_framebuffer *fb)
527{
528 struct drm_device *dev = fb->dev;
Dave Airlief453ba02008-11-07 14:05:41 -0800529 struct drm_crtc *crtc;
Jesse Barnes8cf5c912011-11-14 14:51:27 -0800530 struct drm_plane *plane;
Dave Airlie5ef5f722009-08-17 13:11:23 +1000531 struct drm_mode_set set;
532 int ret;
Dave Airlief453ba02008-11-07 14:05:41 -0800533
Daniel Vetter4b096ac2012-12-10 21:19:18 +0100534 WARN_ON(!list_empty(&fb->filp_head));
Daniel Vetter8faf6b12012-12-01 23:43:11 +0100535
Daniel Vetterb62584e2012-12-11 16:51:35 +0100536 /*
537 * drm ABI mandates that we remove any deleted framebuffers from active
538 * useage. But since most sane clients only remove framebuffers they no
539 * longer need, try to optimize this away.
540 *
541 * Since we're holding a reference ourselves, observing a refcount of 1
542 * means that we're the last holder and can skip it. Also, the refcount
543 * can never increase from 1 again, so we don't need any barriers or
544 * locks.
545 *
546 * Note that userspace could try to race with use and instate a new
547 * usage _after_ we've cleared all current ones. End result will be an
548 * in-use fb with fb-id == 0. Userspace is allowed to shoot its own foot
549 * in this manner.
550 */
551 if (atomic_read(&fb->refcount.refcount) > 1) {
552 drm_modeset_lock_all(dev);
553 /* remove from any CRTC */
554 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
555 if (crtc->fb == fb) {
556 /* should turn off the crtc */
557 memset(&set, 0, sizeof(struct drm_mode_set));
558 set.crtc = crtc;
559 set.fb = NULL;
560 ret = drm_mode_set_config_internal(&set);
561 if (ret)
562 DRM_ERROR("failed to reset crtc %p when fb was deleted\n", crtc);
563 }
Dave Airlie5ef5f722009-08-17 13:11:23 +1000564 }
Dave Airlief453ba02008-11-07 14:05:41 -0800565
Daniel Vetterb62584e2012-12-11 16:51:35 +0100566 list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
567 if (plane->fb == fb) {
568 /* should turn off the crtc */
569 ret = plane->funcs->disable_plane(plane);
570 if (ret)
571 DRM_ERROR("failed to disable plane with busy fb\n");
572 /* disconnect the plane from the fb and crtc: */
573 __drm_framebuffer_unreference(plane->fb);
574 plane->fb = NULL;
575 plane->crtc = NULL;
576 }
Jesse Barnes8cf5c912011-11-14 14:51:27 -0800577 }
Daniel Vetterb62584e2012-12-11 16:51:35 +0100578 drm_modeset_unlock_all(dev);
Jesse Barnes8cf5c912011-11-14 14:51:27 -0800579 }
580
Rob Clarkf7eff602012-09-05 21:48:38 +0000581 drm_framebuffer_unreference(fb);
Dave Airlief453ba02008-11-07 14:05:41 -0800582}
Rob Clarkf7eff602012-09-05 21:48:38 +0000583EXPORT_SYMBOL(drm_framebuffer_remove);
Dave Airlief453ba02008-11-07 14:05:41 -0800584
585/**
586 * drm_crtc_init - Initialise a new CRTC object
587 * @dev: DRM device
588 * @crtc: CRTC object to init
589 * @funcs: callbacks for the new CRTC
590 *
Dave Airlief453ba02008-11-07 14:05:41 -0800591 * Inits a new object created as base part of an driver crtc object.
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +0200592 *
593 * RETURNS:
594 * Zero on success, error code on failure.
Dave Airlief453ba02008-11-07 14:05:41 -0800595 */
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +0200596int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
Dave Airlief453ba02008-11-07 14:05:41 -0800597 const struct drm_crtc_funcs *funcs)
598{
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +0200599 int ret;
600
Dave Airlief453ba02008-11-07 14:05:41 -0800601 crtc->dev = dev;
602 crtc->funcs = funcs;
Rob Clark7c80e122012-09-04 16:35:56 +0000603 crtc->invert_dimensions = false;
Dave Airlief453ba02008-11-07 14:05:41 -0800604
Daniel Vetter84849902012-12-02 00:28:11 +0100605 drm_modeset_lock_all(dev);
Daniel Vetter29494c12012-12-02 02:18:25 +0100606 mutex_init(&crtc->mutex);
607 mutex_lock_nest_lock(&crtc->mutex, &dev->mode_config.mutex);
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +0200608
609 ret = drm_mode_object_get(dev, &crtc->base, DRM_MODE_OBJECT_CRTC);
610 if (ret)
611 goto out;
Dave Airlief453ba02008-11-07 14:05:41 -0800612
Paulo Zanonibffd9de02012-05-15 18:09:05 -0300613 crtc->base.properties = &crtc->properties;
614
Dave Airlief453ba02008-11-07 14:05:41 -0800615 list_add_tail(&crtc->head, &dev->mode_config.crtc_list);
616 dev->mode_config.num_crtc++;
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +0200617
618 out:
Daniel Vetter84849902012-12-02 00:28:11 +0100619 drm_modeset_unlock_all(dev);
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +0200620
621 return ret;
Dave Airlief453ba02008-11-07 14:05:41 -0800622}
623EXPORT_SYMBOL(drm_crtc_init);
624
625/**
626 * drm_crtc_cleanup - Cleans up the core crtc usage.
627 * @crtc: CRTC to cleanup
628 *
Dave Airlief453ba02008-11-07 14:05:41 -0800629 * Cleanup @crtc. Removes from drm modesetting space
630 * does NOT free object, caller does that.
631 */
632void drm_crtc_cleanup(struct drm_crtc *crtc)
633{
634 struct drm_device *dev = crtc->dev;
635
Sachin Kamat9e1c1562012-11-19 09:44:56 +0000636 kfree(crtc->gamma_store);
637 crtc->gamma_store = NULL;
Dave Airlief453ba02008-11-07 14:05:41 -0800638
639 drm_mode_object_put(dev, &crtc->base);
640 list_del(&crtc->head);
641 dev->mode_config.num_crtc--;
642}
643EXPORT_SYMBOL(drm_crtc_cleanup);
644
645/**
646 * drm_mode_probed_add - add a mode to a connector's probed mode list
647 * @connector: connector the new mode
648 * @mode: mode data
649 *
Dave Airlief453ba02008-11-07 14:05:41 -0800650 * Add @mode to @connector's mode list for later use.
651 */
652void drm_mode_probed_add(struct drm_connector *connector,
653 struct drm_display_mode *mode)
654{
655 list_add(&mode->head, &connector->probed_modes);
656}
657EXPORT_SYMBOL(drm_mode_probed_add);
658
659/**
660 * drm_mode_remove - remove and free a mode
661 * @connector: connector list to modify
662 * @mode: mode to remove
663 *
Dave Airlief453ba02008-11-07 14:05:41 -0800664 * Remove @mode from @connector's mode list, then free it.
665 */
666void drm_mode_remove(struct drm_connector *connector,
667 struct drm_display_mode *mode)
668{
669 list_del(&mode->head);
Sascha Hauer554f1d72012-02-01 11:38:19 +0100670 drm_mode_destroy(connector->dev, mode);
Dave Airlief453ba02008-11-07 14:05:41 -0800671}
672EXPORT_SYMBOL(drm_mode_remove);
673
674/**
675 * drm_connector_init - Init a preallocated connector
676 * @dev: DRM device
677 * @connector: the connector to init
678 * @funcs: callbacks for this connector
Daniel Vetter065a50ed2012-12-02 00:09:18 +0100679 * @connector_type: user visible type of the connector
Dave Airlief453ba02008-11-07 14:05:41 -0800680 *
Dave Airlief453ba02008-11-07 14:05:41 -0800681 * Initialises a preallocated connector. Connectors should be
682 * subclassed as part of driver connector objects.
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +0200683 *
684 * RETURNS:
685 * Zero on success, error code on failure.
Dave Airlief453ba02008-11-07 14:05:41 -0800686 */
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +0200687int drm_connector_init(struct drm_device *dev,
688 struct drm_connector *connector,
689 const struct drm_connector_funcs *funcs,
690 int connector_type)
Dave Airlief453ba02008-11-07 14:05:41 -0800691{
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +0200692 int ret;
693
Daniel Vetter84849902012-12-02 00:28:11 +0100694 drm_modeset_lock_all(dev);
Dave Airlief453ba02008-11-07 14:05:41 -0800695
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +0200696 ret = drm_mode_object_get(dev, &connector->base, DRM_MODE_OBJECT_CONNECTOR);
697 if (ret)
698 goto out;
699
Paulo Zanoni7e3bdf42012-05-15 18:09:01 -0300700 connector->base.properties = &connector->properties;
Dave Airlief453ba02008-11-07 14:05:41 -0800701 connector->dev = dev;
702 connector->funcs = funcs;
Dave Airlief453ba02008-11-07 14:05:41 -0800703 connector->connector_type = connector_type;
704 connector->connector_type_id =
705 ++drm_connector_enum_list[connector_type].count; /* TODO */
706 INIT_LIST_HEAD(&connector->user_modes);
707 INIT_LIST_HEAD(&connector->probed_modes);
708 INIT_LIST_HEAD(&connector->modes);
709 connector->edid_blob_ptr = NULL;
Daniel Vetter5e2cb2f2012-10-23 18:23:35 +0000710 connector->status = connector_status_unknown;
Dave Airlief453ba02008-11-07 14:05:41 -0800711
712 list_add_tail(&connector->head, &dev->mode_config.connector_list);
713 dev->mode_config.num_connector++;
714
Thomas Hellstroma7331e52011-10-22 10:36:19 +0200715 if (connector_type != DRM_MODE_CONNECTOR_VIRTUAL)
Rob Clark58495562012-10-11 20:50:56 -0500716 drm_object_attach_property(&connector->base,
Thomas Hellstroma7331e52011-10-22 10:36:19 +0200717 dev->mode_config.edid_property,
718 0);
Dave Airlief453ba02008-11-07 14:05:41 -0800719
Rob Clark58495562012-10-11 20:50:56 -0500720 drm_object_attach_property(&connector->base,
Dave Airlief453ba02008-11-07 14:05:41 -0800721 dev->mode_config.dpms_property, 0);
722
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +0200723 out:
Daniel Vetter84849902012-12-02 00:28:11 +0100724 drm_modeset_unlock_all(dev);
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +0200725
726 return ret;
Dave Airlief453ba02008-11-07 14:05:41 -0800727}
728EXPORT_SYMBOL(drm_connector_init);
729
730/**
731 * drm_connector_cleanup - cleans up an initialised connector
732 * @connector: connector to cleanup
733 *
Dave Airlief453ba02008-11-07 14:05:41 -0800734 * Cleans up the connector but doesn't free the object.
735 */
736void drm_connector_cleanup(struct drm_connector *connector)
737{
738 struct drm_device *dev = connector->dev;
739 struct drm_display_mode *mode, *t;
740
741 list_for_each_entry_safe(mode, t, &connector->probed_modes, head)
742 drm_mode_remove(connector, mode);
743
744 list_for_each_entry_safe(mode, t, &connector->modes, head)
745 drm_mode_remove(connector, mode);
746
747 list_for_each_entry_safe(mode, t, &connector->user_modes, head)
748 drm_mode_remove(connector, mode);
749
Dave Airlief453ba02008-11-07 14:05:41 -0800750 drm_mode_object_put(dev, &connector->base);
751 list_del(&connector->head);
Joonyoung Shim6380c502011-08-27 02:06:21 +0000752 dev->mode_config.num_connector--;
Dave Airlief453ba02008-11-07 14:05:41 -0800753}
754EXPORT_SYMBOL(drm_connector_cleanup);
755
Dave Airliecbc7e222012-02-20 14:16:40 +0000756void drm_connector_unplug_all(struct drm_device *dev)
757{
758 struct drm_connector *connector;
759
760 /* taking the mode config mutex ends up in a clash with sysfs */
761 list_for_each_entry(connector, &dev->mode_config.connector_list, head)
762 drm_sysfs_connector_remove(connector);
763
764}
765EXPORT_SYMBOL(drm_connector_unplug_all);
766
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +0200767int drm_encoder_init(struct drm_device *dev,
Dave Airliecbc7e222012-02-20 14:16:40 +0000768 struct drm_encoder *encoder,
769 const struct drm_encoder_funcs *funcs,
770 int encoder_type)
Dave Airlief453ba02008-11-07 14:05:41 -0800771{
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +0200772 int ret;
773
Daniel Vetter84849902012-12-02 00:28:11 +0100774 drm_modeset_lock_all(dev);
Dave Airlief453ba02008-11-07 14:05:41 -0800775
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +0200776 ret = drm_mode_object_get(dev, &encoder->base, DRM_MODE_OBJECT_ENCODER);
777 if (ret)
778 goto out;
Dave Airlief453ba02008-11-07 14:05:41 -0800779
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +0200780 encoder->dev = dev;
Dave Airlief453ba02008-11-07 14:05:41 -0800781 encoder->encoder_type = encoder_type;
782 encoder->funcs = funcs;
783
784 list_add_tail(&encoder->head, &dev->mode_config.encoder_list);
785 dev->mode_config.num_encoder++;
786
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +0200787 out:
Daniel Vetter84849902012-12-02 00:28:11 +0100788 drm_modeset_unlock_all(dev);
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +0200789
790 return ret;
Dave Airlief453ba02008-11-07 14:05:41 -0800791}
792EXPORT_SYMBOL(drm_encoder_init);
793
794void drm_encoder_cleanup(struct drm_encoder *encoder)
795{
796 struct drm_device *dev = encoder->dev;
Daniel Vetter84849902012-12-02 00:28:11 +0100797 drm_modeset_lock_all(dev);
Dave Airlief453ba02008-11-07 14:05:41 -0800798 drm_mode_object_put(dev, &encoder->base);
799 list_del(&encoder->head);
Joonyoung Shim6380c502011-08-27 02:06:21 +0000800 dev->mode_config.num_encoder--;
Daniel Vetter84849902012-12-02 00:28:11 +0100801 drm_modeset_unlock_all(dev);
Dave Airlief453ba02008-11-07 14:05:41 -0800802}
803EXPORT_SYMBOL(drm_encoder_cleanup);
804
Jesse Barnes8cf5c912011-11-14 14:51:27 -0800805int drm_plane_init(struct drm_device *dev, struct drm_plane *plane,
806 unsigned long possible_crtcs,
807 const struct drm_plane_funcs *funcs,
Rob Clark0a7eb242011-12-13 20:19:36 -0600808 const uint32_t *formats, uint32_t format_count,
809 bool priv)
Jesse Barnes8cf5c912011-11-14 14:51:27 -0800810{
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +0200811 int ret;
812
Daniel Vetter84849902012-12-02 00:28:11 +0100813 drm_modeset_lock_all(dev);
Jesse Barnes8cf5c912011-11-14 14:51:27 -0800814
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +0200815 ret = drm_mode_object_get(dev, &plane->base, DRM_MODE_OBJECT_PLANE);
816 if (ret)
817 goto out;
818
Rob Clark4d939142012-05-17 02:23:27 -0600819 plane->base.properties = &plane->properties;
Jesse Barnes8cf5c912011-11-14 14:51:27 -0800820 plane->dev = dev;
Jesse Barnes8cf5c912011-11-14 14:51:27 -0800821 plane->funcs = funcs;
822 plane->format_types = kmalloc(sizeof(uint32_t) * format_count,
823 GFP_KERNEL);
824 if (!plane->format_types) {
825 DRM_DEBUG_KMS("out of memory when allocating plane\n");
826 drm_mode_object_put(dev, &plane->base);
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +0200827 ret = -ENOMEM;
828 goto out;
Jesse Barnes8cf5c912011-11-14 14:51:27 -0800829 }
830
Jesse Barnes308e5bc2011-11-14 14:51:28 -0800831 memcpy(plane->format_types, formats, format_count * sizeof(uint32_t));
Jesse Barnes8cf5c912011-11-14 14:51:27 -0800832 plane->format_count = format_count;
833 plane->possible_crtcs = possible_crtcs;
834
Rob Clark0a7eb242011-12-13 20:19:36 -0600835 /* private planes are not exposed to userspace, but depending on
836 * display hardware, might be convenient to allow sharing programming
837 * for the scanout engine with the crtc implementation.
838 */
839 if (!priv) {
840 list_add_tail(&plane->head, &dev->mode_config.plane_list);
841 dev->mode_config.num_plane++;
842 } else {
843 INIT_LIST_HEAD(&plane->head);
844 }
Jesse Barnes8cf5c912011-11-14 14:51:27 -0800845
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +0200846 out:
Daniel Vetter84849902012-12-02 00:28:11 +0100847 drm_modeset_unlock_all(dev);
Jesse Barnes8cf5c912011-11-14 14:51:27 -0800848
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +0200849 return ret;
Jesse Barnes8cf5c912011-11-14 14:51:27 -0800850}
851EXPORT_SYMBOL(drm_plane_init);
852
853void drm_plane_cleanup(struct drm_plane *plane)
854{
855 struct drm_device *dev = plane->dev;
856
Daniel Vetter84849902012-12-02 00:28:11 +0100857 drm_modeset_lock_all(dev);
Jesse Barnes8cf5c912011-11-14 14:51:27 -0800858 kfree(plane->format_types);
859 drm_mode_object_put(dev, &plane->base);
Rob Clark0a7eb242011-12-13 20:19:36 -0600860 /* if not added to a list, it must be a private plane */
861 if (!list_empty(&plane->head)) {
862 list_del(&plane->head);
863 dev->mode_config.num_plane--;
864 }
Daniel Vetter84849902012-12-02 00:28:11 +0100865 drm_modeset_unlock_all(dev);
Jesse Barnes8cf5c912011-11-14 14:51:27 -0800866}
867EXPORT_SYMBOL(drm_plane_cleanup);
868
Dave Airlief453ba02008-11-07 14:05:41 -0800869/**
870 * drm_mode_create - create a new display mode
871 * @dev: DRM device
872 *
Dave Airlief453ba02008-11-07 14:05:41 -0800873 * Create a new drm_display_mode, give it an ID, and return it.
874 *
875 * RETURNS:
876 * Pointer to new mode on success, NULL on error.
877 */
878struct drm_display_mode *drm_mode_create(struct drm_device *dev)
879{
880 struct drm_display_mode *nmode;
881
882 nmode = kzalloc(sizeof(struct drm_display_mode), GFP_KERNEL);
883 if (!nmode)
884 return NULL;
885
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +0200886 if (drm_mode_object_get(dev, &nmode->base, DRM_MODE_OBJECT_MODE)) {
887 kfree(nmode);
888 return NULL;
889 }
890
Dave Airlief453ba02008-11-07 14:05:41 -0800891 return nmode;
892}
893EXPORT_SYMBOL(drm_mode_create);
894
895/**
896 * drm_mode_destroy - remove a mode
897 * @dev: DRM device
898 * @mode: mode to remove
899 *
Dave Airlief453ba02008-11-07 14:05:41 -0800900 * Free @mode's unique identifier, then free it.
901 */
902void drm_mode_destroy(struct drm_device *dev, struct drm_display_mode *mode)
903{
Ville Syrjäläee34ab52012-03-13 12:35:43 +0200904 if (!mode)
905 return;
906
Dave Airlief453ba02008-11-07 14:05:41 -0800907 drm_mode_object_put(dev, &mode->base);
908
909 kfree(mode);
910}
911EXPORT_SYMBOL(drm_mode_destroy);
912
913static int drm_mode_create_standard_connector_properties(struct drm_device *dev)
914{
915 struct drm_property *edid;
916 struct drm_property *dpms;
Dave Airlief453ba02008-11-07 14:05:41 -0800917
918 /*
919 * Standard properties (apply to all connectors)
920 */
921 edid = drm_property_create(dev, DRM_MODE_PROP_BLOB |
922 DRM_MODE_PROP_IMMUTABLE,
923 "EDID", 0);
924 dev->mode_config.edid_property = edid;
925
Sascha Hauer4a67d392012-02-06 10:58:17 +0100926 dpms = drm_property_create_enum(dev, 0,
927 "DPMS", drm_dpms_enum_list,
928 ARRAY_SIZE(drm_dpms_enum_list));
Dave Airlief453ba02008-11-07 14:05:41 -0800929 dev->mode_config.dpms_property = dpms;
930
931 return 0;
932}
933
934/**
935 * drm_mode_create_dvi_i_properties - create DVI-I specific connector properties
936 * @dev: DRM device
937 *
938 * Called by a driver the first time a DVI-I connector is made.
939 */
940int drm_mode_create_dvi_i_properties(struct drm_device *dev)
941{
942 struct drm_property *dvi_i_selector;
943 struct drm_property *dvi_i_subconnector;
Dave Airlief453ba02008-11-07 14:05:41 -0800944
945 if (dev->mode_config.dvi_i_select_subconnector_property)
946 return 0;
947
948 dvi_i_selector =
Sascha Hauer4a67d392012-02-06 10:58:17 +0100949 drm_property_create_enum(dev, 0,
Dave Airlief453ba02008-11-07 14:05:41 -0800950 "select subconnector",
Sascha Hauer4a67d392012-02-06 10:58:17 +0100951 drm_dvi_i_select_enum_list,
Dave Airlief453ba02008-11-07 14:05:41 -0800952 ARRAY_SIZE(drm_dvi_i_select_enum_list));
Dave Airlief453ba02008-11-07 14:05:41 -0800953 dev->mode_config.dvi_i_select_subconnector_property = dvi_i_selector;
954
Sascha Hauer4a67d392012-02-06 10:58:17 +0100955 dvi_i_subconnector = drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE,
Dave Airlief453ba02008-11-07 14:05:41 -0800956 "subconnector",
Sascha Hauer4a67d392012-02-06 10:58:17 +0100957 drm_dvi_i_subconnector_enum_list,
Dave Airlief453ba02008-11-07 14:05:41 -0800958 ARRAY_SIZE(drm_dvi_i_subconnector_enum_list));
Dave Airlief453ba02008-11-07 14:05:41 -0800959 dev->mode_config.dvi_i_subconnector_property = dvi_i_subconnector;
960
961 return 0;
962}
963EXPORT_SYMBOL(drm_mode_create_dvi_i_properties);
964
965/**
966 * drm_create_tv_properties - create TV specific connector properties
967 * @dev: DRM device
968 * @num_modes: number of different TV formats (modes) supported
969 * @modes: array of pointers to strings containing name of each format
970 *
971 * Called by a driver's TV initialization routine, this function creates
972 * the TV specific connector properties for a given device. Caller is
973 * responsible for allocating a list of format names and passing them to
974 * this routine.
975 */
976int drm_mode_create_tv_properties(struct drm_device *dev, int num_modes,
977 char *modes[])
978{
979 struct drm_property *tv_selector;
980 struct drm_property *tv_subconnector;
981 int i;
982
983 if (dev->mode_config.tv_select_subconnector_property)
984 return 0;
985
986 /*
987 * Basic connector properties
988 */
Sascha Hauer4a67d392012-02-06 10:58:17 +0100989 tv_selector = drm_property_create_enum(dev, 0,
Dave Airlief453ba02008-11-07 14:05:41 -0800990 "select subconnector",
Sascha Hauer4a67d392012-02-06 10:58:17 +0100991 drm_tv_select_enum_list,
Dave Airlief453ba02008-11-07 14:05:41 -0800992 ARRAY_SIZE(drm_tv_select_enum_list));
Dave Airlief453ba02008-11-07 14:05:41 -0800993 dev->mode_config.tv_select_subconnector_property = tv_selector;
994
995 tv_subconnector =
Sascha Hauer4a67d392012-02-06 10:58:17 +0100996 drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE,
997 "subconnector",
998 drm_tv_subconnector_enum_list,
Dave Airlief453ba02008-11-07 14:05:41 -0800999 ARRAY_SIZE(drm_tv_subconnector_enum_list));
Dave Airlief453ba02008-11-07 14:05:41 -08001000 dev->mode_config.tv_subconnector_property = tv_subconnector;
1001
1002 /*
1003 * Other, TV specific properties: margins & TV modes.
1004 */
1005 dev->mode_config.tv_left_margin_property =
Sascha Hauerd9bc3c02012-02-06 10:58:18 +01001006 drm_property_create_range(dev, 0, "left margin", 0, 100);
Dave Airlief453ba02008-11-07 14:05:41 -08001007
1008 dev->mode_config.tv_right_margin_property =
Sascha Hauerd9bc3c02012-02-06 10:58:18 +01001009 drm_property_create_range(dev, 0, "right margin", 0, 100);
Dave Airlief453ba02008-11-07 14:05:41 -08001010
1011 dev->mode_config.tv_top_margin_property =
Sascha Hauerd9bc3c02012-02-06 10:58:18 +01001012 drm_property_create_range(dev, 0, "top margin", 0, 100);
Dave Airlief453ba02008-11-07 14:05:41 -08001013
1014 dev->mode_config.tv_bottom_margin_property =
Sascha Hauerd9bc3c02012-02-06 10:58:18 +01001015 drm_property_create_range(dev, 0, "bottom margin", 0, 100);
Dave Airlief453ba02008-11-07 14:05:41 -08001016
1017 dev->mode_config.tv_mode_property =
1018 drm_property_create(dev, DRM_MODE_PROP_ENUM,
1019 "mode", num_modes);
1020 for (i = 0; i < num_modes; i++)
1021 drm_property_add_enum(dev->mode_config.tv_mode_property, i,
1022 i, modes[i]);
1023
Francisco Jerezb6b79022009-08-02 04:19:20 +02001024 dev->mode_config.tv_brightness_property =
Sascha Hauerd9bc3c02012-02-06 10:58:18 +01001025 drm_property_create_range(dev, 0, "brightness", 0, 100);
Francisco Jerezb6b79022009-08-02 04:19:20 +02001026
1027 dev->mode_config.tv_contrast_property =
Sascha Hauerd9bc3c02012-02-06 10:58:18 +01001028 drm_property_create_range(dev, 0, "contrast", 0, 100);
Francisco Jerezb6b79022009-08-02 04:19:20 +02001029
1030 dev->mode_config.tv_flicker_reduction_property =
Sascha Hauerd9bc3c02012-02-06 10:58:18 +01001031 drm_property_create_range(dev, 0, "flicker reduction", 0, 100);
Francisco Jerezb6b79022009-08-02 04:19:20 +02001032
Francisco Jereza75f0232009-08-12 02:30:10 +02001033 dev->mode_config.tv_overscan_property =
Sascha Hauerd9bc3c02012-02-06 10:58:18 +01001034 drm_property_create_range(dev, 0, "overscan", 0, 100);
Francisco Jereza75f0232009-08-12 02:30:10 +02001035
1036 dev->mode_config.tv_saturation_property =
Sascha Hauerd9bc3c02012-02-06 10:58:18 +01001037 drm_property_create_range(dev, 0, "saturation", 0, 100);
Francisco Jereza75f0232009-08-12 02:30:10 +02001038
1039 dev->mode_config.tv_hue_property =
Sascha Hauerd9bc3c02012-02-06 10:58:18 +01001040 drm_property_create_range(dev, 0, "hue", 0, 100);
Francisco Jereza75f0232009-08-12 02:30:10 +02001041
Dave Airlief453ba02008-11-07 14:05:41 -08001042 return 0;
1043}
1044EXPORT_SYMBOL(drm_mode_create_tv_properties);
1045
1046/**
1047 * drm_mode_create_scaling_mode_property - create scaling mode property
1048 * @dev: DRM device
1049 *
1050 * Called by a driver the first time it's needed, must be attached to desired
1051 * connectors.
1052 */
1053int drm_mode_create_scaling_mode_property(struct drm_device *dev)
1054{
1055 struct drm_property *scaling_mode;
Dave Airlief453ba02008-11-07 14:05:41 -08001056
1057 if (dev->mode_config.scaling_mode_property)
1058 return 0;
1059
1060 scaling_mode =
Sascha Hauer4a67d392012-02-06 10:58:17 +01001061 drm_property_create_enum(dev, 0, "scaling mode",
1062 drm_scaling_mode_enum_list,
Dave Airlief453ba02008-11-07 14:05:41 -08001063 ARRAY_SIZE(drm_scaling_mode_enum_list));
Dave Airlief453ba02008-11-07 14:05:41 -08001064
1065 dev->mode_config.scaling_mode_property = scaling_mode;
1066
1067 return 0;
1068}
1069EXPORT_SYMBOL(drm_mode_create_scaling_mode_property);
1070
1071/**
1072 * drm_mode_create_dithering_property - create dithering property
1073 * @dev: DRM device
1074 *
1075 * Called by a driver the first time it's needed, must be attached to desired
1076 * connectors.
1077 */
1078int drm_mode_create_dithering_property(struct drm_device *dev)
1079{
1080 struct drm_property *dithering_mode;
Dave Airlief453ba02008-11-07 14:05:41 -08001081
1082 if (dev->mode_config.dithering_mode_property)
1083 return 0;
1084
1085 dithering_mode =
Sascha Hauer4a67d392012-02-06 10:58:17 +01001086 drm_property_create_enum(dev, 0, "dithering",
1087 drm_dithering_mode_enum_list,
Dave Airlief453ba02008-11-07 14:05:41 -08001088 ARRAY_SIZE(drm_dithering_mode_enum_list));
Dave Airlief453ba02008-11-07 14:05:41 -08001089 dev->mode_config.dithering_mode_property = dithering_mode;
1090
1091 return 0;
1092}
1093EXPORT_SYMBOL(drm_mode_create_dithering_property);
1094
1095/**
Jakob Bornecrantz884840a2009-12-03 23:25:47 +00001096 * drm_mode_create_dirty_property - create dirty property
1097 * @dev: DRM device
1098 *
1099 * Called by a driver the first time it's needed, must be attached to desired
1100 * connectors.
1101 */
1102int drm_mode_create_dirty_info_property(struct drm_device *dev)
1103{
1104 struct drm_property *dirty_info;
Jakob Bornecrantz884840a2009-12-03 23:25:47 +00001105
1106 if (dev->mode_config.dirty_info_property)
1107 return 0;
1108
1109 dirty_info =
Sascha Hauer4a67d392012-02-06 10:58:17 +01001110 drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE,
Jakob Bornecrantz884840a2009-12-03 23:25:47 +00001111 "dirty",
Sascha Hauer4a67d392012-02-06 10:58:17 +01001112 drm_dirty_info_enum_list,
Jakob Bornecrantz884840a2009-12-03 23:25:47 +00001113 ARRAY_SIZE(drm_dirty_info_enum_list));
Jakob Bornecrantz884840a2009-12-03 23:25:47 +00001114 dev->mode_config.dirty_info_property = dirty_info;
1115
1116 return 0;
1117}
1118EXPORT_SYMBOL(drm_mode_create_dirty_info_property);
1119
Ville Syrjäläea9cbb02013-04-25 20:09:20 +03001120static int drm_mode_group_init(struct drm_device *dev, struct drm_mode_group *group)
Dave Airlief453ba02008-11-07 14:05:41 -08001121{
1122 uint32_t total_objects = 0;
1123
1124 total_objects += dev->mode_config.num_crtc;
1125 total_objects += dev->mode_config.num_connector;
1126 total_objects += dev->mode_config.num_encoder;
1127
Dave Airlief453ba02008-11-07 14:05:41 -08001128 group->id_list = kzalloc(total_objects * sizeof(uint32_t), GFP_KERNEL);
1129 if (!group->id_list)
1130 return -ENOMEM;
1131
1132 group->num_crtcs = 0;
1133 group->num_connectors = 0;
1134 group->num_encoders = 0;
1135 return 0;
1136}
1137
1138int drm_mode_group_init_legacy_group(struct drm_device *dev,
1139 struct drm_mode_group *group)
1140{
1141 struct drm_crtc *crtc;
1142 struct drm_encoder *encoder;
1143 struct drm_connector *connector;
1144 int ret;
1145
1146 if ((ret = drm_mode_group_init(dev, group)))
1147 return ret;
1148
1149 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
1150 group->id_list[group->num_crtcs++] = crtc->base.id;
1151
1152 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head)
1153 group->id_list[group->num_crtcs + group->num_encoders++] =
1154 encoder->base.id;
1155
1156 list_for_each_entry(connector, &dev->mode_config.connector_list, head)
1157 group->id_list[group->num_crtcs + group->num_encoders +
1158 group->num_connectors++] = connector->base.id;
1159
1160 return 0;
1161}
Dave Airlie9c1dfc52012-03-20 06:59:29 +00001162EXPORT_SYMBOL(drm_mode_group_init_legacy_group);
Dave Airlief453ba02008-11-07 14:05:41 -08001163
1164/**
Dave Airlief453ba02008-11-07 14:05:41 -08001165 * drm_crtc_convert_to_umode - convert a drm_display_mode into a modeinfo
1166 * @out: drm_mode_modeinfo struct to return to the user
1167 * @in: drm_display_mode to use
1168 *
Dave Airlief453ba02008-11-07 14:05:41 -08001169 * Convert a drm_display_mode into a drm_mode_modeinfo structure to return to
1170 * the user.
1171 */
Ville Syrjälä93bbf6d2012-03-13 12:35:47 +02001172static void drm_crtc_convert_to_umode(struct drm_mode_modeinfo *out,
1173 const struct drm_display_mode *in)
Dave Airlief453ba02008-11-07 14:05:41 -08001174{
Ville Syrjäläe36fae32012-03-13 12:35:40 +02001175 WARN(in->hdisplay > USHRT_MAX || in->hsync_start > USHRT_MAX ||
1176 in->hsync_end > USHRT_MAX || in->htotal > USHRT_MAX ||
1177 in->hskew > USHRT_MAX || in->vdisplay > USHRT_MAX ||
1178 in->vsync_start > USHRT_MAX || in->vsync_end > USHRT_MAX ||
1179 in->vtotal > USHRT_MAX || in->vscan > USHRT_MAX,
1180 "timing values too large for mode info\n");
1181
Dave Airlief453ba02008-11-07 14:05:41 -08001182 out->clock = in->clock;
1183 out->hdisplay = in->hdisplay;
1184 out->hsync_start = in->hsync_start;
1185 out->hsync_end = in->hsync_end;
1186 out->htotal = in->htotal;
1187 out->hskew = in->hskew;
1188 out->vdisplay = in->vdisplay;
1189 out->vsync_start = in->vsync_start;
1190 out->vsync_end = in->vsync_end;
1191 out->vtotal = in->vtotal;
1192 out->vscan = in->vscan;
1193 out->vrefresh = in->vrefresh;
1194 out->flags = in->flags;
1195 out->type = in->type;
1196 strncpy(out->name, in->name, DRM_DISPLAY_MODE_LEN);
1197 out->name[DRM_DISPLAY_MODE_LEN-1] = 0;
1198}
1199
1200/**
1201 * drm_crtc_convert_to_umode - convert a modeinfo into a drm_display_mode
1202 * @out: drm_display_mode to return to the user
1203 * @in: drm_mode_modeinfo to use
1204 *
Dave Airlief453ba02008-11-07 14:05:41 -08001205 * Convert a drm_mode_modeinfo into a drm_display_mode structure to return to
1206 * the caller.
Ville Syrjälä90367bf2012-03-13 12:35:44 +02001207 *
1208 * RETURNS:
1209 * Zero on success, errno on failure.
Dave Airlief453ba02008-11-07 14:05:41 -08001210 */
Ville Syrjälä93bbf6d2012-03-13 12:35:47 +02001211static int drm_crtc_convert_umode(struct drm_display_mode *out,
1212 const struct drm_mode_modeinfo *in)
Dave Airlief453ba02008-11-07 14:05:41 -08001213{
Ville Syrjälä90367bf2012-03-13 12:35:44 +02001214 if (in->clock > INT_MAX || in->vrefresh > INT_MAX)
1215 return -ERANGE;
1216
Dave Airlief453ba02008-11-07 14:05:41 -08001217 out->clock = in->clock;
1218 out->hdisplay = in->hdisplay;
1219 out->hsync_start = in->hsync_start;
1220 out->hsync_end = in->hsync_end;
1221 out->htotal = in->htotal;
1222 out->hskew = in->hskew;
1223 out->vdisplay = in->vdisplay;
1224 out->vsync_start = in->vsync_start;
1225 out->vsync_end = in->vsync_end;
1226 out->vtotal = in->vtotal;
1227 out->vscan = in->vscan;
1228 out->vrefresh = in->vrefresh;
1229 out->flags = in->flags;
1230 out->type = in->type;
1231 strncpy(out->name, in->name, DRM_DISPLAY_MODE_LEN);
1232 out->name[DRM_DISPLAY_MODE_LEN-1] = 0;
Ville Syrjälä90367bf2012-03-13 12:35:44 +02001233
1234 return 0;
Dave Airlief453ba02008-11-07 14:05:41 -08001235}
1236
1237/**
1238 * drm_mode_getresources - get graphics configuration
Daniel Vetter065a50ed2012-12-02 00:09:18 +01001239 * @dev: drm device for the ioctl
1240 * @data: data pointer for the ioctl
1241 * @file_priv: drm file for the ioctl call
Dave Airlief453ba02008-11-07 14:05:41 -08001242 *
Dave Airlief453ba02008-11-07 14:05:41 -08001243 * Construct a set of configuration description structures and return
1244 * them to the user, including CRTC, connector and framebuffer configuration.
1245 *
1246 * Called by the user via ioctl.
1247 *
1248 * RETURNS:
1249 * Zero on success, errno on failure.
1250 */
1251int drm_mode_getresources(struct drm_device *dev, void *data,
1252 struct drm_file *file_priv)
1253{
1254 struct drm_mode_card_res *card_res = data;
1255 struct list_head *lh;
1256 struct drm_framebuffer *fb;
1257 struct drm_connector *connector;
1258 struct drm_crtc *crtc;
1259 struct drm_encoder *encoder;
1260 int ret = 0;
1261 int connector_count = 0;
1262 int crtc_count = 0;
1263 int fb_count = 0;
1264 int encoder_count = 0;
1265 int copied = 0, i;
1266 uint32_t __user *fb_id;
1267 uint32_t __user *crtc_id;
1268 uint32_t __user *connector_id;
1269 uint32_t __user *encoder_id;
1270 struct drm_mode_group *mode_group;
1271
Dave Airliefb3b06c2011-02-08 13:55:21 +10001272 if (!drm_core_check_feature(dev, DRIVER_MODESET))
1273 return -EINVAL;
1274
Dave Airlief453ba02008-11-07 14:05:41 -08001275
Daniel Vetter4b096ac2012-12-10 21:19:18 +01001276 mutex_lock(&file_priv->fbs_lock);
Dave Airlief453ba02008-11-07 14:05:41 -08001277 /*
1278 * For the non-control nodes we need to limit the list of resources
1279 * by IDs in the group list for this node
1280 */
1281 list_for_each(lh, &file_priv->fbs)
1282 fb_count++;
1283
Daniel Vetter4b096ac2012-12-10 21:19:18 +01001284 /* handle this in 4 parts */
1285 /* FBs */
1286 if (card_res->count_fbs >= fb_count) {
1287 copied = 0;
1288 fb_id = (uint32_t __user *)(unsigned long)card_res->fb_id_ptr;
1289 list_for_each_entry(fb, &file_priv->fbs, filp_head) {
1290 if (put_user(fb->base.id, fb_id + copied)) {
1291 mutex_unlock(&file_priv->fbs_lock);
1292 return -EFAULT;
1293 }
1294 copied++;
1295 }
1296 }
1297 card_res->count_fbs = fb_count;
1298 mutex_unlock(&file_priv->fbs_lock);
1299
1300 drm_modeset_lock_all(dev);
Dave Airlief453ba02008-11-07 14:05:41 -08001301 mode_group = &file_priv->master->minor->mode_group;
1302 if (file_priv->master->minor->type == DRM_MINOR_CONTROL) {
1303
1304 list_for_each(lh, &dev->mode_config.crtc_list)
1305 crtc_count++;
1306
1307 list_for_each(lh, &dev->mode_config.connector_list)
1308 connector_count++;
1309
1310 list_for_each(lh, &dev->mode_config.encoder_list)
1311 encoder_count++;
1312 } else {
1313
1314 crtc_count = mode_group->num_crtcs;
1315 connector_count = mode_group->num_connectors;
1316 encoder_count = mode_group->num_encoders;
1317 }
1318
1319 card_res->max_height = dev->mode_config.max_height;
1320 card_res->min_height = dev->mode_config.min_height;
1321 card_res->max_width = dev->mode_config.max_width;
1322 card_res->min_width = dev->mode_config.min_width;
1323
Dave Airlief453ba02008-11-07 14:05:41 -08001324 /* CRTCs */
1325 if (card_res->count_crtcs >= crtc_count) {
1326 copied = 0;
1327 crtc_id = (uint32_t __user *)(unsigned long)card_res->crtc_id_ptr;
1328 if (file_priv->master->minor->type == DRM_MINOR_CONTROL) {
1329 list_for_each_entry(crtc, &dev->mode_config.crtc_list,
1330 head) {
Jerome Glisse94401062010-07-15 15:43:25 -04001331 DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id);
Dave Airlief453ba02008-11-07 14:05:41 -08001332 if (put_user(crtc->base.id, crtc_id + copied)) {
1333 ret = -EFAULT;
1334 goto out;
1335 }
1336 copied++;
1337 }
1338 } else {
1339 for (i = 0; i < mode_group->num_crtcs; i++) {
1340 if (put_user(mode_group->id_list[i],
1341 crtc_id + copied)) {
1342 ret = -EFAULT;
1343 goto out;
1344 }
1345 copied++;
1346 }
1347 }
1348 }
1349 card_res->count_crtcs = crtc_count;
1350
1351 /* Encoders */
1352 if (card_res->count_encoders >= encoder_count) {
1353 copied = 0;
1354 encoder_id = (uint32_t __user *)(unsigned long)card_res->encoder_id_ptr;
1355 if (file_priv->master->minor->type == DRM_MINOR_CONTROL) {
1356 list_for_each_entry(encoder,
1357 &dev->mode_config.encoder_list,
1358 head) {
Jerome Glisse94401062010-07-15 15:43:25 -04001359 DRM_DEBUG_KMS("[ENCODER:%d:%s]\n", encoder->base.id,
1360 drm_get_encoder_name(encoder));
Dave Airlief453ba02008-11-07 14:05:41 -08001361 if (put_user(encoder->base.id, encoder_id +
1362 copied)) {
1363 ret = -EFAULT;
1364 goto out;
1365 }
1366 copied++;
1367 }
1368 } else {
1369 for (i = mode_group->num_crtcs; i < mode_group->num_crtcs + mode_group->num_encoders; i++) {
1370 if (put_user(mode_group->id_list[i],
1371 encoder_id + copied)) {
1372 ret = -EFAULT;
1373 goto out;
1374 }
1375 copied++;
1376 }
1377
1378 }
1379 }
1380 card_res->count_encoders = encoder_count;
1381
1382 /* Connectors */
1383 if (card_res->count_connectors >= connector_count) {
1384 copied = 0;
1385 connector_id = (uint32_t __user *)(unsigned long)card_res->connector_id_ptr;
1386 if (file_priv->master->minor->type == DRM_MINOR_CONTROL) {
1387 list_for_each_entry(connector,
1388 &dev->mode_config.connector_list,
1389 head) {
Jerome Glisse94401062010-07-15 15:43:25 -04001390 DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
1391 connector->base.id,
1392 drm_get_connector_name(connector));
Dave Airlief453ba02008-11-07 14:05:41 -08001393 if (put_user(connector->base.id,
1394 connector_id + copied)) {
1395 ret = -EFAULT;
1396 goto out;
1397 }
1398 copied++;
1399 }
1400 } else {
1401 int start = mode_group->num_crtcs +
1402 mode_group->num_encoders;
1403 for (i = start; i < start + mode_group->num_connectors; i++) {
1404 if (put_user(mode_group->id_list[i],
1405 connector_id + copied)) {
1406 ret = -EFAULT;
1407 goto out;
1408 }
1409 copied++;
1410 }
1411 }
1412 }
1413 card_res->count_connectors = connector_count;
1414
Jerome Glisse94401062010-07-15 15:43:25 -04001415 DRM_DEBUG_KMS("CRTC[%d] CONNECTORS[%d] ENCODERS[%d]\n", card_res->count_crtcs,
Dave Airlief453ba02008-11-07 14:05:41 -08001416 card_res->count_connectors, card_res->count_encoders);
1417
1418out:
Daniel Vetter84849902012-12-02 00:28:11 +01001419 drm_modeset_unlock_all(dev);
Dave Airlief453ba02008-11-07 14:05:41 -08001420 return ret;
1421}
1422
1423/**
1424 * drm_mode_getcrtc - get CRTC configuration
Daniel Vetter065a50ed2012-12-02 00:09:18 +01001425 * @dev: drm device for the ioctl
1426 * @data: data pointer for the ioctl
1427 * @file_priv: drm file for the ioctl call
Dave Airlief453ba02008-11-07 14:05:41 -08001428 *
Dave Airlief453ba02008-11-07 14:05:41 -08001429 * Construct a CRTC configuration structure to return to the user.
1430 *
1431 * Called by the user via ioctl.
1432 *
1433 * RETURNS:
1434 * Zero on success, errno on failure.
1435 */
1436int drm_mode_getcrtc(struct drm_device *dev,
1437 void *data, struct drm_file *file_priv)
1438{
1439 struct drm_mode_crtc *crtc_resp = data;
1440 struct drm_crtc *crtc;
1441 struct drm_mode_object *obj;
1442 int ret = 0;
1443
Dave Airliefb3b06c2011-02-08 13:55:21 +10001444 if (!drm_core_check_feature(dev, DRIVER_MODESET))
1445 return -EINVAL;
1446
Daniel Vetter84849902012-12-02 00:28:11 +01001447 drm_modeset_lock_all(dev);
Dave Airlief453ba02008-11-07 14:05:41 -08001448
1449 obj = drm_mode_object_find(dev, crtc_resp->crtc_id,
1450 DRM_MODE_OBJECT_CRTC);
1451 if (!obj) {
1452 ret = -EINVAL;
1453 goto out;
1454 }
1455 crtc = obj_to_crtc(obj);
1456
1457 crtc_resp->x = crtc->x;
1458 crtc_resp->y = crtc->y;
1459 crtc_resp->gamma_size = crtc->gamma_size;
1460 if (crtc->fb)
1461 crtc_resp->fb_id = crtc->fb->base.id;
1462 else
1463 crtc_resp->fb_id = 0;
1464
1465 if (crtc->enabled) {
1466
1467 drm_crtc_convert_to_umode(&crtc_resp->mode, &crtc->mode);
1468 crtc_resp->mode_valid = 1;
1469
1470 } else {
1471 crtc_resp->mode_valid = 0;
1472 }
1473
1474out:
Daniel Vetter84849902012-12-02 00:28:11 +01001475 drm_modeset_unlock_all(dev);
Dave Airlief453ba02008-11-07 14:05:41 -08001476 return ret;
1477}
1478
1479/**
1480 * drm_mode_getconnector - get connector configuration
Daniel Vetter065a50ed2012-12-02 00:09:18 +01001481 * @dev: drm device for the ioctl
1482 * @data: data pointer for the ioctl
1483 * @file_priv: drm file for the ioctl call
Dave Airlief453ba02008-11-07 14:05:41 -08001484 *
Dave Airlief453ba02008-11-07 14:05:41 -08001485 * Construct a connector configuration structure to return to the user.
1486 *
1487 * Called by the user via ioctl.
1488 *
1489 * RETURNS:
1490 * Zero on success, errno on failure.
1491 */
1492int drm_mode_getconnector(struct drm_device *dev, void *data,
1493 struct drm_file *file_priv)
1494{
1495 struct drm_mode_get_connector *out_resp = data;
1496 struct drm_mode_object *obj;
1497 struct drm_connector *connector;
1498 struct drm_display_mode *mode;
1499 int mode_count = 0;
1500 int props_count = 0;
1501 int encoders_count = 0;
1502 int ret = 0;
1503 int copied = 0;
1504 int i;
1505 struct drm_mode_modeinfo u_mode;
1506 struct drm_mode_modeinfo __user *mode_ptr;
1507 uint32_t __user *prop_ptr;
1508 uint64_t __user *prop_values;
1509 uint32_t __user *encoder_ptr;
1510
Dave Airliefb3b06c2011-02-08 13:55:21 +10001511 if (!drm_core_check_feature(dev, DRIVER_MODESET))
1512 return -EINVAL;
1513
Dave Airlief453ba02008-11-07 14:05:41 -08001514 memset(&u_mode, 0, sizeof(struct drm_mode_modeinfo));
1515
Jerome Glisse94401062010-07-15 15:43:25 -04001516 DRM_DEBUG_KMS("[CONNECTOR:%d:?]\n", out_resp->connector_id);
Dave Airlief453ba02008-11-07 14:05:41 -08001517
Daniel Vetter7b240562012-12-12 00:35:33 +01001518 mutex_lock(&dev->mode_config.mutex);
Dave Airlief453ba02008-11-07 14:05:41 -08001519
1520 obj = drm_mode_object_find(dev, out_resp->connector_id,
1521 DRM_MODE_OBJECT_CONNECTOR);
1522 if (!obj) {
1523 ret = -EINVAL;
1524 goto out;
1525 }
1526 connector = obj_to_connector(obj);
1527
Paulo Zanoni7f88a9b2012-05-15 18:09:04 -03001528 props_count = connector->properties.count;
Dave Airlief453ba02008-11-07 14:05:41 -08001529
1530 for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
1531 if (connector->encoder_ids[i] != 0) {
1532 encoders_count++;
1533 }
1534 }
1535
1536 if (out_resp->count_modes == 0) {
1537 connector->funcs->fill_modes(connector,
1538 dev->mode_config.max_width,
1539 dev->mode_config.max_height);
1540 }
1541
1542 /* delayed so we get modes regardless of pre-fill_modes state */
1543 list_for_each_entry(mode, &connector->modes, head)
1544 mode_count++;
1545
1546 out_resp->connector_id = connector->base.id;
1547 out_resp->connector_type = connector->connector_type;
1548 out_resp->connector_type_id = connector->connector_type_id;
1549 out_resp->mm_width = connector->display_info.width_mm;
1550 out_resp->mm_height = connector->display_info.height_mm;
1551 out_resp->subpixel = connector->display_info.subpixel_order;
1552 out_resp->connection = connector->status;
1553 if (connector->encoder)
1554 out_resp->encoder_id = connector->encoder->base.id;
1555 else
1556 out_resp->encoder_id = 0;
1557
1558 /*
1559 * This ioctl is called twice, once to determine how much space is
1560 * needed, and the 2nd time to fill it.
1561 */
1562 if ((out_resp->count_modes >= mode_count) && mode_count) {
1563 copied = 0;
Ville Syrjälä81f6c7f2011-12-20 00:06:42 +02001564 mode_ptr = (struct drm_mode_modeinfo __user *)(unsigned long)out_resp->modes_ptr;
Dave Airlief453ba02008-11-07 14:05:41 -08001565 list_for_each_entry(mode, &connector->modes, head) {
1566 drm_crtc_convert_to_umode(&u_mode, mode);
1567 if (copy_to_user(mode_ptr + copied,
1568 &u_mode, sizeof(u_mode))) {
1569 ret = -EFAULT;
1570 goto out;
1571 }
1572 copied++;
1573 }
1574 }
1575 out_resp->count_modes = mode_count;
1576
1577 if ((out_resp->count_props >= props_count) && props_count) {
1578 copied = 0;
Ville Syrjälä81f6c7f2011-12-20 00:06:42 +02001579 prop_ptr = (uint32_t __user *)(unsigned long)(out_resp->props_ptr);
1580 prop_values = (uint64_t __user *)(unsigned long)(out_resp->prop_values_ptr);
Paulo Zanoni7f88a9b2012-05-15 18:09:04 -03001581 for (i = 0; i < connector->properties.count; i++) {
1582 if (put_user(connector->properties.ids[i],
1583 prop_ptr + copied)) {
1584 ret = -EFAULT;
1585 goto out;
Dave Airlief453ba02008-11-07 14:05:41 -08001586 }
Paulo Zanoni7f88a9b2012-05-15 18:09:04 -03001587
1588 if (put_user(connector->properties.values[i],
1589 prop_values + copied)) {
1590 ret = -EFAULT;
1591 goto out;
1592 }
1593 copied++;
Dave Airlief453ba02008-11-07 14:05:41 -08001594 }
1595 }
1596 out_resp->count_props = props_count;
1597
1598 if ((out_resp->count_encoders >= encoders_count) && encoders_count) {
1599 copied = 0;
Ville Syrjälä81f6c7f2011-12-20 00:06:42 +02001600 encoder_ptr = (uint32_t __user *)(unsigned long)(out_resp->encoders_ptr);
Dave Airlief453ba02008-11-07 14:05:41 -08001601 for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
1602 if (connector->encoder_ids[i] != 0) {
1603 if (put_user(connector->encoder_ids[i],
1604 encoder_ptr + copied)) {
1605 ret = -EFAULT;
1606 goto out;
1607 }
1608 copied++;
1609 }
1610 }
1611 }
1612 out_resp->count_encoders = encoders_count;
1613
1614out:
Daniel Vetter7b240562012-12-12 00:35:33 +01001615 mutex_unlock(&dev->mode_config.mutex);
1616
Dave Airlief453ba02008-11-07 14:05:41 -08001617 return ret;
1618}
1619
1620int drm_mode_getencoder(struct drm_device *dev, void *data,
1621 struct drm_file *file_priv)
1622{
1623 struct drm_mode_get_encoder *enc_resp = data;
1624 struct drm_mode_object *obj;
1625 struct drm_encoder *encoder;
1626 int ret = 0;
1627
Dave Airliefb3b06c2011-02-08 13:55:21 +10001628 if (!drm_core_check_feature(dev, DRIVER_MODESET))
1629 return -EINVAL;
1630
Daniel Vetter84849902012-12-02 00:28:11 +01001631 drm_modeset_lock_all(dev);
Dave Airlief453ba02008-11-07 14:05:41 -08001632 obj = drm_mode_object_find(dev, enc_resp->encoder_id,
1633 DRM_MODE_OBJECT_ENCODER);
1634 if (!obj) {
1635 ret = -EINVAL;
1636 goto out;
1637 }
1638 encoder = obj_to_encoder(obj);
1639
1640 if (encoder->crtc)
1641 enc_resp->crtc_id = encoder->crtc->base.id;
1642 else
1643 enc_resp->crtc_id = 0;
1644 enc_resp->encoder_type = encoder->encoder_type;
1645 enc_resp->encoder_id = encoder->base.id;
1646 enc_resp->possible_crtcs = encoder->possible_crtcs;
1647 enc_resp->possible_clones = encoder->possible_clones;
1648
1649out:
Daniel Vetter84849902012-12-02 00:28:11 +01001650 drm_modeset_unlock_all(dev);
Dave Airlief453ba02008-11-07 14:05:41 -08001651 return ret;
1652}
1653
1654/**
Jesse Barnes8cf5c912011-11-14 14:51:27 -08001655 * drm_mode_getplane_res - get plane info
1656 * @dev: DRM device
1657 * @data: ioctl data
1658 * @file_priv: DRM file info
1659 *
1660 * Return an plane count and set of IDs.
1661 */
1662int drm_mode_getplane_res(struct drm_device *dev, void *data,
1663 struct drm_file *file_priv)
1664{
1665 struct drm_mode_get_plane_res *plane_resp = data;
1666 struct drm_mode_config *config;
1667 struct drm_plane *plane;
1668 uint32_t __user *plane_ptr;
1669 int copied = 0, ret = 0;
1670
1671 if (!drm_core_check_feature(dev, DRIVER_MODESET))
1672 return -EINVAL;
1673
Daniel Vetter84849902012-12-02 00:28:11 +01001674 drm_modeset_lock_all(dev);
Jesse Barnes8cf5c912011-11-14 14:51:27 -08001675 config = &dev->mode_config;
1676
1677 /*
1678 * This ioctl is called twice, once to determine how much space is
1679 * needed, and the 2nd time to fill it.
1680 */
1681 if (config->num_plane &&
1682 (plane_resp->count_planes >= config->num_plane)) {
Ville Syrjälä81f6c7f2011-12-20 00:06:42 +02001683 plane_ptr = (uint32_t __user *)(unsigned long)plane_resp->plane_id_ptr;
Jesse Barnes8cf5c912011-11-14 14:51:27 -08001684
1685 list_for_each_entry(plane, &config->plane_list, head) {
1686 if (put_user(plane->base.id, plane_ptr + copied)) {
1687 ret = -EFAULT;
1688 goto out;
1689 }
1690 copied++;
1691 }
1692 }
1693 plane_resp->count_planes = config->num_plane;
1694
1695out:
Daniel Vetter84849902012-12-02 00:28:11 +01001696 drm_modeset_unlock_all(dev);
Jesse Barnes8cf5c912011-11-14 14:51:27 -08001697 return ret;
1698}
1699
1700/**
1701 * drm_mode_getplane - get plane info
1702 * @dev: DRM device
1703 * @data: ioctl data
1704 * @file_priv: DRM file info
1705 *
1706 * Return plane info, including formats supported, gamma size, any
1707 * current fb, etc.
1708 */
1709int drm_mode_getplane(struct drm_device *dev, void *data,
1710 struct drm_file *file_priv)
1711{
1712 struct drm_mode_get_plane *plane_resp = data;
1713 struct drm_mode_object *obj;
1714 struct drm_plane *plane;
1715 uint32_t __user *format_ptr;
1716 int ret = 0;
1717
1718 if (!drm_core_check_feature(dev, DRIVER_MODESET))
1719 return -EINVAL;
1720
Daniel Vetter84849902012-12-02 00:28:11 +01001721 drm_modeset_lock_all(dev);
Jesse Barnes8cf5c912011-11-14 14:51:27 -08001722 obj = drm_mode_object_find(dev, plane_resp->plane_id,
1723 DRM_MODE_OBJECT_PLANE);
1724 if (!obj) {
1725 ret = -ENOENT;
1726 goto out;
1727 }
1728 plane = obj_to_plane(obj);
1729
1730 if (plane->crtc)
1731 plane_resp->crtc_id = plane->crtc->base.id;
1732 else
1733 plane_resp->crtc_id = 0;
1734
1735 if (plane->fb)
1736 plane_resp->fb_id = plane->fb->base.id;
1737 else
1738 plane_resp->fb_id = 0;
1739
1740 plane_resp->plane_id = plane->base.id;
1741 plane_resp->possible_crtcs = plane->possible_crtcs;
1742 plane_resp->gamma_size = plane->gamma_size;
1743
1744 /*
1745 * This ioctl is called twice, once to determine how much space is
1746 * needed, and the 2nd time to fill it.
1747 */
1748 if (plane->format_count &&
1749 (plane_resp->count_format_types >= plane->format_count)) {
Ville Syrjälä81f6c7f2011-12-20 00:06:42 +02001750 format_ptr = (uint32_t __user *)(unsigned long)plane_resp->format_type_ptr;
Jesse Barnes8cf5c912011-11-14 14:51:27 -08001751 if (copy_to_user(format_ptr,
1752 plane->format_types,
1753 sizeof(uint32_t) * plane->format_count)) {
1754 ret = -EFAULT;
1755 goto out;
1756 }
1757 }
1758 plane_resp->count_format_types = plane->format_count;
1759
1760out:
Daniel Vetter84849902012-12-02 00:28:11 +01001761 drm_modeset_unlock_all(dev);
Jesse Barnes8cf5c912011-11-14 14:51:27 -08001762 return ret;
1763}
1764
1765/**
1766 * drm_mode_setplane - set up or tear down an plane
1767 * @dev: DRM device
1768 * @data: ioctl data*
Daniel Vetter065a50ed2012-12-02 00:09:18 +01001769 * @file_priv: DRM file info
Jesse Barnes8cf5c912011-11-14 14:51:27 -08001770 *
1771 * Set plane info, including placement, fb, scaling, and other factors.
1772 * Or pass a NULL fb to disable.
1773 */
1774int drm_mode_setplane(struct drm_device *dev, void *data,
1775 struct drm_file *file_priv)
1776{
1777 struct drm_mode_set_plane *plane_req = data;
1778 struct drm_mode_object *obj;
1779 struct drm_plane *plane;
1780 struct drm_crtc *crtc;
Daniel Vetter6c2a7532012-12-11 00:59:24 +01001781 struct drm_framebuffer *fb = NULL, *old_fb = NULL;
Jesse Barnes8cf5c912011-11-14 14:51:27 -08001782 int ret = 0;
Ville Syrjälä42ef8782011-12-20 00:06:44 +02001783 unsigned int fb_width, fb_height;
Ville Syrjälä62443be2011-12-20 00:06:47 +02001784 int i;
Jesse Barnes8cf5c912011-11-14 14:51:27 -08001785
1786 if (!drm_core_check_feature(dev, DRIVER_MODESET))
1787 return -EINVAL;
1788
Jesse Barnes8cf5c912011-11-14 14:51:27 -08001789 /*
1790 * First, find the plane, crtc, and fb objects. If not available,
1791 * we don't bother to call the driver.
1792 */
1793 obj = drm_mode_object_find(dev, plane_req->plane_id,
1794 DRM_MODE_OBJECT_PLANE);
1795 if (!obj) {
1796 DRM_DEBUG_KMS("Unknown plane ID %d\n",
1797 plane_req->plane_id);
Daniel Vetter6c2a7532012-12-11 00:59:24 +01001798 return -ENOENT;
Jesse Barnes8cf5c912011-11-14 14:51:27 -08001799 }
1800 plane = obj_to_plane(obj);
1801
1802 /* No fb means shut it down */
1803 if (!plane_req->fb_id) {
Daniel Vetter6c2a7532012-12-11 00:59:24 +01001804 drm_modeset_lock_all(dev);
1805 old_fb = plane->fb;
Jesse Barnes8cf5c912011-11-14 14:51:27 -08001806 plane->funcs->disable_plane(plane);
Ville Syrjäläe5e3b442011-12-20 00:06:43 +02001807 plane->crtc = NULL;
1808 plane->fb = NULL;
Daniel Vetter6c2a7532012-12-11 00:59:24 +01001809 drm_modeset_unlock_all(dev);
Jesse Barnes8cf5c912011-11-14 14:51:27 -08001810 goto out;
1811 }
1812
1813 obj = drm_mode_object_find(dev, plane_req->crtc_id,
1814 DRM_MODE_OBJECT_CRTC);
1815 if (!obj) {
1816 DRM_DEBUG_KMS("Unknown crtc ID %d\n",
1817 plane_req->crtc_id);
1818 ret = -ENOENT;
1819 goto out;
1820 }
1821 crtc = obj_to_crtc(obj);
1822
Daniel Vetter786b99e2012-12-02 21:53:40 +01001823 fb = drm_framebuffer_lookup(dev, plane_req->fb_id);
1824 if (!fb) {
Jesse Barnes8cf5c912011-11-14 14:51:27 -08001825 DRM_DEBUG_KMS("Unknown framebuffer ID %d\n",
1826 plane_req->fb_id);
1827 ret = -ENOENT;
1828 goto out;
1829 }
Jesse Barnes8cf5c912011-11-14 14:51:27 -08001830
Ville Syrjälä62443be2011-12-20 00:06:47 +02001831 /* Check whether this plane supports the fb pixel format. */
1832 for (i = 0; i < plane->format_count; i++)
1833 if (fb->pixel_format == plane->format_types[i])
1834 break;
1835 if (i == plane->format_count) {
1836 DRM_DEBUG_KMS("Invalid pixel format 0x%08x\n", fb->pixel_format);
1837 ret = -EINVAL;
1838 goto out;
1839 }
1840
Ville Syrjälä42ef8782011-12-20 00:06:44 +02001841 fb_width = fb->width << 16;
1842 fb_height = fb->height << 16;
1843
1844 /* Make sure source coordinates are inside the fb. */
1845 if (plane_req->src_w > fb_width ||
1846 plane_req->src_x > fb_width - plane_req->src_w ||
1847 plane_req->src_h > fb_height ||
1848 plane_req->src_y > fb_height - plane_req->src_h) {
1849 DRM_DEBUG_KMS("Invalid source coordinates "
1850 "%u.%06ux%u.%06u+%u.%06u+%u.%06u\n",
1851 plane_req->src_w >> 16,
1852 ((plane_req->src_w & 0xffff) * 15625) >> 10,
1853 plane_req->src_h >> 16,
1854 ((plane_req->src_h & 0xffff) * 15625) >> 10,
1855 plane_req->src_x >> 16,
1856 ((plane_req->src_x & 0xffff) * 15625) >> 10,
1857 plane_req->src_y >> 16,
1858 ((plane_req->src_y & 0xffff) * 15625) >> 10);
1859 ret = -ENOSPC;
1860 goto out;
1861 }
1862
Ville Syrjälä687a0402011-12-20 00:06:45 +02001863 /* Give drivers some help against integer overflows */
1864 if (plane_req->crtc_w > INT_MAX ||
1865 plane_req->crtc_x > INT_MAX - (int32_t) plane_req->crtc_w ||
1866 plane_req->crtc_h > INT_MAX ||
1867 plane_req->crtc_y > INT_MAX - (int32_t) plane_req->crtc_h) {
1868 DRM_DEBUG_KMS("Invalid CRTC coordinates %ux%u+%d+%d\n",
1869 plane_req->crtc_w, plane_req->crtc_h,
1870 plane_req->crtc_x, plane_req->crtc_y);
1871 ret = -ERANGE;
1872 goto out;
1873 }
1874
Daniel Vetter6c2a7532012-12-11 00:59:24 +01001875 drm_modeset_lock_all(dev);
Jesse Barnes8cf5c912011-11-14 14:51:27 -08001876 ret = plane->funcs->update_plane(plane, crtc, fb,
1877 plane_req->crtc_x, plane_req->crtc_y,
1878 plane_req->crtc_w, plane_req->crtc_h,
1879 plane_req->src_x, plane_req->src_y,
1880 plane_req->src_w, plane_req->src_h);
1881 if (!ret) {
Daniel Vetter6c2a7532012-12-11 00:59:24 +01001882 old_fb = plane->fb;
Jesse Barnes8cf5c912011-11-14 14:51:27 -08001883 plane->crtc = crtc;
1884 plane->fb = fb;
Daniel Vetter35f8bad2013-02-15 21:21:37 +01001885 fb = NULL;
Jesse Barnes8cf5c912011-11-14 14:51:27 -08001886 }
Daniel Vetter6c2a7532012-12-11 00:59:24 +01001887 drm_modeset_unlock_all(dev);
Jesse Barnes8cf5c912011-11-14 14:51:27 -08001888
1889out:
Daniel Vetter6c2a7532012-12-11 00:59:24 +01001890 if (fb)
1891 drm_framebuffer_unreference(fb);
1892 if (old_fb)
1893 drm_framebuffer_unreference(old_fb);
Jesse Barnes8cf5c912011-11-14 14:51:27 -08001894
1895 return ret;
1896}
1897
1898/**
Daniel Vetter2d13b672012-12-11 13:47:23 +01001899 * drm_mode_set_config_internal - helper to call ->set_config
1900 * @set: modeset config to set
1901 *
1902 * This is a little helper to wrap internal calls to the ->set_config driver
1903 * interface. The only thing it adds is correct refcounting dance.
1904 */
1905int drm_mode_set_config_internal(struct drm_mode_set *set)
1906{
1907 struct drm_crtc *crtc = set->crtc;
Daniel Vetterb0d12322012-12-11 01:07:12 +01001908 struct drm_framebuffer *fb, *old_fb;
1909 int ret;
Daniel Vetter2d13b672012-12-11 13:47:23 +01001910
Daniel Vetterb0d12322012-12-11 01:07:12 +01001911 old_fb = crtc->fb;
1912 fb = set->fb;
1913
1914 ret = crtc->funcs->set_config(set);
1915 if (ret == 0) {
1916 if (old_fb)
1917 drm_framebuffer_unreference(old_fb);
1918 if (fb)
1919 drm_framebuffer_reference(fb);
1920 }
1921
1922 return ret;
Daniel Vetter2d13b672012-12-11 13:47:23 +01001923}
1924EXPORT_SYMBOL(drm_mode_set_config_internal);
1925
1926/**
Dave Airlief453ba02008-11-07 14:05:41 -08001927 * drm_mode_setcrtc - set CRTC configuration
Daniel Vetter065a50ed2012-12-02 00:09:18 +01001928 * @dev: drm device for the ioctl
1929 * @data: data pointer for the ioctl
1930 * @file_priv: drm file for the ioctl call
Dave Airlief453ba02008-11-07 14:05:41 -08001931 *
Dave Airlief453ba02008-11-07 14:05:41 -08001932 * Build a new CRTC configuration based on user request.
1933 *
1934 * Called by the user via ioctl.
1935 *
1936 * RETURNS:
1937 * Zero on success, errno on failure.
1938 */
1939int drm_mode_setcrtc(struct drm_device *dev, void *data,
1940 struct drm_file *file_priv)
1941{
1942 struct drm_mode_config *config = &dev->mode_config;
1943 struct drm_mode_crtc *crtc_req = data;
1944 struct drm_mode_object *obj;
Ville Syrjälä6653cc82012-03-13 12:35:38 +02001945 struct drm_crtc *crtc;
Dave Airlief453ba02008-11-07 14:05:41 -08001946 struct drm_connector **connector_set = NULL, *connector;
1947 struct drm_framebuffer *fb = NULL;
1948 struct drm_display_mode *mode = NULL;
1949 struct drm_mode_set set;
1950 uint32_t __user *set_connectors_ptr;
Laurent Pinchart4a1b0712012-05-17 13:27:21 +02001951 int ret;
Dave Airlief453ba02008-11-07 14:05:41 -08001952 int i;
1953
Dave Airliefb3b06c2011-02-08 13:55:21 +10001954 if (!drm_core_check_feature(dev, DRIVER_MODESET))
1955 return -EINVAL;
1956
Ville Syrjälä1d97e912012-03-13 12:35:41 +02001957 /* For some reason crtc x/y offsets are signed internally. */
1958 if (crtc_req->x > INT_MAX || crtc_req->y > INT_MAX)
1959 return -ERANGE;
1960
Daniel Vetter84849902012-12-02 00:28:11 +01001961 drm_modeset_lock_all(dev);
Dave Airlief453ba02008-11-07 14:05:41 -08001962 obj = drm_mode_object_find(dev, crtc_req->crtc_id,
1963 DRM_MODE_OBJECT_CRTC);
1964 if (!obj) {
Zhao Yakui58367ed2009-07-20 13:48:07 +08001965 DRM_DEBUG_KMS("Unknown CRTC ID %d\n", crtc_req->crtc_id);
Dave Airlief453ba02008-11-07 14:05:41 -08001966 ret = -EINVAL;
1967 goto out;
1968 }
1969 crtc = obj_to_crtc(obj);
Jerome Glisse94401062010-07-15 15:43:25 -04001970 DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id);
Dave Airlief453ba02008-11-07 14:05:41 -08001971
1972 if (crtc_req->mode_valid) {
Rob Clark7c80e122012-09-04 16:35:56 +00001973 int hdisplay, vdisplay;
Dave Airlief453ba02008-11-07 14:05:41 -08001974 /* If we have a mode we need a framebuffer. */
1975 /* If we pass -1, set the mode with the currently bound fb */
1976 if (crtc_req->fb_id == -1) {
Ville Syrjälä6653cc82012-03-13 12:35:38 +02001977 if (!crtc->fb) {
1978 DRM_DEBUG_KMS("CRTC doesn't have current FB\n");
1979 ret = -EINVAL;
1980 goto out;
Dave Airlief453ba02008-11-07 14:05:41 -08001981 }
Ville Syrjälä6653cc82012-03-13 12:35:38 +02001982 fb = crtc->fb;
Daniel Vetterb0d12322012-12-11 01:07:12 +01001983 /* Make refcounting symmetric with the lookup path. */
1984 drm_framebuffer_reference(fb);
Dave Airlief453ba02008-11-07 14:05:41 -08001985 } else {
Daniel Vetter786b99e2012-12-02 21:53:40 +01001986 fb = drm_framebuffer_lookup(dev, crtc_req->fb_id);
1987 if (!fb) {
Zhao Yakui58367ed2009-07-20 13:48:07 +08001988 DRM_DEBUG_KMS("Unknown FB ID%d\n",
1989 crtc_req->fb_id);
Dave Airlief453ba02008-11-07 14:05:41 -08001990 ret = -EINVAL;
1991 goto out;
1992 }
Dave Airlief453ba02008-11-07 14:05:41 -08001993 }
1994
1995 mode = drm_mode_create(dev);
Ville Syrjäläee34ab52012-03-13 12:35:43 +02001996 if (!mode) {
1997 ret = -ENOMEM;
1998 goto out;
1999 }
2000
Ville Syrjälä90367bf2012-03-13 12:35:44 +02002001 ret = drm_crtc_convert_umode(mode, &crtc_req->mode);
2002 if (ret) {
2003 DRM_DEBUG_KMS("Invalid mode\n");
2004 goto out;
2005 }
2006
Dave Airlief453ba02008-11-07 14:05:41 -08002007 drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
Ville Syrjälä5f61bb42012-03-13 12:35:45 +02002008
Rob Clark7c80e122012-09-04 16:35:56 +00002009 hdisplay = mode->hdisplay;
2010 vdisplay = mode->vdisplay;
2011
2012 if (crtc->invert_dimensions)
2013 swap(hdisplay, vdisplay);
2014
2015 if (hdisplay > fb->width ||
2016 vdisplay > fb->height ||
2017 crtc_req->x > fb->width - hdisplay ||
2018 crtc_req->y > fb->height - vdisplay) {
2019 DRM_DEBUG_KMS("Invalid fb size %ux%u for CRTC viewport %ux%u+%d+%d%s.\n",
2020 fb->width, fb->height,
2021 hdisplay, vdisplay, crtc_req->x, crtc_req->y,
2022 crtc->invert_dimensions ? " (inverted)" : "");
Ville Syrjälä5f61bb42012-03-13 12:35:45 +02002023 ret = -ENOSPC;
2024 goto out;
2025 }
Dave Airlief453ba02008-11-07 14:05:41 -08002026 }
2027
2028 if (crtc_req->count_connectors == 0 && mode) {
Zhao Yakui58367ed2009-07-20 13:48:07 +08002029 DRM_DEBUG_KMS("Count connectors is 0 but mode set\n");
Dave Airlief453ba02008-11-07 14:05:41 -08002030 ret = -EINVAL;
2031 goto out;
2032 }
2033
Jakob Bornecrantz7781de72009-08-03 13:43:58 +01002034 if (crtc_req->count_connectors > 0 && (!mode || !fb)) {
Zhao Yakui58367ed2009-07-20 13:48:07 +08002035 DRM_DEBUG_KMS("Count connectors is %d but no mode or fb set\n",
Dave Airlief453ba02008-11-07 14:05:41 -08002036 crtc_req->count_connectors);
2037 ret = -EINVAL;
2038 goto out;
2039 }
2040
2041 if (crtc_req->count_connectors > 0) {
2042 u32 out_id;
2043
2044 /* Avoid unbounded kernel memory allocation */
2045 if (crtc_req->count_connectors > config->num_connector) {
2046 ret = -EINVAL;
2047 goto out;
2048 }
2049
2050 connector_set = kmalloc(crtc_req->count_connectors *
2051 sizeof(struct drm_connector *),
2052 GFP_KERNEL);
2053 if (!connector_set) {
2054 ret = -ENOMEM;
2055 goto out;
2056 }
2057
2058 for (i = 0; i < crtc_req->count_connectors; i++) {
Ville Syrjälä81f6c7f2011-12-20 00:06:42 +02002059 set_connectors_ptr = (uint32_t __user *)(unsigned long)crtc_req->set_connectors_ptr;
Dave Airlief453ba02008-11-07 14:05:41 -08002060 if (get_user(out_id, &set_connectors_ptr[i])) {
2061 ret = -EFAULT;
2062 goto out;
2063 }
2064
2065 obj = drm_mode_object_find(dev, out_id,
2066 DRM_MODE_OBJECT_CONNECTOR);
2067 if (!obj) {
Zhao Yakui58367ed2009-07-20 13:48:07 +08002068 DRM_DEBUG_KMS("Connector id %d unknown\n",
2069 out_id);
Dave Airlief453ba02008-11-07 14:05:41 -08002070 ret = -EINVAL;
2071 goto out;
2072 }
2073 connector = obj_to_connector(obj);
Jerome Glisse94401062010-07-15 15:43:25 -04002074 DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
2075 connector->base.id,
2076 drm_get_connector_name(connector));
Dave Airlief453ba02008-11-07 14:05:41 -08002077
2078 connector_set[i] = connector;
2079 }
2080 }
2081
2082 set.crtc = crtc;
2083 set.x = crtc_req->x;
2084 set.y = crtc_req->y;
2085 set.mode = mode;
2086 set.connectors = connector_set;
2087 set.num_connectors = crtc_req->count_connectors;
Dave Airlie5ef5f722009-08-17 13:11:23 +10002088 set.fb = fb;
Daniel Vetter2d13b672012-12-11 13:47:23 +01002089 ret = drm_mode_set_config_internal(&set);
Dave Airlief453ba02008-11-07 14:05:41 -08002090
2091out:
Daniel Vetterb0d12322012-12-11 01:07:12 +01002092 if (fb)
2093 drm_framebuffer_unreference(fb);
2094
Dave Airlief453ba02008-11-07 14:05:41 -08002095 kfree(connector_set);
Ville Syrjäläee34ab52012-03-13 12:35:43 +02002096 drm_mode_destroy(dev, mode);
Daniel Vetter84849902012-12-02 00:28:11 +01002097 drm_modeset_unlock_all(dev);
Dave Airlief453ba02008-11-07 14:05:41 -08002098 return ret;
2099}
2100
2101int drm_mode_cursor_ioctl(struct drm_device *dev,
2102 void *data, struct drm_file *file_priv)
2103{
2104 struct drm_mode_cursor *req = data;
2105 struct drm_mode_object *obj;
2106 struct drm_crtc *crtc;
2107 int ret = 0;
2108
Dave Airliefb3b06c2011-02-08 13:55:21 +10002109 if (!drm_core_check_feature(dev, DRIVER_MODESET))
2110 return -EINVAL;
2111
Jakob Bornecrantz7c4eaca2012-08-16 08:29:03 +00002112 if (!req->flags || (~DRM_MODE_CURSOR_FLAGS & req->flags))
Dave Airlief453ba02008-11-07 14:05:41 -08002113 return -EINVAL;
Dave Airlief453ba02008-11-07 14:05:41 -08002114
Jakob Bornecrantze0c84632008-12-19 14:50:50 +10002115 obj = drm_mode_object_find(dev, req->crtc_id, DRM_MODE_OBJECT_CRTC);
Dave Airlief453ba02008-11-07 14:05:41 -08002116 if (!obj) {
Zhao Yakui58367ed2009-07-20 13:48:07 +08002117 DRM_DEBUG_KMS("Unknown CRTC ID %d\n", req->crtc_id);
Daniel Vetterdac35662012-12-02 15:24:10 +01002118 return -EINVAL;
Dave Airlief453ba02008-11-07 14:05:41 -08002119 }
2120 crtc = obj_to_crtc(obj);
2121
Daniel Vetterdac35662012-12-02 15:24:10 +01002122 mutex_lock(&crtc->mutex);
Dave Airlief453ba02008-11-07 14:05:41 -08002123 if (req->flags & DRM_MODE_CURSOR_BO) {
2124 if (!crtc->funcs->cursor_set) {
Dave Airlief453ba02008-11-07 14:05:41 -08002125 ret = -ENXIO;
2126 goto out;
2127 }
2128 /* Turns off the cursor if handle is 0 */
2129 ret = crtc->funcs->cursor_set(crtc, file_priv, req->handle,
2130 req->width, req->height);
2131 }
2132
2133 if (req->flags & DRM_MODE_CURSOR_MOVE) {
2134 if (crtc->funcs->cursor_move) {
2135 ret = crtc->funcs->cursor_move(crtc, req->x, req->y);
2136 } else {
Dave Airlief453ba02008-11-07 14:05:41 -08002137 ret = -EFAULT;
2138 goto out;
2139 }
2140 }
2141out:
Daniel Vetterdac35662012-12-02 15:24:10 +01002142 mutex_unlock(&crtc->mutex);
2143
Dave Airlief453ba02008-11-07 14:05:41 -08002144 return ret;
2145}
2146
Jesse Barnes308e5bc2011-11-14 14:51:28 -08002147/* Original addfb only supported RGB formats, so figure out which one */
2148uint32_t drm_mode_legacy_fb_format(uint32_t bpp, uint32_t depth)
2149{
2150 uint32_t fmt;
2151
2152 switch (bpp) {
2153 case 8:
Ville Syrjäläd84f0312013-01-31 19:43:38 +02002154 fmt = DRM_FORMAT_C8;
Jesse Barnes308e5bc2011-11-14 14:51:28 -08002155 break;
2156 case 16:
2157 if (depth == 15)
Ville Syrjälä04b39242011-11-17 18:05:13 +02002158 fmt = DRM_FORMAT_XRGB1555;
Jesse Barnes308e5bc2011-11-14 14:51:28 -08002159 else
Ville Syrjälä04b39242011-11-17 18:05:13 +02002160 fmt = DRM_FORMAT_RGB565;
Jesse Barnes308e5bc2011-11-14 14:51:28 -08002161 break;
2162 case 24:
Ville Syrjälä04b39242011-11-17 18:05:13 +02002163 fmt = DRM_FORMAT_RGB888;
Jesse Barnes308e5bc2011-11-14 14:51:28 -08002164 break;
2165 case 32:
2166 if (depth == 24)
Ville Syrjälä04b39242011-11-17 18:05:13 +02002167 fmt = DRM_FORMAT_XRGB8888;
Jesse Barnes308e5bc2011-11-14 14:51:28 -08002168 else if (depth == 30)
Ville Syrjälä04b39242011-11-17 18:05:13 +02002169 fmt = DRM_FORMAT_XRGB2101010;
Jesse Barnes308e5bc2011-11-14 14:51:28 -08002170 else
Ville Syrjälä04b39242011-11-17 18:05:13 +02002171 fmt = DRM_FORMAT_ARGB8888;
Jesse Barnes308e5bc2011-11-14 14:51:28 -08002172 break;
2173 default:
Ville Syrjälä04b39242011-11-17 18:05:13 +02002174 DRM_ERROR("bad bpp, assuming x8r8g8b8 pixel format\n");
2175 fmt = DRM_FORMAT_XRGB8888;
Jesse Barnes308e5bc2011-11-14 14:51:28 -08002176 break;
2177 }
2178
2179 return fmt;
2180}
2181EXPORT_SYMBOL(drm_mode_legacy_fb_format);
2182
Dave Airlief453ba02008-11-07 14:05:41 -08002183/**
2184 * drm_mode_addfb - add an FB to the graphics configuration
Daniel Vetter065a50ed2012-12-02 00:09:18 +01002185 * @dev: drm device for the ioctl
2186 * @data: data pointer for the ioctl
2187 * @file_priv: drm file for the ioctl call
Dave Airlief453ba02008-11-07 14:05:41 -08002188 *
Dave Airlief453ba02008-11-07 14:05:41 -08002189 * Add a new FB to the specified CRTC, given a user request.
2190 *
2191 * Called by the user via ioctl.
2192 *
2193 * RETURNS:
2194 * Zero on success, errno on failure.
2195 */
2196int drm_mode_addfb(struct drm_device *dev,
2197 void *data, struct drm_file *file_priv)
2198{
Jesse Barnes308e5bc2011-11-14 14:51:28 -08002199 struct drm_mode_fb_cmd *or = data;
2200 struct drm_mode_fb_cmd2 r = {};
2201 struct drm_mode_config *config = &dev->mode_config;
2202 struct drm_framebuffer *fb;
2203 int ret = 0;
2204
2205 /* Use new struct with format internally */
2206 r.fb_id = or->fb_id;
2207 r.width = or->width;
2208 r.height = or->height;
2209 r.pitches[0] = or->pitch;
2210 r.pixel_format = drm_mode_legacy_fb_format(or->bpp, or->depth);
2211 r.handles[0] = or->handle;
2212
2213 if (!drm_core_check_feature(dev, DRIVER_MODESET))
2214 return -EINVAL;
2215
Jesse Barnesacb4b992011-11-07 12:03:23 -08002216 if ((config->min_width > r.width) || (r.width > config->max_width))
Jesse Barnes308e5bc2011-11-14 14:51:28 -08002217 return -EINVAL;
Jesse Barnesacb4b992011-11-07 12:03:23 -08002218
2219 if ((config->min_height > r.height) || (r.height > config->max_height))
Jesse Barnes308e5bc2011-11-14 14:51:28 -08002220 return -EINVAL;
Jesse Barnes308e5bc2011-11-14 14:51:28 -08002221
Jesse Barnes308e5bc2011-11-14 14:51:28 -08002222 fb = dev->mode_config.funcs->fb_create(dev, file_priv, &r);
2223 if (IS_ERR(fb)) {
Dave Airlie1aa1b112012-05-01 17:38:35 +01002224 DRM_DEBUG_KMS("could not create framebuffer\n");
Daniel Vetter4b096ac2012-12-10 21:19:18 +01002225 return PTR_ERR(fb);
Jesse Barnes308e5bc2011-11-14 14:51:28 -08002226 }
2227
Daniel Vetter4b096ac2012-12-10 21:19:18 +01002228 mutex_lock(&file_priv->fbs_lock);
Jesse Barnes308e5bc2011-11-14 14:51:28 -08002229 or->fb_id = fb->base.id;
2230 list_add(&fb->filp_head, &file_priv->fbs);
2231 DRM_DEBUG_KMS("[FB:%d]\n", fb->base.id);
Daniel Vetter4b096ac2012-12-10 21:19:18 +01002232 mutex_unlock(&file_priv->fbs_lock);
Daniel Vetter4b096ac2012-12-10 21:19:18 +01002233
Jesse Barnes308e5bc2011-11-14 14:51:28 -08002234 return ret;
2235}
2236
Ville Syrjäläcff91b62012-05-24 20:54:00 +03002237static int format_check(const struct drm_mode_fb_cmd2 *r)
Ville Syrjälä935b59772011-12-20 00:06:48 +02002238{
2239 uint32_t format = r->pixel_format & ~DRM_FORMAT_BIG_ENDIAN;
2240
2241 switch (format) {
2242 case DRM_FORMAT_C8:
2243 case DRM_FORMAT_RGB332:
2244 case DRM_FORMAT_BGR233:
2245 case DRM_FORMAT_XRGB4444:
2246 case DRM_FORMAT_XBGR4444:
2247 case DRM_FORMAT_RGBX4444:
2248 case DRM_FORMAT_BGRX4444:
2249 case DRM_FORMAT_ARGB4444:
2250 case DRM_FORMAT_ABGR4444:
2251 case DRM_FORMAT_RGBA4444:
2252 case DRM_FORMAT_BGRA4444:
2253 case DRM_FORMAT_XRGB1555:
2254 case DRM_FORMAT_XBGR1555:
2255 case DRM_FORMAT_RGBX5551:
2256 case DRM_FORMAT_BGRX5551:
2257 case DRM_FORMAT_ARGB1555:
2258 case DRM_FORMAT_ABGR1555:
2259 case DRM_FORMAT_RGBA5551:
2260 case DRM_FORMAT_BGRA5551:
2261 case DRM_FORMAT_RGB565:
2262 case DRM_FORMAT_BGR565:
2263 case DRM_FORMAT_RGB888:
2264 case DRM_FORMAT_BGR888:
2265 case DRM_FORMAT_XRGB8888:
2266 case DRM_FORMAT_XBGR8888:
2267 case DRM_FORMAT_RGBX8888:
2268 case DRM_FORMAT_BGRX8888:
2269 case DRM_FORMAT_ARGB8888:
2270 case DRM_FORMAT_ABGR8888:
2271 case DRM_FORMAT_RGBA8888:
2272 case DRM_FORMAT_BGRA8888:
2273 case DRM_FORMAT_XRGB2101010:
2274 case DRM_FORMAT_XBGR2101010:
2275 case DRM_FORMAT_RGBX1010102:
2276 case DRM_FORMAT_BGRX1010102:
2277 case DRM_FORMAT_ARGB2101010:
2278 case DRM_FORMAT_ABGR2101010:
2279 case DRM_FORMAT_RGBA1010102:
2280 case DRM_FORMAT_BGRA1010102:
2281 case DRM_FORMAT_YUYV:
2282 case DRM_FORMAT_YVYU:
2283 case DRM_FORMAT_UYVY:
2284 case DRM_FORMAT_VYUY:
2285 case DRM_FORMAT_AYUV:
2286 case DRM_FORMAT_NV12:
2287 case DRM_FORMAT_NV21:
2288 case DRM_FORMAT_NV16:
2289 case DRM_FORMAT_NV61:
Laurent Pinchartba623f62012-05-18 23:47:40 +02002290 case DRM_FORMAT_NV24:
2291 case DRM_FORMAT_NV42:
Ville Syrjälä935b59772011-12-20 00:06:48 +02002292 case DRM_FORMAT_YUV410:
2293 case DRM_FORMAT_YVU410:
2294 case DRM_FORMAT_YUV411:
2295 case DRM_FORMAT_YVU411:
2296 case DRM_FORMAT_YUV420:
2297 case DRM_FORMAT_YVU420:
2298 case DRM_FORMAT_YUV422:
2299 case DRM_FORMAT_YVU422:
2300 case DRM_FORMAT_YUV444:
2301 case DRM_FORMAT_YVU444:
2302 return 0;
2303 default:
2304 return -EINVAL;
2305 }
2306}
2307
Ville Syrjäläcff91b62012-05-24 20:54:00 +03002308static int framebuffer_check(const struct drm_mode_fb_cmd2 *r)
Ville Syrjäläd1b45d52012-04-05 21:35:18 +03002309{
2310 int ret, hsub, vsub, num_planes, i;
2311
2312 ret = format_check(r);
2313 if (ret) {
Dave Airlie1aa1b112012-05-01 17:38:35 +01002314 DRM_DEBUG_KMS("bad framebuffer format 0x%08x\n", r->pixel_format);
Ville Syrjäläd1b45d52012-04-05 21:35:18 +03002315 return ret;
2316 }
2317
2318 hsub = drm_format_horz_chroma_subsampling(r->pixel_format);
2319 vsub = drm_format_vert_chroma_subsampling(r->pixel_format);
2320 num_planes = drm_format_num_planes(r->pixel_format);
2321
2322 if (r->width == 0 || r->width % hsub) {
Dave Airlie1aa1b112012-05-01 17:38:35 +01002323 DRM_DEBUG_KMS("bad framebuffer width %u\n", r->height);
Ville Syrjäläd1b45d52012-04-05 21:35:18 +03002324 return -EINVAL;
2325 }
2326
2327 if (r->height == 0 || r->height % vsub) {
Dave Airlie1aa1b112012-05-01 17:38:35 +01002328 DRM_DEBUG_KMS("bad framebuffer height %u\n", r->height);
Ville Syrjäläd1b45d52012-04-05 21:35:18 +03002329 return -EINVAL;
2330 }
2331
2332 for (i = 0; i < num_planes; i++) {
2333 unsigned int width = r->width / (i != 0 ? hsub : 1);
Ville Syrjäläb180b5d2012-10-25 18:05:04 +00002334 unsigned int height = r->height / (i != 0 ? vsub : 1);
2335 unsigned int cpp = drm_format_plane_cpp(r->pixel_format, i);
Ville Syrjäläd1b45d52012-04-05 21:35:18 +03002336
2337 if (!r->handles[i]) {
Dave Airlie1aa1b112012-05-01 17:38:35 +01002338 DRM_DEBUG_KMS("no buffer object handle for plane %d\n", i);
Ville Syrjäläd1b45d52012-04-05 21:35:18 +03002339 return -EINVAL;
2340 }
2341
Ville Syrjäläb180b5d2012-10-25 18:05:04 +00002342 if ((uint64_t) width * cpp > UINT_MAX)
2343 return -ERANGE;
2344
2345 if ((uint64_t) height * r->pitches[i] + r->offsets[i] > UINT_MAX)
2346 return -ERANGE;
2347
2348 if (r->pitches[i] < width * cpp) {
Dave Airlie1aa1b112012-05-01 17:38:35 +01002349 DRM_DEBUG_KMS("bad pitch %u for plane %d\n", r->pitches[i], i);
Ville Syrjäläd1b45d52012-04-05 21:35:18 +03002350 return -EINVAL;
2351 }
2352 }
2353
2354 return 0;
2355}
2356
Jesse Barnes308e5bc2011-11-14 14:51:28 -08002357/**
2358 * drm_mode_addfb2 - add an FB to the graphics configuration
Daniel Vetter065a50ed2012-12-02 00:09:18 +01002359 * @dev: drm device for the ioctl
2360 * @data: data pointer for the ioctl
2361 * @file_priv: drm file for the ioctl call
Jesse Barnes308e5bc2011-11-14 14:51:28 -08002362 *
Jesse Barnes308e5bc2011-11-14 14:51:28 -08002363 * Add a new FB to the specified CRTC, given a user request with format.
2364 *
2365 * Called by the user via ioctl.
2366 *
2367 * RETURNS:
2368 * Zero on success, errno on failure.
2369 */
2370int drm_mode_addfb2(struct drm_device *dev,
2371 void *data, struct drm_file *file_priv)
2372{
2373 struct drm_mode_fb_cmd2 *r = data;
Dave Airlief453ba02008-11-07 14:05:41 -08002374 struct drm_mode_config *config = &dev->mode_config;
2375 struct drm_framebuffer *fb;
Laurent Pinchart4a1b0712012-05-17 13:27:21 +02002376 int ret;
Dave Airlief453ba02008-11-07 14:05:41 -08002377
Dave Airliefb3b06c2011-02-08 13:55:21 +10002378 if (!drm_core_check_feature(dev, DRIVER_MODESET))
2379 return -EINVAL;
2380
Ville Syrjäläe3cc3522012-11-08 09:09:42 +00002381 if (r->flags & ~DRM_MODE_FB_INTERLACED) {
2382 DRM_DEBUG_KMS("bad framebuffer flags 0x%08x\n", r->flags);
2383 return -EINVAL;
2384 }
2385
Dave Airlief453ba02008-11-07 14:05:41 -08002386 if ((config->min_width > r->width) || (r->width > config->max_width)) {
Dave Airlie1aa1b112012-05-01 17:38:35 +01002387 DRM_DEBUG_KMS("bad framebuffer width %d, should be >= %d && <= %d\n",
Jesse Barnes8cf5c912011-11-14 14:51:27 -08002388 r->width, config->min_width, config->max_width);
Dave Airlief453ba02008-11-07 14:05:41 -08002389 return -EINVAL;
2390 }
2391 if ((config->min_height > r->height) || (r->height > config->max_height)) {
Dave Airlie1aa1b112012-05-01 17:38:35 +01002392 DRM_DEBUG_KMS("bad framebuffer height %d, should be >= %d && <= %d\n",
Jesse Barnes8cf5c912011-11-14 14:51:27 -08002393 r->height, config->min_height, config->max_height);
Dave Airlief453ba02008-11-07 14:05:41 -08002394 return -EINVAL;
2395 }
2396
Ville Syrjäläd1b45d52012-04-05 21:35:18 +03002397 ret = framebuffer_check(r);
2398 if (ret)
Ville Syrjälä935b59772011-12-20 00:06:48 +02002399 return ret;
Ville Syrjälä935b59772011-12-20 00:06:48 +02002400
Dave Airlief453ba02008-11-07 14:05:41 -08002401 fb = dev->mode_config.funcs->fb_create(dev, file_priv, r);
Chris Wilsoncce13ff2010-08-08 13:36:38 +01002402 if (IS_ERR(fb)) {
Dave Airlie1aa1b112012-05-01 17:38:35 +01002403 DRM_DEBUG_KMS("could not create framebuffer\n");
Daniel Vetter4b096ac2012-12-10 21:19:18 +01002404 return PTR_ERR(fb);
Dave Airlief453ba02008-11-07 14:05:41 -08002405 }
2406
Daniel Vetter4b096ac2012-12-10 21:19:18 +01002407 mutex_lock(&file_priv->fbs_lock);
Jakob Bornecrantze0c84632008-12-19 14:50:50 +10002408 r->fb_id = fb->base.id;
Dave Airlief453ba02008-11-07 14:05:41 -08002409 list_add(&fb->filp_head, &file_priv->fbs);
Jerome Glisse94401062010-07-15 15:43:25 -04002410 DRM_DEBUG_KMS("[FB:%d]\n", fb->base.id);
Daniel Vetter4b096ac2012-12-10 21:19:18 +01002411 mutex_unlock(&file_priv->fbs_lock);
Dave Airlief453ba02008-11-07 14:05:41 -08002412
Daniel Vetter4b096ac2012-12-10 21:19:18 +01002413
Dave Airlief453ba02008-11-07 14:05:41 -08002414 return ret;
2415}
2416
2417/**
2418 * drm_mode_rmfb - remove an FB from the configuration
Daniel Vetter065a50ed2012-12-02 00:09:18 +01002419 * @dev: drm device for the ioctl
2420 * @data: data pointer for the ioctl
2421 * @file_priv: drm file for the ioctl call
Dave Airlief453ba02008-11-07 14:05:41 -08002422 *
Dave Airlief453ba02008-11-07 14:05:41 -08002423 * Remove the FB specified by the user.
2424 *
2425 * Called by the user via ioctl.
2426 *
2427 * RETURNS:
2428 * Zero on success, errno on failure.
2429 */
2430int drm_mode_rmfb(struct drm_device *dev,
2431 void *data, struct drm_file *file_priv)
2432{
Dave Airlief453ba02008-11-07 14:05:41 -08002433 struct drm_framebuffer *fb = NULL;
2434 struct drm_framebuffer *fbl = NULL;
2435 uint32_t *id = data;
Dave Airlief453ba02008-11-07 14:05:41 -08002436 int found = 0;
2437
Dave Airliefb3b06c2011-02-08 13:55:21 +10002438 if (!drm_core_check_feature(dev, DRIVER_MODESET))
2439 return -EINVAL;
2440
Daniel Vetter4b096ac2012-12-10 21:19:18 +01002441 mutex_lock(&file_priv->fbs_lock);
Daniel Vetter2b677e82012-12-10 21:16:05 +01002442 mutex_lock(&dev->mode_config.fb_lock);
2443 fb = __drm_framebuffer_lookup(dev, *id);
2444 if (!fb)
2445 goto fail_lookup;
2446
Dave Airlief453ba02008-11-07 14:05:41 -08002447 list_for_each_entry(fbl, &file_priv->fbs, filp_head)
2448 if (fb == fbl)
2449 found = 1;
Daniel Vetter2b677e82012-12-10 21:16:05 +01002450 if (!found)
2451 goto fail_lookup;
2452
2453 /* Mark fb as reaped, we still have a ref from fpriv->fbs. */
2454 __drm_framebuffer_unregister(dev, fb);
Dave Airlief453ba02008-11-07 14:05:41 -08002455
Daniel Vetter4b096ac2012-12-10 21:19:18 +01002456 list_del_init(&fb->filp_head);
Daniel Vetter2b677e82012-12-10 21:16:05 +01002457 mutex_unlock(&dev->mode_config.fb_lock);
Daniel Vetter4b096ac2012-12-10 21:19:18 +01002458 mutex_unlock(&file_priv->fbs_lock);
Dave Airlief453ba02008-11-07 14:05:41 -08002459
Daniel Vetter4b096ac2012-12-10 21:19:18 +01002460 drm_framebuffer_remove(fb);
Daniel Vetter4b096ac2012-12-10 21:19:18 +01002461
Daniel Vetter2b677e82012-12-10 21:16:05 +01002462 return 0;
2463
2464fail_lookup:
2465 mutex_unlock(&dev->mode_config.fb_lock);
2466 mutex_unlock(&file_priv->fbs_lock);
2467
2468 return -EINVAL;
Dave Airlief453ba02008-11-07 14:05:41 -08002469}
2470
2471/**
2472 * drm_mode_getfb - get FB info
Daniel Vetter065a50ed2012-12-02 00:09:18 +01002473 * @dev: drm device for the ioctl
2474 * @data: data pointer for the ioctl
2475 * @file_priv: drm file for the ioctl call
Dave Airlief453ba02008-11-07 14:05:41 -08002476 *
Dave Airlief453ba02008-11-07 14:05:41 -08002477 * Lookup the FB given its ID and return info about it.
2478 *
2479 * Called by the user via ioctl.
2480 *
2481 * RETURNS:
2482 * Zero on success, errno on failure.
2483 */
2484int drm_mode_getfb(struct drm_device *dev,
2485 void *data, struct drm_file *file_priv)
2486{
2487 struct drm_mode_fb_cmd *r = data;
Dave Airlief453ba02008-11-07 14:05:41 -08002488 struct drm_framebuffer *fb;
Daniel Vetter58c0dca2012-12-13 23:06:08 +01002489 int ret;
Dave Airlief453ba02008-11-07 14:05:41 -08002490
Dave Airliefb3b06c2011-02-08 13:55:21 +10002491 if (!drm_core_check_feature(dev, DRIVER_MODESET))
2492 return -EINVAL;
2493
Daniel Vetter786b99e2012-12-02 21:53:40 +01002494 fb = drm_framebuffer_lookup(dev, r->fb_id);
Daniel Vetter58c0dca2012-12-13 23:06:08 +01002495 if (!fb)
2496 return -EINVAL;
Dave Airlief453ba02008-11-07 14:05:41 -08002497
2498 r->height = fb->height;
2499 r->width = fb->width;
2500 r->depth = fb->depth;
2501 r->bpp = fb->bits_per_pixel;
Ville Syrjälä01f2c772011-12-20 00:06:49 +02002502 r->pitch = fb->pitches[0];
Daniel Vetteraf26ef32012-12-13 23:07:50 +01002503 if (fb->funcs->create_handle)
2504 ret = fb->funcs->create_handle(fb, file_priv, &r->handle);
2505 else
2506 ret = -ENODEV;
Dave Airlief453ba02008-11-07 14:05:41 -08002507
Daniel Vetter58c0dca2012-12-13 23:06:08 +01002508 drm_framebuffer_unreference(fb);
2509
Dave Airlief453ba02008-11-07 14:05:41 -08002510 return ret;
2511}
2512
Jakob Bornecrantz884840a2009-12-03 23:25:47 +00002513int drm_mode_dirtyfb_ioctl(struct drm_device *dev,
2514 void *data, struct drm_file *file_priv)
2515{
2516 struct drm_clip_rect __user *clips_ptr;
2517 struct drm_clip_rect *clips = NULL;
2518 struct drm_mode_fb_dirty_cmd *r = data;
Jakob Bornecrantz884840a2009-12-03 23:25:47 +00002519 struct drm_framebuffer *fb;
2520 unsigned flags;
2521 int num_clips;
Laurent Pinchart4a1b0712012-05-17 13:27:21 +02002522 int ret;
Jakob Bornecrantz884840a2009-12-03 23:25:47 +00002523
Dave Airliefb3b06c2011-02-08 13:55:21 +10002524 if (!drm_core_check_feature(dev, DRIVER_MODESET))
2525 return -EINVAL;
2526
Daniel Vetter786b99e2012-12-02 21:53:40 +01002527 fb = drm_framebuffer_lookup(dev, r->fb_id);
Daniel Vetter4ccf0972012-12-11 00:38:18 +01002528 if (!fb)
2529 return -EINVAL;
Jakob Bornecrantz884840a2009-12-03 23:25:47 +00002530
2531 num_clips = r->num_clips;
Ville Syrjälä81f6c7f2011-12-20 00:06:42 +02002532 clips_ptr = (struct drm_clip_rect __user *)(unsigned long)r->clips_ptr;
Jakob Bornecrantz884840a2009-12-03 23:25:47 +00002533
2534 if (!num_clips != !clips_ptr) {
2535 ret = -EINVAL;
2536 goto out_err1;
2537 }
2538
2539 flags = DRM_MODE_FB_DIRTY_FLAGS & r->flags;
2540
2541 /* If userspace annotates copy, clips must come in pairs */
2542 if (flags & DRM_MODE_FB_DIRTY_ANNOTATE_COPY && (num_clips % 2)) {
2543 ret = -EINVAL;
2544 goto out_err1;
2545 }
2546
2547 if (num_clips && clips_ptr) {
Xi Wanga5cd3352011-11-23 01:12:01 -05002548 if (num_clips < 0 || num_clips > DRM_MODE_FB_DIRTY_MAX_CLIPS) {
2549 ret = -EINVAL;
2550 goto out_err1;
2551 }
Jakob Bornecrantz884840a2009-12-03 23:25:47 +00002552 clips = kzalloc(num_clips * sizeof(*clips), GFP_KERNEL);
2553 if (!clips) {
2554 ret = -ENOMEM;
2555 goto out_err1;
2556 }
2557
2558 ret = copy_from_user(clips, clips_ptr,
2559 num_clips * sizeof(*clips));
Dan Carpentere902a352010-06-04 12:23:21 +02002560 if (ret) {
2561 ret = -EFAULT;
Jakob Bornecrantz884840a2009-12-03 23:25:47 +00002562 goto out_err2;
Dan Carpentere902a352010-06-04 12:23:21 +02002563 }
Jakob Bornecrantz884840a2009-12-03 23:25:47 +00002564 }
2565
2566 if (fb->funcs->dirty) {
Daniel Vetter4ccf0972012-12-11 00:38:18 +01002567 drm_modeset_lock_all(dev);
Thomas Hellstrom02b00162010-10-05 12:43:02 +02002568 ret = fb->funcs->dirty(fb, file_priv, flags, r->color,
2569 clips, num_clips);
Daniel Vetter4ccf0972012-12-11 00:38:18 +01002570 drm_modeset_unlock_all(dev);
Jakob Bornecrantz884840a2009-12-03 23:25:47 +00002571 } else {
2572 ret = -ENOSYS;
Jakob Bornecrantz884840a2009-12-03 23:25:47 +00002573 }
2574
2575out_err2:
2576 kfree(clips);
2577out_err1:
Daniel Vetter4ccf0972012-12-11 00:38:18 +01002578 drm_framebuffer_unreference(fb);
2579
Jakob Bornecrantz884840a2009-12-03 23:25:47 +00002580 return ret;
2581}
2582
2583
Dave Airlief453ba02008-11-07 14:05:41 -08002584/**
2585 * drm_fb_release - remove and free the FBs on this file
Daniel Vetter065a50ed2012-12-02 00:09:18 +01002586 * @priv: drm file for the ioctl
Dave Airlief453ba02008-11-07 14:05:41 -08002587 *
Dave Airlief453ba02008-11-07 14:05:41 -08002588 * Destroy all the FBs associated with @filp.
2589 *
2590 * Called by the user via ioctl.
2591 *
2592 * RETURNS:
2593 * Zero on success, errno on failure.
2594 */
Kristian Høgsbergea39f832009-02-12 14:37:56 -05002595void drm_fb_release(struct drm_file *priv)
Dave Airlief453ba02008-11-07 14:05:41 -08002596{
Dave Airlief453ba02008-11-07 14:05:41 -08002597 struct drm_device *dev = priv->minor->dev;
2598 struct drm_framebuffer *fb, *tfb;
2599
Daniel Vetter4b096ac2012-12-10 21:19:18 +01002600 mutex_lock(&priv->fbs_lock);
Dave Airlief453ba02008-11-07 14:05:41 -08002601 list_for_each_entry_safe(fb, tfb, &priv->fbs, filp_head) {
Daniel Vetter2b677e82012-12-10 21:16:05 +01002602
2603 mutex_lock(&dev->mode_config.fb_lock);
2604 /* Mark fb as reaped, we still have a ref from fpriv->fbs. */
2605 __drm_framebuffer_unregister(dev, fb);
2606 mutex_unlock(&dev->mode_config.fb_lock);
2607
Daniel Vetter4b096ac2012-12-10 21:19:18 +01002608 list_del_init(&fb->filp_head);
Daniel Vetter2b677e82012-12-10 21:16:05 +01002609
2610 /* This will also drop the fpriv->fbs reference. */
Rob Clarkf7eff602012-09-05 21:48:38 +00002611 drm_framebuffer_remove(fb);
Dave Airlief453ba02008-11-07 14:05:41 -08002612 }
Daniel Vetter4b096ac2012-12-10 21:19:18 +01002613 mutex_unlock(&priv->fbs_lock);
Dave Airlief453ba02008-11-07 14:05:41 -08002614}
2615
2616/**
2617 * drm_mode_attachmode - add a mode to the user mode list
2618 * @dev: DRM device
2619 * @connector: connector to add the mode to
2620 * @mode: mode to add
2621 *
2622 * Add @mode to @connector's user mode list.
2623 */
Ville Syrjälä1dd6c8b2012-03-13 12:35:42 +02002624static void drm_mode_attachmode(struct drm_device *dev,
2625 struct drm_connector *connector,
2626 struct drm_display_mode *mode)
Dave Airlief453ba02008-11-07 14:05:41 -08002627{
Dave Airlief453ba02008-11-07 14:05:41 -08002628 list_add_tail(&mode->head, &connector->user_modes);
Dave Airlief453ba02008-11-07 14:05:41 -08002629}
2630
2631int drm_mode_attachmode_crtc(struct drm_device *dev, struct drm_crtc *crtc,
Ville Syrjäläac235da2012-03-13 12:35:46 +02002632 const struct drm_display_mode *mode)
Dave Airlief453ba02008-11-07 14:05:41 -08002633{
2634 struct drm_connector *connector;
Ville Syrjäläac235da2012-03-13 12:35:46 +02002635 int ret = 0;
2636 struct drm_display_mode *dup_mode, *next;
2637 LIST_HEAD(list);
2638
Dave Airlief453ba02008-11-07 14:05:41 -08002639 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
2640 if (!connector->encoder)
Ville Syrjäläac235da2012-03-13 12:35:46 +02002641 continue;
Dave Airlief453ba02008-11-07 14:05:41 -08002642 if (connector->encoder->crtc == crtc) {
Ville Syrjäläac235da2012-03-13 12:35:46 +02002643 dup_mode = drm_mode_duplicate(dev, mode);
2644 if (!dup_mode) {
2645 ret = -ENOMEM;
2646 goto out;
2647 }
2648 list_add_tail(&dup_mode->head, &list);
Dave Airlief453ba02008-11-07 14:05:41 -08002649 }
2650 }
Ville Syrjäläac235da2012-03-13 12:35:46 +02002651
2652 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
2653 if (!connector->encoder)
2654 continue;
2655 if (connector->encoder->crtc == crtc)
2656 list_move_tail(list.next, &connector->user_modes);
2657 }
2658
2659 WARN_ON(!list_empty(&list));
2660
2661 out:
2662 list_for_each_entry_safe(dup_mode, next, &list, head)
2663 drm_mode_destroy(dev, dup_mode);
2664
2665 return ret;
Dave Airlief453ba02008-11-07 14:05:41 -08002666}
2667EXPORT_SYMBOL(drm_mode_attachmode_crtc);
2668
2669static int drm_mode_detachmode(struct drm_device *dev,
2670 struct drm_connector *connector,
2671 struct drm_display_mode *mode)
2672{
2673 int found = 0;
2674 int ret = 0;
2675 struct drm_display_mode *match_mode, *t;
2676
2677 list_for_each_entry_safe(match_mode, t, &connector->user_modes, head) {
2678 if (drm_mode_equal(match_mode, mode)) {
2679 list_del(&match_mode->head);
2680 drm_mode_destroy(dev, match_mode);
2681 found = 1;
2682 break;
2683 }
2684 }
2685
2686 if (!found)
2687 ret = -EINVAL;
2688
2689 return ret;
2690}
2691
2692int drm_mode_detachmode_crtc(struct drm_device *dev, struct drm_display_mode *mode)
2693{
2694 struct drm_connector *connector;
2695
2696 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
2697 drm_mode_detachmode(dev, connector, mode);
2698 }
2699 return 0;
2700}
2701EXPORT_SYMBOL(drm_mode_detachmode_crtc);
2702
2703/**
2704 * drm_fb_attachmode - Attach a user mode to an connector
Daniel Vetter065a50ed2012-12-02 00:09:18 +01002705 * @dev: drm device for the ioctl
2706 * @data: data pointer for the ioctl
2707 * @file_priv: drm file for the ioctl call
Dave Airlief453ba02008-11-07 14:05:41 -08002708 *
2709 * This attaches a user specified mode to an connector.
2710 * Called by the user via ioctl.
2711 *
2712 * RETURNS:
2713 * Zero on success, errno on failure.
2714 */
2715int drm_mode_attachmode_ioctl(struct drm_device *dev,
2716 void *data, struct drm_file *file_priv)
2717{
2718 struct drm_mode_mode_cmd *mode_cmd = data;
2719 struct drm_connector *connector;
2720 struct drm_display_mode *mode;
2721 struct drm_mode_object *obj;
2722 struct drm_mode_modeinfo *umode = &mode_cmd->mode;
Laurent Pinchart4a1b0712012-05-17 13:27:21 +02002723 int ret;
Dave Airlief453ba02008-11-07 14:05:41 -08002724
Dave Airliefb3b06c2011-02-08 13:55:21 +10002725 if (!drm_core_check_feature(dev, DRIVER_MODESET))
2726 return -EINVAL;
2727
Daniel Vetter84849902012-12-02 00:28:11 +01002728 drm_modeset_lock_all(dev);
Dave Airlief453ba02008-11-07 14:05:41 -08002729
2730 obj = drm_mode_object_find(dev, mode_cmd->connector_id, DRM_MODE_OBJECT_CONNECTOR);
2731 if (!obj) {
2732 ret = -EINVAL;
2733 goto out;
2734 }
2735 connector = obj_to_connector(obj);
2736
2737 mode = drm_mode_create(dev);
2738 if (!mode) {
2739 ret = -ENOMEM;
2740 goto out;
2741 }
2742
Ville Syrjälä90367bf2012-03-13 12:35:44 +02002743 ret = drm_crtc_convert_umode(mode, umode);
2744 if (ret) {
2745 DRM_DEBUG_KMS("Invalid mode\n");
2746 drm_mode_destroy(dev, mode);
2747 goto out;
2748 }
Dave Airlief453ba02008-11-07 14:05:41 -08002749
Ville Syrjälä1dd6c8b2012-03-13 12:35:42 +02002750 drm_mode_attachmode(dev, connector, mode);
Dave Airlief453ba02008-11-07 14:05:41 -08002751out:
Daniel Vetter84849902012-12-02 00:28:11 +01002752 drm_modeset_unlock_all(dev);
Dave Airlief453ba02008-11-07 14:05:41 -08002753 return ret;
2754}
2755
2756
2757/**
2758 * drm_fb_detachmode - Detach a user specified mode from an connector
Daniel Vetter065a50ed2012-12-02 00:09:18 +01002759 * @dev: drm device for the ioctl
2760 * @data: data pointer for the ioctl
2761 * @file_priv: drm file for the ioctl call
Dave Airlief453ba02008-11-07 14:05:41 -08002762 *
2763 * Called by the user via ioctl.
2764 *
2765 * RETURNS:
2766 * Zero on success, errno on failure.
2767 */
2768int drm_mode_detachmode_ioctl(struct drm_device *dev,
2769 void *data, struct drm_file *file_priv)
2770{
2771 struct drm_mode_object *obj;
2772 struct drm_mode_mode_cmd *mode_cmd = data;
2773 struct drm_connector *connector;
2774 struct drm_display_mode mode;
2775 struct drm_mode_modeinfo *umode = &mode_cmd->mode;
Laurent Pinchart4a1b0712012-05-17 13:27:21 +02002776 int ret;
Dave Airlief453ba02008-11-07 14:05:41 -08002777
Dave Airliefb3b06c2011-02-08 13:55:21 +10002778 if (!drm_core_check_feature(dev, DRIVER_MODESET))
2779 return -EINVAL;
2780
Daniel Vetter84849902012-12-02 00:28:11 +01002781 drm_modeset_lock_all(dev);
Dave Airlief453ba02008-11-07 14:05:41 -08002782
2783 obj = drm_mode_object_find(dev, mode_cmd->connector_id, DRM_MODE_OBJECT_CONNECTOR);
2784 if (!obj) {
2785 ret = -EINVAL;
2786 goto out;
2787 }
2788 connector = obj_to_connector(obj);
2789
Ville Syrjälä90367bf2012-03-13 12:35:44 +02002790 ret = drm_crtc_convert_umode(&mode, umode);
2791 if (ret) {
2792 DRM_DEBUG_KMS("Invalid mode\n");
2793 goto out;
2794 }
2795
Dave Airlief453ba02008-11-07 14:05:41 -08002796 ret = drm_mode_detachmode(dev, connector, &mode);
2797out:
Daniel Vetter84849902012-12-02 00:28:11 +01002798 drm_modeset_unlock_all(dev);
Dave Airlief453ba02008-11-07 14:05:41 -08002799 return ret;
2800}
2801
2802struct drm_property *drm_property_create(struct drm_device *dev, int flags,
2803 const char *name, int num_values)
2804{
2805 struct drm_property *property = NULL;
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +02002806 int ret;
Dave Airlief453ba02008-11-07 14:05:41 -08002807
2808 property = kzalloc(sizeof(struct drm_property), GFP_KERNEL);
2809 if (!property)
2810 return NULL;
2811
2812 if (num_values) {
2813 property->values = kzalloc(sizeof(uint64_t)*num_values, GFP_KERNEL);
2814 if (!property->values)
2815 goto fail;
2816 }
2817
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +02002818 ret = drm_mode_object_get(dev, &property->base, DRM_MODE_OBJECT_PROPERTY);
2819 if (ret)
2820 goto fail;
2821
Dave Airlief453ba02008-11-07 14:05:41 -08002822 property->flags = flags;
2823 property->num_values = num_values;
2824 INIT_LIST_HEAD(&property->enum_blob_list);
2825
Vinson Lee471dd2e2011-11-10 11:55:40 -08002826 if (name) {
Dave Airlief453ba02008-11-07 14:05:41 -08002827 strncpy(property->name, name, DRM_PROP_NAME_LEN);
Vinson Lee471dd2e2011-11-10 11:55:40 -08002828 property->name[DRM_PROP_NAME_LEN-1] = '\0';
2829 }
Dave Airlief453ba02008-11-07 14:05:41 -08002830
2831 list_add_tail(&property->head, &dev->mode_config.property_list);
2832 return property;
2833fail:
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +02002834 kfree(property->values);
Dave Airlief453ba02008-11-07 14:05:41 -08002835 kfree(property);
2836 return NULL;
2837}
2838EXPORT_SYMBOL(drm_property_create);
2839
Sascha Hauer4a67d392012-02-06 10:58:17 +01002840struct drm_property *drm_property_create_enum(struct drm_device *dev, int flags,
2841 const char *name,
2842 const struct drm_prop_enum_list *props,
2843 int num_values)
2844{
2845 struct drm_property *property;
2846 int i, ret;
2847
2848 flags |= DRM_MODE_PROP_ENUM;
2849
2850 property = drm_property_create(dev, flags, name, num_values);
2851 if (!property)
2852 return NULL;
2853
2854 for (i = 0; i < num_values; i++) {
2855 ret = drm_property_add_enum(property, i,
2856 props[i].type,
2857 props[i].name);
2858 if (ret) {
2859 drm_property_destroy(dev, property);
2860 return NULL;
2861 }
2862 }
2863
2864 return property;
2865}
2866EXPORT_SYMBOL(drm_property_create_enum);
2867
Rob Clark49e27542012-05-17 02:23:26 -06002868struct drm_property *drm_property_create_bitmask(struct drm_device *dev,
2869 int flags, const char *name,
2870 const struct drm_prop_enum_list *props,
2871 int num_values)
2872{
2873 struct drm_property *property;
2874 int i, ret;
2875
2876 flags |= DRM_MODE_PROP_BITMASK;
2877
2878 property = drm_property_create(dev, flags, name, num_values);
2879 if (!property)
2880 return NULL;
2881
2882 for (i = 0; i < num_values; i++) {
2883 ret = drm_property_add_enum(property, i,
2884 props[i].type,
2885 props[i].name);
2886 if (ret) {
2887 drm_property_destroy(dev, property);
2888 return NULL;
2889 }
2890 }
2891
2892 return property;
2893}
2894EXPORT_SYMBOL(drm_property_create_bitmask);
2895
Sascha Hauerd9bc3c02012-02-06 10:58:18 +01002896struct drm_property *drm_property_create_range(struct drm_device *dev, int flags,
2897 const char *name,
2898 uint64_t min, uint64_t max)
2899{
2900 struct drm_property *property;
2901
2902 flags |= DRM_MODE_PROP_RANGE;
2903
2904 property = drm_property_create(dev, flags, name, 2);
2905 if (!property)
2906 return NULL;
2907
2908 property->values[0] = min;
2909 property->values[1] = max;
2910
2911 return property;
2912}
2913EXPORT_SYMBOL(drm_property_create_range);
2914
Dave Airlief453ba02008-11-07 14:05:41 -08002915int drm_property_add_enum(struct drm_property *property, int index,
2916 uint64_t value, const char *name)
2917{
2918 struct drm_property_enum *prop_enum;
2919
Rob Clark49e27542012-05-17 02:23:26 -06002920 if (!(property->flags & (DRM_MODE_PROP_ENUM | DRM_MODE_PROP_BITMASK)))
2921 return -EINVAL;
2922
2923 /*
2924 * Bitmask enum properties have the additional constraint of values
2925 * from 0 to 63
2926 */
2927 if ((property->flags & DRM_MODE_PROP_BITMASK) && (value > 63))
Dave Airlief453ba02008-11-07 14:05:41 -08002928 return -EINVAL;
2929
2930 if (!list_empty(&property->enum_blob_list)) {
2931 list_for_each_entry(prop_enum, &property->enum_blob_list, head) {
2932 if (prop_enum->value == value) {
2933 strncpy(prop_enum->name, name, DRM_PROP_NAME_LEN);
2934 prop_enum->name[DRM_PROP_NAME_LEN-1] = '\0';
2935 return 0;
2936 }
2937 }
2938 }
2939
2940 prop_enum = kzalloc(sizeof(struct drm_property_enum), GFP_KERNEL);
2941 if (!prop_enum)
2942 return -ENOMEM;
2943
2944 strncpy(prop_enum->name, name, DRM_PROP_NAME_LEN);
2945 prop_enum->name[DRM_PROP_NAME_LEN-1] = '\0';
2946 prop_enum->value = value;
2947
2948 property->values[index] = value;
2949 list_add_tail(&prop_enum->head, &property->enum_blob_list);
2950 return 0;
2951}
2952EXPORT_SYMBOL(drm_property_add_enum);
2953
2954void drm_property_destroy(struct drm_device *dev, struct drm_property *property)
2955{
2956 struct drm_property_enum *prop_enum, *pt;
2957
2958 list_for_each_entry_safe(prop_enum, pt, &property->enum_blob_list, head) {
2959 list_del(&prop_enum->head);
2960 kfree(prop_enum);
2961 }
2962
2963 if (property->num_values)
2964 kfree(property->values);
2965 drm_mode_object_put(dev, &property->base);
2966 list_del(&property->head);
2967 kfree(property);
2968}
2969EXPORT_SYMBOL(drm_property_destroy);
2970
Paulo Zanonic5431882012-05-15 18:09:02 -03002971void drm_object_attach_property(struct drm_mode_object *obj,
2972 struct drm_property *property,
2973 uint64_t init_val)
2974{
Paulo Zanoni7f88a9b2012-05-15 18:09:04 -03002975 int count = obj->properties->count;
Paulo Zanonic5431882012-05-15 18:09:02 -03002976
Paulo Zanoni7f88a9b2012-05-15 18:09:04 -03002977 if (count == DRM_OBJECT_MAX_PROPERTY) {
2978 WARN(1, "Failed to attach object property (type: 0x%x). Please "
2979 "increase DRM_OBJECT_MAX_PROPERTY by 1 for each time "
2980 "you see this message on the same object type.\n",
2981 obj->type);
2982 return;
Paulo Zanonic5431882012-05-15 18:09:02 -03002983 }
2984
Paulo Zanoni7f88a9b2012-05-15 18:09:04 -03002985 obj->properties->ids[count] = property->base.id;
2986 obj->properties->values[count] = init_val;
2987 obj->properties->count++;
Paulo Zanonic5431882012-05-15 18:09:02 -03002988}
2989EXPORT_SYMBOL(drm_object_attach_property);
2990
2991int drm_object_property_set_value(struct drm_mode_object *obj,
2992 struct drm_property *property, uint64_t val)
2993{
2994 int i;
2995
Paulo Zanoni7f88a9b2012-05-15 18:09:04 -03002996 for (i = 0; i < obj->properties->count; i++) {
Paulo Zanonic5431882012-05-15 18:09:02 -03002997 if (obj->properties->ids[i] == property->base.id) {
2998 obj->properties->values[i] = val;
2999 return 0;
3000 }
3001 }
3002
3003 return -EINVAL;
3004}
3005EXPORT_SYMBOL(drm_object_property_set_value);
3006
3007int drm_object_property_get_value(struct drm_mode_object *obj,
3008 struct drm_property *property, uint64_t *val)
3009{
3010 int i;
3011
Paulo Zanoni7f88a9b2012-05-15 18:09:04 -03003012 for (i = 0; i < obj->properties->count; i++) {
Paulo Zanonic5431882012-05-15 18:09:02 -03003013 if (obj->properties->ids[i] == property->base.id) {
3014 *val = obj->properties->values[i];
3015 return 0;
3016 }
3017 }
3018
3019 return -EINVAL;
3020}
3021EXPORT_SYMBOL(drm_object_property_get_value);
3022
Dave Airlief453ba02008-11-07 14:05:41 -08003023int drm_mode_getproperty_ioctl(struct drm_device *dev,
3024 void *data, struct drm_file *file_priv)
3025{
3026 struct drm_mode_object *obj;
3027 struct drm_mode_get_property *out_resp = data;
3028 struct drm_property *property;
3029 int enum_count = 0;
3030 int blob_count = 0;
3031 int value_count = 0;
3032 int ret = 0, i;
3033 int copied;
3034 struct drm_property_enum *prop_enum;
3035 struct drm_mode_property_enum __user *enum_ptr;
3036 struct drm_property_blob *prop_blob;
Ville Syrjälä81f6c7f2011-12-20 00:06:42 +02003037 uint32_t __user *blob_id_ptr;
Dave Airlief453ba02008-11-07 14:05:41 -08003038 uint64_t __user *values_ptr;
3039 uint32_t __user *blob_length_ptr;
3040
Dave Airliefb3b06c2011-02-08 13:55:21 +10003041 if (!drm_core_check_feature(dev, DRIVER_MODESET))
3042 return -EINVAL;
3043
Daniel Vetter84849902012-12-02 00:28:11 +01003044 drm_modeset_lock_all(dev);
Dave Airlief453ba02008-11-07 14:05:41 -08003045 obj = drm_mode_object_find(dev, out_resp->prop_id, DRM_MODE_OBJECT_PROPERTY);
3046 if (!obj) {
3047 ret = -EINVAL;
3048 goto done;
3049 }
3050 property = obj_to_property(obj);
3051
Rob Clark49e27542012-05-17 02:23:26 -06003052 if (property->flags & (DRM_MODE_PROP_ENUM | DRM_MODE_PROP_BITMASK)) {
Dave Airlief453ba02008-11-07 14:05:41 -08003053 list_for_each_entry(prop_enum, &property->enum_blob_list, head)
3054 enum_count++;
3055 } else if (property->flags & DRM_MODE_PROP_BLOB) {
3056 list_for_each_entry(prop_blob, &property->enum_blob_list, head)
3057 blob_count++;
3058 }
3059
3060 value_count = property->num_values;
3061
3062 strncpy(out_resp->name, property->name, DRM_PROP_NAME_LEN);
3063 out_resp->name[DRM_PROP_NAME_LEN-1] = 0;
3064 out_resp->flags = property->flags;
3065
3066 if ((out_resp->count_values >= value_count) && value_count) {
Ville Syrjälä81f6c7f2011-12-20 00:06:42 +02003067 values_ptr = (uint64_t __user *)(unsigned long)out_resp->values_ptr;
Dave Airlief453ba02008-11-07 14:05:41 -08003068 for (i = 0; i < value_count; i++) {
3069 if (copy_to_user(values_ptr + i, &property->values[i], sizeof(uint64_t))) {
3070 ret = -EFAULT;
3071 goto done;
3072 }
3073 }
3074 }
3075 out_resp->count_values = value_count;
3076
Rob Clark49e27542012-05-17 02:23:26 -06003077 if (property->flags & (DRM_MODE_PROP_ENUM | DRM_MODE_PROP_BITMASK)) {
Dave Airlief453ba02008-11-07 14:05:41 -08003078 if ((out_resp->count_enum_blobs >= enum_count) && enum_count) {
3079 copied = 0;
Ville Syrjälä81f6c7f2011-12-20 00:06:42 +02003080 enum_ptr = (struct drm_mode_property_enum __user *)(unsigned long)out_resp->enum_blob_ptr;
Dave Airlief453ba02008-11-07 14:05:41 -08003081 list_for_each_entry(prop_enum, &property->enum_blob_list, head) {
3082
3083 if (copy_to_user(&enum_ptr[copied].value, &prop_enum->value, sizeof(uint64_t))) {
3084 ret = -EFAULT;
3085 goto done;
3086 }
3087
3088 if (copy_to_user(&enum_ptr[copied].name,
3089 &prop_enum->name, DRM_PROP_NAME_LEN)) {
3090 ret = -EFAULT;
3091 goto done;
3092 }
3093 copied++;
3094 }
3095 }
3096 out_resp->count_enum_blobs = enum_count;
3097 }
3098
3099 if (property->flags & DRM_MODE_PROP_BLOB) {
3100 if ((out_resp->count_enum_blobs >= blob_count) && blob_count) {
3101 copied = 0;
Ville Syrjälä81f6c7f2011-12-20 00:06:42 +02003102 blob_id_ptr = (uint32_t __user *)(unsigned long)out_resp->enum_blob_ptr;
3103 blob_length_ptr = (uint32_t __user *)(unsigned long)out_resp->values_ptr;
Dave Airlief453ba02008-11-07 14:05:41 -08003104
3105 list_for_each_entry(prop_blob, &property->enum_blob_list, head) {
3106 if (put_user(prop_blob->base.id, blob_id_ptr + copied)) {
3107 ret = -EFAULT;
3108 goto done;
3109 }
3110
3111 if (put_user(prop_blob->length, blob_length_ptr + copied)) {
3112 ret = -EFAULT;
3113 goto done;
3114 }
3115
3116 copied++;
3117 }
3118 }
3119 out_resp->count_enum_blobs = blob_count;
3120 }
3121done:
Daniel Vetter84849902012-12-02 00:28:11 +01003122 drm_modeset_unlock_all(dev);
Dave Airlief453ba02008-11-07 14:05:41 -08003123 return ret;
3124}
3125
3126static struct drm_property_blob *drm_property_create_blob(struct drm_device *dev, int length,
3127 void *data)
3128{
3129 struct drm_property_blob *blob;
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +02003130 int ret;
Dave Airlief453ba02008-11-07 14:05:41 -08003131
3132 if (!length || !data)
3133 return NULL;
3134
3135 blob = kzalloc(sizeof(struct drm_property_blob)+length, GFP_KERNEL);
3136 if (!blob)
3137 return NULL;
3138
Ville Syrjälä6bfc56a2012-03-13 12:35:48 +02003139 ret = drm_mode_object_get(dev, &blob->base, DRM_MODE_OBJECT_BLOB);
3140 if (ret) {
3141 kfree(blob);
3142 return NULL;
3143 }
3144
Dave Airlief453ba02008-11-07 14:05:41 -08003145 blob->length = length;
3146
3147 memcpy(blob->data, data, length);
3148
Dave Airlief453ba02008-11-07 14:05:41 -08003149 list_add_tail(&blob->head, &dev->mode_config.property_blob_list);
3150 return blob;
3151}
3152
3153static void drm_property_destroy_blob(struct drm_device *dev,
3154 struct drm_property_blob *blob)
3155{
3156 drm_mode_object_put(dev, &blob->base);
3157 list_del(&blob->head);
3158 kfree(blob);
3159}
3160
3161int drm_mode_getblob_ioctl(struct drm_device *dev,
3162 void *data, struct drm_file *file_priv)
3163{
3164 struct drm_mode_object *obj;
3165 struct drm_mode_get_blob *out_resp = data;
3166 struct drm_property_blob *blob;
3167 int ret = 0;
Ville Syrjälä81f6c7f2011-12-20 00:06:42 +02003168 void __user *blob_ptr;
Dave Airlief453ba02008-11-07 14:05:41 -08003169
Dave Airliefb3b06c2011-02-08 13:55:21 +10003170 if (!drm_core_check_feature(dev, DRIVER_MODESET))
3171 return -EINVAL;
3172
Daniel Vetter84849902012-12-02 00:28:11 +01003173 drm_modeset_lock_all(dev);
Dave Airlief453ba02008-11-07 14:05:41 -08003174 obj = drm_mode_object_find(dev, out_resp->blob_id, DRM_MODE_OBJECT_BLOB);
3175 if (!obj) {
3176 ret = -EINVAL;
3177 goto done;
3178 }
3179 blob = obj_to_blob(obj);
3180
3181 if (out_resp->length == blob->length) {
Ville Syrjälä81f6c7f2011-12-20 00:06:42 +02003182 blob_ptr = (void __user *)(unsigned long)out_resp->data;
Dave Airlief453ba02008-11-07 14:05:41 -08003183 if (copy_to_user(blob_ptr, blob->data, blob->length)){
3184 ret = -EFAULT;
3185 goto done;
3186 }
3187 }
3188 out_resp->length = blob->length;
3189
3190done:
Daniel Vetter84849902012-12-02 00:28:11 +01003191 drm_modeset_unlock_all(dev);
Dave Airlief453ba02008-11-07 14:05:41 -08003192 return ret;
3193}
3194
3195int drm_mode_connector_update_edid_property(struct drm_connector *connector,
3196 struct edid *edid)
3197{
3198 struct drm_device *dev = connector->dev;
Laurent Pinchart4a1b0712012-05-17 13:27:21 +02003199 int ret, size;
Dave Airlief453ba02008-11-07 14:05:41 -08003200
3201 if (connector->edid_blob_ptr)
3202 drm_property_destroy_blob(dev, connector->edid_blob_ptr);
3203
3204 /* Delete edid, when there is none. */
3205 if (!edid) {
3206 connector->edid_blob_ptr = NULL;
Rob Clark58495562012-10-11 20:50:56 -05003207 ret = drm_object_property_set_value(&connector->base, dev->mode_config.edid_property, 0);
Dave Airlief453ba02008-11-07 14:05:41 -08003208 return ret;
3209 }
3210
Adam Jackson7466f4c2010-03-29 21:43:23 +00003211 size = EDID_LENGTH * (1 + edid->extensions);
3212 connector->edid_blob_ptr = drm_property_create_blob(connector->dev,
3213 size, edid);
Sachin Kamate655d122012-11-19 09:44:57 +00003214 if (!connector->edid_blob_ptr)
3215 return -EINVAL;
Dave Airlief453ba02008-11-07 14:05:41 -08003216
Rob Clark58495562012-10-11 20:50:56 -05003217 ret = drm_object_property_set_value(&connector->base,
Dave Airlief453ba02008-11-07 14:05:41 -08003218 dev->mode_config.edid_property,
3219 connector->edid_blob_ptr->base.id);
3220
3221 return ret;
3222}
3223EXPORT_SYMBOL(drm_mode_connector_update_edid_property);
3224
Paulo Zanoni26a34812012-05-15 18:08:59 -03003225static bool drm_property_change_is_valid(struct drm_property *property,
Ville Syrjälä592c20e2012-05-24 20:53:58 +03003226 uint64_t value)
Paulo Zanoni26a34812012-05-15 18:08:59 -03003227{
3228 if (property->flags & DRM_MODE_PROP_IMMUTABLE)
3229 return false;
3230 if (property->flags & DRM_MODE_PROP_RANGE) {
3231 if (value < property->values[0] || value > property->values[1])
3232 return false;
3233 return true;
Rob Clark49e27542012-05-17 02:23:26 -06003234 } else if (property->flags & DRM_MODE_PROP_BITMASK) {
3235 int i;
Ville Syrjälä592c20e2012-05-24 20:53:58 +03003236 uint64_t valid_mask = 0;
Rob Clark49e27542012-05-17 02:23:26 -06003237 for (i = 0; i < property->num_values; i++)
3238 valid_mask |= (1ULL << property->values[i]);
3239 return !(value & ~valid_mask);
Ville Syrjäläc4a56752012-10-25 18:05:06 +00003240 } else if (property->flags & DRM_MODE_PROP_BLOB) {
3241 /* Only the driver knows */
3242 return true;
Paulo Zanoni26a34812012-05-15 18:08:59 -03003243 } else {
3244 int i;
3245 for (i = 0; i < property->num_values; i++)
3246 if (property->values[i] == value)
3247 return true;
3248 return false;
3249 }
3250}
3251
Dave Airlief453ba02008-11-07 14:05:41 -08003252int drm_mode_connector_property_set_ioctl(struct drm_device *dev,
3253 void *data, struct drm_file *file_priv)
3254{
Paulo Zanoni0057d8d2012-05-15 18:09:03 -03003255 struct drm_mode_connector_set_property *conn_set_prop = data;
3256 struct drm_mode_obj_set_property obj_set_prop = {
3257 .value = conn_set_prop->value,
3258 .prop_id = conn_set_prop->prop_id,
3259 .obj_id = conn_set_prop->connector_id,
3260 .obj_type = DRM_MODE_OBJECT_CONNECTOR
3261 };
Dave Airlief453ba02008-11-07 14:05:41 -08003262
Paulo Zanoni0057d8d2012-05-15 18:09:03 -03003263 /* It does all the locking and checking we need */
3264 return drm_mode_obj_set_property_ioctl(dev, &obj_set_prop, file_priv);
Dave Airlief453ba02008-11-07 14:05:41 -08003265}
3266
Paulo Zanonic5431882012-05-15 18:09:02 -03003267static int drm_mode_connector_set_obj_prop(struct drm_mode_object *obj,
3268 struct drm_property *property,
3269 uint64_t value)
3270{
3271 int ret = -EINVAL;
3272 struct drm_connector *connector = obj_to_connector(obj);
3273
3274 /* Do DPMS ourselves */
3275 if (property == connector->dev->mode_config.dpms_property) {
3276 if (connector->funcs->dpms)
3277 (*connector->funcs->dpms)(connector, (int)value);
3278 ret = 0;
3279 } else if (connector->funcs->set_property)
3280 ret = connector->funcs->set_property(connector, property, value);
3281
3282 /* store the property value if successful */
3283 if (!ret)
Rob Clark58495562012-10-11 20:50:56 -05003284 drm_object_property_set_value(&connector->base, property, value);
Paulo Zanonic5431882012-05-15 18:09:02 -03003285 return ret;
3286}
3287
Paulo Zanonibffd9de02012-05-15 18:09:05 -03003288static int drm_mode_crtc_set_obj_prop(struct drm_mode_object *obj,
3289 struct drm_property *property,
3290 uint64_t value)
3291{
3292 int ret = -EINVAL;
3293 struct drm_crtc *crtc = obj_to_crtc(obj);
3294
3295 if (crtc->funcs->set_property)
3296 ret = crtc->funcs->set_property(crtc, property, value);
3297 if (!ret)
3298 drm_object_property_set_value(obj, property, value);
3299
3300 return ret;
3301}
3302
Rob Clark4d939142012-05-17 02:23:27 -06003303static int drm_mode_plane_set_obj_prop(struct drm_mode_object *obj,
3304 struct drm_property *property,
3305 uint64_t value)
3306{
3307 int ret = -EINVAL;
3308 struct drm_plane *plane = obj_to_plane(obj);
3309
3310 if (plane->funcs->set_property)
3311 ret = plane->funcs->set_property(plane, property, value);
3312 if (!ret)
3313 drm_object_property_set_value(obj, property, value);
3314
3315 return ret;
3316}
3317
Paulo Zanonic5431882012-05-15 18:09:02 -03003318int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data,
3319 struct drm_file *file_priv)
3320{
3321 struct drm_mode_obj_get_properties *arg = data;
3322 struct drm_mode_object *obj;
3323 int ret = 0;
3324 int i;
3325 int copied = 0;
3326 int props_count = 0;
3327 uint32_t __user *props_ptr;
3328 uint64_t __user *prop_values_ptr;
3329
3330 if (!drm_core_check_feature(dev, DRIVER_MODESET))
3331 return -EINVAL;
3332
Daniel Vetter84849902012-12-02 00:28:11 +01003333 drm_modeset_lock_all(dev);
Paulo Zanonic5431882012-05-15 18:09:02 -03003334
3335 obj = drm_mode_object_find(dev, arg->obj_id, arg->obj_type);
3336 if (!obj) {
3337 ret = -EINVAL;
3338 goto out;
3339 }
3340 if (!obj->properties) {
3341 ret = -EINVAL;
3342 goto out;
3343 }
3344
Paulo Zanoni7f88a9b2012-05-15 18:09:04 -03003345 props_count = obj->properties->count;
Paulo Zanonic5431882012-05-15 18:09:02 -03003346
3347 /* This ioctl is called twice, once to determine how much space is
3348 * needed, and the 2nd time to fill it. */
3349 if ((arg->count_props >= props_count) && props_count) {
3350 copied = 0;
3351 props_ptr = (uint32_t __user *)(unsigned long)(arg->props_ptr);
3352 prop_values_ptr = (uint64_t __user *)(unsigned long)
3353 (arg->prop_values_ptr);
3354 for (i = 0; i < props_count; i++) {
3355 if (put_user(obj->properties->ids[i],
3356 props_ptr + copied)) {
3357 ret = -EFAULT;
3358 goto out;
3359 }
3360 if (put_user(obj->properties->values[i],
3361 prop_values_ptr + copied)) {
3362 ret = -EFAULT;
3363 goto out;
3364 }
3365 copied++;
3366 }
3367 }
3368 arg->count_props = props_count;
3369out:
Daniel Vetter84849902012-12-02 00:28:11 +01003370 drm_modeset_unlock_all(dev);
Paulo Zanonic5431882012-05-15 18:09:02 -03003371 return ret;
3372}
3373
3374int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data,
3375 struct drm_file *file_priv)
3376{
3377 struct drm_mode_obj_set_property *arg = data;
3378 struct drm_mode_object *arg_obj;
3379 struct drm_mode_object *prop_obj;
3380 struct drm_property *property;
3381 int ret = -EINVAL;
3382 int i;
3383
3384 if (!drm_core_check_feature(dev, DRIVER_MODESET))
3385 return -EINVAL;
3386
Daniel Vetter84849902012-12-02 00:28:11 +01003387 drm_modeset_lock_all(dev);
Paulo Zanonic5431882012-05-15 18:09:02 -03003388
3389 arg_obj = drm_mode_object_find(dev, arg->obj_id, arg->obj_type);
3390 if (!arg_obj)
3391 goto out;
3392 if (!arg_obj->properties)
3393 goto out;
3394
Paulo Zanoni7f88a9b2012-05-15 18:09:04 -03003395 for (i = 0; i < arg_obj->properties->count; i++)
Paulo Zanonic5431882012-05-15 18:09:02 -03003396 if (arg_obj->properties->ids[i] == arg->prop_id)
3397 break;
3398
Paulo Zanoni7f88a9b2012-05-15 18:09:04 -03003399 if (i == arg_obj->properties->count)
Paulo Zanonic5431882012-05-15 18:09:02 -03003400 goto out;
3401
3402 prop_obj = drm_mode_object_find(dev, arg->prop_id,
3403 DRM_MODE_OBJECT_PROPERTY);
3404 if (!prop_obj)
3405 goto out;
3406 property = obj_to_property(prop_obj);
3407
3408 if (!drm_property_change_is_valid(property, arg->value))
3409 goto out;
3410
3411 switch (arg_obj->type) {
3412 case DRM_MODE_OBJECT_CONNECTOR:
3413 ret = drm_mode_connector_set_obj_prop(arg_obj, property,
3414 arg->value);
3415 break;
Paulo Zanonibffd9de02012-05-15 18:09:05 -03003416 case DRM_MODE_OBJECT_CRTC:
3417 ret = drm_mode_crtc_set_obj_prop(arg_obj, property, arg->value);
3418 break;
Rob Clark4d939142012-05-17 02:23:27 -06003419 case DRM_MODE_OBJECT_PLANE:
3420 ret = drm_mode_plane_set_obj_prop(arg_obj, property, arg->value);
3421 break;
Paulo Zanonic5431882012-05-15 18:09:02 -03003422 }
3423
3424out:
Daniel Vetter84849902012-12-02 00:28:11 +01003425 drm_modeset_unlock_all(dev);
Paulo Zanonic5431882012-05-15 18:09:02 -03003426 return ret;
3427}
3428
Dave Airlief453ba02008-11-07 14:05:41 -08003429int drm_mode_connector_attach_encoder(struct drm_connector *connector,
3430 struct drm_encoder *encoder)
3431{
3432 int i;
3433
3434 for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
3435 if (connector->encoder_ids[i] == 0) {
3436 connector->encoder_ids[i] = encoder->base.id;
3437 return 0;
3438 }
3439 }
3440 return -ENOMEM;
3441}
3442EXPORT_SYMBOL(drm_mode_connector_attach_encoder);
3443
3444void drm_mode_connector_detach_encoder(struct drm_connector *connector,
3445 struct drm_encoder *encoder)
3446{
3447 int i;
3448 for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
3449 if (connector->encoder_ids[i] == encoder->base.id) {
3450 connector->encoder_ids[i] = 0;
3451 if (connector->encoder == encoder)
3452 connector->encoder = NULL;
3453 break;
3454 }
3455 }
3456}
3457EXPORT_SYMBOL(drm_mode_connector_detach_encoder);
3458
Sascha Hauer4cae5b82012-02-01 11:38:23 +01003459int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc,
Dave Airlief453ba02008-11-07 14:05:41 -08003460 int gamma_size)
3461{
3462 crtc->gamma_size = gamma_size;
3463
3464 crtc->gamma_store = kzalloc(gamma_size * sizeof(uint16_t) * 3, GFP_KERNEL);
3465 if (!crtc->gamma_store) {
3466 crtc->gamma_size = 0;
Sascha Hauer4cae5b82012-02-01 11:38:23 +01003467 return -ENOMEM;
Dave Airlief453ba02008-11-07 14:05:41 -08003468 }
3469
Sascha Hauer4cae5b82012-02-01 11:38:23 +01003470 return 0;
Dave Airlief453ba02008-11-07 14:05:41 -08003471}
3472EXPORT_SYMBOL(drm_mode_crtc_set_gamma_size);
3473
3474int drm_mode_gamma_set_ioctl(struct drm_device *dev,
3475 void *data, struct drm_file *file_priv)
3476{
3477 struct drm_mode_crtc_lut *crtc_lut = data;
3478 struct drm_mode_object *obj;
3479 struct drm_crtc *crtc;
3480 void *r_base, *g_base, *b_base;
3481 int size;
3482 int ret = 0;
3483
Dave Airliefb3b06c2011-02-08 13:55:21 +10003484 if (!drm_core_check_feature(dev, DRIVER_MODESET))
3485 return -EINVAL;
3486
Daniel Vetter84849902012-12-02 00:28:11 +01003487 drm_modeset_lock_all(dev);
Dave Airlief453ba02008-11-07 14:05:41 -08003488 obj = drm_mode_object_find(dev, crtc_lut->crtc_id, DRM_MODE_OBJECT_CRTC);
3489 if (!obj) {
3490 ret = -EINVAL;
3491 goto out;
3492 }
3493 crtc = obj_to_crtc(obj);
3494
Laurent Pinchartebe0f242012-05-17 13:27:24 +02003495 if (crtc->funcs->gamma_set == NULL) {
3496 ret = -ENOSYS;
3497 goto out;
3498 }
3499
Dave Airlief453ba02008-11-07 14:05:41 -08003500 /* memcpy into gamma store */
3501 if (crtc_lut->gamma_size != crtc->gamma_size) {
3502 ret = -EINVAL;
3503 goto out;
3504 }
3505
3506 size = crtc_lut->gamma_size * (sizeof(uint16_t));
3507 r_base = crtc->gamma_store;
3508 if (copy_from_user(r_base, (void __user *)(unsigned long)crtc_lut->red, size)) {
3509 ret = -EFAULT;
3510 goto out;
3511 }
3512
3513 g_base = r_base + size;
3514 if (copy_from_user(g_base, (void __user *)(unsigned long)crtc_lut->green, size)) {
3515 ret = -EFAULT;
3516 goto out;
3517 }
3518
3519 b_base = g_base + size;
3520 if (copy_from_user(b_base, (void __user *)(unsigned long)crtc_lut->blue, size)) {
3521 ret = -EFAULT;
3522 goto out;
3523 }
3524
James Simmons72034252010-08-03 01:33:19 +01003525 crtc->funcs->gamma_set(crtc, r_base, g_base, b_base, 0, crtc->gamma_size);
Dave Airlief453ba02008-11-07 14:05:41 -08003526
3527out:
Daniel Vetter84849902012-12-02 00:28:11 +01003528 drm_modeset_unlock_all(dev);
Dave Airlief453ba02008-11-07 14:05:41 -08003529 return ret;
3530
3531}
3532
3533int drm_mode_gamma_get_ioctl(struct drm_device *dev,
3534 void *data, struct drm_file *file_priv)
3535{
3536 struct drm_mode_crtc_lut *crtc_lut = data;
3537 struct drm_mode_object *obj;
3538 struct drm_crtc *crtc;
3539 void *r_base, *g_base, *b_base;
3540 int size;
3541 int ret = 0;
3542
Dave Airliefb3b06c2011-02-08 13:55:21 +10003543 if (!drm_core_check_feature(dev, DRIVER_MODESET))
3544 return -EINVAL;
3545
Daniel Vetter84849902012-12-02 00:28:11 +01003546 drm_modeset_lock_all(dev);
Dave Airlief453ba02008-11-07 14:05:41 -08003547 obj = drm_mode_object_find(dev, crtc_lut->crtc_id, DRM_MODE_OBJECT_CRTC);
3548 if (!obj) {
3549 ret = -EINVAL;
3550 goto out;
3551 }
3552 crtc = obj_to_crtc(obj);
3553
3554 /* memcpy into gamma store */
3555 if (crtc_lut->gamma_size != crtc->gamma_size) {
3556 ret = -EINVAL;
3557 goto out;
3558 }
3559
3560 size = crtc_lut->gamma_size * (sizeof(uint16_t));
3561 r_base = crtc->gamma_store;
3562 if (copy_to_user((void __user *)(unsigned long)crtc_lut->red, r_base, size)) {
3563 ret = -EFAULT;
3564 goto out;
3565 }
3566
3567 g_base = r_base + size;
3568 if (copy_to_user((void __user *)(unsigned long)crtc_lut->green, g_base, size)) {
3569 ret = -EFAULT;
3570 goto out;
3571 }
3572
3573 b_base = g_base + size;
3574 if (copy_to_user((void __user *)(unsigned long)crtc_lut->blue, b_base, size)) {
3575 ret = -EFAULT;
3576 goto out;
3577 }
3578out:
Daniel Vetter84849902012-12-02 00:28:11 +01003579 drm_modeset_unlock_all(dev);
Dave Airlief453ba02008-11-07 14:05:41 -08003580 return ret;
3581}
Kristian Høgsbergd91d8a32009-11-17 12:43:55 -05003582
3583int drm_mode_page_flip_ioctl(struct drm_device *dev,
3584 void *data, struct drm_file *file_priv)
3585{
3586 struct drm_mode_crtc_page_flip *page_flip = data;
3587 struct drm_mode_object *obj;
3588 struct drm_crtc *crtc;
Daniel Vetterb0d12322012-12-11 01:07:12 +01003589 struct drm_framebuffer *fb = NULL, *old_fb = NULL;
Kristian Høgsbergd91d8a32009-11-17 12:43:55 -05003590 struct drm_pending_vblank_event *e = NULL;
3591 unsigned long flags;
Rob Clark7c80e122012-09-04 16:35:56 +00003592 int hdisplay, vdisplay;
Kristian Høgsbergd91d8a32009-11-17 12:43:55 -05003593 int ret = -EINVAL;
3594
3595 if (page_flip->flags & ~DRM_MODE_PAGE_FLIP_FLAGS ||
3596 page_flip->reserved != 0)
3597 return -EINVAL;
3598
Kristian Høgsbergd91d8a32009-11-17 12:43:55 -05003599 obj = drm_mode_object_find(dev, page_flip->crtc_id, DRM_MODE_OBJECT_CRTC);
3600 if (!obj)
Daniel Vetterb4d5e7d2012-12-11 16:59:31 +01003601 return -EINVAL;
Kristian Høgsbergd91d8a32009-11-17 12:43:55 -05003602 crtc = obj_to_crtc(obj);
3603
Daniel Vetterb4d5e7d2012-12-11 16:59:31 +01003604 mutex_lock(&crtc->mutex);
Chris Wilson90c1efd2010-07-17 20:23:26 +01003605 if (crtc->fb == NULL) {
3606 /* The framebuffer is currently unbound, presumably
3607 * due to a hotplug event, that userspace has not
3608 * yet discovered.
3609 */
3610 ret = -EBUSY;
3611 goto out;
3612 }
3613
Kristian Høgsbergd91d8a32009-11-17 12:43:55 -05003614 if (crtc->funcs->page_flip == NULL)
3615 goto out;
3616
Daniel Vetter786b99e2012-12-02 21:53:40 +01003617 fb = drm_framebuffer_lookup(dev, page_flip->fb_id);
3618 if (!fb)
Kristian Høgsbergd91d8a32009-11-17 12:43:55 -05003619 goto out;
Kristian Høgsbergd91d8a32009-11-17 12:43:55 -05003620
Rob Clark7c80e122012-09-04 16:35:56 +00003621 hdisplay = crtc->mode.hdisplay;
3622 vdisplay = crtc->mode.vdisplay;
3623
3624 if (crtc->invert_dimensions)
3625 swap(hdisplay, vdisplay);
3626
3627 if (hdisplay > fb->width ||
3628 vdisplay > fb->height ||
3629 crtc->x > fb->width - hdisplay ||
3630 crtc->y > fb->height - vdisplay) {
3631 DRM_DEBUG_KMS("Invalid fb size %ux%u for CRTC viewport %ux%u+%d+%d%s.\n",
3632 fb->width, fb->height, hdisplay, vdisplay, crtc->x, crtc->y,
3633 crtc->invert_dimensions ? " (inverted)" : "");
Ville Syrjälä5f61bb42012-03-13 12:35:45 +02003634 ret = -ENOSPC;
3635 goto out;
3636 }
3637
Laurent Pinchart909d9cd2013-04-22 01:38:46 +02003638 if (crtc->fb->pixel_format != fb->pixel_format) {
3639 DRM_DEBUG_KMS("Page flip is not allowed to change frame buffer format.\n");
3640 ret = -EINVAL;
3641 goto out;
3642 }
3643
Kristian Høgsbergd91d8a32009-11-17 12:43:55 -05003644 if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) {
3645 ret = -ENOMEM;
3646 spin_lock_irqsave(&dev->event_lock, flags);
3647 if (file_priv->event_space < sizeof e->event) {
3648 spin_unlock_irqrestore(&dev->event_lock, flags);
3649 goto out;
3650 }
3651 file_priv->event_space -= sizeof e->event;
3652 spin_unlock_irqrestore(&dev->event_lock, flags);
3653
3654 e = kzalloc(sizeof *e, GFP_KERNEL);
3655 if (e == NULL) {
3656 spin_lock_irqsave(&dev->event_lock, flags);
3657 file_priv->event_space += sizeof e->event;
3658 spin_unlock_irqrestore(&dev->event_lock, flags);
3659 goto out;
3660 }
3661
Jesse Barnes7bd4d7b2009-11-19 10:50:22 -08003662 e->event.base.type = DRM_EVENT_FLIP_COMPLETE;
Kristian Høgsbergd91d8a32009-11-17 12:43:55 -05003663 e->event.base.length = sizeof e->event;
3664 e->event.user_data = page_flip->user_data;
3665 e->base.event = &e->event.base;
3666 e->base.file_priv = file_priv;
3667 e->base.destroy =
3668 (void (*) (struct drm_pending_event *)) kfree;
3669 }
3670
Daniel Vetterb0d12322012-12-11 01:07:12 +01003671 old_fb = crtc->fb;
Kristian Høgsbergd91d8a32009-11-17 12:43:55 -05003672 ret = crtc->funcs->page_flip(crtc, fb, e);
3673 if (ret) {
Joonyoung Shimaef6a7e2012-04-18 13:47:02 +09003674 if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) {
3675 spin_lock_irqsave(&dev->event_lock, flags);
3676 file_priv->event_space += sizeof e->event;
3677 spin_unlock_irqrestore(&dev->event_lock, flags);
3678 kfree(e);
3679 }
Daniel Vetterb0d12322012-12-11 01:07:12 +01003680 /* Keep the old fb, don't unref it. */
3681 old_fb = NULL;
3682 } else {
Thierry Reding8cf1e982013-02-13 16:08:33 +01003683 /*
3684 * Warn if the driver hasn't properly updated the crtc->fb
3685 * field to reflect that the new framebuffer is now used.
3686 * Failing to do so will screw with the reference counting
3687 * on framebuffers.
3688 */
3689 WARN_ON(crtc->fb != fb);
Daniel Vetterb0d12322012-12-11 01:07:12 +01003690 /* Unref only the old framebuffer. */
3691 fb = NULL;
Kristian Høgsbergd91d8a32009-11-17 12:43:55 -05003692 }
3693
3694out:
Daniel Vetterb0d12322012-12-11 01:07:12 +01003695 if (fb)
3696 drm_framebuffer_unreference(fb);
3697 if (old_fb)
3698 drm_framebuffer_unreference(old_fb);
Daniel Vetterb4d5e7d2012-12-11 16:59:31 +01003699 mutex_unlock(&crtc->mutex);
3700
Kristian Høgsbergd91d8a32009-11-17 12:43:55 -05003701 return ret;
3702}
Chris Wilsoneb033552011-01-24 15:11:08 +00003703
3704void drm_mode_config_reset(struct drm_device *dev)
3705{
3706 struct drm_crtc *crtc;
3707 struct drm_encoder *encoder;
3708 struct drm_connector *connector;
3709
3710 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
3711 if (crtc->funcs->reset)
3712 crtc->funcs->reset(crtc);
3713
3714 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head)
3715 if (encoder->funcs->reset)
3716 encoder->funcs->reset(encoder);
3717
Daniel Vetter5e2cb2f2012-10-23 18:23:35 +00003718 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
3719 connector->status = connector_status_unknown;
3720
Chris Wilsoneb033552011-01-24 15:11:08 +00003721 if (connector->funcs->reset)
3722 connector->funcs->reset(connector);
Daniel Vetter5e2cb2f2012-10-23 18:23:35 +00003723 }
Chris Wilsoneb033552011-01-24 15:11:08 +00003724}
3725EXPORT_SYMBOL(drm_mode_config_reset);
Dave Airlieff72145b2011-02-07 12:16:14 +10003726
3727int drm_mode_create_dumb_ioctl(struct drm_device *dev,
3728 void *data, struct drm_file *file_priv)
3729{
3730 struct drm_mode_create_dumb *args = data;
3731
3732 if (!dev->driver->dumb_create)
3733 return -ENOSYS;
3734 return dev->driver->dumb_create(file_priv, dev, args);
3735}
3736
3737int drm_mode_mmap_dumb_ioctl(struct drm_device *dev,
3738 void *data, struct drm_file *file_priv)
3739{
3740 struct drm_mode_map_dumb *args = data;
3741
3742 /* call driver ioctl to get mmap offset */
3743 if (!dev->driver->dumb_map_offset)
3744 return -ENOSYS;
3745
3746 return dev->driver->dumb_map_offset(file_priv, dev, args->handle, &args->offset);
3747}
3748
3749int drm_mode_destroy_dumb_ioctl(struct drm_device *dev,
3750 void *data, struct drm_file *file_priv)
3751{
3752 struct drm_mode_destroy_dumb *args = data;
3753
3754 if (!dev->driver->dumb_destroy)
3755 return -ENOSYS;
3756
3757 return dev->driver->dumb_destroy(file_priv, dev, args->handle);
3758}
Dave Airlie248dbc22011-11-29 20:02:54 +00003759
3760/*
3761 * Just need to support RGB formats here for compat with code that doesn't
3762 * use pixel formats directly yet.
3763 */
3764void drm_fb_get_bpp_depth(uint32_t format, unsigned int *depth,
3765 int *bpp)
3766{
3767 switch (format) {
Ville Syrjäläc51a6bc2013-01-31 19:43:37 +02003768 case DRM_FORMAT_C8:
Ville Syrjälä04b39242011-11-17 18:05:13 +02003769 case DRM_FORMAT_RGB332:
3770 case DRM_FORMAT_BGR233:
Dave Airlie248dbc22011-11-29 20:02:54 +00003771 *depth = 8;
3772 *bpp = 8;
3773 break;
Ville Syrjälä04b39242011-11-17 18:05:13 +02003774 case DRM_FORMAT_XRGB1555:
3775 case DRM_FORMAT_XBGR1555:
3776 case DRM_FORMAT_RGBX5551:
3777 case DRM_FORMAT_BGRX5551:
3778 case DRM_FORMAT_ARGB1555:
3779 case DRM_FORMAT_ABGR1555:
3780 case DRM_FORMAT_RGBA5551:
3781 case DRM_FORMAT_BGRA5551:
Dave Airlie248dbc22011-11-29 20:02:54 +00003782 *depth = 15;
3783 *bpp = 16;
3784 break;
Ville Syrjälä04b39242011-11-17 18:05:13 +02003785 case DRM_FORMAT_RGB565:
3786 case DRM_FORMAT_BGR565:
Dave Airlie248dbc22011-11-29 20:02:54 +00003787 *depth = 16;
3788 *bpp = 16;
3789 break;
Ville Syrjälä04b39242011-11-17 18:05:13 +02003790 case DRM_FORMAT_RGB888:
3791 case DRM_FORMAT_BGR888:
3792 *depth = 24;
3793 *bpp = 24;
3794 break;
3795 case DRM_FORMAT_XRGB8888:
3796 case DRM_FORMAT_XBGR8888:
3797 case DRM_FORMAT_RGBX8888:
3798 case DRM_FORMAT_BGRX8888:
Dave Airlie248dbc22011-11-29 20:02:54 +00003799 *depth = 24;
3800 *bpp = 32;
3801 break;
Ville Syrjälä04b39242011-11-17 18:05:13 +02003802 case DRM_FORMAT_XRGB2101010:
3803 case DRM_FORMAT_XBGR2101010:
3804 case DRM_FORMAT_RGBX1010102:
3805 case DRM_FORMAT_BGRX1010102:
3806 case DRM_FORMAT_ARGB2101010:
3807 case DRM_FORMAT_ABGR2101010:
3808 case DRM_FORMAT_RGBA1010102:
3809 case DRM_FORMAT_BGRA1010102:
Dave Airlie248dbc22011-11-29 20:02:54 +00003810 *depth = 30;
3811 *bpp = 32;
3812 break;
Ville Syrjälä04b39242011-11-17 18:05:13 +02003813 case DRM_FORMAT_ARGB8888:
3814 case DRM_FORMAT_ABGR8888:
3815 case DRM_FORMAT_RGBA8888:
3816 case DRM_FORMAT_BGRA8888:
Dave Airlie248dbc22011-11-29 20:02:54 +00003817 *depth = 32;
3818 *bpp = 32;
3819 break;
3820 default:
3821 DRM_DEBUG_KMS("unsupported pixel format\n");
3822 *depth = 0;
3823 *bpp = 0;
3824 break;
3825 }
3826}
3827EXPORT_SYMBOL(drm_fb_get_bpp_depth);
Ville Syrjälä141670e2012-04-05 21:35:15 +03003828
3829/**
3830 * drm_format_num_planes - get the number of planes for format
3831 * @format: pixel format (DRM_FORMAT_*)
3832 *
3833 * RETURNS:
3834 * The number of planes used by the specified pixel format.
3835 */
3836int drm_format_num_planes(uint32_t format)
3837{
3838 switch (format) {
3839 case DRM_FORMAT_YUV410:
3840 case DRM_FORMAT_YVU410:
3841 case DRM_FORMAT_YUV411:
3842 case DRM_FORMAT_YVU411:
3843 case DRM_FORMAT_YUV420:
3844 case DRM_FORMAT_YVU420:
3845 case DRM_FORMAT_YUV422:
3846 case DRM_FORMAT_YVU422:
3847 case DRM_FORMAT_YUV444:
3848 case DRM_FORMAT_YVU444:
3849 return 3;
3850 case DRM_FORMAT_NV12:
3851 case DRM_FORMAT_NV21:
3852 case DRM_FORMAT_NV16:
3853 case DRM_FORMAT_NV61:
Laurent Pinchartba623f62012-05-18 23:47:40 +02003854 case DRM_FORMAT_NV24:
3855 case DRM_FORMAT_NV42:
Ville Syrjälä141670e2012-04-05 21:35:15 +03003856 return 2;
3857 default:
3858 return 1;
3859 }
3860}
3861EXPORT_SYMBOL(drm_format_num_planes);
Ville Syrjälä5a86bd52012-04-05 21:35:16 +03003862
3863/**
3864 * drm_format_plane_cpp - determine the bytes per pixel value
3865 * @format: pixel format (DRM_FORMAT_*)
3866 * @plane: plane index
3867 *
3868 * RETURNS:
3869 * The bytes per pixel value for the specified plane.
3870 */
3871int drm_format_plane_cpp(uint32_t format, int plane)
3872{
3873 unsigned int depth;
3874 int bpp;
3875
3876 if (plane >= drm_format_num_planes(format))
3877 return 0;
3878
3879 switch (format) {
3880 case DRM_FORMAT_YUYV:
3881 case DRM_FORMAT_YVYU:
3882 case DRM_FORMAT_UYVY:
3883 case DRM_FORMAT_VYUY:
3884 return 2;
3885 case DRM_FORMAT_NV12:
3886 case DRM_FORMAT_NV21:
3887 case DRM_FORMAT_NV16:
3888 case DRM_FORMAT_NV61:
Laurent Pinchartba623f62012-05-18 23:47:40 +02003889 case DRM_FORMAT_NV24:
3890 case DRM_FORMAT_NV42:
Ville Syrjälä5a86bd52012-04-05 21:35:16 +03003891 return plane ? 2 : 1;
3892 case DRM_FORMAT_YUV410:
3893 case DRM_FORMAT_YVU410:
3894 case DRM_FORMAT_YUV411:
3895 case DRM_FORMAT_YVU411:
3896 case DRM_FORMAT_YUV420:
3897 case DRM_FORMAT_YVU420:
3898 case DRM_FORMAT_YUV422:
3899 case DRM_FORMAT_YVU422:
3900 case DRM_FORMAT_YUV444:
3901 case DRM_FORMAT_YVU444:
3902 return 1;
3903 default:
3904 drm_fb_get_bpp_depth(format, &depth, &bpp);
3905 return bpp >> 3;
3906 }
3907}
3908EXPORT_SYMBOL(drm_format_plane_cpp);
Ville Syrjälä01b68b02012-04-05 21:35:17 +03003909
3910/**
3911 * drm_format_horz_chroma_subsampling - get the horizontal chroma subsampling factor
3912 * @format: pixel format (DRM_FORMAT_*)
3913 *
3914 * RETURNS:
3915 * The horizontal chroma subsampling factor for the
3916 * specified pixel format.
3917 */
3918int drm_format_horz_chroma_subsampling(uint32_t format)
3919{
3920 switch (format) {
3921 case DRM_FORMAT_YUV411:
3922 case DRM_FORMAT_YVU411:
3923 case DRM_FORMAT_YUV410:
3924 case DRM_FORMAT_YVU410:
3925 return 4;
3926 case DRM_FORMAT_YUYV:
3927 case DRM_FORMAT_YVYU:
3928 case DRM_FORMAT_UYVY:
3929 case DRM_FORMAT_VYUY:
3930 case DRM_FORMAT_NV12:
3931 case DRM_FORMAT_NV21:
3932 case DRM_FORMAT_NV16:
3933 case DRM_FORMAT_NV61:
3934 case DRM_FORMAT_YUV422:
3935 case DRM_FORMAT_YVU422:
3936 case DRM_FORMAT_YUV420:
3937 case DRM_FORMAT_YVU420:
3938 return 2;
3939 default:
3940 return 1;
3941 }
3942}
3943EXPORT_SYMBOL(drm_format_horz_chroma_subsampling);
3944
3945/**
3946 * drm_format_vert_chroma_subsampling - get the vertical chroma subsampling factor
3947 * @format: pixel format (DRM_FORMAT_*)
3948 *
3949 * RETURNS:
3950 * The vertical chroma subsampling factor for the
3951 * specified pixel format.
3952 */
3953int drm_format_vert_chroma_subsampling(uint32_t format)
3954{
3955 switch (format) {
3956 case DRM_FORMAT_YUV410:
3957 case DRM_FORMAT_YVU410:
3958 return 4;
3959 case DRM_FORMAT_YUV420:
3960 case DRM_FORMAT_YVU420:
3961 case DRM_FORMAT_NV12:
3962 case DRM_FORMAT_NV21:
3963 return 2;
3964 default:
3965 return 1;
3966 }
3967}
3968EXPORT_SYMBOL(drm_format_vert_chroma_subsampling);
Laurent Pinchart87d24fc2013-04-15 15:37:16 +02003969
3970/**
3971 * drm_mode_config_init - initialize DRM mode_configuration structure
3972 * @dev: DRM device
3973 *
3974 * Initialize @dev's mode_config structure, used for tracking the graphics
3975 * configuration of @dev.
3976 *
3977 * Since this initializes the modeset locks, no locking is possible. Which is no
3978 * problem, since this should happen single threaded at init time. It is the
3979 * driver's problem to ensure this guarantee.
3980 *
3981 */
3982void drm_mode_config_init(struct drm_device *dev)
3983{
3984 mutex_init(&dev->mode_config.mutex);
3985 mutex_init(&dev->mode_config.idr_mutex);
3986 mutex_init(&dev->mode_config.fb_lock);
3987 INIT_LIST_HEAD(&dev->mode_config.fb_list);
3988 INIT_LIST_HEAD(&dev->mode_config.crtc_list);
3989 INIT_LIST_HEAD(&dev->mode_config.connector_list);
3990 INIT_LIST_HEAD(&dev->mode_config.encoder_list);
3991 INIT_LIST_HEAD(&dev->mode_config.property_list);
3992 INIT_LIST_HEAD(&dev->mode_config.property_blob_list);
3993 INIT_LIST_HEAD(&dev->mode_config.plane_list);
3994 idr_init(&dev->mode_config.crtc_idr);
3995
3996 drm_modeset_lock_all(dev);
3997 drm_mode_create_standard_connector_properties(dev);
3998 drm_modeset_unlock_all(dev);
3999
4000 /* Just to be sure */
4001 dev->mode_config.num_fb = 0;
4002 dev->mode_config.num_connector = 0;
4003 dev->mode_config.num_crtc = 0;
4004 dev->mode_config.num_encoder = 0;
4005}
4006EXPORT_SYMBOL(drm_mode_config_init);
4007
4008/**
4009 * drm_mode_config_cleanup - free up DRM mode_config info
4010 * @dev: DRM device
4011 *
4012 * Free up all the connectors and CRTCs associated with this DRM device, then
4013 * free up the framebuffers and associated buffer objects.
4014 *
4015 * Note that since this /should/ happen single-threaded at driver/device
4016 * teardown time, no locking is required. It's the driver's job to ensure that
4017 * this guarantee actually holds true.
4018 *
4019 * FIXME: cleanup any dangling user buffer objects too
4020 */
4021void drm_mode_config_cleanup(struct drm_device *dev)
4022{
4023 struct drm_connector *connector, *ot;
4024 struct drm_crtc *crtc, *ct;
4025 struct drm_encoder *encoder, *enct;
4026 struct drm_framebuffer *fb, *fbt;
4027 struct drm_property *property, *pt;
4028 struct drm_property_blob *blob, *bt;
4029 struct drm_plane *plane, *plt;
4030
4031 list_for_each_entry_safe(encoder, enct, &dev->mode_config.encoder_list,
4032 head) {
4033 encoder->funcs->destroy(encoder);
4034 }
4035
4036 list_for_each_entry_safe(connector, ot,
4037 &dev->mode_config.connector_list, head) {
4038 connector->funcs->destroy(connector);
4039 }
4040
4041 list_for_each_entry_safe(property, pt, &dev->mode_config.property_list,
4042 head) {
4043 drm_property_destroy(dev, property);
4044 }
4045
4046 list_for_each_entry_safe(blob, bt, &dev->mode_config.property_blob_list,
4047 head) {
4048 drm_property_destroy_blob(dev, blob);
4049 }
4050
4051 /*
4052 * Single-threaded teardown context, so it's not required to grab the
4053 * fb_lock to protect against concurrent fb_list access. Contrary, it
4054 * would actually deadlock with the drm_framebuffer_cleanup function.
4055 *
4056 * Also, if there are any framebuffers left, that's a driver leak now,
4057 * so politely WARN about this.
4058 */
4059 WARN_ON(!list_empty(&dev->mode_config.fb_list));
4060 list_for_each_entry_safe(fb, fbt, &dev->mode_config.fb_list, head) {
4061 drm_framebuffer_remove(fb);
4062 }
4063
4064 list_for_each_entry_safe(plane, plt, &dev->mode_config.plane_list,
4065 head) {
4066 plane->funcs->destroy(plane);
4067 }
4068
4069 list_for_each_entry_safe(crtc, ct, &dev->mode_config.crtc_list, head) {
4070 crtc->funcs->destroy(crtc);
4071 }
4072
4073 idr_destroy(&dev->mode_config.crtc_idr);
4074}
4075EXPORT_SYMBOL(drm_mode_config_cleanup);