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