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