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