• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * \file xf86drmMode.c
3  * Header for DRM modesetting interface.
4  *
5  * \author Jakob Bornecrantz <wallbraker@gmail.com>
6  *
7  * \par Acknowledgements:
8  * Feb 2007, Dave Airlie <airlied@linux.ie>
9  */
10 
11 /*
12  * Copyright (c) 2007-2008 Tungsten Graphics, Inc., Cedar Park, Texas.
13  * Copyright (c) 2007-2008 Dave Airlie <airlied@linux.ie>
14  * Copyright (c) 2007-2008 Jakob Bornecrantz <wallbraker@gmail.com>
15  *
16  * Permission is hereby granted, free of charge, to any person obtaining a
17  * copy of this software and associated documentation files (the "Software"),
18  * to deal in the Software without restriction, including without limitation
19  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
20  * and/or sell copies of the Software, and to permit persons to whom the
21  * Software is furnished to do so, subject to the following conditions:
22  *
23  * The above copyright notice and this permission notice shall be included in
24  * all copies or substantial portions of the Software.
25  *
26  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
27  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
28  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
29  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
30  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
31  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
32  * IN THE SOFTWARE.
33  *
34  */
35 
36 #include <limits.h>
37 #include <stdint.h>
38 #include <stdlib.h>
39 #include <sys/ioctl.h>
40 #if HAVE_SYS_SYSCTL_H
41 #include <sys/sysctl.h>
42 #endif
43 #include <stdio.h>
44 #include <stdbool.h>
45 
46 #include "libdrm_macros.h"
47 #include "xf86drmMode.h"
48 #include "xf86drm.h"
49 #include <drm.h>
50 #include <string.h>
51 #include <dirent.h>
52 #include <unistd.h>
53 #include <errno.h>
54 
55 #define memclear(s) memset(&s, 0, sizeof(s))
56 
57 #define U642VOID(x) ((void *)(unsigned long)(x))
58 #define VOID2U64(x) ((uint64_t)(unsigned long)(x))
59 
DRM_IOCTL(int fd,unsigned long cmd,void * arg)60 static inline int DRM_IOCTL(int fd, unsigned long cmd, void *arg)
61 {
62 	int ret = drmIoctl(fd, cmd, arg);
63 	return ret < 0 ? -errno : ret;
64 }
65 
66 /*
67  * Util functions
68  */
69 
drmAllocCpy(char * array,int count,int entry_size)70 static void* drmAllocCpy(char *array, int count, int entry_size)
71 {
72 	char *r;
73 	int i;
74 
75 	if (!count || !array || !entry_size)
76 		return 0;
77 
78 	if (!(r = drmMalloc(count*entry_size)))
79 		return 0;
80 
81 	for (i = 0; i < count; i++)
82 		memcpy(r+(entry_size*i), array+(entry_size*i), entry_size);
83 
84 	return r;
85 }
86 
87 /*
88  * A couple of free functions.
89  */
90 
drmModeFreeModeInfo(drmModeModeInfoPtr ptr)91 drm_public void drmModeFreeModeInfo(drmModeModeInfoPtr ptr)
92 {
93 	if (!ptr)
94 		return;
95 
96 	drmFree(ptr);
97 }
98 
drmModeFreeResources(drmModeResPtr ptr)99 drm_public void drmModeFreeResources(drmModeResPtr ptr)
100 {
101 	if (!ptr)
102 		return;
103 
104 	drmFree(ptr->fbs);
105 	drmFree(ptr->crtcs);
106 	drmFree(ptr->connectors);
107 	drmFree(ptr->encoders);
108 	drmFree(ptr);
109 }
110 
drmModeFreeFB(drmModeFBPtr ptr)111 drm_public void drmModeFreeFB(drmModeFBPtr ptr)
112 {
113 	if (!ptr)
114 		return;
115 
116 	/* we might add more frees later. */
117 	drmFree(ptr);
118 }
119 
drmModeFreeCrtc(drmModeCrtcPtr ptr)120 drm_public void drmModeFreeCrtc(drmModeCrtcPtr ptr)
121 {
122 	if (!ptr)
123 		return;
124 
125 	drmFree(ptr);
126 }
127 
drmModeFreeConnector(drmModeConnectorPtr ptr)128 drm_public void drmModeFreeConnector(drmModeConnectorPtr ptr)
129 {
130 	if (!ptr)
131 		return;
132 
133 	drmFree(ptr->encoders);
134 	drmFree(ptr->prop_values);
135 	drmFree(ptr->props);
136 	drmFree(ptr->modes);
137 	drmFree(ptr);
138 }
139 
drmModeFreeEncoder(drmModeEncoderPtr ptr)140 drm_public void drmModeFreeEncoder(drmModeEncoderPtr ptr)
141 {
142 	drmFree(ptr);
143 }
144 
145 /*
146  * ModeSetting functions.
147  */
148 
drmIsKMS(int fd)149 drm_public int drmIsKMS(int fd)
150 {
151 	struct drm_mode_card_res res = {0};
152 
153 	if (drmIoctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res) != 0)
154 		return 0;
155 
156 	return res.count_crtcs > 0 && res.count_connectors > 0 && res.count_encoders > 0;
157 }
158 
drmModeGetResources(int fd)159 drm_public drmModeResPtr drmModeGetResources(int fd)
160 {
161 	struct drm_mode_card_res res, counts;
162 	drmModeResPtr r = 0;
163 
164 retry:
165 	memclear(res);
166 	if (drmIoctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res))
167 		return 0;
168 
169 	counts = res;
170 
171 	if (res.count_fbs) {
172 		res.fb_id_ptr = VOID2U64(drmMalloc(res.count_fbs*sizeof(uint32_t)));
173 		if (!res.fb_id_ptr)
174 			goto err_allocs;
175 	}
176 	if (res.count_crtcs) {
177 		res.crtc_id_ptr = VOID2U64(drmMalloc(res.count_crtcs*sizeof(uint32_t)));
178 		if (!res.crtc_id_ptr)
179 			goto err_allocs;
180 	}
181 	if (res.count_connectors) {
182 		res.connector_id_ptr = VOID2U64(drmMalloc(res.count_connectors*sizeof(uint32_t)));
183 		if (!res.connector_id_ptr)
184 			goto err_allocs;
185 	}
186 	if (res.count_encoders) {
187 		res.encoder_id_ptr = VOID2U64(drmMalloc(res.count_encoders*sizeof(uint32_t)));
188 		if (!res.encoder_id_ptr)
189 			goto err_allocs;
190 	}
191 
192 	if (drmIoctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res))
193 		goto err_allocs;
194 
195 	/* The number of available connectors and etc may have changed with a
196 	 * hotplug event in between the ioctls, in which case the field is
197 	 * silently ignored by the kernel.
198 	 */
199 	if (counts.count_fbs < res.count_fbs ||
200 	    counts.count_crtcs < res.count_crtcs ||
201 	    counts.count_connectors < res.count_connectors ||
202 	    counts.count_encoders < res.count_encoders)
203 	{
204 		drmFree(U642VOID(res.fb_id_ptr));
205 		drmFree(U642VOID(res.crtc_id_ptr));
206 		drmFree(U642VOID(res.connector_id_ptr));
207 		drmFree(U642VOID(res.encoder_id_ptr));
208 
209 		goto retry;
210 	}
211 
212 	/*
213 	 * return
214 	 */
215 	if (!(r = drmMalloc(sizeof(*r))))
216 		goto err_allocs;
217 
218 	r->min_width     = res.min_width;
219 	r->max_width     = res.max_width;
220 	r->min_height    = res.min_height;
221 	r->max_height    = res.max_height;
222 	r->count_fbs     = res.count_fbs;
223 	r->count_crtcs   = res.count_crtcs;
224 	r->count_connectors = res.count_connectors;
225 	r->count_encoders = res.count_encoders;
226 
227 	r->fbs        = drmAllocCpy(U642VOID(res.fb_id_ptr), res.count_fbs, sizeof(uint32_t));
228 	r->crtcs      = drmAllocCpy(U642VOID(res.crtc_id_ptr), res.count_crtcs, sizeof(uint32_t));
229 	r->connectors = drmAllocCpy(U642VOID(res.connector_id_ptr), res.count_connectors, sizeof(uint32_t));
230 	r->encoders   = drmAllocCpy(U642VOID(res.encoder_id_ptr), res.count_encoders, sizeof(uint32_t));
231 	if ((res.count_fbs && !r->fbs) ||
232 	    (res.count_crtcs && !r->crtcs) ||
233 	    (res.count_connectors && !r->connectors) ||
234 	    (res.count_encoders && !r->encoders))
235 	{
236 		drmFree(r->fbs);
237 		drmFree(r->crtcs);
238 		drmFree(r->connectors);
239 		drmFree(r->encoders);
240 		drmFree(r);
241 		r = 0;
242 	}
243 
244 err_allocs:
245 	drmFree(U642VOID(res.fb_id_ptr));
246 	drmFree(U642VOID(res.crtc_id_ptr));
247 	drmFree(U642VOID(res.connector_id_ptr));
248 	drmFree(U642VOID(res.encoder_id_ptr));
249 
250 	return r;
251 }
252 
253 
drmModeAddFB(int fd,uint32_t width,uint32_t height,uint8_t depth,uint8_t bpp,uint32_t pitch,uint32_t bo_handle,uint32_t * buf_id)254 drm_public int drmModeAddFB(int fd, uint32_t width, uint32_t height, uint8_t depth,
255                             uint8_t bpp, uint32_t pitch, uint32_t bo_handle,
256                             uint32_t *buf_id)
257 {
258 	struct drm_mode_fb_cmd f;
259 	int ret;
260 
261 	memclear(f);
262 	f.width  = width;
263 	f.height = height;
264 	f.pitch  = pitch;
265 	f.bpp    = bpp;
266 	f.depth  = depth;
267 	f.handle = bo_handle;
268 
269 	if ((ret = DRM_IOCTL(fd, DRM_IOCTL_MODE_ADDFB, &f)))
270 		return ret;
271 
272 	*buf_id = f.fb_id;
273 	return 0;
274 }
275 
drmModeAddFB2WithModifiers(int fd,uint32_t width,uint32_t height,uint32_t pixel_format,const uint32_t bo_handles[4],const uint32_t pitches[4],const uint32_t offsets[4],const uint64_t modifier[4],uint32_t * buf_id,uint32_t flags)276 drm_public int drmModeAddFB2WithModifiers(int fd, uint32_t width,
277 		uint32_t height, uint32_t pixel_format, const uint32_t bo_handles[4],
278 		const uint32_t pitches[4], const uint32_t offsets[4],
279 		const uint64_t modifier[4], uint32_t *buf_id, uint32_t flags)
280 {
281 	struct drm_mode_fb_cmd2 f;
282 	int ret;
283 
284 	memclear(f);
285 	f.width  = width;
286 	f.height = height;
287 	f.pixel_format = pixel_format;
288 	f.flags = flags;
289 	memcpy(f.handles, bo_handles, 4 * sizeof(bo_handles[0]));
290 	memcpy(f.pitches, pitches, 4 * sizeof(pitches[0]));
291 	memcpy(f.offsets, offsets, 4 * sizeof(offsets[0]));
292 	if (modifier)
293 		memcpy(f.modifier, modifier, 4 * sizeof(modifier[0]));
294 
295 	if ((ret = DRM_IOCTL(fd, DRM_IOCTL_MODE_ADDFB2, &f)))
296 		return ret;
297 
298 	*buf_id = f.fb_id;
299 	return 0;
300 }
301 
drmModeAddFB2(int fd,uint32_t width,uint32_t height,uint32_t pixel_format,const uint32_t bo_handles[4],const uint32_t pitches[4],const uint32_t offsets[4],uint32_t * buf_id,uint32_t flags)302 drm_public int drmModeAddFB2(int fd, uint32_t width, uint32_t height,
303 		uint32_t pixel_format, const uint32_t bo_handles[4],
304 		const uint32_t pitches[4], const uint32_t offsets[4],
305 		uint32_t *buf_id, uint32_t flags)
306 {
307 	return drmModeAddFB2WithModifiers(fd, width, height,
308 					  pixel_format, bo_handles,
309 					  pitches, offsets, NULL,
310 					  buf_id, flags);
311 }
312 
drmModeRmFB(int fd,uint32_t bufferId)313 drm_public int drmModeRmFB(int fd, uint32_t bufferId)
314 {
315 	return DRM_IOCTL(fd, DRM_IOCTL_MODE_RMFB, &bufferId);
316 }
317 
drmModeGetFB(int fd,uint32_t buf)318 drm_public drmModeFBPtr drmModeGetFB(int fd, uint32_t buf)
319 {
320 	struct drm_mode_fb_cmd info;
321 	drmModeFBPtr r;
322 
323 	memclear(info);
324 	info.fb_id = buf;
325 
326 	if (drmIoctl(fd, DRM_IOCTL_MODE_GETFB, &info))
327 		return NULL;
328 
329 	if (!(r = drmMalloc(sizeof(*r))))
330 		return NULL;
331 
332 	r->fb_id = info.fb_id;
333 	r->width = info.width;
334 	r->height = info.height;
335 	r->pitch = info.pitch;
336 	r->bpp = info.bpp;
337 	r->handle = info.handle;
338 	r->depth = info.depth;
339 
340 	return r;
341 }
342 
drmModeDirtyFB(int fd,uint32_t bufferId,drmModeClipPtr clips,uint32_t num_clips)343 drm_public int drmModeDirtyFB(int fd, uint32_t bufferId,
344 		   drmModeClipPtr clips, uint32_t num_clips)
345 {
346 	struct drm_mode_fb_dirty_cmd dirty;
347 
348 	memclear(dirty);
349 	dirty.fb_id = bufferId;
350 	dirty.clips_ptr = VOID2U64(clips);
351 	dirty.num_clips = num_clips;
352 
353 	return DRM_IOCTL(fd, DRM_IOCTL_MODE_DIRTYFB, &dirty);
354 }
355 
356 /*
357  * Crtc functions
358  */
359 
drmModeGetCrtc(int fd,uint32_t crtcId)360 drm_public drmModeCrtcPtr drmModeGetCrtc(int fd, uint32_t crtcId)
361 {
362 	struct drm_mode_crtc crtc;
363 	drmModeCrtcPtr r;
364 
365 	memclear(crtc);
366 	crtc.crtc_id = crtcId;
367 
368 	if (drmIoctl(fd, DRM_IOCTL_MODE_GETCRTC, &crtc))
369 		return 0;
370 
371 	/*
372 	 * return
373 	 */
374 
375 	if (!(r = drmMalloc(sizeof(*r))))
376 		return 0;
377 
378 	r->crtc_id         = crtc.crtc_id;
379 	r->x               = crtc.x;
380 	r->y               = crtc.y;
381 	r->mode_valid      = crtc.mode_valid;
382 	if (r->mode_valid) {
383 		memcpy(&r->mode, &crtc.mode, sizeof(struct drm_mode_modeinfo));
384 		r->width = crtc.mode.hdisplay;
385 		r->height = crtc.mode.vdisplay;
386 	}
387 	r->buffer_id       = crtc.fb_id;
388 	r->gamma_size      = crtc.gamma_size;
389 	return r;
390 }
391 
drmModeSetCrtc(int fd,uint32_t crtcId,uint32_t bufferId,uint32_t x,uint32_t y,uint32_t * connectors,int count,drmModeModeInfoPtr mode)392 drm_public int drmModeSetCrtc(int fd, uint32_t crtcId, uint32_t bufferId,
393 		   uint32_t x, uint32_t y, uint32_t *connectors, int count,
394 		   drmModeModeInfoPtr mode)
395 {
396 	struct drm_mode_crtc crtc;
397 
398 	memclear(crtc);
399 	crtc.x             = x;
400 	crtc.y             = y;
401 	crtc.crtc_id       = crtcId;
402 	crtc.fb_id         = bufferId;
403 	crtc.set_connectors_ptr = VOID2U64(connectors);
404 	crtc.count_connectors = count;
405 	if (mode) {
406 	  memcpy(&crtc.mode, mode, sizeof(struct drm_mode_modeinfo));
407 	  crtc.mode_valid = 1;
408 	}
409 
410 	return DRM_IOCTL(fd, DRM_IOCTL_MODE_SETCRTC, &crtc);
411 }
412 
413 /*
414  * Cursor manipulation
415  */
416 
drmModeSetCursor(int fd,uint32_t crtcId,uint32_t bo_handle,uint32_t width,uint32_t height)417 drm_public int drmModeSetCursor(int fd, uint32_t crtcId, uint32_t bo_handle,
418 								uint32_t width, uint32_t height)
419 {
420 	struct drm_mode_cursor arg;
421 
422 	memclear(arg);
423 	arg.flags = DRM_MODE_CURSOR_BO;
424 	arg.crtc_id = crtcId;
425 	arg.width = width;
426 	arg.height = height;
427 	arg.handle = bo_handle;
428 
429 	return DRM_IOCTL(fd, DRM_IOCTL_MODE_CURSOR, &arg);
430 }
431 
drmModeSetCursor2(int fd,uint32_t crtcId,uint32_t bo_handle,uint32_t width,uint32_t height,int32_t hot_x,int32_t hot_y)432 drm_public int drmModeSetCursor2(int fd, uint32_t crtcId, uint32_t bo_handle,
433 								 uint32_t width, uint32_t height, int32_t hot_x,
434 								 int32_t hot_y)
435 {
436 	struct drm_mode_cursor2 arg;
437 
438 	memclear(arg);
439 	arg.flags = DRM_MODE_CURSOR_BO;
440 	arg.crtc_id = crtcId;
441 	arg.width = width;
442 	arg.height = height;
443 	arg.handle = bo_handle;
444 	arg.hot_x = hot_x;
445 	arg.hot_y = hot_y;
446 
447 	return DRM_IOCTL(fd, DRM_IOCTL_MODE_CURSOR2, &arg);
448 }
449 
drmModeMoveCursor(int fd,uint32_t crtcId,int x,int y)450 drm_public int drmModeMoveCursor(int fd, uint32_t crtcId, int x, int y)
451 {
452 	struct drm_mode_cursor arg;
453 
454 	memclear(arg);
455 	arg.flags = DRM_MODE_CURSOR_MOVE;
456 	arg.crtc_id = crtcId;
457 	arg.x = x;
458 	arg.y = y;
459 
460 	return DRM_IOCTL(fd, DRM_IOCTL_MODE_CURSOR, &arg);
461 }
462 
463 /*
464  * Encoder get
465  */
drmModeGetEncoder(int fd,uint32_t encoder_id)466 drm_public drmModeEncoderPtr drmModeGetEncoder(int fd, uint32_t encoder_id)
467 {
468 	struct drm_mode_get_encoder enc;
469 	drmModeEncoderPtr r = NULL;
470 
471 	memclear(enc);
472 	enc.encoder_id = encoder_id;
473 
474 	if (drmIoctl(fd, DRM_IOCTL_MODE_GETENCODER, &enc))
475 		return 0;
476 
477 	if (!(r = drmMalloc(sizeof(*r))))
478 		return 0;
479 
480 	r->encoder_id = enc.encoder_id;
481 	r->crtc_id = enc.crtc_id;
482 	r->encoder_type = enc.encoder_type;
483 	r->possible_crtcs = enc.possible_crtcs;
484 	r->possible_clones = enc.possible_clones;
485 
486 	return r;
487 }
488 
489 /*
490  * Connector manipulation
491  */
492 static drmModeConnectorPtr
_drmModeGetConnector(int fd,uint32_t connector_id,int probe)493 _drmModeGetConnector(int fd, uint32_t connector_id, int probe)
494 {
495 	struct drm_mode_get_connector conn, counts;
496 	drmModeConnectorPtr r = NULL;
497 	struct drm_mode_modeinfo stack_mode;
498 
499 	memclear(conn);
500 	conn.connector_id = connector_id;
501 	if (!probe) {
502 		conn.count_modes = 1;
503 		conn.modes_ptr = VOID2U64(&stack_mode);
504 	}
505 
506 	if (drmIoctl(fd, DRM_IOCTL_MODE_GETCONNECTOR, &conn))
507 		return 0;
508 
509 retry:
510 	counts = conn;
511 
512 	if (conn.count_props) {
513 		conn.props_ptr = VOID2U64(drmMalloc(conn.count_props*sizeof(uint32_t)));
514 		if (!conn.props_ptr)
515 			goto err_allocs;
516 		conn.prop_values_ptr = VOID2U64(drmMalloc(conn.count_props*sizeof(uint64_t)));
517 		if (!conn.prop_values_ptr)
518 			goto err_allocs;
519 	}
520 
521 	if (conn.count_modes) {
522 		conn.modes_ptr = VOID2U64(drmMalloc(conn.count_modes*sizeof(struct drm_mode_modeinfo)));
523 		if (!conn.modes_ptr)
524 			goto err_allocs;
525 	} else {
526 		conn.count_modes = 1;
527 		conn.modes_ptr = VOID2U64(&stack_mode);
528 	}
529 
530 	if (conn.count_encoders) {
531 		conn.encoders_ptr = VOID2U64(drmMalloc(conn.count_encoders*sizeof(uint32_t)));
532 		if (!conn.encoders_ptr)
533 			goto err_allocs;
534 	}
535 
536 	if (drmIoctl(fd, DRM_IOCTL_MODE_GETCONNECTOR, &conn))
537 		goto err_allocs;
538 
539 	/* The number of available connectors and etc may have changed with a
540 	 * hotplug event in between the ioctls, in which case the field is
541 	 * silently ignored by the kernel.
542 	 */
543 	if (counts.count_props < conn.count_props ||
544 	    counts.count_modes < conn.count_modes ||
545 	    counts.count_encoders < conn.count_encoders) {
546 		drmFree(U642VOID(conn.props_ptr));
547 		drmFree(U642VOID(conn.prop_values_ptr));
548 		if (U642VOID(conn.modes_ptr) != &stack_mode)
549 			drmFree(U642VOID(conn.modes_ptr));
550 		drmFree(U642VOID(conn.encoders_ptr));
551 
552 		goto retry;
553 	}
554 
555 	if(!(r = drmMalloc(sizeof(*r)))) {
556 		goto err_allocs;
557 	}
558 
559 	r->connector_id = conn.connector_id;
560 	r->encoder_id = conn.encoder_id;
561 	r->connection   = conn.connection;
562 	r->mmWidth      = conn.mm_width;
563 	r->mmHeight     = conn.mm_height;
564 	/* convert subpixel from kernel to userspace */
565 	r->subpixel     = conn.subpixel + 1;
566 	r->count_modes  = conn.count_modes;
567 	r->count_props  = conn.count_props;
568 	r->props        = drmAllocCpy(U642VOID(conn.props_ptr), conn.count_props, sizeof(uint32_t));
569 	r->prop_values  = drmAllocCpy(U642VOID(conn.prop_values_ptr), conn.count_props, sizeof(uint64_t));
570 	r->modes        = drmAllocCpy(U642VOID(conn.modes_ptr), conn.count_modes, sizeof(struct drm_mode_modeinfo));
571 	r->count_encoders = conn.count_encoders;
572 	r->encoders     = drmAllocCpy(U642VOID(conn.encoders_ptr), conn.count_encoders, sizeof(uint32_t));
573 	r->connector_type  = conn.connector_type;
574 	r->connector_type_id = conn.connector_type_id;
575 
576 	if ((r->count_props && !r->props) ||
577 	    (r->count_props && !r->prop_values) ||
578 	    (r->count_modes && !r->modes) ||
579 	    (r->count_encoders && !r->encoders)) {
580 		drmFree(r->props);
581 		drmFree(r->prop_values);
582 		drmFree(r->modes);
583 		drmFree(r->encoders);
584 		drmFree(r);
585 		r = 0;
586 	}
587 
588 err_allocs:
589 	drmFree(U642VOID(conn.prop_values_ptr));
590 	drmFree(U642VOID(conn.props_ptr));
591 	if (U642VOID(conn.modes_ptr) != &stack_mode)
592 		drmFree(U642VOID(conn.modes_ptr));
593 	drmFree(U642VOID(conn.encoders_ptr));
594 
595 	return r;
596 }
597 
drmModeGetConnector(int fd,uint32_t connector_id)598 drm_public drmModeConnectorPtr drmModeGetConnector(int fd, uint32_t connector_id)
599 {
600 	return _drmModeGetConnector(fd, connector_id, 1);
601 }
602 
drmModeGetConnectorCurrent(int fd,uint32_t connector_id)603 drm_public drmModeConnectorPtr drmModeGetConnectorCurrent(int fd, uint32_t connector_id)
604 {
605 	return _drmModeGetConnector(fd, connector_id, 0);
606 }
607 
drmModeAttachMode(int fd,uint32_t connector_id,drmModeModeInfoPtr mode_info)608 drm_public int drmModeAttachMode(int fd, uint32_t connector_id, drmModeModeInfoPtr mode_info)
609 {
610 	struct drm_mode_mode_cmd res;
611 
612 	memclear(res);
613 	memcpy(&res.mode, mode_info, sizeof(struct drm_mode_modeinfo));
614 	res.connector_id = connector_id;
615 
616 	return DRM_IOCTL(fd, DRM_IOCTL_MODE_ATTACHMODE, &res);
617 }
618 
drmModeDetachMode(int fd,uint32_t connector_id,drmModeModeInfoPtr mode_info)619 drm_public int drmModeDetachMode(int fd, uint32_t connector_id, drmModeModeInfoPtr mode_info)
620 {
621 	struct drm_mode_mode_cmd res;
622 
623 	memclear(res);
624 	memcpy(&res.mode, mode_info, sizeof(struct drm_mode_modeinfo));
625 	res.connector_id = connector_id;
626 
627 	return DRM_IOCTL(fd, DRM_IOCTL_MODE_DETACHMODE, &res);
628 }
629 
drmModeGetProperty(int fd,uint32_t property_id)630 drm_public drmModePropertyPtr drmModeGetProperty(int fd, uint32_t property_id)
631 {
632 	struct drm_mode_get_property prop;
633 	drmModePropertyPtr r;
634 
635 	memclear(prop);
636 	prop.prop_id = property_id;
637 
638 	if (drmIoctl(fd, DRM_IOCTL_MODE_GETPROPERTY, &prop))
639 		return 0;
640 
641 	if (prop.count_values)
642 		prop.values_ptr = VOID2U64(drmMalloc(prop.count_values * sizeof(uint64_t)));
643 
644 	if (prop.count_enum_blobs && (prop.flags & (DRM_MODE_PROP_ENUM | DRM_MODE_PROP_BITMASK)))
645 		prop.enum_blob_ptr = VOID2U64(drmMalloc(prop.count_enum_blobs * sizeof(struct drm_mode_property_enum)));
646 
647 	if (prop.count_enum_blobs && (prop.flags & DRM_MODE_PROP_BLOB)) {
648 		prop.values_ptr = VOID2U64(drmMalloc(prop.count_enum_blobs * sizeof(uint32_t)));
649 		prop.enum_blob_ptr = VOID2U64(drmMalloc(prop.count_enum_blobs * sizeof(uint32_t)));
650 	}
651 
652 	if (drmIoctl(fd, DRM_IOCTL_MODE_GETPROPERTY, &prop)) {
653 		r = NULL;
654 		goto err_allocs;
655 	}
656 
657 	if (!(r = drmMalloc(sizeof(*r))))
658 		goto err_allocs;
659 
660 	r->prop_id = prop.prop_id;
661 	r->count_values = prop.count_values;
662 
663 	r->flags = prop.flags;
664 	if (prop.count_values)
665 		r->values = drmAllocCpy(U642VOID(prop.values_ptr), prop.count_values, sizeof(uint64_t));
666 	if (prop.flags & (DRM_MODE_PROP_ENUM | DRM_MODE_PROP_BITMASK)) {
667 		r->count_enums = prop.count_enum_blobs;
668 		r->enums = drmAllocCpy(U642VOID(prop.enum_blob_ptr), prop.count_enum_blobs, sizeof(struct drm_mode_property_enum));
669 	} else if (prop.flags & DRM_MODE_PROP_BLOB) {
670 		r->values = drmAllocCpy(U642VOID(prop.values_ptr), prop.count_enum_blobs, sizeof(uint32_t));
671 		r->blob_ids = drmAllocCpy(U642VOID(prop.enum_blob_ptr), prop.count_enum_blobs, sizeof(uint32_t));
672 		r->count_blobs = prop.count_enum_blobs;
673 	}
674 	strncpy(r->name, prop.name, DRM_PROP_NAME_LEN);
675 	r->name[DRM_PROP_NAME_LEN-1] = 0;
676 
677 err_allocs:
678 	drmFree(U642VOID(prop.values_ptr));
679 	drmFree(U642VOID(prop.enum_blob_ptr));
680 
681 	return r;
682 }
683 
drmModeFreeProperty(drmModePropertyPtr ptr)684 drm_public void drmModeFreeProperty(drmModePropertyPtr ptr)
685 {
686 	if (!ptr)
687 		return;
688 
689 	drmFree(ptr->values);
690 	drmFree(ptr->enums);
691 	drmFree(ptr->blob_ids);
692 	drmFree(ptr);
693 }
694 
drmModeGetPropertyBlob(int fd,uint32_t blob_id)695 drm_public drmModePropertyBlobPtr drmModeGetPropertyBlob(int fd,
696 														 uint32_t blob_id)
697 {
698 	struct drm_mode_get_blob blob;
699 	drmModePropertyBlobPtr r;
700 
701 	memclear(blob);
702 	blob.blob_id = blob_id;
703 
704 	if (drmIoctl(fd, DRM_IOCTL_MODE_GETPROPBLOB, &blob))
705 		return NULL;
706 
707 	if (blob.length)
708 		blob.data = VOID2U64(drmMalloc(blob.length));
709 
710 	if (drmIoctl(fd, DRM_IOCTL_MODE_GETPROPBLOB, &blob)) {
711 		r = NULL;
712 		goto err_allocs;
713 	}
714 
715 	if (!(r = drmMalloc(sizeof(*r))))
716 		goto err_allocs;
717 
718 	r->id = blob.blob_id;
719 	r->length = blob.length;
720 	r->data = drmAllocCpy(U642VOID(blob.data), 1, blob.length);
721 
722 err_allocs:
723 	drmFree(U642VOID(blob.data));
724 	return r;
725 }
726 
drmModeFreePropertyBlob(drmModePropertyBlobPtr ptr)727 drm_public void drmModeFreePropertyBlob(drmModePropertyBlobPtr ptr)
728 {
729 	if (!ptr)
730 		return;
731 
732 	drmFree(ptr->data);
733 	drmFree(ptr);
734 }
735 
drmModeConnectorSetProperty(int fd,uint32_t connector_id,uint32_t property_id,uint64_t value)736 drm_public int drmModeConnectorSetProperty(int fd, uint32_t connector_id,
737 										   uint32_t property_id,
738 										   uint64_t value)
739 {
740 	struct drm_mode_connector_set_property osp;
741 
742 	memclear(osp);
743 	osp.connector_id = connector_id;
744 	osp.prop_id = property_id;
745 	osp.value = value;
746 
747 	return DRM_IOCTL(fd, DRM_IOCTL_MODE_SETPROPERTY, &osp);
748 }
749 
750 /*
751  * checks if a modesetting capable driver has attached to the pci id
752  * returns 0 if modesetting supported.
753  *  -EINVAL or invalid bus id
754  *  -ENOSYS if no modesetting support
755 */
drmCheckModesettingSupported(const char * busid)756 drm_public int drmCheckModesettingSupported(const char *busid)
757 {
758 #if defined (__linux__)
759 	char pci_dev_dir[1024];
760 	int domain, bus, dev, func;
761 	DIR *sysdir;
762 	struct dirent *dent;
763 	int found = 0, ret;
764 
765 	ret = sscanf(busid, "pci:%04x:%02x:%02x.%d", &domain, &bus, &dev, &func);
766 	if (ret != 4)
767 		return -EINVAL;
768 
769 	sprintf(pci_dev_dir, "/sys/bus/pci/devices/%04x:%02x:%02x.%d/drm",
770 		domain, bus, dev, func);
771 
772 	sysdir = opendir(pci_dev_dir);
773 	if (sysdir) {
774 		dent = readdir(sysdir);
775 		while (dent) {
776 			if (!strncmp(dent->d_name, "controlD", 8)) {
777 				found = 1;
778 				break;
779 			}
780 
781 			dent = readdir(sysdir);
782 		}
783 		closedir(sysdir);
784 		if (found)
785 			return 0;
786 	}
787 
788 	sprintf(pci_dev_dir, "/sys/bus/pci/devices/%04x:%02x:%02x.%d/",
789 		domain, bus, dev, func);
790 
791 	sysdir = opendir(pci_dev_dir);
792 	if (!sysdir)
793 		return -EINVAL;
794 
795 	dent = readdir(sysdir);
796 	while (dent) {
797 		if (!strncmp(dent->d_name, "drm:controlD", 12)) {
798 			found = 1;
799 			break;
800 		}
801 
802 		dent = readdir(sysdir);
803 	}
804 
805 	closedir(sysdir);
806 	if (found)
807 		return 0;
808 #elif defined (__FreeBSD__) || defined (__FreeBSD_kernel__)
809 	char sbusid[1024];
810 	char oid[128];
811 	int i, modesetting, ret;
812 	size_t len;
813 
814 	/* How many GPUs do we expect in the machine ? */
815 	for (i = 0; i < 10; i++) {
816 		snprintf(oid, sizeof(oid), "hw.dri.%d.busid", i);
817 		len = sizeof(sbusid);
818 		ret = sysctlbyname(oid, sbusid, &len, NULL, 0);
819 		if (ret == -1) {
820 			if (errno == ENOENT)
821 				continue;
822 			return -EINVAL;
823 		}
824 		if (strcmp(sbusid, busid) != 0)
825 			continue;
826 		snprintf(oid, sizeof(oid), "hw.dri.%d.modesetting", i);
827 		len = sizeof(modesetting);
828 		ret = sysctlbyname(oid, &modesetting, &len, NULL, 0);
829 		if (ret == -1 || len != sizeof(modesetting))
830 			return -EINVAL;
831 		return (modesetting ? 0 : -ENOSYS);
832 	}
833 #elif defined(__DragonFly__)
834 	return 0;
835 #elif defined(__OpenBSD__)
836 	int	fd;
837 	struct drm_mode_card_res res;
838 	drmModeResPtr r = 0;
839 
840 	if ((fd = drmOpen(NULL, busid)) < 0)
841 		return -EINVAL;
842 
843 	memset(&res, 0, sizeof(struct drm_mode_card_res));
844 
845 	if (drmIoctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res)) {
846 		drmClose(fd);
847 		return -errno;
848 	}
849 
850 	drmClose(fd);
851 	return 0;
852 #endif
853 	return -ENOSYS;
854 }
855 
drmModeCrtcGetGamma(int fd,uint32_t crtc_id,uint32_t size,uint16_t * red,uint16_t * green,uint16_t * blue)856 drm_public int drmModeCrtcGetGamma(int fd, uint32_t crtc_id, uint32_t size,
857 								   uint16_t *red, uint16_t *green,
858 								   uint16_t *blue)
859 {
860 	struct drm_mode_crtc_lut l;
861 
862 	memclear(l);
863 	l.crtc_id = crtc_id;
864 	l.gamma_size = size;
865 	l.red = VOID2U64(red);
866 	l.green = VOID2U64(green);
867 	l.blue = VOID2U64(blue);
868 
869 	return DRM_IOCTL(fd, DRM_IOCTL_MODE_GETGAMMA, &l);
870 }
871 
drmModeCrtcSetGamma(int fd,uint32_t crtc_id,uint32_t size,uint16_t * red,uint16_t * green,uint16_t * blue)872 drm_public int drmModeCrtcSetGamma(int fd, uint32_t crtc_id, uint32_t size,
873 								   uint16_t *red, uint16_t *green,
874 								   uint16_t *blue)
875 {
876 	struct drm_mode_crtc_lut l;
877 
878 	memclear(l);
879 	l.crtc_id = crtc_id;
880 	l.gamma_size = size;
881 	l.red = VOID2U64(red);
882 	l.green = VOID2U64(green);
883 	l.blue = VOID2U64(blue);
884 
885 	return DRM_IOCTL(fd, DRM_IOCTL_MODE_SETGAMMA, &l);
886 }
887 
drmHandleEvent(int fd,drmEventContextPtr evctx)888 drm_public int drmHandleEvent(int fd, drmEventContextPtr evctx)
889 {
890 	char buffer[1024];
891 	int len, i;
892 	struct drm_event *e;
893 	struct drm_event_vblank *vblank;
894 	struct drm_event_crtc_sequence *seq;
895 	void *user_data;
896 
897 	/* The DRM read semantics guarantees that we always get only
898 	 * complete events. */
899 
900 	len = read(fd, buffer, sizeof buffer);
901 	if (len == 0)
902 		return 0;
903 	if (len < (int)sizeof *e)
904 		return -1;
905 
906 	i = 0;
907 	while (i < len) {
908 		e = (struct drm_event *)(buffer + i);
909 		switch (e->type) {
910 		case DRM_EVENT_VBLANK:
911 			if (evctx->version < 1 ||
912 			    evctx->vblank_handler == NULL)
913 				break;
914 			vblank = (struct drm_event_vblank *) e;
915 			evctx->vblank_handler(fd,
916 					      vblank->sequence,
917 					      vblank->tv_sec,
918 					      vblank->tv_usec,
919 					      U642VOID (vblank->user_data));
920 			break;
921 		case DRM_EVENT_FLIP_COMPLETE:
922 			vblank = (struct drm_event_vblank *) e;
923 			user_data = U642VOID (vblank->user_data);
924 
925 			if (evctx->version >= 3 && evctx->page_flip_handler2)
926 				evctx->page_flip_handler2(fd,
927 							 vblank->sequence,
928 							 vblank->tv_sec,
929 							 vblank->tv_usec,
930 							 vblank->crtc_id,
931 							 user_data);
932 			else if (evctx->version >= 2 && evctx->page_flip_handler)
933 				evctx->page_flip_handler(fd,
934 							 vblank->sequence,
935 							 vblank->tv_sec,
936 							 vblank->tv_usec,
937 							 user_data);
938 			break;
939 		case DRM_EVENT_CRTC_SEQUENCE:
940 			seq = (struct drm_event_crtc_sequence *) e;
941 			if (evctx->version >= 4 && evctx->sequence_handler)
942 				evctx->sequence_handler(fd,
943 							seq->sequence,
944 							seq->time_ns,
945 							seq->user_data);
946 			break;
947 		default:
948 			break;
949 		}
950 		i += e->length;
951 	}
952 
953 	return 0;
954 }
955 
drmModePageFlip(int fd,uint32_t crtc_id,uint32_t fb_id,uint32_t flags,void * user_data)956 drm_public int drmModePageFlip(int fd, uint32_t crtc_id, uint32_t fb_id,
957 		    uint32_t flags, void *user_data)
958 {
959 	struct drm_mode_crtc_page_flip flip;
960 
961 	memclear(flip);
962 	flip.fb_id = fb_id;
963 	flip.crtc_id = crtc_id;
964 	flip.user_data = VOID2U64(user_data);
965 	flip.flags = flags;
966 
967 	return DRM_IOCTL(fd, DRM_IOCTL_MODE_PAGE_FLIP, &flip);
968 }
969 
drmModePageFlipTarget(int fd,uint32_t crtc_id,uint32_t fb_id,uint32_t flags,void * user_data,uint32_t target_vblank)970 drm_public int drmModePageFlipTarget(int fd, uint32_t crtc_id, uint32_t fb_id,
971 			  uint32_t flags, void *user_data,
972 			  uint32_t target_vblank)
973 {
974 	struct drm_mode_crtc_page_flip_target flip_target;
975 
976 	memclear(flip_target);
977 	flip_target.fb_id = fb_id;
978 	flip_target.crtc_id = crtc_id;
979 	flip_target.user_data = VOID2U64(user_data);
980 	flip_target.flags = flags;
981 	flip_target.sequence = target_vblank;
982 
983 	return DRM_IOCTL(fd, DRM_IOCTL_MODE_PAGE_FLIP, &flip_target);
984 }
985 
drmModeSetPlane(int fd,uint32_t plane_id,uint32_t crtc_id,uint32_t fb_id,uint32_t flags,int32_t crtc_x,int32_t crtc_y,uint32_t crtc_w,uint32_t crtc_h,uint32_t src_x,uint32_t src_y,uint32_t src_w,uint32_t src_h)986 drm_public int drmModeSetPlane(int fd, uint32_t plane_id, uint32_t crtc_id,
987 		    uint32_t fb_id, uint32_t flags,
988 		    int32_t crtc_x, int32_t crtc_y,
989 		    uint32_t crtc_w, uint32_t crtc_h,
990 		    uint32_t src_x, uint32_t src_y,
991 		    uint32_t src_w, uint32_t src_h)
992 {
993 	struct drm_mode_set_plane s;
994 
995 	memclear(s);
996 	s.plane_id = plane_id;
997 	s.crtc_id = crtc_id;
998 	s.fb_id = fb_id;
999 	s.flags = flags;
1000 	s.crtc_x = crtc_x;
1001 	s.crtc_y = crtc_y;
1002 	s.crtc_w = crtc_w;
1003 	s.crtc_h = crtc_h;
1004 	s.src_x = src_x;
1005 	s.src_y = src_y;
1006 	s.src_w = src_w;
1007 	s.src_h = src_h;
1008 
1009 	return DRM_IOCTL(fd, DRM_IOCTL_MODE_SETPLANE, &s);
1010 }
1011 
drmModeGetPlane(int fd,uint32_t plane_id)1012 drm_public drmModePlanePtr drmModeGetPlane(int fd, uint32_t plane_id)
1013 {
1014 	struct drm_mode_get_plane ovr, counts;
1015 	drmModePlanePtr r = 0;
1016 
1017 retry:
1018 	memclear(ovr);
1019 	ovr.plane_id = plane_id;
1020 	if (drmIoctl(fd, DRM_IOCTL_MODE_GETPLANE, &ovr))
1021 		return 0;
1022 
1023 	counts = ovr;
1024 
1025 	if (ovr.count_format_types) {
1026 		ovr.format_type_ptr = VOID2U64(drmMalloc(ovr.count_format_types *
1027 							 sizeof(uint32_t)));
1028 		if (!ovr.format_type_ptr)
1029 			goto err_allocs;
1030 	}
1031 
1032 	if (drmIoctl(fd, DRM_IOCTL_MODE_GETPLANE, &ovr))
1033 		goto err_allocs;
1034 
1035 	if (counts.count_format_types < ovr.count_format_types) {
1036 		drmFree(U642VOID(ovr.format_type_ptr));
1037 		goto retry;
1038 	}
1039 
1040 	if (!(r = drmMalloc(sizeof(*r))))
1041 		goto err_allocs;
1042 
1043 	r->count_formats = ovr.count_format_types;
1044 	r->plane_id = ovr.plane_id;
1045 	r->crtc_id = ovr.crtc_id;
1046 	r->fb_id = ovr.fb_id;
1047 	r->possible_crtcs = ovr.possible_crtcs;
1048 	r->gamma_size = ovr.gamma_size;
1049 	r->formats = drmAllocCpy(U642VOID(ovr.format_type_ptr),
1050 				 ovr.count_format_types, sizeof(uint32_t));
1051 	if (ovr.count_format_types && !r->formats) {
1052 		drmFree(r->formats);
1053 		drmFree(r);
1054 		r = 0;
1055 	}
1056 
1057 err_allocs:
1058 	drmFree(U642VOID(ovr.format_type_ptr));
1059 
1060 	return r;
1061 }
1062 
drmModeFreePlane(drmModePlanePtr ptr)1063 drm_public void drmModeFreePlane(drmModePlanePtr ptr)
1064 {
1065 	if (!ptr)
1066 		return;
1067 
1068 	drmFree(ptr->formats);
1069 	drmFree(ptr);
1070 }
1071 
drmModeGetPlaneResources(int fd)1072 drm_public drmModePlaneResPtr drmModeGetPlaneResources(int fd)
1073 {
1074 	struct drm_mode_get_plane_res res, counts;
1075 	drmModePlaneResPtr r = 0;
1076 
1077 retry:
1078 	memclear(res);
1079 	if (drmIoctl(fd, DRM_IOCTL_MODE_GETPLANERESOURCES, &res))
1080 		return 0;
1081 
1082 	counts = res;
1083 
1084 	if (res.count_planes) {
1085 		res.plane_id_ptr = VOID2U64(drmMalloc(res.count_planes *
1086 							sizeof(uint32_t)));
1087 		if (!res.plane_id_ptr)
1088 			goto err_allocs;
1089 	}
1090 
1091 	if (drmIoctl(fd, DRM_IOCTL_MODE_GETPLANERESOURCES, &res))
1092 		goto err_allocs;
1093 
1094 	if (counts.count_planes < res.count_planes) {
1095 		drmFree(U642VOID(res.plane_id_ptr));
1096 		goto retry;
1097 	}
1098 
1099 	if (!(r = drmMalloc(sizeof(*r))))
1100 		goto err_allocs;
1101 
1102 	r->count_planes = res.count_planes;
1103 	r->planes = drmAllocCpy(U642VOID(res.plane_id_ptr),
1104 				  res.count_planes, sizeof(uint32_t));
1105 	if (res.count_planes && !r->planes) {
1106 		drmFree(r->planes);
1107 		drmFree(r);
1108 		r = 0;
1109 	}
1110 
1111 err_allocs:
1112 	drmFree(U642VOID(res.plane_id_ptr));
1113 
1114 	return r;
1115 }
1116 
drmModeFreePlaneResources(drmModePlaneResPtr ptr)1117 drm_public void drmModeFreePlaneResources(drmModePlaneResPtr ptr)
1118 {
1119 	if (!ptr)
1120 		return;
1121 
1122 	drmFree(ptr->planes);
1123 	drmFree(ptr);
1124 }
1125 
drmModeObjectGetProperties(int fd,uint32_t object_id,uint32_t object_type)1126 drm_public drmModeObjectPropertiesPtr drmModeObjectGetProperties(int fd,
1127 						      uint32_t object_id,
1128 						      uint32_t object_type)
1129 {
1130 	struct drm_mode_obj_get_properties properties;
1131 	drmModeObjectPropertiesPtr ret = NULL;
1132 	uint32_t count;
1133 
1134 retry:
1135 	memclear(properties);
1136 	properties.obj_id = object_id;
1137 	properties.obj_type = object_type;
1138 
1139 	if (drmIoctl(fd, DRM_IOCTL_MODE_OBJ_GETPROPERTIES, &properties))
1140 		return 0;
1141 
1142 	count = properties.count_props;
1143 
1144 	if (count) {
1145 		properties.props_ptr = VOID2U64(drmMalloc(count *
1146 							  sizeof(uint32_t)));
1147 		if (!properties.props_ptr)
1148 			goto err_allocs;
1149 		properties.prop_values_ptr = VOID2U64(drmMalloc(count *
1150 						      sizeof(uint64_t)));
1151 		if (!properties.prop_values_ptr)
1152 			goto err_allocs;
1153 	}
1154 
1155 	if (drmIoctl(fd, DRM_IOCTL_MODE_OBJ_GETPROPERTIES, &properties))
1156 		goto err_allocs;
1157 
1158 	if (count < properties.count_props) {
1159 		drmFree(U642VOID(properties.props_ptr));
1160 		drmFree(U642VOID(properties.prop_values_ptr));
1161 		goto retry;
1162 	}
1163 	count = properties.count_props;
1164 
1165 	ret = drmMalloc(sizeof(*ret));
1166 	if (!ret)
1167 		goto err_allocs;
1168 
1169 	ret->count_props = count;
1170 	ret->props = drmAllocCpy(U642VOID(properties.props_ptr),
1171 				 count, sizeof(uint32_t));
1172 	ret->prop_values = drmAllocCpy(U642VOID(properties.prop_values_ptr),
1173 				       count, sizeof(uint64_t));
1174 	if (ret->count_props && (!ret->props || !ret->prop_values)) {
1175 		drmFree(ret->props);
1176 		drmFree(ret->prop_values);
1177 		drmFree(ret);
1178 		ret = NULL;
1179 	}
1180 
1181 err_allocs:
1182 	drmFree(U642VOID(properties.props_ptr));
1183 	drmFree(U642VOID(properties.prop_values_ptr));
1184 	return ret;
1185 }
1186 
drmModeFreeObjectProperties(drmModeObjectPropertiesPtr ptr)1187 drm_public void drmModeFreeObjectProperties(drmModeObjectPropertiesPtr ptr)
1188 {
1189 	if (!ptr)
1190 		return;
1191 	drmFree(ptr->props);
1192 	drmFree(ptr->prop_values);
1193 	drmFree(ptr);
1194 }
1195 
drmModeObjectSetProperty(int fd,uint32_t object_id,uint32_t object_type,uint32_t property_id,uint64_t value)1196 drm_public int drmModeObjectSetProperty(int fd, uint32_t object_id, uint32_t object_type,
1197 			     uint32_t property_id, uint64_t value)
1198 {
1199 	struct drm_mode_obj_set_property prop;
1200 
1201 	memclear(prop);
1202 	prop.value = value;
1203 	prop.prop_id = property_id;
1204 	prop.obj_id = object_id;
1205 	prop.obj_type = object_type;
1206 
1207 	return DRM_IOCTL(fd, DRM_IOCTL_MODE_OBJ_SETPROPERTY, &prop);
1208 }
1209 
1210 typedef struct _drmModeAtomicReqItem drmModeAtomicReqItem, *drmModeAtomicReqItemPtr;
1211 
1212 struct _drmModeAtomicReqItem {
1213 	uint32_t object_id;
1214 	uint32_t property_id;
1215 	uint64_t value;
1216 };
1217 
1218 struct _drmModeAtomicReq {
1219 	uint32_t cursor;
1220 	uint32_t size_items;
1221 	drmModeAtomicReqItemPtr items;
1222 };
1223 
drmModeAtomicAlloc(void)1224 drm_public drmModeAtomicReqPtr drmModeAtomicAlloc(void)
1225 {
1226 	drmModeAtomicReqPtr req;
1227 
1228 	req = drmMalloc(sizeof *req);
1229 	if (!req)
1230 		return NULL;
1231 
1232 	req->items = NULL;
1233 	req->cursor = 0;
1234 	req->size_items = 0;
1235 
1236 	return req;
1237 }
1238 
drmModeAtomicDuplicate(drmModeAtomicReqPtr old)1239 drm_public drmModeAtomicReqPtr drmModeAtomicDuplicate(drmModeAtomicReqPtr old)
1240 {
1241 	drmModeAtomicReqPtr new;
1242 
1243 	if (!old)
1244 		return NULL;
1245 
1246 	new = drmMalloc(sizeof *new);
1247 	if (!new)
1248 		return NULL;
1249 
1250 	new->cursor = old->cursor;
1251 	new->size_items = old->size_items;
1252 
1253 	if (old->size_items) {
1254 		new->items = drmMalloc(old->size_items * sizeof(*new->items));
1255 		if (!new->items) {
1256 			free(new);
1257 			return NULL;
1258 		}
1259 		memcpy(new->items, old->items,
1260 		       old->cursor * sizeof(*new->items));
1261 	} else {
1262 		new->items = NULL;
1263 	}
1264 
1265 	return new;
1266 }
1267 
drmModeAtomicMerge(drmModeAtomicReqPtr base,drmModeAtomicReqPtr augment)1268 drm_public int drmModeAtomicMerge(drmModeAtomicReqPtr base,
1269                                   drmModeAtomicReqPtr augment)
1270 {
1271 	if (!base)
1272 		return -EINVAL;
1273 
1274 	if (!augment || augment->cursor == 0)
1275 		return 0;
1276 
1277 	if (base->cursor + augment->cursor >= base->size_items) {
1278 		drmModeAtomicReqItemPtr new;
1279 		int saved_size = base->size_items;
1280 
1281 		base->size_items = base->cursor + augment->cursor;
1282 		new = realloc(base->items,
1283 			      base->size_items * sizeof(*base->items));
1284 		if (!new) {
1285 			base->size_items = saved_size;
1286 			return -ENOMEM;
1287 		}
1288 		base->items = new;
1289 	}
1290 
1291 	memcpy(&base->items[base->cursor], augment->items,
1292 	       augment->cursor * sizeof(*augment->items));
1293 	base->cursor += augment->cursor;
1294 
1295 	return 0;
1296 }
1297 
drmModeAtomicGetCursor(drmModeAtomicReqPtr req)1298 drm_public int drmModeAtomicGetCursor(drmModeAtomicReqPtr req)
1299 {
1300 	if (!req)
1301 		return -EINVAL;
1302 	return req->cursor;
1303 }
1304 
drmModeAtomicSetCursor(drmModeAtomicReqPtr req,int cursor)1305 drm_public void drmModeAtomicSetCursor(drmModeAtomicReqPtr req, int cursor)
1306 {
1307 	if (req)
1308 		req->cursor = cursor;
1309 }
1310 
drmModeAtomicAddProperty(drmModeAtomicReqPtr req,uint32_t object_id,uint32_t property_id,uint64_t value)1311 drm_public int drmModeAtomicAddProperty(drmModeAtomicReqPtr req,
1312                                         uint32_t object_id,
1313                                         uint32_t property_id,
1314                                         uint64_t value)
1315 {
1316 	if (!req)
1317 		return -EINVAL;
1318 
1319 	if (object_id == 0 || property_id == 0)
1320 		return -EINVAL;
1321 
1322 	if (req->cursor >= req->size_items) {
1323 		const uint32_t item_size_inc = getpagesize() / sizeof(*req->items);
1324 		drmModeAtomicReqItemPtr new;
1325 
1326 		req->size_items += item_size_inc;
1327 		new = realloc(req->items, req->size_items * sizeof(*req->items));
1328 		if (!new) {
1329 			req->size_items -= item_size_inc;
1330 			return -ENOMEM;
1331 		}
1332 		req->items = new;
1333 	}
1334 
1335 	req->items[req->cursor].object_id = object_id;
1336 	req->items[req->cursor].property_id = property_id;
1337 	req->items[req->cursor].value = value;
1338 	req->cursor++;
1339 
1340 	return req->cursor;
1341 }
1342 
drmModeAtomicFree(drmModeAtomicReqPtr req)1343 drm_public void drmModeAtomicFree(drmModeAtomicReqPtr req)
1344 {
1345 	if (!req)
1346 		return;
1347 
1348 	if (req->items)
1349 		drmFree(req->items);
1350 	drmFree(req);
1351 }
1352 
sort_req_list(const void * misc,const void * other)1353 static int sort_req_list(const void *misc, const void *other)
1354 {
1355 	const drmModeAtomicReqItem *first = misc;
1356 	const drmModeAtomicReqItem *second = other;
1357 
1358 	if (first->object_id < second->object_id)
1359 		return -1;
1360 	else if (first->object_id > second->object_id)
1361 		return 1;
1362 	else
1363 		return second->property_id - first->property_id;
1364 }
1365 
drmModeAtomicCommit(int fd,drmModeAtomicReqPtr req,uint32_t flags,void * user_data)1366 drm_public int drmModeAtomicCommit(int fd, drmModeAtomicReqPtr req,
1367                                    uint32_t flags, void *user_data)
1368 {
1369 	drmModeAtomicReqPtr sorted;
1370 	struct drm_mode_atomic atomic;
1371 	uint32_t *objs_ptr = NULL;
1372 	uint32_t *count_props_ptr = NULL;
1373 	uint32_t *props_ptr = NULL;
1374 	uint64_t *prop_values_ptr = NULL;
1375 	uint32_t last_obj_id = 0;
1376 	uint32_t i;
1377 	int obj_idx = -1;
1378 	int ret = -1;
1379 
1380 	if (!req)
1381 		return -EINVAL;
1382 
1383 	if (req->cursor == 0)
1384 		return 0;
1385 
1386 	sorted = drmModeAtomicDuplicate(req);
1387 	if (sorted == NULL)
1388 		return -ENOMEM;
1389 
1390 	memclear(atomic);
1391 
1392 	/* Sort the list by object ID, then by property ID. */
1393 	qsort(sorted->items, sorted->cursor, sizeof(*sorted->items),
1394 	      sort_req_list);
1395 
1396 	/* Now the list is sorted, eliminate duplicate property sets. */
1397 	for (i = 0; i < sorted->cursor; i++) {
1398 		if (sorted->items[i].object_id != last_obj_id) {
1399 			atomic.count_objs++;
1400 			last_obj_id = sorted->items[i].object_id;
1401 		}
1402 
1403 		if (i == sorted->cursor - 1)
1404 			continue;
1405 
1406 		if (sorted->items[i].object_id != sorted->items[i + 1].object_id ||
1407 		    sorted->items[i].property_id != sorted->items[i + 1].property_id)
1408 			continue;
1409 
1410 		memmove(&sorted->items[i], &sorted->items[i + 1],
1411 			(sorted->cursor - i - 1) * sizeof(*sorted->items));
1412 		sorted->cursor--;
1413 	}
1414 
1415 	objs_ptr = drmMalloc(atomic.count_objs * sizeof objs_ptr[0]);
1416 	if (!objs_ptr) {
1417 		errno = ENOMEM;
1418 		goto out;
1419 	}
1420 
1421 	count_props_ptr = drmMalloc(atomic.count_objs * sizeof count_props_ptr[0]);
1422 	if (!count_props_ptr) {
1423 		errno = ENOMEM;
1424 		goto out;
1425 	}
1426 
1427 	props_ptr = drmMalloc(sorted->cursor * sizeof props_ptr[0]);
1428 	if (!props_ptr) {
1429 		errno = ENOMEM;
1430 		goto out;
1431 	}
1432 
1433 	prop_values_ptr = drmMalloc(sorted->cursor * sizeof prop_values_ptr[0]);
1434 	if (!prop_values_ptr) {
1435 		errno = ENOMEM;
1436 		goto out;
1437 	}
1438 
1439 	for (i = 0, last_obj_id = 0; i < sorted->cursor; i++) {
1440 		if (sorted->items[i].object_id != last_obj_id) {
1441 			obj_idx++;
1442 			objs_ptr[obj_idx] = sorted->items[i].object_id;
1443 			last_obj_id = objs_ptr[obj_idx];
1444 		}
1445 
1446 		count_props_ptr[obj_idx]++;
1447 		props_ptr[i] = sorted->items[i].property_id;
1448 		prop_values_ptr[i] = sorted->items[i].value;
1449 
1450 	}
1451 
1452 	atomic.flags = flags;
1453 	atomic.objs_ptr = VOID2U64(objs_ptr);
1454 	atomic.count_props_ptr = VOID2U64(count_props_ptr);
1455 	atomic.props_ptr = VOID2U64(props_ptr);
1456 	atomic.prop_values_ptr = VOID2U64(prop_values_ptr);
1457 	atomic.user_data = VOID2U64(user_data);
1458 
1459 	ret = DRM_IOCTL(fd, DRM_IOCTL_MODE_ATOMIC, &atomic);
1460 
1461 out:
1462 	drmFree(objs_ptr);
1463 	drmFree(count_props_ptr);
1464 	drmFree(props_ptr);
1465 	drmFree(prop_values_ptr);
1466 	drmModeAtomicFree(sorted);
1467 
1468 	return ret;
1469 }
1470 
1471 drm_public int
drmModeCreatePropertyBlob(int fd,const void * data,size_t length,uint32_t * id)1472 drmModeCreatePropertyBlob(int fd, const void *data, size_t length,
1473                                      uint32_t *id)
1474 {
1475 	struct drm_mode_create_blob create;
1476 	int ret;
1477 
1478 	if (length >= 0xffffffff)
1479 		return -ERANGE;
1480 
1481 	memclear(create);
1482 
1483 	create.length = length;
1484 	create.data = (uintptr_t) data;
1485 	create.blob_id = 0;
1486 	*id = 0;
1487 
1488 	ret = DRM_IOCTL(fd, DRM_IOCTL_MODE_CREATEPROPBLOB, &create);
1489 	if (ret != 0)
1490 		return ret;
1491 
1492 	*id = create.blob_id;
1493 	return 0;
1494 }
1495 
1496 drm_public int
drmModeDestroyPropertyBlob(int fd,uint32_t id)1497 drmModeDestroyPropertyBlob(int fd, uint32_t id)
1498 {
1499 	struct drm_mode_destroy_blob destroy;
1500 
1501 	memclear(destroy);
1502 	destroy.blob_id = id;
1503 	return DRM_IOCTL(fd, DRM_IOCTL_MODE_DESTROYPROPBLOB, &destroy);
1504 }
1505 
1506 drm_public int
drmModeCreateLease(int fd,const uint32_t * objects,int num_objects,int flags,uint32_t * lessee_id)1507 drmModeCreateLease(int fd, const uint32_t *objects, int num_objects, int flags,
1508                    uint32_t *lessee_id)
1509 {
1510 	struct drm_mode_create_lease create;
1511 	int ret;
1512 
1513 	memclear(create);
1514 	create.object_ids = (uintptr_t) objects;
1515 	create.object_count = num_objects;
1516 	create.flags = flags;
1517 
1518 	ret = DRM_IOCTL(fd, DRM_IOCTL_MODE_CREATE_LEASE, &create);
1519 	if (ret == 0) {
1520 		*lessee_id = create.lessee_id;
1521 		return create.fd;
1522 	}
1523 	return -errno;
1524 }
1525 
1526 drm_public drmModeLesseeListPtr
drmModeListLessees(int fd)1527 drmModeListLessees(int fd)
1528 {
1529 	struct drm_mode_list_lessees list;
1530 	uint32_t count;
1531 	drmModeLesseeListPtr ret;
1532 
1533 	memclear(list);
1534 
1535 	if (DRM_IOCTL(fd, DRM_IOCTL_MODE_LIST_LESSEES, &list))
1536 		return NULL;
1537 
1538 	count = list.count_lessees;
1539 	ret = drmMalloc(sizeof (drmModeLesseeListRes) + count * sizeof (ret->lessees[0]));
1540 	if (!ret)
1541 		return NULL;
1542 
1543 	list.lessees_ptr = VOID2U64(&ret->lessees[0]);
1544 	if (DRM_IOCTL(fd, DRM_IOCTL_MODE_LIST_LESSEES, &list)) {
1545 		drmFree(ret);
1546 		return NULL;
1547 	}
1548 
1549 	ret->count = count;
1550 	return ret;
1551 }
1552 
1553 drm_public drmModeObjectListPtr
drmModeGetLease(int fd)1554 drmModeGetLease(int fd)
1555 {
1556 	struct drm_mode_get_lease get;
1557 	uint32_t count;
1558 	drmModeObjectListPtr ret;
1559 
1560 	memclear(get);
1561 
1562 	if (DRM_IOCTL(fd, DRM_IOCTL_MODE_GET_LEASE, &get))
1563 		return NULL;
1564 
1565 	count = get.count_objects;
1566 	ret = drmMalloc(sizeof (drmModeObjectListRes) + count * sizeof (ret->objects[0]));
1567 	if (!ret)
1568 		return NULL;
1569 
1570 	get.objects_ptr = VOID2U64(&ret->objects[0]);
1571 	if (DRM_IOCTL(fd, DRM_IOCTL_MODE_GET_LEASE, &get)) {
1572 		drmFree(ret);
1573 		return NULL;
1574 	}
1575 
1576 	ret->count = count;
1577 	return ret;
1578 }
1579 
1580 drm_public int
drmModeRevokeLease(int fd,uint32_t lessee_id)1581 drmModeRevokeLease(int fd, uint32_t lessee_id)
1582 {
1583 	struct drm_mode_revoke_lease revoke;
1584 	int ret;
1585 
1586 	memclear(revoke);
1587 
1588 	revoke.lessee_id = lessee_id;
1589 
1590 	ret = DRM_IOCTL(fd, DRM_IOCTL_MODE_REVOKE_LEASE, &revoke);
1591 	if (ret == 0)
1592 		return 0;
1593 	return -errno;
1594 }
1595 
1596 drm_public drmModeFB2Ptr
drmModeGetFB2(int fd,uint32_t fb_id)1597 drmModeGetFB2(int fd, uint32_t fb_id)
1598 {
1599 	struct drm_mode_fb_cmd2 get = {
1600 		.fb_id = fb_id,
1601 	};
1602 	drmModeFB2Ptr ret;
1603 	int err;
1604 
1605 	err = DRM_IOCTL(fd, DRM_IOCTL_MODE_GETFB2, &get);
1606 	if (err != 0)
1607 		return NULL;
1608 
1609 	ret = drmMalloc(sizeof(drmModeFB2));
1610 	if (!ret)
1611 		return NULL;
1612 
1613 	ret->fb_id = fb_id;
1614 	ret->width = get.width;
1615 	ret->height = get.height;
1616 	ret->pixel_format = get.pixel_format;
1617 	ret->flags = get.flags;
1618 	ret->modifier = get.modifier[0];
1619 	memcpy(ret->handles, get.handles, sizeof(uint32_t) * 4);
1620 	memcpy(ret->pitches, get.pitches, sizeof(uint32_t) * 4);
1621 	memcpy(ret->offsets, get.offsets, sizeof(uint32_t) * 4);
1622 
1623 	return ret;
1624 }
1625 
drmModeFreeFB2(drmModeFB2Ptr ptr)1626 drm_public void drmModeFreeFB2(drmModeFB2Ptr ptr)
1627 {
1628 	drmFree(ptr);
1629 }
1630