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