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