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