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