xf86drmMode.c revision d049871a
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
44#include "xf86drmMode.h"
45#include "xf86drm.h"
46#include <drm.h>
47#include <string.h>
48#include <dirent.h>
49#include <unistd.h>
50#include <errno.h>
51
52#define U642VOID(x) ((void *)(unsigned long)(x))
53#define VOID2U64(x) ((uint64_t)(unsigned long)(x))
54
55static inline DRM_IOCTL(int fd, int cmd, void *arg)
56{
57	int ret = drmIoctl(fd, cmd, arg);
58	return ret < 0 ? -errno : ret;
59}
60
61/*
62 * Util functions
63 */
64
65void* drmAllocCpy(void *array, int count, int entry_size)
66{
67	char *r;
68	int i;
69
70	if (!count || !array || !entry_size)
71		return 0;
72
73	if (!(r = drmMalloc(count*entry_size)))
74		return 0;
75
76	for (i = 0; i < count; i++)
77		memcpy(r+(entry_size*i), array+(entry_size*i), entry_size);
78
79	return r;
80}
81
82/*
83 * A couple of free functions.
84 */
85
86void drmModeFreeModeInfo(drmModeModeInfoPtr ptr)
87{
88	if (!ptr)
89		return;
90
91	drmFree(ptr);
92}
93
94void drmModeFreeResources(drmModeResPtr ptr)
95{
96	if (!ptr)
97		return;
98
99	drmFree(ptr);
100
101}
102
103void drmModeFreeFB(drmModeFBPtr ptr)
104{
105	if (!ptr)
106		return;
107
108	/* we might add more frees later. */
109	drmFree(ptr);
110}
111
112void drmModeFreeCrtc(drmModeCrtcPtr ptr)
113{
114	if (!ptr)
115		return;
116
117	drmFree(ptr);
118
119}
120
121void drmModeFreeConnector(drmModeConnectorPtr ptr)
122{
123	if (!ptr)
124		return;
125
126	drmFree(ptr->encoders);
127	drmFree(ptr->prop_values);
128	drmFree(ptr->props);
129	drmFree(ptr->modes);
130	drmFree(ptr);
131
132}
133
134void drmModeFreeEncoder(drmModeEncoderPtr ptr)
135{
136	drmFree(ptr);
137}
138
139/*
140 * ModeSetting functions.
141 */
142
143drmModeResPtr drmModeGetResources(int fd)
144{
145	struct drm_mode_card_res res, counts;
146	drmModeResPtr r = 0;
147
148retry:
149	memset(&res, 0, sizeof(struct drm_mode_card_res));
150	if (drmIoctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res))
151		return 0;
152
153	counts = res;
154
155	if (res.count_fbs) {
156		res.fb_id_ptr = VOID2U64(drmMalloc(res.count_fbs*sizeof(uint32_t)));
157		if (!res.fb_id_ptr)
158			goto err_allocs;
159	}
160	if (res.count_crtcs) {
161		res.crtc_id_ptr = VOID2U64(drmMalloc(res.count_crtcs*sizeof(uint32_t)));
162		if (!res.crtc_id_ptr)
163			goto err_allocs;
164	}
165	if (res.count_connectors) {
166		res.connector_id_ptr = VOID2U64(drmMalloc(res.count_connectors*sizeof(uint32_t)));
167		if (!res.connector_id_ptr)
168			goto err_allocs;
169	}
170	if (res.count_encoders) {
171		res.encoder_id_ptr = VOID2U64(drmMalloc(res.count_encoders*sizeof(uint32_t)));
172		if (!res.encoder_id_ptr)
173			goto err_allocs;
174	}
175
176	if (drmIoctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res))
177		goto err_allocs;
178
179	/* The number of available connectors and etc may have changed with a
180	 * hotplug event in between the ioctls, in which case the field is
181	 * silently ignored by the kernel.
182	 */
183	if (counts.count_fbs < res.count_fbs ||
184	    counts.count_crtcs < res.count_crtcs ||
185	    counts.count_connectors < res.count_connectors ||
186	    counts.count_encoders < res.count_encoders)
187	{
188		drmFree(U642VOID(res.fb_id_ptr));
189		drmFree(U642VOID(res.crtc_id_ptr));
190		drmFree(U642VOID(res.connector_id_ptr));
191		drmFree(U642VOID(res.encoder_id_ptr));
192
193		goto retry;
194	}
195
196	/*
197	 * return
198	 */
199	if (!(r = drmMalloc(sizeof(*r))))
200		goto err_allocs;
201
202	r->min_width     = res.min_width;
203	r->max_width     = res.max_width;
204	r->min_height    = res.min_height;
205	r->max_height    = res.max_height;
206	r->count_fbs     = res.count_fbs;
207	r->count_crtcs   = res.count_crtcs;
208	r->count_connectors = res.count_connectors;
209	r->count_encoders = res.count_encoders;
210
211	r->fbs        = drmAllocCpy(U642VOID(res.fb_id_ptr), res.count_fbs, sizeof(uint32_t));
212	r->crtcs      = drmAllocCpy(U642VOID(res.crtc_id_ptr), res.count_crtcs, sizeof(uint32_t));
213	r->connectors = drmAllocCpy(U642VOID(res.connector_id_ptr), res.count_connectors, sizeof(uint32_t));
214	r->encoders   = drmAllocCpy(U642VOID(res.encoder_id_ptr), res.count_encoders, sizeof(uint32_t));
215	if ((res.count_fbs && !r->fbs) ||
216	    (res.count_crtcs && !r->crtcs) ||
217	    (res.count_connectors && !r->connectors) ||
218	    (res.count_encoders && !r->encoders))
219	{
220		drmFree(r->fbs);
221		drmFree(r->crtcs);
222		drmFree(r->connectors);
223		drmFree(r->encoders);
224		drmFree(r);
225		r = 0;
226	}
227
228err_allocs:
229	drmFree(U642VOID(res.fb_id_ptr));
230	drmFree(U642VOID(res.crtc_id_ptr));
231	drmFree(U642VOID(res.connector_id_ptr));
232	drmFree(U642VOID(res.encoder_id_ptr));
233
234	return r;
235}
236
237int drmModeAddFB(int fd, uint32_t width, uint32_t height, uint8_t depth,
238                 uint8_t bpp, uint32_t pitch, uint32_t bo_handle,
239		 uint32_t *buf_id)
240{
241	struct drm_mode_fb_cmd f;
242	int ret;
243
244	f.width  = width;
245	f.height = height;
246	f.pitch  = pitch;
247	f.bpp    = bpp;
248	f.depth  = depth;
249	f.handle = bo_handle;
250
251	if ((ret = DRM_IOCTL(fd, DRM_IOCTL_MODE_ADDFB, &f)))
252		return ret;
253
254	*buf_id = f.fb_id;
255	return 0;
256}
257
258int drmModeRmFB(int fd, uint32_t bufferId)
259{
260	return DRM_IOCTL(fd, DRM_IOCTL_MODE_RMFB, &bufferId);
261
262
263}
264
265drmModeFBPtr drmModeGetFB(int fd, uint32_t buf)
266{
267	struct drm_mode_fb_cmd info;
268	drmModeFBPtr r;
269
270	info.fb_id = buf;
271
272	if (drmIoctl(fd, DRM_IOCTL_MODE_GETFB, &info))
273		return NULL;
274
275	if (!(r = drmMalloc(sizeof(*r))))
276		return NULL;
277
278	r->fb_id = info.fb_id;
279	r->width = info.width;
280	r->height = info.height;
281	r->pitch = info.pitch;
282	r->bpp = info.bpp;
283	r->handle = info.handle;
284	r->depth = info.depth;
285
286	return r;
287}
288
289int drmModeDirtyFB(int fd, uint32_t bufferId,
290		   drmModeClipPtr clips, uint32_t num_clips)
291{
292	struct drm_mode_fb_dirty_cmd dirty = { 0 };
293
294	dirty.fb_id = bufferId;
295	dirty.clips_ptr = VOID2U64(clips);
296	dirty.num_clips = num_clips;
297
298	return DRM_IOCTL(fd, DRM_IOCTL_MODE_DIRTYFB, &dirty);
299}
300
301
302/*
303 * Crtc functions
304 */
305
306drmModeCrtcPtr drmModeGetCrtc(int fd, uint32_t crtcId)
307{
308	struct drm_mode_crtc crtc;
309	drmModeCrtcPtr r;
310
311	crtc.crtc_id = crtcId;
312
313	if (drmIoctl(fd, DRM_IOCTL_MODE_GETCRTC, &crtc))
314		return 0;
315
316	/*
317	 * return
318	 */
319
320	if (!(r = drmMalloc(sizeof(*r))))
321		return 0;
322
323	r->crtc_id         = crtc.crtc_id;
324	r->x               = crtc.x;
325	r->y               = crtc.y;
326	r->mode_valid      = crtc.mode_valid;
327	if (r->mode_valid)
328		memcpy(&r->mode, &crtc.mode, sizeof(struct drm_mode_modeinfo));
329	r->buffer_id       = crtc.fb_id;
330	r->gamma_size      = crtc.gamma_size;
331	return r;
332}
333
334
335int drmModeSetCrtc(int fd, uint32_t crtcId, uint32_t bufferId,
336                   uint32_t x, uint32_t y, uint32_t *connectors, int count,
337		   drmModeModeInfoPtr mode)
338{
339	struct drm_mode_crtc crtc;
340
341	crtc.x             = x;
342	crtc.y             = y;
343	crtc.crtc_id       = crtcId;
344	crtc.fb_id         = bufferId;
345	crtc.set_connectors_ptr = VOID2U64(connectors);
346	crtc.count_connectors = count;
347	if (mode) {
348	  memcpy(&crtc.mode, mode, sizeof(struct drm_mode_modeinfo));
349	  crtc.mode_valid = 1;
350	} else
351	  crtc.mode_valid = 0;
352
353	return DRM_IOCTL(fd, DRM_IOCTL_MODE_SETCRTC, &crtc);
354}
355
356/*
357 * Cursor manipulation
358 */
359
360int drmModeSetCursor(int fd, uint32_t crtcId, uint32_t bo_handle, uint32_t width, uint32_t height)
361{
362	struct drm_mode_cursor arg;
363
364	arg.flags = DRM_MODE_CURSOR_BO;
365	arg.crtc_id = crtcId;
366	arg.width = width;
367	arg.height = height;
368	arg.handle = bo_handle;
369
370	return DRM_IOCTL(fd, DRM_IOCTL_MODE_CURSOR, &arg);
371}
372
373int drmModeMoveCursor(int fd, uint32_t crtcId, int x, int y)
374{
375	struct drm_mode_cursor arg;
376
377	arg.flags = DRM_MODE_CURSOR_MOVE;
378	arg.crtc_id = crtcId;
379	arg.x = x;
380	arg.y = y;
381
382	return DRM_IOCTL(fd, DRM_IOCTL_MODE_CURSOR, &arg);
383}
384
385/*
386 * Encoder get
387 */
388drmModeEncoderPtr drmModeGetEncoder(int fd, uint32_t encoder_id)
389{
390	struct drm_mode_get_encoder enc;
391	drmModeEncoderPtr r = NULL;
392
393	enc.encoder_id = encoder_id;
394	enc.encoder_type = 0;
395	enc.possible_crtcs = 0;
396	enc.possible_clones = 0;
397
398	if (drmIoctl(fd, DRM_IOCTL_MODE_GETENCODER, &enc))
399		return 0;
400
401	if (!(r = drmMalloc(sizeof(*r))))
402		return 0;
403
404	r->encoder_id = enc.encoder_id;
405	r->crtc_id = enc.crtc_id;
406	r->encoder_type = enc.encoder_type;
407	r->possible_crtcs = enc.possible_crtcs;
408	r->possible_clones = enc.possible_clones;
409
410	return r;
411}
412
413/*
414 * Connector manipulation
415 */
416
417drmModeConnectorPtr drmModeGetConnector(int fd, uint32_t connector_id)
418{
419	struct drm_mode_get_connector conn, counts;
420	drmModeConnectorPtr r = NULL;
421
422retry:
423	memset(&conn, 0, sizeof(struct drm_mode_get_connector));
424	conn.connector_id = connector_id;
425
426	if (drmIoctl(fd, DRM_IOCTL_MODE_GETCONNECTOR, &conn))
427		return 0;
428
429	counts = conn;
430
431	if (conn.count_props) {
432		conn.props_ptr = VOID2U64(drmMalloc(conn.count_props*sizeof(uint32_t)));
433		if (!conn.props_ptr)
434			goto err_allocs;
435		conn.prop_values_ptr = VOID2U64(drmMalloc(conn.count_props*sizeof(uint64_t)));
436		if (!conn.prop_values_ptr)
437			goto err_allocs;
438	}
439
440	if (conn.count_modes) {
441		conn.modes_ptr = VOID2U64(drmMalloc(conn.count_modes*sizeof(struct drm_mode_modeinfo)));
442		if (!conn.modes_ptr)
443			goto err_allocs;
444	}
445
446	if (conn.count_encoders) {
447		conn.encoders_ptr = VOID2U64(drmMalloc(conn.count_encoders*sizeof(uint32_t)));
448		if (!conn.encoders_ptr)
449			goto err_allocs;
450	}
451
452	if (drmIoctl(fd, DRM_IOCTL_MODE_GETCONNECTOR, &conn))
453		goto err_allocs;
454
455	/* The number of available connectors and etc may have changed with a
456	 * hotplug event in between the ioctls, in which case the field is
457	 * silently ignored by the kernel.
458	 */
459	if (counts.count_props < conn.count_props ||
460	    counts.count_modes < conn.count_modes ||
461	    counts.count_encoders < conn.count_encoders) {
462		drmFree(U642VOID(conn.props_ptr));
463		drmFree(U642VOID(conn.prop_values_ptr));
464		drmFree(U642VOID(conn.modes_ptr));
465		drmFree(U642VOID(conn.encoders_ptr));
466
467		goto retry;
468	}
469
470	if(!(r = drmMalloc(sizeof(*r)))) {
471		goto err_allocs;
472	}
473
474	r->connector_id = conn.connector_id;
475	r->encoder_id = conn.encoder_id;
476	r->connection   = conn.connection;
477	r->mmWidth      = conn.mm_width;
478	r->mmHeight     = conn.mm_height;
479	/* convert subpixel from kernel to userspace */
480	r->subpixel     = conn.subpixel + 1;
481	r->count_modes  = conn.count_modes;
482	r->count_props  = conn.count_props;
483	r->props        = drmAllocCpy(U642VOID(conn.props_ptr), conn.count_props, sizeof(uint32_t));
484	r->prop_values  = drmAllocCpy(U642VOID(conn.prop_values_ptr), conn.count_props, sizeof(uint64_t));
485	r->modes        = drmAllocCpy(U642VOID(conn.modes_ptr), conn.count_modes, sizeof(struct drm_mode_modeinfo));
486	r->count_encoders = conn.count_encoders;
487	r->encoders     = drmAllocCpy(U642VOID(conn.encoders_ptr), conn.count_encoders, sizeof(uint32_t));
488	r->connector_type  = conn.connector_type;
489	r->connector_type_id = conn.connector_type_id;
490
491	if ((r->count_props && !r->props) ||
492	    (r->count_props && !r->prop_values) ||
493	    (r->count_modes && !r->modes) ||
494	    (r->count_encoders && !r->encoders)) {
495		drmFree(r->props);
496		drmFree(r->prop_values);
497		drmFree(r->modes);
498		drmFree(r->encoders);
499		drmFree(r);
500		r = 0;
501	}
502
503err_allocs:
504	drmFree(U642VOID(conn.prop_values_ptr));
505	drmFree(U642VOID(conn.props_ptr));
506	drmFree(U642VOID(conn.modes_ptr));
507	drmFree(U642VOID(conn.encoders_ptr));
508
509	return r;
510}
511
512int drmModeAttachMode(int fd, uint32_t connector_id, drmModeModeInfoPtr mode_info)
513{
514	struct drm_mode_mode_cmd res;
515
516	memcpy(&res.mode, mode_info, sizeof(struct drm_mode_modeinfo));
517	res.connector_id = connector_id;
518
519	return DRM_IOCTL(fd, DRM_IOCTL_MODE_ATTACHMODE, &res);
520}
521
522int drmModeDetachMode(int fd, uint32_t connector_id, drmModeModeInfoPtr mode_info)
523{
524	struct drm_mode_mode_cmd res;
525
526	memcpy(&res.mode, mode_info, sizeof(struct drm_mode_modeinfo));
527	res.connector_id = connector_id;
528
529	return DRM_IOCTL(fd, DRM_IOCTL_MODE_DETACHMODE, &res);
530}
531
532
533drmModePropertyPtr drmModeGetProperty(int fd, uint32_t property_id)
534{
535	struct drm_mode_get_property prop;
536	drmModePropertyPtr r;
537
538	prop.prop_id = property_id;
539	prop.count_enum_blobs = 0;
540	prop.count_values = 0;
541	prop.flags = 0;
542	prop.enum_blob_ptr = 0;
543	prop.values_ptr = 0;
544
545	if (drmIoctl(fd, DRM_IOCTL_MODE_GETPROPERTY, &prop))
546		return 0;
547
548	if (prop.count_values)
549		prop.values_ptr = VOID2U64(drmMalloc(prop.count_values * sizeof(uint64_t)));
550
551	if (prop.count_enum_blobs && (prop.flags & DRM_MODE_PROP_ENUM))
552		prop.enum_blob_ptr = VOID2U64(drmMalloc(prop.count_enum_blobs * sizeof(struct drm_mode_property_enum)));
553
554	if (prop.count_enum_blobs && (prop.flags & DRM_MODE_PROP_BLOB)) {
555		prop.values_ptr = VOID2U64(drmMalloc(prop.count_enum_blobs * sizeof(uint32_t)));
556		prop.enum_blob_ptr = VOID2U64(drmMalloc(prop.count_enum_blobs * sizeof(uint32_t)));
557	}
558
559	if (drmIoctl(fd, DRM_IOCTL_MODE_GETPROPERTY, &prop)) {
560		r = NULL;
561		goto err_allocs;
562	}
563
564	if (!(r = drmMalloc(sizeof(*r))))
565		return NULL;
566
567	r->prop_id = prop.prop_id;
568	r->count_values = prop.count_values;
569
570	r->flags = prop.flags;
571	if (prop.count_values)
572		r->values = drmAllocCpy(U642VOID(prop.values_ptr), prop.count_values, sizeof(uint64_t));
573	if (prop.flags & DRM_MODE_PROP_ENUM) {
574		r->count_enums = prop.count_enum_blobs;
575		r->enums = drmAllocCpy(U642VOID(prop.enum_blob_ptr), prop.count_enum_blobs, sizeof(struct drm_mode_property_enum));
576	} else if (prop.flags & DRM_MODE_PROP_BLOB) {
577		r->values = drmAllocCpy(U642VOID(prop.values_ptr), prop.count_enum_blobs, sizeof(uint32_t));
578		r->blob_ids = drmAllocCpy(U642VOID(prop.enum_blob_ptr), prop.count_enum_blobs, sizeof(uint32_t));
579		r->count_blobs = prop.count_enum_blobs;
580	}
581	strncpy(r->name, prop.name, DRM_PROP_NAME_LEN);
582	r->name[DRM_PROP_NAME_LEN-1] = 0;
583
584err_allocs:
585	drmFree(U642VOID(prop.values_ptr));
586	drmFree(U642VOID(prop.enum_blob_ptr));
587
588	return r;
589}
590
591void drmModeFreeProperty(drmModePropertyPtr ptr)
592{
593	if (!ptr)
594		return;
595
596	drmFree(ptr->values);
597	drmFree(ptr->enums);
598	drmFree(ptr);
599}
600
601drmModePropertyBlobPtr drmModeGetPropertyBlob(int fd, uint32_t blob_id)
602{
603	struct drm_mode_get_blob blob;
604	drmModePropertyBlobPtr r;
605
606	blob.length = 0;
607	blob.data = 0;
608	blob.blob_id = blob_id;
609
610	if (drmIoctl(fd, DRM_IOCTL_MODE_GETPROPBLOB, &blob))
611		return NULL;
612
613	if (blob.length)
614		blob.data = VOID2U64(drmMalloc(blob.length));
615
616	if (drmIoctl(fd, DRM_IOCTL_MODE_GETPROPBLOB, &blob)) {
617		r = NULL;
618		goto err_allocs;
619	}
620
621	if (!(r = drmMalloc(sizeof(*r))))
622		goto err_allocs;
623
624	r->id = blob.blob_id;
625	r->length = blob.length;
626	r->data = drmAllocCpy(U642VOID(blob.data), 1, blob.length);
627
628err_allocs:
629	drmFree(U642VOID(blob.data));
630	return r;
631}
632
633void drmModeFreePropertyBlob(drmModePropertyBlobPtr ptr)
634{
635	if (!ptr)
636		return;
637
638	drmFree(ptr->data);
639	drmFree(ptr);
640}
641
642int drmModeConnectorSetProperty(int fd, uint32_t connector_id, uint32_t property_id,
643			     uint64_t value)
644{
645	struct drm_mode_connector_set_property osp;
646
647	osp.connector_id = connector_id;
648	osp.prop_id = property_id;
649	osp.value = value;
650
651	return DRM_IOCTL(fd, DRM_IOCTL_MODE_SETPROPERTY, &osp);
652}
653
654/*
655 * checks if a modesetting capable driver has attached to the pci id
656 * returns 0 if modesetting supported.
657 *  -EINVAL or invalid bus id
658 *  -ENOSYS if no modesetting support
659*/
660int drmCheckModesettingSupported(const char *busid)
661{
662#ifdef __linux__
663	char pci_dev_dir[1024];
664	int domain, bus, dev, func;
665	DIR *sysdir;
666	struct dirent *dent;
667	int found = 0, ret;
668
669	ret = sscanf(busid, "pci:%04x:%02x:%02x.%d", &domain, &bus, &dev, &func);
670	if (ret != 4)
671		return -EINVAL;
672
673	sprintf(pci_dev_dir, "/sys/bus/pci/devices/%04x:%02x:%02x.%d/drm",
674		domain, bus, dev, func);
675
676	sysdir = opendir(pci_dev_dir);
677	if (sysdir) {
678		dent = readdir(sysdir);
679		while (dent) {
680			if (!strncmp(dent->d_name, "controlD", 8)) {
681				found = 1;
682				break;
683			}
684
685			dent = readdir(sysdir);
686		}
687		closedir(sysdir);
688		if (found)
689			return 0;
690	}
691
692	sprintf(pci_dev_dir, "/sys/bus/pci/devices/%04x:%02x:%02x.%d/",
693		domain, bus, dev, func);
694
695	sysdir = opendir(pci_dev_dir);
696	if (!sysdir)
697		return -EINVAL;
698
699	dent = readdir(sysdir);
700	while (dent) {
701		if (!strncmp(dent->d_name, "drm:controlD", 12)) {
702			found = 1;
703			break;
704		}
705
706		dent = readdir(sysdir);
707	}
708
709	closedir(sysdir);
710	if (found)
711		return 0;
712#endif
713	return -ENOSYS;
714
715}
716
717int drmModeCrtcGetGamma(int fd, uint32_t crtc_id, uint32_t size,
718			uint16_t *red, uint16_t *green, uint16_t *blue)
719{
720	struct drm_mode_crtc_lut l;
721
722	l.crtc_id = crtc_id;
723	l.gamma_size = size;
724	l.red = VOID2U64(red);
725	l.green = VOID2U64(green);
726	l.blue = VOID2U64(blue);
727
728	return DRM_IOCTL(fd, DRM_IOCTL_MODE_GETGAMMA, &l);
729}
730
731int drmModeCrtcSetGamma(int fd, uint32_t crtc_id, uint32_t size,
732			uint16_t *red, uint16_t *green, uint16_t *blue)
733{
734	struct drm_mode_crtc_lut l;
735
736	l.crtc_id = crtc_id;
737	l.gamma_size = size;
738	l.red = VOID2U64(red);
739	l.green = VOID2U64(green);
740	l.blue = VOID2U64(blue);
741
742	return DRM_IOCTL(fd, DRM_IOCTL_MODE_SETGAMMA, &l);
743}
744
745int drmHandleEvent(int fd, drmEventContextPtr evctx)
746{
747	char buffer[1024];
748	int len, i;
749	struct drm_event *e;
750	struct drm_event_vblank *vblank;
751
752	/* The DRM read semantics guarantees that we always get only
753	 * complete events. */
754
755	len = read(fd, buffer, sizeof buffer);
756	if (len == 0)
757		return 0;
758	if (len < sizeof *e)
759		return -1;
760
761	i = 0;
762	while (i < len) {
763		e = (struct drm_event *) &buffer[i];
764		switch (e->type) {
765		case DRM_EVENT_VBLANK:
766			if (evctx->version < 1 ||
767			    evctx->vblank_handler == NULL)
768				break;
769			vblank = (struct drm_event_vblank *) e;
770			evctx->vblank_handler(fd,
771					      vblank->sequence,
772					      vblank->tv_sec,
773					      vblank->tv_usec,
774					      U642VOID (vblank->user_data));
775			break;
776		case DRM_EVENT_FLIP_COMPLETE:
777			if (evctx->version < 2 ||
778			    evctx->page_flip_handler == NULL)
779				break;
780			vblank = (struct drm_event_vblank *) e;
781			evctx->page_flip_handler(fd,
782						 vblank->sequence,
783						 vblank->tv_sec,
784						 vblank->tv_usec,
785						 U642VOID (vblank->user_data));
786			break;
787		default:
788			break;
789		}
790		i += e->length;
791	}
792
793	return 0;
794}
795
796int drmModePageFlip(int fd, uint32_t crtc_id, uint32_t fb_id,
797		    uint32_t flags, void *user_data)
798{
799	struct drm_mode_crtc_page_flip flip;
800
801	flip.fb_id = fb_id;
802	flip.crtc_id = crtc_id;
803	flip.user_data = VOID2U64(user_data);
804	flip.flags = flags;
805	flip.reserved = 0;
806
807	return DRM_IOCTL(fd, DRM_IOCTL_MODE_PAGE_FLIP, &flip);
808}
809