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