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