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