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