xf86drm.c revision 3b115362
1/** 2 * \file xf86drm.c 3 * User-level interface to DRM device 4 * 5 * \author Rickard E. (Rik) Faith <faith@valinux.com> 6 * \author Kevin E. Martin <martin@valinux.com> 7 */ 8 9/* 10 * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. 11 * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. 12 * All Rights Reserved. 13 * 14 * Permission is hereby granted, free of charge, to any person obtaining a 15 * copy of this software and associated documentation files (the "Software"), 16 * to deal in the Software without restriction, including without limitation 17 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 18 * and/or sell copies of the Software, and to permit persons to whom the 19 * Software is furnished to do so, subject to the following conditions: 20 * 21 * The above copyright notice and this permission notice (including the next 22 * paragraph) shall be included in all copies or substantial portions of the 23 * Software. 24 * 25 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 26 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 27 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 28 * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 29 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 30 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 31 * DEALINGS IN THE SOFTWARE. 32 */ 33 34#include <stdio.h> 35#include <stdlib.h> 36#include <stdbool.h> 37#include <unistd.h> 38#include <string.h> 39#include <strings.h> 40#include <ctype.h> 41#include <dirent.h> 42#include <stddef.h> 43#include <fcntl.h> 44#include <errno.h> 45#include <limits.h> 46#include <signal.h> 47#include <time.h> 48#include <sys/types.h> 49#include <sys/stat.h> 50#define stat_t struct stat 51#include <sys/ioctl.h> 52#include <sys/time.h> 53#include <stdarg.h> 54#ifdef MAJOR_IN_MKDEV 55#include <sys/mkdev.h> 56#endif 57#ifdef MAJOR_IN_SYSMACROS 58#include <sys/sysmacros.h> 59#endif 60#if HAVE_SYS_SYSCTL_H 61#include <sys/sysctl.h> 62#endif 63#include <math.h> 64#include <inttypes.h> 65 66#if defined(__FreeBSD__) 67#include <sys/param.h> 68#include <sys/pciio.h> 69#endif 70 71#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) 72 73/* Not all systems have MAP_FAILED defined */ 74#ifndef MAP_FAILED 75#define MAP_FAILED ((void *)-1) 76#endif 77 78#include "xf86drm.h" 79#include "libdrm_macros.h" 80#include "drm_fourcc.h" 81 82#include "util_math.h" 83 84#ifdef __DragonFly__ 85#define DRM_MAJOR 145 86#endif 87 88#ifdef __NetBSD__ 89#undef DRM_MAJOR 90#define DRM_MAJOR 180 91#include <sys/param.h> 92#include <dev/pci/pcireg.h> 93#include <pci.h> 94#endif 95 96#ifdef __OpenBSD__ 97#ifdef __i386__ 98#define DRM_MAJOR 88 99#else 100#define DRM_MAJOR 87 101#endif 102#endif /* __OpenBSD__ */ 103 104#ifndef DRM_MAJOR 105#define DRM_MAJOR 226 /* Linux */ 106#endif 107 108#if defined(__OpenBSD__) || defined(__DragonFly__) 109struct drm_pciinfo { 110 uint16_t domain; 111 uint8_t bus; 112 uint8_t dev; 113 uint8_t func; 114 uint16_t vendor_id; 115 uint16_t device_id; 116 uint16_t subvendor_id; 117 uint16_t subdevice_id; 118 uint8_t revision_id; 119}; 120 121#define DRM_IOCTL_GET_PCIINFO DRM_IOR(0x15, struct drm_pciinfo) 122#endif 123 124#define DRM_MSG_VERBOSITY 3 125 126#define memclear(s) memset(&s, 0, sizeof(s)) 127 128static drmServerInfoPtr drm_server_info; 129 130static bool drmNodeIsDRM(int maj, int min); 131static char *drmGetMinorNameForFD(int fd, int type); 132 133#define DRM_MODIFIER(v, f, f_name) \ 134 .modifier = DRM_FORMAT_MOD_##v ## _ ##f, \ 135 .modifier_name = #f_name 136 137#define DRM_MODIFIER_INVALID(v, f_name) \ 138 .modifier = DRM_FORMAT_MOD_INVALID, .modifier_name = #f_name 139 140#define DRM_MODIFIER_LINEAR(v, f_name) \ 141 .modifier = DRM_FORMAT_MOD_LINEAR, .modifier_name = #f_name 142 143/* Intel is abit special as the format doesn't follow other vendors naming 144 * scheme */ 145#define DRM_MODIFIER_INTEL(f, f_name) \ 146 .modifier = I915_FORMAT_MOD_##f, .modifier_name = #f_name 147 148struct drmFormatModifierInfo { 149 uint64_t modifier; 150 const char *modifier_name; 151}; 152 153struct drmFormatModifierVendorInfo { 154 uint8_t vendor; 155 const char *vendor_name; 156}; 157 158#include "generated_static_table_fourcc.h" 159 160struct drmVendorInfo { 161 uint8_t vendor; 162 char *(*vendor_cb)(uint64_t modifier); 163}; 164 165struct drmFormatVendorModifierInfo { 166 uint64_t modifier; 167 const char *modifier_name; 168}; 169 170static char * 171drmGetFormatModifierNameFromArm(uint64_t modifier); 172 173static char * 174drmGetFormatModifierNameFromNvidia(uint64_t modifier); 175 176static char * 177drmGetFormatModifierNameFromAmd(uint64_t modifier); 178 179static char * 180drmGetFormatModifierNameFromAmlogic(uint64_t modifier); 181 182static const struct drmVendorInfo modifier_format_vendor_table[] = { 183 { DRM_FORMAT_MOD_VENDOR_ARM, drmGetFormatModifierNameFromArm }, 184 { DRM_FORMAT_MOD_VENDOR_NVIDIA, drmGetFormatModifierNameFromNvidia }, 185 { DRM_FORMAT_MOD_VENDOR_AMD, drmGetFormatModifierNameFromAmd }, 186 { DRM_FORMAT_MOD_VENDOR_AMLOGIC, drmGetFormatModifierNameFromAmlogic }, 187}; 188 189#ifndef AFBC_FORMAT_MOD_MODE_VALUE_MASK 190#define AFBC_FORMAT_MOD_MODE_VALUE_MASK 0x000fffffffffffffULL 191#endif 192 193static const struct drmFormatVendorModifierInfo arm_mode_value_table[] = { 194 { AFBC_FORMAT_MOD_YTR, "YTR" }, 195 { AFBC_FORMAT_MOD_SPLIT, "SPLIT" }, 196 { AFBC_FORMAT_MOD_SPARSE, "SPARSE" }, 197 { AFBC_FORMAT_MOD_CBR, "CBR" }, 198 { AFBC_FORMAT_MOD_TILED, "TILED" }, 199 { AFBC_FORMAT_MOD_SC, "SC" }, 200 { AFBC_FORMAT_MOD_DB, "DB" }, 201 { AFBC_FORMAT_MOD_BCH, "BCH" }, 202 { AFBC_FORMAT_MOD_USM, "USM" }, 203}; 204 205static bool is_x_t_amd_gfx9_tile(uint64_t tile) 206{ 207 switch (tile) { 208 case AMD_FMT_MOD_TILE_GFX9_64K_S_X: 209 case AMD_FMT_MOD_TILE_GFX9_64K_D_X: 210 case AMD_FMT_MOD_TILE_GFX9_64K_R_X: 211 return true; 212 } 213 214 return false; 215} 216 217static bool 218drmGetAfbcFormatModifierNameFromArm(uint64_t modifier, FILE *fp) 219{ 220 uint64_t mode_value = modifier & AFBC_FORMAT_MOD_MODE_VALUE_MASK; 221 uint64_t block_size = mode_value & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK; 222 223 const char *block = NULL; 224 const char *mode = NULL; 225 bool did_print_mode = false; 226 227 /* add block, can only have a (single) block */ 228 switch (block_size) { 229 case AFBC_FORMAT_MOD_BLOCK_SIZE_16x16: 230 block = "16x16"; 231 break; 232 case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8: 233 block = "32x8"; 234 break; 235 case AFBC_FORMAT_MOD_BLOCK_SIZE_64x4: 236 block = "64x4"; 237 break; 238 case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8_64x4: 239 block = "32x8_64x4"; 240 break; 241 } 242 243 if (!block) { 244 return false; 245 } 246 247 fprintf(fp, "BLOCK_SIZE=%s,", block); 248 249 /* add mode */ 250 for (unsigned int i = 0; i < ARRAY_SIZE(arm_mode_value_table); i++) { 251 if (arm_mode_value_table[i].modifier & mode_value) { 252 mode = arm_mode_value_table[i].modifier_name; 253 if (!did_print_mode) { 254 fprintf(fp, "MODE=%s", mode); 255 did_print_mode = true; 256 } else { 257 fprintf(fp, "|%s", mode); 258 } 259 } 260 } 261 262 return true; 263} 264 265static bool 266drmGetAfrcFormatModifierNameFromArm(uint64_t modifier, FILE *fp) 267{ 268 bool scan_layout; 269 for (unsigned int i = 0; i < 2; ++i) { 270 uint64_t coding_unit_block = 271 (modifier >> (i * 4)) & AFRC_FORMAT_MOD_CU_SIZE_MASK; 272 const char *coding_unit_size = NULL; 273 274 switch (coding_unit_block) { 275 case AFRC_FORMAT_MOD_CU_SIZE_16: 276 coding_unit_size = "CU_16"; 277 break; 278 case AFRC_FORMAT_MOD_CU_SIZE_24: 279 coding_unit_size = "CU_24"; 280 break; 281 case AFRC_FORMAT_MOD_CU_SIZE_32: 282 coding_unit_size = "CU_32"; 283 break; 284 } 285 286 if (!coding_unit_size) { 287 if (i == 0) { 288 return false; 289 } 290 break; 291 } 292 293 if (i == 0) { 294 fprintf(fp, "P0=%s,", coding_unit_size); 295 } else { 296 fprintf(fp, "P12=%s,", coding_unit_size); 297 } 298 } 299 300 scan_layout = 301 (modifier & AFRC_FORMAT_MOD_LAYOUT_SCAN) == AFRC_FORMAT_MOD_LAYOUT_SCAN; 302 if (scan_layout) { 303 fprintf(fp, "SCAN"); 304 } else { 305 fprintf(fp, "ROT"); 306 } 307 return true; 308} 309 310static char * 311drmGetFormatModifierNameFromArm(uint64_t modifier) 312{ 313 uint64_t type = (modifier >> 52) & 0xf; 314 315 FILE *fp; 316 size_t size = 0; 317 char *modifier_name = NULL; 318 bool result = false; 319 320 fp = open_memstream(&modifier_name, &size); 321 if (!fp) 322 return NULL; 323 324 switch (type) { 325 case DRM_FORMAT_MOD_ARM_TYPE_AFBC: 326 result = drmGetAfbcFormatModifierNameFromArm(modifier, fp); 327 break; 328 case DRM_FORMAT_MOD_ARM_TYPE_AFRC: 329 result = drmGetAfrcFormatModifierNameFromArm(modifier, fp); 330 break; 331 /* misc type is already handled by the static table */ 332 case DRM_FORMAT_MOD_ARM_TYPE_MISC: 333 default: 334 result = false; 335 break; 336 } 337 338 fclose(fp); 339 if (!result) { 340 free(modifier_name); 341 return NULL; 342 } 343 344 return modifier_name; 345} 346 347static char * 348drmGetFormatModifierNameFromNvidia(uint64_t modifier) 349{ 350 uint64_t height, kind, gen, sector, compression; 351 352 height = modifier & 0xf; 353 kind = (modifier >> 12) & 0xff; 354 355 gen = (modifier >> 20) & 0x3; 356 sector = (modifier >> 22) & 0x1; 357 compression = (modifier >> 23) & 0x7; 358 359 /* just in case there could other simpler modifiers, not yet added, avoid 360 * testing against TEGRA_TILE */ 361 if ((modifier & 0x10) == 0x10) { 362 char *mod_nvidia; 363 asprintf(&mod_nvidia, "BLOCK_LINEAR_2D,HEIGHT=%"PRIu64",KIND=%"PRIu64"," 364 "GEN=%"PRIu64",SECTOR=%"PRIu64",COMPRESSION=%"PRIu64"", height, 365 kind, gen, sector, compression); 366 return mod_nvidia; 367 } 368 369 return NULL; 370} 371 372static void 373drmGetFormatModifierNameFromAmdDcc(uint64_t modifier, FILE *fp) 374{ 375 uint64_t dcc_max_compressed_block = 376 AMD_FMT_MOD_GET(DCC_MAX_COMPRESSED_BLOCK, modifier); 377 uint64_t dcc_retile = AMD_FMT_MOD_GET(DCC_RETILE, modifier); 378 379 const char *dcc_max_compressed_block_str = NULL; 380 381 fprintf(fp, ",DCC"); 382 383 if (dcc_retile) 384 fprintf(fp, ",DCC_RETILE"); 385 386 if (!dcc_retile && AMD_FMT_MOD_GET(DCC_PIPE_ALIGN, modifier)) 387 fprintf(fp, ",DCC_PIPE_ALIGN"); 388 389 if (AMD_FMT_MOD_GET(DCC_INDEPENDENT_64B, modifier)) 390 fprintf(fp, ",DCC_INDEPENDENT_64B"); 391 392 if (AMD_FMT_MOD_GET(DCC_INDEPENDENT_128B, modifier)) 393 fprintf(fp, ",DCC_INDEPENDENT_128B"); 394 395 switch (dcc_max_compressed_block) { 396 case AMD_FMT_MOD_DCC_BLOCK_64B: 397 dcc_max_compressed_block_str = "64B"; 398 break; 399 case AMD_FMT_MOD_DCC_BLOCK_128B: 400 dcc_max_compressed_block_str = "128B"; 401 break; 402 case AMD_FMT_MOD_DCC_BLOCK_256B: 403 dcc_max_compressed_block_str = "256B"; 404 break; 405 } 406 407 if (dcc_max_compressed_block_str) 408 fprintf(fp, ",DCC_MAX_COMPRESSED_BLOCK=%s", 409 dcc_max_compressed_block_str); 410 411 if (AMD_FMT_MOD_GET(DCC_CONSTANT_ENCODE, modifier)) 412 fprintf(fp, ",DCC_CONSTANT_ENCODE"); 413} 414 415static void 416drmGetFormatModifierNameFromAmdTile(uint64_t modifier, FILE *fp) 417{ 418 uint64_t pipe_xor_bits, bank_xor_bits, packers, rb; 419 uint64_t pipe, pipe_align, dcc, dcc_retile, tile_version; 420 421 pipe_align = AMD_FMT_MOD_GET(DCC_PIPE_ALIGN, modifier); 422 pipe_xor_bits = AMD_FMT_MOD_GET(PIPE_XOR_BITS, modifier); 423 dcc = AMD_FMT_MOD_GET(DCC, modifier); 424 dcc_retile = AMD_FMT_MOD_GET(DCC_RETILE, modifier); 425 tile_version = AMD_FMT_MOD_GET(TILE_VERSION, modifier); 426 427 fprintf(fp, ",PIPE_XOR_BITS=%"PRIu64, pipe_xor_bits); 428 429 if (tile_version == AMD_FMT_MOD_TILE_VER_GFX9) { 430 bank_xor_bits = AMD_FMT_MOD_GET(BANK_XOR_BITS, modifier); 431 fprintf(fp, ",BANK_XOR_BITS=%"PRIu64, bank_xor_bits); 432 } 433 434 if (tile_version == AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS) { 435 packers = AMD_FMT_MOD_GET(PACKERS, modifier); 436 fprintf(fp, ",PACKERS=%"PRIu64, packers); 437 } 438 439 if (dcc && tile_version == AMD_FMT_MOD_TILE_VER_GFX9) { 440 rb = AMD_FMT_MOD_GET(RB, modifier); 441 fprintf(fp, ",RB=%"PRIu64, rb); 442 } 443 444 if (dcc && tile_version == AMD_FMT_MOD_TILE_VER_GFX9 && 445 (dcc_retile || pipe_align)) { 446 pipe = AMD_FMT_MOD_GET(PIPE, modifier); 447 fprintf(fp, ",PIPE_%"PRIu64, pipe); 448 } 449} 450 451static char * 452drmGetFormatModifierNameFromAmd(uint64_t modifier) 453{ 454 uint64_t tile, tile_version, dcc; 455 FILE *fp; 456 char *mod_amd = NULL; 457 size_t size = 0; 458 459 const char *str_tile = NULL; 460 const char *str_tile_version = NULL; 461 462 tile = AMD_FMT_MOD_GET(TILE, modifier); 463 tile_version = AMD_FMT_MOD_GET(TILE_VERSION, modifier); 464 dcc = AMD_FMT_MOD_GET(DCC, modifier); 465 466 fp = open_memstream(&mod_amd, &size); 467 if (!fp) 468 return NULL; 469 470 /* add tile */ 471 switch (tile_version) { 472 case AMD_FMT_MOD_TILE_VER_GFX9: 473 str_tile_version = "GFX9"; 474 break; 475 case AMD_FMT_MOD_TILE_VER_GFX10: 476 str_tile_version = "GFX10"; 477 break; 478 case AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS: 479 str_tile_version = "GFX10_RBPLUS"; 480 break; 481 } 482 483 if (str_tile_version) { 484 fprintf(fp, "%s", str_tile_version); 485 } else { 486 fclose(fp); 487 free(mod_amd); 488 return NULL; 489 } 490 491 /* add tile str */ 492 switch (tile) { 493 case AMD_FMT_MOD_TILE_GFX9_64K_S: 494 str_tile = "GFX9_64K_S"; 495 break; 496 case AMD_FMT_MOD_TILE_GFX9_64K_D: 497 str_tile = "GFX9_64K_D"; 498 break; 499 case AMD_FMT_MOD_TILE_GFX9_64K_S_X: 500 str_tile = "GFX9_64K_S_X"; 501 break; 502 case AMD_FMT_MOD_TILE_GFX9_64K_D_X: 503 str_tile = "GFX9_64K_D_X"; 504 break; 505 case AMD_FMT_MOD_TILE_GFX9_64K_R_X: 506 str_tile = "GFX9_64K_R_X"; 507 break; 508 } 509 510 if (str_tile) 511 fprintf(fp, ",%s", str_tile); 512 513 if (dcc) 514 drmGetFormatModifierNameFromAmdDcc(modifier, fp); 515 516 if (tile_version >= AMD_FMT_MOD_TILE_VER_GFX9 && is_x_t_amd_gfx9_tile(tile)) 517 drmGetFormatModifierNameFromAmdTile(modifier, fp); 518 519 fclose(fp); 520 return mod_amd; 521} 522 523static char * 524drmGetFormatModifierNameFromAmlogic(uint64_t modifier) 525{ 526 uint64_t layout = modifier & 0xff; 527 uint64_t options = (modifier >> 8) & 0xff; 528 char *mod_amlogic = NULL; 529 530 const char *layout_str; 531 const char *opts_str; 532 533 switch (layout) { 534 case AMLOGIC_FBC_LAYOUT_BASIC: 535 layout_str = "BASIC"; 536 break; 537 case AMLOGIC_FBC_LAYOUT_SCATTER: 538 layout_str = "SCATTER"; 539 break; 540 default: 541 layout_str = "INVALID_LAYOUT"; 542 break; 543 } 544 545 if (options & AMLOGIC_FBC_OPTION_MEM_SAVING) 546 opts_str = "MEM_SAVING"; 547 else 548 opts_str = "0"; 549 550 asprintf(&mod_amlogic, "FBC,LAYOUT=%s,OPTIONS=%s", layout_str, opts_str); 551 return mod_amlogic; 552} 553 554static unsigned log2_int(unsigned x) 555{ 556 unsigned l; 557 558 if (x < 2) { 559 return 0; 560 } 561 for (l = 2; ; l++) { 562 if ((unsigned)(1 << l) > x) { 563 return l - 1; 564 } 565 } 566 return 0; 567} 568 569 570drm_public void drmSetServerInfo(drmServerInfoPtr info) 571{ 572 drm_server_info = info; 573} 574 575/** 576 * Output a message to stderr. 577 * 578 * \param format printf() like format string. 579 * 580 * \internal 581 * This function is a wrapper around vfprintf(). 582 */ 583 584static int DRM_PRINTFLIKE(1, 0) 585drmDebugPrint(const char *format, va_list ap) 586{ 587 return vfprintf(stderr, format, ap); 588} 589 590drm_public void 591drmMsg(const char *format, ...) 592{ 593 va_list ap; 594 const char *env; 595 if (((env = getenv("LIBGL_DEBUG")) && strstr(env, "verbose")) || 596 (drm_server_info && drm_server_info->debug_print)) 597 { 598 va_start(ap, format); 599 if (drm_server_info) { 600 drm_server_info->debug_print(format,ap); 601 } else { 602 drmDebugPrint(format, ap); 603 } 604 va_end(ap); 605 } 606} 607 608static void *drmHashTable = NULL; /* Context switch callbacks */ 609 610drm_public void *drmGetHashTable(void) 611{ 612 return drmHashTable; 613} 614 615drm_public void *drmMalloc(int size) 616{ 617 return calloc(1, size); 618} 619 620drm_public void drmFree(void *pt) 621{ 622 free(pt); 623} 624 625/** 626 * Call ioctl, restarting if it is interrupted 627 */ 628drm_public int 629drmIoctl(int fd, unsigned long request, void *arg) 630{ 631 int ret; 632 633 do { 634 ret = ioctl(fd, request, arg); 635 } while (ret == -1 && (errno == EINTR || errno == EAGAIN)); 636 return ret; 637} 638 639static unsigned long drmGetKeyFromFd(int fd) 640{ 641 stat_t st; 642 643 st.st_rdev = 0; 644 fstat(fd, &st); 645 return st.st_rdev; 646} 647 648drm_public drmHashEntry *drmGetEntry(int fd) 649{ 650 unsigned long key = drmGetKeyFromFd(fd); 651 void *value; 652 drmHashEntry *entry; 653 654 if (!drmHashTable) 655 drmHashTable = drmHashCreate(); 656 657 if (drmHashLookup(drmHashTable, key, &value)) { 658 entry = drmMalloc(sizeof(*entry)); 659 entry->fd = fd; 660 entry->f = NULL; 661 entry->tagTable = drmHashCreate(); 662 drmHashInsert(drmHashTable, key, entry); 663 } else { 664 entry = value; 665 } 666 return entry; 667} 668 669/** 670 * Compare two busid strings 671 * 672 * \param first 673 * \param second 674 * 675 * \return 1 if matched. 676 * 677 * \internal 678 * This function compares two bus ID strings. It understands the older 679 * PCI:b:d:f format and the newer pci:oooo:bb:dd.f format. In the format, o is 680 * domain, b is bus, d is device, f is function. 681 */ 682static int drmMatchBusID(const char *id1, const char *id2, int pci_domain_ok) 683{ 684 /* First, check if the IDs are exactly the same */ 685 if (strcasecmp(id1, id2) == 0) 686 return 1; 687 688 /* Try to match old/new-style PCI bus IDs. */ 689 if (strncasecmp(id1, "pci", 3) == 0) { 690 unsigned int o1, b1, d1, f1; 691 unsigned int o2, b2, d2, f2; 692 int ret; 693 694 ret = sscanf(id1, "pci:%04x:%02x:%02x.%u", &o1, &b1, &d1, &f1); 695 if (ret != 4) { 696 o1 = 0; 697 ret = sscanf(id1, "PCI:%u:%u:%u", &b1, &d1, &f1); 698 if (ret != 3) 699 return 0; 700 } 701 702 ret = sscanf(id2, "pci:%04x:%02x:%02x.%u", &o2, &b2, &d2, &f2); 703 if (ret != 4) { 704 o2 = 0; 705 ret = sscanf(id2, "PCI:%u:%u:%u", &b2, &d2, &f2); 706 if (ret != 3) 707 return 0; 708 } 709 710 /* If domains aren't properly supported by the kernel interface, 711 * just ignore them, which sucks less than picking a totally random 712 * card with "open by name" 713 */ 714 if (!pci_domain_ok) 715 o1 = o2 = 0; 716 717 if ((o1 != o2) || (b1 != b2) || (d1 != d2) || (f1 != f2)) 718 return 0; 719 else 720 return 1; 721 } 722 return 0; 723} 724 725/** 726 * Handles error checking for chown call. 727 * 728 * \param path to file. 729 * \param id of the new owner. 730 * \param id of the new group. 731 * 732 * \return zero if success or -1 if failure. 733 * 734 * \internal 735 * Checks for failure. If failure was caused by signal call chown again. 736 * If any other failure happened then it will output error message using 737 * drmMsg() call. 738 */ 739#if !UDEV 740static int chown_check_return(const char *path, uid_t owner, gid_t group) 741{ 742 int rv; 743 744 do { 745 rv = chown(path, owner, group); 746 } while (rv != 0 && errno == EINTR); 747 748 if (rv == 0) 749 return 0; 750 751 drmMsg("Failed to change owner or group for file %s! %d: %s\n", 752 path, errno, strerror(errno)); 753 return -1; 754} 755#endif 756 757static const char *drmGetDeviceName(int type) 758{ 759 switch (type) { 760 case DRM_NODE_PRIMARY: 761 return DRM_DEV_NAME; 762 case DRM_NODE_CONTROL: 763 return DRM_CONTROL_DEV_NAME; 764 case DRM_NODE_RENDER: 765 return DRM_RENDER_DEV_NAME; 766 } 767 return NULL; 768} 769 770/** 771 * Open the DRM device, creating it if necessary. 772 * 773 * \param dev major and minor numbers of the device. 774 * \param minor minor number of the device. 775 * 776 * \return a file descriptor on success, or a negative value on error. 777 * 778 * \internal 779 * Assembles the device name from \p minor and opens it, creating the device 780 * special file node with the major and minor numbers specified by \p dev and 781 * parent directory if necessary and was called by root. 782 */ 783static int drmOpenDevice(dev_t dev, int minor, int type) 784{ 785 stat_t st; 786 const char *dev_name = drmGetDeviceName(type); 787 char buf[DRM_NODE_NAME_MAX]; 788 int fd; 789 mode_t devmode = DRM_DEV_MODE, serv_mode; 790 gid_t serv_group; 791#if !UDEV 792 int isroot = !geteuid(); 793 uid_t user = DRM_DEV_UID; 794 gid_t group = DRM_DEV_GID; 795#endif 796 797 if (!dev_name) 798 return -EINVAL; 799 800 sprintf(buf, dev_name, DRM_DIR_NAME, minor); 801 drmMsg("drmOpenDevice: node name is %s\n", buf); 802 803 if (drm_server_info && drm_server_info->get_perms) { 804 drm_server_info->get_perms(&serv_group, &serv_mode); 805 devmode = serv_mode ? serv_mode : DRM_DEV_MODE; 806 devmode &= ~(S_IXUSR|S_IXGRP|S_IXOTH); 807 } 808 809#if !UDEV 810 if (stat(DRM_DIR_NAME, &st)) { 811 if (!isroot) 812 return DRM_ERR_NOT_ROOT; 813 mkdir(DRM_DIR_NAME, DRM_DEV_DIRMODE); 814 chown_check_return(DRM_DIR_NAME, 0, 0); /* root:root */ 815 chmod(DRM_DIR_NAME, DRM_DEV_DIRMODE); 816 } 817 818 /* Check if the device node exists and create it if necessary. */ 819 if (stat(buf, &st)) { 820 if (!isroot) 821 return DRM_ERR_NOT_ROOT; 822 remove(buf); 823 mknod(buf, S_IFCHR | devmode, dev); 824 } 825 826 if (drm_server_info && drm_server_info->get_perms) { 827 group = ((int)serv_group >= 0) ? serv_group : DRM_DEV_GID; 828 chown_check_return(buf, user, group); 829 chmod(buf, devmode); 830 } 831#else 832 /* if we modprobed then wait for udev */ 833 { 834 int udev_count = 0; 835wait_for_udev: 836 if (stat(DRM_DIR_NAME, &st)) { 837 usleep(20); 838 udev_count++; 839 840 if (udev_count == 50) 841 return -1; 842 goto wait_for_udev; 843 } 844 845 if (stat(buf, &st)) { 846 usleep(20); 847 udev_count++; 848 849 if (udev_count == 50) 850 return -1; 851 goto wait_for_udev; 852 } 853 } 854#endif 855 856 fd = open(buf, O_RDWR | O_CLOEXEC); 857 drmMsg("drmOpenDevice: open result is %d, (%s)\n", 858 fd, fd < 0 ? strerror(errno) : "OK"); 859 if (fd >= 0) 860 return fd; 861 862#if !UDEV 863 /* Check if the device node is not what we expect it to be, and recreate it 864 * and try again if so. 865 */ 866 if (st.st_rdev != dev) { 867 if (!isroot) 868 return DRM_ERR_NOT_ROOT; 869 remove(buf); 870 mknod(buf, S_IFCHR | devmode, dev); 871 if (drm_server_info && drm_server_info->get_perms) { 872 chown_check_return(buf, user, group); 873 chmod(buf, devmode); 874 } 875 } 876 fd = open(buf, O_RDWR | O_CLOEXEC); 877 drmMsg("drmOpenDevice: open result is %d, (%s)\n", 878 fd, fd < 0 ? strerror(errno) : "OK"); 879 if (fd >= 0) 880 return fd; 881 882 drmMsg("drmOpenDevice: Open failed\n"); 883 remove(buf); 884#endif 885 return -errno; 886} 887 888 889/** 890 * Open the DRM device 891 * 892 * \param minor device minor number. 893 * \param create allow to create the device if set. 894 * 895 * \return a file descriptor on success, or a negative value on error. 896 * 897 * \internal 898 * Calls drmOpenDevice() if \p create is set, otherwise assembles the device 899 * name from \p minor and opens it. 900 */ 901static int drmOpenMinor(int minor, int create, int type) 902{ 903 int fd; 904 char buf[DRM_NODE_NAME_MAX]; 905 const char *dev_name = drmGetDeviceName(type); 906 907 if (create) 908 return drmOpenDevice(makedev(DRM_MAJOR, minor), minor, type); 909 910 if (!dev_name) 911 return -EINVAL; 912 913 sprintf(buf, dev_name, DRM_DIR_NAME, minor); 914 if ((fd = open(buf, O_RDWR | O_CLOEXEC)) >= 0) 915 return fd; 916 return -errno; 917} 918 919 920/** 921 * Determine whether the DRM kernel driver has been loaded. 922 * 923 * \return 1 if the DRM driver is loaded, 0 otherwise. 924 * 925 * \internal 926 * Determine the presence of the kernel driver by attempting to open the 0 927 * minor and get version information. For backward compatibility with older 928 * Linux implementations, /proc/dri is also checked. 929 */ 930drm_public int drmAvailable(void) 931{ 932 drmVersionPtr version; 933 int retval = 0; 934 int fd; 935 936 if ((fd = drmOpenMinor(0, 1, DRM_NODE_PRIMARY)) < 0) { 937#ifdef __linux__ 938 /* Try proc for backward Linux compatibility */ 939 if (!access("/proc/dri/0", R_OK)) 940 return 1; 941#endif 942 return 0; 943 } 944 945 if ((version = drmGetVersion(fd))) { 946 retval = 1; 947 drmFreeVersion(version); 948 } 949 close(fd); 950 951 return retval; 952} 953 954static int drmGetMinorBase(int type) 955{ 956 switch (type) { 957 case DRM_NODE_PRIMARY: 958 return 0; 959 case DRM_NODE_CONTROL: 960 return 64; 961 case DRM_NODE_RENDER: 962 return 128; 963 default: 964 return -1; 965 }; 966} 967 968static int drmGetMinorType(int major, int minor) 969{ 970#ifdef __FreeBSD__ 971 char name[SPECNAMELEN]; 972 int id; 973 974 if (!devname_r(makedev(major, minor), S_IFCHR, name, sizeof(name))) 975 return -1; 976 977 if (sscanf(name, "drm/%d", &id) != 1) { 978 // If not in /dev/drm/ we have the type in the name 979 if (sscanf(name, "dri/card%d\n", &id) >= 1) 980 return DRM_NODE_PRIMARY; 981 else if (sscanf(name, "dri/control%d\n", &id) >= 1) 982 return DRM_NODE_CONTROL; 983 else if (sscanf(name, "dri/renderD%d\n", &id) >= 1) 984 return DRM_NODE_RENDER; 985 return -1; 986 } 987 988 minor = id; 989#endif 990 int type = minor >> 6; 991 992 if (minor < 0) 993 return -1; 994 995 switch (type) { 996 case DRM_NODE_PRIMARY: 997 case DRM_NODE_CONTROL: 998 case DRM_NODE_RENDER: 999 return type; 1000 default: 1001 return -1; 1002 } 1003} 1004 1005static const char *drmGetMinorName(int type) 1006{ 1007 switch (type) { 1008 case DRM_NODE_PRIMARY: 1009 return DRM_PRIMARY_MINOR_NAME; 1010 case DRM_NODE_CONTROL: 1011 return DRM_CONTROL_MINOR_NAME; 1012 case DRM_NODE_RENDER: 1013 return DRM_RENDER_MINOR_NAME; 1014 default: 1015 return NULL; 1016 } 1017} 1018 1019/** 1020 * Open the device by bus ID. 1021 * 1022 * \param busid bus ID. 1023 * \param type device node type. 1024 * 1025 * \return a file descriptor on success, or a negative value on error. 1026 * 1027 * \internal 1028 * This function attempts to open every possible minor (up to DRM_MAX_MINOR), 1029 * comparing the device bus ID with the one supplied. 1030 * 1031 * \sa drmOpenMinor() and drmGetBusid(). 1032 */ 1033static int drmOpenByBusid(const char *busid, int type) 1034{ 1035 int i, pci_domain_ok = 1; 1036 int fd; 1037 const char *buf; 1038 drmSetVersion sv; 1039 int base = drmGetMinorBase(type); 1040 1041 if (base < 0) 1042 return -1; 1043 1044 drmMsg("drmOpenByBusid: Searching for BusID %s\n", busid); 1045 for (i = base; i < base + DRM_MAX_MINOR; i++) { 1046 fd = drmOpenMinor(i, 1, type); 1047 drmMsg("drmOpenByBusid: drmOpenMinor returns %d\n", fd); 1048 if (fd >= 0) { 1049 /* We need to try for 1.4 first for proper PCI domain support 1050 * and if that fails, we know the kernel is busted 1051 */ 1052 sv.drm_di_major = 1; 1053 sv.drm_di_minor = 4; 1054 sv.drm_dd_major = -1; /* Don't care */ 1055 sv.drm_dd_minor = -1; /* Don't care */ 1056 if (drmSetInterfaceVersion(fd, &sv)) { 1057#ifndef __alpha__ 1058 pci_domain_ok = 0; 1059#endif 1060 sv.drm_di_major = 1; 1061 sv.drm_di_minor = 1; 1062 sv.drm_dd_major = -1; /* Don't care */ 1063 sv.drm_dd_minor = -1; /* Don't care */ 1064 drmMsg("drmOpenByBusid: Interface 1.4 failed, trying 1.1\n"); 1065 drmSetInterfaceVersion(fd, &sv); 1066 } 1067 buf = drmGetBusid(fd); 1068 drmMsg("drmOpenByBusid: drmGetBusid reports %s\n", buf); 1069 if (buf && drmMatchBusID(buf, busid, pci_domain_ok)) { 1070 drmFreeBusid(buf); 1071 return fd; 1072 } 1073 if (buf) 1074 drmFreeBusid(buf); 1075 close(fd); 1076 } 1077 } 1078 return -1; 1079} 1080 1081 1082/** 1083 * Open the device by name. 1084 * 1085 * \param name driver name. 1086 * \param type the device node type. 1087 * 1088 * \return a file descriptor on success, or a negative value on error. 1089 * 1090 * \internal 1091 * This function opens the first minor number that matches the driver name and 1092 * isn't already in use. If it's in use it then it will already have a bus ID 1093 * assigned. 1094 * 1095 * \sa drmOpenMinor(), drmGetVersion() and drmGetBusid(). 1096 */ 1097static int drmOpenByName(const char *name, int type) 1098{ 1099 int i; 1100 int fd; 1101 drmVersionPtr version; 1102 char * id; 1103 int base = drmGetMinorBase(type); 1104 1105 if (base < 0) 1106 return -1; 1107 1108 /* 1109 * Open the first minor number that matches the driver name and isn't 1110 * already in use. If it's in use it will have a busid assigned already. 1111 */ 1112 for (i = base; i < base + DRM_MAX_MINOR; i++) { 1113 if ((fd = drmOpenMinor(i, 1, type)) >= 0) { 1114 if ((version = drmGetVersion(fd))) { 1115 if (!strcmp(version->name, name)) { 1116 drmFreeVersion(version); 1117 id = drmGetBusid(fd); 1118 drmMsg("drmGetBusid returned '%s'\n", id ? id : "NULL"); 1119 if (!id || !*id) { 1120 if (id) 1121 drmFreeBusid(id); 1122 return fd; 1123 } else { 1124 drmFreeBusid(id); 1125 } 1126 } else { 1127 drmFreeVersion(version); 1128 } 1129 } 1130 close(fd); 1131 } 1132 } 1133 1134#ifdef __linux__ 1135 /* Backward-compatibility /proc support */ 1136 for (i = 0; i < 8; i++) { 1137 char proc_name[64], buf[512]; 1138 char *driver, *pt, *devstring; 1139 int retcode; 1140 1141 sprintf(proc_name, "/proc/dri/%d/name", i); 1142 if ((fd = open(proc_name, O_RDONLY)) >= 0) { 1143 retcode = read(fd, buf, sizeof(buf)-1); 1144 close(fd); 1145 if (retcode) { 1146 buf[retcode-1] = '\0'; 1147 for (driver = pt = buf; *pt && *pt != ' '; ++pt) 1148 ; 1149 if (*pt) { /* Device is next */ 1150 *pt = '\0'; 1151 if (!strcmp(driver, name)) { /* Match */ 1152 for (devstring = ++pt; *pt && *pt != ' '; ++pt) 1153 ; 1154 if (*pt) { /* Found busid */ 1155 return drmOpenByBusid(++pt, type); 1156 } else { /* No busid */ 1157 return drmOpenDevice(strtol(devstring, NULL, 0),i, type); 1158 } 1159 } 1160 } 1161 } 1162 } 1163 } 1164#endif 1165 1166 return -1; 1167} 1168 1169 1170/** 1171 * Open the DRM device. 1172 * 1173 * Looks up the specified name and bus ID, and opens the device found. The 1174 * entry in /dev/dri is created if necessary and if called by root. 1175 * 1176 * \param name driver name. Not referenced if bus ID is supplied. 1177 * \param busid bus ID. Zero if not known. 1178 * 1179 * \return a file descriptor on success, or a negative value on error. 1180 * 1181 * \internal 1182 * It calls drmOpenByBusid() if \p busid is specified or drmOpenByName() 1183 * otherwise. 1184 */ 1185drm_public int drmOpen(const char *name, const char *busid) 1186{ 1187 return drmOpenWithType(name, busid, DRM_NODE_PRIMARY); 1188} 1189 1190/** 1191 * Open the DRM device with specified type. 1192 * 1193 * Looks up the specified name and bus ID, and opens the device found. The 1194 * entry in /dev/dri is created if necessary and if called by root. 1195 * 1196 * \param name driver name. Not referenced if bus ID is supplied. 1197 * \param busid bus ID. Zero if not known. 1198 * \param type the device node type to open, PRIMARY, CONTROL or RENDER 1199 * 1200 * \return a file descriptor on success, or a negative value on error. 1201 * 1202 * \internal 1203 * It calls drmOpenByBusid() if \p busid is specified or drmOpenByName() 1204 * otherwise. 1205 */ 1206drm_public int drmOpenWithType(const char *name, const char *busid, int type) 1207{ 1208 if (name != NULL && drm_server_info && 1209 drm_server_info->load_module && !drmAvailable()) { 1210 /* try to load the kernel module */ 1211 if (!drm_server_info->load_module(name)) { 1212 drmMsg("[drm] failed to load kernel module \"%s\"\n", name); 1213 return -1; 1214 } 1215 } 1216 1217 if (busid) { 1218 int fd = drmOpenByBusid(busid, type); 1219 if (fd >= 0) 1220 return fd; 1221 } 1222 1223 if (name) 1224 return drmOpenByName(name, type); 1225 1226 return -1; 1227} 1228 1229drm_public int drmOpenControl(int minor) 1230{ 1231 return drmOpenMinor(minor, 0, DRM_NODE_CONTROL); 1232} 1233 1234drm_public int drmOpenRender(int minor) 1235{ 1236 return drmOpenMinor(minor, 0, DRM_NODE_RENDER); 1237} 1238 1239/** 1240 * Free the version information returned by drmGetVersion(). 1241 * 1242 * \param v pointer to the version information. 1243 * 1244 * \internal 1245 * It frees the memory pointed by \p %v as well as all the non-null strings 1246 * pointers in it. 1247 */ 1248drm_public void drmFreeVersion(drmVersionPtr v) 1249{ 1250 if (!v) 1251 return; 1252 drmFree(v->name); 1253 drmFree(v->date); 1254 drmFree(v->desc); 1255 drmFree(v); 1256} 1257 1258 1259/** 1260 * Free the non-public version information returned by the kernel. 1261 * 1262 * \param v pointer to the version information. 1263 * 1264 * \internal 1265 * Used by drmGetVersion() to free the memory pointed by \p %v as well as all 1266 * the non-null strings pointers in it. 1267 */ 1268static void drmFreeKernelVersion(drm_version_t *v) 1269{ 1270 if (!v) 1271 return; 1272 drmFree(v->name); 1273 drmFree(v->date); 1274 drmFree(v->desc); 1275 drmFree(v); 1276} 1277 1278 1279/** 1280 * Copy version information. 1281 * 1282 * \param d destination pointer. 1283 * \param s source pointer. 1284 * 1285 * \internal 1286 * Used by drmGetVersion() to translate the information returned by the ioctl 1287 * interface in a private structure into the public structure counterpart. 1288 */ 1289static void drmCopyVersion(drmVersionPtr d, const drm_version_t *s) 1290{ 1291 d->version_major = s->version_major; 1292 d->version_minor = s->version_minor; 1293 d->version_patchlevel = s->version_patchlevel; 1294 d->name_len = s->name_len; 1295 d->name = strdup(s->name); 1296 d->date_len = s->date_len; 1297 d->date = strdup(s->date); 1298 d->desc_len = s->desc_len; 1299 d->desc = strdup(s->desc); 1300} 1301 1302 1303/** 1304 * Query the driver version information. 1305 * 1306 * \param fd file descriptor. 1307 * 1308 * \return pointer to a drmVersion structure which should be freed with 1309 * drmFreeVersion(). 1310 * 1311 * \note Similar information is available via /proc/dri. 1312 * 1313 * \internal 1314 * It gets the version information via successive DRM_IOCTL_VERSION ioctls, 1315 * first with zeros to get the string lengths, and then the actually strings. 1316 * It also null-terminates them since they might not be already. 1317 */ 1318drm_public drmVersionPtr drmGetVersion(int fd) 1319{ 1320 drmVersionPtr retval; 1321 drm_version_t *version = drmMalloc(sizeof(*version)); 1322 1323 if (drmIoctl(fd, DRM_IOCTL_VERSION, version)) { 1324 drmFreeKernelVersion(version); 1325 return NULL; 1326 } 1327 1328 if (version->name_len) 1329 version->name = drmMalloc(version->name_len + 1); 1330 if (version->date_len) 1331 version->date = drmMalloc(version->date_len + 1); 1332 if (version->desc_len) 1333 version->desc = drmMalloc(version->desc_len + 1); 1334 1335 if (drmIoctl(fd, DRM_IOCTL_VERSION, version)) { 1336 drmMsg("DRM_IOCTL_VERSION: %s\n", strerror(errno)); 1337 drmFreeKernelVersion(version); 1338 return NULL; 1339 } 1340 1341 /* The results might not be null-terminated strings, so terminate them. */ 1342 if (version->name_len) version->name[version->name_len] = '\0'; 1343 if (version->date_len) version->date[version->date_len] = '\0'; 1344 if (version->desc_len) version->desc[version->desc_len] = '\0'; 1345 1346 retval = drmMalloc(sizeof(*retval)); 1347 drmCopyVersion(retval, version); 1348 drmFreeKernelVersion(version); 1349 return retval; 1350} 1351 1352 1353/** 1354 * Get version information for the DRM user space library. 1355 * 1356 * This version number is driver independent. 1357 * 1358 * \param fd file descriptor. 1359 * 1360 * \return version information. 1361 * 1362 * \internal 1363 * This function allocates and fills a drm_version structure with a hard coded 1364 * version number. 1365 */ 1366drm_public drmVersionPtr drmGetLibVersion(int fd) 1367{ 1368 drm_version_t *version = drmMalloc(sizeof(*version)); 1369 1370 /* Version history: 1371 * NOTE THIS MUST NOT GO ABOVE VERSION 1.X due to drivers needing it 1372 * revision 1.0.x = original DRM interface with no drmGetLibVersion 1373 * entry point and many drm<Device> extensions 1374 * revision 1.1.x = added drmCommand entry points for device extensions 1375 * added drmGetLibVersion to identify libdrm.a version 1376 * revision 1.2.x = added drmSetInterfaceVersion 1377 * modified drmOpen to handle both busid and name 1378 * revision 1.3.x = added server + memory manager 1379 */ 1380 version->version_major = 1; 1381 version->version_minor = 3; 1382 version->version_patchlevel = 0; 1383 1384 return (drmVersionPtr)version; 1385} 1386 1387drm_public int drmGetCap(int fd, uint64_t capability, uint64_t *value) 1388{ 1389 struct drm_get_cap cap; 1390 int ret; 1391 1392 memclear(cap); 1393 cap.capability = capability; 1394 1395 ret = drmIoctl(fd, DRM_IOCTL_GET_CAP, &cap); 1396 if (ret) 1397 return ret; 1398 1399 *value = cap.value; 1400 return 0; 1401} 1402 1403drm_public int drmSetClientCap(int fd, uint64_t capability, uint64_t value) 1404{ 1405 struct drm_set_client_cap cap; 1406 1407 memclear(cap); 1408 cap.capability = capability; 1409 cap.value = value; 1410 1411 return drmIoctl(fd, DRM_IOCTL_SET_CLIENT_CAP, &cap); 1412} 1413 1414/** 1415 * Free the bus ID information. 1416 * 1417 * \param busid bus ID information string as given by drmGetBusid(). 1418 * 1419 * \internal 1420 * This function is just frees the memory pointed by \p busid. 1421 */ 1422drm_public void drmFreeBusid(const char *busid) 1423{ 1424 drmFree((void *)busid); 1425} 1426 1427 1428/** 1429 * Get the bus ID of the device. 1430 * 1431 * \param fd file descriptor. 1432 * 1433 * \return bus ID string. 1434 * 1435 * \internal 1436 * This function gets the bus ID via successive DRM_IOCTL_GET_UNIQUE ioctls to 1437 * get the string length and data, passing the arguments in a drm_unique 1438 * structure. 1439 */ 1440drm_public char *drmGetBusid(int fd) 1441{ 1442 drm_unique_t u; 1443 1444 memclear(u); 1445 1446 if (drmIoctl(fd, DRM_IOCTL_GET_UNIQUE, &u)) 1447 return NULL; 1448 u.unique = drmMalloc(u.unique_len + 1); 1449 if (drmIoctl(fd, DRM_IOCTL_GET_UNIQUE, &u)) { 1450 drmFree(u.unique); 1451 return NULL; 1452 } 1453 u.unique[u.unique_len] = '\0'; 1454 1455 return u.unique; 1456} 1457 1458 1459/** 1460 * Set the bus ID of the device. 1461 * 1462 * \param fd file descriptor. 1463 * \param busid bus ID string. 1464 * 1465 * \return zero on success, negative on failure. 1466 * 1467 * \internal 1468 * This function is a wrapper around the DRM_IOCTL_SET_UNIQUE ioctl, passing 1469 * the arguments in a drm_unique structure. 1470 */ 1471drm_public int drmSetBusid(int fd, const char *busid) 1472{ 1473 drm_unique_t u; 1474 1475 memclear(u); 1476 u.unique = (char *)busid; 1477 u.unique_len = strlen(busid); 1478 1479 if (drmIoctl(fd, DRM_IOCTL_SET_UNIQUE, &u)) { 1480 return -errno; 1481 } 1482 return 0; 1483} 1484 1485drm_public int drmGetMagic(int fd, drm_magic_t * magic) 1486{ 1487 drm_auth_t auth; 1488 1489 memclear(auth); 1490 1491 *magic = 0; 1492 if (drmIoctl(fd, DRM_IOCTL_GET_MAGIC, &auth)) 1493 return -errno; 1494 *magic = auth.magic; 1495 return 0; 1496} 1497 1498drm_public int drmAuthMagic(int fd, drm_magic_t magic) 1499{ 1500 drm_auth_t auth; 1501 1502 memclear(auth); 1503 auth.magic = magic; 1504 if (drmIoctl(fd, DRM_IOCTL_AUTH_MAGIC, &auth)) 1505 return -errno; 1506 return 0; 1507} 1508 1509/** 1510 * Specifies a range of memory that is available for mapping by a 1511 * non-root process. 1512 * 1513 * \param fd file descriptor. 1514 * \param offset usually the physical address. The actual meaning depends of 1515 * the \p type parameter. See below. 1516 * \param size of the memory in bytes. 1517 * \param type type of the memory to be mapped. 1518 * \param flags combination of several flags to modify the function actions. 1519 * \param handle will be set to a value that may be used as the offset 1520 * parameter for mmap(). 1521 * 1522 * \return zero on success or a negative value on error. 1523 * 1524 * \par Mapping the frame buffer 1525 * For the frame buffer 1526 * - \p offset will be the physical address of the start of the frame buffer, 1527 * - \p size will be the size of the frame buffer in bytes, and 1528 * - \p type will be DRM_FRAME_BUFFER. 1529 * 1530 * \par 1531 * The area mapped will be uncached. If MTRR support is available in the 1532 * kernel, the frame buffer area will be set to write combining. 1533 * 1534 * \par Mapping the MMIO register area 1535 * For the MMIO register area, 1536 * - \p offset will be the physical address of the start of the register area, 1537 * - \p size will be the size of the register area bytes, and 1538 * - \p type will be DRM_REGISTERS. 1539 * \par 1540 * The area mapped will be uncached. 1541 * 1542 * \par Mapping the SAREA 1543 * For the SAREA, 1544 * - \p offset will be ignored and should be set to zero, 1545 * - \p size will be the desired size of the SAREA in bytes, 1546 * - \p type will be DRM_SHM. 1547 * 1548 * \par 1549 * A shared memory area of the requested size will be created and locked in 1550 * kernel memory. This area may be mapped into client-space by using the handle 1551 * returned. 1552 * 1553 * \note May only be called by root. 1554 * 1555 * \internal 1556 * This function is a wrapper around the DRM_IOCTL_ADD_MAP ioctl, passing 1557 * the arguments in a drm_map structure. 1558 */ 1559drm_public int drmAddMap(int fd, drm_handle_t offset, drmSize size, drmMapType type, 1560 drmMapFlags flags, drm_handle_t *handle) 1561{ 1562 drm_map_t map; 1563 1564 memclear(map); 1565 map.offset = offset; 1566 map.size = size; 1567 map.type = (enum drm_map_type)type; 1568 map.flags = (enum drm_map_flags)flags; 1569 if (drmIoctl(fd, DRM_IOCTL_ADD_MAP, &map)) 1570 return -errno; 1571 if (handle) 1572 *handle = (drm_handle_t)(uintptr_t)map.handle; 1573 return 0; 1574} 1575 1576drm_public int drmRmMap(int fd, drm_handle_t handle) 1577{ 1578 drm_map_t map; 1579 1580 memclear(map); 1581 map.handle = (void *)(uintptr_t)handle; 1582 1583 if(drmIoctl(fd, DRM_IOCTL_RM_MAP, &map)) 1584 return -errno; 1585 return 0; 1586} 1587 1588/** 1589 * Make buffers available for DMA transfers. 1590 * 1591 * \param fd file descriptor. 1592 * \param count number of buffers. 1593 * \param size size of each buffer. 1594 * \param flags buffer allocation flags. 1595 * \param agp_offset offset in the AGP aperture 1596 * 1597 * \return number of buffers allocated, negative on error. 1598 * 1599 * \internal 1600 * This function is a wrapper around DRM_IOCTL_ADD_BUFS ioctl. 1601 * 1602 * \sa drm_buf_desc. 1603 */ 1604drm_public int drmAddBufs(int fd, int count, int size, drmBufDescFlags flags, 1605 int agp_offset) 1606{ 1607 drm_buf_desc_t request; 1608 1609 memclear(request); 1610 request.count = count; 1611 request.size = size; 1612 request.flags = (int)flags; 1613 request.agp_start = agp_offset; 1614 1615 if (drmIoctl(fd, DRM_IOCTL_ADD_BUFS, &request)) 1616 return -errno; 1617 return request.count; 1618} 1619 1620drm_public int drmMarkBufs(int fd, double low, double high) 1621{ 1622 drm_buf_info_t info; 1623 int i; 1624 1625 memclear(info); 1626 1627 if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info)) 1628 return -EINVAL; 1629 1630 if (!info.count) 1631 return -EINVAL; 1632 1633 if (!(info.list = drmMalloc(info.count * sizeof(*info.list)))) 1634 return -ENOMEM; 1635 1636 if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info)) { 1637 int retval = -errno; 1638 drmFree(info.list); 1639 return retval; 1640 } 1641 1642 for (i = 0; i < info.count; i++) { 1643 info.list[i].low_mark = low * info.list[i].count; 1644 info.list[i].high_mark = high * info.list[i].count; 1645 if (drmIoctl(fd, DRM_IOCTL_MARK_BUFS, &info.list[i])) { 1646 int retval = -errno; 1647 drmFree(info.list); 1648 return retval; 1649 } 1650 } 1651 drmFree(info.list); 1652 1653 return 0; 1654} 1655 1656/** 1657 * Free buffers. 1658 * 1659 * \param fd file descriptor. 1660 * \param count number of buffers to free. 1661 * \param list list of buffers to be freed. 1662 * 1663 * \return zero on success, or a negative value on failure. 1664 * 1665 * \note This function is primarily used for debugging. 1666 * 1667 * \internal 1668 * This function is a wrapper around the DRM_IOCTL_FREE_BUFS ioctl, passing 1669 * the arguments in a drm_buf_free structure. 1670 */ 1671drm_public int drmFreeBufs(int fd, int count, int *list) 1672{ 1673 drm_buf_free_t request; 1674 1675 memclear(request); 1676 request.count = count; 1677 request.list = list; 1678 if (drmIoctl(fd, DRM_IOCTL_FREE_BUFS, &request)) 1679 return -errno; 1680 return 0; 1681} 1682 1683 1684/** 1685 * Close the device. 1686 * 1687 * \param fd file descriptor. 1688 * 1689 * \internal 1690 * This function closes the file descriptor. 1691 */ 1692drm_public int drmClose(int fd) 1693{ 1694 unsigned long key = drmGetKeyFromFd(fd); 1695 drmHashEntry *entry = drmGetEntry(fd); 1696 1697 drmHashDestroy(entry->tagTable); 1698 entry->fd = 0; 1699 entry->f = NULL; 1700 entry->tagTable = NULL; 1701 1702 drmHashDelete(drmHashTable, key); 1703 drmFree(entry); 1704 1705 return close(fd); 1706} 1707 1708 1709/** 1710 * Map a region of memory. 1711 * 1712 * \param fd file descriptor. 1713 * \param handle handle returned by drmAddMap(). 1714 * \param size size in bytes. Must match the size used by drmAddMap(). 1715 * \param address will contain the user-space virtual address where the mapping 1716 * begins. 1717 * 1718 * \return zero on success, or a negative value on failure. 1719 * 1720 * \internal 1721 * This function is a wrapper for mmap(). 1722 */ 1723drm_public int drmMap(int fd, drm_handle_t handle, drmSize size, 1724 drmAddressPtr address) 1725{ 1726 static unsigned long pagesize_mask = 0; 1727 1728 if (fd < 0) 1729 return -EINVAL; 1730 1731 if (!pagesize_mask) 1732 pagesize_mask = getpagesize() - 1; 1733 1734 size = (size + pagesize_mask) & ~pagesize_mask; 1735 1736 *address = drm_mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, handle); 1737 if (*address == MAP_FAILED) 1738 return -errno; 1739 return 0; 1740} 1741 1742 1743/** 1744 * Unmap mappings obtained with drmMap(). 1745 * 1746 * \param address address as given by drmMap(). 1747 * \param size size in bytes. Must match the size used by drmMap(). 1748 * 1749 * \return zero on success, or a negative value on failure. 1750 * 1751 * \internal 1752 * This function is a wrapper for munmap(). 1753 */ 1754drm_public int drmUnmap(drmAddress address, drmSize size) 1755{ 1756 return drm_munmap(address, size); 1757} 1758 1759drm_public drmBufInfoPtr drmGetBufInfo(int fd) 1760{ 1761 drm_buf_info_t info; 1762 drmBufInfoPtr retval; 1763 int i; 1764 1765 memclear(info); 1766 1767 if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info)) 1768 return NULL; 1769 1770 if (info.count) { 1771 if (!(info.list = drmMalloc(info.count * sizeof(*info.list)))) 1772 return NULL; 1773 1774 if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info)) { 1775 drmFree(info.list); 1776 return NULL; 1777 } 1778 1779 retval = drmMalloc(sizeof(*retval)); 1780 retval->count = info.count; 1781 if (!(retval->list = drmMalloc(info.count * sizeof(*retval->list)))) { 1782 drmFree(retval); 1783 drmFree(info.list); 1784 return NULL; 1785 } 1786 1787 for (i = 0; i < info.count; i++) { 1788 retval->list[i].count = info.list[i].count; 1789 retval->list[i].size = info.list[i].size; 1790 retval->list[i].low_mark = info.list[i].low_mark; 1791 retval->list[i].high_mark = info.list[i].high_mark; 1792 } 1793 drmFree(info.list); 1794 return retval; 1795 } 1796 return NULL; 1797} 1798 1799/** 1800 * Map all DMA buffers into client-virtual space. 1801 * 1802 * \param fd file descriptor. 1803 * 1804 * \return a pointer to a ::drmBufMap structure. 1805 * 1806 * \note The client may not use these buffers until obtaining buffer indices 1807 * with drmDMA(). 1808 * 1809 * \internal 1810 * This function calls the DRM_IOCTL_MAP_BUFS ioctl and copies the returned 1811 * information about the buffers in a drm_buf_map structure into the 1812 * client-visible data structures. 1813 */ 1814drm_public drmBufMapPtr drmMapBufs(int fd) 1815{ 1816 drm_buf_map_t bufs; 1817 drmBufMapPtr retval; 1818 int i; 1819 1820 memclear(bufs); 1821 if (drmIoctl(fd, DRM_IOCTL_MAP_BUFS, &bufs)) 1822 return NULL; 1823 1824 if (!bufs.count) 1825 return NULL; 1826 1827 if (!(bufs.list = drmMalloc(bufs.count * sizeof(*bufs.list)))) 1828 return NULL; 1829 1830 if (drmIoctl(fd, DRM_IOCTL_MAP_BUFS, &bufs)) { 1831 drmFree(bufs.list); 1832 return NULL; 1833 } 1834 1835 retval = drmMalloc(sizeof(*retval)); 1836 retval->count = bufs.count; 1837 retval->list = drmMalloc(bufs.count * sizeof(*retval->list)); 1838 for (i = 0; i < bufs.count; i++) { 1839 retval->list[i].idx = bufs.list[i].idx; 1840 retval->list[i].total = bufs.list[i].total; 1841 retval->list[i].used = 0; 1842 retval->list[i].address = bufs.list[i].address; 1843 } 1844 1845 drmFree(bufs.list); 1846 return retval; 1847} 1848 1849 1850/** 1851 * Unmap buffers allocated with drmMapBufs(). 1852 * 1853 * \return zero on success, or negative value on failure. 1854 * 1855 * \internal 1856 * Calls munmap() for every buffer stored in \p bufs and frees the 1857 * memory allocated by drmMapBufs(). 1858 */ 1859drm_public int drmUnmapBufs(drmBufMapPtr bufs) 1860{ 1861 int i; 1862 1863 for (i = 0; i < bufs->count; i++) { 1864 drm_munmap(bufs->list[i].address, bufs->list[i].total); 1865 } 1866 1867 drmFree(bufs->list); 1868 drmFree(bufs); 1869 return 0; 1870} 1871 1872 1873#define DRM_DMA_RETRY 16 1874 1875/** 1876 * Reserve DMA buffers. 1877 * 1878 * \param fd file descriptor. 1879 * \param request 1880 * 1881 * \return zero on success, or a negative value on failure. 1882 * 1883 * \internal 1884 * Assemble the arguments into a drm_dma structure and keeps issuing the 1885 * DRM_IOCTL_DMA ioctl until success or until maximum number of retries. 1886 */ 1887drm_public int drmDMA(int fd, drmDMAReqPtr request) 1888{ 1889 drm_dma_t dma; 1890 int ret, i = 0; 1891 1892 dma.context = request->context; 1893 dma.send_count = request->send_count; 1894 dma.send_indices = request->send_list; 1895 dma.send_sizes = request->send_sizes; 1896 dma.flags = (enum drm_dma_flags)request->flags; 1897 dma.request_count = request->request_count; 1898 dma.request_size = request->request_size; 1899 dma.request_indices = request->request_list; 1900 dma.request_sizes = request->request_sizes; 1901 dma.granted_count = 0; 1902 1903 do { 1904 ret = ioctl( fd, DRM_IOCTL_DMA, &dma ); 1905 } while ( ret && errno == EAGAIN && i++ < DRM_DMA_RETRY ); 1906 1907 if ( ret == 0 ) { 1908 request->granted_count = dma.granted_count; 1909 return 0; 1910 } else { 1911 return -errno; 1912 } 1913} 1914 1915 1916/** 1917 * Obtain heavyweight hardware lock. 1918 * 1919 * \param fd file descriptor. 1920 * \param context context. 1921 * \param flags flags that determine the state of the hardware when the function 1922 * returns. 1923 * 1924 * \return always zero. 1925 * 1926 * \internal 1927 * This function translates the arguments into a drm_lock structure and issue 1928 * the DRM_IOCTL_LOCK ioctl until the lock is successfully acquired. 1929 */ 1930drm_public int drmGetLock(int fd, drm_context_t context, drmLockFlags flags) 1931{ 1932 drm_lock_t lock; 1933 1934 memclear(lock); 1935 lock.context = context; 1936 lock.flags = 0; 1937 if (flags & DRM_LOCK_READY) lock.flags |= _DRM_LOCK_READY; 1938 if (flags & DRM_LOCK_QUIESCENT) lock.flags |= _DRM_LOCK_QUIESCENT; 1939 if (flags & DRM_LOCK_FLUSH) lock.flags |= _DRM_LOCK_FLUSH; 1940 if (flags & DRM_LOCK_FLUSH_ALL) lock.flags |= _DRM_LOCK_FLUSH_ALL; 1941 if (flags & DRM_HALT_ALL_QUEUES) lock.flags |= _DRM_HALT_ALL_QUEUES; 1942 if (flags & DRM_HALT_CUR_QUEUES) lock.flags |= _DRM_HALT_CUR_QUEUES; 1943 1944 while (drmIoctl(fd, DRM_IOCTL_LOCK, &lock)) 1945 ; 1946 return 0; 1947} 1948 1949/** 1950 * Release the hardware lock. 1951 * 1952 * \param fd file descriptor. 1953 * \param context context. 1954 * 1955 * \return zero on success, or a negative value on failure. 1956 * 1957 * \internal 1958 * This function is a wrapper around the DRM_IOCTL_UNLOCK ioctl, passing the 1959 * argument in a drm_lock structure. 1960 */ 1961drm_public int drmUnlock(int fd, drm_context_t context) 1962{ 1963 drm_lock_t lock; 1964 1965 memclear(lock); 1966 lock.context = context; 1967 return drmIoctl(fd, DRM_IOCTL_UNLOCK, &lock); 1968} 1969 1970drm_public drm_context_t *drmGetReservedContextList(int fd, int *count) 1971{ 1972 drm_ctx_res_t res; 1973 drm_ctx_t *list; 1974 drm_context_t * retval; 1975 int i; 1976 1977 memclear(res); 1978 if (drmIoctl(fd, DRM_IOCTL_RES_CTX, &res)) 1979 return NULL; 1980 1981 if (!res.count) 1982 return NULL; 1983 1984 if (!(list = drmMalloc(res.count * sizeof(*list)))) 1985 return NULL; 1986 if (!(retval = drmMalloc(res.count * sizeof(*retval)))) 1987 goto err_free_list; 1988 1989 res.contexts = list; 1990 if (drmIoctl(fd, DRM_IOCTL_RES_CTX, &res)) 1991 goto err_free_context; 1992 1993 for (i = 0; i < res.count; i++) 1994 retval[i] = list[i].handle; 1995 drmFree(list); 1996 1997 *count = res.count; 1998 return retval; 1999 2000err_free_list: 2001 drmFree(list); 2002err_free_context: 2003 drmFree(retval); 2004 return NULL; 2005} 2006 2007drm_public void drmFreeReservedContextList(drm_context_t *pt) 2008{ 2009 drmFree(pt); 2010} 2011 2012/** 2013 * Create context. 2014 * 2015 * Used by the X server during GLXContext initialization. This causes 2016 * per-context kernel-level resources to be allocated. 2017 * 2018 * \param fd file descriptor. 2019 * \param handle is set on success. To be used by the client when requesting DMA 2020 * dispatch with drmDMA(). 2021 * 2022 * \return zero on success, or a negative value on failure. 2023 * 2024 * \note May only be called by root. 2025 * 2026 * \internal 2027 * This function is a wrapper around the DRM_IOCTL_ADD_CTX ioctl, passing the 2028 * argument in a drm_ctx structure. 2029 */ 2030drm_public int drmCreateContext(int fd, drm_context_t *handle) 2031{ 2032 drm_ctx_t ctx; 2033 2034 memclear(ctx); 2035 if (drmIoctl(fd, DRM_IOCTL_ADD_CTX, &ctx)) 2036 return -errno; 2037 *handle = ctx.handle; 2038 return 0; 2039} 2040 2041drm_public int drmSwitchToContext(int fd, drm_context_t context) 2042{ 2043 drm_ctx_t ctx; 2044 2045 memclear(ctx); 2046 ctx.handle = context; 2047 if (drmIoctl(fd, DRM_IOCTL_SWITCH_CTX, &ctx)) 2048 return -errno; 2049 return 0; 2050} 2051 2052drm_public int drmSetContextFlags(int fd, drm_context_t context, 2053 drm_context_tFlags flags) 2054{ 2055 drm_ctx_t ctx; 2056 2057 /* 2058 * Context preserving means that no context switches are done between DMA 2059 * buffers from one context and the next. This is suitable for use in the 2060 * X server (which promises to maintain hardware context), or in the 2061 * client-side library when buffers are swapped on behalf of two threads. 2062 */ 2063 memclear(ctx); 2064 ctx.handle = context; 2065 if (flags & DRM_CONTEXT_PRESERVED) 2066 ctx.flags |= _DRM_CONTEXT_PRESERVED; 2067 if (flags & DRM_CONTEXT_2DONLY) 2068 ctx.flags |= _DRM_CONTEXT_2DONLY; 2069 if (drmIoctl(fd, DRM_IOCTL_MOD_CTX, &ctx)) 2070 return -errno; 2071 return 0; 2072} 2073 2074drm_public int drmGetContextFlags(int fd, drm_context_t context, 2075 drm_context_tFlagsPtr flags) 2076{ 2077 drm_ctx_t ctx; 2078 2079 memclear(ctx); 2080 ctx.handle = context; 2081 if (drmIoctl(fd, DRM_IOCTL_GET_CTX, &ctx)) 2082 return -errno; 2083 *flags = 0; 2084 if (ctx.flags & _DRM_CONTEXT_PRESERVED) 2085 *flags |= DRM_CONTEXT_PRESERVED; 2086 if (ctx.flags & _DRM_CONTEXT_2DONLY) 2087 *flags |= DRM_CONTEXT_2DONLY; 2088 return 0; 2089} 2090 2091/** 2092 * Destroy context. 2093 * 2094 * Free any kernel-level resources allocated with drmCreateContext() associated 2095 * with the context. 2096 * 2097 * \param fd file descriptor. 2098 * \param handle handle given by drmCreateContext(). 2099 * 2100 * \return zero on success, or a negative value on failure. 2101 * 2102 * \note May only be called by root. 2103 * 2104 * \internal 2105 * This function is a wrapper around the DRM_IOCTL_RM_CTX ioctl, passing the 2106 * argument in a drm_ctx structure. 2107 */ 2108drm_public int drmDestroyContext(int fd, drm_context_t handle) 2109{ 2110 drm_ctx_t ctx; 2111 2112 memclear(ctx); 2113 ctx.handle = handle; 2114 if (drmIoctl(fd, DRM_IOCTL_RM_CTX, &ctx)) 2115 return -errno; 2116 return 0; 2117} 2118 2119drm_public int drmCreateDrawable(int fd, drm_drawable_t *handle) 2120{ 2121 drm_draw_t draw; 2122 2123 memclear(draw); 2124 if (drmIoctl(fd, DRM_IOCTL_ADD_DRAW, &draw)) 2125 return -errno; 2126 *handle = draw.handle; 2127 return 0; 2128} 2129 2130drm_public int drmDestroyDrawable(int fd, drm_drawable_t handle) 2131{ 2132 drm_draw_t draw; 2133 2134 memclear(draw); 2135 draw.handle = handle; 2136 if (drmIoctl(fd, DRM_IOCTL_RM_DRAW, &draw)) 2137 return -errno; 2138 return 0; 2139} 2140 2141drm_public int drmUpdateDrawableInfo(int fd, drm_drawable_t handle, 2142 drm_drawable_info_type_t type, 2143 unsigned int num, void *data) 2144{ 2145 drm_update_draw_t update; 2146 2147 memclear(update); 2148 update.handle = handle; 2149 update.type = type; 2150 update.num = num; 2151 update.data = (unsigned long long)(unsigned long)data; 2152 2153 if (drmIoctl(fd, DRM_IOCTL_UPDATE_DRAW, &update)) 2154 return -errno; 2155 2156 return 0; 2157} 2158 2159drm_public int drmCrtcGetSequence(int fd, uint32_t crtcId, uint64_t *sequence, 2160 uint64_t *ns) 2161{ 2162 struct drm_crtc_get_sequence get_seq; 2163 int ret; 2164 2165 memclear(get_seq); 2166 get_seq.crtc_id = crtcId; 2167 ret = drmIoctl(fd, DRM_IOCTL_CRTC_GET_SEQUENCE, &get_seq); 2168 if (ret) 2169 return ret; 2170 2171 if (sequence) 2172 *sequence = get_seq.sequence; 2173 if (ns) 2174 *ns = get_seq.sequence_ns; 2175 return 0; 2176} 2177 2178drm_public int drmCrtcQueueSequence(int fd, uint32_t crtcId, uint32_t flags, 2179 uint64_t sequence, 2180 uint64_t *sequence_queued, 2181 uint64_t user_data) 2182{ 2183 struct drm_crtc_queue_sequence queue_seq; 2184 int ret; 2185 2186 memclear(queue_seq); 2187 queue_seq.crtc_id = crtcId; 2188 queue_seq.flags = flags; 2189 queue_seq.sequence = sequence; 2190 queue_seq.user_data = user_data; 2191 2192 ret = drmIoctl(fd, DRM_IOCTL_CRTC_QUEUE_SEQUENCE, &queue_seq); 2193 if (ret == 0 && sequence_queued) 2194 *sequence_queued = queue_seq.sequence; 2195 2196 return ret; 2197} 2198 2199/** 2200 * Acquire the AGP device. 2201 * 2202 * Must be called before any of the other AGP related calls. 2203 * 2204 * \param fd file descriptor. 2205 * 2206 * \return zero on success, or a negative value on failure. 2207 * 2208 * \internal 2209 * This function is a wrapper around the DRM_IOCTL_AGP_ACQUIRE ioctl. 2210 */ 2211drm_public int drmAgpAcquire(int fd) 2212{ 2213 if (drmIoctl(fd, DRM_IOCTL_AGP_ACQUIRE, NULL)) 2214 return -errno; 2215 return 0; 2216} 2217 2218 2219/** 2220 * Release the AGP device. 2221 * 2222 * \param fd file descriptor. 2223 * 2224 * \return zero on success, or a negative value on failure. 2225 * 2226 * \internal 2227 * This function is a wrapper around the DRM_IOCTL_AGP_RELEASE ioctl. 2228 */ 2229drm_public int drmAgpRelease(int fd) 2230{ 2231 if (drmIoctl(fd, DRM_IOCTL_AGP_RELEASE, NULL)) 2232 return -errno; 2233 return 0; 2234} 2235 2236 2237/** 2238 * Set the AGP mode. 2239 * 2240 * \param fd file descriptor. 2241 * \param mode AGP mode. 2242 * 2243 * \return zero on success, or a negative value on failure. 2244 * 2245 * \internal 2246 * This function is a wrapper around the DRM_IOCTL_AGP_ENABLE ioctl, passing the 2247 * argument in a drm_agp_mode structure. 2248 */ 2249drm_public int drmAgpEnable(int fd, unsigned long mode) 2250{ 2251 drm_agp_mode_t m; 2252 2253 memclear(m); 2254 m.mode = mode; 2255 if (drmIoctl(fd, DRM_IOCTL_AGP_ENABLE, &m)) 2256 return -errno; 2257 return 0; 2258} 2259 2260 2261/** 2262 * Allocate a chunk of AGP memory. 2263 * 2264 * \param fd file descriptor. 2265 * \param size requested memory size in bytes. Will be rounded to page boundary. 2266 * \param type type of memory to allocate. 2267 * \param address if not zero, will be set to the physical address of the 2268 * allocated memory. 2269 * \param handle on success will be set to a handle of the allocated memory. 2270 * 2271 * \return zero on success, or a negative value on failure. 2272 * 2273 * \internal 2274 * This function is a wrapper around the DRM_IOCTL_AGP_ALLOC ioctl, passing the 2275 * arguments in a drm_agp_buffer structure. 2276 */ 2277drm_public int drmAgpAlloc(int fd, unsigned long size, unsigned long type, 2278 unsigned long *address, drm_handle_t *handle) 2279{ 2280 drm_agp_buffer_t b; 2281 2282 memclear(b); 2283 *handle = DRM_AGP_NO_HANDLE; 2284 b.size = size; 2285 b.type = type; 2286 if (drmIoctl(fd, DRM_IOCTL_AGP_ALLOC, &b)) 2287 return -errno; 2288 if (address != 0UL) 2289 *address = b.physical; 2290 *handle = b.handle; 2291 return 0; 2292} 2293 2294 2295/** 2296 * Free a chunk of AGP memory. 2297 * 2298 * \param fd file descriptor. 2299 * \param handle handle to the allocated memory, as given by drmAgpAllocate(). 2300 * 2301 * \return zero on success, or a negative value on failure. 2302 * 2303 * \internal 2304 * This function is a wrapper around the DRM_IOCTL_AGP_FREE ioctl, passing the 2305 * argument in a drm_agp_buffer structure. 2306 */ 2307drm_public int drmAgpFree(int fd, drm_handle_t handle) 2308{ 2309 drm_agp_buffer_t b; 2310 2311 memclear(b); 2312 b.handle = handle; 2313 if (drmIoctl(fd, DRM_IOCTL_AGP_FREE, &b)) 2314 return -errno; 2315 return 0; 2316} 2317 2318 2319/** 2320 * Bind a chunk of AGP memory. 2321 * 2322 * \param fd file descriptor. 2323 * \param handle handle to the allocated memory, as given by drmAgpAllocate(). 2324 * \param offset offset in bytes. It will round to page boundary. 2325 * 2326 * \return zero on success, or a negative value on failure. 2327 * 2328 * \internal 2329 * This function is a wrapper around the DRM_IOCTL_AGP_BIND ioctl, passing the 2330 * argument in a drm_agp_binding structure. 2331 */ 2332drm_public int drmAgpBind(int fd, drm_handle_t handle, unsigned long offset) 2333{ 2334 drm_agp_binding_t b; 2335 2336 memclear(b); 2337 b.handle = handle; 2338 b.offset = offset; 2339 if (drmIoctl(fd, DRM_IOCTL_AGP_BIND, &b)) 2340 return -errno; 2341 return 0; 2342} 2343 2344 2345/** 2346 * Unbind a chunk of AGP memory. 2347 * 2348 * \param fd file descriptor. 2349 * \param handle handle to the allocated memory, as given by drmAgpAllocate(). 2350 * 2351 * \return zero on success, or a negative value on failure. 2352 * 2353 * \internal 2354 * This function is a wrapper around the DRM_IOCTL_AGP_UNBIND ioctl, passing 2355 * the argument in a drm_agp_binding structure. 2356 */ 2357drm_public int drmAgpUnbind(int fd, drm_handle_t handle) 2358{ 2359 drm_agp_binding_t b; 2360 2361 memclear(b); 2362 b.handle = handle; 2363 if (drmIoctl(fd, DRM_IOCTL_AGP_UNBIND, &b)) 2364 return -errno; 2365 return 0; 2366} 2367 2368 2369/** 2370 * Get AGP driver major version number. 2371 * 2372 * \param fd file descriptor. 2373 * 2374 * \return major version number on success, or a negative value on failure.. 2375 * 2376 * \internal 2377 * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the 2378 * necessary information in a drm_agp_info structure. 2379 */ 2380drm_public int drmAgpVersionMajor(int fd) 2381{ 2382 drm_agp_info_t i; 2383 2384 memclear(i); 2385 2386 if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i)) 2387 return -errno; 2388 return i.agp_version_major; 2389} 2390 2391 2392/** 2393 * Get AGP driver minor version number. 2394 * 2395 * \param fd file descriptor. 2396 * 2397 * \return minor version number on success, or a negative value on failure. 2398 * 2399 * \internal 2400 * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the 2401 * necessary information in a drm_agp_info structure. 2402 */ 2403drm_public int drmAgpVersionMinor(int fd) 2404{ 2405 drm_agp_info_t i; 2406 2407 memclear(i); 2408 2409 if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i)) 2410 return -errno; 2411 return i.agp_version_minor; 2412} 2413 2414 2415/** 2416 * Get AGP mode. 2417 * 2418 * \param fd file descriptor. 2419 * 2420 * \return mode on success, or zero on failure. 2421 * 2422 * \internal 2423 * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the 2424 * necessary information in a drm_agp_info structure. 2425 */ 2426drm_public unsigned long drmAgpGetMode(int fd) 2427{ 2428 drm_agp_info_t i; 2429 2430 memclear(i); 2431 2432 if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i)) 2433 return 0; 2434 return i.mode; 2435} 2436 2437 2438/** 2439 * Get AGP aperture base. 2440 * 2441 * \param fd file descriptor. 2442 * 2443 * \return aperture base on success, zero on failure. 2444 * 2445 * \internal 2446 * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the 2447 * necessary information in a drm_agp_info structure. 2448 */ 2449drm_public unsigned long drmAgpBase(int fd) 2450{ 2451 drm_agp_info_t i; 2452 2453 memclear(i); 2454 2455 if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i)) 2456 return 0; 2457 return i.aperture_base; 2458} 2459 2460 2461/** 2462 * Get AGP aperture size. 2463 * 2464 * \param fd file descriptor. 2465 * 2466 * \return aperture size on success, zero on failure. 2467 * 2468 * \internal 2469 * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the 2470 * necessary information in a drm_agp_info structure. 2471 */ 2472drm_public unsigned long drmAgpSize(int fd) 2473{ 2474 drm_agp_info_t i; 2475 2476 memclear(i); 2477 2478 if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i)) 2479 return 0; 2480 return i.aperture_size; 2481} 2482 2483 2484/** 2485 * Get used AGP memory. 2486 * 2487 * \param fd file descriptor. 2488 * 2489 * \return memory used on success, or zero on failure. 2490 * 2491 * \internal 2492 * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the 2493 * necessary information in a drm_agp_info structure. 2494 */ 2495drm_public unsigned long drmAgpMemoryUsed(int fd) 2496{ 2497 drm_agp_info_t i; 2498 2499 memclear(i); 2500 2501 if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i)) 2502 return 0; 2503 return i.memory_used; 2504} 2505 2506 2507/** 2508 * Get available AGP memory. 2509 * 2510 * \param fd file descriptor. 2511 * 2512 * \return memory available on success, or zero on failure. 2513 * 2514 * \internal 2515 * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the 2516 * necessary information in a drm_agp_info structure. 2517 */ 2518drm_public unsigned long drmAgpMemoryAvail(int fd) 2519{ 2520 drm_agp_info_t i; 2521 2522 memclear(i); 2523 2524 if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i)) 2525 return 0; 2526 return i.memory_allowed; 2527} 2528 2529 2530/** 2531 * Get hardware vendor ID. 2532 * 2533 * \param fd file descriptor. 2534 * 2535 * \return vendor ID on success, or zero on failure. 2536 * 2537 * \internal 2538 * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the 2539 * necessary information in a drm_agp_info structure. 2540 */ 2541drm_public unsigned int drmAgpVendorId(int fd) 2542{ 2543 drm_agp_info_t i; 2544 2545 memclear(i); 2546 2547 if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i)) 2548 return 0; 2549 return i.id_vendor; 2550} 2551 2552 2553/** 2554 * Get hardware device ID. 2555 * 2556 * \param fd file descriptor. 2557 * 2558 * \return zero on success, or zero on failure. 2559 * 2560 * \internal 2561 * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the 2562 * necessary information in a drm_agp_info structure. 2563 */ 2564drm_public unsigned int drmAgpDeviceId(int fd) 2565{ 2566 drm_agp_info_t i; 2567 2568 memclear(i); 2569 2570 if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i)) 2571 return 0; 2572 return i.id_device; 2573} 2574 2575drm_public int drmScatterGatherAlloc(int fd, unsigned long size, 2576 drm_handle_t *handle) 2577{ 2578 drm_scatter_gather_t sg; 2579 2580 memclear(sg); 2581 2582 *handle = 0; 2583 sg.size = size; 2584 if (drmIoctl(fd, DRM_IOCTL_SG_ALLOC, &sg)) 2585 return -errno; 2586 *handle = sg.handle; 2587 return 0; 2588} 2589 2590drm_public int drmScatterGatherFree(int fd, drm_handle_t handle) 2591{ 2592 drm_scatter_gather_t sg; 2593 2594 memclear(sg); 2595 sg.handle = handle; 2596 if (drmIoctl(fd, DRM_IOCTL_SG_FREE, &sg)) 2597 return -errno; 2598 return 0; 2599} 2600 2601/** 2602 * Wait for VBLANK. 2603 * 2604 * \param fd file descriptor. 2605 * \param vbl pointer to a drmVBlank structure. 2606 * 2607 * \return zero on success, or a negative value on failure. 2608 * 2609 * \internal 2610 * This function is a wrapper around the DRM_IOCTL_WAIT_VBLANK ioctl. 2611 */ 2612drm_public int drmWaitVBlank(int fd, drmVBlankPtr vbl) 2613{ 2614 struct timespec timeout, cur; 2615 int ret; 2616 2617 ret = clock_gettime(CLOCK_MONOTONIC, &timeout); 2618 if (ret < 0) { 2619 fprintf(stderr, "clock_gettime failed: %s\n", strerror(errno)); 2620 goto out; 2621 } 2622 timeout.tv_sec++; 2623 2624 do { 2625 ret = ioctl(fd, DRM_IOCTL_WAIT_VBLANK, vbl); 2626 vbl->request.type &= ~DRM_VBLANK_RELATIVE; 2627 if (ret && errno == EINTR) { 2628 clock_gettime(CLOCK_MONOTONIC, &cur); 2629 /* Timeout after 1s */ 2630 if (cur.tv_sec > timeout.tv_sec + 1 || 2631 (cur.tv_sec == timeout.tv_sec && cur.tv_nsec >= 2632 timeout.tv_nsec)) { 2633 errno = EBUSY; 2634 ret = -1; 2635 break; 2636 } 2637 } 2638 } while (ret && errno == EINTR); 2639 2640out: 2641 return ret; 2642} 2643 2644drm_public int drmError(int err, const char *label) 2645{ 2646 switch (err) { 2647 case DRM_ERR_NO_DEVICE: 2648 fprintf(stderr, "%s: no device\n", label); 2649 break; 2650 case DRM_ERR_NO_ACCESS: 2651 fprintf(stderr, "%s: no access\n", label); 2652 break; 2653 case DRM_ERR_NOT_ROOT: 2654 fprintf(stderr, "%s: not root\n", label); 2655 break; 2656 case DRM_ERR_INVALID: 2657 fprintf(stderr, "%s: invalid args\n", label); 2658 break; 2659 default: 2660 if (err < 0) 2661 err = -err; 2662 fprintf( stderr, "%s: error %d (%s)\n", label, err, strerror(err) ); 2663 break; 2664 } 2665 2666 return 1; 2667} 2668 2669/** 2670 * Install IRQ handler. 2671 * 2672 * \param fd file descriptor. 2673 * \param irq IRQ number. 2674 * 2675 * \return zero on success, or a negative value on failure. 2676 * 2677 * \internal 2678 * This function is a wrapper around the DRM_IOCTL_CONTROL ioctl, passing the 2679 * argument in a drm_control structure. 2680 */ 2681drm_public int drmCtlInstHandler(int fd, int irq) 2682{ 2683 drm_control_t ctl; 2684 2685 memclear(ctl); 2686 ctl.func = DRM_INST_HANDLER; 2687 ctl.irq = irq; 2688 if (drmIoctl(fd, DRM_IOCTL_CONTROL, &ctl)) 2689 return -errno; 2690 return 0; 2691} 2692 2693 2694/** 2695 * Uninstall IRQ handler. 2696 * 2697 * \param fd file descriptor. 2698 * 2699 * \return zero on success, or a negative value on failure. 2700 * 2701 * \internal 2702 * This function is a wrapper around the DRM_IOCTL_CONTROL ioctl, passing the 2703 * argument in a drm_control structure. 2704 */ 2705drm_public int drmCtlUninstHandler(int fd) 2706{ 2707 drm_control_t ctl; 2708 2709 memclear(ctl); 2710 ctl.func = DRM_UNINST_HANDLER; 2711 ctl.irq = 0; 2712 if (drmIoctl(fd, DRM_IOCTL_CONTROL, &ctl)) 2713 return -errno; 2714 return 0; 2715} 2716 2717drm_public int drmFinish(int fd, int context, drmLockFlags flags) 2718{ 2719 drm_lock_t lock; 2720 2721 memclear(lock); 2722 lock.context = context; 2723 if (flags & DRM_LOCK_READY) lock.flags |= _DRM_LOCK_READY; 2724 if (flags & DRM_LOCK_QUIESCENT) lock.flags |= _DRM_LOCK_QUIESCENT; 2725 if (flags & DRM_LOCK_FLUSH) lock.flags |= _DRM_LOCK_FLUSH; 2726 if (flags & DRM_LOCK_FLUSH_ALL) lock.flags |= _DRM_LOCK_FLUSH_ALL; 2727 if (flags & DRM_HALT_ALL_QUEUES) lock.flags |= _DRM_HALT_ALL_QUEUES; 2728 if (flags & DRM_HALT_CUR_QUEUES) lock.flags |= _DRM_HALT_CUR_QUEUES; 2729 if (drmIoctl(fd, DRM_IOCTL_FINISH, &lock)) 2730 return -errno; 2731 return 0; 2732} 2733 2734/** 2735 * Get IRQ from bus ID. 2736 * 2737 * \param fd file descriptor. 2738 * \param busnum bus number. 2739 * \param devnum device number. 2740 * \param funcnum function number. 2741 * 2742 * \return IRQ number on success, or a negative value on failure. 2743 * 2744 * \internal 2745 * This function is a wrapper around the DRM_IOCTL_IRQ_BUSID ioctl, passing the 2746 * arguments in a drm_irq_busid structure. 2747 */ 2748drm_public int drmGetInterruptFromBusID(int fd, int busnum, int devnum, 2749 int funcnum) 2750{ 2751 drm_irq_busid_t p; 2752 2753 memclear(p); 2754 p.busnum = busnum; 2755 p.devnum = devnum; 2756 p.funcnum = funcnum; 2757 if (drmIoctl(fd, DRM_IOCTL_IRQ_BUSID, &p)) 2758 return -errno; 2759 return p.irq; 2760} 2761 2762drm_public int drmAddContextTag(int fd, drm_context_t context, void *tag) 2763{ 2764 drmHashEntry *entry = drmGetEntry(fd); 2765 2766 if (drmHashInsert(entry->tagTable, context, tag)) { 2767 drmHashDelete(entry->tagTable, context); 2768 drmHashInsert(entry->tagTable, context, tag); 2769 } 2770 return 0; 2771} 2772 2773drm_public int drmDelContextTag(int fd, drm_context_t context) 2774{ 2775 drmHashEntry *entry = drmGetEntry(fd); 2776 2777 return drmHashDelete(entry->tagTable, context); 2778} 2779 2780drm_public void *drmGetContextTag(int fd, drm_context_t context) 2781{ 2782 drmHashEntry *entry = drmGetEntry(fd); 2783 void *value; 2784 2785 if (drmHashLookup(entry->tagTable, context, &value)) 2786 return NULL; 2787 2788 return value; 2789} 2790 2791drm_public int drmAddContextPrivateMapping(int fd, drm_context_t ctx_id, 2792 drm_handle_t handle) 2793{ 2794 drm_ctx_priv_map_t map; 2795 2796 memclear(map); 2797 map.ctx_id = ctx_id; 2798 map.handle = (void *)(uintptr_t)handle; 2799 2800 if (drmIoctl(fd, DRM_IOCTL_SET_SAREA_CTX, &map)) 2801 return -errno; 2802 return 0; 2803} 2804 2805drm_public int drmGetContextPrivateMapping(int fd, drm_context_t ctx_id, 2806 drm_handle_t *handle) 2807{ 2808 drm_ctx_priv_map_t map; 2809 2810 memclear(map); 2811 map.ctx_id = ctx_id; 2812 2813 if (drmIoctl(fd, DRM_IOCTL_GET_SAREA_CTX, &map)) 2814 return -errno; 2815 if (handle) 2816 *handle = (drm_handle_t)(uintptr_t)map.handle; 2817 2818 return 0; 2819} 2820 2821drm_public int drmGetMap(int fd, int idx, drm_handle_t *offset, drmSize *size, 2822 drmMapType *type, drmMapFlags *flags, 2823 drm_handle_t *handle, int *mtrr) 2824{ 2825 drm_map_t map; 2826 2827 memclear(map); 2828 map.offset = idx; 2829 if (drmIoctl(fd, DRM_IOCTL_GET_MAP, &map)) 2830 return -errno; 2831 *offset = map.offset; 2832 *size = map.size; 2833 *type = (drmMapType)map.type; 2834 *flags = (drmMapFlags)map.flags; 2835 *handle = (unsigned long)map.handle; 2836 *mtrr = map.mtrr; 2837 return 0; 2838} 2839 2840drm_public int drmGetClient(int fd, int idx, int *auth, int *pid, int *uid, 2841 unsigned long *magic, unsigned long *iocs) 2842{ 2843 drm_client_t client; 2844 2845 memclear(client); 2846 client.idx = idx; 2847 if (drmIoctl(fd, DRM_IOCTL_GET_CLIENT, &client)) 2848 return -errno; 2849 *auth = client.auth; 2850 *pid = client.pid; 2851 *uid = client.uid; 2852 *magic = client.magic; 2853 *iocs = client.iocs; 2854 return 0; 2855} 2856 2857drm_public int drmGetStats(int fd, drmStatsT *stats) 2858{ 2859 drm_stats_t s; 2860 unsigned i; 2861 2862 memclear(s); 2863 if (drmIoctl(fd, DRM_IOCTL_GET_STATS, &s)) 2864 return -errno; 2865 2866 stats->count = 0; 2867 memset(stats, 0, sizeof(*stats)); 2868 if (s.count > sizeof(stats->data)/sizeof(stats->data[0])) 2869 return -1; 2870 2871#define SET_VALUE \ 2872 stats->data[i].long_format = "%-20.20s"; \ 2873 stats->data[i].rate_format = "%8.8s"; \ 2874 stats->data[i].isvalue = 1; \ 2875 stats->data[i].verbose = 0 2876 2877#define SET_COUNT \ 2878 stats->data[i].long_format = "%-20.20s"; \ 2879 stats->data[i].rate_format = "%5.5s"; \ 2880 stats->data[i].isvalue = 0; \ 2881 stats->data[i].mult_names = "kgm"; \ 2882 stats->data[i].mult = 1000; \ 2883 stats->data[i].verbose = 0 2884 2885#define SET_BYTE \ 2886 stats->data[i].long_format = "%-20.20s"; \ 2887 stats->data[i].rate_format = "%5.5s"; \ 2888 stats->data[i].isvalue = 0; \ 2889 stats->data[i].mult_names = "KGM"; \ 2890 stats->data[i].mult = 1024; \ 2891 stats->data[i].verbose = 0 2892 2893 2894 stats->count = s.count; 2895 for (i = 0; i < s.count; i++) { 2896 stats->data[i].value = s.data[i].value; 2897 switch (s.data[i].type) { 2898 case _DRM_STAT_LOCK: 2899 stats->data[i].long_name = "Lock"; 2900 stats->data[i].rate_name = "Lock"; 2901 SET_VALUE; 2902 break; 2903 case _DRM_STAT_OPENS: 2904 stats->data[i].long_name = "Opens"; 2905 stats->data[i].rate_name = "O"; 2906 SET_COUNT; 2907 stats->data[i].verbose = 1; 2908 break; 2909 case _DRM_STAT_CLOSES: 2910 stats->data[i].long_name = "Closes"; 2911 stats->data[i].rate_name = "Lock"; 2912 SET_COUNT; 2913 stats->data[i].verbose = 1; 2914 break; 2915 case _DRM_STAT_IOCTLS: 2916 stats->data[i].long_name = "Ioctls"; 2917 stats->data[i].rate_name = "Ioc/s"; 2918 SET_COUNT; 2919 break; 2920 case _DRM_STAT_LOCKS: 2921 stats->data[i].long_name = "Locks"; 2922 stats->data[i].rate_name = "Lck/s"; 2923 SET_COUNT; 2924 break; 2925 case _DRM_STAT_UNLOCKS: 2926 stats->data[i].long_name = "Unlocks"; 2927 stats->data[i].rate_name = "Unl/s"; 2928 SET_COUNT; 2929 break; 2930 case _DRM_STAT_IRQ: 2931 stats->data[i].long_name = "IRQs"; 2932 stats->data[i].rate_name = "IRQ/s"; 2933 SET_COUNT; 2934 break; 2935 case _DRM_STAT_PRIMARY: 2936 stats->data[i].long_name = "Primary Bytes"; 2937 stats->data[i].rate_name = "PB/s"; 2938 SET_BYTE; 2939 break; 2940 case _DRM_STAT_SECONDARY: 2941 stats->data[i].long_name = "Secondary Bytes"; 2942 stats->data[i].rate_name = "SB/s"; 2943 SET_BYTE; 2944 break; 2945 case _DRM_STAT_DMA: 2946 stats->data[i].long_name = "DMA"; 2947 stats->data[i].rate_name = "DMA/s"; 2948 SET_COUNT; 2949 break; 2950 case _DRM_STAT_SPECIAL: 2951 stats->data[i].long_name = "Special DMA"; 2952 stats->data[i].rate_name = "dma/s"; 2953 SET_COUNT; 2954 break; 2955 case _DRM_STAT_MISSED: 2956 stats->data[i].long_name = "Miss"; 2957 stats->data[i].rate_name = "Ms/s"; 2958 SET_COUNT; 2959 break; 2960 case _DRM_STAT_VALUE: 2961 stats->data[i].long_name = "Value"; 2962 stats->data[i].rate_name = "Value"; 2963 SET_VALUE; 2964 break; 2965 case _DRM_STAT_BYTE: 2966 stats->data[i].long_name = "Bytes"; 2967 stats->data[i].rate_name = "B/s"; 2968 SET_BYTE; 2969 break; 2970 case _DRM_STAT_COUNT: 2971 default: 2972 stats->data[i].long_name = "Count"; 2973 stats->data[i].rate_name = "Cnt/s"; 2974 SET_COUNT; 2975 break; 2976 } 2977 } 2978 return 0; 2979} 2980 2981/** 2982 * Issue a set-version ioctl. 2983 * 2984 * \param fd file descriptor. 2985 * \param drmCommandIndex command index 2986 * \param data source pointer of the data to be read and written. 2987 * \param size size of the data to be read and written. 2988 * 2989 * \return zero on success, or a negative value on failure. 2990 * 2991 * \internal 2992 * It issues a read-write ioctl given by 2993 * \code DRM_COMMAND_BASE + drmCommandIndex \endcode. 2994 */ 2995drm_public int drmSetInterfaceVersion(int fd, drmSetVersion *version) 2996{ 2997 int retcode = 0; 2998 drm_set_version_t sv; 2999 3000 memclear(sv); 3001 sv.drm_di_major = version->drm_di_major; 3002 sv.drm_di_minor = version->drm_di_minor; 3003 sv.drm_dd_major = version->drm_dd_major; 3004 sv.drm_dd_minor = version->drm_dd_minor; 3005 3006 if (drmIoctl(fd, DRM_IOCTL_SET_VERSION, &sv)) { 3007 retcode = -errno; 3008 } 3009 3010 version->drm_di_major = sv.drm_di_major; 3011 version->drm_di_minor = sv.drm_di_minor; 3012 version->drm_dd_major = sv.drm_dd_major; 3013 version->drm_dd_minor = sv.drm_dd_minor; 3014 3015 return retcode; 3016} 3017 3018/** 3019 * Send a device-specific command. 3020 * 3021 * \param fd file descriptor. 3022 * \param drmCommandIndex command index 3023 * 3024 * \return zero on success, or a negative value on failure. 3025 * 3026 * \internal 3027 * It issues a ioctl given by 3028 * \code DRM_COMMAND_BASE + drmCommandIndex \endcode. 3029 */ 3030drm_public int drmCommandNone(int fd, unsigned long drmCommandIndex) 3031{ 3032 unsigned long request; 3033 3034 request = DRM_IO( DRM_COMMAND_BASE + drmCommandIndex); 3035 3036 if (drmIoctl(fd, request, NULL)) { 3037 return -errno; 3038 } 3039 return 0; 3040} 3041 3042 3043/** 3044 * Send a device-specific read command. 3045 * 3046 * \param fd file descriptor. 3047 * \param drmCommandIndex command index 3048 * \param data destination pointer of the data to be read. 3049 * \param size size of the data to be read. 3050 * 3051 * \return zero on success, or a negative value on failure. 3052 * 3053 * \internal 3054 * It issues a read ioctl given by 3055 * \code DRM_COMMAND_BASE + drmCommandIndex \endcode. 3056 */ 3057drm_public int drmCommandRead(int fd, unsigned long drmCommandIndex, 3058 void *data, unsigned long size) 3059{ 3060 unsigned long request; 3061 3062 request = DRM_IOC( DRM_IOC_READ, DRM_IOCTL_BASE, 3063 DRM_COMMAND_BASE + drmCommandIndex, size); 3064 3065 if (drmIoctl(fd, request, data)) { 3066 return -errno; 3067 } 3068 return 0; 3069} 3070 3071 3072/** 3073 * Send a device-specific write command. 3074 * 3075 * \param fd file descriptor. 3076 * \param drmCommandIndex command index 3077 * \param data source pointer of the data to be written. 3078 * \param size size of the data to be written. 3079 * 3080 * \return zero on success, or a negative value on failure. 3081 * 3082 * \internal 3083 * It issues a write ioctl given by 3084 * \code DRM_COMMAND_BASE + drmCommandIndex \endcode. 3085 */ 3086drm_public int drmCommandWrite(int fd, unsigned long drmCommandIndex, 3087 void *data, unsigned long size) 3088{ 3089 unsigned long request; 3090 3091 request = DRM_IOC( DRM_IOC_WRITE, DRM_IOCTL_BASE, 3092 DRM_COMMAND_BASE + drmCommandIndex, size); 3093 3094 if (drmIoctl(fd, request, data)) { 3095 return -errno; 3096 } 3097 return 0; 3098} 3099 3100 3101/** 3102 * Send a device-specific read-write command. 3103 * 3104 * \param fd file descriptor. 3105 * \param drmCommandIndex command index 3106 * \param data source pointer of the data to be read and written. 3107 * \param size size of the data to be read and written. 3108 * 3109 * \return zero on success, or a negative value on failure. 3110 * 3111 * \internal 3112 * It issues a read-write ioctl given by 3113 * \code DRM_COMMAND_BASE + drmCommandIndex \endcode. 3114 */ 3115drm_public int drmCommandWriteRead(int fd, unsigned long drmCommandIndex, 3116 void *data, unsigned long size) 3117{ 3118 unsigned long request; 3119 3120 request = DRM_IOC( DRM_IOC_READ|DRM_IOC_WRITE, DRM_IOCTL_BASE, 3121 DRM_COMMAND_BASE + drmCommandIndex, size); 3122 3123 if (drmIoctl(fd, request, data)) 3124 return -errno; 3125 return 0; 3126} 3127 3128#define DRM_MAX_FDS 16 3129static struct { 3130 char *BusID; 3131 int fd; 3132 int refcount; 3133 int type; 3134} connection[DRM_MAX_FDS]; 3135 3136static int nr_fds = 0; 3137 3138drm_public int drmOpenOnce(void *unused, const char *BusID, int *newlyopened) 3139{ 3140 return drmOpenOnceWithType(BusID, newlyopened, DRM_NODE_PRIMARY); 3141} 3142 3143drm_public int drmOpenOnceWithType(const char *BusID, int *newlyopened, 3144 int type) 3145{ 3146 int i; 3147 int fd; 3148 3149 for (i = 0; i < nr_fds; i++) 3150 if ((strcmp(BusID, connection[i].BusID) == 0) && 3151 (connection[i].type == type)) { 3152 connection[i].refcount++; 3153 *newlyopened = 0; 3154 return connection[i].fd; 3155 } 3156 3157 fd = drmOpenWithType(NULL, BusID, type); 3158 if (fd < 0 || nr_fds == DRM_MAX_FDS) 3159 return fd; 3160 3161 connection[nr_fds].BusID = strdup(BusID); 3162 connection[nr_fds].fd = fd; 3163 connection[nr_fds].refcount = 1; 3164 connection[nr_fds].type = type; 3165 *newlyopened = 1; 3166 3167 if (0) 3168 fprintf(stderr, "saved connection %d for %s %d\n", 3169 nr_fds, connection[nr_fds].BusID, 3170 strcmp(BusID, connection[nr_fds].BusID)); 3171 3172 nr_fds++; 3173 3174 return fd; 3175} 3176 3177drm_public void drmCloseOnce(int fd) 3178{ 3179 int i; 3180 3181 for (i = 0; i < nr_fds; i++) { 3182 if (fd == connection[i].fd) { 3183 if (--connection[i].refcount == 0) { 3184 drmClose(connection[i].fd); 3185 free(connection[i].BusID); 3186 3187 if (i < --nr_fds) 3188 connection[i] = connection[nr_fds]; 3189 3190 return; 3191 } 3192 } 3193 } 3194} 3195 3196drm_public int drmSetMaster(int fd) 3197{ 3198 return drmIoctl(fd, DRM_IOCTL_SET_MASTER, NULL); 3199} 3200 3201drm_public int drmDropMaster(int fd) 3202{ 3203 return drmIoctl(fd, DRM_IOCTL_DROP_MASTER, NULL); 3204} 3205 3206drm_public int drmIsMaster(int fd) 3207{ 3208 /* Detect master by attempting something that requires master. 3209 * 3210 * Authenticating magic tokens requires master and 0 is an 3211 * internal kernel detail which we could use. Attempting this on 3212 * a master fd would fail therefore fail with EINVAL because 0 3213 * is invalid. 3214 * 3215 * A non-master fd will fail with EACCES, as the kernel checks 3216 * for master before attempting to do anything else. 3217 * 3218 * Since we don't want to leak implementation details, use 3219 * EACCES. 3220 */ 3221 return drmAuthMagic(fd, 0) != -EACCES; 3222} 3223 3224drm_public char *drmGetDeviceNameFromFd(int fd) 3225{ 3226#ifdef __FreeBSD__ 3227 struct stat sbuf; 3228 int maj, min; 3229 int nodetype; 3230 3231 if (fstat(fd, &sbuf)) 3232 return NULL; 3233 3234 maj = major(sbuf.st_rdev); 3235 min = minor(sbuf.st_rdev); 3236 nodetype = drmGetMinorType(maj, min); 3237 return drmGetMinorNameForFD(fd, nodetype); 3238#else 3239 char name[128]; 3240 struct stat sbuf; 3241 dev_t d; 3242 int i; 3243 3244 /* The whole drmOpen thing is a fiasco and we need to find a way 3245 * back to just using open(2). For now, however, lets just make 3246 * things worse with even more ad hoc directory walking code to 3247 * discover the device file name. */ 3248 3249 fstat(fd, &sbuf); 3250 d = sbuf.st_rdev; 3251 3252 for (i = 0; i < DRM_MAX_MINOR; i++) { 3253 snprintf(name, sizeof name, DRM_DEV_NAME, DRM_DIR_NAME, i); 3254 if (stat(name, &sbuf) == 0 && sbuf.st_rdev == d) 3255 break; 3256 } 3257 if (i == DRM_MAX_MINOR) 3258 return NULL; 3259 3260 return strdup(name); 3261#endif 3262} 3263 3264static bool drmNodeIsDRM(int maj, int min) 3265{ 3266#ifdef __linux__ 3267 char path[64]; 3268 struct stat sbuf; 3269 3270 snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device/drm", 3271 maj, min); 3272 return stat(path, &sbuf) == 0; 3273#elif defined(__FreeBSD__) 3274 char name[SPECNAMELEN]; 3275 3276 if (!devname_r(makedev(maj, min), S_IFCHR, name, sizeof(name))) 3277 return 0; 3278 /* Handle drm/ and dri/ as both are present in different FreeBSD version 3279 * FreeBSD on amd64/i386/powerpc external kernel modules create node in 3280 * in /dev/drm/ and links in /dev/dri while a WIP in kernel driver creates 3281 * only device nodes in /dev/dri/ */ 3282 return (!strncmp(name, "drm/", 4) || !strncmp(name, "dri/", 4)); 3283#else 3284 return maj == DRM_MAJOR; 3285#endif 3286} 3287 3288drm_public int drmGetNodeTypeFromFd(int fd) 3289{ 3290 struct stat sbuf; 3291 int maj, min, type; 3292 3293 if (fstat(fd, &sbuf)) 3294 return -1; 3295 3296 maj = major(sbuf.st_rdev); 3297 min = minor(sbuf.st_rdev); 3298 3299 if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode)) { 3300 errno = EINVAL; 3301 return -1; 3302 } 3303 3304 type = drmGetMinorType(maj, min); 3305 if (type == -1) 3306 errno = ENODEV; 3307 return type; 3308} 3309 3310drm_public int drmPrimeHandleToFD(int fd, uint32_t handle, uint32_t flags, 3311 int *prime_fd) 3312{ 3313 struct drm_prime_handle args; 3314 int ret; 3315 3316 memclear(args); 3317 args.fd = -1; 3318 args.handle = handle; 3319 args.flags = flags; 3320 ret = drmIoctl(fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &args); 3321 if (ret) 3322 return ret; 3323 3324 *prime_fd = args.fd; 3325 return 0; 3326} 3327 3328drm_public int drmPrimeFDToHandle(int fd, int prime_fd, uint32_t *handle) 3329{ 3330 struct drm_prime_handle args; 3331 int ret; 3332 3333 memclear(args); 3334 args.fd = prime_fd; 3335 ret = drmIoctl(fd, DRM_IOCTL_PRIME_FD_TO_HANDLE, &args); 3336 if (ret) 3337 return ret; 3338 3339 *handle = args.handle; 3340 return 0; 3341} 3342 3343drm_public int drmCloseBufferHandle(int fd, uint32_t handle) 3344{ 3345 struct drm_gem_close args; 3346 3347 memclear(args); 3348 args.handle = handle; 3349 return drmIoctl(fd, DRM_IOCTL_GEM_CLOSE, &args); 3350} 3351 3352static char *drmGetMinorNameForFD(int fd, int type) 3353{ 3354#ifdef __linux__ 3355 DIR *sysdir; 3356 struct dirent *ent; 3357 struct stat sbuf; 3358 const char *name = drmGetMinorName(type); 3359 int len; 3360 char dev_name[64], buf[64]; 3361 int maj, min; 3362 3363 if (!name) 3364 return NULL; 3365 3366 len = strlen(name); 3367 3368 if (fstat(fd, &sbuf)) 3369 return NULL; 3370 3371 maj = major(sbuf.st_rdev); 3372 min = minor(sbuf.st_rdev); 3373 3374 if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode)) 3375 return NULL; 3376 3377 snprintf(buf, sizeof(buf), "/sys/dev/char/%d:%d/device/drm", maj, min); 3378 3379 sysdir = opendir(buf); 3380 if (!sysdir) 3381 return NULL; 3382 3383 while ((ent = readdir(sysdir))) { 3384 if (strncmp(ent->d_name, name, len) == 0) { 3385 if (snprintf(dev_name, sizeof(dev_name), DRM_DIR_NAME "/%s", 3386 ent->d_name) < 0) 3387 return NULL; 3388 3389 closedir(sysdir); 3390 return strdup(dev_name); 3391 } 3392 } 3393 3394 closedir(sysdir); 3395 return NULL; 3396#elif defined(__FreeBSD__) 3397 struct stat sbuf; 3398 char dname[SPECNAMELEN]; 3399 const char *mname; 3400 char name[SPECNAMELEN]; 3401 int id, maj, min, nodetype, i; 3402 3403 if (fstat(fd, &sbuf)) 3404 return NULL; 3405 3406 maj = major(sbuf.st_rdev); 3407 min = minor(sbuf.st_rdev); 3408 3409 if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode)) 3410 return NULL; 3411 3412 if (!devname_r(sbuf.st_rdev, S_IFCHR, dname, sizeof(dname))) 3413 return NULL; 3414 3415 /* Handle both /dev/drm and /dev/dri 3416 * FreeBSD on amd64/i386/powerpc external kernel modules create node in 3417 * in /dev/drm/ and links in /dev/dri while a WIP in kernel driver creates 3418 * only device nodes in /dev/dri/ */ 3419 3420 /* Get the node type represented by fd so we can deduce the target name */ 3421 nodetype = drmGetMinorType(maj, min); 3422 if (nodetype == -1) 3423 return (NULL); 3424 mname = drmGetMinorName(type); 3425 3426 for (i = 0; i < SPECNAMELEN; i++) { 3427 if (isalpha(dname[i]) == 0 && dname[i] != '/') 3428 break; 3429 } 3430 if (dname[i] == '\0') 3431 return (NULL); 3432 3433 id = (int)strtol(&dname[i], NULL, 10); 3434 id -= drmGetMinorBase(nodetype); 3435 snprintf(name, sizeof(name), DRM_DIR_NAME "/%s%d", mname, 3436 id + drmGetMinorBase(type)); 3437 3438 return strdup(name); 3439#else 3440 struct stat sbuf; 3441 char buf[PATH_MAX + 1]; 3442 const char *dev_name = drmGetDeviceName(type); 3443 unsigned int maj, min; 3444 int n; 3445 3446 if (fstat(fd, &sbuf)) 3447 return NULL; 3448 3449 maj = major(sbuf.st_rdev); 3450 min = minor(sbuf.st_rdev); 3451 3452 if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode)) 3453 return NULL; 3454 3455 if (!dev_name) 3456 return NULL; 3457 3458 n = snprintf(buf, sizeof(buf), dev_name, DRM_DIR_NAME, min); 3459 if (n == -1 || n >= sizeof(buf)) 3460 return NULL; 3461 3462 return strdup(buf); 3463#endif 3464} 3465 3466drm_public char *drmGetPrimaryDeviceNameFromFd(int fd) 3467{ 3468 return drmGetMinorNameForFD(fd, DRM_NODE_PRIMARY); 3469} 3470 3471drm_public char *drmGetRenderDeviceNameFromFd(int fd) 3472{ 3473 return drmGetMinorNameForFD(fd, DRM_NODE_RENDER); 3474} 3475 3476#ifdef __linux__ 3477static char * DRM_PRINTFLIKE(2, 3) 3478sysfs_uevent_get(const char *path, const char *fmt, ...) 3479{ 3480 char filename[PATH_MAX + 1], *key, *line = NULL, *value = NULL; 3481 size_t size = 0, len; 3482 ssize_t num; 3483 va_list ap; 3484 FILE *fp; 3485 3486 va_start(ap, fmt); 3487 num = vasprintf(&key, fmt, ap); 3488 va_end(ap); 3489 len = num; 3490 3491 snprintf(filename, sizeof(filename), "%s/uevent", path); 3492 3493 fp = fopen(filename, "r"); 3494 if (!fp) { 3495 free(key); 3496 return NULL; 3497 } 3498 3499 while ((num = getline(&line, &size, fp)) >= 0) { 3500 if ((strncmp(line, key, len) == 0) && (line[len] == '=')) { 3501 char *start = line + len + 1, *end = line + num - 1; 3502 3503 if (*end != '\n') 3504 end++; 3505 3506 value = strndup(start, end - start); 3507 break; 3508 } 3509 } 3510 3511 free(line); 3512 fclose(fp); 3513 3514 free(key); 3515 3516 return value; 3517} 3518#endif 3519 3520/* Little white lie to avoid major rework of the existing code */ 3521#define DRM_BUS_VIRTIO 0x10 3522 3523#ifdef __linux__ 3524static int get_subsystem_type(const char *device_path) 3525{ 3526 char path[PATH_MAX + 1] = ""; 3527 char link[PATH_MAX + 1] = ""; 3528 char *name; 3529 struct { 3530 const char *name; 3531 int bus_type; 3532 } bus_types[] = { 3533 { "/pci", DRM_BUS_PCI }, 3534 { "/usb", DRM_BUS_USB }, 3535 { "/platform", DRM_BUS_PLATFORM }, 3536 { "/spi", DRM_BUS_PLATFORM }, 3537 { "/host1x", DRM_BUS_HOST1X }, 3538 { "/virtio", DRM_BUS_VIRTIO }, 3539 }; 3540 3541 strncpy(path, device_path, PATH_MAX); 3542 strncat(path, "/subsystem", PATH_MAX); 3543 3544 if (readlink(path, link, PATH_MAX) < 0) 3545 return -errno; 3546 3547 name = strrchr(link, '/'); 3548 if (!name) 3549 return -EINVAL; 3550 3551 for (unsigned i = 0; i < ARRAY_SIZE(bus_types); i++) { 3552 if (strncmp(name, bus_types[i].name, strlen(bus_types[i].name)) == 0) 3553 return bus_types[i].bus_type; 3554 } 3555 3556 return -EINVAL; 3557} 3558#endif 3559 3560static int drmParseSubsystemType(int maj, int min) 3561{ 3562#ifdef __linux__ 3563 char path[PATH_MAX + 1] = ""; 3564 char real_path[PATH_MAX + 1] = ""; 3565 int subsystem_type; 3566 3567 snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min); 3568 3569 subsystem_type = get_subsystem_type(path); 3570 /* Try to get the parent (underlying) device type */ 3571 if (subsystem_type == DRM_BUS_VIRTIO) { 3572 /* Assume virtio-pci on error */ 3573 if (!realpath(path, real_path)) 3574 return DRM_BUS_VIRTIO; 3575 strncat(path, "/..", PATH_MAX); 3576 subsystem_type = get_subsystem_type(path); 3577 if (subsystem_type < 0) 3578 return DRM_BUS_VIRTIO; 3579 } 3580#elif defined(__NetBSD__) 3581 int type, fd; 3582 drmSetVersion sv; 3583 char *buf; 3584 unsigned domain, bus, dev; 3585 int func; 3586 int ret; 3587 3588 /* Get the type of device we're looking for to pick the right pathname. */ 3589 type = drmGetMinorType(maj, min); 3590 if (type == -1) 3591 return -ENODEV; 3592 3593 /* Open the device. Don't try to create it if it's not there. */ 3594 fd = drmOpenMinor(min, 0, type); 3595 if (fd < 0) 3596 return -errno; 3597 3598 /* 3599 * Set the interface version to 1.4 or 1.1, which has the effect of 3600 * populating the bus id for us. 3601 */ 3602 sv.drm_di_major = 1; 3603 sv.drm_di_minor = 4; 3604 sv.drm_dd_major = -1; 3605 sv.drm_dd_minor = -1; 3606 if (drmSetInterfaceVersion(fd, &sv)) { 3607 sv.drm_di_major = 1; 3608 sv.drm_di_minor = 1; 3609 sv.drm_dd_major = -1; 3610 sv.drm_dd_minor = -1; 3611 if (drmSetInterfaceVersion(fd, &sv)) { 3612 /* 3613 * We're probably not the master. Hope the master already 3614 * set the version to >=1.1 so that we can get the busid. 3615 */ 3616 } 3617 } 3618 3619 /* Get the bus id. */ 3620 buf = drmGetBusid(fd); 3621 3622 /* We're done with the device now. */ 3623 (void)close(fd); 3624 3625 /* If there is no bus id, fail. */ 3626 if (buf == NULL) 3627 return -ENODEV; 3628 3629 /* Find a string we know about; otherwise -EINVAL. */ 3630 ret = -EINVAL; 3631 if (strncmp(buf, "pci:", 4) == 0) 3632 ret = DRM_BUS_PCI; 3633 3634 /* We're done with the bus id. */ 3635 free(buf); 3636 3637 /* Success or not, we're done. */ 3638 return ret; 3639#elif defined(__OpenBSD__) || defined(__DragonFly__) 3640 return DRM_BUS_PCI; 3641#else 3642#warning "Missing implementation of drmParseSubsystemType" 3643 return -EINVAL; 3644#endif 3645} 3646 3647#ifdef __linux__ 3648static void 3649get_pci_path(int maj, int min, char *pci_path) 3650{ 3651 char path[PATH_MAX + 1], *term; 3652 3653 snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min); 3654 if (!realpath(path, pci_path)) { 3655 strcpy(pci_path, path); 3656 return; 3657 } 3658 3659 term = strrchr(pci_path, '/'); 3660 if (term && strncmp(term, "/virtio", 7) == 0) 3661 *term = 0; 3662} 3663#endif 3664 3665#ifdef __FreeBSD__ 3666static int get_sysctl_pci_bus_info(int maj, int min, drmPciBusInfoPtr info) 3667{ 3668 char dname[SPECNAMELEN]; 3669 char sysctl_name[16]; 3670 char sysctl_val[256]; 3671 size_t sysctl_len; 3672 int id, type, nelem; 3673 unsigned int rdev, majmin, domain, bus, dev, func; 3674 3675 rdev = makedev(maj, min); 3676 if (!devname_r(rdev, S_IFCHR, dname, sizeof(dname))) 3677 return -EINVAL; 3678 3679 if (sscanf(dname, "drm/%d\n", &id) != 1) 3680 return -EINVAL; 3681 type = drmGetMinorType(maj, min); 3682 if (type == -1) 3683 return -EINVAL; 3684 3685 /* BUG: This above section is iffy, since it mandates that a driver will 3686 * create both card and render node. 3687 * If it does not, the next DRM device will create card#X and 3688 * renderD#(128+X)-1. 3689 * This is a possibility in FreeBSD but for now there is no good way for 3690 * obtaining the info. 3691 */ 3692 switch (type) { 3693 case DRM_NODE_PRIMARY: 3694 break; 3695 case DRM_NODE_CONTROL: 3696 id -= 64; 3697 break; 3698 case DRM_NODE_RENDER: 3699 id -= 128; 3700 break; 3701 } 3702 if (id < 0) 3703 return -EINVAL; 3704 3705 if (snprintf(sysctl_name, sizeof(sysctl_name), "hw.dri.%d.busid", id) <= 0) 3706 return -EINVAL; 3707 sysctl_len = sizeof(sysctl_val); 3708 if (sysctlbyname(sysctl_name, sysctl_val, &sysctl_len, NULL, 0)) 3709 return -EINVAL; 3710 3711 #define bus_fmt "pci:%04x:%02x:%02x.%u" 3712 3713 nelem = sscanf(sysctl_val, bus_fmt, &domain, &bus, &dev, &func); 3714 if (nelem != 4) 3715 return -EINVAL; 3716 info->domain = domain; 3717 info->bus = bus; 3718 info->dev = dev; 3719 info->func = func; 3720 3721 return 0; 3722} 3723#endif 3724 3725static int drmParsePciBusInfo(int maj, int min, drmPciBusInfoPtr info) 3726{ 3727#ifdef __linux__ 3728 unsigned int domain, bus, dev, func; 3729 char pci_path[PATH_MAX + 1], *value; 3730 int num; 3731 3732 get_pci_path(maj, min, pci_path); 3733 3734 value = sysfs_uevent_get(pci_path, "PCI_SLOT_NAME"); 3735 if (!value) 3736 return -ENOENT; 3737 3738 num = sscanf(value, "%04x:%02x:%02x.%1u", &domain, &bus, &dev, &func); 3739 free(value); 3740 3741 if (num != 4) 3742 return -EINVAL; 3743 3744 info->domain = domain; 3745 info->bus = bus; 3746 info->dev = dev; 3747 info->func = func; 3748 3749 return 0; 3750#elif defined(__NetBSD__) 3751 int type, fd; 3752 drmSetVersion sv; 3753 char *buf; 3754 unsigned domain, bus, dev; 3755 int func; 3756 int ret; 3757 3758 /* Get the type of device we're looking for to pick the right pathname. */ 3759 type = drmGetMinorType(maj, min); 3760 if (type == -1) 3761 return -ENODEV; 3762 3763 /* Open the device. Don't try to create it if it's not there. */ 3764 fd = drmOpenMinor(min, 0, type); 3765 if (fd < 0) 3766 return -errno; 3767 3768 /* 3769 * Set the interface version to 1.4 or 1.1, which has the effect of 3770 * populating the bus id for us. 3771 */ 3772 sv.drm_di_major = 1; 3773 sv.drm_di_minor = 4; 3774 sv.drm_dd_major = -1; 3775 sv.drm_dd_minor = -1; 3776 if (drmSetInterfaceVersion(fd, &sv)) { 3777 sv.drm_di_major = 1; 3778 sv.drm_di_minor = 1; 3779 sv.drm_dd_major = -1; 3780 sv.drm_dd_minor = -1; 3781 if (drmSetInterfaceVersion(fd, &sv)) { 3782 /* 3783 * We're probably not the master. Hope the master already 3784 * set the version to >=1.1 so that we can get the busid. 3785 */ 3786 } 3787 } 3788 3789 /* Get the bus id. */ 3790 buf = drmGetBusid(fd); 3791 3792 /* We're done with the device now. */ 3793 (void)close(fd); 3794 3795 /* If there is no bus id, fail. */ 3796 if (buf == NULL) 3797 return -ENODEV; 3798 3799 /* Parse the bus id. */ 3800 ret = sscanf(buf, "pci:%04x:%02x:%02x.%d", &domain, &bus, &dev, &func); 3801 3802 /* We're done with the bus id. */ 3803 free(buf); 3804 3805 /* If scanf didn't return 4 -- domain, bus, dev, func -- then fail. */ 3806 if (ret != 4) 3807 return -ENODEV; 3808 3809 /* Populate the results. */ 3810 info->domain = domain; 3811 info->bus = bus; 3812 info->dev = dev; 3813 info->func = func; 3814 3815 /* Success! */ 3816 return 0; 3817#elif defined(__OpenBSD__) || defined(__DragonFly__) 3818 struct drm_pciinfo pinfo; 3819 int fd, type; 3820 3821 type = drmGetMinorType(maj, min); 3822 if (type == -1) 3823 return -ENODEV; 3824 3825 fd = drmOpenMinor(min, 0, type); 3826 if (fd < 0) 3827 return -errno; 3828 3829 if (drmIoctl(fd, DRM_IOCTL_GET_PCIINFO, &pinfo)) { 3830 close(fd); 3831 return -errno; 3832 } 3833 close(fd); 3834 3835 info->domain = pinfo.domain; 3836 info->bus = pinfo.bus; 3837 info->dev = pinfo.dev; 3838 info->func = pinfo.func; 3839 3840 return 0; 3841#elif defined(__FreeBSD__) 3842 return get_sysctl_pci_bus_info(maj, min, info); 3843#else 3844#warning "Missing implementation of drmParsePciBusInfo" 3845 return -EINVAL; 3846#endif 3847} 3848 3849drm_public int drmDevicesEqual(drmDevicePtr a, drmDevicePtr b) 3850{ 3851 if (a == NULL || b == NULL) 3852 return 0; 3853 3854 if (a->bustype != b->bustype) 3855 return 0; 3856 3857 switch (a->bustype) { 3858 case DRM_BUS_PCI: 3859 return memcmp(a->businfo.pci, b->businfo.pci, sizeof(drmPciBusInfo)) == 0; 3860 3861 case DRM_BUS_USB: 3862 return memcmp(a->businfo.usb, b->businfo.usb, sizeof(drmUsbBusInfo)) == 0; 3863 3864 case DRM_BUS_PLATFORM: 3865 return memcmp(a->businfo.platform, b->businfo.platform, sizeof(drmPlatformBusInfo)) == 0; 3866 3867 case DRM_BUS_HOST1X: 3868 return memcmp(a->businfo.host1x, b->businfo.host1x, sizeof(drmHost1xBusInfo)) == 0; 3869 3870 default: 3871 break; 3872 } 3873 3874 return 0; 3875} 3876 3877static int drmGetNodeType(const char *name) 3878{ 3879 if (strncmp(name, DRM_CONTROL_MINOR_NAME, 3880 sizeof(DRM_CONTROL_MINOR_NAME ) - 1) == 0) 3881 return DRM_NODE_CONTROL; 3882 3883 if (strncmp(name, DRM_RENDER_MINOR_NAME, 3884 sizeof(DRM_RENDER_MINOR_NAME) - 1) == 0) 3885 return DRM_NODE_RENDER; 3886 3887 if (strncmp(name, DRM_PRIMARY_MINOR_NAME, 3888 sizeof(DRM_PRIMARY_MINOR_NAME) - 1) == 0) 3889 return DRM_NODE_PRIMARY; 3890 3891 return -EINVAL; 3892} 3893 3894static int drmGetMaxNodeName(void) 3895{ 3896 return sizeof(DRM_DIR_NAME) + 3897 MAX3(sizeof(DRM_PRIMARY_MINOR_NAME), 3898 sizeof(DRM_CONTROL_MINOR_NAME), 3899 sizeof(DRM_RENDER_MINOR_NAME)) + 3900 3 /* length of the node number */; 3901} 3902 3903#ifdef __linux__ 3904static int parse_separate_sysfs_files(int maj, int min, 3905 drmPciDeviceInfoPtr device, 3906 bool ignore_revision) 3907{ 3908 static const char *attrs[] = { 3909 "revision", /* Older kernels are missing the file, so check for it first */ 3910 "vendor", 3911 "device", 3912 "subsystem_vendor", 3913 "subsystem_device", 3914 }; 3915 char path[PATH_MAX + 1], pci_path[PATH_MAX + 1]; 3916 unsigned int data[ARRAY_SIZE(attrs)]; 3917 FILE *fp; 3918 int ret; 3919 3920 get_pci_path(maj, min, pci_path); 3921 3922 for (unsigned i = ignore_revision ? 1 : 0; i < ARRAY_SIZE(attrs); i++) { 3923 if (snprintf(path, PATH_MAX, "%s/%s", pci_path, attrs[i]) < 0) 3924 return -errno; 3925 3926 fp = fopen(path, "r"); 3927 if (!fp) 3928 return -errno; 3929 3930 ret = fscanf(fp, "%x", &data[i]); 3931 fclose(fp); 3932 if (ret != 1) 3933 return -errno; 3934 3935 } 3936 3937 device->revision_id = ignore_revision ? 0xff : data[0] & 0xff; 3938 device->vendor_id = data[1] & 0xffff; 3939 device->device_id = data[2] & 0xffff; 3940 device->subvendor_id = data[3] & 0xffff; 3941 device->subdevice_id = data[4] & 0xffff; 3942 3943 return 0; 3944} 3945 3946static int parse_config_sysfs_file(int maj, int min, 3947 drmPciDeviceInfoPtr device) 3948{ 3949 char path[PATH_MAX + 1], pci_path[PATH_MAX + 1]; 3950 unsigned char config[64]; 3951 int fd, ret; 3952 3953 get_pci_path(maj, min, pci_path); 3954 3955 if (snprintf(path, PATH_MAX, "%s/config", pci_path) < 0) 3956 return -errno; 3957 3958 fd = open(path, O_RDONLY); 3959 if (fd < 0) 3960 return -errno; 3961 3962 ret = read(fd, config, sizeof(config)); 3963 close(fd); 3964 if (ret < 0) 3965 return -errno; 3966 3967 device->vendor_id = config[0] | (config[1] << 8); 3968 device->device_id = config[2] | (config[3] << 8); 3969 device->revision_id = config[8]; 3970 device->subvendor_id = config[44] | (config[45] << 8); 3971 device->subdevice_id = config[46] | (config[47] << 8); 3972 3973 return 0; 3974} 3975#endif 3976 3977static int drmParsePciDeviceInfo(int maj, int min, 3978 drmPciDeviceInfoPtr device, 3979 uint32_t flags) 3980{ 3981#ifdef __linux__ 3982 if (!(flags & DRM_DEVICE_GET_PCI_REVISION)) 3983 return parse_separate_sysfs_files(maj, min, device, true); 3984 3985 if (parse_separate_sysfs_files(maj, min, device, false)) 3986 return parse_config_sysfs_file(maj, min, device); 3987 3988 return 0; 3989#elif defined(__NetBSD__) 3990 drmPciBusInfo businfo; 3991 char fname[PATH_MAX]; 3992 int pcifd; 3993 pcireg_t id, class, subsys; 3994 int ret; 3995 3996 /* Find where on the bus the device lives. */ 3997 ret = drmParsePciBusInfo(maj, min, &businfo); 3998 if (ret) 3999 return ret; 4000 4001 /* Open the pciN device node to get at its config registers. */ 4002 if (snprintf(fname, sizeof fname, "/dev/pci%u", businfo.domain) 4003 >= sizeof fname) 4004 return -ENODEV; 4005 if ((pcifd = open(fname, O_RDONLY)) == -1) 4006 return -errno; 4007 4008 ret = -1; 4009 /* Read the id and class pci config registers. */ 4010 if (pcibus_conf_read(pcifd, businfo.bus, businfo.dev, businfo.func, 4011 PCI_ID_REG, &id) == -1) 4012 goto out; 4013 if (pcibus_conf_read(pcifd, businfo.bus, businfo.dev, businfo.func, 4014 PCI_CLASS_REG, &class) == -1) 4015 goto out; 4016 if (pcibus_conf_read(pcifd, businfo.bus, businfo.dev, businfo.func, 4017 PCI_SUBSYS_ID_REG, &subsys) == -1) 4018 goto out; 4019 4020 ret = 0; 4021 device->vendor_id = PCI_VENDOR(id); 4022 device->device_id = PCI_PRODUCT(id); 4023 device->subvendor_id = PCI_SUBSYS_VENDOR(subsys); 4024 device->subdevice_id = PCI_SUBSYS_ID(subsys); 4025 device->revision_id = PCI_REVISION(class); 4026out: 4027 if (ret == -1) 4028 ret = -errno; 4029 close(pcifd); 4030 return ret; 4031#elif defined(__OpenBSD__) || defined(__DragonFly__) 4032 struct drm_pciinfo pinfo; 4033 int fd, type; 4034 4035 type = drmGetMinorType(maj, min); 4036 if (type == -1) 4037 return -ENODEV; 4038 4039 fd = drmOpenMinor(min, 0, type); 4040 if (fd < 0) 4041 return -errno; 4042 4043 if (drmIoctl(fd, DRM_IOCTL_GET_PCIINFO, &pinfo)) { 4044 close(fd); 4045 return -errno; 4046 } 4047 close(fd); 4048 4049 device->vendor_id = pinfo.vendor_id; 4050 device->device_id = pinfo.device_id; 4051 device->revision_id = pinfo.revision_id; 4052 device->subvendor_id = pinfo.subvendor_id; 4053 device->subdevice_id = pinfo.subdevice_id; 4054 4055 return 0; 4056#elif defined(__FreeBSD__) 4057 drmPciBusInfo info; 4058 struct pci_conf_io pc; 4059 struct pci_match_conf patterns[1]; 4060 struct pci_conf results[1]; 4061 int fd, error; 4062 4063 if (get_sysctl_pci_bus_info(maj, min, &info) != 0) 4064 return -EINVAL; 4065 4066 fd = open("/dev/pci", O_RDONLY); 4067 if (fd < 0) 4068 return -errno; 4069 4070 bzero(&patterns, sizeof(patterns)); 4071 patterns[0].pc_sel.pc_domain = info.domain; 4072 patterns[0].pc_sel.pc_bus = info.bus; 4073 patterns[0].pc_sel.pc_dev = info.dev; 4074 patterns[0].pc_sel.pc_func = info.func; 4075 patterns[0].flags = PCI_GETCONF_MATCH_DOMAIN | PCI_GETCONF_MATCH_BUS 4076 | PCI_GETCONF_MATCH_DEV | PCI_GETCONF_MATCH_FUNC; 4077 bzero(&pc, sizeof(struct pci_conf_io)); 4078 pc.num_patterns = 1; 4079 pc.pat_buf_len = sizeof(patterns); 4080 pc.patterns = patterns; 4081 pc.match_buf_len = sizeof(results); 4082 pc.matches = results; 4083 4084 if (ioctl(fd, PCIOCGETCONF, &pc) || pc.status == PCI_GETCONF_ERROR) { 4085 error = errno; 4086 close(fd); 4087 return -error; 4088 } 4089 close(fd); 4090 4091 device->vendor_id = results[0].pc_vendor; 4092 device->device_id = results[0].pc_device; 4093 device->subvendor_id = results[0].pc_subvendor; 4094 device->subdevice_id = results[0].pc_subdevice; 4095 device->revision_id = results[0].pc_revid; 4096 4097 return 0; 4098#else 4099#warning "Missing implementation of drmParsePciDeviceInfo" 4100 return -EINVAL; 4101#endif 4102} 4103 4104static void drmFreePlatformDevice(drmDevicePtr device) 4105{ 4106 if (device->deviceinfo.platform) { 4107 if (device->deviceinfo.platform->compatible) { 4108 char **compatible = device->deviceinfo.platform->compatible; 4109 4110 while (*compatible) { 4111 free(*compatible); 4112 compatible++; 4113 } 4114 4115 free(device->deviceinfo.platform->compatible); 4116 } 4117 } 4118} 4119 4120static void drmFreeHost1xDevice(drmDevicePtr device) 4121{ 4122 if (device->deviceinfo.host1x) { 4123 if (device->deviceinfo.host1x->compatible) { 4124 char **compatible = device->deviceinfo.host1x->compatible; 4125 4126 while (*compatible) { 4127 free(*compatible); 4128 compatible++; 4129 } 4130 4131 free(device->deviceinfo.host1x->compatible); 4132 } 4133 } 4134} 4135 4136drm_public void drmFreeDevice(drmDevicePtr *device) 4137{ 4138 if (device == NULL) 4139 return; 4140 4141 if (*device) { 4142 switch ((*device)->bustype) { 4143 case DRM_BUS_PLATFORM: 4144 drmFreePlatformDevice(*device); 4145 break; 4146 4147 case DRM_BUS_HOST1X: 4148 drmFreeHost1xDevice(*device); 4149 break; 4150 } 4151 } 4152 4153 free(*device); 4154 *device = NULL; 4155} 4156 4157drm_public void drmFreeDevices(drmDevicePtr devices[], int count) 4158{ 4159 int i; 4160 4161 if (devices == NULL) 4162 return; 4163 4164 for (i = 0; i < count; i++) 4165 if (devices[i]) 4166 drmFreeDevice(&devices[i]); 4167} 4168 4169static drmDevicePtr drmDeviceAlloc(unsigned int type, const char *node, 4170 size_t bus_size, size_t device_size, 4171 char **ptrp) 4172{ 4173 size_t max_node_length, extra, size; 4174 drmDevicePtr device; 4175 unsigned int i; 4176 char *ptr; 4177 4178 max_node_length = ALIGN(drmGetMaxNodeName(), sizeof(void *)); 4179 extra = DRM_NODE_MAX * (sizeof(void *) + max_node_length); 4180 4181 size = sizeof(*device) + extra + bus_size + device_size; 4182 4183 device = calloc(1, size); 4184 if (!device) 4185 return NULL; 4186 4187 device->available_nodes = 1 << type; 4188 4189 ptr = (char *)device + sizeof(*device); 4190 device->nodes = (char **)ptr; 4191 4192 ptr += DRM_NODE_MAX * sizeof(void *); 4193 4194 for (i = 0; i < DRM_NODE_MAX; i++) { 4195 device->nodes[i] = ptr; 4196 ptr += max_node_length; 4197 } 4198 4199 memcpy(device->nodes[type], node, max_node_length); 4200 4201 *ptrp = ptr; 4202 4203 return device; 4204} 4205 4206static int drmProcessPciDevice(drmDevicePtr *device, 4207 const char *node, int node_type, 4208 int maj, int min, bool fetch_deviceinfo, 4209 uint32_t flags) 4210{ 4211 drmDevicePtr dev; 4212 char *addr; 4213 int ret; 4214 4215 dev = drmDeviceAlloc(node_type, node, sizeof(drmPciBusInfo), 4216 sizeof(drmPciDeviceInfo), &addr); 4217 if (!dev) 4218 return -ENOMEM; 4219 4220 dev->bustype = DRM_BUS_PCI; 4221 4222 dev->businfo.pci = (drmPciBusInfoPtr)addr; 4223 4224 ret = drmParsePciBusInfo(maj, min, dev->businfo.pci); 4225 if (ret) 4226 goto free_device; 4227 4228 // Fetch the device info if the user has requested it 4229 if (fetch_deviceinfo) { 4230 addr += sizeof(drmPciBusInfo); 4231 dev->deviceinfo.pci = (drmPciDeviceInfoPtr)addr; 4232 4233 ret = drmParsePciDeviceInfo(maj, min, dev->deviceinfo.pci, flags); 4234 if (ret) 4235 goto free_device; 4236 } 4237 4238 *device = dev; 4239 4240 return 0; 4241 4242free_device: 4243 free(dev); 4244 return ret; 4245} 4246 4247#ifdef __linux__ 4248static int drm_usb_dev_path(int maj, int min, char *path, size_t len) 4249{ 4250 char *value, *tmp_path, *slash; 4251 bool usb_device, usb_interface; 4252 4253 snprintf(path, len, "/sys/dev/char/%d:%d/device", maj, min); 4254 4255 value = sysfs_uevent_get(path, "DEVTYPE"); 4256 if (!value) 4257 return -ENOENT; 4258 4259 usb_device = strcmp(value, "usb_device") == 0; 4260 usb_interface = strcmp(value, "usb_interface") == 0; 4261 free(value); 4262 4263 if (usb_device) 4264 return 0; 4265 if (!usb_interface) 4266 return -ENOTSUP; 4267 4268 /* The parent of a usb_interface is a usb_device */ 4269 4270 tmp_path = realpath(path, NULL); 4271 if (!tmp_path) 4272 return -errno; 4273 4274 slash = strrchr(tmp_path, '/'); 4275 if (!slash) { 4276 free(tmp_path); 4277 return -EINVAL; 4278 } 4279 4280 *slash = '\0'; 4281 4282 if (snprintf(path, len, "%s", tmp_path) >= (int)len) { 4283 free(tmp_path); 4284 return -EINVAL; 4285 } 4286 4287 free(tmp_path); 4288 return 0; 4289} 4290#endif 4291 4292static int drmParseUsbBusInfo(int maj, int min, drmUsbBusInfoPtr info) 4293{ 4294#ifdef __linux__ 4295 char path[PATH_MAX + 1], *value; 4296 unsigned int bus, dev; 4297 int ret; 4298 4299 ret = drm_usb_dev_path(maj, min, path, sizeof(path)); 4300 if (ret < 0) 4301 return ret; 4302 4303 value = sysfs_uevent_get(path, "BUSNUM"); 4304 if (!value) 4305 return -ENOENT; 4306 4307 ret = sscanf(value, "%03u", &bus); 4308 free(value); 4309 4310 if (ret <= 0) 4311 return -errno; 4312 4313 value = sysfs_uevent_get(path, "DEVNUM"); 4314 if (!value) 4315 return -ENOENT; 4316 4317 ret = sscanf(value, "%03u", &dev); 4318 free(value); 4319 4320 if (ret <= 0) 4321 return -errno; 4322 4323 info->bus = bus; 4324 info->dev = dev; 4325 4326 return 0; 4327#else 4328#warning "Missing implementation of drmParseUsbBusInfo" 4329 return -EINVAL; 4330#endif 4331} 4332 4333static int drmParseUsbDeviceInfo(int maj, int min, drmUsbDeviceInfoPtr info) 4334{ 4335#ifdef __linux__ 4336 char path[PATH_MAX + 1], *value; 4337 unsigned int vendor, product; 4338 int ret; 4339 4340 ret = drm_usb_dev_path(maj, min, path, sizeof(path)); 4341 if (ret < 0) 4342 return ret; 4343 4344 value = sysfs_uevent_get(path, "PRODUCT"); 4345 if (!value) 4346 return -ENOENT; 4347 4348 ret = sscanf(value, "%x/%x", &vendor, &product); 4349 free(value); 4350 4351 if (ret <= 0) 4352 return -errno; 4353 4354 info->vendor = vendor; 4355 info->product = product; 4356 4357 return 0; 4358#else 4359#warning "Missing implementation of drmParseUsbDeviceInfo" 4360 return -EINVAL; 4361#endif 4362} 4363 4364static int drmProcessUsbDevice(drmDevicePtr *device, const char *node, 4365 int node_type, int maj, int min, 4366 bool fetch_deviceinfo, uint32_t flags) 4367{ 4368 drmDevicePtr dev; 4369 char *ptr; 4370 int ret; 4371 4372 dev = drmDeviceAlloc(node_type, node, sizeof(drmUsbBusInfo), 4373 sizeof(drmUsbDeviceInfo), &ptr); 4374 if (!dev) 4375 return -ENOMEM; 4376 4377 dev->bustype = DRM_BUS_USB; 4378 4379 dev->businfo.usb = (drmUsbBusInfoPtr)ptr; 4380 4381 ret = drmParseUsbBusInfo(maj, min, dev->businfo.usb); 4382 if (ret < 0) 4383 goto free_device; 4384 4385 if (fetch_deviceinfo) { 4386 ptr += sizeof(drmUsbBusInfo); 4387 dev->deviceinfo.usb = (drmUsbDeviceInfoPtr)ptr; 4388 4389 ret = drmParseUsbDeviceInfo(maj, min, dev->deviceinfo.usb); 4390 if (ret < 0) 4391 goto free_device; 4392 } 4393 4394 *device = dev; 4395 4396 return 0; 4397 4398free_device: 4399 free(dev); 4400 return ret; 4401} 4402 4403static int drmParseOFBusInfo(int maj, int min, char *fullname) 4404{ 4405#ifdef __linux__ 4406 char path[PATH_MAX + 1], *name, *tmp_name; 4407 4408 snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min); 4409 4410 name = sysfs_uevent_get(path, "OF_FULLNAME"); 4411 tmp_name = name; 4412 if (!name) { 4413 /* If the device lacks OF data, pick the MODALIAS info */ 4414 name = sysfs_uevent_get(path, "MODALIAS"); 4415 if (!name) 4416 return -ENOENT; 4417 4418 /* .. and strip the MODALIAS=[platform,usb...]: part. */ 4419 tmp_name = strrchr(name, ':'); 4420 if (!tmp_name) { 4421 free(name); 4422 return -ENOENT; 4423 } 4424 tmp_name++; 4425 } 4426 4427 strncpy(fullname, tmp_name, DRM_PLATFORM_DEVICE_NAME_LEN); 4428 fullname[DRM_PLATFORM_DEVICE_NAME_LEN - 1] = '\0'; 4429 free(name); 4430 4431 return 0; 4432#else 4433#warning "Missing implementation of drmParseOFBusInfo" 4434 return -EINVAL; 4435#endif 4436} 4437 4438static int drmParseOFDeviceInfo(int maj, int min, char ***compatible) 4439{ 4440#ifdef __linux__ 4441 char path[PATH_MAX + 1], *value, *tmp_name; 4442 unsigned int count, i; 4443 int err; 4444 4445 snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min); 4446 4447 value = sysfs_uevent_get(path, "OF_COMPATIBLE_N"); 4448 if (value) { 4449 sscanf(value, "%u", &count); 4450 free(value); 4451 } else { 4452 /* Assume one entry if the device lack OF data */ 4453 count = 1; 4454 } 4455 4456 *compatible = calloc(count + 1, sizeof(char *)); 4457 if (!*compatible) 4458 return -ENOMEM; 4459 4460 for (i = 0; i < count; i++) { 4461 value = sysfs_uevent_get(path, "OF_COMPATIBLE_%u", i); 4462 tmp_name = value; 4463 if (!value) { 4464 /* If the device lacks OF data, pick the MODALIAS info */ 4465 value = sysfs_uevent_get(path, "MODALIAS"); 4466 if (!value) { 4467 err = -ENOENT; 4468 goto free; 4469 } 4470 4471 /* .. and strip the MODALIAS=[platform,usb...]: part. */ 4472 tmp_name = strrchr(value, ':'); 4473 if (!tmp_name) { 4474 free(value); 4475 return -ENOENT; 4476 } 4477 tmp_name = strdup(tmp_name + 1); 4478 free(value); 4479 } 4480 4481 (*compatible)[i] = tmp_name; 4482 } 4483 4484 return 0; 4485 4486free: 4487 while (i--) 4488 free((*compatible)[i]); 4489 4490 free(*compatible); 4491 return err; 4492#else 4493#warning "Missing implementation of drmParseOFDeviceInfo" 4494 return -EINVAL; 4495#endif 4496} 4497 4498static int drmProcessPlatformDevice(drmDevicePtr *device, 4499 const char *node, int node_type, 4500 int maj, int min, bool fetch_deviceinfo, 4501 uint32_t flags) 4502{ 4503 drmDevicePtr dev; 4504 char *ptr; 4505 int ret; 4506 4507 dev = drmDeviceAlloc(node_type, node, sizeof(drmPlatformBusInfo), 4508 sizeof(drmPlatformDeviceInfo), &ptr); 4509 if (!dev) 4510 return -ENOMEM; 4511 4512 dev->bustype = DRM_BUS_PLATFORM; 4513 4514 dev->businfo.platform = (drmPlatformBusInfoPtr)ptr; 4515 4516 ret = drmParseOFBusInfo(maj, min, dev->businfo.platform->fullname); 4517 if (ret < 0) 4518 goto free_device; 4519 4520 if (fetch_deviceinfo) { 4521 ptr += sizeof(drmPlatformBusInfo); 4522 dev->deviceinfo.platform = (drmPlatformDeviceInfoPtr)ptr; 4523 4524 ret = drmParseOFDeviceInfo(maj, min, &dev->deviceinfo.platform->compatible); 4525 if (ret < 0) 4526 goto free_device; 4527 } 4528 4529 *device = dev; 4530 4531 return 0; 4532 4533free_device: 4534 free(dev); 4535 return ret; 4536} 4537 4538static int drmProcessHost1xDevice(drmDevicePtr *device, 4539 const char *node, int node_type, 4540 int maj, int min, bool fetch_deviceinfo, 4541 uint32_t flags) 4542{ 4543 drmDevicePtr dev; 4544 char *ptr; 4545 int ret; 4546 4547 dev = drmDeviceAlloc(node_type, node, sizeof(drmHost1xBusInfo), 4548 sizeof(drmHost1xDeviceInfo), &ptr); 4549 if (!dev) 4550 return -ENOMEM; 4551 4552 dev->bustype = DRM_BUS_HOST1X; 4553 4554 dev->businfo.host1x = (drmHost1xBusInfoPtr)ptr; 4555 4556 ret = drmParseOFBusInfo(maj, min, dev->businfo.host1x->fullname); 4557 if (ret < 0) 4558 goto free_device; 4559 4560 if (fetch_deviceinfo) { 4561 ptr += sizeof(drmHost1xBusInfo); 4562 dev->deviceinfo.host1x = (drmHost1xDeviceInfoPtr)ptr; 4563 4564 ret = drmParseOFDeviceInfo(maj, min, &dev->deviceinfo.host1x->compatible); 4565 if (ret < 0) 4566 goto free_device; 4567 } 4568 4569 *device = dev; 4570 4571 return 0; 4572 4573free_device: 4574 free(dev); 4575 return ret; 4576} 4577 4578static int 4579process_device(drmDevicePtr *device, const char *d_name, 4580 int req_subsystem_type, 4581 bool fetch_deviceinfo, uint32_t flags) 4582{ 4583 struct stat sbuf; 4584 char node[PATH_MAX + 1]; 4585 int node_type, subsystem_type; 4586 unsigned int maj, min; 4587 4588 node_type = drmGetNodeType(d_name); 4589 if (node_type < 0) 4590 return -1; 4591 4592 snprintf(node, PATH_MAX, "%s/%s", DRM_DIR_NAME, d_name); 4593 if (stat(node, &sbuf)) 4594 return -1; 4595 4596 maj = major(sbuf.st_rdev); 4597 min = minor(sbuf.st_rdev); 4598 4599 if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode)) 4600 return -1; 4601 4602 subsystem_type = drmParseSubsystemType(maj, min); 4603 if (req_subsystem_type != -1 && req_subsystem_type != subsystem_type) 4604 return -1; 4605 4606 switch (subsystem_type) { 4607 case DRM_BUS_PCI: 4608 case DRM_BUS_VIRTIO: 4609 return drmProcessPciDevice(device, node, node_type, maj, min, 4610 fetch_deviceinfo, flags); 4611 case DRM_BUS_USB: 4612 return drmProcessUsbDevice(device, node, node_type, maj, min, 4613 fetch_deviceinfo, flags); 4614 case DRM_BUS_PLATFORM: 4615 return drmProcessPlatformDevice(device, node, node_type, maj, min, 4616 fetch_deviceinfo, flags); 4617 case DRM_BUS_HOST1X: 4618 return drmProcessHost1xDevice(device, node, node_type, maj, min, 4619 fetch_deviceinfo, flags); 4620 default: 4621 return -1; 4622 } 4623} 4624 4625/* Consider devices located on the same bus as duplicate and fold the respective 4626 * entries into a single one. 4627 * 4628 * Note: this leaves "gaps" in the array, while preserving the length. 4629 */ 4630static void drmFoldDuplicatedDevices(drmDevicePtr local_devices[], int count) 4631{ 4632 int node_type, i, j; 4633 4634 for (i = 0; i < count; i++) { 4635 for (j = i + 1; j < count; j++) { 4636 if (drmDevicesEqual(local_devices[i], local_devices[j])) { 4637 local_devices[i]->available_nodes |= local_devices[j]->available_nodes; 4638 node_type = log2_int(local_devices[j]->available_nodes); 4639 memcpy(local_devices[i]->nodes[node_type], 4640 local_devices[j]->nodes[node_type], drmGetMaxNodeName()); 4641 drmFreeDevice(&local_devices[j]); 4642 } 4643 } 4644 } 4645} 4646 4647/* Check that the given flags are valid returning 0 on success */ 4648static int 4649drm_device_validate_flags(uint32_t flags) 4650{ 4651 return (flags & ~DRM_DEVICE_GET_PCI_REVISION); 4652} 4653 4654static bool 4655drm_device_has_rdev(drmDevicePtr device, dev_t find_rdev) 4656{ 4657 struct stat sbuf; 4658 4659 for (int i = 0; i < DRM_NODE_MAX; i++) { 4660 if (device->available_nodes & 1 << i) { 4661 if (stat(device->nodes[i], &sbuf) == 0 && 4662 sbuf.st_rdev == find_rdev) 4663 return true; 4664 } 4665 } 4666 return false; 4667} 4668 4669/* 4670 * The kernel drm core has a number of places that assume maximum of 4671 * 3x64 devices nodes. That's 64 for each of primary, control and 4672 * render nodes. Rounded it up to 256 for simplicity. 4673 */ 4674#define MAX_DRM_NODES 256 4675 4676/** 4677 * Get information about a device from its dev_t identifier 4678 * 4679 * \param find_rdev dev_t identifier of the device 4680 * \param flags feature/behaviour bitmask 4681 * \param device the address of a drmDevicePtr where the information 4682 * will be allocated in stored 4683 * 4684 * \return zero on success, negative error code otherwise. 4685 */ 4686drm_public int drmGetDeviceFromDevId(dev_t find_rdev, uint32_t flags, drmDevicePtr *device) 4687{ 4688#ifdef __OpenBSD__ 4689 /* 4690 * DRI device nodes on OpenBSD are not in their own directory, they reside 4691 * in /dev along with a large number of statically generated /dev nodes. 4692 * Avoid stat'ing all of /dev needlessly by implementing this custom path. 4693 */ 4694 drmDevicePtr d; 4695 char node[PATH_MAX + 1]; 4696 const char *dev_name; 4697 int node_type, subsystem_type; 4698 int maj, min, n, ret; 4699 4700 if (device == NULL) 4701 return -EINVAL; 4702 4703 maj = major(find_rdev); 4704 min = minor(find_rdev); 4705 4706 if (!drmNodeIsDRM(maj, min)) 4707 return -EINVAL; 4708 4709 node_type = drmGetMinorType(maj, min); 4710 if (node_type == -1) 4711 return -ENODEV; 4712 4713 dev_name = drmGetDeviceName(node_type); 4714 if (!dev_name) 4715 return -EINVAL; 4716 4717 n = snprintf(node, PATH_MAX, dev_name, DRM_DIR_NAME, min); 4718 if (n == -1 || n >= PATH_MAX) 4719 return -errno; 4720 if (stat(node, &sbuf)) 4721 return -EINVAL; 4722 4723 subsystem_type = drmParseSubsystemType(maj, min); 4724 if (subsystem_type != DRM_BUS_PCI) 4725 return -ENODEV; 4726 4727 ret = drmProcessPciDevice(&d, node, node_type, maj, min, true, flags); 4728 if (ret) 4729 return ret; 4730 4731 *device = d; 4732 4733 return 0; 4734#else 4735 drmDevicePtr local_devices[MAX_DRM_NODES]; 4736 drmDevicePtr d; 4737 DIR *sysdir; 4738 struct dirent *dent; 4739 int subsystem_type; 4740 int maj, min; 4741 int ret, i, node_count; 4742 4743 if (drm_device_validate_flags(flags)) 4744 return -EINVAL; 4745 4746 if (device == NULL) 4747 return -EINVAL; 4748 4749 maj = major(find_rdev); 4750 min = minor(find_rdev); 4751 4752 if (!drmNodeIsDRM(maj, min)) 4753 return -EINVAL; 4754 4755 subsystem_type = drmParseSubsystemType(maj, min); 4756 if (subsystem_type < 0) 4757 return subsystem_type; 4758 4759 sysdir = opendir(DRM_DIR_NAME); 4760 if (!sysdir) 4761 return -errno; 4762 4763 i = 0; 4764 while ((dent = readdir(sysdir))) { 4765 ret = process_device(&d, dent->d_name, subsystem_type, true, flags); 4766 if (ret) 4767 continue; 4768 4769 if (i >= MAX_DRM_NODES) { 4770 fprintf(stderr, "More than %d drm nodes detected. " 4771 "Please report a bug - that should not happen.\n" 4772 "Skipping extra nodes\n", MAX_DRM_NODES); 4773 break; 4774 } 4775 local_devices[i] = d; 4776 i++; 4777 } 4778 node_count = i; 4779 4780 drmFoldDuplicatedDevices(local_devices, node_count); 4781 4782 *device = NULL; 4783 4784 for (i = 0; i < node_count; i++) { 4785 if (!local_devices[i]) 4786 continue; 4787 4788 if (drm_device_has_rdev(local_devices[i], find_rdev)) 4789 *device = local_devices[i]; 4790 else 4791 drmFreeDevice(&local_devices[i]); 4792 } 4793 4794 closedir(sysdir); 4795 if (*device == NULL) 4796 return -ENODEV; 4797 return 0; 4798#endif 4799} 4800 4801/** 4802 * Get information about the opened drm device 4803 * 4804 * \param fd file descriptor of the drm device 4805 * \param flags feature/behaviour bitmask 4806 * \param device the address of a drmDevicePtr where the information 4807 * will be allocated in stored 4808 * 4809 * \return zero on success, negative error code otherwise. 4810 * 4811 * \note Unlike drmGetDevice it does not retrieve the pci device revision field 4812 * unless the DRM_DEVICE_GET_PCI_REVISION \p flag is set. 4813 */ 4814drm_public int drmGetDevice2(int fd, uint32_t flags, drmDevicePtr *device) 4815{ 4816 struct stat sbuf; 4817 4818 if (fd == -1) 4819 return -EINVAL; 4820 4821 if (fstat(fd, &sbuf)) 4822 return -errno; 4823 4824 if (!S_ISCHR(sbuf.st_mode)) 4825 return -EINVAL; 4826 4827 return drmGetDeviceFromDevId(sbuf.st_rdev, flags, device); 4828} 4829 4830/** 4831 * Get information about the opened drm device 4832 * 4833 * \param fd file descriptor of the drm device 4834 * \param device the address of a drmDevicePtr where the information 4835 * will be allocated in stored 4836 * 4837 * \return zero on success, negative error code otherwise. 4838 */ 4839drm_public int drmGetDevice(int fd, drmDevicePtr *device) 4840{ 4841 return drmGetDevice2(fd, DRM_DEVICE_GET_PCI_REVISION, device); 4842} 4843 4844/** 4845 * Get drm devices on the system 4846 * 4847 * \param flags feature/behaviour bitmask 4848 * \param devices the array of devices with drmDevicePtr elements 4849 * can be NULL to get the device number first 4850 * \param max_devices the maximum number of devices for the array 4851 * 4852 * \return on error - negative error code, 4853 * if devices is NULL - total number of devices available on the system, 4854 * alternatively the number of devices stored in devices[], which is 4855 * capped by the max_devices. 4856 * 4857 * \note Unlike drmGetDevices it does not retrieve the pci device revision field 4858 * unless the DRM_DEVICE_GET_PCI_REVISION \p flag is set. 4859 */ 4860drm_public int drmGetDevices2(uint32_t flags, drmDevicePtr devices[], 4861 int max_devices) 4862{ 4863 drmDevicePtr local_devices[MAX_DRM_NODES]; 4864 drmDevicePtr device; 4865 DIR *sysdir; 4866 struct dirent *dent; 4867 int ret, i, node_count, device_count; 4868 4869 if (drm_device_validate_flags(flags)) 4870 return -EINVAL; 4871 4872 sysdir = opendir(DRM_DIR_NAME); 4873 if (!sysdir) 4874 return -errno; 4875 4876 i = 0; 4877 while ((dent = readdir(sysdir))) { 4878 ret = process_device(&device, dent->d_name, -1, devices != NULL, flags); 4879 if (ret) 4880 continue; 4881 4882 if (i >= MAX_DRM_NODES) { 4883 fprintf(stderr, "More than %d drm nodes detected. " 4884 "Please report a bug - that should not happen.\n" 4885 "Skipping extra nodes\n", MAX_DRM_NODES); 4886 break; 4887 } 4888 local_devices[i] = device; 4889 i++; 4890 } 4891 node_count = i; 4892 4893 drmFoldDuplicatedDevices(local_devices, node_count); 4894 4895 device_count = 0; 4896 for (i = 0; i < node_count; i++) { 4897 if (!local_devices[i]) 4898 continue; 4899 4900 if ((devices != NULL) && (device_count < max_devices)) 4901 devices[device_count] = local_devices[i]; 4902 else 4903 drmFreeDevice(&local_devices[i]); 4904 4905 device_count++; 4906 } 4907 4908 closedir(sysdir); 4909 4910 if (devices != NULL) 4911 return MIN2(device_count, max_devices); 4912 4913 return device_count; 4914} 4915 4916/** 4917 * Get drm devices on the system 4918 * 4919 * \param devices the array of devices with drmDevicePtr elements 4920 * can be NULL to get the device number first 4921 * \param max_devices the maximum number of devices for the array 4922 * 4923 * \return on error - negative error code, 4924 * if devices is NULL - total number of devices available on the system, 4925 * alternatively the number of devices stored in devices[], which is 4926 * capped by the max_devices. 4927 */ 4928drm_public int drmGetDevices(drmDevicePtr devices[], int max_devices) 4929{ 4930 return drmGetDevices2(DRM_DEVICE_GET_PCI_REVISION, devices, max_devices); 4931} 4932 4933drm_public char *drmGetDeviceNameFromFd2(int fd) 4934{ 4935#ifdef __linux__ 4936 struct stat sbuf; 4937 char path[PATH_MAX + 1], *value; 4938 unsigned int maj, min; 4939 4940 if (fstat(fd, &sbuf)) 4941 return NULL; 4942 4943 maj = major(sbuf.st_rdev); 4944 min = minor(sbuf.st_rdev); 4945 4946 if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode)) 4947 return NULL; 4948 4949 snprintf(path, sizeof(path), "/sys/dev/char/%d:%d", maj, min); 4950 4951 value = sysfs_uevent_get(path, "DEVNAME"); 4952 if (!value) 4953 return NULL; 4954 4955 snprintf(path, sizeof(path), "/dev/%s", value); 4956 free(value); 4957 4958 return strdup(path); 4959#elif defined(__FreeBSD__) 4960 return drmGetDeviceNameFromFd(fd); 4961#else 4962 struct stat sbuf; 4963 char node[PATH_MAX + 1]; 4964 const char *dev_name; 4965 int node_type; 4966 int maj, min, n; 4967 4968 if (fstat(fd, &sbuf)) 4969 return NULL; 4970 4971 maj = major(sbuf.st_rdev); 4972 min = minor(sbuf.st_rdev); 4973 4974 if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode)) 4975 return NULL; 4976 4977 node_type = drmGetMinorType(maj, min); 4978 if (node_type == -1) 4979 return NULL; 4980 4981 dev_name = drmGetDeviceName(node_type); 4982 if (!dev_name) 4983 return NULL; 4984 4985 n = snprintf(node, PATH_MAX, dev_name, DRM_DIR_NAME, min); 4986 if (n == -1 || n >= PATH_MAX) 4987 return NULL; 4988 4989 return strdup(node); 4990#endif 4991} 4992 4993drm_public int drmSyncobjCreate(int fd, uint32_t flags, uint32_t *handle) 4994{ 4995 struct drm_syncobj_create args; 4996 int ret; 4997 4998 memclear(args); 4999 args.flags = flags; 5000 args.handle = 0; 5001 ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_CREATE, &args); 5002 if (ret) 5003 return ret; 5004 *handle = args.handle; 5005 return 0; 5006} 5007 5008drm_public int drmSyncobjDestroy(int fd, uint32_t handle) 5009{ 5010 struct drm_syncobj_destroy args; 5011 5012 memclear(args); 5013 args.handle = handle; 5014 return drmIoctl(fd, DRM_IOCTL_SYNCOBJ_DESTROY, &args); 5015} 5016 5017drm_public int drmSyncobjHandleToFD(int fd, uint32_t handle, int *obj_fd) 5018{ 5019 struct drm_syncobj_handle args; 5020 int ret; 5021 5022 memclear(args); 5023 args.fd = -1; 5024 args.handle = handle; 5025 ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD, &args); 5026 if (ret) 5027 return ret; 5028 *obj_fd = args.fd; 5029 return 0; 5030} 5031 5032drm_public int drmSyncobjFDToHandle(int fd, int obj_fd, uint32_t *handle) 5033{ 5034 struct drm_syncobj_handle args; 5035 int ret; 5036 5037 memclear(args); 5038 args.fd = obj_fd; 5039 args.handle = 0; 5040 ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE, &args); 5041 if (ret) 5042 return ret; 5043 *handle = args.handle; 5044 return 0; 5045} 5046 5047drm_public int drmSyncobjImportSyncFile(int fd, uint32_t handle, 5048 int sync_file_fd) 5049{ 5050 struct drm_syncobj_handle args; 5051 5052 memclear(args); 5053 args.fd = sync_file_fd; 5054 args.handle = handle; 5055 args.flags = DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_IMPORT_SYNC_FILE; 5056 return drmIoctl(fd, DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE, &args); 5057} 5058 5059drm_public int drmSyncobjExportSyncFile(int fd, uint32_t handle, 5060 int *sync_file_fd) 5061{ 5062 struct drm_syncobj_handle args; 5063 int ret; 5064 5065 memclear(args); 5066 args.fd = -1; 5067 args.handle = handle; 5068 args.flags = DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_EXPORT_SYNC_FILE; 5069 ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD, &args); 5070 if (ret) 5071 return ret; 5072 *sync_file_fd = args.fd; 5073 return 0; 5074} 5075 5076drm_public int drmSyncobjWait(int fd, uint32_t *handles, unsigned num_handles, 5077 int64_t timeout_nsec, unsigned flags, 5078 uint32_t *first_signaled) 5079{ 5080 struct drm_syncobj_wait args; 5081 int ret; 5082 5083 memclear(args); 5084 args.handles = (uintptr_t)handles; 5085 args.timeout_nsec = timeout_nsec; 5086 args.count_handles = num_handles; 5087 args.flags = flags; 5088 5089 ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_WAIT, &args); 5090 if (ret < 0) 5091 return -errno; 5092 5093 if (first_signaled) 5094 *first_signaled = args.first_signaled; 5095 return ret; 5096} 5097 5098drm_public int drmSyncobjReset(int fd, const uint32_t *handles, 5099 uint32_t handle_count) 5100{ 5101 struct drm_syncobj_array args; 5102 int ret; 5103 5104 memclear(args); 5105 args.handles = (uintptr_t)handles; 5106 args.count_handles = handle_count; 5107 5108 ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_RESET, &args); 5109 return ret; 5110} 5111 5112drm_public int drmSyncobjSignal(int fd, const uint32_t *handles, 5113 uint32_t handle_count) 5114{ 5115 struct drm_syncobj_array args; 5116 int ret; 5117 5118 memclear(args); 5119 args.handles = (uintptr_t)handles; 5120 args.count_handles = handle_count; 5121 5122 ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_SIGNAL, &args); 5123 return ret; 5124} 5125 5126drm_public int drmSyncobjTimelineSignal(int fd, const uint32_t *handles, 5127 uint64_t *points, uint32_t handle_count) 5128{ 5129 struct drm_syncobj_timeline_array args; 5130 int ret; 5131 5132 memclear(args); 5133 args.handles = (uintptr_t)handles; 5134 args.points = (uintptr_t)points; 5135 args.count_handles = handle_count; 5136 5137 ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_TIMELINE_SIGNAL, &args); 5138 return ret; 5139} 5140 5141drm_public int drmSyncobjTimelineWait(int fd, uint32_t *handles, uint64_t *points, 5142 unsigned num_handles, 5143 int64_t timeout_nsec, unsigned flags, 5144 uint32_t *first_signaled) 5145{ 5146 struct drm_syncobj_timeline_wait args; 5147 int ret; 5148 5149 memclear(args); 5150 args.handles = (uintptr_t)handles; 5151 args.points = (uintptr_t)points; 5152 args.timeout_nsec = timeout_nsec; 5153 args.count_handles = num_handles; 5154 args.flags = flags; 5155 5156 ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_TIMELINE_WAIT, &args); 5157 if (ret < 0) 5158 return -errno; 5159 5160 if (first_signaled) 5161 *first_signaled = args.first_signaled; 5162 return ret; 5163} 5164 5165 5166drm_public int drmSyncobjQuery(int fd, uint32_t *handles, uint64_t *points, 5167 uint32_t handle_count) 5168{ 5169 struct drm_syncobj_timeline_array args; 5170 int ret; 5171 5172 memclear(args); 5173 args.handles = (uintptr_t)handles; 5174 args.points = (uintptr_t)points; 5175 args.count_handles = handle_count; 5176 5177 ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_QUERY, &args); 5178 if (ret) 5179 return ret; 5180 return 0; 5181} 5182 5183drm_public int drmSyncobjQuery2(int fd, uint32_t *handles, uint64_t *points, 5184 uint32_t handle_count, uint32_t flags) 5185{ 5186 struct drm_syncobj_timeline_array args; 5187 5188 memclear(args); 5189 args.handles = (uintptr_t)handles; 5190 args.points = (uintptr_t)points; 5191 args.count_handles = handle_count; 5192 args.flags = flags; 5193 5194 return drmIoctl(fd, DRM_IOCTL_SYNCOBJ_QUERY, &args); 5195} 5196 5197 5198drm_public int drmSyncobjTransfer(int fd, 5199 uint32_t dst_handle, uint64_t dst_point, 5200 uint32_t src_handle, uint64_t src_point, 5201 uint32_t flags) 5202{ 5203 struct drm_syncobj_transfer args; 5204 int ret; 5205 5206 memclear(args); 5207 args.src_handle = src_handle; 5208 args.dst_handle = dst_handle; 5209 args.src_point = src_point; 5210 args.dst_point = dst_point; 5211 args.flags = flags; 5212 5213 ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_TRANSFER, &args); 5214 5215 return ret; 5216} 5217 5218static char * 5219drmGetFormatModifierFromSimpleTokens(uint64_t modifier) 5220{ 5221 unsigned int i; 5222 5223 for (i = 0; i < ARRAY_SIZE(drm_format_modifier_table); i++) { 5224 if (drm_format_modifier_table[i].modifier == modifier) 5225 return strdup(drm_format_modifier_table[i].modifier_name); 5226 } 5227 5228 return NULL; 5229} 5230 5231/** Retrieves a human-readable representation of a vendor (as a string) from 5232 * the format token modifier 5233 * 5234 * \param modifier the format modifier token 5235 * \return a char pointer to the human-readable form of the vendor. Caller is 5236 * responsible for freeing it. 5237 */ 5238drm_public char * 5239drmGetFormatModifierVendor(uint64_t modifier) 5240{ 5241 unsigned int i; 5242 uint8_t vendor = fourcc_mod_get_vendor(modifier); 5243 5244 for (i = 0; i < ARRAY_SIZE(drm_format_modifier_vendor_table); i++) { 5245 if (drm_format_modifier_vendor_table[i].vendor == vendor) 5246 return strdup(drm_format_modifier_vendor_table[i].vendor_name); 5247 } 5248 5249 return NULL; 5250} 5251 5252/** Retrieves a human-readable representation string from a format token 5253 * modifier 5254 * 5255 * If the dedicated function was not able to extract a valid name or searching 5256 * the format modifier was not in the table, this function would return NULL. 5257 * 5258 * \param modifier the token format 5259 * \return a malloc'ed string representation of the modifier. Caller is 5260 * responsible for freeing the string returned. 5261 * 5262 */ 5263drm_public char * 5264drmGetFormatModifierName(uint64_t modifier) 5265{ 5266 uint8_t vendorid = fourcc_mod_get_vendor(modifier); 5267 char *modifier_found = NULL; 5268 unsigned int i; 5269 5270 for (i = 0; i < ARRAY_SIZE(modifier_format_vendor_table); i++) { 5271 if (modifier_format_vendor_table[i].vendor == vendorid) 5272 modifier_found = modifier_format_vendor_table[i].vendor_cb(modifier); 5273 } 5274 5275 if (!modifier_found) 5276 return drmGetFormatModifierFromSimpleTokens(modifier); 5277 5278 return modifier_found; 5279} 5280 5281/** 5282 * Get a human-readable name for a DRM FourCC format. 5283 * 5284 * \param format The format. 5285 * \return A malloc'ed string containing the format name. Caller is responsible 5286 * for freeing it. 5287 */ 5288drm_public char * 5289drmGetFormatName(uint32_t format) 5290{ 5291 char *str, code[5]; 5292 const char *be; 5293 size_t str_size, i; 5294 5295 be = (format & DRM_FORMAT_BIG_ENDIAN) ? "_BE" : ""; 5296 format &= ~DRM_FORMAT_BIG_ENDIAN; 5297 5298 if (format == DRM_FORMAT_INVALID) 5299 return strdup("INVALID"); 5300 5301 code[0] = (char) ((format >> 0) & 0xFF); 5302 code[1] = (char) ((format >> 8) & 0xFF); 5303 code[2] = (char) ((format >> 16) & 0xFF); 5304 code[3] = (char) ((format >> 24) & 0xFF); 5305 code[4] = '\0'; 5306 5307 /* Trim spaces at the end */ 5308 for (i = 3; i > 0 && code[i] == ' '; i--) 5309 code[i] = '\0'; 5310 5311 str_size = strlen(code) + strlen(be) + 1; 5312 str = malloc(str_size); 5313 if (!str) 5314 return NULL; 5315 5316 snprintf(str, str_size, "%s%s", code, be); 5317 5318 return str; 5319} 5320