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