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