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 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 44 #include "xf86drmMode.h" 45 #include "xf86drm.h" 46 #include <drm.h> 47 #include <string.h> 48 #include <dirent.h> 49 #include <errno.h> 50 51 #define U642VOID(x) ((void *)(unsigned long)(x)) 52 #define VOID2U64(x) ((uint64_t)(unsigned long)(x)) 53 54 /* 55 * Util functions 56 */ 57 58 void* drmAllocCpy(void *array, int count, int entry_size) 59 { 60 char *r; 61 int i; 62 63 if (!count || !array || !entry_size) 64 return 0; 65 66 if (!(r = drmMalloc(count*entry_size))) 67 return 0; 68 69 for (i = 0; i < count; i++) 70 memcpy(r+(entry_size*i), array+(entry_size*i), entry_size); 71 72 return r; 73 } 74 75 /* 76 * A couple of free functions. 77 */ 78 79 void drmModeFreeModeInfo(drmModeModeInfoPtr ptr) 80 { 81 if (!ptr) 82 return; 83 84 drmFree(ptr); 85 } 86 87 void drmModeFreeResources(drmModeResPtr ptr) 88 { 89 if (!ptr) 90 return; 91 92 drmFree(ptr); 93 94 } 95 96 void drmModeFreeFB(drmModeFBPtr ptr) 97 { 98 if (!ptr) 99 return; 100 101 /* we might add more frees later. */ 102 drmFree(ptr); 103 } 104 105 void drmModeFreeCrtc(drmModeCrtcPtr ptr) 106 { 107 if (!ptr) 108 return; 109 110 drmFree(ptr); 111 112 } 113 114 void drmModeFreeConnector(drmModeConnectorPtr ptr) 115 { 116 if (!ptr) 117 return; 118 119 drmFree(ptr->encoders); 120 drmFree(ptr->prop_values); 121 drmFree(ptr->props); 122 drmFree(ptr->modes); 123 drmFree(ptr); 124 125 } 126 127 void drmModeFreeEncoder(drmModeEncoderPtr ptr) 128 { 129 drmFree(ptr); 130 } 131 132 /* 133 * ModeSetting functions. 134 */ 135 136 drmModeResPtr drmModeGetResources(int fd) 137 { 138 struct drm_mode_card_res res; 139 drmModeResPtr r = 0; 140 141 memset(&res, 0, sizeof(struct drm_mode_card_res)); 142 143 if (drmIoctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res)) 144 return 0; 145 146 if (res.count_fbs) 147 res.fb_id_ptr = VOID2U64(drmMalloc(res.count_fbs*sizeof(uint32_t))); 148 if (res.count_crtcs) 149 res.crtc_id_ptr = VOID2U64(drmMalloc(res.count_crtcs*sizeof(uint32_t))); 150 if (res.count_connectors) 151 res.connector_id_ptr = VOID2U64(drmMalloc(res.count_connectors*sizeof(uint32_t))); 152 if (res.count_encoders) 153 res.encoder_id_ptr = VOID2U64(drmMalloc(res.count_encoders*sizeof(uint32_t))); 154 155 if (drmIoctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res)) { 156 r = NULL; 157 goto err_allocs; 158 } 159 160 /* 161 * return 162 */ 163 164 165 if (!(r = drmMalloc(sizeof(*r)))) 166 return 0; 167 168 r->min_width = res.min_width; 169 r->max_width = res.max_width; 170 r->min_height = res.min_height; 171 r->max_height = res.max_height; 172 r->count_fbs = res.count_fbs; 173 r->count_crtcs = res.count_crtcs; 174 r->count_connectors = res.count_connectors; 175 r->count_encoders = res.count_encoders; 176 /* TODO we realy should test if these allocs fails. */ 177 r->fbs = drmAllocCpy(U642VOID(res.fb_id_ptr), res.count_fbs, sizeof(uint32_t)); 178 r->crtcs = drmAllocCpy(U642VOID(res.crtc_id_ptr), res.count_crtcs, sizeof(uint32_t)); 179 r->connectors = drmAllocCpy(U642VOID(res.connector_id_ptr), res.count_connectors, sizeof(uint32_t)); 180 r->encoders = drmAllocCpy(U642VOID(res.encoder_id_ptr), res.count_encoders, sizeof(uint32_t)); 181 182 err_allocs: 183 drmFree(U642VOID(res.fb_id_ptr)); 184 drmFree(U642VOID(res.crtc_id_ptr)); 185 drmFree(U642VOID(res.connector_id_ptr)); 186 drmFree(U642VOID(res.encoder_id_ptr)); 187 188 return r; 189 } 190 191 int drmModeAddFB(int fd, uint32_t width, uint32_t height, uint8_t depth, 192 uint8_t bpp, uint32_t pitch, uint32_t bo_handle, 193 uint32_t *buf_id) 194 { 195 struct drm_mode_fb_cmd f; 196 int ret; 197 198 f.width = width; 199 f.height = height; 200 f.pitch = pitch; 201 f.bpp = bpp; 202 f.depth = depth; 203 f.handle = bo_handle; 204 205 if ((ret = drmIoctl(fd, DRM_IOCTL_MODE_ADDFB, &f))) 206 return ret; 207 208 *buf_id = f.fb_id; 209 return 0; 210 } 211 212 int drmModeRmFB(int fd, uint32_t bufferId) 213 { 214 return drmIoctl(fd, DRM_IOCTL_MODE_RMFB, &bufferId); 215 216 217 } 218 219 drmModeFBPtr drmModeGetFB(int fd, uint32_t buf) 220 { 221 struct drm_mode_fb_cmd info; 222 drmModeFBPtr r; 223 224 info.fb_id = buf; 225 226 if (drmIoctl(fd, DRM_IOCTL_MODE_GETFB, &info)) 227 return NULL; 228 229 if (!(r = drmMalloc(sizeof(*r)))) 230 return NULL; 231 232 r->fb_id = info.fb_id; 233 r->width = info.width; 234 r->height = info.height; 235 r->pitch = info.pitch; 236 r->bpp = info.bpp; 237 r->handle = info.handle; 238 r->depth = info.depth; 239 240 return r; 241 } 242 243 244 /* 245 * Crtc functions 246 */ 247 248 drmModeCrtcPtr drmModeGetCrtc(int fd, uint32_t crtcId) 249 { 250 struct drm_mode_crtc crtc; 251 drmModeCrtcPtr r; 252 253 crtc.crtc_id = crtcId; 254 255 if (drmIoctl(fd, DRM_IOCTL_MODE_GETCRTC, &crtc)) 256 return 0; 257 258 /* 259 * return 260 */ 261 262 if (!(r = drmMalloc(sizeof(*r)))) 263 return 0; 264 265 r->crtc_id = crtc.crtc_id; 266 r->x = crtc.x; 267 r->y = crtc.y; 268 r->mode_valid = crtc.mode_valid; 269 if (r->mode_valid) 270 memcpy(&r->mode, &crtc.mode, sizeof(struct drm_mode_modeinfo)); 271 r->buffer_id = crtc.fb_id; 272 r->gamma_size = crtc.gamma_size; 273 return r; 274 } 275 276 277 int drmModeSetCrtc(int fd, uint32_t crtcId, uint32_t bufferId, 278 uint32_t x, uint32_t y, uint32_t *connectors, int count, 279 drmModeModeInfoPtr mode) 280 { 281 struct drm_mode_crtc crtc; 282 283 crtc.x = x; 284 crtc.y = y; 285 crtc.crtc_id = crtcId; 286 crtc.fb_id = bufferId; 287 crtc.set_connectors_ptr = VOID2U64(connectors); 288 crtc.count_connectors = count; 289 if (mode) { 290 memcpy(&crtc.mode, mode, sizeof(struct drm_mode_modeinfo)); 291 crtc.mode_valid = 1; 292 } else 293 crtc.mode_valid = 0; 294 295 return drmIoctl(fd, DRM_IOCTL_MODE_SETCRTC, &crtc); 296 } 297 298 /* 299 * Cursor manipulation 300 */ 301 302 int drmModeSetCursor(int fd, uint32_t crtcId, uint32_t bo_handle, uint32_t width, uint32_t height) 303 { 304 struct drm_mode_cursor arg; 305 306 arg.flags = DRM_MODE_CURSOR_BO; 307 arg.crtc_id = crtcId; 308 arg.width = width; 309 arg.height = height; 310 arg.handle = bo_handle; 311 312 return drmIoctl(fd, DRM_IOCTL_MODE_CURSOR, &arg); 313 } 314 315 int drmModeMoveCursor(int fd, uint32_t crtcId, int x, int y) 316 { 317 struct drm_mode_cursor arg; 318 319 arg.flags = DRM_MODE_CURSOR_MOVE; 320 arg.crtc_id = crtcId; 321 arg.x = x; 322 arg.y = y; 323 324 return drmIoctl(fd, DRM_IOCTL_MODE_CURSOR, &arg); 325 } 326 327 /* 328 * Encoder get 329 */ 330 drmModeEncoderPtr drmModeGetEncoder(int fd, uint32_t encoder_id) 331 { 332 struct drm_mode_get_encoder enc; 333 drmModeEncoderPtr r = NULL; 334 335 enc.encoder_id = encoder_id; 336 enc.encoder_type = 0; 337 enc.possible_crtcs = 0; 338 enc.possible_clones = 0; 339 340 if (drmIoctl(fd, DRM_IOCTL_MODE_GETENCODER, &enc)) 341 return 0; 342 343 if (!(r = drmMalloc(sizeof(*r)))) 344 return 0; 345 346 r->encoder_id = enc.encoder_id; 347 r->crtc_id = enc.crtc_id; 348 r->encoder_type = enc.encoder_type; 349 r->possible_crtcs = enc.possible_crtcs; 350 r->possible_clones = enc.possible_clones; 351 352 return r; 353 } 354 355 /* 356 * Connector manipulation 357 */ 358 359 drmModeConnectorPtr drmModeGetConnector(int fd, uint32_t connector_id) 360 { 361 struct drm_mode_get_connector conn, counts; 362 drmModeConnectorPtr r = NULL; 363 364 retry: 365 memset(&conn, 0, sizeof(struct drm_mode_get_connector)); 366 conn.connector_id = connector_id; 367 368 if (drmIoctl(fd, DRM_IOCTL_MODE_GETCONNECTOR, &conn)) 369 return 0; 370 371 counts = conn; 372 373 if (conn.count_props) { 374 conn.props_ptr = VOID2U64(drmMalloc(conn.count_props*sizeof(uint32_t))); 375 if (!conn.props_ptr) 376 goto err_allocs; 377 conn.prop_values_ptr = VOID2U64(drmMalloc(conn.count_props*sizeof(uint64_t))); 378 if (!conn.prop_values_ptr) 379 goto err_allocs; 380 } 381 382 if (conn.count_modes) { 383 conn.modes_ptr = VOID2U64(drmMalloc(conn.count_modes*sizeof(struct drm_mode_modeinfo))); 384 if (!conn.modes_ptr) 385 goto err_allocs; 386 } 387 388 if (conn.count_encoders) { 389 conn.encoders_ptr = VOID2U64(drmMalloc(conn.count_encoders*sizeof(uint32_t))); 390 if (!conn.encoders_ptr) 391 goto err_allocs; 392 } 393 394 if (drmIoctl(fd, DRM_IOCTL_MODE_GETCONNECTOR, &conn)) 395 goto err_allocs; 396 397 /* The number of available connectors and etc may have changed with a 398 * hotplug event in between the ioctls, in which case the field is 399 * silently ignored by the kernel. 400 */ 401 if (counts.count_props < conn.count_props || 402 counts.count_modes < conn.count_modes || 403 counts.count_encoders < conn.count_encoders) { 404 drmFree(U642VOID(conn.props_ptr)); 405 drmFree(U642VOID(conn.prop_values_ptr)); 406 drmFree(U642VOID(conn.modes_ptr)); 407 drmFree(U642VOID(conn.encoders_ptr)); 408 409 goto retry; 410 } 411 412 if(!(r = drmMalloc(sizeof(*r)))) { 413 goto err_allocs; 414 } 415 416 r->connector_id = conn.connector_id; 417 r->encoder_id = conn.encoder_id; 418 r->connection = conn.connection; 419 r->mmWidth = conn.mm_width; 420 r->mmHeight = conn.mm_height; 421 /* convert subpixel from kernel to userspace */ 422 r->subpixel = conn.subpixel + 1; 423 r->count_modes = conn.count_modes; 424 r->count_props = conn.count_props; 425 r->props = drmAllocCpy(U642VOID(conn.props_ptr), conn.count_props, sizeof(uint32_t)); 426 r->prop_values = drmAllocCpy(U642VOID(conn.prop_values_ptr), conn.count_props, sizeof(uint64_t)); 427 r->modes = drmAllocCpy(U642VOID(conn.modes_ptr), conn.count_modes, sizeof(struct drm_mode_modeinfo)); 428 r->count_encoders = conn.count_encoders; 429 r->encoders = drmAllocCpy(U642VOID(conn.encoders_ptr), conn.count_encoders, sizeof(uint32_t)); 430 r->connector_type = conn.connector_type; 431 r->connector_type_id = conn.connector_type_id; 432 433 if ((r->count_props && !r->props) || 434 (r->count_props && !r->prop_values) || 435 (r->count_modes && !r->modes) || 436 (r->count_encoders && !r->encoders)) { 437 drmFree(r->props); 438 drmFree(r->prop_values); 439 drmFree(r->modes); 440 drmFree(r->encoders); 441 drmFree(r); 442 r = 0; 443 } 444 445 err_allocs: 446 drmFree(U642VOID(conn.prop_values_ptr)); 447 drmFree(U642VOID(conn.props_ptr)); 448 drmFree(U642VOID(conn.modes_ptr)); 449 drmFree(U642VOID(conn.encoders_ptr)); 450 451 return r; 452 } 453 454 int drmModeAttachMode(int fd, uint32_t connector_id, drmModeModeInfoPtr mode_info) 455 { 456 struct drm_mode_mode_cmd res; 457 458 memcpy(&res.mode, mode_info, sizeof(struct drm_mode_modeinfo)); 459 res.connector_id = connector_id; 460 461 return drmIoctl(fd, DRM_IOCTL_MODE_ATTACHMODE, &res); 462 } 463 464 int drmModeDetachMode(int fd, uint32_t connector_id, drmModeModeInfoPtr mode_info) 465 { 466 struct drm_mode_mode_cmd res; 467 468 memcpy(&res.mode, mode_info, sizeof(struct drm_mode_modeinfo)); 469 res.connector_id = connector_id; 470 471 return drmIoctl(fd, DRM_IOCTL_MODE_DETACHMODE, &res); 472 } 473 474 475 drmModePropertyPtr drmModeGetProperty(int fd, uint32_t property_id) 476 { 477 struct drm_mode_get_property prop; 478 drmModePropertyPtr r; 479 480 prop.prop_id = property_id; 481 prop.count_enum_blobs = 0; 482 prop.count_values = 0; 483 prop.flags = 0; 484 prop.enum_blob_ptr = 0; 485 prop.values_ptr = 0; 486 487 if (drmIoctl(fd, DRM_IOCTL_MODE_GETPROPERTY, &prop)) 488 return 0; 489 490 if (prop.count_values) 491 prop.values_ptr = VOID2U64(drmMalloc(prop.count_values * sizeof(uint64_t))); 492 493 if (prop.count_enum_blobs && (prop.flags & DRM_MODE_PROP_ENUM)) 494 prop.enum_blob_ptr = VOID2U64(drmMalloc(prop.count_enum_blobs * sizeof(struct drm_mode_property_enum))); 495 496 if (prop.count_enum_blobs && (prop.flags & DRM_MODE_PROP_BLOB)) { 497 prop.values_ptr = VOID2U64(drmMalloc(prop.count_enum_blobs * sizeof(uint32_t))); 498 prop.enum_blob_ptr = VOID2U64(drmMalloc(prop.count_enum_blobs * sizeof(uint32_t))); 499 } 500 501 if (drmIoctl(fd, DRM_IOCTL_MODE_GETPROPERTY, &prop)) { 502 r = NULL; 503 goto err_allocs; 504 } 505 506 if (!(r = drmMalloc(sizeof(*r)))) 507 return NULL; 508 509 r->prop_id = prop.prop_id; 510 r->count_values = prop.count_values; 511 512 r->flags = prop.flags; 513 if (prop.count_values) 514 r->values = drmAllocCpy(U642VOID(prop.values_ptr), prop.count_values, sizeof(uint64_t)); 515 if (prop.flags & DRM_MODE_PROP_ENUM) { 516 r->count_enums = prop.count_enum_blobs; 517 r->enums = drmAllocCpy(U642VOID(prop.enum_blob_ptr), prop.count_enum_blobs, sizeof(struct drm_mode_property_enum)); 518 } else if (prop.flags & DRM_MODE_PROP_BLOB) { 519 r->values = drmAllocCpy(U642VOID(prop.values_ptr), prop.count_enum_blobs, sizeof(uint32_t)); 520 r->blob_ids = drmAllocCpy(U642VOID(prop.enum_blob_ptr), prop.count_enum_blobs, sizeof(uint32_t)); 521 r->count_blobs = prop.count_enum_blobs; 522 } 523 strncpy(r->name, prop.name, DRM_PROP_NAME_LEN); 524 r->name[DRM_PROP_NAME_LEN-1] = 0; 525 526 err_allocs: 527 drmFree(U642VOID(prop.values_ptr)); 528 drmFree(U642VOID(prop.enum_blob_ptr)); 529 530 return r; 531 } 532 533 void drmModeFreeProperty(drmModePropertyPtr ptr) 534 { 535 if (!ptr) 536 return; 537 538 drmFree(ptr->values); 539 drmFree(ptr->enums); 540 drmFree(ptr); 541 } 542 543 drmModePropertyBlobPtr drmModeGetPropertyBlob(int fd, uint32_t blob_id) 544 { 545 struct drm_mode_get_blob blob; 546 drmModePropertyBlobPtr r; 547 548 blob.length = 0; 549 blob.data = 0; 550 blob.blob_id = blob_id; 551 552 if (drmIoctl(fd, DRM_IOCTL_MODE_GETPROPBLOB, &blob)) 553 return NULL; 554 555 if (blob.length) 556 blob.data = VOID2U64(drmMalloc(blob.length)); 557 558 if (drmIoctl(fd, DRM_IOCTL_MODE_GETPROPBLOB, &blob)) { 559 r = NULL; 560 goto err_allocs; 561 } 562 563 if (!(r = drmMalloc(sizeof(*r)))) 564 return NULL; 565 566 r->id = blob.blob_id; 567 r->length = blob.length; 568 r->data = drmAllocCpy(U642VOID(blob.data), 1, blob.length); 569 570 err_allocs: 571 drmFree(U642VOID(blob.data)); 572 return r; 573 } 574 575 void drmModeFreePropertyBlob(drmModePropertyBlobPtr ptr) 576 { 577 if (!ptr) 578 return; 579 580 drmFree(ptr->data); 581 drmFree(ptr); 582 } 583 584 int drmModeConnectorSetProperty(int fd, uint32_t connector_id, uint32_t property_id, 585 uint64_t value) 586 { 587 struct drm_mode_connector_set_property osp; 588 int ret; 589 590 osp.connector_id = connector_id; 591 osp.prop_id = property_id; 592 osp.value = value; 593 594 if ((ret = drmIoctl(fd, DRM_IOCTL_MODE_SETPROPERTY, &osp))) 595 return ret; 596 597 return 0; 598 } 599 600 /* 601 * checks if a modesetting capable driver has attached to the pci id 602 * returns 0 if modesetting supported. 603 * -EINVAL or invalid bus id 604 * -ENOSYS if no modesetting support 605 */ 606 int drmCheckModesettingSupported(const char *busid) 607 { 608 #ifdef __linux__ 609 char pci_dev_dir[1024]; 610 int domain, bus, dev, func; 611 DIR *sysdir; 612 struct dirent *dent; 613 int found = 0, ret; 614 615 ret = sscanf(busid, "pci:%04x:%02x:%02x.%d", &domain, &bus, &dev, &func); 616 if (ret != 4) 617 return -EINVAL; 618 619 sprintf(pci_dev_dir, "/sys/bus/pci/devices/%04x:%02x:%02x.%d/drm", 620 domain, bus, dev, func); 621 622 sysdir = opendir(pci_dev_dir); 623 if (sysdir) { 624 dent = readdir(sysdir); 625 while (dent) { 626 if (!strncmp(dent->d_name, "controlD", 8)) { 627 found = 1; 628 break; 629 } 630 631 dent = readdir(sysdir); 632 } 633 closedir(sysdir); 634 if (found) 635 return 0; 636 } 637 638 sprintf(pci_dev_dir, "/sys/bus/pci/devices/%04x:%02x:%02x.%d/", 639 domain, bus, dev, func); 640 641 sysdir = opendir(pci_dev_dir); 642 if (!sysdir) 643 return -EINVAL; 644 645 dent = readdir(sysdir); 646 while (dent) { 647 if (!strncmp(dent->d_name, "drm:controlD", 12)) { 648 found = 1; 649 break; 650 } 651 652 dent = readdir(sysdir); 653 } 654 655 closedir(sysdir); 656 if (found) 657 return 0; 658 #endif 659 return -ENOSYS; 660 661 } 662 663 int drmModeCrtcGetGamma(int fd, uint32_t crtc_id, uint32_t size, 664 uint16_t *red, uint16_t *green, uint16_t *blue) 665 { 666 int ret; 667 struct drm_mode_crtc_lut l; 668 669 l.crtc_id = crtc_id; 670 l.gamma_size = size; 671 l.red = VOID2U64(red); 672 l.green = VOID2U64(green); 673 l.blue = VOID2U64(blue); 674 675 if ((ret = drmIoctl(fd, DRM_IOCTL_MODE_GETGAMMA, &l))) 676 return ret; 677 678 return 0; 679 } 680 681 int drmModeCrtcSetGamma(int fd, uint32_t crtc_id, uint32_t size, 682 uint16_t *red, uint16_t *green, uint16_t *blue) 683 { 684 int ret; 685 struct drm_mode_crtc_lut l; 686 687 l.crtc_id = crtc_id; 688 l.gamma_size = size; 689 l.red = VOID2U64(red); 690 l.green = VOID2U64(green); 691 l.blue = VOID2U64(blue); 692 693 if ((ret = drmIoctl(fd, DRM_IOCTL_MODE_SETGAMMA, &l))) 694 return ret; 695 696 return 0; 697 } 698