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