xf86drm.c revision adfa0b0c
122944501Smrg/** 2fe517fc9Smrg * \file xf86drm.c 322944501Smrg * User-level interface to DRM device 422944501Smrg * 522944501Smrg * \author Rickard E. (Rik) Faith <faith@valinux.com> 622944501Smrg * \author Kevin E. Martin <martin@valinux.com> 722944501Smrg */ 822944501Smrg 922944501Smrg/* 1022944501Smrg * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. 1122944501Smrg * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. 1222944501Smrg * All Rights Reserved. 1322944501Smrg * 1422944501Smrg * Permission is hereby granted, free of charge, to any person obtaining a 1522944501Smrg * copy of this software and associated documentation files (the "Software"), 1622944501Smrg * to deal in the Software without restriction, including without limitation 1722944501Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 1822944501Smrg * and/or sell copies of the Software, and to permit persons to whom the 1922944501Smrg * Software is furnished to do so, subject to the following conditions: 2022944501Smrg * 2122944501Smrg * The above copyright notice and this permission notice (including the next 2222944501Smrg * paragraph) shall be included in all copies or substantial portions of the 2322944501Smrg * Software. 2422944501Smrg * 2522944501Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 2622944501Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 2722944501Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 2822944501Smrg * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 2922944501Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 3022944501Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 3122944501Smrg * DEALINGS IN THE SOFTWARE. 3222944501Smrg */ 3322944501Smrg 3422944501Smrg#include <stdio.h> 3522944501Smrg#include <stdlib.h> 36fe517fc9Smrg#include <stdbool.h> 3722944501Smrg#include <unistd.h> 3822944501Smrg#include <string.h> 3922944501Smrg#include <strings.h> 4022944501Smrg#include <ctype.h> 41424e9256Smrg#include <dirent.h> 42424e9256Smrg#include <stddef.h> 4322944501Smrg#include <fcntl.h> 4422944501Smrg#include <errno.h> 45fe517fc9Smrg#include <limits.h> 4622944501Smrg#include <signal.h> 4722944501Smrg#include <time.h> 4822944501Smrg#include <sys/types.h> 4922944501Smrg#include <sys/stat.h> 5022944501Smrg#define stat_t struct stat 5122944501Smrg#include <sys/ioctl.h> 5222944501Smrg#include <sys/time.h> 5322944501Smrg#include <stdarg.h> 54fe517fc9Smrg#ifdef MAJOR_IN_MKDEV 55fe517fc9Smrg#include <sys/mkdev.h> 56424e9256Smrg#endif 57fe517fc9Smrg#ifdef MAJOR_IN_SYSMACROS 58fe517fc9Smrg#include <sys/sysmacros.h> 59fe517fc9Smrg#endif 6087bf8e7cSmrg#if HAVE_SYS_SYSCTL_H 6187bf8e7cSmrg#include <sys/sysctl.h> 6287bf8e7cSmrg#endif 63fe517fc9Smrg#include <math.h> 64636d5e9fSmrg#include <inttypes.h> 6522944501Smrg 6687bf8e7cSmrg#if defined(__FreeBSD__) 6787bf8e7cSmrg#include <sys/param.h> 6887bf8e7cSmrg#include <sys/pciio.h> 6987bf8e7cSmrg#endif 7087bf8e7cSmrg 714545e80cSmrg#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) 724545e80cSmrg 732ee35494Smrg/* Not all systems have MAP_FAILED defined */ 742ee35494Smrg#ifndef MAP_FAILED 752ee35494Smrg#define MAP_FAILED ((void *)-1) 762ee35494Smrg#endif 7722944501Smrg 7822944501Smrg#include "xf86drm.h" 79424e9256Smrg#include "libdrm_macros.h" 80636d5e9fSmrg#include "drm_fourcc.h" 8122944501Smrg 82fe517fc9Smrg#include "util_math.h" 83fe517fc9Smrg 8487bf8e7cSmrg#ifdef __DragonFly__ 8522944501Smrg#define DRM_MAJOR 145 8622944501Smrg#endif 8722944501Smrg 8822944501Smrg#ifdef __NetBSD__ 892e6867f6Smrg#undef DRM_MAJOR 902e6867f6Smrg#define DRM_MAJOR 180 9106815bcbSmaya#include <sys/param.h> 92a970b457Sriastradh#include <dev/pci/pcireg.h> 93a970b457Sriastradh#include <pci.h> 9422944501Smrg#endif 9522944501Smrg 96fe517fc9Smrg#ifdef __OpenBSD__ 97fe517fc9Smrg#ifdef __i386__ 98fe517fc9Smrg#define DRM_MAJOR 88 99fe517fc9Smrg#else 100fe517fc9Smrg#define DRM_MAJOR 87 10122944501Smrg#endif 102fe517fc9Smrg#endif /* __OpenBSD__ */ 10322944501Smrg 104fe517fc9Smrg#ifndef DRM_MAJOR 105fe517fc9Smrg#define DRM_MAJOR 226 /* Linux */ 10622944501Smrg#endif 10722944501Smrg 1084545e80cSmrg#if defined(__OpenBSD__) || defined(__DragonFly__) 1092ee35494Smrgstruct drm_pciinfo { 1102ee35494Smrg uint16_t domain; 1112ee35494Smrg uint8_t bus; 1122ee35494Smrg uint8_t dev; 1132ee35494Smrg uint8_t func; 1142ee35494Smrg uint16_t vendor_id; 1152ee35494Smrg uint16_t device_id; 1162ee35494Smrg uint16_t subvendor_id; 1172ee35494Smrg uint16_t subdevice_id; 1182ee35494Smrg uint8_t revision_id; 1192ee35494Smrg}; 1202ee35494Smrg 1212ee35494Smrg#define DRM_IOCTL_GET_PCIINFO DRM_IOR(0x15, struct drm_pciinfo) 12211c53d23Schristos#endif 12311c53d23Schristos 12422944501Smrg#define DRM_MSG_VERBOSITY 3 12522944501Smrg 126424e9256Smrg#define memclear(s) memset(&s, 0, sizeof(s)) 12722944501Smrg 12822944501Smrgstatic drmServerInfoPtr drm_server_info; 12922944501Smrg 13087bf8e7cSmrgstatic bool drmNodeIsDRM(int maj, int min); 13187bf8e7cSmrgstatic char *drmGetMinorNameForFD(int fd, int type); 13287bf8e7cSmrg 133636d5e9fSmrg#define DRM_MODIFIER(v, f, f_name) \ 134636d5e9fSmrg .modifier = DRM_FORMAT_MOD_##v ## _ ##f, \ 135636d5e9fSmrg .modifier_name = #f_name 136636d5e9fSmrg 137636d5e9fSmrg#define DRM_MODIFIER_INVALID(v, f_name) \ 138636d5e9fSmrg .modifier = DRM_FORMAT_MOD_INVALID, .modifier_name = #f_name 139636d5e9fSmrg 140636d5e9fSmrg#define DRM_MODIFIER_LINEAR(v, f_name) \ 141636d5e9fSmrg .modifier = DRM_FORMAT_MOD_LINEAR, .modifier_name = #f_name 142636d5e9fSmrg 143636d5e9fSmrg/* Intel is abit special as the format doesn't follow other vendors naming 144636d5e9fSmrg * scheme */ 145636d5e9fSmrg#define DRM_MODIFIER_INTEL(f, f_name) \ 146636d5e9fSmrg .modifier = I915_FORMAT_MOD_##f, .modifier_name = #f_name 147636d5e9fSmrg 148636d5e9fSmrgstruct drmFormatModifierInfo { 149636d5e9fSmrg uint64_t modifier; 150636d5e9fSmrg const char *modifier_name; 151636d5e9fSmrg}; 152636d5e9fSmrg 153636d5e9fSmrgstruct drmFormatModifierVendorInfo { 154636d5e9fSmrg uint8_t vendor; 155636d5e9fSmrg const char *vendor_name; 156636d5e9fSmrg}; 157636d5e9fSmrg 158636d5e9fSmrg#include "generated_static_table_fourcc.h" 159636d5e9fSmrg 160636d5e9fSmrgstruct drmVendorInfo { 161636d5e9fSmrg uint8_t vendor; 162636d5e9fSmrg char *(*vendor_cb)(uint64_t modifier); 163636d5e9fSmrg}; 164636d5e9fSmrg 165636d5e9fSmrgstruct drmFormatVendorModifierInfo { 166636d5e9fSmrg uint64_t modifier; 167636d5e9fSmrg const char *modifier_name; 168636d5e9fSmrg}; 169636d5e9fSmrg 170636d5e9fSmrgstatic char * 171636d5e9fSmrgdrmGetFormatModifierNameFromArm(uint64_t modifier); 172636d5e9fSmrg 173636d5e9fSmrgstatic char * 174636d5e9fSmrgdrmGetFormatModifierNameFromNvidia(uint64_t modifier); 175636d5e9fSmrg 176636d5e9fSmrgstatic char * 177636d5e9fSmrgdrmGetFormatModifierNameFromAmd(uint64_t modifier); 178636d5e9fSmrg 179636d5e9fSmrgstatic char * 180636d5e9fSmrgdrmGetFormatModifierNameFromAmlogic(uint64_t modifier); 181636d5e9fSmrg 182636d5e9fSmrgstatic const struct drmVendorInfo modifier_format_vendor_table[] = { 183636d5e9fSmrg { DRM_FORMAT_MOD_VENDOR_ARM, drmGetFormatModifierNameFromArm }, 184636d5e9fSmrg { DRM_FORMAT_MOD_VENDOR_NVIDIA, drmGetFormatModifierNameFromNvidia }, 185636d5e9fSmrg { DRM_FORMAT_MOD_VENDOR_AMD, drmGetFormatModifierNameFromAmd }, 186636d5e9fSmrg { DRM_FORMAT_MOD_VENDOR_AMLOGIC, drmGetFormatModifierNameFromAmlogic }, 187636d5e9fSmrg}; 188636d5e9fSmrg 189636d5e9fSmrg#ifndef AFBC_FORMAT_MOD_MODE_VALUE_MASK 190636d5e9fSmrg#define AFBC_FORMAT_MOD_MODE_VALUE_MASK 0x000fffffffffffffULL 191636d5e9fSmrg#endif 192636d5e9fSmrg 193636d5e9fSmrgstatic const struct drmFormatVendorModifierInfo arm_mode_value_table[] = { 194636d5e9fSmrg { AFBC_FORMAT_MOD_YTR, "YTR" }, 195636d5e9fSmrg { AFBC_FORMAT_MOD_SPLIT, "SPLIT" }, 196636d5e9fSmrg { AFBC_FORMAT_MOD_SPARSE, "SPARSE" }, 197636d5e9fSmrg { AFBC_FORMAT_MOD_CBR, "CBR" }, 198636d5e9fSmrg { AFBC_FORMAT_MOD_TILED, "TILED" }, 199636d5e9fSmrg { AFBC_FORMAT_MOD_SC, "SC" }, 200636d5e9fSmrg { AFBC_FORMAT_MOD_DB, "DB" }, 201636d5e9fSmrg { AFBC_FORMAT_MOD_BCH, "BCH" }, 202636d5e9fSmrg { AFBC_FORMAT_MOD_USM, "USM" }, 203636d5e9fSmrg}; 204636d5e9fSmrg 205636d5e9fSmrgstatic bool is_x_t_amd_gfx9_tile(uint64_t tile) 206636d5e9fSmrg{ 207636d5e9fSmrg switch (tile) { 208636d5e9fSmrg case AMD_FMT_MOD_TILE_GFX9_64K_S_X: 209636d5e9fSmrg case AMD_FMT_MOD_TILE_GFX9_64K_D_X: 210636d5e9fSmrg case AMD_FMT_MOD_TILE_GFX9_64K_R_X: 211636d5e9fSmrg return true; 212636d5e9fSmrg } 213636d5e9fSmrg 214636d5e9fSmrg return false; 215636d5e9fSmrg} 216636d5e9fSmrg 217adfa0b0cSmrgstatic bool 218adfa0b0cSmrgdrmGetAfbcFormatModifierNameFromArm(uint64_t modifier, FILE *fp) 219636d5e9fSmrg{ 220636d5e9fSmrg uint64_t mode_value = modifier & AFBC_FORMAT_MOD_MODE_VALUE_MASK; 221636d5e9fSmrg uint64_t block_size = mode_value & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK; 222636d5e9fSmrg 223636d5e9fSmrg const char *block = NULL; 224636d5e9fSmrg const char *mode = NULL; 225636d5e9fSmrg bool did_print_mode = false; 226636d5e9fSmrg 227636d5e9fSmrg /* add block, can only have a (single) block */ 228636d5e9fSmrg switch (block_size) { 229636d5e9fSmrg case AFBC_FORMAT_MOD_BLOCK_SIZE_16x16: 230636d5e9fSmrg block = "16x16"; 231636d5e9fSmrg break; 232636d5e9fSmrg case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8: 233636d5e9fSmrg block = "32x8"; 234636d5e9fSmrg break; 235636d5e9fSmrg case AFBC_FORMAT_MOD_BLOCK_SIZE_64x4: 236636d5e9fSmrg block = "64x4"; 237636d5e9fSmrg break; 238636d5e9fSmrg case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8_64x4: 239636d5e9fSmrg block = "32x8_64x4"; 240636d5e9fSmrg break; 241636d5e9fSmrg } 242636d5e9fSmrg 243636d5e9fSmrg if (!block) { 244adfa0b0cSmrg return false; 245636d5e9fSmrg } 246636d5e9fSmrg 247636d5e9fSmrg fprintf(fp, "BLOCK_SIZE=%s,", block); 248636d5e9fSmrg 249636d5e9fSmrg /* add mode */ 250adfa0b0cSmrg for (unsigned int i = 0; i < ARRAY_SIZE(arm_mode_value_table); i++) { 251636d5e9fSmrg if (arm_mode_value_table[i].modifier & mode_value) { 252636d5e9fSmrg mode = arm_mode_value_table[i].modifier_name; 253636d5e9fSmrg if (!did_print_mode) { 254636d5e9fSmrg fprintf(fp, "MODE=%s", mode); 255636d5e9fSmrg did_print_mode = true; 256636d5e9fSmrg } else { 257636d5e9fSmrg fprintf(fp, "|%s", mode); 258636d5e9fSmrg } 259636d5e9fSmrg } 260636d5e9fSmrg } 261636d5e9fSmrg 262adfa0b0cSmrg return true; 263adfa0b0cSmrg} 264adfa0b0cSmrg 265adfa0b0cSmrgstatic bool 266adfa0b0cSmrgdrmGetAfrcFormatModifierNameFromArm(uint64_t modifier, FILE *fp) 267adfa0b0cSmrg{ 268adfa0b0cSmrg for (unsigned int i = 0; i < 2; ++i) { 269adfa0b0cSmrg uint64_t coding_unit_block = 270adfa0b0cSmrg (modifier >> (i * 4)) & AFRC_FORMAT_MOD_CU_SIZE_MASK; 271adfa0b0cSmrg const char *coding_unit_size = NULL; 272adfa0b0cSmrg 273adfa0b0cSmrg switch (coding_unit_block) { 274adfa0b0cSmrg case AFRC_FORMAT_MOD_CU_SIZE_16: 275adfa0b0cSmrg coding_unit_size = "CU_16"; 276adfa0b0cSmrg break; 277adfa0b0cSmrg case AFRC_FORMAT_MOD_CU_SIZE_24: 278adfa0b0cSmrg coding_unit_size = "CU_24"; 279adfa0b0cSmrg break; 280adfa0b0cSmrg case AFRC_FORMAT_MOD_CU_SIZE_32: 281adfa0b0cSmrg coding_unit_size = "CU_32"; 282adfa0b0cSmrg break; 283adfa0b0cSmrg } 284adfa0b0cSmrg 285adfa0b0cSmrg if (!coding_unit_size) { 286adfa0b0cSmrg if (i == 0) { 287adfa0b0cSmrg return false; 288adfa0b0cSmrg } 289adfa0b0cSmrg break; 290adfa0b0cSmrg } 291adfa0b0cSmrg 292adfa0b0cSmrg if (i == 0) { 293adfa0b0cSmrg fprintf(fp, "P0=%s,", coding_unit_size); 294adfa0b0cSmrg } else { 295adfa0b0cSmrg fprintf(fp, "P12=%s,", coding_unit_size); 296adfa0b0cSmrg } 297adfa0b0cSmrg } 298adfa0b0cSmrg 299adfa0b0cSmrg bool scan_layout = 300adfa0b0cSmrg (modifier & AFRC_FORMAT_MOD_LAYOUT_SCAN) == AFRC_FORMAT_MOD_LAYOUT_SCAN; 301adfa0b0cSmrg if (scan_layout) { 302adfa0b0cSmrg fprintf(fp, "SCAN"); 303adfa0b0cSmrg } else { 304adfa0b0cSmrg fprintf(fp, "ROT"); 305adfa0b0cSmrg } 306adfa0b0cSmrg return true; 307adfa0b0cSmrg} 308adfa0b0cSmrg 309adfa0b0cSmrgstatic char * 310adfa0b0cSmrgdrmGetFormatModifierNameFromArm(uint64_t modifier) 311adfa0b0cSmrg{ 312adfa0b0cSmrg uint64_t type = (modifier >> 52) & 0xf; 313adfa0b0cSmrg 314adfa0b0cSmrg FILE *fp; 315adfa0b0cSmrg size_t size = 0; 316adfa0b0cSmrg char *modifier_name = NULL; 317adfa0b0cSmrg bool result = false; 318adfa0b0cSmrg 319adfa0b0cSmrg fp = open_memstream(&modifier_name, &size); 320adfa0b0cSmrg if (!fp) 321adfa0b0cSmrg return NULL; 322adfa0b0cSmrg 323adfa0b0cSmrg switch (type) { 324adfa0b0cSmrg case DRM_FORMAT_MOD_ARM_TYPE_AFBC: 325adfa0b0cSmrg result = drmGetAfbcFormatModifierNameFromArm(modifier, fp); 326adfa0b0cSmrg break; 327adfa0b0cSmrg case DRM_FORMAT_MOD_ARM_TYPE_AFRC: 328adfa0b0cSmrg result = drmGetAfrcFormatModifierNameFromArm(modifier, fp); 329adfa0b0cSmrg break; 330adfa0b0cSmrg /* misc type is already handled by the static table */ 331adfa0b0cSmrg case DRM_FORMAT_MOD_ARM_TYPE_MISC: 332adfa0b0cSmrg default: 333adfa0b0cSmrg result = false; 334adfa0b0cSmrg break; 335adfa0b0cSmrg } 336adfa0b0cSmrg 337636d5e9fSmrg fclose(fp); 338adfa0b0cSmrg if (!result) { 339adfa0b0cSmrg free(modifier_name); 340adfa0b0cSmrg return NULL; 341adfa0b0cSmrg } 342adfa0b0cSmrg 343636d5e9fSmrg return modifier_name; 344636d5e9fSmrg} 345636d5e9fSmrg 346636d5e9fSmrgstatic char * 347636d5e9fSmrgdrmGetFormatModifierNameFromNvidia(uint64_t modifier) 348636d5e9fSmrg{ 349636d5e9fSmrg uint64_t height, kind, gen, sector, compression; 350636d5e9fSmrg 351636d5e9fSmrg height = modifier & 0xf; 352636d5e9fSmrg kind = (modifier >> 12) & 0xff; 353636d5e9fSmrg 354636d5e9fSmrg gen = (modifier >> 20) & 0x3; 355636d5e9fSmrg sector = (modifier >> 22) & 0x1; 356636d5e9fSmrg compression = (modifier >> 23) & 0x7; 357636d5e9fSmrg 358636d5e9fSmrg /* just in case there could other simpler modifiers, not yet added, avoid 359636d5e9fSmrg * testing against TEGRA_TILE */ 360636d5e9fSmrg if ((modifier & 0x10) == 0x10) { 361636d5e9fSmrg char *mod_nvidia; 362636d5e9fSmrg asprintf(&mod_nvidia, "BLOCK_LINEAR_2D,HEIGHT=%"PRIu64",KIND=%"PRIu64"," 363636d5e9fSmrg "GEN=%"PRIu64",SECTOR=%"PRIu64",COMPRESSION=%"PRIu64"", height, 364636d5e9fSmrg kind, gen, sector, compression); 365636d5e9fSmrg return mod_nvidia; 366636d5e9fSmrg } 367636d5e9fSmrg 368636d5e9fSmrg return NULL; 369636d5e9fSmrg} 370636d5e9fSmrg 371636d5e9fSmrgstatic void 372636d5e9fSmrgdrmGetFormatModifierNameFromAmdDcc(uint64_t modifier, FILE *fp) 373636d5e9fSmrg{ 374636d5e9fSmrg uint64_t dcc_max_compressed_block = 375636d5e9fSmrg AMD_FMT_MOD_GET(DCC_MAX_COMPRESSED_BLOCK, modifier); 376636d5e9fSmrg uint64_t dcc_retile = AMD_FMT_MOD_GET(DCC_RETILE, modifier); 377636d5e9fSmrg 378636d5e9fSmrg const char *dcc_max_compressed_block_str = NULL; 379636d5e9fSmrg 380636d5e9fSmrg fprintf(fp, ",DCC"); 381636d5e9fSmrg 382636d5e9fSmrg if (dcc_retile) 383636d5e9fSmrg fprintf(fp, ",DCC_RETILE"); 384636d5e9fSmrg 385636d5e9fSmrg if (!dcc_retile && AMD_FMT_MOD_GET(DCC_PIPE_ALIGN, modifier)) 386636d5e9fSmrg fprintf(fp, ",DCC_PIPE_ALIGN"); 387636d5e9fSmrg 388636d5e9fSmrg if (AMD_FMT_MOD_GET(DCC_INDEPENDENT_64B, modifier)) 389636d5e9fSmrg fprintf(fp, ",DCC_INDEPENDENT_64B"); 390636d5e9fSmrg 391636d5e9fSmrg if (AMD_FMT_MOD_GET(DCC_INDEPENDENT_128B, modifier)) 392636d5e9fSmrg fprintf(fp, ",DCC_INDEPENDENT_128B"); 393636d5e9fSmrg 394636d5e9fSmrg switch (dcc_max_compressed_block) { 395636d5e9fSmrg case AMD_FMT_MOD_DCC_BLOCK_64B: 396636d5e9fSmrg dcc_max_compressed_block_str = "64B"; 397636d5e9fSmrg break; 398636d5e9fSmrg case AMD_FMT_MOD_DCC_BLOCK_128B: 399636d5e9fSmrg dcc_max_compressed_block_str = "128B"; 400636d5e9fSmrg break; 401636d5e9fSmrg case AMD_FMT_MOD_DCC_BLOCK_256B: 402636d5e9fSmrg dcc_max_compressed_block_str = "256B"; 403636d5e9fSmrg break; 404636d5e9fSmrg } 405636d5e9fSmrg 406636d5e9fSmrg if (dcc_max_compressed_block_str) 407636d5e9fSmrg fprintf(fp, ",DCC_MAX_COMPRESSED_BLOCK=%s", 408636d5e9fSmrg dcc_max_compressed_block_str); 409636d5e9fSmrg 410636d5e9fSmrg if (AMD_FMT_MOD_GET(DCC_CONSTANT_ENCODE, modifier)) 411636d5e9fSmrg fprintf(fp, ",DCC_CONSTANT_ENCODE"); 412636d5e9fSmrg} 413636d5e9fSmrg 414636d5e9fSmrgstatic void 415636d5e9fSmrgdrmGetFormatModifierNameFromAmdTile(uint64_t modifier, FILE *fp) 416636d5e9fSmrg{ 417636d5e9fSmrg uint64_t pipe_xor_bits, bank_xor_bits, packers, rb; 418636d5e9fSmrg uint64_t pipe, pipe_align, dcc, dcc_retile, tile_version; 419636d5e9fSmrg 420636d5e9fSmrg pipe_align = AMD_FMT_MOD_GET(DCC_PIPE_ALIGN, modifier); 421636d5e9fSmrg pipe_xor_bits = AMD_FMT_MOD_GET(PIPE_XOR_BITS, modifier); 422636d5e9fSmrg dcc = AMD_FMT_MOD_GET(DCC, modifier); 423636d5e9fSmrg dcc_retile = AMD_FMT_MOD_GET(DCC_RETILE, modifier); 424636d5e9fSmrg tile_version = AMD_FMT_MOD_GET(TILE_VERSION, modifier); 425636d5e9fSmrg 426636d5e9fSmrg fprintf(fp, ",PIPE_XOR_BITS=%"PRIu64, pipe_xor_bits); 427636d5e9fSmrg 428636d5e9fSmrg if (tile_version == AMD_FMT_MOD_TILE_VER_GFX9) { 429636d5e9fSmrg bank_xor_bits = AMD_FMT_MOD_GET(BANK_XOR_BITS, modifier); 430636d5e9fSmrg fprintf(fp, ",BANK_XOR_BITS=%"PRIu64, bank_xor_bits); 431636d5e9fSmrg } 432636d5e9fSmrg 433636d5e9fSmrg if (tile_version == AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS) { 434636d5e9fSmrg packers = AMD_FMT_MOD_GET(PACKERS, modifier); 435636d5e9fSmrg fprintf(fp, ",PACKERS=%"PRIu64, packers); 436636d5e9fSmrg } 437636d5e9fSmrg 438636d5e9fSmrg if (dcc && tile_version == AMD_FMT_MOD_TILE_VER_GFX9) { 439636d5e9fSmrg rb = AMD_FMT_MOD_GET(RB, modifier); 440636d5e9fSmrg fprintf(fp, ",RB=%"PRIu64, rb); 441636d5e9fSmrg } 442636d5e9fSmrg 443636d5e9fSmrg if (dcc && tile_version == AMD_FMT_MOD_TILE_VER_GFX9 && 444636d5e9fSmrg (dcc_retile || pipe_align)) { 445636d5e9fSmrg pipe = AMD_FMT_MOD_GET(PIPE, modifier); 446636d5e9fSmrg fprintf(fp, ",PIPE_%"PRIu64, pipe); 447636d5e9fSmrg } 448636d5e9fSmrg} 449636d5e9fSmrg 450636d5e9fSmrgstatic char * 451636d5e9fSmrgdrmGetFormatModifierNameFromAmd(uint64_t modifier) 452636d5e9fSmrg{ 453636d5e9fSmrg uint64_t tile, tile_version, dcc; 454636d5e9fSmrg FILE *fp; 455636d5e9fSmrg char *mod_amd = NULL; 456636d5e9fSmrg size_t size = 0; 457636d5e9fSmrg 458636d5e9fSmrg const char *str_tile = NULL; 459636d5e9fSmrg const char *str_tile_version = NULL; 460636d5e9fSmrg 461636d5e9fSmrg tile = AMD_FMT_MOD_GET(TILE, modifier); 462636d5e9fSmrg tile_version = AMD_FMT_MOD_GET(TILE_VERSION, modifier); 463636d5e9fSmrg dcc = AMD_FMT_MOD_GET(DCC, modifier); 464636d5e9fSmrg 465636d5e9fSmrg fp = open_memstream(&mod_amd, &size); 466636d5e9fSmrg if (!fp) 467636d5e9fSmrg return NULL; 468636d5e9fSmrg 469636d5e9fSmrg /* add tile */ 470636d5e9fSmrg switch (tile_version) { 471636d5e9fSmrg case AMD_FMT_MOD_TILE_VER_GFX9: 472636d5e9fSmrg str_tile_version = "GFX9"; 473636d5e9fSmrg break; 474636d5e9fSmrg case AMD_FMT_MOD_TILE_VER_GFX10: 475636d5e9fSmrg str_tile_version = "GFX10"; 476636d5e9fSmrg break; 477636d5e9fSmrg case AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS: 478636d5e9fSmrg str_tile_version = "GFX10_RBPLUS"; 479636d5e9fSmrg break; 480636d5e9fSmrg } 481636d5e9fSmrg 482636d5e9fSmrg if (str_tile_version) { 483636d5e9fSmrg fprintf(fp, "%s", str_tile_version); 484636d5e9fSmrg } else { 485636d5e9fSmrg fclose(fp); 486636d5e9fSmrg free(mod_amd); 487636d5e9fSmrg return NULL; 488636d5e9fSmrg } 489636d5e9fSmrg 490636d5e9fSmrg /* add tile str */ 491636d5e9fSmrg switch (tile) { 492636d5e9fSmrg case AMD_FMT_MOD_TILE_GFX9_64K_S: 493636d5e9fSmrg str_tile = "GFX9_64K_S"; 494636d5e9fSmrg break; 495636d5e9fSmrg case AMD_FMT_MOD_TILE_GFX9_64K_D: 496636d5e9fSmrg str_tile = "GFX9_64K_D"; 497636d5e9fSmrg break; 498636d5e9fSmrg case AMD_FMT_MOD_TILE_GFX9_64K_S_X: 499636d5e9fSmrg str_tile = "GFX9_64K_S_X"; 500636d5e9fSmrg break; 501636d5e9fSmrg case AMD_FMT_MOD_TILE_GFX9_64K_D_X: 502636d5e9fSmrg str_tile = "GFX9_64K_D_X"; 503636d5e9fSmrg break; 504636d5e9fSmrg case AMD_FMT_MOD_TILE_GFX9_64K_R_X: 505636d5e9fSmrg str_tile = "GFX9_64K_R_X"; 506636d5e9fSmrg break; 507636d5e9fSmrg } 508636d5e9fSmrg 509636d5e9fSmrg if (str_tile) 510636d5e9fSmrg fprintf(fp, ",%s", str_tile); 511636d5e9fSmrg 512636d5e9fSmrg if (dcc) 513636d5e9fSmrg drmGetFormatModifierNameFromAmdDcc(modifier, fp); 514636d5e9fSmrg 515636d5e9fSmrg if (tile_version >= AMD_FMT_MOD_TILE_VER_GFX9 && is_x_t_amd_gfx9_tile(tile)) 516636d5e9fSmrg drmGetFormatModifierNameFromAmdTile(modifier, fp); 517636d5e9fSmrg 518636d5e9fSmrg fclose(fp); 519636d5e9fSmrg return mod_amd; 520636d5e9fSmrg} 521636d5e9fSmrg 522636d5e9fSmrgstatic char * 523636d5e9fSmrgdrmGetFormatModifierNameFromAmlogic(uint64_t modifier) 524636d5e9fSmrg{ 525636d5e9fSmrg uint64_t layout = modifier & 0xff; 526636d5e9fSmrg uint64_t options = (modifier >> 8) & 0xff; 527636d5e9fSmrg char *mod_amlogic = NULL; 528636d5e9fSmrg 529636d5e9fSmrg const char *layout_str; 530636d5e9fSmrg const char *opts_str; 531636d5e9fSmrg 532636d5e9fSmrg switch (layout) { 533636d5e9fSmrg case AMLOGIC_FBC_LAYOUT_BASIC: 534636d5e9fSmrg layout_str = "BASIC"; 535636d5e9fSmrg break; 536636d5e9fSmrg case AMLOGIC_FBC_LAYOUT_SCATTER: 537636d5e9fSmrg layout_str = "SCATTER"; 538636d5e9fSmrg break; 539636d5e9fSmrg default: 540636d5e9fSmrg layout_str = "INVALID_LAYOUT"; 541636d5e9fSmrg break; 542636d5e9fSmrg } 543636d5e9fSmrg 544636d5e9fSmrg if (options & AMLOGIC_FBC_OPTION_MEM_SAVING) 545636d5e9fSmrg opts_str = "MEM_SAVING"; 546636d5e9fSmrg else 547636d5e9fSmrg opts_str = "0"; 548636d5e9fSmrg 549636d5e9fSmrg asprintf(&mod_amlogic, "FBC,LAYOUT=%s,OPTIONS=%s", layout_str, opts_str); 550636d5e9fSmrg return mod_amlogic; 551636d5e9fSmrg} 552636d5e9fSmrg 5534b3d3f37Smrgstatic unsigned log2_int(unsigned x) 5544b3d3f37Smrg{ 5554b3d3f37Smrg unsigned l; 5564b3d3f37Smrg 5574b3d3f37Smrg if (x < 2) { 5584b3d3f37Smrg return 0; 5594b3d3f37Smrg } 5604b3d3f37Smrg for (l = 2; ; l++) { 5614b3d3f37Smrg if ((unsigned)(1 << l) > x) { 5624b3d3f37Smrg return l - 1; 5634b3d3f37Smrg } 5644b3d3f37Smrg } 5654b3d3f37Smrg return 0; 5664b3d3f37Smrg} 5674b3d3f37Smrg 5684b3d3f37Smrg 5696260e5d5Smrgdrm_public void drmSetServerInfo(drmServerInfoPtr info) 57022944501Smrg{ 57122944501Smrg drm_server_info = info; 57222944501Smrg} 57322944501Smrg 57422944501Smrg/** 57522944501Smrg * Output a message to stderr. 57622944501Smrg * 57722944501Smrg * \param format printf() like format string. 57822944501Smrg * 57922944501Smrg * \internal 58022944501Smrg * This function is a wrapper around vfprintf(). 58122944501Smrg */ 58222944501Smrg 583a7d7de1eSmrgstatic int DRM_PRINTFLIKE(1, 0) 584a7d7de1eSmrgdrmDebugPrint(const char *format, va_list ap) 58522944501Smrg{ 58622944501Smrg return vfprintf(stderr, format, ap); 58722944501Smrg} 58822944501Smrg 5896260e5d5Smrgdrm_public void 59022944501SmrgdrmMsg(const char *format, ...) 59122944501Smrg{ 592fe517fc9Smrg va_list ap; 59322944501Smrg const char *env; 594fe517fc9Smrg if (((env = getenv("LIBGL_DEBUG")) && strstr(env, "verbose")) || 595fe517fc9Smrg (drm_server_info && drm_server_info->debug_print)) 59622944501Smrg { 597fe517fc9Smrg va_start(ap, format); 598fe517fc9Smrg if (drm_server_info) { 599fe517fc9Smrg drm_server_info->debug_print(format,ap); 600fe517fc9Smrg } else { 601fe517fc9Smrg drmDebugPrint(format, ap); 602fe517fc9Smrg } 603fe517fc9Smrg va_end(ap); 60422944501Smrg } 60522944501Smrg} 60622944501Smrg 60722944501Smrgstatic void *drmHashTable = NULL; /* Context switch callbacks */ 60822944501Smrg 6096260e5d5Smrgdrm_public void *drmGetHashTable(void) 61022944501Smrg{ 61122944501Smrg return drmHashTable; 61222944501Smrg} 61322944501Smrg 6146260e5d5Smrgdrm_public void *drmMalloc(int size) 61522944501Smrg{ 616424e9256Smrg return calloc(1, size); 61722944501Smrg} 61822944501Smrg 6196260e5d5Smrgdrm_public void drmFree(void *pt) 62022944501Smrg{ 621424e9256Smrg free(pt); 62222944501Smrg} 62322944501Smrg 62422944501Smrg/** 625bf6cc7dcSmrg * Call ioctl, restarting if it is interrupted 62622944501Smrg */ 6276260e5d5Smrgdrm_public int 62822944501SmrgdrmIoctl(int fd, unsigned long request, void *arg) 62922944501Smrg{ 630fe517fc9Smrg int ret; 63122944501Smrg 63222944501Smrg do { 633fe517fc9Smrg ret = ioctl(fd, request, arg); 63422944501Smrg } while (ret == -1 && (errno == EINTR || errno == EAGAIN)); 63522944501Smrg return ret; 63622944501Smrg} 63722944501Smrg 63822944501Smrgstatic unsigned long drmGetKeyFromFd(int fd) 63922944501Smrg{ 64022944501Smrg stat_t st; 64122944501Smrg 64222944501Smrg st.st_rdev = 0; 64322944501Smrg fstat(fd, &st); 64422944501Smrg return st.st_rdev; 64522944501Smrg} 64622944501Smrg 6476260e5d5Smrgdrm_public drmHashEntry *drmGetEntry(int fd) 64822944501Smrg{ 64922944501Smrg unsigned long key = drmGetKeyFromFd(fd); 65022944501Smrg void *value; 65122944501Smrg drmHashEntry *entry; 65222944501Smrg 65322944501Smrg if (!drmHashTable) 654fe517fc9Smrg drmHashTable = drmHashCreate(); 65522944501Smrg 65622944501Smrg if (drmHashLookup(drmHashTable, key, &value)) { 657fe517fc9Smrg entry = drmMalloc(sizeof(*entry)); 658fe517fc9Smrg entry->fd = fd; 659fe517fc9Smrg entry->f = NULL; 660fe517fc9Smrg entry->tagTable = drmHashCreate(); 661fe517fc9Smrg drmHashInsert(drmHashTable, key, entry); 66222944501Smrg } else { 663fe517fc9Smrg entry = value; 66422944501Smrg } 66522944501Smrg return entry; 66622944501Smrg} 66722944501Smrg 66822944501Smrg/** 66922944501Smrg * Compare two busid strings 67022944501Smrg * 67122944501Smrg * \param first 67222944501Smrg * \param second 67322944501Smrg * 67422944501Smrg * \return 1 if matched. 67522944501Smrg * 67622944501Smrg * \internal 67722944501Smrg * This function compares two bus ID strings. It understands the older 67822944501Smrg * PCI:b:d:f format and the newer pci:oooo:bb:dd.f format. In the format, o is 67922944501Smrg * domain, b is bus, d is device, f is function. 68022944501Smrg */ 6816d98c517Smrgstatic int drmMatchBusID(const char *id1, const char *id2, int pci_domain_ok) 68222944501Smrg{ 68322944501Smrg /* First, check if the IDs are exactly the same */ 68422944501Smrg if (strcasecmp(id1, id2) == 0) 685fe517fc9Smrg return 1; 68622944501Smrg 68722944501Smrg /* Try to match old/new-style PCI bus IDs. */ 68822944501Smrg if (strncasecmp(id1, "pci", 3) == 0) { 689fe517fc9Smrg unsigned int o1, b1, d1, f1; 690fe517fc9Smrg unsigned int o2, b2, d2, f2; 691fe517fc9Smrg int ret; 692fe517fc9Smrg 693fe517fc9Smrg ret = sscanf(id1, "pci:%04x:%02x:%02x.%u", &o1, &b1, &d1, &f1); 694fe517fc9Smrg if (ret != 4) { 695fe517fc9Smrg o1 = 0; 696fe517fc9Smrg ret = sscanf(id1, "PCI:%u:%u:%u", &b1, &d1, &f1); 697fe517fc9Smrg if (ret != 3) 698fe517fc9Smrg return 0; 699fe517fc9Smrg } 700fe517fc9Smrg 701fe517fc9Smrg ret = sscanf(id2, "pci:%04x:%02x:%02x.%u", &o2, &b2, &d2, &f2); 702fe517fc9Smrg if (ret != 4) { 703fe517fc9Smrg o2 = 0; 704fe517fc9Smrg ret = sscanf(id2, "PCI:%u:%u:%u", &b2, &d2, &f2); 705fe517fc9Smrg if (ret != 3) 706fe517fc9Smrg return 0; 707fe517fc9Smrg } 708fe517fc9Smrg 709fe517fc9Smrg /* If domains aren't properly supported by the kernel interface, 710fe517fc9Smrg * just ignore them, which sucks less than picking a totally random 711fe517fc9Smrg * card with "open by name" 712fe517fc9Smrg */ 713fe517fc9Smrg if (!pci_domain_ok) 714fe517fc9Smrg o1 = o2 = 0; 715fe517fc9Smrg 716fe517fc9Smrg if ((o1 != o2) || (b1 != b2) || (d1 != d2) || (f1 != f2)) 717fe517fc9Smrg return 0; 718fe517fc9Smrg else 719fe517fc9Smrg return 1; 72022944501Smrg } 72122944501Smrg return 0; 72222944501Smrg} 72322944501Smrg 72422944501Smrg/** 72522944501Smrg * Handles error checking for chown call. 72622944501Smrg * 72722944501Smrg * \param path to file. 72822944501Smrg * \param id of the new owner. 72922944501Smrg * \param id of the new group. 73022944501Smrg * 73122944501Smrg * \return zero if success or -1 if failure. 73222944501Smrg * 73322944501Smrg * \internal 73422944501Smrg * Checks for failure. If failure was caused by signal call chown again. 735bf6cc7dcSmrg * If any other failure happened then it will output error message using 73622944501Smrg * drmMsg() call. 73722944501Smrg */ 7386260e5d5Smrg#if !UDEV 73922944501Smrgstatic int chown_check_return(const char *path, uid_t owner, gid_t group) 74022944501Smrg{ 741fe517fc9Smrg int rv; 74222944501Smrg 743fe517fc9Smrg do { 744fe517fc9Smrg rv = chown(path, owner, group); 745fe517fc9Smrg } while (rv != 0 && errno == EINTR); 74622944501Smrg 747fe517fc9Smrg if (rv == 0) 748fe517fc9Smrg return 0; 74922944501Smrg 750fe517fc9Smrg drmMsg("Failed to change owner or group for file %s! %d: %s\n", 751fe517fc9Smrg path, errno, strerror(errno)); 752fe517fc9Smrg return -1; 75322944501Smrg} 754424e9256Smrg#endif 75522944501Smrg 75682025ec7Smrgstatic const char *drmGetDeviceName(int type) 75782025ec7Smrg{ 75882025ec7Smrg switch (type) { 75982025ec7Smrg case DRM_NODE_PRIMARY: 76082025ec7Smrg return DRM_DEV_NAME; 76182025ec7Smrg case DRM_NODE_CONTROL: 76282025ec7Smrg return DRM_CONTROL_DEV_NAME; 76382025ec7Smrg case DRM_NODE_RENDER: 76482025ec7Smrg return DRM_RENDER_DEV_NAME; 76582025ec7Smrg } 76682025ec7Smrg return NULL; 76782025ec7Smrg} 76882025ec7Smrg 76922944501Smrg/** 77022944501Smrg * Open the DRM device, creating it if necessary. 77122944501Smrg * 77222944501Smrg * \param dev major and minor numbers of the device. 77322944501Smrg * \param minor minor number of the device. 774fe517fc9Smrg * 77522944501Smrg * \return a file descriptor on success, or a negative value on error. 77622944501Smrg * 77722944501Smrg * \internal 77822944501Smrg * Assembles the device name from \p minor and opens it, creating the device 77922944501Smrg * special file node with the major and minor numbers specified by \p dev and 78022944501Smrg * parent directory if necessary and was called by root. 78122944501Smrg */ 782424e9256Smrgstatic int drmOpenDevice(dev_t dev, int minor, int type) 78322944501Smrg{ 78422944501Smrg stat_t st; 78582025ec7Smrg const char *dev_name = drmGetDeviceName(type); 78682025ec7Smrg char buf[DRM_NODE_NAME_MAX]; 78722944501Smrg int fd; 78822944501Smrg mode_t devmode = DRM_DEV_MODE, serv_mode; 789424e9256Smrg gid_t serv_group; 7906260e5d5Smrg#if !UDEV 79122944501Smrg int isroot = !geteuid(); 79222944501Smrg uid_t user = DRM_DEV_UID; 793424e9256Smrg gid_t group = DRM_DEV_GID; 794424e9256Smrg#endif 795424e9256Smrg 79682025ec7Smrg if (!dev_name) 797fe517fc9Smrg return -EINVAL; 798424e9256Smrg 799424e9256Smrg sprintf(buf, dev_name, DRM_DIR_NAME, minor); 80022944501Smrg drmMsg("drmOpenDevice: node name is %s\n", buf); 80122944501Smrg 802fe517fc9Smrg if (drm_server_info && drm_server_info->get_perms) { 803fe517fc9Smrg drm_server_info->get_perms(&serv_group, &serv_mode); 804fe517fc9Smrg devmode = serv_mode ? serv_mode : DRM_DEV_MODE; 805fe517fc9Smrg devmode &= ~(S_IXUSR|S_IXGRP|S_IXOTH); 80622944501Smrg } 80722944501Smrg 8086260e5d5Smrg#if !UDEV 80922944501Smrg if (stat(DRM_DIR_NAME, &st)) { 810fe517fc9Smrg if (!isroot) 811fe517fc9Smrg return DRM_ERR_NOT_ROOT; 812fe517fc9Smrg mkdir(DRM_DIR_NAME, DRM_DEV_DIRMODE); 813fe517fc9Smrg chown_check_return(DRM_DIR_NAME, 0, 0); /* root:root */ 814fe517fc9Smrg chmod(DRM_DIR_NAME, DRM_DEV_DIRMODE); 81522944501Smrg } 81622944501Smrg 81722944501Smrg /* Check if the device node exists and create it if necessary. */ 81822944501Smrg if (stat(buf, &st)) { 819fe517fc9Smrg if (!isroot) 820fe517fc9Smrg return DRM_ERR_NOT_ROOT; 821fe517fc9Smrg remove(buf); 822fe517fc9Smrg mknod(buf, S_IFCHR | devmode, dev); 82322944501Smrg } 82422944501Smrg 825fe517fc9Smrg if (drm_server_info && drm_server_info->get_perms) { 826fe517fc9Smrg group = ((int)serv_group >= 0) ? serv_group : DRM_DEV_GID; 827fe517fc9Smrg chown_check_return(buf, user, group); 828fe517fc9Smrg chmod(buf, devmode); 82922944501Smrg } 83022944501Smrg#else 83122944501Smrg /* if we modprobed then wait for udev */ 83222944501Smrg { 833fe517fc9Smrg int udev_count = 0; 83422944501Smrgwait_for_udev: 83522944501Smrg if (stat(DRM_DIR_NAME, &st)) { 836fe517fc9Smrg usleep(20); 837fe517fc9Smrg udev_count++; 838fe517fc9Smrg 839fe517fc9Smrg if (udev_count == 50) 840fe517fc9Smrg return -1; 841fe517fc9Smrg goto wait_for_udev; 842fe517fc9Smrg } 843fe517fc9Smrg 844fe517fc9Smrg if (stat(buf, &st)) { 845fe517fc9Smrg usleep(20); 846fe517fc9Smrg udev_count++; 847fe517fc9Smrg 848fe517fc9Smrg if (udev_count == 50) 849fe517fc9Smrg return -1; 850fe517fc9Smrg goto wait_for_udev; 851fe517fc9Smrg } 85222944501Smrg } 85322944501Smrg#endif 85422944501Smrg 8556260e5d5Smrg fd = open(buf, O_RDWR | O_CLOEXEC, 0); 85622944501Smrg drmMsg("drmOpenDevice: open result is %d, (%s)\n", 857fe517fc9Smrg fd, fd < 0 ? strerror(errno) : "OK"); 85822944501Smrg if (fd >= 0) 859fe517fc9Smrg return fd; 86022944501Smrg 8616260e5d5Smrg#if !UDEV 86222944501Smrg /* Check if the device node is not what we expect it to be, and recreate it 86322944501Smrg * and try again if so. 86422944501Smrg */ 86522944501Smrg if (st.st_rdev != dev) { 866fe517fc9Smrg if (!isroot) 867fe517fc9Smrg return DRM_ERR_NOT_ROOT; 868fe517fc9Smrg remove(buf); 869fe517fc9Smrg mknod(buf, S_IFCHR | devmode, dev); 870fe517fc9Smrg if (drm_server_info && drm_server_info->get_perms) { 871fe517fc9Smrg chown_check_return(buf, user, group); 872fe517fc9Smrg chmod(buf, devmode); 873fe517fc9Smrg } 87422944501Smrg } 8756260e5d5Smrg fd = open(buf, O_RDWR | O_CLOEXEC, 0); 87622944501Smrg drmMsg("drmOpenDevice: open result is %d, (%s)\n", 877fe517fc9Smrg fd, fd < 0 ? strerror(errno) : "OK"); 87822944501Smrg if (fd >= 0) 879fe517fc9Smrg return fd; 88022944501Smrg 88122944501Smrg drmMsg("drmOpenDevice: Open failed\n"); 88222944501Smrg remove(buf); 8839ce4edccSmrg#endif 88422944501Smrg return -errno; 88522944501Smrg} 88622944501Smrg 88722944501Smrg 88822944501Smrg/** 88922944501Smrg * Open the DRM device 89022944501Smrg * 89122944501Smrg * \param minor device minor number. 89222944501Smrg * \param create allow to create the device if set. 89322944501Smrg * 89422944501Smrg * \return a file descriptor on success, or a negative value on error. 895fe517fc9Smrg * 89622944501Smrg * \internal 89722944501Smrg * Calls drmOpenDevice() if \p create is set, otherwise assembles the device 89822944501Smrg * name from \p minor and opens it. 89922944501Smrg */ 90022944501Smrgstatic int drmOpenMinor(int minor, int create, int type) 90122944501Smrg{ 90222944501Smrg int fd; 90382025ec7Smrg char buf[DRM_NODE_NAME_MAX]; 90482025ec7Smrg const char *dev_name = drmGetDeviceName(type); 905fe517fc9Smrg 90622944501Smrg if (create) 907fe517fc9Smrg return drmOpenDevice(makedev(DRM_MAJOR, minor), minor, type); 908fe517fc9Smrg 90982025ec7Smrg if (!dev_name) 910fe517fc9Smrg return -EINVAL; 911424e9256Smrg 912424e9256Smrg sprintf(buf, dev_name, DRM_DIR_NAME, minor); 9136260e5d5Smrg if ((fd = open(buf, O_RDWR | O_CLOEXEC, 0)) >= 0) 914fe517fc9Smrg return fd; 91522944501Smrg return -errno; 91622944501Smrg} 91722944501Smrg 91822944501Smrg 91922944501Smrg/** 92022944501Smrg * Determine whether the DRM kernel driver has been loaded. 921fe517fc9Smrg * 92222944501Smrg * \return 1 if the DRM driver is loaded, 0 otherwise. 92322944501Smrg * 924fe517fc9Smrg * \internal 92522944501Smrg * Determine the presence of the kernel driver by attempting to open the 0 92622944501Smrg * minor and get version information. For backward compatibility with older 92722944501Smrg * Linux implementations, /proc/dri is also checked. 92822944501Smrg */ 9296260e5d5Smrgdrm_public int drmAvailable(void) 93022944501Smrg{ 93122944501Smrg drmVersionPtr version; 93222944501Smrg int retval = 0; 93322944501Smrg int fd; 93422944501Smrg 935424e9256Smrg if ((fd = drmOpenMinor(0, 1, DRM_NODE_PRIMARY)) < 0) { 93622944501Smrg#ifdef __linux__ 937fe517fc9Smrg /* Try proc for backward Linux compatibility */ 938fe517fc9Smrg if (!access("/proc/dri/0", R_OK)) 939fe517fc9Smrg return 1; 94022944501Smrg#endif 941fe517fc9Smrg return 0; 94222944501Smrg } 943fe517fc9Smrg 94422944501Smrg if ((version = drmGetVersion(fd))) { 945fe517fc9Smrg retval = 1; 946fe517fc9Smrg drmFreeVersion(version); 94722944501Smrg } 94822944501Smrg close(fd); 94922944501Smrg 95022944501Smrg return retval; 95122944501Smrg} 95222944501Smrg 953424e9256Smrgstatic int drmGetMinorBase(int type) 954424e9256Smrg{ 955424e9256Smrg switch (type) { 956424e9256Smrg case DRM_NODE_PRIMARY: 957424e9256Smrg return 0; 958424e9256Smrg case DRM_NODE_CONTROL: 959424e9256Smrg return 64; 960424e9256Smrg case DRM_NODE_RENDER: 961424e9256Smrg return 128; 962424e9256Smrg default: 963424e9256Smrg return -1; 964424e9256Smrg }; 965424e9256Smrg} 966424e9256Smrg 96787bf8e7cSmrgstatic int drmGetMinorType(int major, int minor) 968424e9256Smrg{ 96987bf8e7cSmrg#ifdef __FreeBSD__ 97087bf8e7cSmrg char name[SPECNAMELEN]; 97187bf8e7cSmrg int id; 97287bf8e7cSmrg 97387bf8e7cSmrg if (!devname_r(makedev(major, minor), S_IFCHR, name, sizeof(name))) 97487bf8e7cSmrg return -1; 97587bf8e7cSmrg 97687bf8e7cSmrg if (sscanf(name, "drm/%d", &id) != 1) { 97787bf8e7cSmrg // If not in /dev/drm/ we have the type in the name 97887bf8e7cSmrg if (sscanf(name, "dri/card%d\n", &id) >= 1) 97987bf8e7cSmrg return DRM_NODE_PRIMARY; 98087bf8e7cSmrg else if (sscanf(name, "dri/control%d\n", &id) >= 1) 98187bf8e7cSmrg return DRM_NODE_CONTROL; 98287bf8e7cSmrg else if (sscanf(name, "dri/renderD%d\n", &id) >= 1) 98387bf8e7cSmrg return DRM_NODE_RENDER; 98487bf8e7cSmrg return -1; 98587bf8e7cSmrg } 98687bf8e7cSmrg 98787bf8e7cSmrg minor = id; 98887bf8e7cSmrg#endif 989424e9256Smrg int type = minor >> 6; 990424e9256Smrg 991424e9256Smrg if (minor < 0) 992424e9256Smrg return -1; 993424e9256Smrg 994424e9256Smrg switch (type) { 995424e9256Smrg case DRM_NODE_PRIMARY: 996424e9256Smrg case DRM_NODE_CONTROL: 997424e9256Smrg case DRM_NODE_RENDER: 998424e9256Smrg return type; 999424e9256Smrg default: 1000424e9256Smrg return -1; 1001424e9256Smrg } 1002424e9256Smrg} 1003424e9256Smrg 1004424e9256Smrgstatic const char *drmGetMinorName(int type) 1005424e9256Smrg{ 1006424e9256Smrg switch (type) { 1007424e9256Smrg case DRM_NODE_PRIMARY: 1008fe517fc9Smrg return DRM_PRIMARY_MINOR_NAME; 1009424e9256Smrg case DRM_NODE_CONTROL: 1010fe517fc9Smrg return DRM_CONTROL_MINOR_NAME; 1011424e9256Smrg case DRM_NODE_RENDER: 1012fe517fc9Smrg return DRM_RENDER_MINOR_NAME; 1013424e9256Smrg default: 1014424e9256Smrg return NULL; 1015424e9256Smrg } 1016424e9256Smrg} 101722944501Smrg 101822944501Smrg/** 101922944501Smrg * Open the device by bus ID. 102022944501Smrg * 102122944501Smrg * \param busid bus ID. 1022424e9256Smrg * \param type device node type. 102322944501Smrg * 102422944501Smrg * \return a file descriptor on success, or a negative value on error. 102522944501Smrg * 102622944501Smrg * \internal 102722944501Smrg * This function attempts to open every possible minor (up to DRM_MAX_MINOR), 102822944501Smrg * comparing the device bus ID with the one supplied. 102922944501Smrg * 103022944501Smrg * \sa drmOpenMinor() and drmGetBusid(). 103122944501Smrg */ 1032424e9256Smrgstatic int drmOpenByBusid(const char *busid, int type) 103322944501Smrg{ 10346d98c517Smrg int i, pci_domain_ok = 1; 103522944501Smrg int fd; 103622944501Smrg const char *buf; 103722944501Smrg drmSetVersion sv; 1038424e9256Smrg int base = drmGetMinorBase(type); 1039424e9256Smrg 1040424e9256Smrg if (base < 0) 1041424e9256Smrg return -1; 104222944501Smrg 104322944501Smrg drmMsg("drmOpenByBusid: Searching for BusID %s\n", busid); 1044424e9256Smrg for (i = base; i < base + DRM_MAX_MINOR; i++) { 1045fe517fc9Smrg fd = drmOpenMinor(i, 1, type); 1046fe517fc9Smrg drmMsg("drmOpenByBusid: drmOpenMinor returns %d\n", fd); 1047fe517fc9Smrg if (fd >= 0) { 1048fe517fc9Smrg /* We need to try for 1.4 first for proper PCI domain support 1049fe517fc9Smrg * and if that fails, we know the kernel is busted 1050fe517fc9Smrg */ 1051fe517fc9Smrg sv.drm_di_major = 1; 1052fe517fc9Smrg sv.drm_di_minor = 4; 1053fe517fc9Smrg sv.drm_dd_major = -1; /* Don't care */ 1054fe517fc9Smrg sv.drm_dd_minor = -1; /* Don't care */ 1055fe517fc9Smrg if (drmSetInterfaceVersion(fd, &sv)) { 10566d98c517Smrg#ifndef __alpha__ 1057fe517fc9Smrg pci_domain_ok = 0; 10586d98c517Smrg#endif 1059fe517fc9Smrg sv.drm_di_major = 1; 1060fe517fc9Smrg sv.drm_di_minor = 1; 1061fe517fc9Smrg sv.drm_dd_major = -1; /* Don't care */ 1062fe517fc9Smrg sv.drm_dd_minor = -1; /* Don't care */ 1063fe517fc9Smrg drmMsg("drmOpenByBusid: Interface 1.4 failed, trying 1.1\n"); 1064fe517fc9Smrg drmSetInterfaceVersion(fd, &sv); 1065fe517fc9Smrg } 1066fe517fc9Smrg buf = drmGetBusid(fd); 1067fe517fc9Smrg drmMsg("drmOpenByBusid: drmGetBusid reports %s\n", buf); 1068fe517fc9Smrg if (buf && drmMatchBusID(buf, busid, pci_domain_ok)) { 1069fe517fc9Smrg drmFreeBusid(buf); 1070fe517fc9Smrg return fd; 1071fe517fc9Smrg } 1072fe517fc9Smrg if (buf) 1073fe517fc9Smrg drmFreeBusid(buf); 1074fe517fc9Smrg close(fd); 1075fe517fc9Smrg } 107622944501Smrg } 107722944501Smrg return -1; 107822944501Smrg} 107922944501Smrg 108022944501Smrg 108122944501Smrg/** 108222944501Smrg * Open the device by name. 108322944501Smrg * 108422944501Smrg * \param name driver name. 1085424e9256Smrg * \param type the device node type. 1086fe517fc9Smrg * 108722944501Smrg * \return a file descriptor on success, or a negative value on error. 1088fe517fc9Smrg * 108922944501Smrg * \internal 109022944501Smrg * This function opens the first minor number that matches the driver name and 109122944501Smrg * isn't already in use. If it's in use it then it will already have a bus ID 109222944501Smrg * assigned. 1093fe517fc9Smrg * 109422944501Smrg * \sa drmOpenMinor(), drmGetVersion() and drmGetBusid(). 109522944501Smrg */ 1096424e9256Smrgstatic int drmOpenByName(const char *name, int type) 109722944501Smrg{ 109822944501Smrg int i; 109922944501Smrg int fd; 110022944501Smrg drmVersionPtr version; 110122944501Smrg char * id; 1102424e9256Smrg int base = drmGetMinorBase(type); 1103424e9256Smrg 1104424e9256Smrg if (base < 0) 1105424e9256Smrg return -1; 110622944501Smrg 110722944501Smrg /* 110822944501Smrg * Open the first minor number that matches the driver name and isn't 110922944501Smrg * already in use. If it's in use it will have a busid assigned already. 111022944501Smrg */ 1111424e9256Smrg for (i = base; i < base + DRM_MAX_MINOR; i++) { 1112fe517fc9Smrg if ((fd = drmOpenMinor(i, 1, type)) >= 0) { 1113fe517fc9Smrg if ((version = drmGetVersion(fd))) { 1114fe517fc9Smrg if (!strcmp(version->name, name)) { 1115fe517fc9Smrg drmFreeVersion(version); 1116fe517fc9Smrg id = drmGetBusid(fd); 1117fe517fc9Smrg drmMsg("drmGetBusid returned '%s'\n", id ? id : "NULL"); 1118fe517fc9Smrg if (!id || !*id) { 1119fe517fc9Smrg if (id) 1120fe517fc9Smrg drmFreeBusid(id); 1121fe517fc9Smrg return fd; 1122fe517fc9Smrg } else { 1123fe517fc9Smrg drmFreeBusid(id); 1124fe517fc9Smrg } 1125fe517fc9Smrg } else { 1126fe517fc9Smrg drmFreeVersion(version); 1127fe517fc9Smrg } 1128fe517fc9Smrg } 1129fe517fc9Smrg close(fd); 1130fe517fc9Smrg } 113122944501Smrg } 113222944501Smrg 113322944501Smrg#ifdef __linux__ 113422944501Smrg /* Backward-compatibility /proc support */ 113522944501Smrg for (i = 0; i < 8; i++) { 1136fe517fc9Smrg char proc_name[64], buf[512]; 1137fe517fc9Smrg char *driver, *pt, *devstring; 1138fe517fc9Smrg int retcode; 1139fe517fc9Smrg 1140fe517fc9Smrg sprintf(proc_name, "/proc/dri/%d/name", i); 11414b3d3f37Smrg if ((fd = open(proc_name, O_RDONLY, 0)) >= 0) { 1142fe517fc9Smrg retcode = read(fd, buf, sizeof(buf)-1); 1143fe517fc9Smrg close(fd); 1144fe517fc9Smrg if (retcode) { 1145fe517fc9Smrg buf[retcode-1] = '\0'; 1146fe517fc9Smrg for (driver = pt = buf; *pt && *pt != ' '; ++pt) 1147fe517fc9Smrg ; 1148fe517fc9Smrg if (*pt) { /* Device is next */ 1149fe517fc9Smrg *pt = '\0'; 1150fe517fc9Smrg if (!strcmp(driver, name)) { /* Match */ 1151fe517fc9Smrg for (devstring = ++pt; *pt && *pt != ' '; ++pt) 1152fe517fc9Smrg ; 1153fe517fc9Smrg if (*pt) { /* Found busid */ 1154fe517fc9Smrg return drmOpenByBusid(++pt, type); 1155fe517fc9Smrg } else { /* No busid */ 1156fe517fc9Smrg return drmOpenDevice(strtol(devstring, NULL, 0),i, type); 1157fe517fc9Smrg } 1158fe517fc9Smrg } 1159fe517fc9Smrg } 1160fe517fc9Smrg } 1161fe517fc9Smrg } 116222944501Smrg } 116322944501Smrg#endif 116422944501Smrg 116522944501Smrg return -1; 116622944501Smrg} 116722944501Smrg 116822944501Smrg 116922944501Smrg/** 117022944501Smrg * Open the DRM device. 117122944501Smrg * 117222944501Smrg * Looks up the specified name and bus ID, and opens the device found. The 117322944501Smrg * entry in /dev/dri is created if necessary and if called by root. 117422944501Smrg * 117522944501Smrg * \param name driver name. Not referenced if bus ID is supplied. 117622944501Smrg * \param busid bus ID. Zero if not known. 1177fe517fc9Smrg * 117822944501Smrg * \return a file descriptor on success, or a negative value on error. 1179fe517fc9Smrg * 118022944501Smrg * \internal 118122944501Smrg * It calls drmOpenByBusid() if \p busid is specified or drmOpenByName() 118222944501Smrg * otherwise. 118322944501Smrg */ 11846260e5d5Smrgdrm_public int drmOpen(const char *name, const char *busid) 1185424e9256Smrg{ 1186424e9256Smrg return drmOpenWithType(name, busid, DRM_NODE_PRIMARY); 1187424e9256Smrg} 1188424e9256Smrg 1189424e9256Smrg/** 1190424e9256Smrg * Open the DRM device with specified type. 1191424e9256Smrg * 1192424e9256Smrg * Looks up the specified name and bus ID, and opens the device found. The 1193424e9256Smrg * entry in /dev/dri is created if necessary and if called by root. 1194424e9256Smrg * 1195424e9256Smrg * \param name driver name. Not referenced if bus ID is supplied. 1196424e9256Smrg * \param busid bus ID. Zero if not known. 1197424e9256Smrg * \param type the device node type to open, PRIMARY, CONTROL or RENDER 1198424e9256Smrg * 1199424e9256Smrg * \return a file descriptor on success, or a negative value on error. 1200424e9256Smrg * 1201424e9256Smrg * \internal 1202424e9256Smrg * It calls drmOpenByBusid() if \p busid is specified or drmOpenByName() 1203424e9256Smrg * otherwise. 1204424e9256Smrg */ 12056260e5d5Smrgdrm_public int drmOpenWithType(const char *name, const char *busid, int type) 120622944501Smrg{ 1207bf6cc7dcSmrg if (name != NULL && drm_server_info && 1208bf6cc7dcSmrg drm_server_info->load_module && !drmAvailable()) { 1209fe517fc9Smrg /* try to load the kernel module */ 1210fe517fc9Smrg if (!drm_server_info->load_module(name)) { 1211fe517fc9Smrg drmMsg("[drm] failed to load kernel module \"%s\"\n", name); 1212fe517fc9Smrg return -1; 1213fe517fc9Smrg } 121422944501Smrg } 121522944501Smrg 121622944501Smrg if (busid) { 1217fe517fc9Smrg int fd = drmOpenByBusid(busid, type); 1218fe517fc9Smrg if (fd >= 0) 1219fe517fc9Smrg return fd; 122022944501Smrg } 1221fe517fc9Smrg 122222944501Smrg if (name) 1223fe517fc9Smrg return drmOpenByName(name, type); 122422944501Smrg 122522944501Smrg return -1; 122622944501Smrg} 122722944501Smrg 12286260e5d5Smrgdrm_public int drmOpenControl(int minor) 122922944501Smrg{ 123022944501Smrg return drmOpenMinor(minor, 0, DRM_NODE_CONTROL); 123122944501Smrg} 123222944501Smrg 12336260e5d5Smrgdrm_public int drmOpenRender(int minor) 1234424e9256Smrg{ 1235424e9256Smrg return drmOpenMinor(minor, 0, DRM_NODE_RENDER); 1236424e9256Smrg} 1237424e9256Smrg 123822944501Smrg/** 123922944501Smrg * Free the version information returned by drmGetVersion(). 124022944501Smrg * 124122944501Smrg * \param v pointer to the version information. 124222944501Smrg * 124322944501Smrg * \internal 124422944501Smrg * It frees the memory pointed by \p %v as well as all the non-null strings 124522944501Smrg * pointers in it. 124622944501Smrg */ 12476260e5d5Smrgdrm_public void drmFreeVersion(drmVersionPtr v) 124822944501Smrg{ 124922944501Smrg if (!v) 1250fe517fc9Smrg return; 125122944501Smrg drmFree(v->name); 125222944501Smrg drmFree(v->date); 125322944501Smrg drmFree(v->desc); 125422944501Smrg drmFree(v); 125522944501Smrg} 125622944501Smrg 125722944501Smrg 125822944501Smrg/** 125922944501Smrg * Free the non-public version information returned by the kernel. 126022944501Smrg * 126122944501Smrg * \param v pointer to the version information. 126222944501Smrg * 126322944501Smrg * \internal 126422944501Smrg * Used by drmGetVersion() to free the memory pointed by \p %v as well as all 126522944501Smrg * the non-null strings pointers in it. 126622944501Smrg */ 126722944501Smrgstatic void drmFreeKernelVersion(drm_version_t *v) 126822944501Smrg{ 126922944501Smrg if (!v) 1270fe517fc9Smrg return; 127122944501Smrg drmFree(v->name); 127222944501Smrg drmFree(v->date); 127322944501Smrg drmFree(v->desc); 127422944501Smrg drmFree(v); 127522944501Smrg} 127622944501Smrg 127722944501Smrg 127822944501Smrg/** 127922944501Smrg * Copy version information. 1280fe517fc9Smrg * 128122944501Smrg * \param d destination pointer. 128222944501Smrg * \param s source pointer. 1283fe517fc9Smrg * 128422944501Smrg * \internal 128522944501Smrg * Used by drmGetVersion() to translate the information returned by the ioctl 128622944501Smrg * interface in a private structure into the public structure counterpart. 128722944501Smrg */ 128822944501Smrgstatic void drmCopyVersion(drmVersionPtr d, const drm_version_t *s) 128922944501Smrg{ 129022944501Smrg d->version_major = s->version_major; 129122944501Smrg d->version_minor = s->version_minor; 129222944501Smrg d->version_patchlevel = s->version_patchlevel; 129322944501Smrg d->name_len = s->name_len; 12949ce4edccSmrg d->name = strdup(s->name); 129522944501Smrg d->date_len = s->date_len; 12969ce4edccSmrg d->date = strdup(s->date); 129722944501Smrg d->desc_len = s->desc_len; 12989ce4edccSmrg d->desc = strdup(s->desc); 129922944501Smrg} 130022944501Smrg 130122944501Smrg 130222944501Smrg/** 130322944501Smrg * Query the driver version information. 130422944501Smrg * 130522944501Smrg * \param fd file descriptor. 1306fe517fc9Smrg * 130722944501Smrg * \return pointer to a drmVersion structure which should be freed with 130822944501Smrg * drmFreeVersion(). 1309fe517fc9Smrg * 131022944501Smrg * \note Similar information is available via /proc/dri. 1311fe517fc9Smrg * 131222944501Smrg * \internal 131322944501Smrg * It gets the version information via successive DRM_IOCTL_VERSION ioctls, 131422944501Smrg * first with zeros to get the string lengths, and then the actually strings. 131522944501Smrg * It also null-terminates them since they might not be already. 131622944501Smrg */ 13176260e5d5Smrgdrm_public drmVersionPtr drmGetVersion(int fd) 131822944501Smrg{ 131922944501Smrg drmVersionPtr retval; 132022944501Smrg drm_version_t *version = drmMalloc(sizeof(*version)); 132122944501Smrg 132222944501Smrg if (drmIoctl(fd, DRM_IOCTL_VERSION, version)) { 1323fe517fc9Smrg drmFreeKernelVersion(version); 1324fe517fc9Smrg return NULL; 132522944501Smrg } 132622944501Smrg 132722944501Smrg if (version->name_len) 1328fe517fc9Smrg version->name = drmMalloc(version->name_len + 1); 132922944501Smrg if (version->date_len) 1330fe517fc9Smrg version->date = drmMalloc(version->date_len + 1); 133122944501Smrg if (version->desc_len) 1332fe517fc9Smrg version->desc = drmMalloc(version->desc_len + 1); 133322944501Smrg 133422944501Smrg if (drmIoctl(fd, DRM_IOCTL_VERSION, version)) { 1335fe517fc9Smrg drmMsg("DRM_IOCTL_VERSION: %s\n", strerror(errno)); 1336fe517fc9Smrg drmFreeKernelVersion(version); 1337fe517fc9Smrg return NULL; 133822944501Smrg } 133922944501Smrg 134022944501Smrg /* The results might not be null-terminated strings, so terminate them. */ 134122944501Smrg if (version->name_len) version->name[version->name_len] = '\0'; 134222944501Smrg if (version->date_len) version->date[version->date_len] = '\0'; 134322944501Smrg if (version->desc_len) version->desc[version->desc_len] = '\0'; 134422944501Smrg 134522944501Smrg retval = drmMalloc(sizeof(*retval)); 134622944501Smrg drmCopyVersion(retval, version); 134722944501Smrg drmFreeKernelVersion(version); 134822944501Smrg return retval; 134922944501Smrg} 135022944501Smrg 135122944501Smrg 135222944501Smrg/** 135322944501Smrg * Get version information for the DRM user space library. 1354fe517fc9Smrg * 135522944501Smrg * This version number is driver independent. 1356fe517fc9Smrg * 135722944501Smrg * \param fd file descriptor. 135822944501Smrg * 135922944501Smrg * \return version information. 1360fe517fc9Smrg * 136122944501Smrg * \internal 136222944501Smrg * This function allocates and fills a drm_version structure with a hard coded 136322944501Smrg * version number. 136422944501Smrg */ 13656260e5d5Smrgdrm_public drmVersionPtr drmGetLibVersion(int fd) 136622944501Smrg{ 136722944501Smrg drm_version_t *version = drmMalloc(sizeof(*version)); 136822944501Smrg 136922944501Smrg /* Version history: 137022944501Smrg * NOTE THIS MUST NOT GO ABOVE VERSION 1.X due to drivers needing it 137122944501Smrg * revision 1.0.x = original DRM interface with no drmGetLibVersion 137222944501Smrg * entry point and many drm<Device> extensions 137322944501Smrg * revision 1.1.x = added drmCommand entry points for device extensions 137422944501Smrg * added drmGetLibVersion to identify libdrm.a version 137522944501Smrg * revision 1.2.x = added drmSetInterfaceVersion 137622944501Smrg * modified drmOpen to handle both busid and name 137722944501Smrg * revision 1.3.x = added server + memory manager 137822944501Smrg */ 137922944501Smrg version->version_major = 1; 138022944501Smrg version->version_minor = 3; 138122944501Smrg version->version_patchlevel = 0; 138222944501Smrg 138322944501Smrg return (drmVersionPtr)version; 138422944501Smrg} 138522944501Smrg 13866260e5d5Smrgdrm_public int drmGetCap(int fd, uint64_t capability, uint64_t *value) 138720131375Smrg{ 1388fe517fc9Smrg struct drm_get_cap cap; 1389fe517fc9Smrg int ret; 139020131375Smrg 1391fe517fc9Smrg memclear(cap); 1392fe517fc9Smrg cap.capability = capability; 1393424e9256Smrg 1394fe517fc9Smrg ret = drmIoctl(fd, DRM_IOCTL_GET_CAP, &cap); 1395fe517fc9Smrg if (ret) 1396fe517fc9Smrg return ret; 139720131375Smrg 1398fe517fc9Smrg *value = cap.value; 1399fe517fc9Smrg return 0; 140020131375Smrg} 140120131375Smrg 14026260e5d5Smrgdrm_public int drmSetClientCap(int fd, uint64_t capability, uint64_t value) 140320131375Smrg{ 1404fe517fc9Smrg struct drm_set_client_cap cap; 1405424e9256Smrg 1406fe517fc9Smrg memclear(cap); 1407fe517fc9Smrg cap.capability = capability; 1408fe517fc9Smrg cap.value = value; 140920131375Smrg 1410fe517fc9Smrg return drmIoctl(fd, DRM_IOCTL_SET_CLIENT_CAP, &cap); 141120131375Smrg} 141222944501Smrg 141322944501Smrg/** 141422944501Smrg * Free the bus ID information. 141522944501Smrg * 141622944501Smrg * \param busid bus ID information string as given by drmGetBusid(). 141722944501Smrg * 141822944501Smrg * \internal 141922944501Smrg * This function is just frees the memory pointed by \p busid. 142022944501Smrg */ 14216260e5d5Smrgdrm_public void drmFreeBusid(const char *busid) 142222944501Smrg{ 142322944501Smrg drmFree((void *)busid); 142422944501Smrg} 142522944501Smrg 142622944501Smrg 142722944501Smrg/** 142822944501Smrg * Get the bus ID of the device. 142922944501Smrg * 143022944501Smrg * \param fd file descriptor. 143122944501Smrg * 143222944501Smrg * \return bus ID string. 143322944501Smrg * 143422944501Smrg * \internal 143522944501Smrg * This function gets the bus ID via successive DRM_IOCTL_GET_UNIQUE ioctls to 143622944501Smrg * get the string length and data, passing the arguments in a drm_unique 143722944501Smrg * structure. 143822944501Smrg */ 14396260e5d5Smrgdrm_public char *drmGetBusid(int fd) 144022944501Smrg{ 144122944501Smrg drm_unique_t u; 144222944501Smrg 1443424e9256Smrg memclear(u); 144422944501Smrg 144522944501Smrg if (drmIoctl(fd, DRM_IOCTL_GET_UNIQUE, &u)) 1446fe517fc9Smrg return NULL; 144722944501Smrg u.unique = drmMalloc(u.unique_len + 1); 14480655efefSmrg if (drmIoctl(fd, DRM_IOCTL_GET_UNIQUE, &u)) { 14490655efefSmrg drmFree(u.unique); 1450fe517fc9Smrg return NULL; 14510655efefSmrg } 145222944501Smrg u.unique[u.unique_len] = '\0'; 145322944501Smrg 145422944501Smrg return u.unique; 145522944501Smrg} 145622944501Smrg 145722944501Smrg 145822944501Smrg/** 145922944501Smrg * Set the bus ID of the device. 146022944501Smrg * 146122944501Smrg * \param fd file descriptor. 146222944501Smrg * \param busid bus ID string. 146322944501Smrg * 146422944501Smrg * \return zero on success, negative on failure. 146522944501Smrg * 146622944501Smrg * \internal 146722944501Smrg * This function is a wrapper around the DRM_IOCTL_SET_UNIQUE ioctl, passing 146822944501Smrg * the arguments in a drm_unique structure. 146922944501Smrg */ 14706260e5d5Smrgdrm_public int drmSetBusid(int fd, const char *busid) 147122944501Smrg{ 147222944501Smrg drm_unique_t u; 147322944501Smrg 1474424e9256Smrg memclear(u); 147522944501Smrg u.unique = (char *)busid; 147622944501Smrg u.unique_len = strlen(busid); 147722944501Smrg 147822944501Smrg if (drmIoctl(fd, DRM_IOCTL_SET_UNIQUE, &u)) { 1479fe517fc9Smrg return -errno; 148022944501Smrg } 148122944501Smrg return 0; 148222944501Smrg} 148322944501Smrg 14846260e5d5Smrgdrm_public int drmGetMagic(int fd, drm_magic_t * magic) 148522944501Smrg{ 148622944501Smrg drm_auth_t auth; 148722944501Smrg 1488424e9256Smrg memclear(auth); 1489424e9256Smrg 149022944501Smrg *magic = 0; 149122944501Smrg if (drmIoctl(fd, DRM_IOCTL_GET_MAGIC, &auth)) 1492fe517fc9Smrg return -errno; 149322944501Smrg *magic = auth.magic; 149422944501Smrg return 0; 149522944501Smrg} 149622944501Smrg 14976260e5d5Smrgdrm_public int drmAuthMagic(int fd, drm_magic_t magic) 149822944501Smrg{ 149922944501Smrg drm_auth_t auth; 150022944501Smrg 1501424e9256Smrg memclear(auth); 150222944501Smrg auth.magic = magic; 150322944501Smrg if (drmIoctl(fd, DRM_IOCTL_AUTH_MAGIC, &auth)) 1504fe517fc9Smrg return -errno; 150522944501Smrg return 0; 150622944501Smrg} 150722944501Smrg 150822944501Smrg/** 150922944501Smrg * Specifies a range of memory that is available for mapping by a 151022944501Smrg * non-root process. 151122944501Smrg * 151222944501Smrg * \param fd file descriptor. 151322944501Smrg * \param offset usually the physical address. The actual meaning depends of 151422944501Smrg * the \p type parameter. See below. 151522944501Smrg * \param size of the memory in bytes. 151622944501Smrg * \param type type of the memory to be mapped. 151722944501Smrg * \param flags combination of several flags to modify the function actions. 151822944501Smrg * \param handle will be set to a value that may be used as the offset 151922944501Smrg * parameter for mmap(). 1520fe517fc9Smrg * 152122944501Smrg * \return zero on success or a negative value on error. 152222944501Smrg * 152322944501Smrg * \par Mapping the frame buffer 152422944501Smrg * For the frame buffer 152522944501Smrg * - \p offset will be the physical address of the start of the frame buffer, 152622944501Smrg * - \p size will be the size of the frame buffer in bytes, and 152722944501Smrg * - \p type will be DRM_FRAME_BUFFER. 152822944501Smrg * 152922944501Smrg * \par 153022944501Smrg * The area mapped will be uncached. If MTRR support is available in the 1531fe517fc9Smrg * kernel, the frame buffer area will be set to write combining. 153222944501Smrg * 153322944501Smrg * \par Mapping the MMIO register area 153422944501Smrg * For the MMIO register area, 153522944501Smrg * - \p offset will be the physical address of the start of the register area, 153622944501Smrg * - \p size will be the size of the register area bytes, and 153722944501Smrg * - \p type will be DRM_REGISTERS. 153822944501Smrg * \par 1539fe517fc9Smrg * The area mapped will be uncached. 1540fe517fc9Smrg * 154122944501Smrg * \par Mapping the SAREA 154222944501Smrg * For the SAREA, 154322944501Smrg * - \p offset will be ignored and should be set to zero, 154422944501Smrg * - \p size will be the desired size of the SAREA in bytes, 154522944501Smrg * - \p type will be DRM_SHM. 1546fe517fc9Smrg * 154722944501Smrg * \par 154822944501Smrg * A shared memory area of the requested size will be created and locked in 154922944501Smrg * kernel memory. This area may be mapped into client-space by using the handle 1550fe517fc9Smrg * returned. 1551fe517fc9Smrg * 155222944501Smrg * \note May only be called by root. 155322944501Smrg * 155422944501Smrg * \internal 155522944501Smrg * This function is a wrapper around the DRM_IOCTL_ADD_MAP ioctl, passing 155622944501Smrg * the arguments in a drm_map structure. 155722944501Smrg */ 15586260e5d5Smrgdrm_public int drmAddMap(int fd, drm_handle_t offset, drmSize size, drmMapType type, 15596260e5d5Smrg drmMapFlags flags, drm_handle_t *handle) 156022944501Smrg{ 156122944501Smrg drm_map_t map; 156222944501Smrg 1563424e9256Smrg memclear(map); 156422944501Smrg map.offset = offset; 156522944501Smrg map.size = size; 1566adfa0b0cSmrg map.type = (enum drm_map_type)type; 1567adfa0b0cSmrg map.flags = (enum drm_map_flags)flags; 156822944501Smrg if (drmIoctl(fd, DRM_IOCTL_ADD_MAP, &map)) 1569fe517fc9Smrg return -errno; 157022944501Smrg if (handle) 1571fe517fc9Smrg *handle = (drm_handle_t)(uintptr_t)map.handle; 157222944501Smrg return 0; 157322944501Smrg} 157422944501Smrg 15756260e5d5Smrgdrm_public int drmRmMap(int fd, drm_handle_t handle) 157622944501Smrg{ 157722944501Smrg drm_map_t map; 157822944501Smrg 1579424e9256Smrg memclear(map); 158020131375Smrg map.handle = (void *)(uintptr_t)handle; 158122944501Smrg 158222944501Smrg if(drmIoctl(fd, DRM_IOCTL_RM_MAP, &map)) 1583fe517fc9Smrg return -errno; 158422944501Smrg return 0; 158522944501Smrg} 158622944501Smrg 158722944501Smrg/** 158822944501Smrg * Make buffers available for DMA transfers. 1589fe517fc9Smrg * 159022944501Smrg * \param fd file descriptor. 159122944501Smrg * \param count number of buffers. 159222944501Smrg * \param size size of each buffer. 159322944501Smrg * \param flags buffer allocation flags. 1594fe517fc9Smrg * \param agp_offset offset in the AGP aperture 159522944501Smrg * 159622944501Smrg * \return number of buffers allocated, negative on error. 159722944501Smrg * 159822944501Smrg * \internal 159922944501Smrg * This function is a wrapper around DRM_IOCTL_ADD_BUFS ioctl. 160022944501Smrg * 160122944501Smrg * \sa drm_buf_desc. 160222944501Smrg */ 16036260e5d5Smrgdrm_public int drmAddBufs(int fd, int count, int size, drmBufDescFlags flags, 16046260e5d5Smrg int agp_offset) 160522944501Smrg{ 160622944501Smrg drm_buf_desc_t request; 160722944501Smrg 1608424e9256Smrg memclear(request); 160922944501Smrg request.count = count; 161022944501Smrg request.size = size; 1611adfa0b0cSmrg request.flags = (int)flags; 161222944501Smrg request.agp_start = agp_offset; 161322944501Smrg 161422944501Smrg if (drmIoctl(fd, DRM_IOCTL_ADD_BUFS, &request)) 1615fe517fc9Smrg return -errno; 161622944501Smrg return request.count; 161722944501Smrg} 161822944501Smrg 16196260e5d5Smrgdrm_public int drmMarkBufs(int fd, double low, double high) 162022944501Smrg{ 162122944501Smrg drm_buf_info_t info; 162222944501Smrg int i; 162322944501Smrg 1624424e9256Smrg memclear(info); 162522944501Smrg 162622944501Smrg if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info)) 1627fe517fc9Smrg return -EINVAL; 162822944501Smrg 162922944501Smrg if (!info.count) 1630fe517fc9Smrg return -EINVAL; 163122944501Smrg 163222944501Smrg if (!(info.list = drmMalloc(info.count * sizeof(*info.list)))) 1633fe517fc9Smrg return -ENOMEM; 163422944501Smrg 163522944501Smrg if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info)) { 1636fe517fc9Smrg int retval = -errno; 1637fe517fc9Smrg drmFree(info.list); 1638fe517fc9Smrg return retval; 163922944501Smrg } 164022944501Smrg 164122944501Smrg for (i = 0; i < info.count; i++) { 1642fe517fc9Smrg info.list[i].low_mark = low * info.list[i].count; 1643fe517fc9Smrg info.list[i].high_mark = high * info.list[i].count; 1644fe517fc9Smrg if (drmIoctl(fd, DRM_IOCTL_MARK_BUFS, &info.list[i])) { 1645fe517fc9Smrg int retval = -errno; 1646fe517fc9Smrg drmFree(info.list); 1647fe517fc9Smrg return retval; 1648fe517fc9Smrg } 164922944501Smrg } 165022944501Smrg drmFree(info.list); 165122944501Smrg 165222944501Smrg return 0; 165322944501Smrg} 165422944501Smrg 165522944501Smrg/** 165622944501Smrg * Free buffers. 165722944501Smrg * 165822944501Smrg * \param fd file descriptor. 165922944501Smrg * \param count number of buffers to free. 166022944501Smrg * \param list list of buffers to be freed. 166122944501Smrg * 166222944501Smrg * \return zero on success, or a negative value on failure. 1663fe517fc9Smrg * 166422944501Smrg * \note This function is primarily used for debugging. 1665fe517fc9Smrg * 166622944501Smrg * \internal 166722944501Smrg * This function is a wrapper around the DRM_IOCTL_FREE_BUFS ioctl, passing 166822944501Smrg * the arguments in a drm_buf_free structure. 166922944501Smrg */ 16706260e5d5Smrgdrm_public int drmFreeBufs(int fd, int count, int *list) 167122944501Smrg{ 167222944501Smrg drm_buf_free_t request; 167322944501Smrg 1674424e9256Smrg memclear(request); 167522944501Smrg request.count = count; 167622944501Smrg request.list = list; 167722944501Smrg if (drmIoctl(fd, DRM_IOCTL_FREE_BUFS, &request)) 1678fe517fc9Smrg return -errno; 167922944501Smrg return 0; 168022944501Smrg} 168122944501Smrg 168222944501Smrg 168322944501Smrg/** 168422944501Smrg * Close the device. 168522944501Smrg * 168622944501Smrg * \param fd file descriptor. 168722944501Smrg * 168822944501Smrg * \internal 168922944501Smrg * This function closes the file descriptor. 169022944501Smrg */ 16916260e5d5Smrgdrm_public int drmClose(int fd) 169222944501Smrg{ 169322944501Smrg unsigned long key = drmGetKeyFromFd(fd); 169422944501Smrg drmHashEntry *entry = drmGetEntry(fd); 169522944501Smrg 169622944501Smrg drmHashDestroy(entry->tagTable); 169722944501Smrg entry->fd = 0; 169822944501Smrg entry->f = NULL; 169922944501Smrg entry->tagTable = NULL; 170022944501Smrg 170122944501Smrg drmHashDelete(drmHashTable, key); 170222944501Smrg drmFree(entry); 170322944501Smrg 170422944501Smrg return close(fd); 170522944501Smrg} 170622944501Smrg 170722944501Smrg 170822944501Smrg/** 170922944501Smrg * Map a region of memory. 171022944501Smrg * 171122944501Smrg * \param fd file descriptor. 171222944501Smrg * \param handle handle returned by drmAddMap(). 171322944501Smrg * \param size size in bytes. Must match the size used by drmAddMap(). 171422944501Smrg * \param address will contain the user-space virtual address where the mapping 171522944501Smrg * begins. 171622944501Smrg * 171722944501Smrg * \return zero on success, or a negative value on failure. 1718fe517fc9Smrg * 171922944501Smrg * \internal 172022944501Smrg * This function is a wrapper for mmap(). 172122944501Smrg */ 17226260e5d5Smrgdrm_public int drmMap(int fd, drm_handle_t handle, drmSize size, 17236260e5d5Smrg drmAddressPtr address) 172422944501Smrg{ 172522944501Smrg static unsigned long pagesize_mask = 0; 172622944501Smrg 172722944501Smrg if (fd < 0) 1728fe517fc9Smrg return -EINVAL; 172922944501Smrg 173022944501Smrg if (!pagesize_mask) 1731fe517fc9Smrg pagesize_mask = getpagesize() - 1; 173222944501Smrg 173322944501Smrg size = (size + pagesize_mask) & ~pagesize_mask; 173422944501Smrg 1735a884aba1Smrg *address = drm_mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, handle); 173622944501Smrg if (*address == MAP_FAILED) 1737fe517fc9Smrg return -errno; 173822944501Smrg return 0; 173922944501Smrg} 174022944501Smrg 174122944501Smrg 174222944501Smrg/** 174322944501Smrg * Unmap mappings obtained with drmMap(). 174422944501Smrg * 174522944501Smrg * \param address address as given by drmMap(). 174622944501Smrg * \param size size in bytes. Must match the size used by drmMap(). 1747fe517fc9Smrg * 174822944501Smrg * \return zero on success, or a negative value on failure. 174922944501Smrg * 175022944501Smrg * \internal 175122944501Smrg * This function is a wrapper for munmap(). 175222944501Smrg */ 17536260e5d5Smrgdrm_public int drmUnmap(drmAddress address, drmSize size) 175422944501Smrg{ 1755a884aba1Smrg return drm_munmap(address, size); 175622944501Smrg} 175722944501Smrg 17586260e5d5Smrgdrm_public drmBufInfoPtr drmGetBufInfo(int fd) 175922944501Smrg{ 176022944501Smrg drm_buf_info_t info; 176122944501Smrg drmBufInfoPtr retval; 176222944501Smrg int i; 176322944501Smrg 1764424e9256Smrg memclear(info); 176522944501Smrg 176622944501Smrg if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info)) 1767fe517fc9Smrg return NULL; 176822944501Smrg 176922944501Smrg if (info.count) { 1770fe517fc9Smrg if (!(info.list = drmMalloc(info.count * sizeof(*info.list)))) 1771fe517fc9Smrg return NULL; 1772fe517fc9Smrg 1773fe517fc9Smrg if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info)) { 1774fe517fc9Smrg drmFree(info.list); 1775fe517fc9Smrg return NULL; 1776fe517fc9Smrg } 1777fe517fc9Smrg 1778fe517fc9Smrg retval = drmMalloc(sizeof(*retval)); 1779fe517fc9Smrg retval->count = info.count; 17804b3d3f37Smrg if (!(retval->list = drmMalloc(info.count * sizeof(*retval->list)))) { 17814b3d3f37Smrg drmFree(retval); 17824b3d3f37Smrg drmFree(info.list); 17834b3d3f37Smrg return NULL; 17844b3d3f37Smrg } 17854b3d3f37Smrg 1786fe517fc9Smrg for (i = 0; i < info.count; i++) { 1787fe517fc9Smrg retval->list[i].count = info.list[i].count; 1788fe517fc9Smrg retval->list[i].size = info.list[i].size; 1789fe517fc9Smrg retval->list[i].low_mark = info.list[i].low_mark; 1790fe517fc9Smrg retval->list[i].high_mark = info.list[i].high_mark; 1791fe517fc9Smrg } 1792fe517fc9Smrg drmFree(info.list); 1793fe517fc9Smrg return retval; 179422944501Smrg } 179522944501Smrg return NULL; 179622944501Smrg} 179722944501Smrg 179822944501Smrg/** 179922944501Smrg * Map all DMA buffers into client-virtual space. 180022944501Smrg * 180122944501Smrg * \param fd file descriptor. 180222944501Smrg * 180322944501Smrg * \return a pointer to a ::drmBufMap structure. 180422944501Smrg * 180522944501Smrg * \note The client may not use these buffers until obtaining buffer indices 180622944501Smrg * with drmDMA(). 1807fe517fc9Smrg * 180822944501Smrg * \internal 180922944501Smrg * This function calls the DRM_IOCTL_MAP_BUFS ioctl and copies the returned 181022944501Smrg * information about the buffers in a drm_buf_map structure into the 181122944501Smrg * client-visible data structures. 1812fe517fc9Smrg */ 18136260e5d5Smrgdrm_public drmBufMapPtr drmMapBufs(int fd) 181422944501Smrg{ 181522944501Smrg drm_buf_map_t bufs; 181622944501Smrg drmBufMapPtr retval; 181722944501Smrg int i; 181822944501Smrg 1819424e9256Smrg memclear(bufs); 182022944501Smrg if (drmIoctl(fd, DRM_IOCTL_MAP_BUFS, &bufs)) 1821fe517fc9Smrg return NULL; 182222944501Smrg 182322944501Smrg if (!bufs.count) 1824fe517fc9Smrg return NULL; 182522944501Smrg 1826fe517fc9Smrg if (!(bufs.list = drmMalloc(bufs.count * sizeof(*bufs.list)))) 1827fe517fc9Smrg return NULL; 182822944501Smrg 1829fe517fc9Smrg if (drmIoctl(fd, DRM_IOCTL_MAP_BUFS, &bufs)) { 1830fe517fc9Smrg drmFree(bufs.list); 1831fe517fc9Smrg return NULL; 1832fe517fc9Smrg } 183322944501Smrg 1834fe517fc9Smrg retval = drmMalloc(sizeof(*retval)); 1835fe517fc9Smrg retval->count = bufs.count; 1836fe517fc9Smrg retval->list = drmMalloc(bufs.count * sizeof(*retval->list)); 1837fe517fc9Smrg for (i = 0; i < bufs.count; i++) { 1838fe517fc9Smrg retval->list[i].idx = bufs.list[i].idx; 1839fe517fc9Smrg retval->list[i].total = bufs.list[i].total; 1840fe517fc9Smrg retval->list[i].used = 0; 1841fe517fc9Smrg retval->list[i].address = bufs.list[i].address; 1842fe517fc9Smrg } 184322944501Smrg 1844fe517fc9Smrg drmFree(bufs.list); 1845fe517fc9Smrg return retval; 184622944501Smrg} 184722944501Smrg 184822944501Smrg 184922944501Smrg/** 185022944501Smrg * Unmap buffers allocated with drmMapBufs(). 185122944501Smrg * 185222944501Smrg * \return zero on success, or negative value on failure. 185322944501Smrg * 185422944501Smrg * \internal 185522944501Smrg * Calls munmap() for every buffer stored in \p bufs and frees the 185622944501Smrg * memory allocated by drmMapBufs(). 185722944501Smrg */ 18586260e5d5Smrgdrm_public int drmUnmapBufs(drmBufMapPtr bufs) 185922944501Smrg{ 186022944501Smrg int i; 186122944501Smrg 186222944501Smrg for (i = 0; i < bufs->count; i++) { 1863fe517fc9Smrg drm_munmap(bufs->list[i].address, bufs->list[i].total); 186422944501Smrg } 186522944501Smrg 186622944501Smrg drmFree(bufs->list); 186722944501Smrg drmFree(bufs); 186822944501Smrg return 0; 186922944501Smrg} 187022944501Smrg 187122944501Smrg 1872fe517fc9Smrg#define DRM_DMA_RETRY 16 187322944501Smrg 187422944501Smrg/** 187522944501Smrg * Reserve DMA buffers. 187622944501Smrg * 187722944501Smrg * \param fd file descriptor. 1878fe517fc9Smrg * \param request 1879fe517fc9Smrg * 188022944501Smrg * \return zero on success, or a negative value on failure. 188122944501Smrg * 188222944501Smrg * \internal 188322944501Smrg * Assemble the arguments into a drm_dma structure and keeps issuing the 188422944501Smrg * DRM_IOCTL_DMA ioctl until success or until maximum number of retries. 188522944501Smrg */ 18866260e5d5Smrgdrm_public int drmDMA(int fd, drmDMAReqPtr request) 188722944501Smrg{ 188822944501Smrg drm_dma_t dma; 188922944501Smrg int ret, i = 0; 189022944501Smrg 189122944501Smrg dma.context = request->context; 189222944501Smrg dma.send_count = request->send_count; 189322944501Smrg dma.send_indices = request->send_list; 189422944501Smrg dma.send_sizes = request->send_sizes; 1895adfa0b0cSmrg dma.flags = (enum drm_dma_flags)request->flags; 189622944501Smrg dma.request_count = request->request_count; 189722944501Smrg dma.request_size = request->request_size; 189822944501Smrg dma.request_indices = request->request_list; 189922944501Smrg dma.request_sizes = request->request_sizes; 190022944501Smrg dma.granted_count = 0; 190122944501Smrg 190222944501Smrg do { 1903fe517fc9Smrg ret = ioctl( fd, DRM_IOCTL_DMA, &dma ); 190422944501Smrg } while ( ret && errno == EAGAIN && i++ < DRM_DMA_RETRY ); 190522944501Smrg 190622944501Smrg if ( ret == 0 ) { 1907fe517fc9Smrg request->granted_count = dma.granted_count; 1908fe517fc9Smrg return 0; 190922944501Smrg } else { 1910fe517fc9Smrg return -errno; 191122944501Smrg } 191222944501Smrg} 191322944501Smrg 191422944501Smrg 191522944501Smrg/** 191622944501Smrg * Obtain heavyweight hardware lock. 191722944501Smrg * 191822944501Smrg * \param fd file descriptor. 191922944501Smrg * \param context context. 1920bf6cc7dcSmrg * \param flags flags that determine the state of the hardware when the function 192122944501Smrg * returns. 1922fe517fc9Smrg * 192322944501Smrg * \return always zero. 1924fe517fc9Smrg * 192522944501Smrg * \internal 192622944501Smrg * This function translates the arguments into a drm_lock structure and issue 192722944501Smrg * the DRM_IOCTL_LOCK ioctl until the lock is successfully acquired. 192822944501Smrg */ 19296260e5d5Smrgdrm_public int drmGetLock(int fd, drm_context_t context, drmLockFlags flags) 193022944501Smrg{ 193122944501Smrg drm_lock_t lock; 193222944501Smrg 1933424e9256Smrg memclear(lock); 193422944501Smrg lock.context = context; 193522944501Smrg lock.flags = 0; 193622944501Smrg if (flags & DRM_LOCK_READY) lock.flags |= _DRM_LOCK_READY; 193722944501Smrg if (flags & DRM_LOCK_QUIESCENT) lock.flags |= _DRM_LOCK_QUIESCENT; 193822944501Smrg if (flags & DRM_LOCK_FLUSH) lock.flags |= _DRM_LOCK_FLUSH; 193922944501Smrg if (flags & DRM_LOCK_FLUSH_ALL) lock.flags |= _DRM_LOCK_FLUSH_ALL; 194022944501Smrg if (flags & DRM_HALT_ALL_QUEUES) lock.flags |= _DRM_HALT_ALL_QUEUES; 194122944501Smrg if (flags & DRM_HALT_CUR_QUEUES) lock.flags |= _DRM_HALT_CUR_QUEUES; 194222944501Smrg 194322944501Smrg while (drmIoctl(fd, DRM_IOCTL_LOCK, &lock)) 1944fe517fc9Smrg ; 194522944501Smrg return 0; 194622944501Smrg} 194722944501Smrg 194822944501Smrg/** 194922944501Smrg * Release the hardware lock. 195022944501Smrg * 195122944501Smrg * \param fd file descriptor. 195222944501Smrg * \param context context. 1953fe517fc9Smrg * 195422944501Smrg * \return zero on success, or a negative value on failure. 1955fe517fc9Smrg * 195622944501Smrg * \internal 195722944501Smrg * This function is a wrapper around the DRM_IOCTL_UNLOCK ioctl, passing the 195822944501Smrg * argument in a drm_lock structure. 195922944501Smrg */ 19606260e5d5Smrgdrm_public int drmUnlock(int fd, drm_context_t context) 196122944501Smrg{ 196222944501Smrg drm_lock_t lock; 196322944501Smrg 1964424e9256Smrg memclear(lock); 196522944501Smrg lock.context = context; 196622944501Smrg return drmIoctl(fd, DRM_IOCTL_UNLOCK, &lock); 196722944501Smrg} 196822944501Smrg 19696260e5d5Smrgdrm_public drm_context_t *drmGetReservedContextList(int fd, int *count) 197022944501Smrg{ 197122944501Smrg drm_ctx_res_t res; 197222944501Smrg drm_ctx_t *list; 197322944501Smrg drm_context_t * retval; 197422944501Smrg int i; 197522944501Smrg 1976424e9256Smrg memclear(res); 197722944501Smrg if (drmIoctl(fd, DRM_IOCTL_RES_CTX, &res)) 1978fe517fc9Smrg return NULL; 197922944501Smrg 198022944501Smrg if (!res.count) 1981fe517fc9Smrg return NULL; 198222944501Smrg 198322944501Smrg if (!(list = drmMalloc(res.count * sizeof(*list)))) 1984fe517fc9Smrg return NULL; 19850655efefSmrg if (!(retval = drmMalloc(res.count * sizeof(*retval)))) 19860655efefSmrg goto err_free_list; 198722944501Smrg 198822944501Smrg res.contexts = list; 198922944501Smrg if (drmIoctl(fd, DRM_IOCTL_RES_CTX, &res)) 19900655efefSmrg goto err_free_context; 199122944501Smrg 199222944501Smrg for (i = 0; i < res.count; i++) 1993fe517fc9Smrg retval[i] = list[i].handle; 199422944501Smrg drmFree(list); 199522944501Smrg 199622944501Smrg *count = res.count; 199722944501Smrg return retval; 19980655efefSmrg 19990655efefSmrgerr_free_list: 20000655efefSmrg drmFree(list); 20010655efefSmrgerr_free_context: 20020655efefSmrg drmFree(retval); 20030655efefSmrg return NULL; 200422944501Smrg} 200522944501Smrg 20066260e5d5Smrgdrm_public void drmFreeReservedContextList(drm_context_t *pt) 200722944501Smrg{ 200822944501Smrg drmFree(pt); 200922944501Smrg} 201022944501Smrg 201122944501Smrg/** 201222944501Smrg * Create context. 201322944501Smrg * 201422944501Smrg * Used by the X server during GLXContext initialization. This causes 201522944501Smrg * per-context kernel-level resources to be allocated. 201622944501Smrg * 201722944501Smrg * \param fd file descriptor. 201822944501Smrg * \param handle is set on success. To be used by the client when requesting DMA 201922944501Smrg * dispatch with drmDMA(). 2020fe517fc9Smrg * 202122944501Smrg * \return zero on success, or a negative value on failure. 2022fe517fc9Smrg * 202322944501Smrg * \note May only be called by root. 2024fe517fc9Smrg * 202522944501Smrg * \internal 202622944501Smrg * This function is a wrapper around the DRM_IOCTL_ADD_CTX ioctl, passing the 202722944501Smrg * argument in a drm_ctx structure. 202822944501Smrg */ 20296260e5d5Smrgdrm_public int drmCreateContext(int fd, drm_context_t *handle) 203022944501Smrg{ 203122944501Smrg drm_ctx_t ctx; 203222944501Smrg 2033424e9256Smrg memclear(ctx); 203422944501Smrg if (drmIoctl(fd, DRM_IOCTL_ADD_CTX, &ctx)) 2035fe517fc9Smrg return -errno; 203622944501Smrg *handle = ctx.handle; 203722944501Smrg return 0; 203822944501Smrg} 203922944501Smrg 20406260e5d5Smrgdrm_public int drmSwitchToContext(int fd, drm_context_t context) 204122944501Smrg{ 204222944501Smrg drm_ctx_t ctx; 204322944501Smrg 2044424e9256Smrg memclear(ctx); 204522944501Smrg ctx.handle = context; 204622944501Smrg if (drmIoctl(fd, DRM_IOCTL_SWITCH_CTX, &ctx)) 2047fe517fc9Smrg return -errno; 204822944501Smrg return 0; 204922944501Smrg} 205022944501Smrg 20516260e5d5Smrgdrm_public int drmSetContextFlags(int fd, drm_context_t context, 20526260e5d5Smrg drm_context_tFlags flags) 205322944501Smrg{ 205422944501Smrg drm_ctx_t ctx; 205522944501Smrg 205622944501Smrg /* 205722944501Smrg * Context preserving means that no context switches are done between DMA 205822944501Smrg * buffers from one context and the next. This is suitable for use in the 205922944501Smrg * X server (which promises to maintain hardware context), or in the 206022944501Smrg * client-side library when buffers are swapped on behalf of two threads. 206122944501Smrg */ 2062424e9256Smrg memclear(ctx); 206322944501Smrg ctx.handle = context; 206422944501Smrg if (flags & DRM_CONTEXT_PRESERVED) 2065fe517fc9Smrg ctx.flags |= _DRM_CONTEXT_PRESERVED; 206622944501Smrg if (flags & DRM_CONTEXT_2DONLY) 2067fe517fc9Smrg ctx.flags |= _DRM_CONTEXT_2DONLY; 206822944501Smrg if (drmIoctl(fd, DRM_IOCTL_MOD_CTX, &ctx)) 2069fe517fc9Smrg return -errno; 207022944501Smrg return 0; 207122944501Smrg} 207222944501Smrg 20736260e5d5Smrgdrm_public int drmGetContextFlags(int fd, drm_context_t context, 20746260e5d5Smrg drm_context_tFlagsPtr flags) 207522944501Smrg{ 207622944501Smrg drm_ctx_t ctx; 207722944501Smrg 2078424e9256Smrg memclear(ctx); 207922944501Smrg ctx.handle = context; 208022944501Smrg if (drmIoctl(fd, DRM_IOCTL_GET_CTX, &ctx)) 2081fe517fc9Smrg return -errno; 208222944501Smrg *flags = 0; 208322944501Smrg if (ctx.flags & _DRM_CONTEXT_PRESERVED) 2084fe517fc9Smrg *flags |= DRM_CONTEXT_PRESERVED; 208522944501Smrg if (ctx.flags & _DRM_CONTEXT_2DONLY) 2086fe517fc9Smrg *flags |= DRM_CONTEXT_2DONLY; 208722944501Smrg return 0; 208822944501Smrg} 208922944501Smrg 209022944501Smrg/** 209122944501Smrg * Destroy context. 209222944501Smrg * 209322944501Smrg * Free any kernel-level resources allocated with drmCreateContext() associated 209422944501Smrg * with the context. 2095fe517fc9Smrg * 209622944501Smrg * \param fd file descriptor. 209722944501Smrg * \param handle handle given by drmCreateContext(). 2098fe517fc9Smrg * 209922944501Smrg * \return zero on success, or a negative value on failure. 2100fe517fc9Smrg * 210122944501Smrg * \note May only be called by root. 2102fe517fc9Smrg * 210322944501Smrg * \internal 210422944501Smrg * This function is a wrapper around the DRM_IOCTL_RM_CTX ioctl, passing the 210522944501Smrg * argument in a drm_ctx structure. 210622944501Smrg */ 21076260e5d5Smrgdrm_public int drmDestroyContext(int fd, drm_context_t handle) 210822944501Smrg{ 210922944501Smrg drm_ctx_t ctx; 2110424e9256Smrg 2111424e9256Smrg memclear(ctx); 211222944501Smrg ctx.handle = handle; 211322944501Smrg if (drmIoctl(fd, DRM_IOCTL_RM_CTX, &ctx)) 2114fe517fc9Smrg return -errno; 211522944501Smrg return 0; 211622944501Smrg} 211722944501Smrg 21186260e5d5Smrgdrm_public int drmCreateDrawable(int fd, drm_drawable_t *handle) 211922944501Smrg{ 212022944501Smrg drm_draw_t draw; 2121424e9256Smrg 2122424e9256Smrg memclear(draw); 212322944501Smrg if (drmIoctl(fd, DRM_IOCTL_ADD_DRAW, &draw)) 2124fe517fc9Smrg return -errno; 212522944501Smrg *handle = draw.handle; 212622944501Smrg return 0; 212722944501Smrg} 212822944501Smrg 21296260e5d5Smrgdrm_public int drmDestroyDrawable(int fd, drm_drawable_t handle) 213022944501Smrg{ 213122944501Smrg drm_draw_t draw; 2132424e9256Smrg 2133424e9256Smrg memclear(draw); 213422944501Smrg draw.handle = handle; 213522944501Smrg if (drmIoctl(fd, DRM_IOCTL_RM_DRAW, &draw)) 2136fe517fc9Smrg return -errno; 213722944501Smrg return 0; 213822944501Smrg} 213922944501Smrg 21406260e5d5Smrgdrm_public int drmUpdateDrawableInfo(int fd, drm_drawable_t handle, 21416260e5d5Smrg drm_drawable_info_type_t type, 21426260e5d5Smrg unsigned int num, void *data) 214322944501Smrg{ 214422944501Smrg drm_update_draw_t update; 214522944501Smrg 2146424e9256Smrg memclear(update); 214722944501Smrg update.handle = handle; 214822944501Smrg update.type = type; 214922944501Smrg update.num = num; 215022944501Smrg update.data = (unsigned long long)(unsigned long)data; 215122944501Smrg 215222944501Smrg if (drmIoctl(fd, DRM_IOCTL_UPDATE_DRAW, &update)) 2153fe517fc9Smrg return -errno; 215422944501Smrg 215522944501Smrg return 0; 215622944501Smrg} 215722944501Smrg 21586260e5d5Smrgdrm_public int drmCrtcGetSequence(int fd, uint32_t crtcId, uint64_t *sequence, 21596260e5d5Smrg uint64_t *ns) 21602b90624aSmrg{ 21612b90624aSmrg struct drm_crtc_get_sequence get_seq; 21622b90624aSmrg int ret; 21632b90624aSmrg 21642b90624aSmrg memclear(get_seq); 21652b90624aSmrg get_seq.crtc_id = crtcId; 21662b90624aSmrg ret = drmIoctl(fd, DRM_IOCTL_CRTC_GET_SEQUENCE, &get_seq); 21672b90624aSmrg if (ret) 21682b90624aSmrg return ret; 21692b90624aSmrg 21702b90624aSmrg if (sequence) 21712b90624aSmrg *sequence = get_seq.sequence; 21722b90624aSmrg if (ns) 21732b90624aSmrg *ns = get_seq.sequence_ns; 21742b90624aSmrg return 0; 21752b90624aSmrg} 21762b90624aSmrg 21776260e5d5Smrgdrm_public int drmCrtcQueueSequence(int fd, uint32_t crtcId, uint32_t flags, 21786260e5d5Smrg uint64_t sequence, 21796260e5d5Smrg uint64_t *sequence_queued, 21806260e5d5Smrg uint64_t user_data) 21812b90624aSmrg{ 21822b90624aSmrg struct drm_crtc_queue_sequence queue_seq; 21832b90624aSmrg int ret; 21842b90624aSmrg 21852b90624aSmrg memclear(queue_seq); 21862b90624aSmrg queue_seq.crtc_id = crtcId; 21872b90624aSmrg queue_seq.flags = flags; 21882b90624aSmrg queue_seq.sequence = sequence; 21892b90624aSmrg queue_seq.user_data = user_data; 21902b90624aSmrg 21912b90624aSmrg ret = drmIoctl(fd, DRM_IOCTL_CRTC_QUEUE_SEQUENCE, &queue_seq); 21922b90624aSmrg if (ret == 0 && sequence_queued) 21932b90624aSmrg *sequence_queued = queue_seq.sequence; 21942b90624aSmrg 21952b90624aSmrg return ret; 21962b90624aSmrg} 21972b90624aSmrg 219822944501Smrg/** 219922944501Smrg * Acquire the AGP device. 220022944501Smrg * 220122944501Smrg * Must be called before any of the other AGP related calls. 220222944501Smrg * 220322944501Smrg * \param fd file descriptor. 2204fe517fc9Smrg * 220522944501Smrg * \return zero on success, or a negative value on failure. 2206fe517fc9Smrg * 220722944501Smrg * \internal 220822944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_ACQUIRE ioctl. 220922944501Smrg */ 22106260e5d5Smrgdrm_public int drmAgpAcquire(int fd) 221122944501Smrg{ 221222944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_ACQUIRE, NULL)) 2213fe517fc9Smrg return -errno; 221422944501Smrg return 0; 221522944501Smrg} 221622944501Smrg 221722944501Smrg 221822944501Smrg/** 221922944501Smrg * Release the AGP device. 222022944501Smrg * 222122944501Smrg * \param fd file descriptor. 2222fe517fc9Smrg * 222322944501Smrg * \return zero on success, or a negative value on failure. 2224fe517fc9Smrg * 222522944501Smrg * \internal 222622944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_RELEASE ioctl. 222722944501Smrg */ 22286260e5d5Smrgdrm_public int drmAgpRelease(int fd) 222922944501Smrg{ 223022944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_RELEASE, NULL)) 2231fe517fc9Smrg return -errno; 223222944501Smrg return 0; 223322944501Smrg} 223422944501Smrg 223522944501Smrg 223622944501Smrg/** 223722944501Smrg * Set the AGP mode. 223822944501Smrg * 223922944501Smrg * \param fd file descriptor. 224022944501Smrg * \param mode AGP mode. 2241fe517fc9Smrg * 224222944501Smrg * \return zero on success, or a negative value on failure. 2243fe517fc9Smrg * 224422944501Smrg * \internal 224522944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_ENABLE ioctl, passing the 224622944501Smrg * argument in a drm_agp_mode structure. 224722944501Smrg */ 22486260e5d5Smrgdrm_public int drmAgpEnable(int fd, unsigned long mode) 224922944501Smrg{ 225022944501Smrg drm_agp_mode_t m; 225122944501Smrg 2252424e9256Smrg memclear(m); 225322944501Smrg m.mode = mode; 225422944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_ENABLE, &m)) 2255fe517fc9Smrg return -errno; 225622944501Smrg return 0; 225722944501Smrg} 225822944501Smrg 225922944501Smrg 226022944501Smrg/** 226122944501Smrg * Allocate a chunk of AGP memory. 226222944501Smrg * 226322944501Smrg * \param fd file descriptor. 226422944501Smrg * \param size requested memory size in bytes. Will be rounded to page boundary. 226522944501Smrg * \param type type of memory to allocate. 226622944501Smrg * \param address if not zero, will be set to the physical address of the 226722944501Smrg * allocated memory. 226822944501Smrg * \param handle on success will be set to a handle of the allocated memory. 2269fe517fc9Smrg * 227022944501Smrg * \return zero on success, or a negative value on failure. 2271fe517fc9Smrg * 227222944501Smrg * \internal 227322944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_ALLOC ioctl, passing the 227422944501Smrg * arguments in a drm_agp_buffer structure. 227522944501Smrg */ 22766260e5d5Smrgdrm_public int drmAgpAlloc(int fd, unsigned long size, unsigned long type, 22776260e5d5Smrg unsigned long *address, drm_handle_t *handle) 227822944501Smrg{ 227922944501Smrg drm_agp_buffer_t b; 228022944501Smrg 2281424e9256Smrg memclear(b); 228222944501Smrg *handle = DRM_AGP_NO_HANDLE; 228322944501Smrg b.size = size; 228422944501Smrg b.type = type; 228522944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_ALLOC, &b)) 2286fe517fc9Smrg return -errno; 228722944501Smrg if (address != 0UL) 2288fe517fc9Smrg *address = b.physical; 228922944501Smrg *handle = b.handle; 229022944501Smrg return 0; 229122944501Smrg} 229222944501Smrg 229322944501Smrg 229422944501Smrg/** 229522944501Smrg * Free a chunk of AGP memory. 229622944501Smrg * 229722944501Smrg * \param fd file descriptor. 229822944501Smrg * \param handle handle to the allocated memory, as given by drmAgpAllocate(). 2299fe517fc9Smrg * 230022944501Smrg * \return zero on success, or a negative value on failure. 2301fe517fc9Smrg * 230222944501Smrg * \internal 230322944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_FREE ioctl, passing the 230422944501Smrg * argument in a drm_agp_buffer structure. 230522944501Smrg */ 23066260e5d5Smrgdrm_public int drmAgpFree(int fd, drm_handle_t handle) 230722944501Smrg{ 230822944501Smrg drm_agp_buffer_t b; 230922944501Smrg 2310424e9256Smrg memclear(b); 231122944501Smrg b.handle = handle; 231222944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_FREE, &b)) 2313fe517fc9Smrg return -errno; 231422944501Smrg return 0; 231522944501Smrg} 231622944501Smrg 231722944501Smrg 231822944501Smrg/** 231922944501Smrg * Bind a chunk of AGP memory. 232022944501Smrg * 232122944501Smrg * \param fd file descriptor. 232222944501Smrg * \param handle handle to the allocated memory, as given by drmAgpAllocate(). 232322944501Smrg * \param offset offset in bytes. It will round to page boundary. 2324fe517fc9Smrg * 232522944501Smrg * \return zero on success, or a negative value on failure. 2326fe517fc9Smrg * 232722944501Smrg * \internal 232822944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_BIND ioctl, passing the 232922944501Smrg * argument in a drm_agp_binding structure. 233022944501Smrg */ 23316260e5d5Smrgdrm_public int drmAgpBind(int fd, drm_handle_t handle, unsigned long offset) 233222944501Smrg{ 233322944501Smrg drm_agp_binding_t b; 233422944501Smrg 2335424e9256Smrg memclear(b); 233622944501Smrg b.handle = handle; 233722944501Smrg b.offset = offset; 233822944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_BIND, &b)) 2339fe517fc9Smrg return -errno; 234022944501Smrg return 0; 234122944501Smrg} 234222944501Smrg 234322944501Smrg 234422944501Smrg/** 234522944501Smrg * Unbind a chunk of AGP memory. 234622944501Smrg * 234722944501Smrg * \param fd file descriptor. 234822944501Smrg * \param handle handle to the allocated memory, as given by drmAgpAllocate(). 2349fe517fc9Smrg * 235022944501Smrg * \return zero on success, or a negative value on failure. 2351fe517fc9Smrg * 235222944501Smrg * \internal 235322944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_UNBIND ioctl, passing 235422944501Smrg * the argument in a drm_agp_binding structure. 235522944501Smrg */ 23566260e5d5Smrgdrm_public int drmAgpUnbind(int fd, drm_handle_t handle) 235722944501Smrg{ 235822944501Smrg drm_agp_binding_t b; 235922944501Smrg 2360424e9256Smrg memclear(b); 236122944501Smrg b.handle = handle; 236222944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_UNBIND, &b)) 2363fe517fc9Smrg return -errno; 236422944501Smrg return 0; 236522944501Smrg} 236622944501Smrg 236722944501Smrg 236822944501Smrg/** 236922944501Smrg * Get AGP driver major version number. 237022944501Smrg * 237122944501Smrg * \param fd file descriptor. 2372fe517fc9Smrg * 237322944501Smrg * \return major version number on success, or a negative value on failure.. 2374fe517fc9Smrg * 237522944501Smrg * \internal 237622944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the 237722944501Smrg * necessary information in a drm_agp_info structure. 237822944501Smrg */ 23796260e5d5Smrgdrm_public int drmAgpVersionMajor(int fd) 238022944501Smrg{ 238122944501Smrg drm_agp_info_t i; 238222944501Smrg 2383424e9256Smrg memclear(i); 2384424e9256Smrg 238522944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i)) 2386fe517fc9Smrg return -errno; 238722944501Smrg return i.agp_version_major; 238822944501Smrg} 238922944501Smrg 239022944501Smrg 239122944501Smrg/** 239222944501Smrg * Get AGP driver minor version number. 239322944501Smrg * 239422944501Smrg * \param fd file descriptor. 2395fe517fc9Smrg * 239622944501Smrg * \return minor version number on success, or a negative value on failure. 2397fe517fc9Smrg * 239822944501Smrg * \internal 239922944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the 240022944501Smrg * necessary information in a drm_agp_info structure. 240122944501Smrg */ 24026260e5d5Smrgdrm_public int drmAgpVersionMinor(int fd) 240322944501Smrg{ 240422944501Smrg drm_agp_info_t i; 240522944501Smrg 2406424e9256Smrg memclear(i); 2407424e9256Smrg 240822944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i)) 2409fe517fc9Smrg return -errno; 241022944501Smrg return i.agp_version_minor; 241122944501Smrg} 241222944501Smrg 241322944501Smrg 241422944501Smrg/** 241522944501Smrg * Get AGP mode. 241622944501Smrg * 241722944501Smrg * \param fd file descriptor. 2418fe517fc9Smrg * 241922944501Smrg * \return mode on success, or zero on failure. 2420fe517fc9Smrg * 242122944501Smrg * \internal 242222944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the 242322944501Smrg * necessary information in a drm_agp_info structure. 242422944501Smrg */ 24256260e5d5Smrgdrm_public unsigned long drmAgpGetMode(int fd) 242622944501Smrg{ 242722944501Smrg drm_agp_info_t i; 242822944501Smrg 2429424e9256Smrg memclear(i); 2430424e9256Smrg 243122944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i)) 2432fe517fc9Smrg return 0; 243322944501Smrg return i.mode; 243422944501Smrg} 243522944501Smrg 243622944501Smrg 243722944501Smrg/** 243822944501Smrg * Get AGP aperture base. 243922944501Smrg * 244022944501Smrg * \param fd file descriptor. 2441fe517fc9Smrg * 244222944501Smrg * \return aperture base on success, zero on failure. 2443fe517fc9Smrg * 244422944501Smrg * \internal 244522944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the 244622944501Smrg * necessary information in a drm_agp_info structure. 244722944501Smrg */ 24486260e5d5Smrgdrm_public unsigned long drmAgpBase(int fd) 244922944501Smrg{ 245022944501Smrg drm_agp_info_t i; 245122944501Smrg 2452424e9256Smrg memclear(i); 2453424e9256Smrg 245422944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i)) 2455fe517fc9Smrg return 0; 245622944501Smrg return i.aperture_base; 245722944501Smrg} 245822944501Smrg 245922944501Smrg 246022944501Smrg/** 246122944501Smrg * Get AGP aperture size. 246222944501Smrg * 246322944501Smrg * \param fd file descriptor. 2464fe517fc9Smrg * 246522944501Smrg * \return aperture size on success, zero on failure. 2466fe517fc9Smrg * 246722944501Smrg * \internal 246822944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the 246922944501Smrg * necessary information in a drm_agp_info structure. 247022944501Smrg */ 24716260e5d5Smrgdrm_public unsigned long drmAgpSize(int fd) 247222944501Smrg{ 247322944501Smrg drm_agp_info_t i; 247422944501Smrg 2475424e9256Smrg memclear(i); 2476424e9256Smrg 247722944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i)) 2478fe517fc9Smrg return 0; 247922944501Smrg return i.aperture_size; 248022944501Smrg} 248122944501Smrg 248222944501Smrg 248322944501Smrg/** 248422944501Smrg * Get used AGP memory. 248522944501Smrg * 248622944501Smrg * \param fd file descriptor. 2487fe517fc9Smrg * 248822944501Smrg * \return memory used on success, or zero on failure. 2489fe517fc9Smrg * 249022944501Smrg * \internal 249122944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the 249222944501Smrg * necessary information in a drm_agp_info structure. 249322944501Smrg */ 24946260e5d5Smrgdrm_public unsigned long drmAgpMemoryUsed(int fd) 249522944501Smrg{ 249622944501Smrg drm_agp_info_t i; 249722944501Smrg 2498424e9256Smrg memclear(i); 2499424e9256Smrg 250022944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i)) 2501fe517fc9Smrg return 0; 250222944501Smrg return i.memory_used; 250322944501Smrg} 250422944501Smrg 250522944501Smrg 250622944501Smrg/** 250722944501Smrg * Get available AGP memory. 250822944501Smrg * 250922944501Smrg * \param fd file descriptor. 2510fe517fc9Smrg * 251122944501Smrg * \return memory available on success, or zero on failure. 2512fe517fc9Smrg * 251322944501Smrg * \internal 251422944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the 251522944501Smrg * necessary information in a drm_agp_info structure. 251622944501Smrg */ 25176260e5d5Smrgdrm_public unsigned long drmAgpMemoryAvail(int fd) 251822944501Smrg{ 251922944501Smrg drm_agp_info_t i; 252022944501Smrg 2521424e9256Smrg memclear(i); 2522424e9256Smrg 252322944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i)) 2524fe517fc9Smrg return 0; 252522944501Smrg return i.memory_allowed; 252622944501Smrg} 252722944501Smrg 252822944501Smrg 252922944501Smrg/** 253022944501Smrg * Get hardware vendor ID. 253122944501Smrg * 253222944501Smrg * \param fd file descriptor. 2533fe517fc9Smrg * 253422944501Smrg * \return vendor ID on success, or zero on failure. 2535fe517fc9Smrg * 253622944501Smrg * \internal 253722944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the 253822944501Smrg * necessary information in a drm_agp_info structure. 253922944501Smrg */ 25406260e5d5Smrgdrm_public unsigned int drmAgpVendorId(int fd) 254122944501Smrg{ 254222944501Smrg drm_agp_info_t i; 254322944501Smrg 2544424e9256Smrg memclear(i); 2545424e9256Smrg 254622944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i)) 2547fe517fc9Smrg return 0; 254822944501Smrg return i.id_vendor; 254922944501Smrg} 255022944501Smrg 255122944501Smrg 255222944501Smrg/** 255322944501Smrg * Get hardware device ID. 255422944501Smrg * 255522944501Smrg * \param fd file descriptor. 2556fe517fc9Smrg * 255722944501Smrg * \return zero on success, or zero on failure. 2558fe517fc9Smrg * 255922944501Smrg * \internal 256022944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the 256122944501Smrg * necessary information in a drm_agp_info structure. 256222944501Smrg */ 25636260e5d5Smrgdrm_public unsigned int drmAgpDeviceId(int fd) 256422944501Smrg{ 256522944501Smrg drm_agp_info_t i; 256622944501Smrg 2567424e9256Smrg memclear(i); 2568424e9256Smrg 256922944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i)) 2570fe517fc9Smrg return 0; 257122944501Smrg return i.id_device; 257222944501Smrg} 257322944501Smrg 25746260e5d5Smrgdrm_public int drmScatterGatherAlloc(int fd, unsigned long size, 25756260e5d5Smrg drm_handle_t *handle) 257622944501Smrg{ 257722944501Smrg drm_scatter_gather_t sg; 257822944501Smrg 2579424e9256Smrg memclear(sg); 2580424e9256Smrg 258122944501Smrg *handle = 0; 258222944501Smrg sg.size = size; 258322944501Smrg if (drmIoctl(fd, DRM_IOCTL_SG_ALLOC, &sg)) 2584fe517fc9Smrg return -errno; 258522944501Smrg *handle = sg.handle; 258622944501Smrg return 0; 258722944501Smrg} 258822944501Smrg 25896260e5d5Smrgdrm_public int drmScatterGatherFree(int fd, drm_handle_t handle) 259022944501Smrg{ 259122944501Smrg drm_scatter_gather_t sg; 259222944501Smrg 2593424e9256Smrg memclear(sg); 259422944501Smrg sg.handle = handle; 259522944501Smrg if (drmIoctl(fd, DRM_IOCTL_SG_FREE, &sg)) 2596fe517fc9Smrg return -errno; 259722944501Smrg return 0; 259822944501Smrg} 259922944501Smrg 260022944501Smrg/** 260122944501Smrg * Wait for VBLANK. 260222944501Smrg * 260322944501Smrg * \param fd file descriptor. 260422944501Smrg * \param vbl pointer to a drmVBlank structure. 2605fe517fc9Smrg * 260622944501Smrg * \return zero on success, or a negative value on failure. 2607fe517fc9Smrg * 260822944501Smrg * \internal 260922944501Smrg * This function is a wrapper around the DRM_IOCTL_WAIT_VBLANK ioctl. 261022944501Smrg */ 26116260e5d5Smrgdrm_public int drmWaitVBlank(int fd, drmVBlankPtr vbl) 261222944501Smrg{ 261322944501Smrg struct timespec timeout, cur; 261422944501Smrg int ret; 261522944501Smrg 261622944501Smrg ret = clock_gettime(CLOCK_MONOTONIC, &timeout); 261722944501Smrg if (ret < 0) { 2618fe517fc9Smrg fprintf(stderr, "clock_gettime failed: %s\n", strerror(errno)); 2619fe517fc9Smrg goto out; 262022944501Smrg } 262122944501Smrg timeout.tv_sec++; 262222944501Smrg 262322944501Smrg do { 262422944501Smrg ret = ioctl(fd, DRM_IOCTL_WAIT_VBLANK, vbl); 262522944501Smrg vbl->request.type &= ~DRM_VBLANK_RELATIVE; 262622944501Smrg if (ret && errno == EINTR) { 2627fe517fc9Smrg clock_gettime(CLOCK_MONOTONIC, &cur); 2628fe517fc9Smrg /* Timeout after 1s */ 2629fe517fc9Smrg if (cur.tv_sec > timeout.tv_sec + 1 || 2630fe517fc9Smrg (cur.tv_sec == timeout.tv_sec && cur.tv_nsec >= 2631fe517fc9Smrg timeout.tv_nsec)) { 2632fe517fc9Smrg errno = EBUSY; 2633fe517fc9Smrg ret = -1; 2634fe517fc9Smrg break; 2635fe517fc9Smrg } 263622944501Smrg } 263722944501Smrg } while (ret && errno == EINTR); 263822944501Smrg 263922944501Smrgout: 264022944501Smrg return ret; 264122944501Smrg} 264222944501Smrg 26436260e5d5Smrgdrm_public int drmError(int err, const char *label) 264422944501Smrg{ 264522944501Smrg switch (err) { 264622944501Smrg case DRM_ERR_NO_DEVICE: 2647fe517fc9Smrg fprintf(stderr, "%s: no device\n", label); 2648fe517fc9Smrg break; 264922944501Smrg case DRM_ERR_NO_ACCESS: 2650fe517fc9Smrg fprintf(stderr, "%s: no access\n", label); 2651fe517fc9Smrg break; 265222944501Smrg case DRM_ERR_NOT_ROOT: 2653fe517fc9Smrg fprintf(stderr, "%s: not root\n", label); 2654fe517fc9Smrg break; 265522944501Smrg case DRM_ERR_INVALID: 2656fe517fc9Smrg fprintf(stderr, "%s: invalid args\n", label); 2657fe517fc9Smrg break; 265822944501Smrg default: 2659fe517fc9Smrg if (err < 0) 2660fe517fc9Smrg err = -err; 2661fe517fc9Smrg fprintf( stderr, "%s: error %d (%s)\n", label, err, strerror(err) ); 2662fe517fc9Smrg break; 266322944501Smrg } 266422944501Smrg 266522944501Smrg return 1; 266622944501Smrg} 266722944501Smrg 266822944501Smrg/** 266922944501Smrg * Install IRQ handler. 267022944501Smrg * 267122944501Smrg * \param fd file descriptor. 267222944501Smrg * \param irq IRQ number. 2673fe517fc9Smrg * 267422944501Smrg * \return zero on success, or a negative value on failure. 2675fe517fc9Smrg * 267622944501Smrg * \internal 267722944501Smrg * This function is a wrapper around the DRM_IOCTL_CONTROL ioctl, passing the 267822944501Smrg * argument in a drm_control structure. 267922944501Smrg */ 26806260e5d5Smrgdrm_public int drmCtlInstHandler(int fd, int irq) 268122944501Smrg{ 268222944501Smrg drm_control_t ctl; 268322944501Smrg 2684424e9256Smrg memclear(ctl); 268522944501Smrg ctl.func = DRM_INST_HANDLER; 268622944501Smrg ctl.irq = irq; 268722944501Smrg if (drmIoctl(fd, DRM_IOCTL_CONTROL, &ctl)) 2688fe517fc9Smrg return -errno; 268922944501Smrg return 0; 269022944501Smrg} 269122944501Smrg 269222944501Smrg 269322944501Smrg/** 269422944501Smrg * Uninstall IRQ handler. 269522944501Smrg * 269622944501Smrg * \param fd file descriptor. 2697fe517fc9Smrg * 269822944501Smrg * \return zero on success, or a negative value on failure. 2699fe517fc9Smrg * 270022944501Smrg * \internal 270122944501Smrg * This function is a wrapper around the DRM_IOCTL_CONTROL ioctl, passing the 270222944501Smrg * argument in a drm_control structure. 270322944501Smrg */ 27046260e5d5Smrgdrm_public int drmCtlUninstHandler(int fd) 270522944501Smrg{ 270622944501Smrg drm_control_t ctl; 270722944501Smrg 2708424e9256Smrg memclear(ctl); 270922944501Smrg ctl.func = DRM_UNINST_HANDLER; 271022944501Smrg ctl.irq = 0; 271122944501Smrg if (drmIoctl(fd, DRM_IOCTL_CONTROL, &ctl)) 2712fe517fc9Smrg return -errno; 271322944501Smrg return 0; 271422944501Smrg} 271522944501Smrg 27166260e5d5Smrgdrm_public int drmFinish(int fd, int context, drmLockFlags flags) 271722944501Smrg{ 271822944501Smrg drm_lock_t lock; 271922944501Smrg 2720424e9256Smrg memclear(lock); 272122944501Smrg lock.context = context; 272222944501Smrg if (flags & DRM_LOCK_READY) lock.flags |= _DRM_LOCK_READY; 272322944501Smrg if (flags & DRM_LOCK_QUIESCENT) lock.flags |= _DRM_LOCK_QUIESCENT; 272422944501Smrg if (flags & DRM_LOCK_FLUSH) lock.flags |= _DRM_LOCK_FLUSH; 272522944501Smrg if (flags & DRM_LOCK_FLUSH_ALL) lock.flags |= _DRM_LOCK_FLUSH_ALL; 272622944501Smrg if (flags & DRM_HALT_ALL_QUEUES) lock.flags |= _DRM_HALT_ALL_QUEUES; 272722944501Smrg if (flags & DRM_HALT_CUR_QUEUES) lock.flags |= _DRM_HALT_CUR_QUEUES; 272822944501Smrg if (drmIoctl(fd, DRM_IOCTL_FINISH, &lock)) 2729fe517fc9Smrg return -errno; 273022944501Smrg return 0; 273122944501Smrg} 273222944501Smrg 273322944501Smrg/** 273422944501Smrg * Get IRQ from bus ID. 273522944501Smrg * 273622944501Smrg * \param fd file descriptor. 273722944501Smrg * \param busnum bus number. 273822944501Smrg * \param devnum device number. 273922944501Smrg * \param funcnum function number. 2740fe517fc9Smrg * 274122944501Smrg * \return IRQ number on success, or a negative value on failure. 2742fe517fc9Smrg * 274322944501Smrg * \internal 274422944501Smrg * This function is a wrapper around the DRM_IOCTL_IRQ_BUSID ioctl, passing the 274522944501Smrg * arguments in a drm_irq_busid structure. 274622944501Smrg */ 27476260e5d5Smrgdrm_public int drmGetInterruptFromBusID(int fd, int busnum, int devnum, 27486260e5d5Smrg int funcnum) 274922944501Smrg{ 275022944501Smrg drm_irq_busid_t p; 275122944501Smrg 2752424e9256Smrg memclear(p); 275322944501Smrg p.busnum = busnum; 275422944501Smrg p.devnum = devnum; 275522944501Smrg p.funcnum = funcnum; 275622944501Smrg if (drmIoctl(fd, DRM_IOCTL_IRQ_BUSID, &p)) 2757fe517fc9Smrg return -errno; 275822944501Smrg return p.irq; 275922944501Smrg} 276022944501Smrg 27616260e5d5Smrgdrm_public int drmAddContextTag(int fd, drm_context_t context, void *tag) 276222944501Smrg{ 276322944501Smrg drmHashEntry *entry = drmGetEntry(fd); 276422944501Smrg 276522944501Smrg if (drmHashInsert(entry->tagTable, context, tag)) { 2766fe517fc9Smrg drmHashDelete(entry->tagTable, context); 2767fe517fc9Smrg drmHashInsert(entry->tagTable, context, tag); 276822944501Smrg } 276922944501Smrg return 0; 277022944501Smrg} 277122944501Smrg 27726260e5d5Smrgdrm_public int drmDelContextTag(int fd, drm_context_t context) 277322944501Smrg{ 277422944501Smrg drmHashEntry *entry = drmGetEntry(fd); 277522944501Smrg 277622944501Smrg return drmHashDelete(entry->tagTable, context); 277722944501Smrg} 277822944501Smrg 27796260e5d5Smrgdrm_public void *drmGetContextTag(int fd, drm_context_t context) 278022944501Smrg{ 278122944501Smrg drmHashEntry *entry = drmGetEntry(fd); 278222944501Smrg void *value; 278322944501Smrg 278422944501Smrg if (drmHashLookup(entry->tagTable, context, &value)) 2785fe517fc9Smrg return NULL; 278622944501Smrg 278722944501Smrg return value; 278822944501Smrg} 278922944501Smrg 27906260e5d5Smrgdrm_public int drmAddContextPrivateMapping(int fd, drm_context_t ctx_id, 27916260e5d5Smrg drm_handle_t handle) 279222944501Smrg{ 279322944501Smrg drm_ctx_priv_map_t map; 279422944501Smrg 2795424e9256Smrg memclear(map); 279622944501Smrg map.ctx_id = ctx_id; 279720131375Smrg map.handle = (void *)(uintptr_t)handle; 279822944501Smrg 279922944501Smrg if (drmIoctl(fd, DRM_IOCTL_SET_SAREA_CTX, &map)) 2800fe517fc9Smrg return -errno; 280122944501Smrg return 0; 280222944501Smrg} 280322944501Smrg 28046260e5d5Smrgdrm_public int drmGetContextPrivateMapping(int fd, drm_context_t ctx_id, 28056260e5d5Smrg drm_handle_t *handle) 280622944501Smrg{ 280722944501Smrg drm_ctx_priv_map_t map; 280822944501Smrg 2809424e9256Smrg memclear(map); 281022944501Smrg map.ctx_id = ctx_id; 281122944501Smrg 281222944501Smrg if (drmIoctl(fd, DRM_IOCTL_GET_SAREA_CTX, &map)) 2813fe517fc9Smrg return -errno; 281422944501Smrg if (handle) 2815fe517fc9Smrg *handle = (drm_handle_t)(uintptr_t)map.handle; 281622944501Smrg 281722944501Smrg return 0; 281822944501Smrg} 281922944501Smrg 28206260e5d5Smrgdrm_public int drmGetMap(int fd, int idx, drm_handle_t *offset, drmSize *size, 28216260e5d5Smrg drmMapType *type, drmMapFlags *flags, 28226260e5d5Smrg drm_handle_t *handle, int *mtrr) 282322944501Smrg{ 282422944501Smrg drm_map_t map; 282522944501Smrg 2826424e9256Smrg memclear(map); 282722944501Smrg map.offset = idx; 282822944501Smrg if (drmIoctl(fd, DRM_IOCTL_GET_MAP, &map)) 2829fe517fc9Smrg return -errno; 283022944501Smrg *offset = map.offset; 283122944501Smrg *size = map.size; 2832adfa0b0cSmrg *type = (drmMapType)map.type; 2833adfa0b0cSmrg *flags = (drmMapFlags)map.flags; 283422944501Smrg *handle = (unsigned long)map.handle; 283522944501Smrg *mtrr = map.mtrr; 283622944501Smrg return 0; 283722944501Smrg} 283822944501Smrg 28396260e5d5Smrgdrm_public int drmGetClient(int fd, int idx, int *auth, int *pid, int *uid, 28406260e5d5Smrg unsigned long *magic, unsigned long *iocs) 284122944501Smrg{ 284222944501Smrg drm_client_t client; 284322944501Smrg 2844424e9256Smrg memclear(client); 284522944501Smrg client.idx = idx; 284622944501Smrg if (drmIoctl(fd, DRM_IOCTL_GET_CLIENT, &client)) 2847fe517fc9Smrg return -errno; 284822944501Smrg *auth = client.auth; 284922944501Smrg *pid = client.pid; 285022944501Smrg *uid = client.uid; 285122944501Smrg *magic = client.magic; 285222944501Smrg *iocs = client.iocs; 285322944501Smrg return 0; 285422944501Smrg} 285522944501Smrg 28566260e5d5Smrgdrm_public int drmGetStats(int fd, drmStatsT *stats) 285722944501Smrg{ 285822944501Smrg drm_stats_t s; 2859424e9256Smrg unsigned i; 286022944501Smrg 2861424e9256Smrg memclear(s); 286222944501Smrg if (drmIoctl(fd, DRM_IOCTL_GET_STATS, &s)) 2863fe517fc9Smrg return -errno; 286422944501Smrg 286522944501Smrg stats->count = 0; 286622944501Smrg memset(stats, 0, sizeof(*stats)); 286722944501Smrg if (s.count > sizeof(stats->data)/sizeof(stats->data[0])) 2868fe517fc9Smrg return -1; 286922944501Smrg 287022944501Smrg#define SET_VALUE \ 287122944501Smrg stats->data[i].long_format = "%-20.20s"; \ 287222944501Smrg stats->data[i].rate_format = "%8.8s"; \ 287322944501Smrg stats->data[i].isvalue = 1; \ 287422944501Smrg stats->data[i].verbose = 0 287522944501Smrg 287622944501Smrg#define SET_COUNT \ 287722944501Smrg stats->data[i].long_format = "%-20.20s"; \ 287822944501Smrg stats->data[i].rate_format = "%5.5s"; \ 287922944501Smrg stats->data[i].isvalue = 0; \ 288022944501Smrg stats->data[i].mult_names = "kgm"; \ 288122944501Smrg stats->data[i].mult = 1000; \ 288222944501Smrg stats->data[i].verbose = 0 288322944501Smrg 288422944501Smrg#define SET_BYTE \ 288522944501Smrg stats->data[i].long_format = "%-20.20s"; \ 288622944501Smrg stats->data[i].rate_format = "%5.5s"; \ 288722944501Smrg stats->data[i].isvalue = 0; \ 288822944501Smrg stats->data[i].mult_names = "KGM"; \ 288922944501Smrg stats->data[i].mult = 1024; \ 289022944501Smrg stats->data[i].verbose = 0 289122944501Smrg 289222944501Smrg 289322944501Smrg stats->count = s.count; 289422944501Smrg for (i = 0; i < s.count; i++) { 2895fe517fc9Smrg stats->data[i].value = s.data[i].value; 2896fe517fc9Smrg switch (s.data[i].type) { 2897fe517fc9Smrg case _DRM_STAT_LOCK: 2898fe517fc9Smrg stats->data[i].long_name = "Lock"; 2899fe517fc9Smrg stats->data[i].rate_name = "Lock"; 2900fe517fc9Smrg SET_VALUE; 2901fe517fc9Smrg break; 2902fe517fc9Smrg case _DRM_STAT_OPENS: 2903fe517fc9Smrg stats->data[i].long_name = "Opens"; 2904fe517fc9Smrg stats->data[i].rate_name = "O"; 2905fe517fc9Smrg SET_COUNT; 2906fe517fc9Smrg stats->data[i].verbose = 1; 2907fe517fc9Smrg break; 2908fe517fc9Smrg case _DRM_STAT_CLOSES: 2909fe517fc9Smrg stats->data[i].long_name = "Closes"; 2910fe517fc9Smrg stats->data[i].rate_name = "Lock"; 2911fe517fc9Smrg SET_COUNT; 2912fe517fc9Smrg stats->data[i].verbose = 1; 2913fe517fc9Smrg break; 2914fe517fc9Smrg case _DRM_STAT_IOCTLS: 2915fe517fc9Smrg stats->data[i].long_name = "Ioctls"; 2916fe517fc9Smrg stats->data[i].rate_name = "Ioc/s"; 2917fe517fc9Smrg SET_COUNT; 2918fe517fc9Smrg break; 2919fe517fc9Smrg case _DRM_STAT_LOCKS: 2920fe517fc9Smrg stats->data[i].long_name = "Locks"; 2921fe517fc9Smrg stats->data[i].rate_name = "Lck/s"; 2922fe517fc9Smrg SET_COUNT; 2923fe517fc9Smrg break; 2924fe517fc9Smrg case _DRM_STAT_UNLOCKS: 2925fe517fc9Smrg stats->data[i].long_name = "Unlocks"; 2926fe517fc9Smrg stats->data[i].rate_name = "Unl/s"; 2927fe517fc9Smrg SET_COUNT; 2928fe517fc9Smrg break; 2929fe517fc9Smrg case _DRM_STAT_IRQ: 2930fe517fc9Smrg stats->data[i].long_name = "IRQs"; 2931fe517fc9Smrg stats->data[i].rate_name = "IRQ/s"; 2932fe517fc9Smrg SET_COUNT; 2933fe517fc9Smrg break; 2934fe517fc9Smrg case _DRM_STAT_PRIMARY: 2935fe517fc9Smrg stats->data[i].long_name = "Primary Bytes"; 2936fe517fc9Smrg stats->data[i].rate_name = "PB/s"; 2937fe517fc9Smrg SET_BYTE; 2938fe517fc9Smrg break; 2939fe517fc9Smrg case _DRM_STAT_SECONDARY: 2940fe517fc9Smrg stats->data[i].long_name = "Secondary Bytes"; 2941fe517fc9Smrg stats->data[i].rate_name = "SB/s"; 2942fe517fc9Smrg SET_BYTE; 2943fe517fc9Smrg break; 2944fe517fc9Smrg case _DRM_STAT_DMA: 2945fe517fc9Smrg stats->data[i].long_name = "DMA"; 2946fe517fc9Smrg stats->data[i].rate_name = "DMA/s"; 2947fe517fc9Smrg SET_COUNT; 2948fe517fc9Smrg break; 2949fe517fc9Smrg case _DRM_STAT_SPECIAL: 2950fe517fc9Smrg stats->data[i].long_name = "Special DMA"; 2951fe517fc9Smrg stats->data[i].rate_name = "dma/s"; 2952fe517fc9Smrg SET_COUNT; 2953fe517fc9Smrg break; 2954fe517fc9Smrg case _DRM_STAT_MISSED: 2955fe517fc9Smrg stats->data[i].long_name = "Miss"; 2956fe517fc9Smrg stats->data[i].rate_name = "Ms/s"; 2957fe517fc9Smrg SET_COUNT; 2958fe517fc9Smrg break; 2959fe517fc9Smrg case _DRM_STAT_VALUE: 2960fe517fc9Smrg stats->data[i].long_name = "Value"; 2961fe517fc9Smrg stats->data[i].rate_name = "Value"; 2962fe517fc9Smrg SET_VALUE; 2963fe517fc9Smrg break; 2964fe517fc9Smrg case _DRM_STAT_BYTE: 2965fe517fc9Smrg stats->data[i].long_name = "Bytes"; 2966fe517fc9Smrg stats->data[i].rate_name = "B/s"; 2967fe517fc9Smrg SET_BYTE; 2968fe517fc9Smrg break; 2969fe517fc9Smrg case _DRM_STAT_COUNT: 2970fe517fc9Smrg default: 2971fe517fc9Smrg stats->data[i].long_name = "Count"; 2972fe517fc9Smrg stats->data[i].rate_name = "Cnt/s"; 2973fe517fc9Smrg SET_COUNT; 2974fe517fc9Smrg break; 2975fe517fc9Smrg } 297622944501Smrg } 297722944501Smrg return 0; 297822944501Smrg} 297922944501Smrg 298022944501Smrg/** 298122944501Smrg * Issue a set-version ioctl. 298222944501Smrg * 298322944501Smrg * \param fd file descriptor. 2984fe517fc9Smrg * \param drmCommandIndex command index 298522944501Smrg * \param data source pointer of the data to be read and written. 298622944501Smrg * \param size size of the data to be read and written. 2987fe517fc9Smrg * 298822944501Smrg * \return zero on success, or a negative value on failure. 2989fe517fc9Smrg * 299022944501Smrg * \internal 2991fe517fc9Smrg * It issues a read-write ioctl given by 299222944501Smrg * \code DRM_COMMAND_BASE + drmCommandIndex \endcode. 299322944501Smrg */ 29946260e5d5Smrgdrm_public int drmSetInterfaceVersion(int fd, drmSetVersion *version) 299522944501Smrg{ 299622944501Smrg int retcode = 0; 299722944501Smrg drm_set_version_t sv; 299822944501Smrg 2999424e9256Smrg memclear(sv); 300022944501Smrg sv.drm_di_major = version->drm_di_major; 300122944501Smrg sv.drm_di_minor = version->drm_di_minor; 300222944501Smrg sv.drm_dd_major = version->drm_dd_major; 300322944501Smrg sv.drm_dd_minor = version->drm_dd_minor; 300422944501Smrg 300522944501Smrg if (drmIoctl(fd, DRM_IOCTL_SET_VERSION, &sv)) { 3006fe517fc9Smrg retcode = -errno; 300722944501Smrg } 300822944501Smrg 300922944501Smrg version->drm_di_major = sv.drm_di_major; 301022944501Smrg version->drm_di_minor = sv.drm_di_minor; 301122944501Smrg version->drm_dd_major = sv.drm_dd_major; 301222944501Smrg version->drm_dd_minor = sv.drm_dd_minor; 301322944501Smrg 301422944501Smrg return retcode; 301522944501Smrg} 301622944501Smrg 301722944501Smrg/** 301822944501Smrg * Send a device-specific command. 301922944501Smrg * 302022944501Smrg * \param fd file descriptor. 3021fe517fc9Smrg * \param drmCommandIndex command index 3022fe517fc9Smrg * 302322944501Smrg * \return zero on success, or a negative value on failure. 3024fe517fc9Smrg * 302522944501Smrg * \internal 3026fe517fc9Smrg * It issues a ioctl given by 302722944501Smrg * \code DRM_COMMAND_BASE + drmCommandIndex \endcode. 302822944501Smrg */ 30296260e5d5Smrgdrm_public int drmCommandNone(int fd, unsigned long drmCommandIndex) 303022944501Smrg{ 303122944501Smrg unsigned long request; 303222944501Smrg 303322944501Smrg request = DRM_IO( DRM_COMMAND_BASE + drmCommandIndex); 303422944501Smrg 3035424e9256Smrg if (drmIoctl(fd, request, NULL)) { 3036fe517fc9Smrg return -errno; 303722944501Smrg } 303822944501Smrg return 0; 303922944501Smrg} 304022944501Smrg 304122944501Smrg 304222944501Smrg/** 304322944501Smrg * Send a device-specific read command. 304422944501Smrg * 304522944501Smrg * \param fd file descriptor. 3046fe517fc9Smrg * \param drmCommandIndex command index 304722944501Smrg * \param data destination pointer of the data to be read. 304822944501Smrg * \param size size of the data to be read. 3049fe517fc9Smrg * 305022944501Smrg * \return zero on success, or a negative value on failure. 305122944501Smrg * 305222944501Smrg * \internal 3053fe517fc9Smrg * It issues a read ioctl given by 305422944501Smrg * \code DRM_COMMAND_BASE + drmCommandIndex \endcode. 305522944501Smrg */ 30566260e5d5Smrgdrm_public int drmCommandRead(int fd, unsigned long drmCommandIndex, 30576260e5d5Smrg void *data, unsigned long size) 305822944501Smrg{ 305922944501Smrg unsigned long request; 306022944501Smrg 3061fe517fc9Smrg request = DRM_IOC( DRM_IOC_READ, DRM_IOCTL_BASE, 3062fe517fc9Smrg DRM_COMMAND_BASE + drmCommandIndex, size); 306322944501Smrg 306422944501Smrg if (drmIoctl(fd, request, data)) { 3065fe517fc9Smrg return -errno; 306622944501Smrg } 306722944501Smrg return 0; 306822944501Smrg} 306922944501Smrg 307022944501Smrg 307122944501Smrg/** 307222944501Smrg * Send a device-specific write command. 307322944501Smrg * 307422944501Smrg * \param fd file descriptor. 3075fe517fc9Smrg * \param drmCommandIndex command index 307622944501Smrg * \param data source pointer of the data to be written. 307722944501Smrg * \param size size of the data to be written. 3078fe517fc9Smrg * 307922944501Smrg * \return zero on success, or a negative value on failure. 3080fe517fc9Smrg * 308122944501Smrg * \internal 3082fe517fc9Smrg * It issues a write ioctl given by 308322944501Smrg * \code DRM_COMMAND_BASE + drmCommandIndex \endcode. 308422944501Smrg */ 30856260e5d5Smrgdrm_public int drmCommandWrite(int fd, unsigned long drmCommandIndex, 30866260e5d5Smrg void *data, unsigned long size) 308722944501Smrg{ 308822944501Smrg unsigned long request; 308922944501Smrg 3090fe517fc9Smrg request = DRM_IOC( DRM_IOC_WRITE, DRM_IOCTL_BASE, 3091fe517fc9Smrg DRM_COMMAND_BASE + drmCommandIndex, size); 309222944501Smrg 309322944501Smrg if (drmIoctl(fd, request, data)) { 3094fe517fc9Smrg return -errno; 309522944501Smrg } 309622944501Smrg return 0; 309722944501Smrg} 309822944501Smrg 309922944501Smrg 310022944501Smrg/** 310122944501Smrg * Send a device-specific read-write command. 310222944501Smrg * 310322944501Smrg * \param fd file descriptor. 3104fe517fc9Smrg * \param drmCommandIndex command index 310522944501Smrg * \param data source pointer of the data to be read and written. 310622944501Smrg * \param size size of the data to be read and written. 3107fe517fc9Smrg * 310822944501Smrg * \return zero on success, or a negative value on failure. 3109fe517fc9Smrg * 311022944501Smrg * \internal 3111fe517fc9Smrg * It issues a read-write ioctl given by 311222944501Smrg * \code DRM_COMMAND_BASE + drmCommandIndex \endcode. 311322944501Smrg */ 31146260e5d5Smrgdrm_public int drmCommandWriteRead(int fd, unsigned long drmCommandIndex, 31156260e5d5Smrg void *data, unsigned long size) 311622944501Smrg{ 311722944501Smrg unsigned long request; 311822944501Smrg 3119fe517fc9Smrg request = DRM_IOC( DRM_IOC_READ|DRM_IOC_WRITE, DRM_IOCTL_BASE, 3120fe517fc9Smrg DRM_COMMAND_BASE + drmCommandIndex, size); 312122944501Smrg 312222944501Smrg if (drmIoctl(fd, request, data)) 3123fe517fc9Smrg return -errno; 312422944501Smrg return 0; 312522944501Smrg} 312622944501Smrg 312722944501Smrg#define DRM_MAX_FDS 16 312822944501Smrgstatic struct { 312922944501Smrg char *BusID; 313022944501Smrg int fd; 313122944501Smrg int refcount; 3132424e9256Smrg int type; 313322944501Smrg} connection[DRM_MAX_FDS]; 313422944501Smrg 313522944501Smrgstatic int nr_fds = 0; 313622944501Smrg 31376260e5d5Smrgdrm_public int drmOpenOnce(void *unused, const char *BusID, int *newlyopened) 3138424e9256Smrg{ 3139424e9256Smrg return drmOpenOnceWithType(BusID, newlyopened, DRM_NODE_PRIMARY); 3140424e9256Smrg} 3141424e9256Smrg 31426260e5d5Smrgdrm_public int drmOpenOnceWithType(const char *BusID, int *newlyopened, 31436260e5d5Smrg int type) 314422944501Smrg{ 314522944501Smrg int i; 314622944501Smrg int fd; 3147fe517fc9Smrg 314822944501Smrg for (i = 0; i < nr_fds; i++) 3149fe517fc9Smrg if ((strcmp(BusID, connection[i].BusID) == 0) && 3150fe517fc9Smrg (connection[i].type == type)) { 3151fe517fc9Smrg connection[i].refcount++; 3152fe517fc9Smrg *newlyopened = 0; 3153fe517fc9Smrg return connection[i].fd; 3154fe517fc9Smrg } 315522944501Smrg 3156424e9256Smrg fd = drmOpenWithType(NULL, BusID, type); 3157fe517fc9Smrg if (fd < 0 || nr_fds == DRM_MAX_FDS) 3158fe517fc9Smrg return fd; 3159fe517fc9Smrg 316022944501Smrg connection[nr_fds].BusID = strdup(BusID); 316122944501Smrg connection[nr_fds].fd = fd; 316222944501Smrg connection[nr_fds].refcount = 1; 3163424e9256Smrg connection[nr_fds].type = type; 316422944501Smrg *newlyopened = 1; 316522944501Smrg 316622944501Smrg if (0) 3167fe517fc9Smrg fprintf(stderr, "saved connection %d for %s %d\n", 3168fe517fc9Smrg nr_fds, connection[nr_fds].BusID, 3169fe517fc9Smrg strcmp(BusID, connection[nr_fds].BusID)); 317022944501Smrg 317122944501Smrg nr_fds++; 317222944501Smrg 317322944501Smrg return fd; 317422944501Smrg} 317522944501Smrg 31766260e5d5Smrgdrm_public void drmCloseOnce(int fd) 317722944501Smrg{ 317822944501Smrg int i; 317922944501Smrg 318022944501Smrg for (i = 0; i < nr_fds; i++) { 3181fe517fc9Smrg if (fd == connection[i].fd) { 3182fe517fc9Smrg if (--connection[i].refcount == 0) { 3183fe517fc9Smrg drmClose(connection[i].fd); 3184fe517fc9Smrg free(connection[i].BusID); 3185fe517fc9Smrg 3186fe517fc9Smrg if (i < --nr_fds) 3187fe517fc9Smrg connection[i] = connection[nr_fds]; 3188fe517fc9Smrg 3189fe517fc9Smrg return; 3190fe517fc9Smrg } 3191fe517fc9Smrg } 319222944501Smrg } 319322944501Smrg} 319422944501Smrg 31956260e5d5Smrgdrm_public int drmSetMaster(int fd) 319622944501Smrg{ 3197fe517fc9Smrg return drmIoctl(fd, DRM_IOCTL_SET_MASTER, NULL); 319822944501Smrg} 319922944501Smrg 32006260e5d5Smrgdrm_public int drmDropMaster(int fd) 320122944501Smrg{ 3202fe517fc9Smrg return drmIoctl(fd, DRM_IOCTL_DROP_MASTER, NULL); 320322944501Smrg} 320422944501Smrg 3205bf6cc7dcSmrgdrm_public int drmIsMaster(int fd) 3206bf6cc7dcSmrg{ 3207bf6cc7dcSmrg /* Detect master by attempting something that requires master. 3208bf6cc7dcSmrg * 3209bf6cc7dcSmrg * Authenticating magic tokens requires master and 0 is an 3210bf6cc7dcSmrg * internal kernel detail which we could use. Attempting this on 3211bf6cc7dcSmrg * a master fd would fail therefore fail with EINVAL because 0 3212bf6cc7dcSmrg * is invalid. 3213bf6cc7dcSmrg * 3214bf6cc7dcSmrg * A non-master fd will fail with EACCES, as the kernel checks 3215bf6cc7dcSmrg * for master before attempting to do anything else. 3216bf6cc7dcSmrg * 3217bf6cc7dcSmrg * Since we don't want to leak implementation details, use 3218bf6cc7dcSmrg * EACCES. 3219bf6cc7dcSmrg */ 3220bf6cc7dcSmrg return drmAuthMagic(fd, 0) != -EACCES; 3221bf6cc7dcSmrg} 3222bf6cc7dcSmrg 32236260e5d5Smrgdrm_public char *drmGetDeviceNameFromFd(int fd) 322422944501Smrg{ 322587bf8e7cSmrg#ifdef __FreeBSD__ 322687bf8e7cSmrg struct stat sbuf; 322787bf8e7cSmrg int maj, min; 322887bf8e7cSmrg int nodetype; 322987bf8e7cSmrg 323087bf8e7cSmrg if (fstat(fd, &sbuf)) 323187bf8e7cSmrg return NULL; 323287bf8e7cSmrg 323387bf8e7cSmrg maj = major(sbuf.st_rdev); 323487bf8e7cSmrg min = minor(sbuf.st_rdev); 323587bf8e7cSmrg nodetype = drmGetMinorType(maj, min); 323687bf8e7cSmrg return drmGetMinorNameForFD(fd, nodetype); 323787bf8e7cSmrg#else 3238fe517fc9Smrg char name[128]; 3239fe517fc9Smrg struct stat sbuf; 3240fe517fc9Smrg dev_t d; 3241fe517fc9Smrg int i; 324222944501Smrg 3243fe517fc9Smrg /* The whole drmOpen thing is a fiasco and we need to find a way 3244fe517fc9Smrg * back to just using open(2). For now, however, lets just make 3245fe517fc9Smrg * things worse with even more ad hoc directory walking code to 3246fe517fc9Smrg * discover the device file name. */ 324722944501Smrg 3248fe517fc9Smrg fstat(fd, &sbuf); 3249fe517fc9Smrg d = sbuf.st_rdev; 325022944501Smrg 3251fe517fc9Smrg for (i = 0; i < DRM_MAX_MINOR; i++) { 3252fe517fc9Smrg snprintf(name, sizeof name, DRM_DEV_NAME, DRM_DIR_NAME, i); 3253fe517fc9Smrg if (stat(name, &sbuf) == 0 && sbuf.st_rdev == d) 3254fe517fc9Smrg break; 3255fe517fc9Smrg } 3256fe517fc9Smrg if (i == DRM_MAX_MINOR) 3257fe517fc9Smrg return NULL; 325822944501Smrg 3259fe517fc9Smrg return strdup(name); 326087bf8e7cSmrg#endif 326122944501Smrg} 326220131375Smrg 32636260e5d5Smrgstatic bool drmNodeIsDRM(int maj, int min) 32646260e5d5Smrg{ 32656260e5d5Smrg#ifdef __linux__ 32666260e5d5Smrg char path[64]; 32676260e5d5Smrg struct stat sbuf; 32686260e5d5Smrg 32696260e5d5Smrg snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device/drm", 32706260e5d5Smrg maj, min); 32716260e5d5Smrg return stat(path, &sbuf) == 0; 32724b3d3f37Smrg#elif defined(__FreeBSD__) 327387bf8e7cSmrg char name[SPECNAMELEN]; 327487bf8e7cSmrg 327587bf8e7cSmrg if (!devname_r(makedev(maj, min), S_IFCHR, name, sizeof(name))) 327687bf8e7cSmrg return 0; 327787bf8e7cSmrg /* Handle drm/ and dri/ as both are present in different FreeBSD version 327887bf8e7cSmrg * FreeBSD on amd64/i386/powerpc external kernel modules create node in 327987bf8e7cSmrg * in /dev/drm/ and links in /dev/dri while a WIP in kernel driver creates 328087bf8e7cSmrg * only device nodes in /dev/dri/ */ 328187bf8e7cSmrg return (!strncmp(name, "drm/", 4) || !strncmp(name, "dri/", 4)); 32826260e5d5Smrg#else 32836260e5d5Smrg return maj == DRM_MAJOR; 32846260e5d5Smrg#endif 32856260e5d5Smrg} 32866260e5d5Smrg 32876260e5d5Smrgdrm_public int drmGetNodeTypeFromFd(int fd) 3288424e9256Smrg{ 3289fe517fc9Smrg struct stat sbuf; 3290fe517fc9Smrg int maj, min, type; 3291424e9256Smrg 3292fe517fc9Smrg if (fstat(fd, &sbuf)) 3293fe517fc9Smrg return -1; 3294424e9256Smrg 3295fe517fc9Smrg maj = major(sbuf.st_rdev); 3296fe517fc9Smrg min = minor(sbuf.st_rdev); 3297424e9256Smrg 32986260e5d5Smrg if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode)) { 3299fe517fc9Smrg errno = EINVAL; 3300fe517fc9Smrg return -1; 3301fe517fc9Smrg } 3302424e9256Smrg 330387bf8e7cSmrg type = drmGetMinorType(maj, min); 3304fe517fc9Smrg if (type == -1) 3305fe517fc9Smrg errno = ENODEV; 3306fe517fc9Smrg return type; 3307424e9256Smrg} 3308424e9256Smrg 33096260e5d5Smrgdrm_public int drmPrimeHandleToFD(int fd, uint32_t handle, uint32_t flags, 33106260e5d5Smrg int *prime_fd) 331120131375Smrg{ 3312fe517fc9Smrg struct drm_prime_handle args; 3313fe517fc9Smrg int ret; 331420131375Smrg 3315fe517fc9Smrg memclear(args); 3316fe517fc9Smrg args.fd = -1; 3317fe517fc9Smrg args.handle = handle; 3318fe517fc9Smrg args.flags = flags; 3319fe517fc9Smrg ret = drmIoctl(fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &args); 3320fe517fc9Smrg if (ret) 3321fe517fc9Smrg return ret; 332220131375Smrg 3323fe517fc9Smrg *prime_fd = args.fd; 3324fe517fc9Smrg return 0; 332520131375Smrg} 332620131375Smrg 33276260e5d5Smrgdrm_public int drmPrimeFDToHandle(int fd, int prime_fd, uint32_t *handle) 332820131375Smrg{ 3329fe517fc9Smrg struct drm_prime_handle args; 3330fe517fc9Smrg int ret; 333120131375Smrg 3332fe517fc9Smrg memclear(args); 3333fe517fc9Smrg args.fd = prime_fd; 3334fe517fc9Smrg ret = drmIoctl(fd, DRM_IOCTL_PRIME_FD_TO_HANDLE, &args); 3335fe517fc9Smrg if (ret) 3336fe517fc9Smrg return ret; 333720131375Smrg 3338fe517fc9Smrg *handle = args.handle; 3339fe517fc9Smrg return 0; 334020131375Smrg} 3341424e9256Smrg 3342adfa0b0cSmrgdrm_public int drmCloseBufferHandle(int fd, uint32_t handle) 3343adfa0b0cSmrg{ 3344adfa0b0cSmrg struct drm_gem_close args; 3345adfa0b0cSmrg 3346adfa0b0cSmrg memclear(args); 3347adfa0b0cSmrg args.handle = handle; 3348adfa0b0cSmrg return drmIoctl(fd, DRM_IOCTL_GEM_CLOSE, &args); 3349adfa0b0cSmrg} 3350adfa0b0cSmrg 3351424e9256Smrgstatic char *drmGetMinorNameForFD(int fd, int type) 3352424e9256Smrg{ 3353424e9256Smrg#ifdef __linux__ 3354fe517fc9Smrg DIR *sysdir; 33556260e5d5Smrg struct dirent *ent; 3356fe517fc9Smrg struct stat sbuf; 3357fe517fc9Smrg const char *name = drmGetMinorName(type); 3358fe517fc9Smrg int len; 3359fe517fc9Smrg char dev_name[64], buf[64]; 3360fe517fc9Smrg int maj, min; 3361fe517fc9Smrg 3362fe517fc9Smrg if (!name) 3363fe517fc9Smrg return NULL; 3364424e9256Smrg 3365fe517fc9Smrg len = strlen(name); 3366424e9256Smrg 3367fe517fc9Smrg if (fstat(fd, &sbuf)) 3368fe517fc9Smrg return NULL; 3369424e9256Smrg 3370fe517fc9Smrg maj = major(sbuf.st_rdev); 3371fe517fc9Smrg min = minor(sbuf.st_rdev); 3372424e9256Smrg 33736260e5d5Smrg if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode)) 3374fe517fc9Smrg return NULL; 3375424e9256Smrg 3376fe517fc9Smrg snprintf(buf, sizeof(buf), "/sys/dev/char/%d:%d/device/drm", maj, min); 3377424e9256Smrg 3378fe517fc9Smrg sysdir = opendir(buf); 3379fe517fc9Smrg if (!sysdir) 3380fe517fc9Smrg return NULL; 3381424e9256Smrg 33826260e5d5Smrg while ((ent = readdir(sysdir))) { 3383fe517fc9Smrg if (strncmp(ent->d_name, name, len) == 0) { 3384adfa0b0cSmrg if (snprintf(dev_name, sizeof(dev_name), DRM_DIR_NAME "/%s", 3385adfa0b0cSmrg ent->d_name) < 0) 3386adfa0b0cSmrg return NULL; 3387424e9256Smrg 3388fe517fc9Smrg closedir(sysdir); 3389fe517fc9Smrg return strdup(dev_name); 3390fe517fc9Smrg } 3391fe517fc9Smrg } 3392424e9256Smrg 3393fe517fc9Smrg closedir(sysdir); 33946260e5d5Smrg return NULL; 33954b3d3f37Smrg#elif defined(__FreeBSD__) 339687bf8e7cSmrg struct stat sbuf; 339787bf8e7cSmrg char dname[SPECNAMELEN]; 339887bf8e7cSmrg const char *mname; 339987bf8e7cSmrg char name[SPECNAMELEN]; 340087bf8e7cSmrg int id, maj, min, nodetype, i; 340187bf8e7cSmrg 340287bf8e7cSmrg if (fstat(fd, &sbuf)) 340387bf8e7cSmrg return NULL; 340487bf8e7cSmrg 340587bf8e7cSmrg maj = major(sbuf.st_rdev); 340687bf8e7cSmrg min = minor(sbuf.st_rdev); 340787bf8e7cSmrg 340887bf8e7cSmrg if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode)) 340987bf8e7cSmrg return NULL; 341087bf8e7cSmrg 341187bf8e7cSmrg if (!devname_r(sbuf.st_rdev, S_IFCHR, dname, sizeof(dname))) 341287bf8e7cSmrg return NULL; 341387bf8e7cSmrg 341487bf8e7cSmrg /* Handle both /dev/drm and /dev/dri 341587bf8e7cSmrg * FreeBSD on amd64/i386/powerpc external kernel modules create node in 341687bf8e7cSmrg * in /dev/drm/ and links in /dev/dri while a WIP in kernel driver creates 341787bf8e7cSmrg * only device nodes in /dev/dri/ */ 341887bf8e7cSmrg 341987bf8e7cSmrg /* Get the node type represented by fd so we can deduce the target name */ 342087bf8e7cSmrg nodetype = drmGetMinorType(maj, min); 342187bf8e7cSmrg if (nodetype == -1) 342287bf8e7cSmrg return (NULL); 342387bf8e7cSmrg mname = drmGetMinorName(type); 342487bf8e7cSmrg 342587bf8e7cSmrg for (i = 0; i < SPECNAMELEN; i++) { 342687bf8e7cSmrg if (isalpha(dname[i]) == 0 && dname[i] != '/') 342787bf8e7cSmrg break; 342887bf8e7cSmrg } 342987bf8e7cSmrg if (dname[i] == '\0') 343087bf8e7cSmrg return (NULL); 343187bf8e7cSmrg 343287bf8e7cSmrg id = (int)strtol(&dname[i], NULL, 10); 343387bf8e7cSmrg id -= drmGetMinorBase(nodetype); 343487bf8e7cSmrg snprintf(name, sizeof(name), DRM_DIR_NAME "/%s%d", mname, 343587bf8e7cSmrg id + drmGetMinorBase(type)); 343687bf8e7cSmrg 343787bf8e7cSmrg return strdup(name); 3438fe517fc9Smrg#else 34392ee35494Smrg struct stat sbuf; 34402ee35494Smrg char buf[PATH_MAX + 1]; 344182025ec7Smrg const char *dev_name = drmGetDeviceName(type); 34422ee35494Smrg unsigned int maj, min; 344382025ec7Smrg int n; 34442ee35494Smrg 34452ee35494Smrg if (fstat(fd, &sbuf)) 34462ee35494Smrg return NULL; 34472ee35494Smrg 34482ee35494Smrg maj = major(sbuf.st_rdev); 34492ee35494Smrg min = minor(sbuf.st_rdev); 34502ee35494Smrg 34516260e5d5Smrg if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode)) 34522ee35494Smrg return NULL; 34532ee35494Smrg 345482025ec7Smrg if (!dev_name) 34552ee35494Smrg return NULL; 34562ee35494Smrg 345782025ec7Smrg n = snprintf(buf, sizeof(buf), dev_name, DRM_DIR_NAME, min); 34582ee35494Smrg if (n == -1 || n >= sizeof(buf)) 34592ee35494Smrg return NULL; 34602ee35494Smrg 34612ee35494Smrg return strdup(buf); 3462424e9256Smrg#endif 3463424e9256Smrg} 3464424e9256Smrg 34656260e5d5Smrgdrm_public char *drmGetPrimaryDeviceNameFromFd(int fd) 3466424e9256Smrg{ 3467fe517fc9Smrg return drmGetMinorNameForFD(fd, DRM_NODE_PRIMARY); 3468424e9256Smrg} 3469424e9256Smrg 34706260e5d5Smrgdrm_public char *drmGetRenderDeviceNameFromFd(int fd) 3471424e9256Smrg{ 3472fe517fc9Smrg return drmGetMinorNameForFD(fd, DRM_NODE_RENDER); 3473fe517fc9Smrg} 3474fe517fc9Smrg 34752ee35494Smrg#ifdef __linux__ 34762ee35494Smrgstatic char * DRM_PRINTFLIKE(2, 3) 34772ee35494Smrgsysfs_uevent_get(const char *path, const char *fmt, ...) 34782ee35494Smrg{ 34792ee35494Smrg char filename[PATH_MAX + 1], *key, *line = NULL, *value = NULL; 34802ee35494Smrg size_t size = 0, len; 34812ee35494Smrg ssize_t num; 34822ee35494Smrg va_list ap; 34832ee35494Smrg FILE *fp; 34842ee35494Smrg 34852ee35494Smrg va_start(ap, fmt); 34862ee35494Smrg num = vasprintf(&key, fmt, ap); 34872ee35494Smrg va_end(ap); 34882ee35494Smrg len = num; 34892ee35494Smrg 34902ee35494Smrg snprintf(filename, sizeof(filename), "%s/uevent", path); 34912ee35494Smrg 34922ee35494Smrg fp = fopen(filename, "r"); 34932ee35494Smrg if (!fp) { 34942ee35494Smrg free(key); 34952ee35494Smrg return NULL; 34962ee35494Smrg } 34972ee35494Smrg 34982ee35494Smrg while ((num = getline(&line, &size, fp)) >= 0) { 34992ee35494Smrg if ((strncmp(line, key, len) == 0) && (line[len] == '=')) { 35002ee35494Smrg char *start = line + len + 1, *end = line + num - 1; 35012ee35494Smrg 35022ee35494Smrg if (*end != '\n') 35032ee35494Smrg end++; 35042ee35494Smrg 35052ee35494Smrg value = strndup(start, end - start); 35062ee35494Smrg break; 35072ee35494Smrg } 35082ee35494Smrg } 35092ee35494Smrg 35102ee35494Smrg free(line); 35112ee35494Smrg fclose(fp); 35122ee35494Smrg 35132ee35494Smrg free(key); 35142ee35494Smrg 35152ee35494Smrg return value; 35162ee35494Smrg} 35172ee35494Smrg#endif 35182ee35494Smrg 35196260e5d5Smrg/* Little white lie to avoid major rework of the existing code */ 35206260e5d5Smrg#define DRM_BUS_VIRTIO 0x10 35216260e5d5Smrg 3522fe517fc9Smrg#ifdef __linux__ 352387bf8e7cSmrgstatic int get_subsystem_type(const char *device_path) 352487bf8e7cSmrg{ 352587bf8e7cSmrg char path[PATH_MAX + 1] = ""; 3526fe517fc9Smrg char link[PATH_MAX + 1] = ""; 3527fe517fc9Smrg char *name; 35284545e80cSmrg struct { 35294545e80cSmrg const char *name; 35304545e80cSmrg int bus_type; 35314545e80cSmrg } bus_types[] = { 35324545e80cSmrg { "/pci", DRM_BUS_PCI }, 35334545e80cSmrg { "/usb", DRM_BUS_USB }, 35344545e80cSmrg { "/platform", DRM_BUS_PLATFORM }, 35354545e80cSmrg { "/spi", DRM_BUS_PLATFORM }, 35364545e80cSmrg { "/host1x", DRM_BUS_HOST1X }, 35374545e80cSmrg { "/virtio", DRM_BUS_VIRTIO }, 35384545e80cSmrg }; 3539fe517fc9Smrg 354087bf8e7cSmrg strncpy(path, device_path, PATH_MAX); 354187bf8e7cSmrg strncat(path, "/subsystem", PATH_MAX); 3542fe517fc9Smrg 3543fe517fc9Smrg if (readlink(path, link, PATH_MAX) < 0) 3544fe517fc9Smrg return -errno; 3545fe517fc9Smrg 3546fe517fc9Smrg name = strrchr(link, '/'); 3547fe517fc9Smrg if (!name) 3548fe517fc9Smrg return -EINVAL; 3549fe517fc9Smrg 35504545e80cSmrg for (unsigned i = 0; i < ARRAY_SIZE(bus_types); i++) { 35514545e80cSmrg if (strncmp(name, bus_types[i].name, strlen(bus_types[i].name)) == 0) 35524545e80cSmrg return bus_types[i].bus_type; 35534545e80cSmrg } 35546260e5d5Smrg 3555fe517fc9Smrg return -EINVAL; 355687bf8e7cSmrg} 355787bf8e7cSmrg#endif 355887bf8e7cSmrg 355987bf8e7cSmrgstatic int drmParseSubsystemType(int maj, int min) 356087bf8e7cSmrg{ 356187bf8e7cSmrg#ifdef __linux__ 356287bf8e7cSmrg char path[PATH_MAX + 1] = ""; 356387bf8e7cSmrg char real_path[PATH_MAX + 1] = ""; 356487bf8e7cSmrg int subsystem_type; 356587bf8e7cSmrg 356687bf8e7cSmrg snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min); 356787bf8e7cSmrg 356887bf8e7cSmrg subsystem_type = get_subsystem_type(path); 356987bf8e7cSmrg /* Try to get the parent (underlying) device type */ 357087bf8e7cSmrg if (subsystem_type == DRM_BUS_VIRTIO) { 357187bf8e7cSmrg /* Assume virtio-pci on error */ 357287bf8e7cSmrg if (!realpath(path, real_path)) 357387bf8e7cSmrg return DRM_BUS_VIRTIO; 357487bf8e7cSmrg strncat(path, "/..", PATH_MAX); 357587bf8e7cSmrg subsystem_type = get_subsystem_type(path); 357687bf8e7cSmrg if (subsystem_type < 0) 357787bf8e7cSmrg return DRM_BUS_VIRTIO; 357887bf8e7cSmrg } 3579a970b457Sriastradh#elif defined(__NetBSD__) 3580a970b457Sriastradh int type, fd; 3581a970b457Sriastradh drmSetVersion sv; 3582a970b457Sriastradh char *buf; 3583a970b457Sriastradh unsigned domain, bus, dev; 3584a970b457Sriastradh int func; 3585a970b457Sriastradh int ret; 3586a970b457Sriastradh 3587a970b457Sriastradh /* Get the type of device we're looking for to pick the right pathname. */ 358877e87e13Smrg type = drmGetMinorType(maj, min); 3589a970b457Sriastradh if (type == -1) 3590a970b457Sriastradh return -ENODEV; 3591a970b457Sriastradh 3592a970b457Sriastradh /* Open the device. Don't try to create it if it's not there. */ 3593a970b457Sriastradh fd = drmOpenMinor(min, 0, type); 3594a970b457Sriastradh if (fd < 0) 3595a970b457Sriastradh return -errno; 3596a970b457Sriastradh 3597a970b457Sriastradh /* 3598a970b457Sriastradh * Set the interface version to 1.4 or 1.1, which has the effect of 3599a970b457Sriastradh * populating the bus id for us. 3600a970b457Sriastradh */ 3601a970b457Sriastradh sv.drm_di_major = 1; 3602a970b457Sriastradh sv.drm_di_minor = 4; 3603a970b457Sriastradh sv.drm_dd_major = -1; 3604a970b457Sriastradh sv.drm_dd_minor = -1; 3605a970b457Sriastradh if (drmSetInterfaceVersion(fd, &sv)) { 3606a970b457Sriastradh sv.drm_di_major = 1; 3607a970b457Sriastradh sv.drm_di_minor = 1; 3608a970b457Sriastradh sv.drm_dd_major = -1; 3609a970b457Sriastradh sv.drm_dd_minor = -1; 3610a970b457Sriastradh if (drmSetInterfaceVersion(fd, &sv)) { 36115046d36bSriastradh /* 36125046d36bSriastradh * We're probably not the master. Hope the master already 36135046d36bSriastradh * set the version to >=1.1 so that we can get the busid. 36145046d36bSriastradh */ 3615a970b457Sriastradh } 3616a970b457Sriastradh } 3617a970b457Sriastradh 3618a970b457Sriastradh /* Get the bus id. */ 3619a970b457Sriastradh buf = drmGetBusid(fd); 3620a970b457Sriastradh 3621a970b457Sriastradh /* We're done with the device now. */ 3622a970b457Sriastradh (void)close(fd); 3623a970b457Sriastradh 3624a970b457Sriastradh /* If there is no bus id, fail. */ 3625a970b457Sriastradh if (buf == NULL) 3626a970b457Sriastradh return -ENODEV; 3627a970b457Sriastradh 3628a970b457Sriastradh /* Find a string we know about; otherwise -EINVAL. */ 3629a970b457Sriastradh ret = -EINVAL; 363048994cb0Sriastradh if (strncmp(buf, "pci:", 4) == 0) 3631a970b457Sriastradh ret = DRM_BUS_PCI; 3632a970b457Sriastradh 3633a970b457Sriastradh /* We're done with the bus id. */ 3634a970b457Sriastradh free(buf); 3635a970b457Sriastradh 3636a970b457Sriastradh /* Success or not, we're done. */ 3637a970b457Sriastradh return ret; 36384545e80cSmrg#elif defined(__OpenBSD__) || defined(__DragonFly__) 36392ee35494Smrg return DRM_BUS_PCI; 3640fe517fc9Smrg#else 3641fe517fc9Smrg#warning "Missing implementation of drmParseSubsystemType" 3642fe517fc9Smrg return -EINVAL; 3643fe517fc9Smrg#endif 3644fe517fc9Smrg} 3645fe517fc9Smrg 364687bf8e7cSmrg#ifdef __linux__ 36476260e5d5Smrgstatic void 36486260e5d5Smrgget_pci_path(int maj, int min, char *pci_path) 36496260e5d5Smrg{ 36506260e5d5Smrg char path[PATH_MAX + 1], *term; 36516260e5d5Smrg 36526260e5d5Smrg snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min); 36536260e5d5Smrg if (!realpath(path, pci_path)) { 36546260e5d5Smrg strcpy(pci_path, path); 36556260e5d5Smrg return; 36566260e5d5Smrg } 36576260e5d5Smrg 36586260e5d5Smrg term = strrchr(pci_path, '/'); 36596260e5d5Smrg if (term && strncmp(term, "/virtio", 7) == 0) 36606260e5d5Smrg *term = 0; 36616260e5d5Smrg} 366287bf8e7cSmrg#endif 366387bf8e7cSmrg 366487bf8e7cSmrg#ifdef __FreeBSD__ 366587bf8e7cSmrgstatic int get_sysctl_pci_bus_info(int maj, int min, drmPciBusInfoPtr info) 366687bf8e7cSmrg{ 366787bf8e7cSmrg char dname[SPECNAMELEN]; 366887bf8e7cSmrg char sysctl_name[16]; 366987bf8e7cSmrg char sysctl_val[256]; 367087bf8e7cSmrg size_t sysctl_len; 367187bf8e7cSmrg int id, type, nelem; 367287bf8e7cSmrg unsigned int rdev, majmin, domain, bus, dev, func; 367387bf8e7cSmrg 367487bf8e7cSmrg rdev = makedev(maj, min); 367587bf8e7cSmrg if (!devname_r(rdev, S_IFCHR, dname, sizeof(dname))) 367687bf8e7cSmrg return -EINVAL; 367787bf8e7cSmrg 367887bf8e7cSmrg if (sscanf(dname, "drm/%d\n", &id) != 1) 367987bf8e7cSmrg return -EINVAL; 368087bf8e7cSmrg type = drmGetMinorType(maj, min); 368187bf8e7cSmrg if (type == -1) 368287bf8e7cSmrg return -EINVAL; 368387bf8e7cSmrg 368487bf8e7cSmrg /* BUG: This above section is iffy, since it mandates that a driver will 368587bf8e7cSmrg * create both card and render node. 368687bf8e7cSmrg * If it does not, the next DRM device will create card#X and 368787bf8e7cSmrg * renderD#(128+X)-1. 368887bf8e7cSmrg * This is a possibility in FreeBSD but for now there is no good way for 368987bf8e7cSmrg * obtaining the info. 369087bf8e7cSmrg */ 369187bf8e7cSmrg switch (type) { 369287bf8e7cSmrg case DRM_NODE_PRIMARY: 369387bf8e7cSmrg break; 369487bf8e7cSmrg case DRM_NODE_CONTROL: 369587bf8e7cSmrg id -= 64; 369687bf8e7cSmrg break; 369787bf8e7cSmrg case DRM_NODE_RENDER: 369887bf8e7cSmrg id -= 128; 369987bf8e7cSmrg break; 370087bf8e7cSmrg } 370187bf8e7cSmrg if (id < 0) 370287bf8e7cSmrg return -EINVAL; 370387bf8e7cSmrg 370487bf8e7cSmrg if (snprintf(sysctl_name, sizeof(sysctl_name), "hw.dri.%d.busid", id) <= 0) 370587bf8e7cSmrg return -EINVAL; 370687bf8e7cSmrg sysctl_len = sizeof(sysctl_val); 370787bf8e7cSmrg if (sysctlbyname(sysctl_name, sysctl_val, &sysctl_len, NULL, 0)) 370887bf8e7cSmrg return -EINVAL; 370987bf8e7cSmrg 371087bf8e7cSmrg #define bus_fmt "pci:%04x:%02x:%02x.%u" 371187bf8e7cSmrg 371287bf8e7cSmrg nelem = sscanf(sysctl_val, bus_fmt, &domain, &bus, &dev, &func); 371387bf8e7cSmrg if (nelem != 4) 371487bf8e7cSmrg return -EINVAL; 371587bf8e7cSmrg info->domain = domain; 371687bf8e7cSmrg info->bus = bus; 371787bf8e7cSmrg info->dev = dev; 371887bf8e7cSmrg info->func = func; 371987bf8e7cSmrg 372087bf8e7cSmrg return 0; 372187bf8e7cSmrg} 372287bf8e7cSmrg#endif 37236260e5d5Smrg 3724fe517fc9Smrgstatic int drmParsePciBusInfo(int maj, int min, drmPciBusInfoPtr info) 3725fe517fc9Smrg{ 3726fe517fc9Smrg#ifdef __linux__ 37272ee35494Smrg unsigned int domain, bus, dev, func; 37286260e5d5Smrg char pci_path[PATH_MAX + 1], *value; 37292ee35494Smrg int num; 3730fe517fc9Smrg 37316260e5d5Smrg get_pci_path(maj, min, pci_path); 3732fe517fc9Smrg 37336260e5d5Smrg value = sysfs_uevent_get(pci_path, "PCI_SLOT_NAME"); 37342ee35494Smrg if (!value) 37352ee35494Smrg return -ENOENT; 3736fe517fc9Smrg 37372ee35494Smrg num = sscanf(value, "%04x:%02x:%02x.%1u", &domain, &bus, &dev, &func); 37382ee35494Smrg free(value); 3739fe517fc9Smrg 37402ee35494Smrg if (num != 4) 3741fe517fc9Smrg return -EINVAL; 3742fe517fc9Smrg 3743fe517fc9Smrg info->domain = domain; 3744fe517fc9Smrg info->bus = bus; 3745fe517fc9Smrg info->dev = dev; 3746fe517fc9Smrg info->func = func; 3747fe517fc9Smrg 3748a970b457Sriastradh return 0; 3749a970b457Sriastradh#elif defined(__NetBSD__) 3750a970b457Sriastradh int type, fd; 3751a970b457Sriastradh drmSetVersion sv; 3752a970b457Sriastradh char *buf; 3753a970b457Sriastradh unsigned domain, bus, dev; 3754a970b457Sriastradh int func; 3755a970b457Sriastradh int ret; 3756a970b457Sriastradh 3757a970b457Sriastradh /* Get the type of device we're looking for to pick the right pathname. */ 375877e87e13Smrg type = drmGetMinorType(maj, min); 3759a970b457Sriastradh if (type == -1) 3760a970b457Sriastradh return -ENODEV; 3761a970b457Sriastradh 3762a970b457Sriastradh /* Open the device. Don't try to create it if it's not there. */ 3763a970b457Sriastradh fd = drmOpenMinor(min, 0, type); 3764a970b457Sriastradh if (fd < 0) 3765a970b457Sriastradh return -errno; 3766a970b457Sriastradh 3767a970b457Sriastradh /* 3768a970b457Sriastradh * Set the interface version to 1.4 or 1.1, which has the effect of 3769a970b457Sriastradh * populating the bus id for us. 3770a970b457Sriastradh */ 3771a970b457Sriastradh sv.drm_di_major = 1; 3772a970b457Sriastradh sv.drm_di_minor = 4; 3773a970b457Sriastradh sv.drm_dd_major = -1; 3774a970b457Sriastradh sv.drm_dd_minor = -1; 3775a970b457Sriastradh if (drmSetInterfaceVersion(fd, &sv)) { 3776a970b457Sriastradh sv.drm_di_major = 1; 3777a970b457Sriastradh sv.drm_di_minor = 1; 3778a970b457Sriastradh sv.drm_dd_major = -1; 3779a970b457Sriastradh sv.drm_dd_minor = -1; 3780a970b457Sriastradh if (drmSetInterfaceVersion(fd, &sv)) { 378106815bcbSmaya /* 378206815bcbSmaya * We're probably not the master. Hope the master already 378306815bcbSmaya * set the version to >=1.1 so that we can get the busid. 378406815bcbSmaya */ 3785a970b457Sriastradh } 3786a970b457Sriastradh } 3787a970b457Sriastradh 3788a970b457Sriastradh /* Get the bus id. */ 3789a970b457Sriastradh buf = drmGetBusid(fd); 3790a970b457Sriastradh 3791a970b457Sriastradh /* We're done with the device now. */ 3792a970b457Sriastradh (void)close(fd); 3793a970b457Sriastradh 3794a970b457Sriastradh /* If there is no bus id, fail. */ 3795a970b457Sriastradh if (buf == NULL) 3796a970b457Sriastradh return -ENODEV; 3797a970b457Sriastradh 3798a970b457Sriastradh /* Parse the bus id. */ 3799a970b457Sriastradh ret = sscanf(buf, "pci:%04x:%02x:%02x.%d", &domain, &bus, &dev, &func); 3800a970b457Sriastradh 3801a970b457Sriastradh /* We're done with the bus id. */ 3802a970b457Sriastradh free(buf); 3803a970b457Sriastradh 3804a970b457Sriastradh /* If scanf didn't return 4 -- domain, bus, dev, func -- then fail. */ 3805a970b457Sriastradh if (ret != 4) 3806a970b457Sriastradh return -ENODEV; 3807a970b457Sriastradh 3808a970b457Sriastradh /* Populate the results. */ 3809a970b457Sriastradh info->domain = domain; 3810a970b457Sriastradh info->bus = bus; 3811a970b457Sriastradh info->dev = dev; 3812a970b457Sriastradh info->func = func; 3813a970b457Sriastradh 3814a970b457Sriastradh /* Success! */ 38152ee35494Smrg return 0; 38164545e80cSmrg#elif defined(__OpenBSD__) || defined(__DragonFly__) 38172ee35494Smrg struct drm_pciinfo pinfo; 38182ee35494Smrg int fd, type; 38192ee35494Smrg 382087bf8e7cSmrg type = drmGetMinorType(maj, min); 38212ee35494Smrg if (type == -1) 38222ee35494Smrg return -ENODEV; 38232ee35494Smrg 38242ee35494Smrg fd = drmOpenMinor(min, 0, type); 38252ee35494Smrg if (fd < 0) 38262ee35494Smrg return -errno; 38272ee35494Smrg 38282ee35494Smrg if (drmIoctl(fd, DRM_IOCTL_GET_PCIINFO, &pinfo)) { 38292ee35494Smrg close(fd); 38302ee35494Smrg return -errno; 38312ee35494Smrg } 38322ee35494Smrg close(fd); 38332ee35494Smrg 38342ee35494Smrg info->domain = pinfo.domain; 38352ee35494Smrg info->bus = pinfo.bus; 38362ee35494Smrg info->dev = pinfo.dev; 38372ee35494Smrg info->func = pinfo.func; 38382ee35494Smrg 3839fe517fc9Smrg return 0; 38404b3d3f37Smrg#elif defined(__FreeBSD__) 384187bf8e7cSmrg return get_sysctl_pci_bus_info(maj, min, info); 3842fe517fc9Smrg#else 3843fe517fc9Smrg#warning "Missing implementation of drmParsePciBusInfo" 3844fe517fc9Smrg return -EINVAL; 3845fe517fc9Smrg#endif 3846fe517fc9Smrg} 3847fe517fc9Smrg 38486260e5d5Smrgdrm_public int drmDevicesEqual(drmDevicePtr a, drmDevicePtr b) 3849fe517fc9Smrg{ 3850fe517fc9Smrg if (a == NULL || b == NULL) 38510655efefSmrg return 0; 3852fe517fc9Smrg 3853fe517fc9Smrg if (a->bustype != b->bustype) 38540655efefSmrg return 0; 3855fe517fc9Smrg 3856fe517fc9Smrg switch (a->bustype) { 3857fe517fc9Smrg case DRM_BUS_PCI: 38580655efefSmrg return memcmp(a->businfo.pci, b->businfo.pci, sizeof(drmPciBusInfo)) == 0; 38592ee35494Smrg 38602ee35494Smrg case DRM_BUS_USB: 38610655efefSmrg return memcmp(a->businfo.usb, b->businfo.usb, sizeof(drmUsbBusInfo)) == 0; 38622ee35494Smrg 38632ee35494Smrg case DRM_BUS_PLATFORM: 38640655efefSmrg return memcmp(a->businfo.platform, b->businfo.platform, sizeof(drmPlatformBusInfo)) == 0; 38652ee35494Smrg 38662ee35494Smrg case DRM_BUS_HOST1X: 38670655efefSmrg return memcmp(a->businfo.host1x, b->businfo.host1x, sizeof(drmHost1xBusInfo)) == 0; 38682ee35494Smrg 3869fe517fc9Smrg default: 3870fe517fc9Smrg break; 3871fe517fc9Smrg } 3872fe517fc9Smrg 38730655efefSmrg return 0; 3874fe517fc9Smrg} 3875fe517fc9Smrg 3876fe517fc9Smrgstatic int drmGetNodeType(const char *name) 3877fe517fc9Smrg{ 3878fe517fc9Smrg if (strncmp(name, DRM_CONTROL_MINOR_NAME, 3879fe517fc9Smrg sizeof(DRM_CONTROL_MINOR_NAME ) - 1) == 0) 3880fe517fc9Smrg return DRM_NODE_CONTROL; 3881fe517fc9Smrg 3882fe517fc9Smrg if (strncmp(name, DRM_RENDER_MINOR_NAME, 3883fe517fc9Smrg sizeof(DRM_RENDER_MINOR_NAME) - 1) == 0) 3884fe517fc9Smrg return DRM_NODE_RENDER; 3885fe517fc9Smrg 388682025ec7Smrg if (strncmp(name, DRM_PRIMARY_MINOR_NAME, 388782025ec7Smrg sizeof(DRM_PRIMARY_MINOR_NAME) - 1) == 0) 388882025ec7Smrg return DRM_NODE_PRIMARY; 388982025ec7Smrg 3890fe517fc9Smrg return -EINVAL; 3891fe517fc9Smrg} 3892fe517fc9Smrg 3893fe517fc9Smrgstatic int drmGetMaxNodeName(void) 3894fe517fc9Smrg{ 3895fe517fc9Smrg return sizeof(DRM_DIR_NAME) + 3896fe517fc9Smrg MAX3(sizeof(DRM_PRIMARY_MINOR_NAME), 3897fe517fc9Smrg sizeof(DRM_CONTROL_MINOR_NAME), 3898fe517fc9Smrg sizeof(DRM_RENDER_MINOR_NAME)) + 3899fe517fc9Smrg 3 /* length of the node number */; 3900fe517fc9Smrg} 3901fe517fc9Smrg 3902fe517fc9Smrg#ifdef __linux__ 39032ee35494Smrgstatic int parse_separate_sysfs_files(int maj, int min, 39042ee35494Smrg drmPciDeviceInfoPtr device, 39052ee35494Smrg bool ignore_revision) 39062ee35494Smrg{ 39072ee35494Smrg static const char *attrs[] = { 39082ee35494Smrg "revision", /* Older kernels are missing the file, so check for it first */ 39092ee35494Smrg "vendor", 39102ee35494Smrg "device", 39112ee35494Smrg "subsystem_vendor", 39122ee35494Smrg "subsystem_device", 39132ee35494Smrg }; 39146260e5d5Smrg char path[PATH_MAX + 1], pci_path[PATH_MAX + 1]; 39152ee35494Smrg unsigned int data[ARRAY_SIZE(attrs)]; 39162ee35494Smrg FILE *fp; 39172ee35494Smrg int ret; 39182ee35494Smrg 39196260e5d5Smrg get_pci_path(maj, min, pci_path); 39206260e5d5Smrg 39212ee35494Smrg for (unsigned i = ignore_revision ? 1 : 0; i < ARRAY_SIZE(attrs); i++) { 3922adfa0b0cSmrg if (snprintf(path, PATH_MAX, "%s/%s", pci_path, attrs[i]) < 0) 3923adfa0b0cSmrg return -errno; 3924adfa0b0cSmrg 39252ee35494Smrg fp = fopen(path, "r"); 39262ee35494Smrg if (!fp) 39272ee35494Smrg return -errno; 39282ee35494Smrg 39292ee35494Smrg ret = fscanf(fp, "%x", &data[i]); 39302ee35494Smrg fclose(fp); 39312ee35494Smrg if (ret != 1) 39322ee35494Smrg return -errno; 39332ee35494Smrg 39342ee35494Smrg } 39352ee35494Smrg 39362ee35494Smrg device->revision_id = ignore_revision ? 0xff : data[0] & 0xff; 39372ee35494Smrg device->vendor_id = data[1] & 0xffff; 39382ee35494Smrg device->device_id = data[2] & 0xffff; 39392ee35494Smrg device->subvendor_id = data[3] & 0xffff; 39402ee35494Smrg device->subdevice_id = data[4] & 0xffff; 39412ee35494Smrg 39422ee35494Smrg return 0; 39432ee35494Smrg} 39442ee35494Smrg 39452ee35494Smrgstatic int parse_config_sysfs_file(int maj, int min, 39462ee35494Smrg drmPciDeviceInfoPtr device) 39472ee35494Smrg{ 39486260e5d5Smrg char path[PATH_MAX + 1], pci_path[PATH_MAX + 1]; 3949fe517fc9Smrg unsigned char config[64]; 3950fe517fc9Smrg int fd, ret; 3951fe517fc9Smrg 39526260e5d5Smrg get_pci_path(maj, min, pci_path); 39536260e5d5Smrg 3954adfa0b0cSmrg if (snprintf(path, PATH_MAX, "%s/config", pci_path) < 0) 3955adfa0b0cSmrg return -errno; 3956adfa0b0cSmrg 3957fe517fc9Smrg fd = open(path, O_RDONLY); 3958fe517fc9Smrg if (fd < 0) 3959fe517fc9Smrg return -errno; 3960fe517fc9Smrg 3961fe517fc9Smrg ret = read(fd, config, sizeof(config)); 3962fe517fc9Smrg close(fd); 3963fe517fc9Smrg if (ret < 0) 3964fe517fc9Smrg return -errno; 3965fe517fc9Smrg 3966fe517fc9Smrg device->vendor_id = config[0] | (config[1] << 8); 3967fe517fc9Smrg device->device_id = config[2] | (config[3] << 8); 3968fe517fc9Smrg device->revision_id = config[8]; 3969fe517fc9Smrg device->subvendor_id = config[44] | (config[45] << 8); 3970fe517fc9Smrg device->subdevice_id = config[46] | (config[47] << 8); 3971fe517fc9Smrg 39722ee35494Smrg return 0; 39732ee35494Smrg} 39742ee35494Smrg#endif 39752ee35494Smrg 39762ee35494Smrgstatic int drmParsePciDeviceInfo(int maj, int min, 39772ee35494Smrg drmPciDeviceInfoPtr device, 39782ee35494Smrg uint32_t flags) 39792ee35494Smrg{ 39802ee35494Smrg#ifdef __linux__ 39812ee35494Smrg if (!(flags & DRM_DEVICE_GET_PCI_REVISION)) 39822ee35494Smrg return parse_separate_sysfs_files(maj, min, device, true); 39832ee35494Smrg 39842ee35494Smrg if (parse_separate_sysfs_files(maj, min, device, false)) 39852ee35494Smrg return parse_config_sysfs_file(maj, min, device); 39862ee35494Smrg 39872ee35494Smrg return 0; 3988a970b457Sriastradh#elif defined(__NetBSD__) 3989a970b457Sriastradh drmPciBusInfo businfo; 3990a970b457Sriastradh char fname[PATH_MAX]; 3991a970b457Sriastradh int pcifd; 3992a970b457Sriastradh pcireg_t id, class, subsys; 3993a970b457Sriastradh int ret; 3994a970b457Sriastradh 3995a970b457Sriastradh /* Find where on the bus the device lives. */ 3996a970b457Sriastradh ret = drmParsePciBusInfo(maj, min, &businfo); 3997a970b457Sriastradh if (ret) 3998a970b457Sriastradh return ret; 3999a970b457Sriastradh 4000a970b457Sriastradh /* Open the pciN device node to get at its config registers. */ 4001a970b457Sriastradh if (snprintf(fname, sizeof fname, "/dev/pci%u", businfo.domain) 4002a970b457Sriastradh >= sizeof fname) 4003a970b457Sriastradh return -ENODEV; 4004a970b457Sriastradh if ((pcifd = open(fname, O_RDONLY)) == -1) 4005a970b457Sriastradh return -errno; 4006a970b457Sriastradh 4007f8b67707Schristos ret = -1; 4008a970b457Sriastradh /* Read the id and class pci config registers. */ 4009a970b457Sriastradh if (pcibus_conf_read(pcifd, businfo.bus, businfo.dev, businfo.func, 4010a970b457Sriastradh PCI_ID_REG, &id) == -1) 4011f8b67707Schristos goto out; 4012a970b457Sriastradh if (pcibus_conf_read(pcifd, businfo.bus, businfo.dev, businfo.func, 4013a970b457Sriastradh PCI_CLASS_REG, &class) == -1) 4014f8b67707Schristos goto out; 4015a970b457Sriastradh if (pcibus_conf_read(pcifd, businfo.bus, businfo.dev, businfo.func, 4016a970b457Sriastradh PCI_SUBSYS_ID_REG, &subsys) == -1) 4017f8b67707Schristos goto out; 4018a970b457Sriastradh 4019f8b67707Schristos ret = 0; 4020a970b457Sriastradh device->vendor_id = PCI_VENDOR(id); 4021a970b457Sriastradh device->device_id = PCI_PRODUCT(id); 4022a970b457Sriastradh device->subvendor_id = PCI_SUBSYS_VENDOR(subsys); 4023a970b457Sriastradh device->subdevice_id = PCI_SUBSYS_ID(subsys); 4024a970b457Sriastradh device->revision_id = PCI_REVISION(class); 4025f8b67707Schristosout: 4026f8b67707Schristos if (ret == -1) 4027f8b67707Schristos ret = -errno; 4028f8b67707Schristos close(pcifd); 4029f8b67707Schristos return ret; 40304545e80cSmrg#elif defined(__OpenBSD__) || defined(__DragonFly__) 40312ee35494Smrg struct drm_pciinfo pinfo; 40322ee35494Smrg int fd, type; 40332ee35494Smrg 403487bf8e7cSmrg type = drmGetMinorType(maj, min); 40352ee35494Smrg if (type == -1) 40362ee35494Smrg return -ENODEV; 40372ee35494Smrg 40382ee35494Smrg fd = drmOpenMinor(min, 0, type); 40392ee35494Smrg if (fd < 0) 40402ee35494Smrg return -errno; 40412ee35494Smrg 40422ee35494Smrg if (drmIoctl(fd, DRM_IOCTL_GET_PCIINFO, &pinfo)) { 40432ee35494Smrg close(fd); 40442ee35494Smrg return -errno; 40452ee35494Smrg } 40462ee35494Smrg close(fd); 40472ee35494Smrg 40482ee35494Smrg device->vendor_id = pinfo.vendor_id; 40492ee35494Smrg device->device_id = pinfo.device_id; 40502ee35494Smrg device->revision_id = pinfo.revision_id; 40512ee35494Smrg device->subvendor_id = pinfo.subvendor_id; 40522ee35494Smrg device->subdevice_id = pinfo.subdevice_id; 40532ee35494Smrg 405487bf8e7cSmrg return 0; 40554b3d3f37Smrg#elif defined(__FreeBSD__) 405687bf8e7cSmrg drmPciBusInfo info; 405787bf8e7cSmrg struct pci_conf_io pc; 405887bf8e7cSmrg struct pci_match_conf patterns[1]; 405987bf8e7cSmrg struct pci_conf results[1]; 406087bf8e7cSmrg int fd, error; 406187bf8e7cSmrg 406287bf8e7cSmrg if (get_sysctl_pci_bus_info(maj, min, &info) != 0) 406387bf8e7cSmrg return -EINVAL; 406487bf8e7cSmrg 406587bf8e7cSmrg fd = open("/dev/pci", O_RDONLY, 0); 406687bf8e7cSmrg if (fd < 0) 406787bf8e7cSmrg return -errno; 406887bf8e7cSmrg 406987bf8e7cSmrg bzero(&patterns, sizeof(patterns)); 407087bf8e7cSmrg patterns[0].pc_sel.pc_domain = info.domain; 407187bf8e7cSmrg patterns[0].pc_sel.pc_bus = info.bus; 407287bf8e7cSmrg patterns[0].pc_sel.pc_dev = info.dev; 407387bf8e7cSmrg patterns[0].pc_sel.pc_func = info.func; 407487bf8e7cSmrg patterns[0].flags = PCI_GETCONF_MATCH_DOMAIN | PCI_GETCONF_MATCH_BUS 407587bf8e7cSmrg | PCI_GETCONF_MATCH_DEV | PCI_GETCONF_MATCH_FUNC; 407687bf8e7cSmrg bzero(&pc, sizeof(struct pci_conf_io)); 407787bf8e7cSmrg pc.num_patterns = 1; 407887bf8e7cSmrg pc.pat_buf_len = sizeof(patterns); 407987bf8e7cSmrg pc.patterns = patterns; 408087bf8e7cSmrg pc.match_buf_len = sizeof(results); 408187bf8e7cSmrg pc.matches = results; 408287bf8e7cSmrg 408387bf8e7cSmrg if (ioctl(fd, PCIOCGETCONF, &pc) || pc.status == PCI_GETCONF_ERROR) { 408487bf8e7cSmrg error = errno; 408587bf8e7cSmrg close(fd); 408687bf8e7cSmrg return -error; 408787bf8e7cSmrg } 408887bf8e7cSmrg close(fd); 408987bf8e7cSmrg 409087bf8e7cSmrg device->vendor_id = results[0].pc_vendor; 409187bf8e7cSmrg device->device_id = results[0].pc_device; 409287bf8e7cSmrg device->subvendor_id = results[0].pc_subvendor; 409387bf8e7cSmrg device->subdevice_id = results[0].pc_subdevice; 409487bf8e7cSmrg device->revision_id = results[0].pc_revid; 409587bf8e7cSmrg 4096fe517fc9Smrg return 0; 4097fe517fc9Smrg#else 4098fe517fc9Smrg#warning "Missing implementation of drmParsePciDeviceInfo" 4099fe517fc9Smrg return -EINVAL; 4100fe517fc9Smrg#endif 4101fe517fc9Smrg} 4102fe517fc9Smrg 41032ee35494Smrgstatic void drmFreePlatformDevice(drmDevicePtr device) 41042ee35494Smrg{ 41052ee35494Smrg if (device->deviceinfo.platform) { 41062ee35494Smrg if (device->deviceinfo.platform->compatible) { 41072ee35494Smrg char **compatible = device->deviceinfo.platform->compatible; 41082ee35494Smrg 41092ee35494Smrg while (*compatible) { 41102ee35494Smrg free(*compatible); 41112ee35494Smrg compatible++; 41122ee35494Smrg } 41132ee35494Smrg 41142ee35494Smrg free(device->deviceinfo.platform->compatible); 41152ee35494Smrg } 41162ee35494Smrg } 41172ee35494Smrg} 41182ee35494Smrg 41192ee35494Smrgstatic void drmFreeHost1xDevice(drmDevicePtr device) 41202ee35494Smrg{ 41212ee35494Smrg if (device->deviceinfo.host1x) { 41222ee35494Smrg if (device->deviceinfo.host1x->compatible) { 41232ee35494Smrg char **compatible = device->deviceinfo.host1x->compatible; 41242ee35494Smrg 41252ee35494Smrg while (*compatible) { 41262ee35494Smrg free(*compatible); 41272ee35494Smrg compatible++; 41282ee35494Smrg } 41292ee35494Smrg 41302ee35494Smrg free(device->deviceinfo.host1x->compatible); 41312ee35494Smrg } 41322ee35494Smrg } 41332ee35494Smrg} 41342ee35494Smrg 41356260e5d5Smrgdrm_public void drmFreeDevice(drmDevicePtr *device) 4136fe517fc9Smrg{ 4137fe517fc9Smrg if (device == NULL) 4138fe517fc9Smrg return; 4139fe517fc9Smrg 41402ee35494Smrg if (*device) { 41412ee35494Smrg switch ((*device)->bustype) { 41422ee35494Smrg case DRM_BUS_PLATFORM: 41432ee35494Smrg drmFreePlatformDevice(*device); 41442ee35494Smrg break; 41452ee35494Smrg 41462ee35494Smrg case DRM_BUS_HOST1X: 41472ee35494Smrg drmFreeHost1xDevice(*device); 41482ee35494Smrg break; 41492ee35494Smrg } 41502ee35494Smrg } 41512ee35494Smrg 4152fe517fc9Smrg free(*device); 4153fe517fc9Smrg *device = NULL; 4154fe517fc9Smrg} 4155fe517fc9Smrg 41566260e5d5Smrgdrm_public void drmFreeDevices(drmDevicePtr devices[], int count) 4157fe517fc9Smrg{ 4158fe517fc9Smrg int i; 4159fe517fc9Smrg 4160fe517fc9Smrg if (devices == NULL) 4161fe517fc9Smrg return; 4162fe517fc9Smrg 4163fe517fc9Smrg for (i = 0; i < count; i++) 4164fe517fc9Smrg if (devices[i]) 4165fe517fc9Smrg drmFreeDevice(&devices[i]); 4166fe517fc9Smrg} 4167fe517fc9Smrg 41682ee35494Smrgstatic drmDevicePtr drmDeviceAlloc(unsigned int type, const char *node, 41692ee35494Smrg size_t bus_size, size_t device_size, 41702ee35494Smrg char **ptrp) 4171fe517fc9Smrg{ 41722ee35494Smrg size_t max_node_length, extra, size; 41732ee35494Smrg drmDevicePtr device; 41742ee35494Smrg unsigned int i; 41752ee35494Smrg char *ptr; 4176fe517fc9Smrg 41772ee35494Smrg max_node_length = ALIGN(drmGetMaxNodeName(), sizeof(void *)); 41782ee35494Smrg extra = DRM_NODE_MAX * (sizeof(void *) + max_node_length); 4179fe517fc9Smrg 41802ee35494Smrg size = sizeof(*device) + extra + bus_size + device_size; 4181fe517fc9Smrg 41822ee35494Smrg device = calloc(1, size); 41832ee35494Smrg if (!device) 41842ee35494Smrg return NULL; 41852ee35494Smrg 41862ee35494Smrg device->available_nodes = 1 << type; 4187fe517fc9Smrg 41882ee35494Smrg ptr = (char *)device + sizeof(*device); 41892ee35494Smrg device->nodes = (char **)ptr; 41902ee35494Smrg 41912ee35494Smrg ptr += DRM_NODE_MAX * sizeof(void *); 4192fe517fc9Smrg 4193fe517fc9Smrg for (i = 0; i < DRM_NODE_MAX; i++) { 41942ee35494Smrg device->nodes[i] = ptr; 41952ee35494Smrg ptr += max_node_length; 4196fe517fc9Smrg } 4197fe517fc9Smrg 41982ee35494Smrg memcpy(device->nodes[type], node, max_node_length); 41992ee35494Smrg 42002ee35494Smrg *ptrp = ptr; 42012ee35494Smrg 42022ee35494Smrg return device; 42032ee35494Smrg} 42042ee35494Smrg 42052ee35494Smrgstatic int drmProcessPciDevice(drmDevicePtr *device, 42062ee35494Smrg const char *node, int node_type, 42072ee35494Smrg int maj, int min, bool fetch_deviceinfo, 42082ee35494Smrg uint32_t flags) 42092ee35494Smrg{ 42102ee35494Smrg drmDevicePtr dev; 42112ee35494Smrg char *addr; 42122ee35494Smrg int ret; 42132ee35494Smrg 42142ee35494Smrg dev = drmDeviceAlloc(node_type, node, sizeof(drmPciBusInfo), 42152ee35494Smrg sizeof(drmPciDeviceInfo), &addr); 42162ee35494Smrg if (!dev) 42172ee35494Smrg return -ENOMEM; 42182ee35494Smrg 42192ee35494Smrg dev->bustype = DRM_BUS_PCI; 4220fe517fc9Smrg 42212ee35494Smrg dev->businfo.pci = (drmPciBusInfoPtr)addr; 42222ee35494Smrg 42232ee35494Smrg ret = drmParsePciBusInfo(maj, min, dev->businfo.pci); 4224fe517fc9Smrg if (ret) 4225fe517fc9Smrg goto free_device; 4226fe517fc9Smrg 4227fe517fc9Smrg // Fetch the device info if the user has requested it 4228fe517fc9Smrg if (fetch_deviceinfo) { 4229fe517fc9Smrg addr += sizeof(drmPciBusInfo); 42302ee35494Smrg dev->deviceinfo.pci = (drmPciDeviceInfoPtr)addr; 4231fe517fc9Smrg 42322ee35494Smrg ret = drmParsePciDeviceInfo(maj, min, dev->deviceinfo.pci, flags); 4233fe517fc9Smrg if (ret) 4234fe517fc9Smrg goto free_device; 4235fe517fc9Smrg } 42362ee35494Smrg 42372ee35494Smrg *device = dev; 42382ee35494Smrg 4239fe517fc9Smrg return 0; 4240fe517fc9Smrg 4241fe517fc9Smrgfree_device: 42422ee35494Smrg free(dev); 42432ee35494Smrg return ret; 42442ee35494Smrg} 42452ee35494Smrg 424687bf8e7cSmrg#ifdef __linux__ 424787bf8e7cSmrgstatic int drm_usb_dev_path(int maj, int min, char *path, size_t len) 424887bf8e7cSmrg{ 424987bf8e7cSmrg char *value, *tmp_path, *slash; 4250adfa0b0cSmrg bool usb_device, usb_interface; 425187bf8e7cSmrg 425287bf8e7cSmrg snprintf(path, len, "/sys/dev/char/%d:%d/device", maj, min); 425387bf8e7cSmrg 425487bf8e7cSmrg value = sysfs_uevent_get(path, "DEVTYPE"); 425587bf8e7cSmrg if (!value) 425687bf8e7cSmrg return -ENOENT; 425787bf8e7cSmrg 4258adfa0b0cSmrg usb_device = strcmp(value, "usb_device") == 0; 4259adfa0b0cSmrg usb_interface = strcmp(value, "usb_interface") == 0; 4260adfa0b0cSmrg free(value); 4261adfa0b0cSmrg 4262adfa0b0cSmrg if (usb_device) 426387bf8e7cSmrg return 0; 4264adfa0b0cSmrg if (!usb_interface) 426587bf8e7cSmrg return -ENOTSUP; 426687bf8e7cSmrg 426787bf8e7cSmrg /* The parent of a usb_interface is a usb_device */ 426887bf8e7cSmrg 426987bf8e7cSmrg tmp_path = realpath(path, NULL); 427087bf8e7cSmrg if (!tmp_path) 427187bf8e7cSmrg return -errno; 427287bf8e7cSmrg 427387bf8e7cSmrg slash = strrchr(tmp_path, '/'); 427487bf8e7cSmrg if (!slash) { 427587bf8e7cSmrg free(tmp_path); 427687bf8e7cSmrg return -EINVAL; 427787bf8e7cSmrg } 427887bf8e7cSmrg 427987bf8e7cSmrg *slash = '\0'; 428087bf8e7cSmrg 428187bf8e7cSmrg if (snprintf(path, len, "%s", tmp_path) >= (int)len) { 428287bf8e7cSmrg free(tmp_path); 428387bf8e7cSmrg return -EINVAL; 428487bf8e7cSmrg } 428587bf8e7cSmrg 428687bf8e7cSmrg free(tmp_path); 428787bf8e7cSmrg return 0; 428887bf8e7cSmrg} 428987bf8e7cSmrg#endif 429087bf8e7cSmrg 42912ee35494Smrgstatic int drmParseUsbBusInfo(int maj, int min, drmUsbBusInfoPtr info) 42922ee35494Smrg{ 42932ee35494Smrg#ifdef __linux__ 42942ee35494Smrg char path[PATH_MAX + 1], *value; 42952ee35494Smrg unsigned int bus, dev; 42962ee35494Smrg int ret; 42972ee35494Smrg 429887bf8e7cSmrg ret = drm_usb_dev_path(maj, min, path, sizeof(path)); 429987bf8e7cSmrg if (ret < 0) 430087bf8e7cSmrg return ret; 43012ee35494Smrg 43022ee35494Smrg value = sysfs_uevent_get(path, "BUSNUM"); 43032ee35494Smrg if (!value) 43042ee35494Smrg return -ENOENT; 43052ee35494Smrg 43062ee35494Smrg ret = sscanf(value, "%03u", &bus); 43072ee35494Smrg free(value); 43082ee35494Smrg 43092ee35494Smrg if (ret <= 0) 43102ee35494Smrg return -errno; 43112ee35494Smrg 43122ee35494Smrg value = sysfs_uevent_get(path, "DEVNUM"); 43132ee35494Smrg if (!value) 43142ee35494Smrg return -ENOENT; 43152ee35494Smrg 43162ee35494Smrg ret = sscanf(value, "%03u", &dev); 43172ee35494Smrg free(value); 43182ee35494Smrg 43192ee35494Smrg if (ret <= 0) 43202ee35494Smrg return -errno; 43212ee35494Smrg 43222ee35494Smrg info->bus = bus; 43232ee35494Smrg info->dev = dev; 43242ee35494Smrg 43252ee35494Smrg return 0; 43262ee35494Smrg#else 43272ee35494Smrg#warning "Missing implementation of drmParseUsbBusInfo" 43282ee35494Smrg return -EINVAL; 43292ee35494Smrg#endif 43302ee35494Smrg} 43312ee35494Smrg 43322ee35494Smrgstatic int drmParseUsbDeviceInfo(int maj, int min, drmUsbDeviceInfoPtr info) 43332ee35494Smrg{ 43342ee35494Smrg#ifdef __linux__ 43352ee35494Smrg char path[PATH_MAX + 1], *value; 43362ee35494Smrg unsigned int vendor, product; 43372ee35494Smrg int ret; 43382ee35494Smrg 433987bf8e7cSmrg ret = drm_usb_dev_path(maj, min, path, sizeof(path)); 434087bf8e7cSmrg if (ret < 0) 434187bf8e7cSmrg return ret; 43422ee35494Smrg 43432ee35494Smrg value = sysfs_uevent_get(path, "PRODUCT"); 43442ee35494Smrg if (!value) 43452ee35494Smrg return -ENOENT; 43462ee35494Smrg 43472ee35494Smrg ret = sscanf(value, "%x/%x", &vendor, &product); 43482ee35494Smrg free(value); 43492ee35494Smrg 43502ee35494Smrg if (ret <= 0) 43512ee35494Smrg return -errno; 43522ee35494Smrg 43532ee35494Smrg info->vendor = vendor; 43542ee35494Smrg info->product = product; 43552ee35494Smrg 43562ee35494Smrg return 0; 43572ee35494Smrg#else 43582ee35494Smrg#warning "Missing implementation of drmParseUsbDeviceInfo" 43592ee35494Smrg return -EINVAL; 43602ee35494Smrg#endif 43612ee35494Smrg} 43622ee35494Smrg 43632ee35494Smrgstatic int drmProcessUsbDevice(drmDevicePtr *device, const char *node, 43642ee35494Smrg int node_type, int maj, int min, 43652ee35494Smrg bool fetch_deviceinfo, uint32_t flags) 43662ee35494Smrg{ 43672ee35494Smrg drmDevicePtr dev; 43682ee35494Smrg char *ptr; 43692ee35494Smrg int ret; 43702ee35494Smrg 43712ee35494Smrg dev = drmDeviceAlloc(node_type, node, sizeof(drmUsbBusInfo), 43722ee35494Smrg sizeof(drmUsbDeviceInfo), &ptr); 43732ee35494Smrg if (!dev) 43742ee35494Smrg return -ENOMEM; 43752ee35494Smrg 43762ee35494Smrg dev->bustype = DRM_BUS_USB; 43772ee35494Smrg 43782ee35494Smrg dev->businfo.usb = (drmUsbBusInfoPtr)ptr; 43792ee35494Smrg 43802ee35494Smrg ret = drmParseUsbBusInfo(maj, min, dev->businfo.usb); 43812ee35494Smrg if (ret < 0) 43822ee35494Smrg goto free_device; 43832ee35494Smrg 43842ee35494Smrg if (fetch_deviceinfo) { 43852ee35494Smrg ptr += sizeof(drmUsbBusInfo); 43862ee35494Smrg dev->deviceinfo.usb = (drmUsbDeviceInfoPtr)ptr; 43872ee35494Smrg 43882ee35494Smrg ret = drmParseUsbDeviceInfo(maj, min, dev->deviceinfo.usb); 43892ee35494Smrg if (ret < 0) 43902ee35494Smrg goto free_device; 43912ee35494Smrg } 43922ee35494Smrg 43932ee35494Smrg *device = dev; 43942ee35494Smrg 43952ee35494Smrg return 0; 43962ee35494Smrg 43972ee35494Smrgfree_device: 43982ee35494Smrg free(dev); 43992ee35494Smrg return ret; 44002ee35494Smrg} 44012ee35494Smrg 4402bf6cc7dcSmrgstatic int drmParseOFBusInfo(int maj, int min, char *fullname) 44032ee35494Smrg{ 44042ee35494Smrg#ifdef __linux__ 4405bf6cc7dcSmrg char path[PATH_MAX + 1], *name, *tmp_name; 44062ee35494Smrg 44072ee35494Smrg snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min); 44082ee35494Smrg 44092ee35494Smrg name = sysfs_uevent_get(path, "OF_FULLNAME"); 4410bf6cc7dcSmrg tmp_name = name; 4411bf6cc7dcSmrg if (!name) { 4412bf6cc7dcSmrg /* If the device lacks OF data, pick the MODALIAS info */ 4413bf6cc7dcSmrg name = sysfs_uevent_get(path, "MODALIAS"); 4414bf6cc7dcSmrg if (!name) 4415bf6cc7dcSmrg return -ENOENT; 4416bf6cc7dcSmrg 4417bf6cc7dcSmrg /* .. and strip the MODALIAS=[platform,usb...]: part. */ 4418bf6cc7dcSmrg tmp_name = strrchr(name, ':'); 4419bf6cc7dcSmrg if (!tmp_name) { 4420bf6cc7dcSmrg free(name); 4421bf6cc7dcSmrg return -ENOENT; 4422bf6cc7dcSmrg } 4423bf6cc7dcSmrg tmp_name++; 4424bf6cc7dcSmrg } 44252ee35494Smrg 4426bf6cc7dcSmrg strncpy(fullname, tmp_name, DRM_PLATFORM_DEVICE_NAME_LEN); 4427bf6cc7dcSmrg fullname[DRM_PLATFORM_DEVICE_NAME_LEN - 1] = '\0'; 44282ee35494Smrg free(name); 44292ee35494Smrg 44302ee35494Smrg return 0; 44312ee35494Smrg#else 4432bf6cc7dcSmrg#warning "Missing implementation of drmParseOFBusInfo" 44332ee35494Smrg return -EINVAL; 44342ee35494Smrg#endif 44352ee35494Smrg} 44362ee35494Smrg 4437bf6cc7dcSmrgstatic int drmParseOFDeviceInfo(int maj, int min, char ***compatible) 44382ee35494Smrg{ 44392ee35494Smrg#ifdef __linux__ 4440bf6cc7dcSmrg char path[PATH_MAX + 1], *value, *tmp_name; 44412ee35494Smrg unsigned int count, i; 44422ee35494Smrg int err; 44432ee35494Smrg 44442ee35494Smrg snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min); 44452ee35494Smrg 44462ee35494Smrg value = sysfs_uevent_get(path, "OF_COMPATIBLE_N"); 4447bf6cc7dcSmrg if (value) { 4448bf6cc7dcSmrg sscanf(value, "%u", &count); 4449bf6cc7dcSmrg free(value); 4450bf6cc7dcSmrg } else { 4451bf6cc7dcSmrg /* Assume one entry if the device lack OF data */ 4452bf6cc7dcSmrg count = 1; 4453bf6cc7dcSmrg } 44542ee35494Smrg 4455bf6cc7dcSmrg *compatible = calloc(count + 1, sizeof(char *)); 4456bf6cc7dcSmrg if (!*compatible) 44572ee35494Smrg return -ENOMEM; 44582ee35494Smrg 44592ee35494Smrg for (i = 0; i < count; i++) { 44602ee35494Smrg value = sysfs_uevent_get(path, "OF_COMPATIBLE_%u", i); 4461bf6cc7dcSmrg tmp_name = value; 44622ee35494Smrg if (!value) { 4463bf6cc7dcSmrg /* If the device lacks OF data, pick the MODALIAS info */ 4464bf6cc7dcSmrg value = sysfs_uevent_get(path, "MODALIAS"); 4465bf6cc7dcSmrg if (!value) { 4466bf6cc7dcSmrg err = -ENOENT; 4467bf6cc7dcSmrg goto free; 4468bf6cc7dcSmrg } 4469bf6cc7dcSmrg 4470bf6cc7dcSmrg /* .. and strip the MODALIAS=[platform,usb...]: part. */ 4471bf6cc7dcSmrg tmp_name = strrchr(value, ':'); 4472bf6cc7dcSmrg if (!tmp_name) { 4473bf6cc7dcSmrg free(value); 4474bf6cc7dcSmrg return -ENOENT; 4475bf6cc7dcSmrg } 4476bf6cc7dcSmrg tmp_name = strdup(tmp_name + 1); 4477bf6cc7dcSmrg free(value); 44782ee35494Smrg } 44792ee35494Smrg 4480bf6cc7dcSmrg (*compatible)[i] = tmp_name; 44812ee35494Smrg } 44822ee35494Smrg 44832ee35494Smrg return 0; 44842ee35494Smrg 44852ee35494Smrgfree: 44862ee35494Smrg while (i--) 4487bf6cc7dcSmrg free((*compatible)[i]); 44882ee35494Smrg 4489bf6cc7dcSmrg free(*compatible); 44902ee35494Smrg return err; 44912ee35494Smrg#else 4492bf6cc7dcSmrg#warning "Missing implementation of drmParseOFDeviceInfo" 44932ee35494Smrg return -EINVAL; 44942ee35494Smrg#endif 44952ee35494Smrg} 44962ee35494Smrg 44972ee35494Smrgstatic int drmProcessPlatformDevice(drmDevicePtr *device, 44982ee35494Smrg const char *node, int node_type, 44992ee35494Smrg int maj, int min, bool fetch_deviceinfo, 45002ee35494Smrg uint32_t flags) 45012ee35494Smrg{ 45022ee35494Smrg drmDevicePtr dev; 45032ee35494Smrg char *ptr; 45042ee35494Smrg int ret; 45052ee35494Smrg 45062ee35494Smrg dev = drmDeviceAlloc(node_type, node, sizeof(drmPlatformBusInfo), 45072ee35494Smrg sizeof(drmPlatformDeviceInfo), &ptr); 45082ee35494Smrg if (!dev) 45092ee35494Smrg return -ENOMEM; 45102ee35494Smrg 45112ee35494Smrg dev->bustype = DRM_BUS_PLATFORM; 45122ee35494Smrg 45132ee35494Smrg dev->businfo.platform = (drmPlatformBusInfoPtr)ptr; 45142ee35494Smrg 4515bf6cc7dcSmrg ret = drmParseOFBusInfo(maj, min, dev->businfo.platform->fullname); 45162ee35494Smrg if (ret < 0) 45172ee35494Smrg goto free_device; 45182ee35494Smrg 45192ee35494Smrg if (fetch_deviceinfo) { 45202ee35494Smrg ptr += sizeof(drmPlatformBusInfo); 45212ee35494Smrg dev->deviceinfo.platform = (drmPlatformDeviceInfoPtr)ptr; 45222ee35494Smrg 4523bf6cc7dcSmrg ret = drmParseOFDeviceInfo(maj, min, &dev->deviceinfo.platform->compatible); 45242ee35494Smrg if (ret < 0) 45252ee35494Smrg goto free_device; 45262ee35494Smrg } 45272ee35494Smrg 45282ee35494Smrg *device = dev; 45292ee35494Smrg 45302ee35494Smrg return 0; 45312ee35494Smrg 45322ee35494Smrgfree_device: 45332ee35494Smrg free(dev); 45342ee35494Smrg return ret; 45352ee35494Smrg} 45362ee35494Smrg 45372ee35494Smrgstatic int drmProcessHost1xDevice(drmDevicePtr *device, 45382ee35494Smrg const char *node, int node_type, 45392ee35494Smrg int maj, int min, bool fetch_deviceinfo, 45402ee35494Smrg uint32_t flags) 45412ee35494Smrg{ 45422ee35494Smrg drmDevicePtr dev; 45432ee35494Smrg char *ptr; 45442ee35494Smrg int ret; 45452ee35494Smrg 45462ee35494Smrg dev = drmDeviceAlloc(node_type, node, sizeof(drmHost1xBusInfo), 45472ee35494Smrg sizeof(drmHost1xDeviceInfo), &ptr); 45482ee35494Smrg if (!dev) 45492ee35494Smrg return -ENOMEM; 45502ee35494Smrg 45512ee35494Smrg dev->bustype = DRM_BUS_HOST1X; 45522ee35494Smrg 45532ee35494Smrg dev->businfo.host1x = (drmHost1xBusInfoPtr)ptr; 45542ee35494Smrg 4555bf6cc7dcSmrg ret = drmParseOFBusInfo(maj, min, dev->businfo.host1x->fullname); 45562ee35494Smrg if (ret < 0) 45572ee35494Smrg goto free_device; 45582ee35494Smrg 45592ee35494Smrg if (fetch_deviceinfo) { 45602ee35494Smrg ptr += sizeof(drmHost1xBusInfo); 45612ee35494Smrg dev->deviceinfo.host1x = (drmHost1xDeviceInfoPtr)ptr; 45622ee35494Smrg 4563bf6cc7dcSmrg ret = drmParseOFDeviceInfo(maj, min, &dev->deviceinfo.host1x->compatible); 45642ee35494Smrg if (ret < 0) 45652ee35494Smrg goto free_device; 45662ee35494Smrg } 45672ee35494Smrg 45682ee35494Smrg *device = dev; 45692ee35494Smrg 45702ee35494Smrg return 0; 45712ee35494Smrg 45722ee35494Smrgfree_device: 45732ee35494Smrg free(dev); 4574fe517fc9Smrg return ret; 4575fe517fc9Smrg} 4576fe517fc9Smrg 45776260e5d5Smrgstatic int 45786260e5d5Smrgprocess_device(drmDevicePtr *device, const char *d_name, 45796260e5d5Smrg int req_subsystem_type, 45806260e5d5Smrg bool fetch_deviceinfo, uint32_t flags) 45816260e5d5Smrg{ 45826260e5d5Smrg struct stat sbuf; 45836260e5d5Smrg char node[PATH_MAX + 1]; 45846260e5d5Smrg int node_type, subsystem_type; 45856260e5d5Smrg unsigned int maj, min; 45866260e5d5Smrg 45876260e5d5Smrg node_type = drmGetNodeType(d_name); 45886260e5d5Smrg if (node_type < 0) 45896260e5d5Smrg return -1; 45906260e5d5Smrg 45916260e5d5Smrg snprintf(node, PATH_MAX, "%s/%s", DRM_DIR_NAME, d_name); 45926260e5d5Smrg if (stat(node, &sbuf)) 45936260e5d5Smrg return -1; 45946260e5d5Smrg 45956260e5d5Smrg maj = major(sbuf.st_rdev); 45966260e5d5Smrg min = minor(sbuf.st_rdev); 45976260e5d5Smrg 45986260e5d5Smrg if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode)) 45996260e5d5Smrg return -1; 46006260e5d5Smrg 46016260e5d5Smrg subsystem_type = drmParseSubsystemType(maj, min); 46026260e5d5Smrg if (req_subsystem_type != -1 && req_subsystem_type != subsystem_type) 46036260e5d5Smrg return -1; 46046260e5d5Smrg 46056260e5d5Smrg switch (subsystem_type) { 46066260e5d5Smrg case DRM_BUS_PCI: 46076260e5d5Smrg case DRM_BUS_VIRTIO: 46086260e5d5Smrg return drmProcessPciDevice(device, node, node_type, maj, min, 46096260e5d5Smrg fetch_deviceinfo, flags); 46106260e5d5Smrg case DRM_BUS_USB: 46116260e5d5Smrg return drmProcessUsbDevice(device, node, node_type, maj, min, 46126260e5d5Smrg fetch_deviceinfo, flags); 46136260e5d5Smrg case DRM_BUS_PLATFORM: 46146260e5d5Smrg return drmProcessPlatformDevice(device, node, node_type, maj, min, 46156260e5d5Smrg fetch_deviceinfo, flags); 46166260e5d5Smrg case DRM_BUS_HOST1X: 46176260e5d5Smrg return drmProcessHost1xDevice(device, node, node_type, maj, min, 46186260e5d5Smrg fetch_deviceinfo, flags); 46196260e5d5Smrg default: 46206260e5d5Smrg return -1; 46216260e5d5Smrg } 46226260e5d5Smrg} 46236260e5d5Smrg 4624fe517fc9Smrg/* Consider devices located on the same bus as duplicate and fold the respective 4625fe517fc9Smrg * entries into a single one. 4626fe517fc9Smrg * 4627fe517fc9Smrg * Note: this leaves "gaps" in the array, while preserving the length. 4628fe517fc9Smrg */ 4629fe517fc9Smrgstatic void drmFoldDuplicatedDevices(drmDevicePtr local_devices[], int count) 4630fe517fc9Smrg{ 4631fe517fc9Smrg int node_type, i, j; 4632fe517fc9Smrg 4633fe517fc9Smrg for (i = 0; i < count; i++) { 4634fe517fc9Smrg for (j = i + 1; j < count; j++) { 46350655efefSmrg if (drmDevicesEqual(local_devices[i], local_devices[j])) { 4636fe517fc9Smrg local_devices[i]->available_nodes |= local_devices[j]->available_nodes; 46374b3d3f37Smrg node_type = log2_int(local_devices[j]->available_nodes); 4638fe517fc9Smrg memcpy(local_devices[i]->nodes[node_type], 4639fe517fc9Smrg local_devices[j]->nodes[node_type], drmGetMaxNodeName()); 4640fe517fc9Smrg drmFreeDevice(&local_devices[j]); 4641fe517fc9Smrg } 4642fe517fc9Smrg } 4643fe517fc9Smrg } 4644fe517fc9Smrg} 4645fe517fc9Smrg 46462ee35494Smrg/* Check that the given flags are valid returning 0 on success */ 46472ee35494Smrgstatic int 46482ee35494Smrgdrm_device_validate_flags(uint32_t flags) 46492ee35494Smrg{ 46502ee35494Smrg return (flags & ~DRM_DEVICE_GET_PCI_REVISION); 46512ee35494Smrg} 46522ee35494Smrg 46536260e5d5Smrgstatic bool 46546260e5d5Smrgdrm_device_has_rdev(drmDevicePtr device, dev_t find_rdev) 46556260e5d5Smrg{ 46566260e5d5Smrg struct stat sbuf; 46576260e5d5Smrg 46586260e5d5Smrg for (int i = 0; i < DRM_NODE_MAX; i++) { 46596260e5d5Smrg if (device->available_nodes & 1 << i) { 46606260e5d5Smrg if (stat(device->nodes[i], &sbuf) == 0 && 46616260e5d5Smrg sbuf.st_rdev == find_rdev) 46626260e5d5Smrg return true; 46636260e5d5Smrg } 46646260e5d5Smrg } 46656260e5d5Smrg return false; 46666260e5d5Smrg} 46676260e5d5Smrg 46686260e5d5Smrg/* 46696260e5d5Smrg * The kernel drm core has a number of places that assume maximum of 46706260e5d5Smrg * 3x64 devices nodes. That's 64 for each of primary, control and 46716260e5d5Smrg * render nodes. Rounded it up to 256 for simplicity. 46726260e5d5Smrg */ 46736260e5d5Smrg#define MAX_DRM_NODES 256 46746260e5d5Smrg 4675fe517fc9Smrg/** 4676adfa0b0cSmrg * Get information about a device from its dev_t identifier 4677fe517fc9Smrg * 4678adfa0b0cSmrg * \param find_rdev dev_t identifier of the device 46792ee35494Smrg * \param flags feature/behaviour bitmask 4680fe517fc9Smrg * \param device the address of a drmDevicePtr where the information 4681fe517fc9Smrg * will be allocated in stored 4682fe517fc9Smrg * 4683fe517fc9Smrg * \return zero on success, negative error code otherwise. 4684fe517fc9Smrg */ 4685adfa0b0cSmrgdrm_public int drmGetDeviceFromDevId(dev_t find_rdev, uint32_t flags, drmDevicePtr *device) 4686fe517fc9Smrg{ 46872ee35494Smrg#ifdef __OpenBSD__ 46882ee35494Smrg /* 46892ee35494Smrg * DRI device nodes on OpenBSD are not in their own directory, they reside 46902ee35494Smrg * in /dev along with a large number of statically generated /dev nodes. 46912ee35494Smrg * Avoid stat'ing all of /dev needlessly by implementing this custom path. 46922ee35494Smrg */ 46932ee35494Smrg drmDevicePtr d; 46942ee35494Smrg char node[PATH_MAX + 1]; 46952ee35494Smrg const char *dev_name; 46962ee35494Smrg int node_type, subsystem_type; 469782025ec7Smrg int maj, min, n, ret; 46982ee35494Smrg 4699adfa0b0cSmrg if (device == NULL) 47002ee35494Smrg return -EINVAL; 47012ee35494Smrg 4702adfa0b0cSmrg maj = major(find_rdev); 4703adfa0b0cSmrg min = minor(find_rdev); 47042ee35494Smrg 4705adfa0b0cSmrg if (!drmNodeIsDRM(maj, min)) 47062ee35494Smrg return -EINVAL; 47072ee35494Smrg 470887bf8e7cSmrg node_type = drmGetMinorType(maj, min); 47092ee35494Smrg if (node_type == -1) 47102ee35494Smrg return -ENODEV; 47112ee35494Smrg 471282025ec7Smrg dev_name = drmGetDeviceName(node_type); 471382025ec7Smrg if (!dev_name) 47142ee35494Smrg return -EINVAL; 47152ee35494Smrg 471682025ec7Smrg n = snprintf(node, PATH_MAX, dev_name, DRM_DIR_NAME, min); 47172ee35494Smrg if (n == -1 || n >= PATH_MAX) 47182ee35494Smrg return -errno; 47192ee35494Smrg if (stat(node, &sbuf)) 47202ee35494Smrg return -EINVAL; 47212ee35494Smrg 47222ee35494Smrg subsystem_type = drmParseSubsystemType(maj, min); 47232ee35494Smrg if (subsystem_type != DRM_BUS_PCI) 47242ee35494Smrg return -ENODEV; 47252ee35494Smrg 47262ee35494Smrg ret = drmProcessPciDevice(&d, node, node_type, maj, min, true, flags); 47272ee35494Smrg if (ret) 47282ee35494Smrg return ret; 47292ee35494Smrg 47302ee35494Smrg *device = d; 47312ee35494Smrg 47322ee35494Smrg return 0; 47332ee35494Smrg#else 47346260e5d5Smrg drmDevicePtr local_devices[MAX_DRM_NODES]; 4735fe517fc9Smrg drmDevicePtr d; 4736fe517fc9Smrg DIR *sysdir; 4737fe517fc9Smrg struct dirent *dent; 47386260e5d5Smrg int subsystem_type; 4739fe517fc9Smrg int maj, min; 4740fe517fc9Smrg int ret, i, node_count; 4741fe517fc9Smrg 47422ee35494Smrg if (drm_device_validate_flags(flags)) 47432ee35494Smrg return -EINVAL; 47442ee35494Smrg 4745adfa0b0cSmrg if (device == NULL) 4746fe517fc9Smrg return -EINVAL; 4747fe517fc9Smrg 4748adfa0b0cSmrg maj = major(find_rdev); 4749adfa0b0cSmrg min = minor(find_rdev); 4750fe517fc9Smrg 4751adfa0b0cSmrg if (!drmNodeIsDRM(maj, min)) 4752fe517fc9Smrg return -EINVAL; 4753fe517fc9Smrg 4754fe517fc9Smrg subsystem_type = drmParseSubsystemType(maj, min); 47556260e5d5Smrg if (subsystem_type < 0) 47566260e5d5Smrg return subsystem_type; 4757fe517fc9Smrg 4758fe517fc9Smrg sysdir = opendir(DRM_DIR_NAME); 47596260e5d5Smrg if (!sysdir) 47606260e5d5Smrg return -errno; 4761fe517fc9Smrg 4762fe517fc9Smrg i = 0; 4763fe517fc9Smrg while ((dent = readdir(sysdir))) { 47646260e5d5Smrg ret = process_device(&d, dent->d_name, subsystem_type, true, flags); 47656260e5d5Smrg if (ret) 4766fe517fc9Smrg continue; 4767fe517fc9Smrg 47686260e5d5Smrg if (i >= MAX_DRM_NODES) { 47696260e5d5Smrg fprintf(stderr, "More than %d drm nodes detected. " 47706260e5d5Smrg "Please report a bug - that should not happen.\n" 47716260e5d5Smrg "Skipping extra nodes\n", MAX_DRM_NODES); 4772fe517fc9Smrg break; 4773fe517fc9Smrg } 47746260e5d5Smrg local_devices[i] = d; 4775fe517fc9Smrg i++; 4776fe517fc9Smrg } 4777fe517fc9Smrg node_count = i; 4778fe517fc9Smrg 4779fe517fc9Smrg drmFoldDuplicatedDevices(local_devices, node_count); 4780fe517fc9Smrg 47816260e5d5Smrg *device = NULL; 47826260e5d5Smrg 47836260e5d5Smrg for (i = 0; i < node_count; i++) { 47846260e5d5Smrg if (!local_devices[i]) 47856260e5d5Smrg continue; 47866260e5d5Smrg 47876260e5d5Smrg if (drm_device_has_rdev(local_devices[i], find_rdev)) 47886260e5d5Smrg *device = local_devices[i]; 47896260e5d5Smrg else 47906260e5d5Smrg drmFreeDevice(&local_devices[i]); 47916260e5d5Smrg } 4792fe517fc9Smrg 4793fe517fc9Smrg closedir(sysdir); 47942ee35494Smrg if (*device == NULL) 47952ee35494Smrg return -ENODEV; 4796fe517fc9Smrg return 0; 47972ee35494Smrg#endif 47982ee35494Smrg} 47992ee35494Smrg 4800adfa0b0cSmrg/** 4801adfa0b0cSmrg * Get information about the opened drm device 4802adfa0b0cSmrg * 4803adfa0b0cSmrg * \param fd file descriptor of the drm device 4804adfa0b0cSmrg * \param flags feature/behaviour bitmask 4805adfa0b0cSmrg * \param device the address of a drmDevicePtr where the information 4806adfa0b0cSmrg * will be allocated in stored 4807adfa0b0cSmrg * 4808adfa0b0cSmrg * \return zero on success, negative error code otherwise. 4809adfa0b0cSmrg * 4810adfa0b0cSmrg * \note Unlike drmGetDevice it does not retrieve the pci device revision field 4811adfa0b0cSmrg * unless the DRM_DEVICE_GET_PCI_REVISION \p flag is set. 4812adfa0b0cSmrg */ 4813adfa0b0cSmrgdrm_public int drmGetDevice2(int fd, uint32_t flags, drmDevicePtr *device) 4814adfa0b0cSmrg{ 4815adfa0b0cSmrg struct stat sbuf; 4816adfa0b0cSmrg 4817adfa0b0cSmrg if (fd == -1) 4818adfa0b0cSmrg return -EINVAL; 4819adfa0b0cSmrg 4820adfa0b0cSmrg if (fstat(fd, &sbuf)) 4821adfa0b0cSmrg return -errno; 4822adfa0b0cSmrg 4823adfa0b0cSmrg if (!S_ISCHR(sbuf.st_mode)) 4824adfa0b0cSmrg return -EINVAL; 4825adfa0b0cSmrg 4826adfa0b0cSmrg return drmGetDeviceFromDevId(sbuf.st_rdev, flags, device); 4827adfa0b0cSmrg} 4828adfa0b0cSmrg 48292ee35494Smrg/** 48302ee35494Smrg * Get information about the opened drm device 48312ee35494Smrg * 48322ee35494Smrg * \param fd file descriptor of the drm device 48332ee35494Smrg * \param device the address of a drmDevicePtr where the information 48342ee35494Smrg * will be allocated in stored 48352ee35494Smrg * 48362ee35494Smrg * \return zero on success, negative error code otherwise. 48372ee35494Smrg */ 48386260e5d5Smrgdrm_public int drmGetDevice(int fd, drmDevicePtr *device) 48392ee35494Smrg{ 48402ee35494Smrg return drmGetDevice2(fd, DRM_DEVICE_GET_PCI_REVISION, device); 4841fe517fc9Smrg} 4842fe517fc9Smrg 4843fe517fc9Smrg/** 4844fe517fc9Smrg * Get drm devices on the system 4845fe517fc9Smrg * 48462ee35494Smrg * \param flags feature/behaviour bitmask 4847fe517fc9Smrg * \param devices the array of devices with drmDevicePtr elements 4848fe517fc9Smrg * can be NULL to get the device number first 4849fe517fc9Smrg * \param max_devices the maximum number of devices for the array 4850fe517fc9Smrg * 4851fe517fc9Smrg * \return on error - negative error code, 4852fe517fc9Smrg * if devices is NULL - total number of devices available on the system, 4853fe517fc9Smrg * alternatively the number of devices stored in devices[], which is 4854fe517fc9Smrg * capped by the max_devices. 48552ee35494Smrg * 48562ee35494Smrg * \note Unlike drmGetDevices it does not retrieve the pci device revision field 48572ee35494Smrg * unless the DRM_DEVICE_GET_PCI_REVISION \p flag is set. 4858fe517fc9Smrg */ 48596260e5d5Smrgdrm_public int drmGetDevices2(uint32_t flags, drmDevicePtr devices[], 48606260e5d5Smrg int max_devices) 4861fe517fc9Smrg{ 48626260e5d5Smrg drmDevicePtr local_devices[MAX_DRM_NODES]; 4863fe517fc9Smrg drmDevicePtr device; 4864fe517fc9Smrg DIR *sysdir; 4865fe517fc9Smrg struct dirent *dent; 4866fe517fc9Smrg int ret, i, node_count, device_count; 4867fe517fc9Smrg 48682ee35494Smrg if (drm_device_validate_flags(flags)) 48692ee35494Smrg return -EINVAL; 48702ee35494Smrg 4871fe517fc9Smrg sysdir = opendir(DRM_DIR_NAME); 48726260e5d5Smrg if (!sysdir) 48736260e5d5Smrg return -errno; 4874fe517fc9Smrg 4875fe517fc9Smrg i = 0; 4876fe517fc9Smrg while ((dent = readdir(sysdir))) { 48776260e5d5Smrg ret = process_device(&device, dent->d_name, -1, devices != NULL, flags); 48786260e5d5Smrg if (ret) 4879fe517fc9Smrg continue; 4880fe517fc9Smrg 48816260e5d5Smrg if (i >= MAX_DRM_NODES) { 48826260e5d5Smrg fprintf(stderr, "More than %d drm nodes detected. " 48836260e5d5Smrg "Please report a bug - that should not happen.\n" 48846260e5d5Smrg "Skipping extra nodes\n", MAX_DRM_NODES); 48852ee35494Smrg break; 4886fe517fc9Smrg } 4887fe517fc9Smrg local_devices[i] = device; 4888fe517fc9Smrg i++; 4889fe517fc9Smrg } 4890fe517fc9Smrg node_count = i; 4891fe517fc9Smrg 4892fe517fc9Smrg drmFoldDuplicatedDevices(local_devices, node_count); 4893fe517fc9Smrg 4894fe517fc9Smrg device_count = 0; 4895fe517fc9Smrg for (i = 0; i < node_count; i++) { 4896fe517fc9Smrg if (!local_devices[i]) 4897fe517fc9Smrg continue; 4898fe517fc9Smrg 4899fe517fc9Smrg if ((devices != NULL) && (device_count < max_devices)) 4900fe517fc9Smrg devices[device_count] = local_devices[i]; 4901fe517fc9Smrg else 4902fe517fc9Smrg drmFreeDevice(&local_devices[i]); 4903fe517fc9Smrg 4904fe517fc9Smrg device_count++; 4905fe517fc9Smrg } 4906fe517fc9Smrg 4907fe517fc9Smrg closedir(sysdir); 49084b3d3f37Smrg 49094b3d3f37Smrg if (devices != NULL) 49104b3d3f37Smrg return MIN2(device_count, max_devices); 49114b3d3f37Smrg 4912fe517fc9Smrg return device_count; 4913424e9256Smrg} 49142ee35494Smrg 49152ee35494Smrg/** 49162ee35494Smrg * Get drm devices on the system 49172ee35494Smrg * 49182ee35494Smrg * \param devices the array of devices with drmDevicePtr elements 49192ee35494Smrg * can be NULL to get the device number first 49202ee35494Smrg * \param max_devices the maximum number of devices for the array 49212ee35494Smrg * 49222ee35494Smrg * \return on error - negative error code, 49232ee35494Smrg * if devices is NULL - total number of devices available on the system, 49242ee35494Smrg * alternatively the number of devices stored in devices[], which is 49252ee35494Smrg * capped by the max_devices. 49262ee35494Smrg */ 49276260e5d5Smrgdrm_public int drmGetDevices(drmDevicePtr devices[], int max_devices) 49282ee35494Smrg{ 49292ee35494Smrg return drmGetDevices2(DRM_DEVICE_GET_PCI_REVISION, devices, max_devices); 49302ee35494Smrg} 49312ee35494Smrg 49326260e5d5Smrgdrm_public char *drmGetDeviceNameFromFd2(int fd) 49332ee35494Smrg{ 49342ee35494Smrg#ifdef __linux__ 49352ee35494Smrg struct stat sbuf; 49362ee35494Smrg char path[PATH_MAX + 1], *value; 49372ee35494Smrg unsigned int maj, min; 49382ee35494Smrg 49392ee35494Smrg if (fstat(fd, &sbuf)) 49402ee35494Smrg return NULL; 49412ee35494Smrg 49422ee35494Smrg maj = major(sbuf.st_rdev); 49432ee35494Smrg min = minor(sbuf.st_rdev); 49442ee35494Smrg 49456260e5d5Smrg if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode)) 49462ee35494Smrg return NULL; 49472ee35494Smrg 49482ee35494Smrg snprintf(path, sizeof(path), "/sys/dev/char/%d:%d", maj, min); 49492ee35494Smrg 49502ee35494Smrg value = sysfs_uevent_get(path, "DEVNAME"); 49512ee35494Smrg if (!value) 49522ee35494Smrg return NULL; 49532ee35494Smrg 49542ee35494Smrg snprintf(path, sizeof(path), "/dev/%s", value); 49552ee35494Smrg free(value); 49562ee35494Smrg 49572ee35494Smrg return strdup(path); 49584b3d3f37Smrg#elif defined(__FreeBSD__) 495987bf8e7cSmrg return drmGetDeviceNameFromFd(fd); 49602ee35494Smrg#else 49612ee35494Smrg struct stat sbuf; 49622ee35494Smrg char node[PATH_MAX + 1]; 49632ee35494Smrg const char *dev_name; 49642ee35494Smrg int node_type; 496582025ec7Smrg int maj, min, n; 49662ee35494Smrg 49672ee35494Smrg if (fstat(fd, &sbuf)) 49682ee35494Smrg return NULL; 49692ee35494Smrg 49702ee35494Smrg maj = major(sbuf.st_rdev); 49712ee35494Smrg min = minor(sbuf.st_rdev); 49722ee35494Smrg 49736260e5d5Smrg if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode)) 49742ee35494Smrg return NULL; 49752ee35494Smrg 497687bf8e7cSmrg node_type = drmGetMinorType(maj, min); 49772ee35494Smrg if (node_type == -1) 49782ee35494Smrg return NULL; 49792ee35494Smrg 498082025ec7Smrg dev_name = drmGetDeviceName(node_type); 498182025ec7Smrg if (!dev_name) 49822ee35494Smrg return NULL; 49832ee35494Smrg 498482025ec7Smrg n = snprintf(node, PATH_MAX, dev_name, DRM_DIR_NAME, min); 49852ee35494Smrg if (n == -1 || n >= PATH_MAX) 49862ee35494Smrg return NULL; 49872ee35494Smrg 49882ee35494Smrg return strdup(node); 49892ee35494Smrg#endif 49902ee35494Smrg} 49910655efefSmrg 49926260e5d5Smrgdrm_public int drmSyncobjCreate(int fd, uint32_t flags, uint32_t *handle) 49930655efefSmrg{ 49940655efefSmrg struct drm_syncobj_create args; 49950655efefSmrg int ret; 49960655efefSmrg 49970655efefSmrg memclear(args); 49980655efefSmrg args.flags = flags; 49990655efefSmrg args.handle = 0; 50000655efefSmrg ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_CREATE, &args); 50010655efefSmrg if (ret) 50022b90624aSmrg return ret; 50030655efefSmrg *handle = args.handle; 50040655efefSmrg return 0; 50050655efefSmrg} 50060655efefSmrg 50076260e5d5Smrgdrm_public int drmSyncobjDestroy(int fd, uint32_t handle) 50080655efefSmrg{ 50090655efefSmrg struct drm_syncobj_destroy args; 50100655efefSmrg 50110655efefSmrg memclear(args); 50120655efefSmrg args.handle = handle; 50130655efefSmrg return drmIoctl(fd, DRM_IOCTL_SYNCOBJ_DESTROY, &args); 50140655efefSmrg} 50150655efefSmrg 50166260e5d5Smrgdrm_public int drmSyncobjHandleToFD(int fd, uint32_t handle, int *obj_fd) 50170655efefSmrg{ 50180655efefSmrg struct drm_syncobj_handle args; 50190655efefSmrg int ret; 50200655efefSmrg 50210655efefSmrg memclear(args); 50220655efefSmrg args.fd = -1; 50230655efefSmrg args.handle = handle; 50240655efefSmrg ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD, &args); 50250655efefSmrg if (ret) 50262b90624aSmrg return ret; 50270655efefSmrg *obj_fd = args.fd; 50280655efefSmrg return 0; 50290655efefSmrg} 50300655efefSmrg 50316260e5d5Smrgdrm_public int drmSyncobjFDToHandle(int fd, int obj_fd, uint32_t *handle) 50320655efefSmrg{ 50330655efefSmrg struct drm_syncobj_handle args; 50340655efefSmrg int ret; 50350655efefSmrg 50360655efefSmrg memclear(args); 50370655efefSmrg args.fd = obj_fd; 50380655efefSmrg args.handle = 0; 50390655efefSmrg ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE, &args); 50400655efefSmrg if (ret) 50412b90624aSmrg return ret; 50420655efefSmrg *handle = args.handle; 50430655efefSmrg return 0; 50440655efefSmrg} 50450655efefSmrg 50466260e5d5Smrgdrm_public int drmSyncobjImportSyncFile(int fd, uint32_t handle, 50476260e5d5Smrg int sync_file_fd) 50480655efefSmrg{ 50490655efefSmrg struct drm_syncobj_handle args; 50500655efefSmrg 50510655efefSmrg memclear(args); 50520655efefSmrg args.fd = sync_file_fd; 50530655efefSmrg args.handle = handle; 50540655efefSmrg args.flags = DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_IMPORT_SYNC_FILE; 50550655efefSmrg return drmIoctl(fd, DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE, &args); 50560655efefSmrg} 50570655efefSmrg 50586260e5d5Smrgdrm_public int drmSyncobjExportSyncFile(int fd, uint32_t handle, 50596260e5d5Smrg int *sync_file_fd) 50600655efefSmrg{ 50610655efefSmrg struct drm_syncobj_handle args; 50620655efefSmrg int ret; 50630655efefSmrg 50640655efefSmrg memclear(args); 50650655efefSmrg args.fd = -1; 50660655efefSmrg args.handle = handle; 50670655efefSmrg args.flags = DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_EXPORT_SYNC_FILE; 50680655efefSmrg ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD, &args); 50690655efefSmrg if (ret) 50702b90624aSmrg return ret; 50710655efefSmrg *sync_file_fd = args.fd; 50720655efefSmrg return 0; 50730655efefSmrg} 50742b90624aSmrg 50756260e5d5Smrgdrm_public int drmSyncobjWait(int fd, uint32_t *handles, unsigned num_handles, 50766260e5d5Smrg int64_t timeout_nsec, unsigned flags, 50776260e5d5Smrg uint32_t *first_signaled) 50782b90624aSmrg{ 50792b90624aSmrg struct drm_syncobj_wait args; 50802b90624aSmrg int ret; 50812b90624aSmrg 50822b90624aSmrg memclear(args); 50832b90624aSmrg args.handles = (uintptr_t)handles; 50842b90624aSmrg args.timeout_nsec = timeout_nsec; 50852b90624aSmrg args.count_handles = num_handles; 50862b90624aSmrg args.flags = flags; 50872b90624aSmrg 50882b90624aSmrg ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_WAIT, &args); 50892b90624aSmrg if (ret < 0) 50902b90624aSmrg return -errno; 50912b90624aSmrg 50922b90624aSmrg if (first_signaled) 50932b90624aSmrg *first_signaled = args.first_signaled; 50942b90624aSmrg return ret; 50952b90624aSmrg} 50962b90624aSmrg 50976260e5d5Smrgdrm_public int drmSyncobjReset(int fd, const uint32_t *handles, 50986260e5d5Smrg uint32_t handle_count) 50992b90624aSmrg{ 51002b90624aSmrg struct drm_syncobj_array args; 51012b90624aSmrg int ret; 51022b90624aSmrg 51032b90624aSmrg memclear(args); 51042b90624aSmrg args.handles = (uintptr_t)handles; 51052b90624aSmrg args.count_handles = handle_count; 51062b90624aSmrg 51072b90624aSmrg ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_RESET, &args); 51082b90624aSmrg return ret; 51092b90624aSmrg} 51102b90624aSmrg 51116260e5d5Smrgdrm_public int drmSyncobjSignal(int fd, const uint32_t *handles, 51126260e5d5Smrg uint32_t handle_count) 51132b90624aSmrg{ 51142b90624aSmrg struct drm_syncobj_array args; 51152b90624aSmrg int ret; 51162b90624aSmrg 51172b90624aSmrg memclear(args); 51182b90624aSmrg args.handles = (uintptr_t)handles; 51192b90624aSmrg args.count_handles = handle_count; 51202b90624aSmrg 51212b90624aSmrg ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_SIGNAL, &args); 51222b90624aSmrg return ret; 51232b90624aSmrg} 5124bf6cc7dcSmrg 5125bf6cc7dcSmrgdrm_public int drmSyncobjTimelineSignal(int fd, const uint32_t *handles, 5126bf6cc7dcSmrg uint64_t *points, uint32_t handle_count) 5127bf6cc7dcSmrg{ 5128bf6cc7dcSmrg struct drm_syncobj_timeline_array args; 5129bf6cc7dcSmrg int ret; 5130bf6cc7dcSmrg 5131bf6cc7dcSmrg memclear(args); 5132bf6cc7dcSmrg args.handles = (uintptr_t)handles; 5133bf6cc7dcSmrg args.points = (uintptr_t)points; 5134bf6cc7dcSmrg args.count_handles = handle_count; 5135bf6cc7dcSmrg 5136bf6cc7dcSmrg ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_TIMELINE_SIGNAL, &args); 5137bf6cc7dcSmrg return ret; 5138bf6cc7dcSmrg} 5139bf6cc7dcSmrg 5140bf6cc7dcSmrgdrm_public int drmSyncobjTimelineWait(int fd, uint32_t *handles, uint64_t *points, 5141bf6cc7dcSmrg unsigned num_handles, 5142bf6cc7dcSmrg int64_t timeout_nsec, unsigned flags, 5143bf6cc7dcSmrg uint32_t *first_signaled) 5144bf6cc7dcSmrg{ 5145bf6cc7dcSmrg struct drm_syncobj_timeline_wait args; 5146bf6cc7dcSmrg int ret; 5147bf6cc7dcSmrg 5148bf6cc7dcSmrg memclear(args); 5149bf6cc7dcSmrg args.handles = (uintptr_t)handles; 5150bf6cc7dcSmrg args.points = (uintptr_t)points; 5151bf6cc7dcSmrg args.timeout_nsec = timeout_nsec; 5152bf6cc7dcSmrg args.count_handles = num_handles; 5153bf6cc7dcSmrg args.flags = flags; 5154bf6cc7dcSmrg 5155bf6cc7dcSmrg ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_TIMELINE_WAIT, &args); 5156bf6cc7dcSmrg if (ret < 0) 5157bf6cc7dcSmrg return -errno; 5158bf6cc7dcSmrg 5159bf6cc7dcSmrg if (first_signaled) 5160bf6cc7dcSmrg *first_signaled = args.first_signaled; 5161bf6cc7dcSmrg return ret; 5162bf6cc7dcSmrg} 5163bf6cc7dcSmrg 5164bf6cc7dcSmrg 5165bf6cc7dcSmrgdrm_public int drmSyncobjQuery(int fd, uint32_t *handles, uint64_t *points, 5166bf6cc7dcSmrg uint32_t handle_count) 5167bf6cc7dcSmrg{ 5168bf6cc7dcSmrg struct drm_syncobj_timeline_array args; 5169bf6cc7dcSmrg int ret; 5170bf6cc7dcSmrg 5171bf6cc7dcSmrg memclear(args); 5172bf6cc7dcSmrg args.handles = (uintptr_t)handles; 5173bf6cc7dcSmrg args.points = (uintptr_t)points; 5174bf6cc7dcSmrg args.count_handles = handle_count; 5175bf6cc7dcSmrg 5176bf6cc7dcSmrg ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_QUERY, &args); 5177bf6cc7dcSmrg if (ret) 5178bf6cc7dcSmrg return ret; 5179bf6cc7dcSmrg return 0; 5180bf6cc7dcSmrg} 5181bf6cc7dcSmrg 518287bf8e7cSmrgdrm_public int drmSyncobjQuery2(int fd, uint32_t *handles, uint64_t *points, 518387bf8e7cSmrg uint32_t handle_count, uint32_t flags) 518487bf8e7cSmrg{ 518587bf8e7cSmrg struct drm_syncobj_timeline_array args; 518687bf8e7cSmrg 518787bf8e7cSmrg memclear(args); 518887bf8e7cSmrg args.handles = (uintptr_t)handles; 518987bf8e7cSmrg args.points = (uintptr_t)points; 519087bf8e7cSmrg args.count_handles = handle_count; 519187bf8e7cSmrg args.flags = flags; 519287bf8e7cSmrg 519387bf8e7cSmrg return drmIoctl(fd, DRM_IOCTL_SYNCOBJ_QUERY, &args); 519487bf8e7cSmrg} 519587bf8e7cSmrg 519687bf8e7cSmrg 5197bf6cc7dcSmrgdrm_public int drmSyncobjTransfer(int fd, 5198bf6cc7dcSmrg uint32_t dst_handle, uint64_t dst_point, 5199bf6cc7dcSmrg uint32_t src_handle, uint64_t src_point, 5200bf6cc7dcSmrg uint32_t flags) 5201bf6cc7dcSmrg{ 5202bf6cc7dcSmrg struct drm_syncobj_transfer args; 5203bf6cc7dcSmrg int ret; 5204bf6cc7dcSmrg 5205bf6cc7dcSmrg memclear(args); 5206bf6cc7dcSmrg args.src_handle = src_handle; 5207bf6cc7dcSmrg args.dst_handle = dst_handle; 5208bf6cc7dcSmrg args.src_point = src_point; 5209bf6cc7dcSmrg args.dst_point = dst_point; 5210bf6cc7dcSmrg args.flags = flags; 5211bf6cc7dcSmrg 5212bf6cc7dcSmrg ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_TRANSFER, &args); 5213bf6cc7dcSmrg 5214bf6cc7dcSmrg return ret; 5215bf6cc7dcSmrg} 5216636d5e9fSmrg 5217636d5e9fSmrgstatic char * 5218636d5e9fSmrgdrmGetFormatModifierFromSimpleTokens(uint64_t modifier) 5219636d5e9fSmrg{ 5220636d5e9fSmrg unsigned int i; 5221636d5e9fSmrg 5222636d5e9fSmrg for (i = 0; i < ARRAY_SIZE(drm_format_modifier_table); i++) { 5223636d5e9fSmrg if (drm_format_modifier_table[i].modifier == modifier) 5224636d5e9fSmrg return strdup(drm_format_modifier_table[i].modifier_name); 5225636d5e9fSmrg } 5226636d5e9fSmrg 5227636d5e9fSmrg return NULL; 5228636d5e9fSmrg} 5229636d5e9fSmrg 5230636d5e9fSmrg/** Retrieves a human-readable representation of a vendor (as a string) from 5231636d5e9fSmrg * the format token modifier 5232636d5e9fSmrg * 5233636d5e9fSmrg * \param modifier the format modifier token 5234636d5e9fSmrg * \return a char pointer to the human-readable form of the vendor. Caller is 5235636d5e9fSmrg * responsible for freeing it. 5236636d5e9fSmrg */ 5237636d5e9fSmrgdrm_public char * 5238636d5e9fSmrgdrmGetFormatModifierVendor(uint64_t modifier) 5239636d5e9fSmrg{ 5240636d5e9fSmrg unsigned int i; 5241636d5e9fSmrg uint8_t vendor = fourcc_mod_get_vendor(modifier); 5242636d5e9fSmrg 5243636d5e9fSmrg for (i = 0; i < ARRAY_SIZE(drm_format_modifier_vendor_table); i++) { 5244636d5e9fSmrg if (drm_format_modifier_vendor_table[i].vendor == vendor) 5245636d5e9fSmrg return strdup(drm_format_modifier_vendor_table[i].vendor_name); 5246636d5e9fSmrg } 5247636d5e9fSmrg 5248636d5e9fSmrg return NULL; 5249636d5e9fSmrg} 5250636d5e9fSmrg 5251636d5e9fSmrg/** Retrieves a human-readable representation string from a format token 5252636d5e9fSmrg * modifier 5253636d5e9fSmrg * 5254636d5e9fSmrg * If the dedicated function was not able to extract a valid name or searching 5255636d5e9fSmrg * the format modifier was not in the table, this function would return NULL. 5256636d5e9fSmrg * 5257636d5e9fSmrg * \param modifier the token format 5258636d5e9fSmrg * \return a malloc'ed string representation of the modifier. Caller is 5259636d5e9fSmrg * responsible for freeing the string returned. 5260636d5e9fSmrg * 5261636d5e9fSmrg */ 5262636d5e9fSmrgdrm_public char * 5263636d5e9fSmrgdrmGetFormatModifierName(uint64_t modifier) 5264636d5e9fSmrg{ 5265636d5e9fSmrg uint8_t vendorid = fourcc_mod_get_vendor(modifier); 5266636d5e9fSmrg char *modifier_found = NULL; 5267636d5e9fSmrg unsigned int i; 5268636d5e9fSmrg 5269636d5e9fSmrg for (i = 0; i < ARRAY_SIZE(modifier_format_vendor_table); i++) { 5270636d5e9fSmrg if (modifier_format_vendor_table[i].vendor == vendorid) 5271636d5e9fSmrg modifier_found = modifier_format_vendor_table[i].vendor_cb(modifier); 5272636d5e9fSmrg } 5273636d5e9fSmrg 5274636d5e9fSmrg if (!modifier_found) 5275636d5e9fSmrg return drmGetFormatModifierFromSimpleTokens(modifier); 5276636d5e9fSmrg 5277636d5e9fSmrg return modifier_found; 5278636d5e9fSmrg} 5279