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