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 #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 
     70 static 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 
     80 void* 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 
    101 void drmModeFreeModeInfo(drmModeModeInfoPtr ptr)
    102 {
    103 	if (!ptr)
    104 		return;
    105 
    106 	drmFree(ptr);
    107 }
    108 
    109 void 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 
    122 void drmModeFreeFB(drmModeFBPtr ptr)
    123 {
    124 	if (!ptr)
    125 		return;
    126 
    127 	/* we might add more frees later. */
    128 	drmFree(ptr);
    129 }
    130 
    131 void drmModeFreeCrtc(drmModeCrtcPtr ptr)
    132 {
    133 	if (!ptr)
    134 		return;
    135 
    136 	drmFree(ptr);
    137 
    138 }
    139 
    140 void 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 
    153 void drmModeFreeEncoder(drmModeEncoderPtr ptr)
    154 {
    155 	drmFree(ptr);
    156 }
    157 
    158 /*
    159  * ModeSetting functions.
    160  */
    161 
    162 drmModeResPtr drmModeGetResources(int fd)
    163 {
    164 	struct drm_mode_card_res res, counts;
    165 	drmModeResPtr r = 0;
    166 
    167 retry:
    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 
    247 err_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 
    256 int 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 
    278 int 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 
    301 int drmModeRmFB(int fd, uint32_t bufferId)
    302 {
    303 	return DRM_IOCTL(fd, DRM_IOCTL_MODE_RMFB, &bufferId);
    304 
    305 
    306 }
    307 
    308 drmModeFBPtr 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 
    332 int 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 
    349 drmModeCrtcPtr 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 
    382 int 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 
    408 int 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 
    421 int 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 
    436 int 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  */
    451 drmModeEncoderPtr 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 
    481 drmModeConnectorPtr drmModeGetConnector(int fd, uint32_t connector_id)
    482 {
    483 	struct drm_mode_get_connector conn, counts;
    484 	drmModeConnectorPtr r = NULL;
    485 
    486 retry:
    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 
    567 err_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 
    576 int 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 
    586 int 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 
    597 drmModePropertyPtr 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 
    649 err_allocs:
    650 	drmFree(U642VOID(prop.values_ptr));
    651 	drmFree(U642VOID(prop.enum_blob_ptr));
    652 
    653 	return r;
    654 }
    655 
    656 void drmModeFreeProperty(drmModePropertyPtr ptr)
    657 {
    658 	if (!ptr)
    659 		return;
    660 
    661 	drmFree(ptr->values);
    662 	drmFree(ptr->enums);
    663 	drmFree(ptr);
    664 }
    665 
    666 drmModePropertyBlobPtr 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 
    693 err_allocs:
    694 	drmFree(U642VOID(blob.data));
    695 	return r;
    696 }
    697 
    698 void drmModeFreePropertyBlob(drmModePropertyBlobPtr ptr)
    699 {
    700 	if (!ptr)
    701 		return;
    702 
    703 	drmFree(ptr->data);
    704 	drmFree(ptr);
    705 }
    706 
    707 int 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 */
    725 int 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 
    817 int 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 
    831 int 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 
    845 int 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 
    896 int 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 
    910 int 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 
    937 drmModePlanePtr drmModeGetPlane(int fd, uint32_t plane_id)
    938 {
    939 	struct drm_mode_get_plane ovr, counts;
    940 	drmModePlanePtr r = 0;
    941 
    942 retry:
    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 
    982 err_allocs:
    983 	drmFree(U642VOID(ovr.format_type_ptr));
    984 
    985 	return r;
    986 }
    987 
    988 void drmModeFreePlane(drmModePlanePtr ptr)
    989 {
    990 	if (!ptr)
    991 		return;
    992 
    993 	drmFree(ptr->formats);
    994 	drmFree(ptr);
    995 }
    996 
    997 drmModePlaneResPtr drmModeGetPlaneResources(int fd)
    998 {
    999 	struct drm_mode_get_plane_res res, counts;
   1000 	drmModePlaneResPtr r = 0;
   1001 
   1002 retry:
   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 
   1036 err_allocs:
   1037 	drmFree(U642VOID(res.plane_id_ptr));
   1038 
   1039 	return r;
   1040 }
   1041 
   1042 void drmModeFreePlaneResources(drmModePlaneResPtr ptr)
   1043 {
   1044 	if (!ptr)
   1045 		return;
   1046 
   1047 	drmFree(ptr->planes);
   1048 	drmFree(ptr);
   1049 }
   1050 
   1051 drmModeObjectPropertiesPtr 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 
   1059 retry:
   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 
   1106 err_allocs:
   1107 	drmFree(U642VOID(properties.props_ptr));
   1108 	drmFree(U642VOID(properties.prop_values_ptr));
   1109 	return ret;
   1110 }
   1111 
   1112 void drmModeFreeObjectProperties(drmModeObjectPropertiesPtr ptr)
   1113 {
   1114 	if (!ptr)
   1115 		return;
   1116 	drmFree(ptr->props);
   1117 	drmFree(ptr->prop_values);
   1118 	drmFree(ptr);
   1119 }
   1120 
   1121 int 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 
   1134 typedef struct _drmModePropertySetItem drmModePropertySetItem, *drmModePropertySetItemPtr;
   1135 
   1136 struct _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 
   1145 struct _drmModePropertySet {
   1146 	unsigned int count_objs;
   1147 	unsigned int count_props;
   1148 	unsigned int count_blobs;
   1149 	drmModePropertySetItem list;
   1150 };
   1151 
   1152 drmModePropertySetPtr 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 
   1167 int 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 
   1226 int 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 
   1288 void 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 
   1308 int 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 // TODO:
   1389 //	atomic.blob_values_ptr = VOID2U64(blob_values_ptr);
   1390 	atomic.user_data = VOID2U64(user_data);
   1391 
   1392 	ret = DRM_IOCTL(fd, DRM_IOCTL_MODE_ATOMIC, &atomic);
   1393 
   1394 out:
   1395 	drmFree(objs_ptr);
   1396 	drmFree(count_props_ptr);
   1397 	drmFree(props_ptr);
   1398 	drmFree(prop_values_ptr);
   1399 
   1400 	return ret;
   1401 }
   1402