xf86drm.c revision 48246ce7
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 63636d5e9fSmrg#include <inttypes.h> 6422944501Smrg 6587bf8e7cSmrg#if defined(__FreeBSD__) 6687bf8e7cSmrg#include <sys/param.h> 6787bf8e7cSmrg#include <sys/pciio.h> 6887bf8e7cSmrg#endif 6987bf8e7cSmrg 704545e80cSmrg#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) 714545e80cSmrg 722ee35494Smrg/* Not all systems have MAP_FAILED defined */ 732ee35494Smrg#ifndef MAP_FAILED 742ee35494Smrg#define MAP_FAILED ((void *)-1) 752ee35494Smrg#endif 7622944501Smrg 7722944501Smrg#include "xf86drm.h" 78424e9256Smrg#include "libdrm_macros.h" 79636d5e9fSmrg#include "drm_fourcc.h" 8022944501Smrg 81fe517fc9Smrg#include "util_math.h" 82fe517fc9Smrg 8387bf8e7cSmrg#ifdef __DragonFly__ 8422944501Smrg#define DRM_MAJOR 145 8522944501Smrg#endif 8622944501Smrg 8722944501Smrg#ifdef __NetBSD__ 882e6867f6Smrg#undef DRM_MAJOR 892e6867f6Smrg#define DRM_MAJOR 180 9006815bcbSmaya#include <sys/param.h> 91a970b457Sriastradh#include <dev/pci/pcireg.h> 92a970b457Sriastradh#include <pci.h> 9322944501Smrg#endif 9422944501Smrg 95fe517fc9Smrg#ifdef __OpenBSD__ 96fe517fc9Smrg#ifdef __i386__ 97fe517fc9Smrg#define DRM_MAJOR 88 98fe517fc9Smrg#else 99fe517fc9Smrg#define DRM_MAJOR 87 10022944501Smrg#endif 101fe517fc9Smrg#endif /* __OpenBSD__ */ 10222944501Smrg 103fe517fc9Smrg#ifndef DRM_MAJOR 104fe517fc9Smrg#define DRM_MAJOR 226 /* Linux */ 10522944501Smrg#endif 10622944501Smrg 1074545e80cSmrg#if defined(__OpenBSD__) || defined(__DragonFly__) 1082ee35494Smrgstruct drm_pciinfo { 1092ee35494Smrg uint16_t domain; 1102ee35494Smrg uint8_t bus; 1112ee35494Smrg uint8_t dev; 1122ee35494Smrg uint8_t func; 1132ee35494Smrg uint16_t vendor_id; 1142ee35494Smrg uint16_t device_id; 1152ee35494Smrg uint16_t subvendor_id; 1162ee35494Smrg uint16_t subdevice_id; 1172ee35494Smrg uint8_t revision_id; 1182ee35494Smrg}; 1192ee35494Smrg 1202ee35494Smrg#define DRM_IOCTL_GET_PCIINFO DRM_IOR(0x15, struct drm_pciinfo) 12111c53d23Schristos#endif 12211c53d23Schristos 12322944501Smrg#define DRM_MSG_VERBOSITY 3 12422944501Smrg 125424e9256Smrg#define memclear(s) memset(&s, 0, sizeof(s)) 12622944501Smrg 12722944501Smrgstatic drmServerInfoPtr drm_server_info; 12822944501Smrg 12987bf8e7cSmrgstatic bool drmNodeIsDRM(int maj, int min); 13087bf8e7cSmrgstatic char *drmGetMinorNameForFD(int fd, int type); 13187bf8e7cSmrg 132636d5e9fSmrg#define DRM_MODIFIER(v, f, f_name) \ 133636d5e9fSmrg .modifier = DRM_FORMAT_MOD_##v ## _ ##f, \ 134636d5e9fSmrg .modifier_name = #f_name 135636d5e9fSmrg 136636d5e9fSmrg#define DRM_MODIFIER_INVALID(v, f_name) \ 137636d5e9fSmrg .modifier = DRM_FORMAT_MOD_INVALID, .modifier_name = #f_name 138636d5e9fSmrg 139636d5e9fSmrg#define DRM_MODIFIER_LINEAR(v, f_name) \ 140636d5e9fSmrg .modifier = DRM_FORMAT_MOD_LINEAR, .modifier_name = #f_name 141636d5e9fSmrg 142636d5e9fSmrg/* Intel is abit special as the format doesn't follow other vendors naming 143636d5e9fSmrg * scheme */ 144636d5e9fSmrg#define DRM_MODIFIER_INTEL(f, f_name) \ 145636d5e9fSmrg .modifier = I915_FORMAT_MOD_##f, .modifier_name = #f_name 146636d5e9fSmrg 147636d5e9fSmrgstruct drmFormatModifierInfo { 148636d5e9fSmrg uint64_t modifier; 149636d5e9fSmrg const char *modifier_name; 150636d5e9fSmrg}; 151636d5e9fSmrg 152636d5e9fSmrgstruct drmFormatModifierVendorInfo { 153636d5e9fSmrg uint8_t vendor; 154636d5e9fSmrg const char *vendor_name; 155636d5e9fSmrg}; 156636d5e9fSmrg 157636d5e9fSmrg#include "generated_static_table_fourcc.h" 158636d5e9fSmrg 159636d5e9fSmrgstruct drmVendorInfo { 160636d5e9fSmrg uint8_t vendor; 161636d5e9fSmrg char *(*vendor_cb)(uint64_t modifier); 162636d5e9fSmrg}; 163636d5e9fSmrg 164636d5e9fSmrgstruct drmFormatVendorModifierInfo { 165636d5e9fSmrg uint64_t modifier; 166636d5e9fSmrg const char *modifier_name; 167636d5e9fSmrg}; 168636d5e9fSmrg 169636d5e9fSmrgstatic char * 170636d5e9fSmrgdrmGetFormatModifierNameFromArm(uint64_t modifier); 171636d5e9fSmrg 172636d5e9fSmrgstatic char * 173636d5e9fSmrgdrmGetFormatModifierNameFromNvidia(uint64_t modifier); 174636d5e9fSmrg 175636d5e9fSmrgstatic char * 176636d5e9fSmrgdrmGetFormatModifierNameFromAmd(uint64_t modifier); 177636d5e9fSmrg 178636d5e9fSmrgstatic char * 179636d5e9fSmrgdrmGetFormatModifierNameFromAmlogic(uint64_t modifier); 180636d5e9fSmrg 18148246ce7Smrgstatic char * 18248246ce7SmrgdrmGetFormatModifierNameFromVivante(uint64_t modifier); 18348246ce7Smrg 184636d5e9fSmrgstatic const struct drmVendorInfo modifier_format_vendor_table[] = { 185636d5e9fSmrg { DRM_FORMAT_MOD_VENDOR_ARM, drmGetFormatModifierNameFromArm }, 186636d5e9fSmrg { DRM_FORMAT_MOD_VENDOR_NVIDIA, drmGetFormatModifierNameFromNvidia }, 187636d5e9fSmrg { DRM_FORMAT_MOD_VENDOR_AMD, drmGetFormatModifierNameFromAmd }, 188636d5e9fSmrg { DRM_FORMAT_MOD_VENDOR_AMLOGIC, drmGetFormatModifierNameFromAmlogic }, 18948246ce7Smrg { DRM_FORMAT_MOD_VENDOR_VIVANTE, drmGetFormatModifierNameFromVivante }, 190636d5e9fSmrg}; 191636d5e9fSmrg 192636d5e9fSmrg#ifndef AFBC_FORMAT_MOD_MODE_VALUE_MASK 193636d5e9fSmrg#define AFBC_FORMAT_MOD_MODE_VALUE_MASK 0x000fffffffffffffULL 194636d5e9fSmrg#endif 195636d5e9fSmrg 196636d5e9fSmrgstatic const struct drmFormatVendorModifierInfo arm_mode_value_table[] = { 197636d5e9fSmrg { AFBC_FORMAT_MOD_YTR, "YTR" }, 198636d5e9fSmrg { AFBC_FORMAT_MOD_SPLIT, "SPLIT" }, 199636d5e9fSmrg { AFBC_FORMAT_MOD_SPARSE, "SPARSE" }, 200636d5e9fSmrg { AFBC_FORMAT_MOD_CBR, "CBR" }, 201636d5e9fSmrg { AFBC_FORMAT_MOD_TILED, "TILED" }, 202636d5e9fSmrg { AFBC_FORMAT_MOD_SC, "SC" }, 203636d5e9fSmrg { AFBC_FORMAT_MOD_DB, "DB" }, 204636d5e9fSmrg { AFBC_FORMAT_MOD_BCH, "BCH" }, 205636d5e9fSmrg { AFBC_FORMAT_MOD_USM, "USM" }, 206636d5e9fSmrg}; 207636d5e9fSmrg 208636d5e9fSmrgstatic bool is_x_t_amd_gfx9_tile(uint64_t tile) 209636d5e9fSmrg{ 210636d5e9fSmrg switch (tile) { 211636d5e9fSmrg case AMD_FMT_MOD_TILE_GFX9_64K_S_X: 212636d5e9fSmrg case AMD_FMT_MOD_TILE_GFX9_64K_D_X: 213636d5e9fSmrg case AMD_FMT_MOD_TILE_GFX9_64K_R_X: 214636d5e9fSmrg return true; 215636d5e9fSmrg } 216636d5e9fSmrg 217636d5e9fSmrg return false; 218636d5e9fSmrg} 219636d5e9fSmrg 220adfa0b0cSmrgstatic bool 221adfa0b0cSmrgdrmGetAfbcFormatModifierNameFromArm(uint64_t modifier, FILE *fp) 222636d5e9fSmrg{ 223636d5e9fSmrg uint64_t mode_value = modifier & AFBC_FORMAT_MOD_MODE_VALUE_MASK; 224636d5e9fSmrg uint64_t block_size = mode_value & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK; 225636d5e9fSmrg 226636d5e9fSmrg const char *block = NULL; 227636d5e9fSmrg const char *mode = NULL; 228636d5e9fSmrg bool did_print_mode = false; 229636d5e9fSmrg 230636d5e9fSmrg /* add block, can only have a (single) block */ 231636d5e9fSmrg switch (block_size) { 232636d5e9fSmrg case AFBC_FORMAT_MOD_BLOCK_SIZE_16x16: 233636d5e9fSmrg block = "16x16"; 234636d5e9fSmrg break; 235636d5e9fSmrg case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8: 236636d5e9fSmrg block = "32x8"; 237636d5e9fSmrg break; 238636d5e9fSmrg case AFBC_FORMAT_MOD_BLOCK_SIZE_64x4: 239636d5e9fSmrg block = "64x4"; 240636d5e9fSmrg break; 241636d5e9fSmrg case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8_64x4: 242636d5e9fSmrg block = "32x8_64x4"; 243636d5e9fSmrg break; 244636d5e9fSmrg } 245636d5e9fSmrg 246636d5e9fSmrg if (!block) { 247adfa0b0cSmrg return false; 248636d5e9fSmrg } 249636d5e9fSmrg 250636d5e9fSmrg fprintf(fp, "BLOCK_SIZE=%s,", block); 251636d5e9fSmrg 252636d5e9fSmrg /* add mode */ 253adfa0b0cSmrg for (unsigned int i = 0; i < ARRAY_SIZE(arm_mode_value_table); i++) { 254636d5e9fSmrg if (arm_mode_value_table[i].modifier & mode_value) { 255636d5e9fSmrg mode = arm_mode_value_table[i].modifier_name; 256636d5e9fSmrg if (!did_print_mode) { 257636d5e9fSmrg fprintf(fp, "MODE=%s", mode); 258636d5e9fSmrg did_print_mode = true; 259636d5e9fSmrg } else { 260636d5e9fSmrg fprintf(fp, "|%s", mode); 261636d5e9fSmrg } 262636d5e9fSmrg } 263636d5e9fSmrg } 264636d5e9fSmrg 265adfa0b0cSmrg return true; 266adfa0b0cSmrg} 267adfa0b0cSmrg 268adfa0b0cSmrgstatic bool 269adfa0b0cSmrgdrmGetAfrcFormatModifierNameFromArm(uint64_t modifier, FILE *fp) 270adfa0b0cSmrg{ 27150027b5bSmrg bool scan_layout; 272adfa0b0cSmrg for (unsigned int i = 0; i < 2; ++i) { 273adfa0b0cSmrg uint64_t coding_unit_block = 274adfa0b0cSmrg (modifier >> (i * 4)) & AFRC_FORMAT_MOD_CU_SIZE_MASK; 275adfa0b0cSmrg const char *coding_unit_size = NULL; 276adfa0b0cSmrg 277adfa0b0cSmrg switch (coding_unit_block) { 278adfa0b0cSmrg case AFRC_FORMAT_MOD_CU_SIZE_16: 279adfa0b0cSmrg coding_unit_size = "CU_16"; 280adfa0b0cSmrg break; 281adfa0b0cSmrg case AFRC_FORMAT_MOD_CU_SIZE_24: 282adfa0b0cSmrg coding_unit_size = "CU_24"; 283adfa0b0cSmrg break; 284adfa0b0cSmrg case AFRC_FORMAT_MOD_CU_SIZE_32: 285adfa0b0cSmrg coding_unit_size = "CU_32"; 286adfa0b0cSmrg break; 287adfa0b0cSmrg } 288adfa0b0cSmrg 289adfa0b0cSmrg if (!coding_unit_size) { 290adfa0b0cSmrg if (i == 0) { 291adfa0b0cSmrg return false; 292adfa0b0cSmrg } 293adfa0b0cSmrg break; 294adfa0b0cSmrg } 295adfa0b0cSmrg 296adfa0b0cSmrg if (i == 0) { 297adfa0b0cSmrg fprintf(fp, "P0=%s,", coding_unit_size); 298adfa0b0cSmrg } else { 299adfa0b0cSmrg fprintf(fp, "P12=%s,", coding_unit_size); 300adfa0b0cSmrg } 301adfa0b0cSmrg } 302adfa0b0cSmrg 30350027b5bSmrg scan_layout = 304adfa0b0cSmrg (modifier & AFRC_FORMAT_MOD_LAYOUT_SCAN) == AFRC_FORMAT_MOD_LAYOUT_SCAN; 305adfa0b0cSmrg if (scan_layout) { 306adfa0b0cSmrg fprintf(fp, "SCAN"); 307adfa0b0cSmrg } else { 308adfa0b0cSmrg fprintf(fp, "ROT"); 309adfa0b0cSmrg } 310adfa0b0cSmrg return true; 311adfa0b0cSmrg} 312adfa0b0cSmrg 313adfa0b0cSmrgstatic char * 314adfa0b0cSmrgdrmGetFormatModifierNameFromArm(uint64_t modifier) 315adfa0b0cSmrg{ 316adfa0b0cSmrg uint64_t type = (modifier >> 52) & 0xf; 317adfa0b0cSmrg 318adfa0b0cSmrg FILE *fp; 319adfa0b0cSmrg size_t size = 0; 320adfa0b0cSmrg char *modifier_name = NULL; 321adfa0b0cSmrg bool result = false; 322adfa0b0cSmrg 323adfa0b0cSmrg fp = open_memstream(&modifier_name, &size); 324adfa0b0cSmrg if (!fp) 325adfa0b0cSmrg return NULL; 326adfa0b0cSmrg 327adfa0b0cSmrg switch (type) { 328adfa0b0cSmrg case DRM_FORMAT_MOD_ARM_TYPE_AFBC: 329adfa0b0cSmrg result = drmGetAfbcFormatModifierNameFromArm(modifier, fp); 330adfa0b0cSmrg break; 331adfa0b0cSmrg case DRM_FORMAT_MOD_ARM_TYPE_AFRC: 332adfa0b0cSmrg result = drmGetAfrcFormatModifierNameFromArm(modifier, fp); 333adfa0b0cSmrg break; 334adfa0b0cSmrg /* misc type is already handled by the static table */ 335adfa0b0cSmrg case DRM_FORMAT_MOD_ARM_TYPE_MISC: 336adfa0b0cSmrg default: 337adfa0b0cSmrg result = false; 338adfa0b0cSmrg break; 339adfa0b0cSmrg } 340adfa0b0cSmrg 341636d5e9fSmrg fclose(fp); 342adfa0b0cSmrg if (!result) { 343adfa0b0cSmrg free(modifier_name); 344adfa0b0cSmrg return NULL; 345adfa0b0cSmrg } 346adfa0b0cSmrg 347636d5e9fSmrg return modifier_name; 348636d5e9fSmrg} 349636d5e9fSmrg 350636d5e9fSmrgstatic char * 351636d5e9fSmrgdrmGetFormatModifierNameFromNvidia(uint64_t modifier) 352636d5e9fSmrg{ 353636d5e9fSmrg uint64_t height, kind, gen, sector, compression; 354636d5e9fSmrg 355636d5e9fSmrg height = modifier & 0xf; 356636d5e9fSmrg kind = (modifier >> 12) & 0xff; 357636d5e9fSmrg 358636d5e9fSmrg gen = (modifier >> 20) & 0x3; 359636d5e9fSmrg sector = (modifier >> 22) & 0x1; 360636d5e9fSmrg compression = (modifier >> 23) & 0x7; 361636d5e9fSmrg 362636d5e9fSmrg /* just in case there could other simpler modifiers, not yet added, avoid 363636d5e9fSmrg * testing against TEGRA_TILE */ 364636d5e9fSmrg if ((modifier & 0x10) == 0x10) { 365636d5e9fSmrg char *mod_nvidia; 366636d5e9fSmrg asprintf(&mod_nvidia, "BLOCK_LINEAR_2D,HEIGHT=%"PRIu64",KIND=%"PRIu64"," 367636d5e9fSmrg "GEN=%"PRIu64",SECTOR=%"PRIu64",COMPRESSION=%"PRIu64"", height, 368636d5e9fSmrg kind, gen, sector, compression); 369636d5e9fSmrg return mod_nvidia; 370636d5e9fSmrg } 371636d5e9fSmrg 372636d5e9fSmrg return NULL; 373636d5e9fSmrg} 374636d5e9fSmrg 375636d5e9fSmrgstatic void 376636d5e9fSmrgdrmGetFormatModifierNameFromAmdDcc(uint64_t modifier, FILE *fp) 377636d5e9fSmrg{ 378636d5e9fSmrg uint64_t dcc_max_compressed_block = 379636d5e9fSmrg AMD_FMT_MOD_GET(DCC_MAX_COMPRESSED_BLOCK, modifier); 380636d5e9fSmrg uint64_t dcc_retile = AMD_FMT_MOD_GET(DCC_RETILE, modifier); 381636d5e9fSmrg 382636d5e9fSmrg const char *dcc_max_compressed_block_str = NULL; 383636d5e9fSmrg 384636d5e9fSmrg fprintf(fp, ",DCC"); 385636d5e9fSmrg 386636d5e9fSmrg if (dcc_retile) 387636d5e9fSmrg fprintf(fp, ",DCC_RETILE"); 388636d5e9fSmrg 389636d5e9fSmrg if (!dcc_retile && AMD_FMT_MOD_GET(DCC_PIPE_ALIGN, modifier)) 390636d5e9fSmrg fprintf(fp, ",DCC_PIPE_ALIGN"); 391636d5e9fSmrg 392636d5e9fSmrg if (AMD_FMT_MOD_GET(DCC_INDEPENDENT_64B, modifier)) 393636d5e9fSmrg fprintf(fp, ",DCC_INDEPENDENT_64B"); 394636d5e9fSmrg 395636d5e9fSmrg if (AMD_FMT_MOD_GET(DCC_INDEPENDENT_128B, modifier)) 396636d5e9fSmrg fprintf(fp, ",DCC_INDEPENDENT_128B"); 397636d5e9fSmrg 398636d5e9fSmrg switch (dcc_max_compressed_block) { 399636d5e9fSmrg case AMD_FMT_MOD_DCC_BLOCK_64B: 400636d5e9fSmrg dcc_max_compressed_block_str = "64B"; 401636d5e9fSmrg break; 402636d5e9fSmrg case AMD_FMT_MOD_DCC_BLOCK_128B: 403636d5e9fSmrg dcc_max_compressed_block_str = "128B"; 404636d5e9fSmrg break; 405636d5e9fSmrg case AMD_FMT_MOD_DCC_BLOCK_256B: 406636d5e9fSmrg dcc_max_compressed_block_str = "256B"; 407636d5e9fSmrg break; 408636d5e9fSmrg } 409636d5e9fSmrg 410636d5e9fSmrg if (dcc_max_compressed_block_str) 411636d5e9fSmrg fprintf(fp, ",DCC_MAX_COMPRESSED_BLOCK=%s", 412636d5e9fSmrg dcc_max_compressed_block_str); 413636d5e9fSmrg 414636d5e9fSmrg if (AMD_FMT_MOD_GET(DCC_CONSTANT_ENCODE, modifier)) 415636d5e9fSmrg fprintf(fp, ",DCC_CONSTANT_ENCODE"); 416636d5e9fSmrg} 417636d5e9fSmrg 418636d5e9fSmrgstatic void 419636d5e9fSmrgdrmGetFormatModifierNameFromAmdTile(uint64_t modifier, FILE *fp) 420636d5e9fSmrg{ 421636d5e9fSmrg uint64_t pipe_xor_bits, bank_xor_bits, packers, rb; 422636d5e9fSmrg uint64_t pipe, pipe_align, dcc, dcc_retile, tile_version; 423636d5e9fSmrg 424636d5e9fSmrg pipe_align = AMD_FMT_MOD_GET(DCC_PIPE_ALIGN, modifier); 425636d5e9fSmrg pipe_xor_bits = AMD_FMT_MOD_GET(PIPE_XOR_BITS, modifier); 426636d5e9fSmrg dcc = AMD_FMT_MOD_GET(DCC, modifier); 427636d5e9fSmrg dcc_retile = AMD_FMT_MOD_GET(DCC_RETILE, modifier); 428636d5e9fSmrg tile_version = AMD_FMT_MOD_GET(TILE_VERSION, modifier); 429636d5e9fSmrg 430636d5e9fSmrg fprintf(fp, ",PIPE_XOR_BITS=%"PRIu64, pipe_xor_bits); 431636d5e9fSmrg 432636d5e9fSmrg if (tile_version == AMD_FMT_MOD_TILE_VER_GFX9) { 433636d5e9fSmrg bank_xor_bits = AMD_FMT_MOD_GET(BANK_XOR_BITS, modifier); 434636d5e9fSmrg fprintf(fp, ",BANK_XOR_BITS=%"PRIu64, bank_xor_bits); 435636d5e9fSmrg } 436636d5e9fSmrg 437636d5e9fSmrg if (tile_version == AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS) { 438636d5e9fSmrg packers = AMD_FMT_MOD_GET(PACKERS, modifier); 439636d5e9fSmrg fprintf(fp, ",PACKERS=%"PRIu64, packers); 440636d5e9fSmrg } 441636d5e9fSmrg 442636d5e9fSmrg if (dcc && tile_version == AMD_FMT_MOD_TILE_VER_GFX9) { 443636d5e9fSmrg rb = AMD_FMT_MOD_GET(RB, modifier); 444636d5e9fSmrg fprintf(fp, ",RB=%"PRIu64, rb); 445636d5e9fSmrg } 446636d5e9fSmrg 447636d5e9fSmrg if (dcc && tile_version == AMD_FMT_MOD_TILE_VER_GFX9 && 448636d5e9fSmrg (dcc_retile || pipe_align)) { 449636d5e9fSmrg pipe = AMD_FMT_MOD_GET(PIPE, modifier); 450636d5e9fSmrg fprintf(fp, ",PIPE_%"PRIu64, pipe); 451636d5e9fSmrg } 452636d5e9fSmrg} 453636d5e9fSmrg 454636d5e9fSmrgstatic char * 455636d5e9fSmrgdrmGetFormatModifierNameFromAmd(uint64_t modifier) 456636d5e9fSmrg{ 457636d5e9fSmrg uint64_t tile, tile_version, dcc; 458636d5e9fSmrg FILE *fp; 459636d5e9fSmrg char *mod_amd = NULL; 460636d5e9fSmrg size_t size = 0; 461636d5e9fSmrg 462636d5e9fSmrg const char *str_tile = NULL; 463636d5e9fSmrg const char *str_tile_version = NULL; 464636d5e9fSmrg 465636d5e9fSmrg tile = AMD_FMT_MOD_GET(TILE, modifier); 466636d5e9fSmrg tile_version = AMD_FMT_MOD_GET(TILE_VERSION, modifier); 467636d5e9fSmrg dcc = AMD_FMT_MOD_GET(DCC, modifier); 468636d5e9fSmrg 469636d5e9fSmrg fp = open_memstream(&mod_amd, &size); 470636d5e9fSmrg if (!fp) 471636d5e9fSmrg return NULL; 472636d5e9fSmrg 473636d5e9fSmrg /* add tile */ 474636d5e9fSmrg switch (tile_version) { 475636d5e9fSmrg case AMD_FMT_MOD_TILE_VER_GFX9: 476636d5e9fSmrg str_tile_version = "GFX9"; 477636d5e9fSmrg break; 478636d5e9fSmrg case AMD_FMT_MOD_TILE_VER_GFX10: 479636d5e9fSmrg str_tile_version = "GFX10"; 480636d5e9fSmrg break; 481636d5e9fSmrg case AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS: 482636d5e9fSmrg str_tile_version = "GFX10_RBPLUS"; 483636d5e9fSmrg break; 48448246ce7Smrg case AMD_FMT_MOD_TILE_VER_GFX11: 48548246ce7Smrg str_tile_version = "GFX11"; 48648246ce7Smrg break; 487636d5e9fSmrg } 488636d5e9fSmrg 489636d5e9fSmrg if (str_tile_version) { 490636d5e9fSmrg fprintf(fp, "%s", str_tile_version); 491636d5e9fSmrg } else { 492636d5e9fSmrg fclose(fp); 493636d5e9fSmrg free(mod_amd); 494636d5e9fSmrg return NULL; 495636d5e9fSmrg } 496636d5e9fSmrg 497636d5e9fSmrg /* add tile str */ 498636d5e9fSmrg switch (tile) { 499636d5e9fSmrg case AMD_FMT_MOD_TILE_GFX9_64K_S: 500636d5e9fSmrg str_tile = "GFX9_64K_S"; 501636d5e9fSmrg break; 502636d5e9fSmrg case AMD_FMT_MOD_TILE_GFX9_64K_D: 503636d5e9fSmrg str_tile = "GFX9_64K_D"; 504636d5e9fSmrg break; 505636d5e9fSmrg case AMD_FMT_MOD_TILE_GFX9_64K_S_X: 506636d5e9fSmrg str_tile = "GFX9_64K_S_X"; 507636d5e9fSmrg break; 508636d5e9fSmrg case AMD_FMT_MOD_TILE_GFX9_64K_D_X: 509636d5e9fSmrg str_tile = "GFX9_64K_D_X"; 510636d5e9fSmrg break; 511636d5e9fSmrg case AMD_FMT_MOD_TILE_GFX9_64K_R_X: 512636d5e9fSmrg str_tile = "GFX9_64K_R_X"; 513636d5e9fSmrg break; 51448246ce7Smrg case AMD_FMT_MOD_TILE_GFX11_256K_R_X: 51548246ce7Smrg str_tile = "GFX11_256K_R_X"; 51648246ce7Smrg break; 517636d5e9fSmrg } 518636d5e9fSmrg 519636d5e9fSmrg if (str_tile) 520636d5e9fSmrg fprintf(fp, ",%s", str_tile); 521636d5e9fSmrg 522636d5e9fSmrg if (dcc) 523636d5e9fSmrg drmGetFormatModifierNameFromAmdDcc(modifier, fp); 524636d5e9fSmrg 525636d5e9fSmrg if (tile_version >= AMD_FMT_MOD_TILE_VER_GFX9 && is_x_t_amd_gfx9_tile(tile)) 526636d5e9fSmrg drmGetFormatModifierNameFromAmdTile(modifier, fp); 527636d5e9fSmrg 528636d5e9fSmrg fclose(fp); 529636d5e9fSmrg return mod_amd; 530636d5e9fSmrg} 531636d5e9fSmrg 532636d5e9fSmrgstatic char * 533636d5e9fSmrgdrmGetFormatModifierNameFromAmlogic(uint64_t modifier) 534636d5e9fSmrg{ 535636d5e9fSmrg uint64_t layout = modifier & 0xff; 536636d5e9fSmrg uint64_t options = (modifier >> 8) & 0xff; 537636d5e9fSmrg char *mod_amlogic = NULL; 538636d5e9fSmrg 539636d5e9fSmrg const char *layout_str; 540636d5e9fSmrg const char *opts_str; 541636d5e9fSmrg 542636d5e9fSmrg switch (layout) { 543636d5e9fSmrg case AMLOGIC_FBC_LAYOUT_BASIC: 544636d5e9fSmrg layout_str = "BASIC"; 545636d5e9fSmrg break; 546636d5e9fSmrg case AMLOGIC_FBC_LAYOUT_SCATTER: 547636d5e9fSmrg layout_str = "SCATTER"; 548636d5e9fSmrg break; 549636d5e9fSmrg default: 550636d5e9fSmrg layout_str = "INVALID_LAYOUT"; 551636d5e9fSmrg break; 552636d5e9fSmrg } 553636d5e9fSmrg 554636d5e9fSmrg if (options & AMLOGIC_FBC_OPTION_MEM_SAVING) 555636d5e9fSmrg opts_str = "MEM_SAVING"; 556636d5e9fSmrg else 557636d5e9fSmrg opts_str = "0"; 558636d5e9fSmrg 559636d5e9fSmrg asprintf(&mod_amlogic, "FBC,LAYOUT=%s,OPTIONS=%s", layout_str, opts_str); 560636d5e9fSmrg return mod_amlogic; 561636d5e9fSmrg} 562636d5e9fSmrg 56348246ce7Smrgstatic char * 56448246ce7SmrgdrmGetFormatModifierNameFromVivante(uint64_t modifier) 56548246ce7Smrg{ 56648246ce7Smrg const char *color_tiling, *tile_status, *compression; 56748246ce7Smrg char *mod_vivante = NULL; 56848246ce7Smrg 56948246ce7Smrg switch (modifier & VIVANTE_MOD_TS_MASK) { 57048246ce7Smrg case 0: 57148246ce7Smrg tile_status = ""; 57248246ce7Smrg break; 57348246ce7Smrg case VIVANTE_MOD_TS_64_4: 57448246ce7Smrg tile_status = ",TS=64B_4"; 57548246ce7Smrg break; 57648246ce7Smrg case VIVANTE_MOD_TS_64_2: 57748246ce7Smrg tile_status = ",TS=64B_2"; 57848246ce7Smrg break; 57948246ce7Smrg case VIVANTE_MOD_TS_128_4: 58048246ce7Smrg tile_status = ",TS=128B_4"; 58148246ce7Smrg break; 58248246ce7Smrg case VIVANTE_MOD_TS_256_4: 58348246ce7Smrg tile_status = ",TS=256B_4"; 58448246ce7Smrg break; 58548246ce7Smrg default: 58648246ce7Smrg tile_status = ",TS=UNKNOWN"; 58748246ce7Smrg break; 58848246ce7Smrg } 58948246ce7Smrg 59048246ce7Smrg switch (modifier & VIVANTE_MOD_COMP_MASK) { 59148246ce7Smrg case 0: 59248246ce7Smrg compression = ""; 59348246ce7Smrg break; 59448246ce7Smrg case VIVANTE_MOD_COMP_DEC400: 59548246ce7Smrg compression = ",COMP=DEC400"; 59648246ce7Smrg break; 59748246ce7Smrg default: 59848246ce7Smrg compression = ",COMP=UNKNOWN"; 59948246ce7Smrg break; 60048246ce7Smrg } 60148246ce7Smrg 60248246ce7Smrg switch (modifier & ~VIVANTE_MOD_EXT_MASK) { 60348246ce7Smrg case 0: 60448246ce7Smrg color_tiling = "LINEAR"; 60548246ce7Smrg break; 60648246ce7Smrg case DRM_FORMAT_MOD_VIVANTE_TILED: 60748246ce7Smrg color_tiling = "TILED"; 60848246ce7Smrg break; 60948246ce7Smrg case DRM_FORMAT_MOD_VIVANTE_SUPER_TILED: 61048246ce7Smrg color_tiling = "SUPER_TILED"; 61148246ce7Smrg break; 61248246ce7Smrg case DRM_FORMAT_MOD_VIVANTE_SPLIT_TILED: 61348246ce7Smrg color_tiling = "SPLIT_TILED"; 61448246ce7Smrg break; 61548246ce7Smrg case DRM_FORMAT_MOD_VIVANTE_SPLIT_SUPER_TILED: 61648246ce7Smrg color_tiling = "SPLIT_SUPER_TILED"; 61748246ce7Smrg break; 61848246ce7Smrg default: 61948246ce7Smrg color_tiling = "UNKNOWN"; 62048246ce7Smrg break; 62148246ce7Smrg } 62248246ce7Smrg 62348246ce7Smrg asprintf(&mod_vivante, "%s%s%s", color_tiling, tile_status, compression); 62448246ce7Smrg return mod_vivante; 62548246ce7Smrg} 62648246ce7Smrg 6274b3d3f37Smrgstatic unsigned log2_int(unsigned x) 6284b3d3f37Smrg{ 6294b3d3f37Smrg unsigned l; 6304b3d3f37Smrg 6314b3d3f37Smrg if (x < 2) { 6324b3d3f37Smrg return 0; 6334b3d3f37Smrg } 6344b3d3f37Smrg for (l = 2; ; l++) { 6354b3d3f37Smrg if ((unsigned)(1 << l) > x) { 6364b3d3f37Smrg return l - 1; 6374b3d3f37Smrg } 6384b3d3f37Smrg } 6394b3d3f37Smrg return 0; 6404b3d3f37Smrg} 6414b3d3f37Smrg 6424b3d3f37Smrg 6436260e5d5Smrgdrm_public void drmSetServerInfo(drmServerInfoPtr info) 64422944501Smrg{ 64522944501Smrg drm_server_info = info; 64622944501Smrg} 64722944501Smrg 64822944501Smrg/** 64922944501Smrg * Output a message to stderr. 65022944501Smrg * 65122944501Smrg * \param format printf() like format string. 65222944501Smrg * 65322944501Smrg * \internal 65422944501Smrg * This function is a wrapper around vfprintf(). 65522944501Smrg */ 65622944501Smrg 657a7d7de1eSmrgstatic int DRM_PRINTFLIKE(1, 0) 658a7d7de1eSmrgdrmDebugPrint(const char *format, va_list ap) 65922944501Smrg{ 66022944501Smrg return vfprintf(stderr, format, ap); 66122944501Smrg} 66222944501Smrg 6636260e5d5Smrgdrm_public void 66422944501SmrgdrmMsg(const char *format, ...) 66522944501Smrg{ 666fe517fc9Smrg va_list ap; 66722944501Smrg const char *env; 668fe517fc9Smrg if (((env = getenv("LIBGL_DEBUG")) && strstr(env, "verbose")) || 669fe517fc9Smrg (drm_server_info && drm_server_info->debug_print)) 67022944501Smrg { 671fe517fc9Smrg va_start(ap, format); 672fe517fc9Smrg if (drm_server_info) { 673fe517fc9Smrg drm_server_info->debug_print(format,ap); 674fe517fc9Smrg } else { 675fe517fc9Smrg drmDebugPrint(format, ap); 676fe517fc9Smrg } 677fe517fc9Smrg va_end(ap); 67822944501Smrg } 67922944501Smrg} 68022944501Smrg 68122944501Smrgstatic void *drmHashTable = NULL; /* Context switch callbacks */ 68222944501Smrg 6836260e5d5Smrgdrm_public void *drmGetHashTable(void) 68422944501Smrg{ 68522944501Smrg return drmHashTable; 68622944501Smrg} 68722944501Smrg 6886260e5d5Smrgdrm_public void *drmMalloc(int size) 68922944501Smrg{ 690424e9256Smrg return calloc(1, size); 69122944501Smrg} 69222944501Smrg 6936260e5d5Smrgdrm_public void drmFree(void *pt) 69422944501Smrg{ 695424e9256Smrg free(pt); 69622944501Smrg} 69722944501Smrg 69822944501Smrg/** 699bf6cc7dcSmrg * Call ioctl, restarting if it is interrupted 70022944501Smrg */ 7016260e5d5Smrgdrm_public int 70222944501SmrgdrmIoctl(int fd, unsigned long request, void *arg) 70322944501Smrg{ 704fe517fc9Smrg int ret; 70522944501Smrg 70622944501Smrg do { 707fe517fc9Smrg ret = ioctl(fd, request, arg); 70822944501Smrg } while (ret == -1 && (errno == EINTR || errno == EAGAIN)); 70922944501Smrg return ret; 71022944501Smrg} 71122944501Smrg 71222944501Smrgstatic unsigned long drmGetKeyFromFd(int fd) 71322944501Smrg{ 71422944501Smrg stat_t st; 71522944501Smrg 71622944501Smrg st.st_rdev = 0; 71722944501Smrg fstat(fd, &st); 71822944501Smrg return st.st_rdev; 71922944501Smrg} 72022944501Smrg 7216260e5d5Smrgdrm_public drmHashEntry *drmGetEntry(int fd) 72222944501Smrg{ 72322944501Smrg unsigned long key = drmGetKeyFromFd(fd); 72422944501Smrg void *value; 72522944501Smrg drmHashEntry *entry; 72622944501Smrg 72722944501Smrg if (!drmHashTable) 728fe517fc9Smrg drmHashTable = drmHashCreate(); 72922944501Smrg 73022944501Smrg if (drmHashLookup(drmHashTable, key, &value)) { 731fe517fc9Smrg entry = drmMalloc(sizeof(*entry)); 732fe517fc9Smrg entry->fd = fd; 733fe517fc9Smrg entry->f = NULL; 734fe517fc9Smrg entry->tagTable = drmHashCreate(); 735fe517fc9Smrg drmHashInsert(drmHashTable, key, entry); 73622944501Smrg } else { 737fe517fc9Smrg entry = value; 73822944501Smrg } 73922944501Smrg return entry; 74022944501Smrg} 74122944501Smrg 74222944501Smrg/** 74322944501Smrg * Compare two busid strings 74422944501Smrg * 74522944501Smrg * \param first 74622944501Smrg * \param second 74722944501Smrg * 74822944501Smrg * \return 1 if matched. 74922944501Smrg * 75022944501Smrg * \internal 75122944501Smrg * This function compares two bus ID strings. It understands the older 75222944501Smrg * PCI:b:d:f format and the newer pci:oooo:bb:dd.f format. In the format, o is 75322944501Smrg * domain, b is bus, d is device, f is function. 75422944501Smrg */ 7556d98c517Smrgstatic int drmMatchBusID(const char *id1, const char *id2, int pci_domain_ok) 75622944501Smrg{ 75722944501Smrg /* First, check if the IDs are exactly the same */ 75822944501Smrg if (strcasecmp(id1, id2) == 0) 759fe517fc9Smrg return 1; 76022944501Smrg 76122944501Smrg /* Try to match old/new-style PCI bus IDs. */ 76222944501Smrg if (strncasecmp(id1, "pci", 3) == 0) { 763fe517fc9Smrg unsigned int o1, b1, d1, f1; 764fe517fc9Smrg unsigned int o2, b2, d2, f2; 765fe517fc9Smrg int ret; 766fe517fc9Smrg 767fe517fc9Smrg ret = sscanf(id1, "pci:%04x:%02x:%02x.%u", &o1, &b1, &d1, &f1); 768fe517fc9Smrg if (ret != 4) { 769fe517fc9Smrg o1 = 0; 770fe517fc9Smrg ret = sscanf(id1, "PCI:%u:%u:%u", &b1, &d1, &f1); 771fe517fc9Smrg if (ret != 3) 772fe517fc9Smrg return 0; 773fe517fc9Smrg } 774fe517fc9Smrg 775fe517fc9Smrg ret = sscanf(id2, "pci:%04x:%02x:%02x.%u", &o2, &b2, &d2, &f2); 776fe517fc9Smrg if (ret != 4) { 777fe517fc9Smrg o2 = 0; 778fe517fc9Smrg ret = sscanf(id2, "PCI:%u:%u:%u", &b2, &d2, &f2); 779fe517fc9Smrg if (ret != 3) 780fe517fc9Smrg return 0; 781fe517fc9Smrg } 782fe517fc9Smrg 783fe517fc9Smrg /* If domains aren't properly supported by the kernel interface, 784fe517fc9Smrg * just ignore them, which sucks less than picking a totally random 785fe517fc9Smrg * card with "open by name" 786fe517fc9Smrg */ 787fe517fc9Smrg if (!pci_domain_ok) 788fe517fc9Smrg o1 = o2 = 0; 789fe517fc9Smrg 790fe517fc9Smrg if ((o1 != o2) || (b1 != b2) || (d1 != d2) || (f1 != f2)) 791fe517fc9Smrg return 0; 792fe517fc9Smrg else 793fe517fc9Smrg return 1; 79422944501Smrg } 79522944501Smrg return 0; 79622944501Smrg} 79722944501Smrg 79822944501Smrg/** 79922944501Smrg * Handles error checking for chown call. 80022944501Smrg * 80122944501Smrg * \param path to file. 80222944501Smrg * \param id of the new owner. 80322944501Smrg * \param id of the new group. 80422944501Smrg * 80522944501Smrg * \return zero if success or -1 if failure. 80622944501Smrg * 80722944501Smrg * \internal 80822944501Smrg * Checks for failure. If failure was caused by signal call chown again. 809bf6cc7dcSmrg * If any other failure happened then it will output error message using 81022944501Smrg * drmMsg() call. 81122944501Smrg */ 8126260e5d5Smrg#if !UDEV 81322944501Smrgstatic int chown_check_return(const char *path, uid_t owner, gid_t group) 81422944501Smrg{ 815fe517fc9Smrg int rv; 81622944501Smrg 817fe517fc9Smrg do { 818fe517fc9Smrg rv = chown(path, owner, group); 819fe517fc9Smrg } while (rv != 0 && errno == EINTR); 82022944501Smrg 821fe517fc9Smrg if (rv == 0) 822fe517fc9Smrg return 0; 82322944501Smrg 824fe517fc9Smrg drmMsg("Failed to change owner or group for file %s! %d: %s\n", 825fe517fc9Smrg path, errno, strerror(errno)); 826fe517fc9Smrg return -1; 82722944501Smrg} 828424e9256Smrg#endif 82922944501Smrg 83082025ec7Smrgstatic const char *drmGetDeviceName(int type) 83182025ec7Smrg{ 83282025ec7Smrg switch (type) { 83382025ec7Smrg case DRM_NODE_PRIMARY: 83482025ec7Smrg return DRM_DEV_NAME; 83582025ec7Smrg case DRM_NODE_RENDER: 83682025ec7Smrg return DRM_RENDER_DEV_NAME; 83782025ec7Smrg } 83882025ec7Smrg return NULL; 83982025ec7Smrg} 84082025ec7Smrg 84122944501Smrg/** 84222944501Smrg * Open the DRM device, creating it if necessary. 84322944501Smrg * 84422944501Smrg * \param dev major and minor numbers of the device. 84522944501Smrg * \param minor minor number of the device. 846fe517fc9Smrg * 84722944501Smrg * \return a file descriptor on success, or a negative value on error. 84822944501Smrg * 84922944501Smrg * \internal 85022944501Smrg * Assembles the device name from \p minor and opens it, creating the device 85122944501Smrg * special file node with the major and minor numbers specified by \p dev and 85222944501Smrg * parent directory if necessary and was called by root. 85322944501Smrg */ 854424e9256Smrgstatic int drmOpenDevice(dev_t dev, int minor, int type) 85522944501Smrg{ 85622944501Smrg stat_t st; 85782025ec7Smrg const char *dev_name = drmGetDeviceName(type); 85882025ec7Smrg char buf[DRM_NODE_NAME_MAX]; 85922944501Smrg int fd; 86022944501Smrg mode_t devmode = DRM_DEV_MODE, serv_mode; 861424e9256Smrg gid_t serv_group; 8626260e5d5Smrg#if !UDEV 86322944501Smrg int isroot = !geteuid(); 86422944501Smrg uid_t user = DRM_DEV_UID; 865424e9256Smrg gid_t group = DRM_DEV_GID; 866424e9256Smrg#endif 867424e9256Smrg 86882025ec7Smrg if (!dev_name) 869fe517fc9Smrg return -EINVAL; 870424e9256Smrg 871424e9256Smrg sprintf(buf, dev_name, DRM_DIR_NAME, minor); 87222944501Smrg drmMsg("drmOpenDevice: node name is %s\n", buf); 87322944501Smrg 874fe517fc9Smrg if (drm_server_info && drm_server_info->get_perms) { 875fe517fc9Smrg drm_server_info->get_perms(&serv_group, &serv_mode); 876fe517fc9Smrg devmode = serv_mode ? serv_mode : DRM_DEV_MODE; 877fe517fc9Smrg devmode &= ~(S_IXUSR|S_IXGRP|S_IXOTH); 87822944501Smrg } 87922944501Smrg 8806260e5d5Smrg#if !UDEV 88122944501Smrg if (stat(DRM_DIR_NAME, &st)) { 882fe517fc9Smrg if (!isroot) 883fe517fc9Smrg return DRM_ERR_NOT_ROOT; 884fe517fc9Smrg mkdir(DRM_DIR_NAME, DRM_DEV_DIRMODE); 885fe517fc9Smrg chown_check_return(DRM_DIR_NAME, 0, 0); /* root:root */ 886fe517fc9Smrg chmod(DRM_DIR_NAME, DRM_DEV_DIRMODE); 88722944501Smrg } 88822944501Smrg 88922944501Smrg /* Check if the device node exists and create it if necessary. */ 89022944501Smrg if (stat(buf, &st)) { 891fe517fc9Smrg if (!isroot) 892fe517fc9Smrg return DRM_ERR_NOT_ROOT; 893fe517fc9Smrg remove(buf); 894fe517fc9Smrg mknod(buf, S_IFCHR | devmode, dev); 89522944501Smrg } 89622944501Smrg 897fe517fc9Smrg if (drm_server_info && drm_server_info->get_perms) { 898fe517fc9Smrg group = ((int)serv_group >= 0) ? serv_group : DRM_DEV_GID; 899fe517fc9Smrg chown_check_return(buf, user, group); 900fe517fc9Smrg chmod(buf, devmode); 90122944501Smrg } 90222944501Smrg#else 90322944501Smrg /* if we modprobed then wait for udev */ 90422944501Smrg { 905fe517fc9Smrg int udev_count = 0; 90622944501Smrgwait_for_udev: 90722944501Smrg if (stat(DRM_DIR_NAME, &st)) { 908fe517fc9Smrg usleep(20); 909fe517fc9Smrg udev_count++; 910fe517fc9Smrg 911fe517fc9Smrg if (udev_count == 50) 912fe517fc9Smrg return -1; 913fe517fc9Smrg goto wait_for_udev; 914fe517fc9Smrg } 915fe517fc9Smrg 916fe517fc9Smrg if (stat(buf, &st)) { 917fe517fc9Smrg usleep(20); 918fe517fc9Smrg udev_count++; 919fe517fc9Smrg 920fe517fc9Smrg if (udev_count == 50) 921fe517fc9Smrg return -1; 922fe517fc9Smrg goto wait_for_udev; 923fe517fc9Smrg } 92422944501Smrg } 92522944501Smrg#endif 92622944501Smrg 9273b115362Smrg fd = open(buf, O_RDWR | O_CLOEXEC); 92822944501Smrg drmMsg("drmOpenDevice: open result is %d, (%s)\n", 929fe517fc9Smrg fd, fd < 0 ? strerror(errno) : "OK"); 93022944501Smrg if (fd >= 0) 931fe517fc9Smrg return fd; 93222944501Smrg 9336260e5d5Smrg#if !UDEV 93422944501Smrg /* Check if the device node is not what we expect it to be, and recreate it 93522944501Smrg * and try again if so. 93622944501Smrg */ 93722944501Smrg if (st.st_rdev != dev) { 938fe517fc9Smrg if (!isroot) 939fe517fc9Smrg return DRM_ERR_NOT_ROOT; 940fe517fc9Smrg remove(buf); 941fe517fc9Smrg mknod(buf, S_IFCHR | devmode, dev); 942fe517fc9Smrg if (drm_server_info && drm_server_info->get_perms) { 943fe517fc9Smrg chown_check_return(buf, user, group); 944fe517fc9Smrg chmod(buf, devmode); 945fe517fc9Smrg } 94622944501Smrg } 9473b115362Smrg fd = open(buf, O_RDWR | O_CLOEXEC); 94822944501Smrg drmMsg("drmOpenDevice: open result is %d, (%s)\n", 949fe517fc9Smrg fd, fd < 0 ? strerror(errno) : "OK"); 95022944501Smrg if (fd >= 0) 951fe517fc9Smrg return fd; 95222944501Smrg 95322944501Smrg drmMsg("drmOpenDevice: Open failed\n"); 95422944501Smrg remove(buf); 9559ce4edccSmrg#endif 95622944501Smrg return -errno; 95722944501Smrg} 95822944501Smrg 95922944501Smrg 96022944501Smrg/** 96122944501Smrg * Open the DRM device 96222944501Smrg * 96322944501Smrg * \param minor device minor number. 96422944501Smrg * \param create allow to create the device if set. 96522944501Smrg * 96622944501Smrg * \return a file descriptor on success, or a negative value on error. 967fe517fc9Smrg * 96822944501Smrg * \internal 96922944501Smrg * Calls drmOpenDevice() if \p create is set, otherwise assembles the device 97022944501Smrg * name from \p minor and opens it. 97122944501Smrg */ 97222944501Smrgstatic int drmOpenMinor(int minor, int create, int type) 97322944501Smrg{ 97422944501Smrg int fd; 97582025ec7Smrg char buf[DRM_NODE_NAME_MAX]; 97682025ec7Smrg const char *dev_name = drmGetDeviceName(type); 977fe517fc9Smrg 97822944501Smrg if (create) 979fe517fc9Smrg return drmOpenDevice(makedev(DRM_MAJOR, minor), minor, type); 980fe517fc9Smrg 98182025ec7Smrg if (!dev_name) 982fe517fc9Smrg return -EINVAL; 983424e9256Smrg 984424e9256Smrg sprintf(buf, dev_name, DRM_DIR_NAME, minor); 9853b115362Smrg if ((fd = open(buf, O_RDWR | O_CLOEXEC)) >= 0) 986fe517fc9Smrg return fd; 98722944501Smrg return -errno; 98822944501Smrg} 98922944501Smrg 99022944501Smrg 99122944501Smrg/** 99222944501Smrg * Determine whether the DRM kernel driver has been loaded. 993fe517fc9Smrg * 99422944501Smrg * \return 1 if the DRM driver is loaded, 0 otherwise. 99522944501Smrg * 996fe517fc9Smrg * \internal 99722944501Smrg * Determine the presence of the kernel driver by attempting to open the 0 99822944501Smrg * minor and get version information. For backward compatibility with older 99922944501Smrg * Linux implementations, /proc/dri is also checked. 100022944501Smrg */ 10016260e5d5Smrgdrm_public int drmAvailable(void) 100222944501Smrg{ 100322944501Smrg drmVersionPtr version; 100422944501Smrg int retval = 0; 100522944501Smrg int fd; 100622944501Smrg 1007424e9256Smrg if ((fd = drmOpenMinor(0, 1, DRM_NODE_PRIMARY)) < 0) { 100822944501Smrg#ifdef __linux__ 1009fe517fc9Smrg /* Try proc for backward Linux compatibility */ 1010fe517fc9Smrg if (!access("/proc/dri/0", R_OK)) 1011fe517fc9Smrg return 1; 101222944501Smrg#endif 1013fe517fc9Smrg return 0; 101422944501Smrg } 1015fe517fc9Smrg 101622944501Smrg if ((version = drmGetVersion(fd))) { 1017fe517fc9Smrg retval = 1; 1018fe517fc9Smrg drmFreeVersion(version); 101922944501Smrg } 102022944501Smrg close(fd); 102122944501Smrg 102222944501Smrg return retval; 102322944501Smrg} 102422944501Smrg 1025424e9256Smrgstatic int drmGetMinorBase(int type) 1026424e9256Smrg{ 1027424e9256Smrg switch (type) { 1028424e9256Smrg case DRM_NODE_PRIMARY: 1029424e9256Smrg return 0; 1030424e9256Smrg case DRM_NODE_RENDER: 1031424e9256Smrg return 128; 1032424e9256Smrg default: 1033424e9256Smrg return -1; 1034424e9256Smrg }; 1035424e9256Smrg} 1036424e9256Smrg 103787bf8e7cSmrgstatic int drmGetMinorType(int major, int minor) 1038424e9256Smrg{ 103987bf8e7cSmrg#ifdef __FreeBSD__ 104087bf8e7cSmrg char name[SPECNAMELEN]; 104187bf8e7cSmrg int id; 104287bf8e7cSmrg 104387bf8e7cSmrg if (!devname_r(makedev(major, minor), S_IFCHR, name, sizeof(name))) 104487bf8e7cSmrg return -1; 104587bf8e7cSmrg 104687bf8e7cSmrg if (sscanf(name, "drm/%d", &id) != 1) { 104787bf8e7cSmrg // If not in /dev/drm/ we have the type in the name 104887bf8e7cSmrg if (sscanf(name, "dri/card%d\n", &id) >= 1) 104987bf8e7cSmrg return DRM_NODE_PRIMARY; 105087bf8e7cSmrg else if (sscanf(name, "dri/renderD%d\n", &id) >= 1) 105187bf8e7cSmrg return DRM_NODE_RENDER; 105287bf8e7cSmrg return -1; 105387bf8e7cSmrg } 105487bf8e7cSmrg 105587bf8e7cSmrg minor = id; 105687bf8e7cSmrg#endif 105748246ce7Smrg char path[DRM_NODE_NAME_MAX]; 105848246ce7Smrg const char *dev_name; 105948246ce7Smrg int i; 1060424e9256Smrg 106148246ce7Smrg for (i = DRM_NODE_PRIMARY; i < DRM_NODE_MAX; i++) { 106248246ce7Smrg dev_name = drmGetDeviceName(i); 106348246ce7Smrg if (!dev_name) 106448246ce7Smrg continue; 106548246ce7Smrg snprintf(path, sizeof(path), dev_name, DRM_DIR_NAME, minor); 106648246ce7Smrg if (!access(path, F_OK)) 106748246ce7Smrg return i; 1068424e9256Smrg } 106948246ce7Smrg 107048246ce7Smrg return -1; 1071424e9256Smrg} 1072424e9256Smrg 1073424e9256Smrgstatic const char *drmGetMinorName(int type) 1074424e9256Smrg{ 1075424e9256Smrg switch (type) { 1076424e9256Smrg case DRM_NODE_PRIMARY: 1077fe517fc9Smrg return DRM_PRIMARY_MINOR_NAME; 1078424e9256Smrg case DRM_NODE_RENDER: 1079fe517fc9Smrg return DRM_RENDER_MINOR_NAME; 1080424e9256Smrg default: 1081424e9256Smrg return NULL; 1082424e9256Smrg } 1083424e9256Smrg} 108422944501Smrg 108522944501Smrg/** 108622944501Smrg * Open the device by bus ID. 108722944501Smrg * 108822944501Smrg * \param busid bus ID. 1089424e9256Smrg * \param type device node type. 109022944501Smrg * 109122944501Smrg * \return a file descriptor on success, or a negative value on error. 109222944501Smrg * 109322944501Smrg * \internal 109422944501Smrg * This function attempts to open every possible minor (up to DRM_MAX_MINOR), 109522944501Smrg * comparing the device bus ID with the one supplied. 109622944501Smrg * 109722944501Smrg * \sa drmOpenMinor() and drmGetBusid(). 109822944501Smrg */ 1099424e9256Smrgstatic int drmOpenByBusid(const char *busid, int type) 110022944501Smrg{ 11016d98c517Smrg int i, pci_domain_ok = 1; 110222944501Smrg int fd; 110322944501Smrg const char *buf; 110422944501Smrg drmSetVersion sv; 1105424e9256Smrg int base = drmGetMinorBase(type); 1106424e9256Smrg 1107424e9256Smrg if (base < 0) 1108424e9256Smrg return -1; 110922944501Smrg 111022944501Smrg drmMsg("drmOpenByBusid: Searching for BusID %s\n", busid); 1111424e9256Smrg for (i = base; i < base + DRM_MAX_MINOR; i++) { 1112fe517fc9Smrg fd = drmOpenMinor(i, 1, type); 1113fe517fc9Smrg drmMsg("drmOpenByBusid: drmOpenMinor returns %d\n", fd); 1114fe517fc9Smrg if (fd >= 0) { 1115fe517fc9Smrg /* We need to try for 1.4 first for proper PCI domain support 1116fe517fc9Smrg * and if that fails, we know the kernel is busted 1117fe517fc9Smrg */ 1118fe517fc9Smrg sv.drm_di_major = 1; 1119fe517fc9Smrg sv.drm_di_minor = 4; 1120fe517fc9Smrg sv.drm_dd_major = -1; /* Don't care */ 1121fe517fc9Smrg sv.drm_dd_minor = -1; /* Don't care */ 1122fe517fc9Smrg if (drmSetInterfaceVersion(fd, &sv)) { 11236d98c517Smrg#ifndef __alpha__ 1124fe517fc9Smrg pci_domain_ok = 0; 11256d98c517Smrg#endif 1126fe517fc9Smrg sv.drm_di_major = 1; 1127fe517fc9Smrg sv.drm_di_minor = 1; 1128fe517fc9Smrg sv.drm_dd_major = -1; /* Don't care */ 1129fe517fc9Smrg sv.drm_dd_minor = -1; /* Don't care */ 1130fe517fc9Smrg drmMsg("drmOpenByBusid: Interface 1.4 failed, trying 1.1\n"); 1131fe517fc9Smrg drmSetInterfaceVersion(fd, &sv); 1132fe517fc9Smrg } 1133fe517fc9Smrg buf = drmGetBusid(fd); 1134fe517fc9Smrg drmMsg("drmOpenByBusid: drmGetBusid reports %s\n", buf); 1135fe517fc9Smrg if (buf && drmMatchBusID(buf, busid, pci_domain_ok)) { 1136fe517fc9Smrg drmFreeBusid(buf); 1137fe517fc9Smrg return fd; 1138fe517fc9Smrg } 1139fe517fc9Smrg if (buf) 1140fe517fc9Smrg drmFreeBusid(buf); 1141fe517fc9Smrg close(fd); 1142fe517fc9Smrg } 114322944501Smrg } 114422944501Smrg return -1; 114522944501Smrg} 114622944501Smrg 114722944501Smrg 114822944501Smrg/** 114922944501Smrg * Open the device by name. 115022944501Smrg * 115122944501Smrg * \param name driver name. 1152424e9256Smrg * \param type the device node type. 1153fe517fc9Smrg * 115422944501Smrg * \return a file descriptor on success, or a negative value on error. 1155fe517fc9Smrg * 115622944501Smrg * \internal 115722944501Smrg * This function opens the first minor number that matches the driver name and 115822944501Smrg * isn't already in use. If it's in use it then it will already have a bus ID 115922944501Smrg * assigned. 1160fe517fc9Smrg * 116122944501Smrg * \sa drmOpenMinor(), drmGetVersion() and drmGetBusid(). 116222944501Smrg */ 1163424e9256Smrgstatic int drmOpenByName(const char *name, int type) 116422944501Smrg{ 116522944501Smrg int i; 116622944501Smrg int fd; 116722944501Smrg drmVersionPtr version; 116822944501Smrg char * id; 1169424e9256Smrg int base = drmGetMinorBase(type); 1170424e9256Smrg 1171424e9256Smrg if (base < 0) 1172424e9256Smrg return -1; 117322944501Smrg 117422944501Smrg /* 117522944501Smrg * Open the first minor number that matches the driver name and isn't 117622944501Smrg * already in use. If it's in use it will have a busid assigned already. 117722944501Smrg */ 1178424e9256Smrg for (i = base; i < base + DRM_MAX_MINOR; i++) { 1179fe517fc9Smrg if ((fd = drmOpenMinor(i, 1, type)) >= 0) { 1180fe517fc9Smrg if ((version = drmGetVersion(fd))) { 1181fe517fc9Smrg if (!strcmp(version->name, name)) { 1182fe517fc9Smrg drmFreeVersion(version); 1183fe517fc9Smrg id = drmGetBusid(fd); 1184fe517fc9Smrg drmMsg("drmGetBusid returned '%s'\n", id ? id : "NULL"); 1185fe517fc9Smrg if (!id || !*id) { 1186fe517fc9Smrg if (id) 1187fe517fc9Smrg drmFreeBusid(id); 1188fe517fc9Smrg return fd; 1189fe517fc9Smrg } else { 1190fe517fc9Smrg drmFreeBusid(id); 1191fe517fc9Smrg } 1192fe517fc9Smrg } else { 1193fe517fc9Smrg drmFreeVersion(version); 1194fe517fc9Smrg } 1195fe517fc9Smrg } 1196fe517fc9Smrg close(fd); 1197fe517fc9Smrg } 119822944501Smrg } 119922944501Smrg 120022944501Smrg#ifdef __linux__ 120122944501Smrg /* Backward-compatibility /proc support */ 120222944501Smrg for (i = 0; i < 8; i++) { 1203fe517fc9Smrg char proc_name[64], buf[512]; 1204fe517fc9Smrg char *driver, *pt, *devstring; 1205fe517fc9Smrg int retcode; 1206fe517fc9Smrg 1207fe517fc9Smrg sprintf(proc_name, "/proc/dri/%d/name", i); 12083b115362Smrg if ((fd = open(proc_name, O_RDONLY)) >= 0) { 1209fe517fc9Smrg retcode = read(fd, buf, sizeof(buf)-1); 1210fe517fc9Smrg close(fd); 1211fe517fc9Smrg if (retcode) { 1212fe517fc9Smrg buf[retcode-1] = '\0'; 1213fe517fc9Smrg for (driver = pt = buf; *pt && *pt != ' '; ++pt) 1214fe517fc9Smrg ; 1215fe517fc9Smrg if (*pt) { /* Device is next */ 1216fe517fc9Smrg *pt = '\0'; 1217fe517fc9Smrg if (!strcmp(driver, name)) { /* Match */ 1218fe517fc9Smrg for (devstring = ++pt; *pt && *pt != ' '; ++pt) 1219fe517fc9Smrg ; 1220fe517fc9Smrg if (*pt) { /* Found busid */ 1221fe517fc9Smrg return drmOpenByBusid(++pt, type); 1222fe517fc9Smrg } else { /* No busid */ 1223fe517fc9Smrg return drmOpenDevice(strtol(devstring, NULL, 0),i, type); 1224fe517fc9Smrg } 1225fe517fc9Smrg } 1226fe517fc9Smrg } 1227fe517fc9Smrg } 1228fe517fc9Smrg } 122922944501Smrg } 123022944501Smrg#endif 123122944501Smrg 123222944501Smrg return -1; 123322944501Smrg} 123422944501Smrg 123522944501Smrg 123622944501Smrg/** 123722944501Smrg * Open the DRM device. 123822944501Smrg * 123922944501Smrg * Looks up the specified name and bus ID, and opens the device found. The 124022944501Smrg * entry in /dev/dri is created if necessary and if called by root. 124122944501Smrg * 124222944501Smrg * \param name driver name. Not referenced if bus ID is supplied. 124322944501Smrg * \param busid bus ID. Zero if not known. 1244fe517fc9Smrg * 124522944501Smrg * \return a file descriptor on success, or a negative value on error. 1246fe517fc9Smrg * 124722944501Smrg * \internal 124822944501Smrg * It calls drmOpenByBusid() if \p busid is specified or drmOpenByName() 124922944501Smrg * otherwise. 125022944501Smrg */ 12516260e5d5Smrgdrm_public int drmOpen(const char *name, const char *busid) 1252424e9256Smrg{ 1253424e9256Smrg return drmOpenWithType(name, busid, DRM_NODE_PRIMARY); 1254424e9256Smrg} 1255424e9256Smrg 1256424e9256Smrg/** 1257424e9256Smrg * Open the DRM device with specified type. 1258424e9256Smrg * 1259424e9256Smrg * Looks up the specified name and bus ID, and opens the device found. The 1260424e9256Smrg * entry in /dev/dri is created if necessary and if called by root. 1261424e9256Smrg * 1262424e9256Smrg * \param name driver name. Not referenced if bus ID is supplied. 1263424e9256Smrg * \param busid bus ID. Zero if not known. 126448246ce7Smrg * \param type the device node type to open, PRIMARY or RENDER 1265424e9256Smrg * 1266424e9256Smrg * \return a file descriptor on success, or a negative value on error. 1267424e9256Smrg * 1268424e9256Smrg * \internal 1269424e9256Smrg * It calls drmOpenByBusid() if \p busid is specified or drmOpenByName() 1270424e9256Smrg * otherwise. 1271424e9256Smrg */ 12726260e5d5Smrgdrm_public int drmOpenWithType(const char *name, const char *busid, int type) 127322944501Smrg{ 1274bf6cc7dcSmrg if (name != NULL && drm_server_info && 1275bf6cc7dcSmrg drm_server_info->load_module && !drmAvailable()) { 1276fe517fc9Smrg /* try to load the kernel module */ 1277fe517fc9Smrg if (!drm_server_info->load_module(name)) { 1278fe517fc9Smrg drmMsg("[drm] failed to load kernel module \"%s\"\n", name); 1279fe517fc9Smrg return -1; 1280fe517fc9Smrg } 128122944501Smrg } 128222944501Smrg 128322944501Smrg if (busid) { 1284fe517fc9Smrg int fd = drmOpenByBusid(busid, type); 1285fe517fc9Smrg if (fd >= 0) 1286fe517fc9Smrg return fd; 128722944501Smrg } 1288fe517fc9Smrg 128922944501Smrg if (name) 1290fe517fc9Smrg return drmOpenByName(name, type); 129122944501Smrg 129222944501Smrg return -1; 129322944501Smrg} 129422944501Smrg 12956260e5d5Smrgdrm_public int drmOpenControl(int minor) 129622944501Smrg{ 129748246ce7Smrg return -EINVAL; 129822944501Smrg} 129922944501Smrg 13006260e5d5Smrgdrm_public int drmOpenRender(int minor) 1301424e9256Smrg{ 1302424e9256Smrg return drmOpenMinor(minor, 0, DRM_NODE_RENDER); 1303424e9256Smrg} 1304424e9256Smrg 130522944501Smrg/** 130622944501Smrg * Free the version information returned by drmGetVersion(). 130722944501Smrg * 130822944501Smrg * \param v pointer to the version information. 130922944501Smrg * 131022944501Smrg * \internal 131122944501Smrg * It frees the memory pointed by \p %v as well as all the non-null strings 131222944501Smrg * pointers in it. 131322944501Smrg */ 13146260e5d5Smrgdrm_public void drmFreeVersion(drmVersionPtr v) 131522944501Smrg{ 131622944501Smrg if (!v) 1317fe517fc9Smrg return; 131822944501Smrg drmFree(v->name); 131922944501Smrg drmFree(v->date); 132022944501Smrg drmFree(v->desc); 132122944501Smrg drmFree(v); 132222944501Smrg} 132322944501Smrg 132422944501Smrg 132522944501Smrg/** 132622944501Smrg * Free the non-public version information returned by the kernel. 132722944501Smrg * 132822944501Smrg * \param v pointer to the version information. 132922944501Smrg * 133022944501Smrg * \internal 133122944501Smrg * Used by drmGetVersion() to free the memory pointed by \p %v as well as all 133222944501Smrg * the non-null strings pointers in it. 133322944501Smrg */ 133422944501Smrgstatic void drmFreeKernelVersion(drm_version_t *v) 133522944501Smrg{ 133622944501Smrg if (!v) 1337fe517fc9Smrg return; 133822944501Smrg drmFree(v->name); 133922944501Smrg drmFree(v->date); 134022944501Smrg drmFree(v->desc); 134122944501Smrg drmFree(v); 134222944501Smrg} 134322944501Smrg 134422944501Smrg 134522944501Smrg/** 134622944501Smrg * Copy version information. 1347fe517fc9Smrg * 134822944501Smrg * \param d destination pointer. 134922944501Smrg * \param s source pointer. 1350fe517fc9Smrg * 135122944501Smrg * \internal 135222944501Smrg * Used by drmGetVersion() to translate the information returned by the ioctl 135322944501Smrg * interface in a private structure into the public structure counterpart. 135422944501Smrg */ 135522944501Smrgstatic void drmCopyVersion(drmVersionPtr d, const drm_version_t *s) 135622944501Smrg{ 135722944501Smrg d->version_major = s->version_major; 135822944501Smrg d->version_minor = s->version_minor; 135922944501Smrg d->version_patchlevel = s->version_patchlevel; 136022944501Smrg d->name_len = s->name_len; 13619ce4edccSmrg d->name = strdup(s->name); 136222944501Smrg d->date_len = s->date_len; 13639ce4edccSmrg d->date = strdup(s->date); 136422944501Smrg d->desc_len = s->desc_len; 13659ce4edccSmrg d->desc = strdup(s->desc); 136622944501Smrg} 136722944501Smrg 136822944501Smrg 136922944501Smrg/** 137022944501Smrg * Query the driver version information. 137122944501Smrg * 137222944501Smrg * \param fd file descriptor. 1373fe517fc9Smrg * 137422944501Smrg * \return pointer to a drmVersion structure which should be freed with 137522944501Smrg * drmFreeVersion(). 1376fe517fc9Smrg * 137722944501Smrg * \note Similar information is available via /proc/dri. 1378fe517fc9Smrg * 137922944501Smrg * \internal 138022944501Smrg * It gets the version information via successive DRM_IOCTL_VERSION ioctls, 138122944501Smrg * first with zeros to get the string lengths, and then the actually strings. 138222944501Smrg * It also null-terminates them since they might not be already. 138322944501Smrg */ 13846260e5d5Smrgdrm_public drmVersionPtr drmGetVersion(int fd) 138522944501Smrg{ 138622944501Smrg drmVersionPtr retval; 138722944501Smrg drm_version_t *version = drmMalloc(sizeof(*version)); 138822944501Smrg 138922944501Smrg if (drmIoctl(fd, DRM_IOCTL_VERSION, version)) { 1390fe517fc9Smrg drmFreeKernelVersion(version); 1391fe517fc9Smrg return NULL; 139222944501Smrg } 139322944501Smrg 139422944501Smrg if (version->name_len) 1395fe517fc9Smrg version->name = drmMalloc(version->name_len + 1); 139622944501Smrg if (version->date_len) 1397fe517fc9Smrg version->date = drmMalloc(version->date_len + 1); 139822944501Smrg if (version->desc_len) 1399fe517fc9Smrg version->desc = drmMalloc(version->desc_len + 1); 140022944501Smrg 140122944501Smrg if (drmIoctl(fd, DRM_IOCTL_VERSION, version)) { 1402fe517fc9Smrg drmMsg("DRM_IOCTL_VERSION: %s\n", strerror(errno)); 1403fe517fc9Smrg drmFreeKernelVersion(version); 1404fe517fc9Smrg return NULL; 140522944501Smrg } 140622944501Smrg 140722944501Smrg /* The results might not be null-terminated strings, so terminate them. */ 140822944501Smrg if (version->name_len) version->name[version->name_len] = '\0'; 140922944501Smrg if (version->date_len) version->date[version->date_len] = '\0'; 141022944501Smrg if (version->desc_len) version->desc[version->desc_len] = '\0'; 141122944501Smrg 141222944501Smrg retval = drmMalloc(sizeof(*retval)); 141322944501Smrg drmCopyVersion(retval, version); 141422944501Smrg drmFreeKernelVersion(version); 141522944501Smrg return retval; 141622944501Smrg} 141722944501Smrg 141822944501Smrg 141922944501Smrg/** 142022944501Smrg * Get version information for the DRM user space library. 1421fe517fc9Smrg * 142222944501Smrg * This version number is driver independent. 1423fe517fc9Smrg * 142422944501Smrg * \param fd file descriptor. 142522944501Smrg * 142622944501Smrg * \return version information. 1427fe517fc9Smrg * 142822944501Smrg * \internal 142922944501Smrg * This function allocates and fills a drm_version structure with a hard coded 143022944501Smrg * version number. 143122944501Smrg */ 14326260e5d5Smrgdrm_public drmVersionPtr drmGetLibVersion(int fd) 143322944501Smrg{ 143422944501Smrg drm_version_t *version = drmMalloc(sizeof(*version)); 143522944501Smrg 143622944501Smrg /* Version history: 143722944501Smrg * NOTE THIS MUST NOT GO ABOVE VERSION 1.X due to drivers needing it 143822944501Smrg * revision 1.0.x = original DRM interface with no drmGetLibVersion 143922944501Smrg * entry point and many drm<Device> extensions 144022944501Smrg * revision 1.1.x = added drmCommand entry points for device extensions 144122944501Smrg * added drmGetLibVersion to identify libdrm.a version 144222944501Smrg * revision 1.2.x = added drmSetInterfaceVersion 144322944501Smrg * modified drmOpen to handle both busid and name 144422944501Smrg * revision 1.3.x = added server + memory manager 144522944501Smrg */ 144622944501Smrg version->version_major = 1; 144722944501Smrg version->version_minor = 3; 144822944501Smrg version->version_patchlevel = 0; 144922944501Smrg 145022944501Smrg return (drmVersionPtr)version; 145122944501Smrg} 145222944501Smrg 14536260e5d5Smrgdrm_public int drmGetCap(int fd, uint64_t capability, uint64_t *value) 145420131375Smrg{ 1455fe517fc9Smrg struct drm_get_cap cap; 1456fe517fc9Smrg int ret; 145720131375Smrg 1458fe517fc9Smrg memclear(cap); 1459fe517fc9Smrg cap.capability = capability; 1460424e9256Smrg 1461fe517fc9Smrg ret = drmIoctl(fd, DRM_IOCTL_GET_CAP, &cap); 1462fe517fc9Smrg if (ret) 1463fe517fc9Smrg return ret; 146420131375Smrg 1465fe517fc9Smrg *value = cap.value; 1466fe517fc9Smrg return 0; 146720131375Smrg} 146820131375Smrg 14696260e5d5Smrgdrm_public int drmSetClientCap(int fd, uint64_t capability, uint64_t value) 147020131375Smrg{ 1471fe517fc9Smrg struct drm_set_client_cap cap; 1472424e9256Smrg 1473fe517fc9Smrg memclear(cap); 1474fe517fc9Smrg cap.capability = capability; 1475fe517fc9Smrg cap.value = value; 147620131375Smrg 1477fe517fc9Smrg return drmIoctl(fd, DRM_IOCTL_SET_CLIENT_CAP, &cap); 147820131375Smrg} 147922944501Smrg 148022944501Smrg/** 148122944501Smrg * Free the bus ID information. 148222944501Smrg * 148322944501Smrg * \param busid bus ID information string as given by drmGetBusid(). 148422944501Smrg * 148522944501Smrg * \internal 148622944501Smrg * This function is just frees the memory pointed by \p busid. 148722944501Smrg */ 14886260e5d5Smrgdrm_public void drmFreeBusid(const char *busid) 148922944501Smrg{ 149022944501Smrg drmFree((void *)busid); 149122944501Smrg} 149222944501Smrg 149322944501Smrg 149422944501Smrg/** 149522944501Smrg * Get the bus ID of the device. 149622944501Smrg * 149722944501Smrg * \param fd file descriptor. 149822944501Smrg * 149922944501Smrg * \return bus ID string. 150022944501Smrg * 150122944501Smrg * \internal 150222944501Smrg * This function gets the bus ID via successive DRM_IOCTL_GET_UNIQUE ioctls to 150322944501Smrg * get the string length and data, passing the arguments in a drm_unique 150422944501Smrg * structure. 150522944501Smrg */ 15066260e5d5Smrgdrm_public char *drmGetBusid(int fd) 150722944501Smrg{ 150822944501Smrg drm_unique_t u; 150922944501Smrg 1510424e9256Smrg memclear(u); 151122944501Smrg 151222944501Smrg if (drmIoctl(fd, DRM_IOCTL_GET_UNIQUE, &u)) 1513fe517fc9Smrg return NULL; 151422944501Smrg u.unique = drmMalloc(u.unique_len + 1); 15150655efefSmrg if (drmIoctl(fd, DRM_IOCTL_GET_UNIQUE, &u)) { 15160655efefSmrg drmFree(u.unique); 1517fe517fc9Smrg return NULL; 15180655efefSmrg } 151922944501Smrg u.unique[u.unique_len] = '\0'; 152022944501Smrg 152122944501Smrg return u.unique; 152222944501Smrg} 152322944501Smrg 152422944501Smrg 152522944501Smrg/** 152622944501Smrg * Set the bus ID of the device. 152722944501Smrg * 152822944501Smrg * \param fd file descriptor. 152922944501Smrg * \param busid bus ID string. 153022944501Smrg * 153122944501Smrg * \return zero on success, negative on failure. 153222944501Smrg * 153322944501Smrg * \internal 153422944501Smrg * This function is a wrapper around the DRM_IOCTL_SET_UNIQUE ioctl, passing 153522944501Smrg * the arguments in a drm_unique structure. 153622944501Smrg */ 15376260e5d5Smrgdrm_public int drmSetBusid(int fd, const char *busid) 153822944501Smrg{ 153922944501Smrg drm_unique_t u; 154022944501Smrg 1541424e9256Smrg memclear(u); 154222944501Smrg u.unique = (char *)busid; 154322944501Smrg u.unique_len = strlen(busid); 154422944501Smrg 154522944501Smrg if (drmIoctl(fd, DRM_IOCTL_SET_UNIQUE, &u)) { 1546fe517fc9Smrg return -errno; 154722944501Smrg } 154822944501Smrg return 0; 154922944501Smrg} 155022944501Smrg 15516260e5d5Smrgdrm_public int drmGetMagic(int fd, drm_magic_t * magic) 155222944501Smrg{ 155322944501Smrg drm_auth_t auth; 155422944501Smrg 1555424e9256Smrg memclear(auth); 1556424e9256Smrg 155722944501Smrg *magic = 0; 155822944501Smrg if (drmIoctl(fd, DRM_IOCTL_GET_MAGIC, &auth)) 1559fe517fc9Smrg return -errno; 156022944501Smrg *magic = auth.magic; 156122944501Smrg return 0; 156222944501Smrg} 156322944501Smrg 15646260e5d5Smrgdrm_public int drmAuthMagic(int fd, drm_magic_t magic) 156522944501Smrg{ 156622944501Smrg drm_auth_t auth; 156722944501Smrg 1568424e9256Smrg memclear(auth); 156922944501Smrg auth.magic = magic; 157022944501Smrg if (drmIoctl(fd, DRM_IOCTL_AUTH_MAGIC, &auth)) 1571fe517fc9Smrg return -errno; 157222944501Smrg return 0; 157322944501Smrg} 157422944501Smrg 157522944501Smrg/** 157622944501Smrg * Specifies a range of memory that is available for mapping by a 157722944501Smrg * non-root process. 157822944501Smrg * 157922944501Smrg * \param fd file descriptor. 158022944501Smrg * \param offset usually the physical address. The actual meaning depends of 158122944501Smrg * the \p type parameter. See below. 158222944501Smrg * \param size of the memory in bytes. 158322944501Smrg * \param type type of the memory to be mapped. 158422944501Smrg * \param flags combination of several flags to modify the function actions. 158522944501Smrg * \param handle will be set to a value that may be used as the offset 158622944501Smrg * parameter for mmap(). 1587fe517fc9Smrg * 158822944501Smrg * \return zero on success or a negative value on error. 158922944501Smrg * 159022944501Smrg * \par Mapping the frame buffer 159122944501Smrg * For the frame buffer 159222944501Smrg * - \p offset will be the physical address of the start of the frame buffer, 159322944501Smrg * - \p size will be the size of the frame buffer in bytes, and 159422944501Smrg * - \p type will be DRM_FRAME_BUFFER. 159522944501Smrg * 159622944501Smrg * \par 159722944501Smrg * The area mapped will be uncached. If MTRR support is available in the 1598fe517fc9Smrg * kernel, the frame buffer area will be set to write combining. 159922944501Smrg * 160022944501Smrg * \par Mapping the MMIO register area 160122944501Smrg * For the MMIO register area, 160222944501Smrg * - \p offset will be the physical address of the start of the register area, 160322944501Smrg * - \p size will be the size of the register area bytes, and 160422944501Smrg * - \p type will be DRM_REGISTERS. 160522944501Smrg * \par 1606fe517fc9Smrg * The area mapped will be uncached. 1607fe517fc9Smrg * 160822944501Smrg * \par Mapping the SAREA 160922944501Smrg * For the SAREA, 161022944501Smrg * - \p offset will be ignored and should be set to zero, 161122944501Smrg * - \p size will be the desired size of the SAREA in bytes, 161222944501Smrg * - \p type will be DRM_SHM. 1613fe517fc9Smrg * 161422944501Smrg * \par 161522944501Smrg * A shared memory area of the requested size will be created and locked in 161622944501Smrg * kernel memory. This area may be mapped into client-space by using the handle 1617fe517fc9Smrg * returned. 1618fe517fc9Smrg * 161922944501Smrg * \note May only be called by root. 162022944501Smrg * 162122944501Smrg * \internal 162222944501Smrg * This function is a wrapper around the DRM_IOCTL_ADD_MAP ioctl, passing 162322944501Smrg * the arguments in a drm_map structure. 162422944501Smrg */ 16256260e5d5Smrgdrm_public int drmAddMap(int fd, drm_handle_t offset, drmSize size, drmMapType type, 16266260e5d5Smrg drmMapFlags flags, drm_handle_t *handle) 162722944501Smrg{ 162822944501Smrg drm_map_t map; 162922944501Smrg 1630424e9256Smrg memclear(map); 163122944501Smrg map.offset = offset; 163222944501Smrg map.size = size; 1633adfa0b0cSmrg map.type = (enum drm_map_type)type; 1634adfa0b0cSmrg map.flags = (enum drm_map_flags)flags; 163522944501Smrg if (drmIoctl(fd, DRM_IOCTL_ADD_MAP, &map)) 1636fe517fc9Smrg return -errno; 163722944501Smrg if (handle) 1638fe517fc9Smrg *handle = (drm_handle_t)(uintptr_t)map.handle; 163922944501Smrg return 0; 164022944501Smrg} 164122944501Smrg 16426260e5d5Smrgdrm_public int drmRmMap(int fd, drm_handle_t handle) 164322944501Smrg{ 164422944501Smrg drm_map_t map; 164522944501Smrg 1646424e9256Smrg memclear(map); 164720131375Smrg map.handle = (void *)(uintptr_t)handle; 164822944501Smrg 164922944501Smrg if(drmIoctl(fd, DRM_IOCTL_RM_MAP, &map)) 1650fe517fc9Smrg return -errno; 165122944501Smrg return 0; 165222944501Smrg} 165322944501Smrg 165422944501Smrg/** 165522944501Smrg * Make buffers available for DMA transfers. 1656fe517fc9Smrg * 165722944501Smrg * \param fd file descriptor. 165822944501Smrg * \param count number of buffers. 165922944501Smrg * \param size size of each buffer. 166022944501Smrg * \param flags buffer allocation flags. 1661fe517fc9Smrg * \param agp_offset offset in the AGP aperture 166222944501Smrg * 166322944501Smrg * \return number of buffers allocated, negative on error. 166422944501Smrg * 166522944501Smrg * \internal 166622944501Smrg * This function is a wrapper around DRM_IOCTL_ADD_BUFS ioctl. 166722944501Smrg * 166822944501Smrg * \sa drm_buf_desc. 166922944501Smrg */ 16706260e5d5Smrgdrm_public int drmAddBufs(int fd, int count, int size, drmBufDescFlags flags, 16716260e5d5Smrg int agp_offset) 167222944501Smrg{ 167322944501Smrg drm_buf_desc_t request; 167422944501Smrg 1675424e9256Smrg memclear(request); 167622944501Smrg request.count = count; 167722944501Smrg request.size = size; 1678adfa0b0cSmrg request.flags = (int)flags; 167922944501Smrg request.agp_start = agp_offset; 168022944501Smrg 168122944501Smrg if (drmIoctl(fd, DRM_IOCTL_ADD_BUFS, &request)) 1682fe517fc9Smrg return -errno; 168322944501Smrg return request.count; 168422944501Smrg} 168522944501Smrg 16866260e5d5Smrgdrm_public int drmMarkBufs(int fd, double low, double high) 168722944501Smrg{ 168822944501Smrg drm_buf_info_t info; 168922944501Smrg int i; 169022944501Smrg 1691424e9256Smrg memclear(info); 169222944501Smrg 169322944501Smrg if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info)) 1694fe517fc9Smrg return -EINVAL; 169522944501Smrg 169622944501Smrg if (!info.count) 1697fe517fc9Smrg return -EINVAL; 169822944501Smrg 169922944501Smrg if (!(info.list = drmMalloc(info.count * sizeof(*info.list)))) 1700fe517fc9Smrg return -ENOMEM; 170122944501Smrg 170222944501Smrg if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info)) { 1703fe517fc9Smrg int retval = -errno; 1704fe517fc9Smrg drmFree(info.list); 1705fe517fc9Smrg return retval; 170622944501Smrg } 170722944501Smrg 170822944501Smrg for (i = 0; i < info.count; i++) { 1709fe517fc9Smrg info.list[i].low_mark = low * info.list[i].count; 1710fe517fc9Smrg info.list[i].high_mark = high * info.list[i].count; 1711fe517fc9Smrg if (drmIoctl(fd, DRM_IOCTL_MARK_BUFS, &info.list[i])) { 1712fe517fc9Smrg int retval = -errno; 1713fe517fc9Smrg drmFree(info.list); 1714fe517fc9Smrg return retval; 1715fe517fc9Smrg } 171622944501Smrg } 171722944501Smrg drmFree(info.list); 171822944501Smrg 171922944501Smrg return 0; 172022944501Smrg} 172122944501Smrg 172222944501Smrg/** 172322944501Smrg * Free buffers. 172422944501Smrg * 172522944501Smrg * \param fd file descriptor. 172622944501Smrg * \param count number of buffers to free. 172722944501Smrg * \param list list of buffers to be freed. 172822944501Smrg * 172922944501Smrg * \return zero on success, or a negative value on failure. 1730fe517fc9Smrg * 173122944501Smrg * \note This function is primarily used for debugging. 1732fe517fc9Smrg * 173322944501Smrg * \internal 173422944501Smrg * This function is a wrapper around the DRM_IOCTL_FREE_BUFS ioctl, passing 173522944501Smrg * the arguments in a drm_buf_free structure. 173622944501Smrg */ 17376260e5d5Smrgdrm_public int drmFreeBufs(int fd, int count, int *list) 173822944501Smrg{ 173922944501Smrg drm_buf_free_t request; 174022944501Smrg 1741424e9256Smrg memclear(request); 174222944501Smrg request.count = count; 174322944501Smrg request.list = list; 174422944501Smrg if (drmIoctl(fd, DRM_IOCTL_FREE_BUFS, &request)) 1745fe517fc9Smrg return -errno; 174622944501Smrg return 0; 174722944501Smrg} 174822944501Smrg 174922944501Smrg 175022944501Smrg/** 175122944501Smrg * Close the device. 175222944501Smrg * 175322944501Smrg * \param fd file descriptor. 175422944501Smrg * 175522944501Smrg * \internal 175622944501Smrg * This function closes the file descriptor. 175722944501Smrg */ 17586260e5d5Smrgdrm_public int drmClose(int fd) 175922944501Smrg{ 176022944501Smrg unsigned long key = drmGetKeyFromFd(fd); 176122944501Smrg drmHashEntry *entry = drmGetEntry(fd); 176222944501Smrg 176322944501Smrg drmHashDestroy(entry->tagTable); 176422944501Smrg entry->fd = 0; 176522944501Smrg entry->f = NULL; 176622944501Smrg entry->tagTable = NULL; 176722944501Smrg 176822944501Smrg drmHashDelete(drmHashTable, key); 176922944501Smrg drmFree(entry); 177022944501Smrg 177122944501Smrg return close(fd); 177222944501Smrg} 177322944501Smrg 177422944501Smrg 177522944501Smrg/** 177622944501Smrg * Map a region of memory. 177722944501Smrg * 177822944501Smrg * \param fd file descriptor. 177922944501Smrg * \param handle handle returned by drmAddMap(). 178022944501Smrg * \param size size in bytes. Must match the size used by drmAddMap(). 178122944501Smrg * \param address will contain the user-space virtual address where the mapping 178222944501Smrg * begins. 178322944501Smrg * 178422944501Smrg * \return zero on success, or a negative value on failure. 1785fe517fc9Smrg * 178622944501Smrg * \internal 178722944501Smrg * This function is a wrapper for mmap(). 178822944501Smrg */ 17896260e5d5Smrgdrm_public int drmMap(int fd, drm_handle_t handle, drmSize size, 17906260e5d5Smrg drmAddressPtr address) 179122944501Smrg{ 179222944501Smrg static unsigned long pagesize_mask = 0; 179322944501Smrg 179422944501Smrg if (fd < 0) 1795fe517fc9Smrg return -EINVAL; 179622944501Smrg 179722944501Smrg if (!pagesize_mask) 1798fe517fc9Smrg pagesize_mask = getpagesize() - 1; 179922944501Smrg 180022944501Smrg size = (size + pagesize_mask) & ~pagesize_mask; 180122944501Smrg 1802a884aba1Smrg *address = drm_mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, handle); 180322944501Smrg if (*address == MAP_FAILED) 1804fe517fc9Smrg return -errno; 180522944501Smrg return 0; 180622944501Smrg} 180722944501Smrg 180822944501Smrg 180922944501Smrg/** 181022944501Smrg * Unmap mappings obtained with drmMap(). 181122944501Smrg * 181222944501Smrg * \param address address as given by drmMap(). 181322944501Smrg * \param size size in bytes. Must match the size used by drmMap(). 1814fe517fc9Smrg * 181522944501Smrg * \return zero on success, or a negative value on failure. 181622944501Smrg * 181722944501Smrg * \internal 181822944501Smrg * This function is a wrapper for munmap(). 181922944501Smrg */ 18206260e5d5Smrgdrm_public int drmUnmap(drmAddress address, drmSize size) 182122944501Smrg{ 1822a884aba1Smrg return drm_munmap(address, size); 182322944501Smrg} 182422944501Smrg 18256260e5d5Smrgdrm_public drmBufInfoPtr drmGetBufInfo(int fd) 182622944501Smrg{ 182722944501Smrg drm_buf_info_t info; 182822944501Smrg drmBufInfoPtr retval; 182922944501Smrg int i; 183022944501Smrg 1831424e9256Smrg memclear(info); 183222944501Smrg 183322944501Smrg if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info)) 1834fe517fc9Smrg return NULL; 183522944501Smrg 183622944501Smrg if (info.count) { 1837fe517fc9Smrg if (!(info.list = drmMalloc(info.count * sizeof(*info.list)))) 1838fe517fc9Smrg return NULL; 1839fe517fc9Smrg 1840fe517fc9Smrg if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info)) { 1841fe517fc9Smrg drmFree(info.list); 1842fe517fc9Smrg return NULL; 1843fe517fc9Smrg } 1844fe517fc9Smrg 1845fe517fc9Smrg retval = drmMalloc(sizeof(*retval)); 1846fe517fc9Smrg retval->count = info.count; 18474b3d3f37Smrg if (!(retval->list = drmMalloc(info.count * sizeof(*retval->list)))) { 18484b3d3f37Smrg drmFree(retval); 18494b3d3f37Smrg drmFree(info.list); 18504b3d3f37Smrg return NULL; 18514b3d3f37Smrg } 18524b3d3f37Smrg 1853fe517fc9Smrg for (i = 0; i < info.count; i++) { 1854fe517fc9Smrg retval->list[i].count = info.list[i].count; 1855fe517fc9Smrg retval->list[i].size = info.list[i].size; 1856fe517fc9Smrg retval->list[i].low_mark = info.list[i].low_mark; 1857fe517fc9Smrg retval->list[i].high_mark = info.list[i].high_mark; 1858fe517fc9Smrg } 1859fe517fc9Smrg drmFree(info.list); 1860fe517fc9Smrg return retval; 186122944501Smrg } 186222944501Smrg return NULL; 186322944501Smrg} 186422944501Smrg 186522944501Smrg/** 186622944501Smrg * Map all DMA buffers into client-virtual space. 186722944501Smrg * 186822944501Smrg * \param fd file descriptor. 186922944501Smrg * 187022944501Smrg * \return a pointer to a ::drmBufMap structure. 187122944501Smrg * 187222944501Smrg * \note The client may not use these buffers until obtaining buffer indices 187322944501Smrg * with drmDMA(). 1874fe517fc9Smrg * 187522944501Smrg * \internal 187622944501Smrg * This function calls the DRM_IOCTL_MAP_BUFS ioctl and copies the returned 187722944501Smrg * information about the buffers in a drm_buf_map structure into the 187822944501Smrg * client-visible data structures. 1879fe517fc9Smrg */ 18806260e5d5Smrgdrm_public drmBufMapPtr drmMapBufs(int fd) 188122944501Smrg{ 188222944501Smrg drm_buf_map_t bufs; 188322944501Smrg drmBufMapPtr retval; 188422944501Smrg int i; 188522944501Smrg 1886424e9256Smrg memclear(bufs); 188722944501Smrg if (drmIoctl(fd, DRM_IOCTL_MAP_BUFS, &bufs)) 1888fe517fc9Smrg return NULL; 188922944501Smrg 189022944501Smrg if (!bufs.count) 1891fe517fc9Smrg return NULL; 189222944501Smrg 1893fe517fc9Smrg if (!(bufs.list = drmMalloc(bufs.count * sizeof(*bufs.list)))) 1894fe517fc9Smrg return NULL; 189522944501Smrg 1896fe517fc9Smrg if (drmIoctl(fd, DRM_IOCTL_MAP_BUFS, &bufs)) { 1897fe517fc9Smrg drmFree(bufs.list); 1898fe517fc9Smrg return NULL; 1899fe517fc9Smrg } 190022944501Smrg 1901fe517fc9Smrg retval = drmMalloc(sizeof(*retval)); 1902fe517fc9Smrg retval->count = bufs.count; 1903fe517fc9Smrg retval->list = drmMalloc(bufs.count * sizeof(*retval->list)); 1904fe517fc9Smrg for (i = 0; i < bufs.count; i++) { 1905fe517fc9Smrg retval->list[i].idx = bufs.list[i].idx; 1906fe517fc9Smrg retval->list[i].total = bufs.list[i].total; 1907fe517fc9Smrg retval->list[i].used = 0; 1908fe517fc9Smrg retval->list[i].address = bufs.list[i].address; 1909fe517fc9Smrg } 191022944501Smrg 1911fe517fc9Smrg drmFree(bufs.list); 1912fe517fc9Smrg return retval; 191322944501Smrg} 191422944501Smrg 191522944501Smrg 191622944501Smrg/** 191722944501Smrg * Unmap buffers allocated with drmMapBufs(). 191822944501Smrg * 191922944501Smrg * \return zero on success, or negative value on failure. 192022944501Smrg * 192122944501Smrg * \internal 192222944501Smrg * Calls munmap() for every buffer stored in \p bufs and frees the 192322944501Smrg * memory allocated by drmMapBufs(). 192422944501Smrg */ 19256260e5d5Smrgdrm_public int drmUnmapBufs(drmBufMapPtr bufs) 192622944501Smrg{ 192722944501Smrg int i; 192822944501Smrg 192922944501Smrg for (i = 0; i < bufs->count; i++) { 1930fe517fc9Smrg drm_munmap(bufs->list[i].address, bufs->list[i].total); 193122944501Smrg } 193222944501Smrg 193322944501Smrg drmFree(bufs->list); 193422944501Smrg drmFree(bufs); 193522944501Smrg return 0; 193622944501Smrg} 193722944501Smrg 193822944501Smrg 1939fe517fc9Smrg#define DRM_DMA_RETRY 16 194022944501Smrg 194122944501Smrg/** 194222944501Smrg * Reserve DMA buffers. 194322944501Smrg * 194422944501Smrg * \param fd file descriptor. 1945fe517fc9Smrg * \param request 1946fe517fc9Smrg * 194722944501Smrg * \return zero on success, or a negative value on failure. 194822944501Smrg * 194922944501Smrg * \internal 195022944501Smrg * Assemble the arguments into a drm_dma structure and keeps issuing the 195122944501Smrg * DRM_IOCTL_DMA ioctl until success or until maximum number of retries. 195222944501Smrg */ 19536260e5d5Smrgdrm_public int drmDMA(int fd, drmDMAReqPtr request) 195422944501Smrg{ 195522944501Smrg drm_dma_t dma; 195622944501Smrg int ret, i = 0; 195722944501Smrg 195822944501Smrg dma.context = request->context; 195922944501Smrg dma.send_count = request->send_count; 196022944501Smrg dma.send_indices = request->send_list; 196122944501Smrg dma.send_sizes = request->send_sizes; 1962adfa0b0cSmrg dma.flags = (enum drm_dma_flags)request->flags; 196322944501Smrg dma.request_count = request->request_count; 196422944501Smrg dma.request_size = request->request_size; 196522944501Smrg dma.request_indices = request->request_list; 196622944501Smrg dma.request_sizes = request->request_sizes; 196722944501Smrg dma.granted_count = 0; 196822944501Smrg 196922944501Smrg do { 1970fe517fc9Smrg ret = ioctl( fd, DRM_IOCTL_DMA, &dma ); 197122944501Smrg } while ( ret && errno == EAGAIN && i++ < DRM_DMA_RETRY ); 197222944501Smrg 197322944501Smrg if ( ret == 0 ) { 1974fe517fc9Smrg request->granted_count = dma.granted_count; 1975fe517fc9Smrg return 0; 197622944501Smrg } else { 1977fe517fc9Smrg return -errno; 197822944501Smrg } 197922944501Smrg} 198022944501Smrg 198122944501Smrg 198222944501Smrg/** 198322944501Smrg * Obtain heavyweight hardware lock. 198422944501Smrg * 198522944501Smrg * \param fd file descriptor. 198622944501Smrg * \param context context. 1987bf6cc7dcSmrg * \param flags flags that determine the state of the hardware when the function 198822944501Smrg * returns. 1989fe517fc9Smrg * 199022944501Smrg * \return always zero. 1991fe517fc9Smrg * 199222944501Smrg * \internal 199322944501Smrg * This function translates the arguments into a drm_lock structure and issue 199422944501Smrg * the DRM_IOCTL_LOCK ioctl until the lock is successfully acquired. 199522944501Smrg */ 19966260e5d5Smrgdrm_public int drmGetLock(int fd, drm_context_t context, drmLockFlags flags) 199722944501Smrg{ 199822944501Smrg drm_lock_t lock; 199922944501Smrg 2000424e9256Smrg memclear(lock); 200122944501Smrg lock.context = context; 200222944501Smrg lock.flags = 0; 200322944501Smrg if (flags & DRM_LOCK_READY) lock.flags |= _DRM_LOCK_READY; 200422944501Smrg if (flags & DRM_LOCK_QUIESCENT) lock.flags |= _DRM_LOCK_QUIESCENT; 200522944501Smrg if (flags & DRM_LOCK_FLUSH) lock.flags |= _DRM_LOCK_FLUSH; 200622944501Smrg if (flags & DRM_LOCK_FLUSH_ALL) lock.flags |= _DRM_LOCK_FLUSH_ALL; 200722944501Smrg if (flags & DRM_HALT_ALL_QUEUES) lock.flags |= _DRM_HALT_ALL_QUEUES; 200822944501Smrg if (flags & DRM_HALT_CUR_QUEUES) lock.flags |= _DRM_HALT_CUR_QUEUES; 200922944501Smrg 201022944501Smrg while (drmIoctl(fd, DRM_IOCTL_LOCK, &lock)) 2011fe517fc9Smrg ; 201222944501Smrg return 0; 201322944501Smrg} 201422944501Smrg 201522944501Smrg/** 201622944501Smrg * Release the hardware lock. 201722944501Smrg * 201822944501Smrg * \param fd file descriptor. 201922944501Smrg * \param context context. 2020fe517fc9Smrg * 202122944501Smrg * \return zero on success, or a negative value on failure. 2022fe517fc9Smrg * 202322944501Smrg * \internal 202422944501Smrg * This function is a wrapper around the DRM_IOCTL_UNLOCK ioctl, passing the 202522944501Smrg * argument in a drm_lock structure. 202622944501Smrg */ 20276260e5d5Smrgdrm_public int drmUnlock(int fd, drm_context_t context) 202822944501Smrg{ 202922944501Smrg drm_lock_t lock; 203022944501Smrg 2031424e9256Smrg memclear(lock); 203222944501Smrg lock.context = context; 203322944501Smrg return drmIoctl(fd, DRM_IOCTL_UNLOCK, &lock); 203422944501Smrg} 203522944501Smrg 20366260e5d5Smrgdrm_public drm_context_t *drmGetReservedContextList(int fd, int *count) 203722944501Smrg{ 203822944501Smrg drm_ctx_res_t res; 203922944501Smrg drm_ctx_t *list; 204022944501Smrg drm_context_t * retval; 204122944501Smrg int i; 204222944501Smrg 2043424e9256Smrg memclear(res); 204422944501Smrg if (drmIoctl(fd, DRM_IOCTL_RES_CTX, &res)) 2045fe517fc9Smrg return NULL; 204622944501Smrg 204722944501Smrg if (!res.count) 2048fe517fc9Smrg return NULL; 204922944501Smrg 205022944501Smrg if (!(list = drmMalloc(res.count * sizeof(*list)))) 2051fe517fc9Smrg return NULL; 20520655efefSmrg if (!(retval = drmMalloc(res.count * sizeof(*retval)))) 20530655efefSmrg goto err_free_list; 205422944501Smrg 205522944501Smrg res.contexts = list; 205622944501Smrg if (drmIoctl(fd, DRM_IOCTL_RES_CTX, &res)) 20570655efefSmrg goto err_free_context; 205822944501Smrg 205922944501Smrg for (i = 0; i < res.count; i++) 2060fe517fc9Smrg retval[i] = list[i].handle; 206122944501Smrg drmFree(list); 206222944501Smrg 206322944501Smrg *count = res.count; 206422944501Smrg return retval; 20650655efefSmrg 20660655efefSmrgerr_free_list: 20670655efefSmrg drmFree(list); 20680655efefSmrgerr_free_context: 20690655efefSmrg drmFree(retval); 20700655efefSmrg return NULL; 207122944501Smrg} 207222944501Smrg 20736260e5d5Smrgdrm_public void drmFreeReservedContextList(drm_context_t *pt) 207422944501Smrg{ 207522944501Smrg drmFree(pt); 207622944501Smrg} 207722944501Smrg 207822944501Smrg/** 207922944501Smrg * Create context. 208022944501Smrg * 208122944501Smrg * Used by the X server during GLXContext initialization. This causes 208222944501Smrg * per-context kernel-level resources to be allocated. 208322944501Smrg * 208422944501Smrg * \param fd file descriptor. 208522944501Smrg * \param handle is set on success. To be used by the client when requesting DMA 208622944501Smrg * dispatch with drmDMA(). 2087fe517fc9Smrg * 208822944501Smrg * \return zero on success, or a negative value on failure. 2089fe517fc9Smrg * 209022944501Smrg * \note May only be called by root. 2091fe517fc9Smrg * 209222944501Smrg * \internal 209322944501Smrg * This function is a wrapper around the DRM_IOCTL_ADD_CTX ioctl, passing the 209422944501Smrg * argument in a drm_ctx structure. 209522944501Smrg */ 20966260e5d5Smrgdrm_public int drmCreateContext(int fd, drm_context_t *handle) 209722944501Smrg{ 209822944501Smrg drm_ctx_t ctx; 209922944501Smrg 2100424e9256Smrg memclear(ctx); 210122944501Smrg if (drmIoctl(fd, DRM_IOCTL_ADD_CTX, &ctx)) 2102fe517fc9Smrg return -errno; 210322944501Smrg *handle = ctx.handle; 210422944501Smrg return 0; 210522944501Smrg} 210622944501Smrg 21076260e5d5Smrgdrm_public int drmSwitchToContext(int fd, drm_context_t context) 210822944501Smrg{ 210922944501Smrg drm_ctx_t ctx; 211022944501Smrg 2111424e9256Smrg memclear(ctx); 211222944501Smrg ctx.handle = context; 211322944501Smrg if (drmIoctl(fd, DRM_IOCTL_SWITCH_CTX, &ctx)) 2114fe517fc9Smrg return -errno; 211522944501Smrg return 0; 211622944501Smrg} 211722944501Smrg 21186260e5d5Smrgdrm_public int drmSetContextFlags(int fd, drm_context_t context, 21196260e5d5Smrg drm_context_tFlags flags) 212022944501Smrg{ 212122944501Smrg drm_ctx_t ctx; 212222944501Smrg 212322944501Smrg /* 212422944501Smrg * Context preserving means that no context switches are done between DMA 212522944501Smrg * buffers from one context and the next. This is suitable for use in the 212622944501Smrg * X server (which promises to maintain hardware context), or in the 212722944501Smrg * client-side library when buffers are swapped on behalf of two threads. 212822944501Smrg */ 2129424e9256Smrg memclear(ctx); 213022944501Smrg ctx.handle = context; 213122944501Smrg if (flags & DRM_CONTEXT_PRESERVED) 2132fe517fc9Smrg ctx.flags |= _DRM_CONTEXT_PRESERVED; 213322944501Smrg if (flags & DRM_CONTEXT_2DONLY) 2134fe517fc9Smrg ctx.flags |= _DRM_CONTEXT_2DONLY; 213522944501Smrg if (drmIoctl(fd, DRM_IOCTL_MOD_CTX, &ctx)) 2136fe517fc9Smrg return -errno; 213722944501Smrg return 0; 213822944501Smrg} 213922944501Smrg 21406260e5d5Smrgdrm_public int drmGetContextFlags(int fd, drm_context_t context, 21416260e5d5Smrg drm_context_tFlagsPtr flags) 214222944501Smrg{ 214322944501Smrg drm_ctx_t ctx; 214422944501Smrg 2145424e9256Smrg memclear(ctx); 214622944501Smrg ctx.handle = context; 214722944501Smrg if (drmIoctl(fd, DRM_IOCTL_GET_CTX, &ctx)) 2148fe517fc9Smrg return -errno; 214922944501Smrg *flags = 0; 215022944501Smrg if (ctx.flags & _DRM_CONTEXT_PRESERVED) 2151fe517fc9Smrg *flags |= DRM_CONTEXT_PRESERVED; 215222944501Smrg if (ctx.flags & _DRM_CONTEXT_2DONLY) 2153fe517fc9Smrg *flags |= DRM_CONTEXT_2DONLY; 215422944501Smrg return 0; 215522944501Smrg} 215622944501Smrg 215722944501Smrg/** 215822944501Smrg * Destroy context. 215922944501Smrg * 216022944501Smrg * Free any kernel-level resources allocated with drmCreateContext() associated 216122944501Smrg * with the context. 2162fe517fc9Smrg * 216322944501Smrg * \param fd file descriptor. 216422944501Smrg * \param handle handle given by drmCreateContext(). 2165fe517fc9Smrg * 216622944501Smrg * \return zero on success, or a negative value on failure. 2167fe517fc9Smrg * 216822944501Smrg * \note May only be called by root. 2169fe517fc9Smrg * 217022944501Smrg * \internal 217122944501Smrg * This function is a wrapper around the DRM_IOCTL_RM_CTX ioctl, passing the 217222944501Smrg * argument in a drm_ctx structure. 217322944501Smrg */ 21746260e5d5Smrgdrm_public int drmDestroyContext(int fd, drm_context_t handle) 217522944501Smrg{ 217622944501Smrg drm_ctx_t ctx; 2177424e9256Smrg 2178424e9256Smrg memclear(ctx); 217922944501Smrg ctx.handle = handle; 218022944501Smrg if (drmIoctl(fd, DRM_IOCTL_RM_CTX, &ctx)) 2181fe517fc9Smrg return -errno; 218222944501Smrg return 0; 218322944501Smrg} 218422944501Smrg 21856260e5d5Smrgdrm_public int drmCreateDrawable(int fd, drm_drawable_t *handle) 218622944501Smrg{ 218722944501Smrg drm_draw_t draw; 2188424e9256Smrg 2189424e9256Smrg memclear(draw); 219022944501Smrg if (drmIoctl(fd, DRM_IOCTL_ADD_DRAW, &draw)) 2191fe517fc9Smrg return -errno; 219222944501Smrg *handle = draw.handle; 219322944501Smrg return 0; 219422944501Smrg} 219522944501Smrg 21966260e5d5Smrgdrm_public int drmDestroyDrawable(int fd, drm_drawable_t handle) 219722944501Smrg{ 219822944501Smrg drm_draw_t draw; 2199424e9256Smrg 2200424e9256Smrg memclear(draw); 220122944501Smrg draw.handle = handle; 220222944501Smrg if (drmIoctl(fd, DRM_IOCTL_RM_DRAW, &draw)) 2203fe517fc9Smrg return -errno; 220422944501Smrg return 0; 220522944501Smrg} 220622944501Smrg 22076260e5d5Smrgdrm_public int drmUpdateDrawableInfo(int fd, drm_drawable_t handle, 22086260e5d5Smrg drm_drawable_info_type_t type, 22096260e5d5Smrg unsigned int num, void *data) 221022944501Smrg{ 221122944501Smrg drm_update_draw_t update; 221222944501Smrg 2213424e9256Smrg memclear(update); 221422944501Smrg update.handle = handle; 221522944501Smrg update.type = type; 221622944501Smrg update.num = num; 221722944501Smrg update.data = (unsigned long long)(unsigned long)data; 221822944501Smrg 221922944501Smrg if (drmIoctl(fd, DRM_IOCTL_UPDATE_DRAW, &update)) 2220fe517fc9Smrg return -errno; 222122944501Smrg 222222944501Smrg return 0; 222322944501Smrg} 222422944501Smrg 22256260e5d5Smrgdrm_public int drmCrtcGetSequence(int fd, uint32_t crtcId, uint64_t *sequence, 22266260e5d5Smrg uint64_t *ns) 22272b90624aSmrg{ 22282b90624aSmrg struct drm_crtc_get_sequence get_seq; 22292b90624aSmrg int ret; 22302b90624aSmrg 22312b90624aSmrg memclear(get_seq); 22322b90624aSmrg get_seq.crtc_id = crtcId; 22332b90624aSmrg ret = drmIoctl(fd, DRM_IOCTL_CRTC_GET_SEQUENCE, &get_seq); 22342b90624aSmrg if (ret) 22352b90624aSmrg return ret; 22362b90624aSmrg 22372b90624aSmrg if (sequence) 22382b90624aSmrg *sequence = get_seq.sequence; 22392b90624aSmrg if (ns) 22402b90624aSmrg *ns = get_seq.sequence_ns; 22412b90624aSmrg return 0; 22422b90624aSmrg} 22432b90624aSmrg 22446260e5d5Smrgdrm_public int drmCrtcQueueSequence(int fd, uint32_t crtcId, uint32_t flags, 22456260e5d5Smrg uint64_t sequence, 22466260e5d5Smrg uint64_t *sequence_queued, 22476260e5d5Smrg uint64_t user_data) 22482b90624aSmrg{ 22492b90624aSmrg struct drm_crtc_queue_sequence queue_seq; 22502b90624aSmrg int ret; 22512b90624aSmrg 22522b90624aSmrg memclear(queue_seq); 22532b90624aSmrg queue_seq.crtc_id = crtcId; 22542b90624aSmrg queue_seq.flags = flags; 22552b90624aSmrg queue_seq.sequence = sequence; 22562b90624aSmrg queue_seq.user_data = user_data; 22572b90624aSmrg 22582b90624aSmrg ret = drmIoctl(fd, DRM_IOCTL_CRTC_QUEUE_SEQUENCE, &queue_seq); 22592b90624aSmrg if (ret == 0 && sequence_queued) 22602b90624aSmrg *sequence_queued = queue_seq.sequence; 22612b90624aSmrg 22622b90624aSmrg return ret; 22632b90624aSmrg} 22642b90624aSmrg 226522944501Smrg/** 226622944501Smrg * Acquire the AGP device. 226722944501Smrg * 226822944501Smrg * Must be called before any of the other AGP related calls. 226922944501Smrg * 227022944501Smrg * \param fd file descriptor. 2271fe517fc9Smrg * 227222944501Smrg * \return zero on success, or a negative value on failure. 2273fe517fc9Smrg * 227422944501Smrg * \internal 227522944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_ACQUIRE ioctl. 227622944501Smrg */ 22776260e5d5Smrgdrm_public int drmAgpAcquire(int fd) 227822944501Smrg{ 227922944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_ACQUIRE, NULL)) 2280fe517fc9Smrg return -errno; 228122944501Smrg return 0; 228222944501Smrg} 228322944501Smrg 228422944501Smrg 228522944501Smrg/** 228622944501Smrg * Release the AGP device. 228722944501Smrg * 228822944501Smrg * \param fd file descriptor. 2289fe517fc9Smrg * 229022944501Smrg * \return zero on success, or a negative value on failure. 2291fe517fc9Smrg * 229222944501Smrg * \internal 229322944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_RELEASE ioctl. 229422944501Smrg */ 22956260e5d5Smrgdrm_public int drmAgpRelease(int fd) 229622944501Smrg{ 229722944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_RELEASE, NULL)) 2298fe517fc9Smrg return -errno; 229922944501Smrg return 0; 230022944501Smrg} 230122944501Smrg 230222944501Smrg 230322944501Smrg/** 230422944501Smrg * Set the AGP mode. 230522944501Smrg * 230622944501Smrg * \param fd file descriptor. 230722944501Smrg * \param mode AGP mode. 2308fe517fc9Smrg * 230922944501Smrg * \return zero on success, or a negative value on failure. 2310fe517fc9Smrg * 231122944501Smrg * \internal 231222944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_ENABLE ioctl, passing the 231322944501Smrg * argument in a drm_agp_mode structure. 231422944501Smrg */ 23156260e5d5Smrgdrm_public int drmAgpEnable(int fd, unsigned long mode) 231622944501Smrg{ 231722944501Smrg drm_agp_mode_t m; 231822944501Smrg 2319424e9256Smrg memclear(m); 232022944501Smrg m.mode = mode; 232122944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_ENABLE, &m)) 2322fe517fc9Smrg return -errno; 232322944501Smrg return 0; 232422944501Smrg} 232522944501Smrg 232622944501Smrg 232722944501Smrg/** 232822944501Smrg * Allocate a chunk of AGP memory. 232922944501Smrg * 233022944501Smrg * \param fd file descriptor. 233122944501Smrg * \param size requested memory size in bytes. Will be rounded to page boundary. 233222944501Smrg * \param type type of memory to allocate. 233322944501Smrg * \param address if not zero, will be set to the physical address of the 233422944501Smrg * allocated memory. 233522944501Smrg * \param handle on success will be set to a handle of the allocated memory. 2336fe517fc9Smrg * 233722944501Smrg * \return zero on success, or a negative value on failure. 2338fe517fc9Smrg * 233922944501Smrg * \internal 234022944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_ALLOC ioctl, passing the 234122944501Smrg * arguments in a drm_agp_buffer structure. 234222944501Smrg */ 23436260e5d5Smrgdrm_public int drmAgpAlloc(int fd, unsigned long size, unsigned long type, 23446260e5d5Smrg unsigned long *address, drm_handle_t *handle) 234522944501Smrg{ 234622944501Smrg drm_agp_buffer_t b; 234722944501Smrg 2348424e9256Smrg memclear(b); 234922944501Smrg *handle = DRM_AGP_NO_HANDLE; 235022944501Smrg b.size = size; 235122944501Smrg b.type = type; 235222944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_ALLOC, &b)) 2353fe517fc9Smrg return -errno; 235422944501Smrg if (address != 0UL) 2355fe517fc9Smrg *address = b.physical; 235622944501Smrg *handle = b.handle; 235722944501Smrg return 0; 235822944501Smrg} 235922944501Smrg 236022944501Smrg 236122944501Smrg/** 236222944501Smrg * Free a chunk of AGP memory. 236322944501Smrg * 236422944501Smrg * \param fd file descriptor. 236522944501Smrg * \param handle handle to the allocated memory, as given by drmAgpAllocate(). 2366fe517fc9Smrg * 236722944501Smrg * \return zero on success, or a negative value on failure. 2368fe517fc9Smrg * 236922944501Smrg * \internal 237022944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_FREE ioctl, passing the 237122944501Smrg * argument in a drm_agp_buffer structure. 237222944501Smrg */ 23736260e5d5Smrgdrm_public int drmAgpFree(int fd, drm_handle_t handle) 237422944501Smrg{ 237522944501Smrg drm_agp_buffer_t b; 237622944501Smrg 2377424e9256Smrg memclear(b); 237822944501Smrg b.handle = handle; 237922944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_FREE, &b)) 2380fe517fc9Smrg return -errno; 238122944501Smrg return 0; 238222944501Smrg} 238322944501Smrg 238422944501Smrg 238522944501Smrg/** 238622944501Smrg * Bind a chunk of AGP memory. 238722944501Smrg * 238822944501Smrg * \param fd file descriptor. 238922944501Smrg * \param handle handle to the allocated memory, as given by drmAgpAllocate(). 239022944501Smrg * \param offset offset in bytes. It will round to page boundary. 2391fe517fc9Smrg * 239222944501Smrg * \return zero on success, or a negative value on failure. 2393fe517fc9Smrg * 239422944501Smrg * \internal 239522944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_BIND ioctl, passing the 239622944501Smrg * argument in a drm_agp_binding structure. 239722944501Smrg */ 23986260e5d5Smrgdrm_public int drmAgpBind(int fd, drm_handle_t handle, unsigned long offset) 239922944501Smrg{ 240022944501Smrg drm_agp_binding_t b; 240122944501Smrg 2402424e9256Smrg memclear(b); 240322944501Smrg b.handle = handle; 240422944501Smrg b.offset = offset; 240522944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_BIND, &b)) 2406fe517fc9Smrg return -errno; 240722944501Smrg return 0; 240822944501Smrg} 240922944501Smrg 241022944501Smrg 241122944501Smrg/** 241222944501Smrg * Unbind a chunk of AGP memory. 241322944501Smrg * 241422944501Smrg * \param fd file descriptor. 241522944501Smrg * \param handle handle to the allocated memory, as given by drmAgpAllocate(). 2416fe517fc9Smrg * 241722944501Smrg * \return zero on success, or a negative value on failure. 2418fe517fc9Smrg * 241922944501Smrg * \internal 242022944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_UNBIND ioctl, passing 242122944501Smrg * the argument in a drm_agp_binding structure. 242222944501Smrg */ 24236260e5d5Smrgdrm_public int drmAgpUnbind(int fd, drm_handle_t handle) 242422944501Smrg{ 242522944501Smrg drm_agp_binding_t b; 242622944501Smrg 2427424e9256Smrg memclear(b); 242822944501Smrg b.handle = handle; 242922944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_UNBIND, &b)) 2430fe517fc9Smrg return -errno; 243122944501Smrg return 0; 243222944501Smrg} 243322944501Smrg 243422944501Smrg 243522944501Smrg/** 243622944501Smrg * Get AGP driver major version number. 243722944501Smrg * 243822944501Smrg * \param fd file descriptor. 2439fe517fc9Smrg * 244022944501Smrg * \return major version number on success, or a negative value on failure.. 2441fe517fc9Smrg * 244222944501Smrg * \internal 244322944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the 244422944501Smrg * necessary information in a drm_agp_info structure. 244522944501Smrg */ 24466260e5d5Smrgdrm_public int drmAgpVersionMajor(int fd) 244722944501Smrg{ 244822944501Smrg drm_agp_info_t i; 244922944501Smrg 2450424e9256Smrg memclear(i); 2451424e9256Smrg 245222944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i)) 2453fe517fc9Smrg return -errno; 245422944501Smrg return i.agp_version_major; 245522944501Smrg} 245622944501Smrg 245722944501Smrg 245822944501Smrg/** 245922944501Smrg * Get AGP driver minor version number. 246022944501Smrg * 246122944501Smrg * \param fd file descriptor. 2462fe517fc9Smrg * 246322944501Smrg * \return minor version number on success, or a negative value on failure. 2464fe517fc9Smrg * 246522944501Smrg * \internal 246622944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the 246722944501Smrg * necessary information in a drm_agp_info structure. 246822944501Smrg */ 24696260e5d5Smrgdrm_public int drmAgpVersionMinor(int fd) 247022944501Smrg{ 247122944501Smrg drm_agp_info_t i; 247222944501Smrg 2473424e9256Smrg memclear(i); 2474424e9256Smrg 247522944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i)) 2476fe517fc9Smrg return -errno; 247722944501Smrg return i.agp_version_minor; 247822944501Smrg} 247922944501Smrg 248022944501Smrg 248122944501Smrg/** 248222944501Smrg * Get AGP mode. 248322944501Smrg * 248422944501Smrg * \param fd file descriptor. 2485fe517fc9Smrg * 248622944501Smrg * \return mode on success, or zero on failure. 2487fe517fc9Smrg * 248822944501Smrg * \internal 248922944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the 249022944501Smrg * necessary information in a drm_agp_info structure. 249122944501Smrg */ 24926260e5d5Smrgdrm_public unsigned long drmAgpGetMode(int fd) 249322944501Smrg{ 249422944501Smrg drm_agp_info_t i; 249522944501Smrg 2496424e9256Smrg memclear(i); 2497424e9256Smrg 249822944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i)) 2499fe517fc9Smrg return 0; 250022944501Smrg return i.mode; 250122944501Smrg} 250222944501Smrg 250322944501Smrg 250422944501Smrg/** 250522944501Smrg * Get AGP aperture base. 250622944501Smrg * 250722944501Smrg * \param fd file descriptor. 2508fe517fc9Smrg * 250922944501Smrg * \return aperture base on success, zero on failure. 2510fe517fc9Smrg * 251122944501Smrg * \internal 251222944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the 251322944501Smrg * necessary information in a drm_agp_info structure. 251422944501Smrg */ 25156260e5d5Smrgdrm_public unsigned long drmAgpBase(int fd) 251622944501Smrg{ 251722944501Smrg drm_agp_info_t i; 251822944501Smrg 2519424e9256Smrg memclear(i); 2520424e9256Smrg 252122944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i)) 2522fe517fc9Smrg return 0; 252322944501Smrg return i.aperture_base; 252422944501Smrg} 252522944501Smrg 252622944501Smrg 252722944501Smrg/** 252822944501Smrg * Get AGP aperture size. 252922944501Smrg * 253022944501Smrg * \param fd file descriptor. 2531fe517fc9Smrg * 253222944501Smrg * \return aperture size on success, zero on failure. 2533fe517fc9Smrg * 253422944501Smrg * \internal 253522944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the 253622944501Smrg * necessary information in a drm_agp_info structure. 253722944501Smrg */ 25386260e5d5Smrgdrm_public unsigned long drmAgpSize(int fd) 253922944501Smrg{ 254022944501Smrg drm_agp_info_t i; 254122944501Smrg 2542424e9256Smrg memclear(i); 2543424e9256Smrg 254422944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i)) 2545fe517fc9Smrg return 0; 254622944501Smrg return i.aperture_size; 254722944501Smrg} 254822944501Smrg 254922944501Smrg 255022944501Smrg/** 255122944501Smrg * Get used AGP memory. 255222944501Smrg * 255322944501Smrg * \param fd file descriptor. 2554fe517fc9Smrg * 255522944501Smrg * \return memory used on success, or zero on failure. 2556fe517fc9Smrg * 255722944501Smrg * \internal 255822944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the 255922944501Smrg * necessary information in a drm_agp_info structure. 256022944501Smrg */ 25616260e5d5Smrgdrm_public unsigned long drmAgpMemoryUsed(int fd) 256222944501Smrg{ 256322944501Smrg drm_agp_info_t i; 256422944501Smrg 2565424e9256Smrg memclear(i); 2566424e9256Smrg 256722944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i)) 2568fe517fc9Smrg return 0; 256922944501Smrg return i.memory_used; 257022944501Smrg} 257122944501Smrg 257222944501Smrg 257322944501Smrg/** 257422944501Smrg * Get available AGP memory. 257522944501Smrg * 257622944501Smrg * \param fd file descriptor. 2577fe517fc9Smrg * 257822944501Smrg * \return memory available on success, or zero on failure. 2579fe517fc9Smrg * 258022944501Smrg * \internal 258122944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the 258222944501Smrg * necessary information in a drm_agp_info structure. 258322944501Smrg */ 25846260e5d5Smrgdrm_public unsigned long drmAgpMemoryAvail(int fd) 258522944501Smrg{ 258622944501Smrg drm_agp_info_t i; 258722944501Smrg 2588424e9256Smrg memclear(i); 2589424e9256Smrg 259022944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i)) 2591fe517fc9Smrg return 0; 259222944501Smrg return i.memory_allowed; 259322944501Smrg} 259422944501Smrg 259522944501Smrg 259622944501Smrg/** 259722944501Smrg * Get hardware vendor ID. 259822944501Smrg * 259922944501Smrg * \param fd file descriptor. 2600fe517fc9Smrg * 260122944501Smrg * \return vendor ID on success, or zero on failure. 2602fe517fc9Smrg * 260322944501Smrg * \internal 260422944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the 260522944501Smrg * necessary information in a drm_agp_info structure. 260622944501Smrg */ 26076260e5d5Smrgdrm_public unsigned int drmAgpVendorId(int fd) 260822944501Smrg{ 260922944501Smrg drm_agp_info_t i; 261022944501Smrg 2611424e9256Smrg memclear(i); 2612424e9256Smrg 261322944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i)) 2614fe517fc9Smrg return 0; 261522944501Smrg return i.id_vendor; 261622944501Smrg} 261722944501Smrg 261822944501Smrg 261922944501Smrg/** 262022944501Smrg * Get hardware device ID. 262122944501Smrg * 262222944501Smrg * \param fd file descriptor. 2623fe517fc9Smrg * 262422944501Smrg * \return zero on success, or zero on failure. 2625fe517fc9Smrg * 262622944501Smrg * \internal 262722944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the 262822944501Smrg * necessary information in a drm_agp_info structure. 262922944501Smrg */ 26306260e5d5Smrgdrm_public unsigned int drmAgpDeviceId(int fd) 263122944501Smrg{ 263222944501Smrg drm_agp_info_t i; 263322944501Smrg 2634424e9256Smrg memclear(i); 2635424e9256Smrg 263622944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i)) 2637fe517fc9Smrg return 0; 263822944501Smrg return i.id_device; 263922944501Smrg} 264022944501Smrg 26416260e5d5Smrgdrm_public int drmScatterGatherAlloc(int fd, unsigned long size, 26426260e5d5Smrg drm_handle_t *handle) 264322944501Smrg{ 264422944501Smrg drm_scatter_gather_t sg; 264522944501Smrg 2646424e9256Smrg memclear(sg); 2647424e9256Smrg 264822944501Smrg *handle = 0; 264922944501Smrg sg.size = size; 265022944501Smrg if (drmIoctl(fd, DRM_IOCTL_SG_ALLOC, &sg)) 2651fe517fc9Smrg return -errno; 265222944501Smrg *handle = sg.handle; 265322944501Smrg return 0; 265422944501Smrg} 265522944501Smrg 26566260e5d5Smrgdrm_public int drmScatterGatherFree(int fd, drm_handle_t handle) 265722944501Smrg{ 265822944501Smrg drm_scatter_gather_t sg; 265922944501Smrg 2660424e9256Smrg memclear(sg); 266122944501Smrg sg.handle = handle; 266222944501Smrg if (drmIoctl(fd, DRM_IOCTL_SG_FREE, &sg)) 2663fe517fc9Smrg return -errno; 266422944501Smrg return 0; 266522944501Smrg} 266622944501Smrg 266722944501Smrg/** 266822944501Smrg * Wait for VBLANK. 266922944501Smrg * 267022944501Smrg * \param fd file descriptor. 267122944501Smrg * \param vbl pointer to a drmVBlank structure. 2672fe517fc9Smrg * 267322944501Smrg * \return zero on success, or a negative value on failure. 2674fe517fc9Smrg * 267522944501Smrg * \internal 267622944501Smrg * This function is a wrapper around the DRM_IOCTL_WAIT_VBLANK ioctl. 267722944501Smrg */ 26786260e5d5Smrgdrm_public int drmWaitVBlank(int fd, drmVBlankPtr vbl) 267922944501Smrg{ 268022944501Smrg struct timespec timeout, cur; 268122944501Smrg int ret; 268222944501Smrg 268322944501Smrg ret = clock_gettime(CLOCK_MONOTONIC, &timeout); 268422944501Smrg if (ret < 0) { 2685fe517fc9Smrg fprintf(stderr, "clock_gettime failed: %s\n", strerror(errno)); 2686fe517fc9Smrg goto out; 268722944501Smrg } 268822944501Smrg timeout.tv_sec++; 268922944501Smrg 269022944501Smrg do { 269122944501Smrg ret = ioctl(fd, DRM_IOCTL_WAIT_VBLANK, vbl); 269222944501Smrg vbl->request.type &= ~DRM_VBLANK_RELATIVE; 269322944501Smrg if (ret && errno == EINTR) { 2694fe517fc9Smrg clock_gettime(CLOCK_MONOTONIC, &cur); 2695fe517fc9Smrg /* Timeout after 1s */ 2696fe517fc9Smrg if (cur.tv_sec > timeout.tv_sec + 1 || 2697fe517fc9Smrg (cur.tv_sec == timeout.tv_sec && cur.tv_nsec >= 2698fe517fc9Smrg timeout.tv_nsec)) { 2699fe517fc9Smrg errno = EBUSY; 2700fe517fc9Smrg ret = -1; 2701fe517fc9Smrg break; 2702fe517fc9Smrg } 270322944501Smrg } 270422944501Smrg } while (ret && errno == EINTR); 270522944501Smrg 270622944501Smrgout: 270722944501Smrg return ret; 270822944501Smrg} 270922944501Smrg 27106260e5d5Smrgdrm_public int drmError(int err, const char *label) 271122944501Smrg{ 271222944501Smrg switch (err) { 271322944501Smrg case DRM_ERR_NO_DEVICE: 2714fe517fc9Smrg fprintf(stderr, "%s: no device\n", label); 2715fe517fc9Smrg break; 271622944501Smrg case DRM_ERR_NO_ACCESS: 2717fe517fc9Smrg fprintf(stderr, "%s: no access\n", label); 2718fe517fc9Smrg break; 271922944501Smrg case DRM_ERR_NOT_ROOT: 2720fe517fc9Smrg fprintf(stderr, "%s: not root\n", label); 2721fe517fc9Smrg break; 272222944501Smrg case DRM_ERR_INVALID: 2723fe517fc9Smrg fprintf(stderr, "%s: invalid args\n", label); 2724fe517fc9Smrg break; 272522944501Smrg default: 2726fe517fc9Smrg if (err < 0) 2727fe517fc9Smrg err = -err; 2728fe517fc9Smrg fprintf( stderr, "%s: error %d (%s)\n", label, err, strerror(err) ); 2729fe517fc9Smrg break; 273022944501Smrg } 273122944501Smrg 273222944501Smrg return 1; 273322944501Smrg} 273422944501Smrg 273522944501Smrg/** 273622944501Smrg * Install IRQ handler. 273722944501Smrg * 273822944501Smrg * \param fd file descriptor. 273922944501Smrg * \param irq IRQ number. 2740fe517fc9Smrg * 274122944501Smrg * \return zero on success, or a negative value on failure. 2742fe517fc9Smrg * 274322944501Smrg * \internal 274422944501Smrg * This function is a wrapper around the DRM_IOCTL_CONTROL ioctl, passing the 274522944501Smrg * argument in a drm_control structure. 274622944501Smrg */ 27476260e5d5Smrgdrm_public int drmCtlInstHandler(int fd, int irq) 274822944501Smrg{ 274922944501Smrg drm_control_t ctl; 275022944501Smrg 2751424e9256Smrg memclear(ctl); 275222944501Smrg ctl.func = DRM_INST_HANDLER; 275322944501Smrg ctl.irq = irq; 275422944501Smrg if (drmIoctl(fd, DRM_IOCTL_CONTROL, &ctl)) 2755fe517fc9Smrg return -errno; 275622944501Smrg return 0; 275722944501Smrg} 275822944501Smrg 275922944501Smrg 276022944501Smrg/** 276122944501Smrg * Uninstall IRQ handler. 276222944501Smrg * 276322944501Smrg * \param fd file descriptor. 2764fe517fc9Smrg * 276522944501Smrg * \return zero on success, or a negative value on failure. 2766fe517fc9Smrg * 276722944501Smrg * \internal 276822944501Smrg * This function is a wrapper around the DRM_IOCTL_CONTROL ioctl, passing the 276922944501Smrg * argument in a drm_control structure. 277022944501Smrg */ 27716260e5d5Smrgdrm_public int drmCtlUninstHandler(int fd) 277222944501Smrg{ 277322944501Smrg drm_control_t ctl; 277422944501Smrg 2775424e9256Smrg memclear(ctl); 277622944501Smrg ctl.func = DRM_UNINST_HANDLER; 277722944501Smrg ctl.irq = 0; 277822944501Smrg if (drmIoctl(fd, DRM_IOCTL_CONTROL, &ctl)) 2779fe517fc9Smrg return -errno; 278022944501Smrg return 0; 278122944501Smrg} 278222944501Smrg 27836260e5d5Smrgdrm_public int drmFinish(int fd, int context, drmLockFlags flags) 278422944501Smrg{ 278522944501Smrg drm_lock_t lock; 278622944501Smrg 2787424e9256Smrg memclear(lock); 278822944501Smrg lock.context = context; 278922944501Smrg if (flags & DRM_LOCK_READY) lock.flags |= _DRM_LOCK_READY; 279022944501Smrg if (flags & DRM_LOCK_QUIESCENT) lock.flags |= _DRM_LOCK_QUIESCENT; 279122944501Smrg if (flags & DRM_LOCK_FLUSH) lock.flags |= _DRM_LOCK_FLUSH; 279222944501Smrg if (flags & DRM_LOCK_FLUSH_ALL) lock.flags |= _DRM_LOCK_FLUSH_ALL; 279322944501Smrg if (flags & DRM_HALT_ALL_QUEUES) lock.flags |= _DRM_HALT_ALL_QUEUES; 279422944501Smrg if (flags & DRM_HALT_CUR_QUEUES) lock.flags |= _DRM_HALT_CUR_QUEUES; 279522944501Smrg if (drmIoctl(fd, DRM_IOCTL_FINISH, &lock)) 2796fe517fc9Smrg return -errno; 279722944501Smrg return 0; 279822944501Smrg} 279922944501Smrg 280022944501Smrg/** 280122944501Smrg * Get IRQ from bus ID. 280222944501Smrg * 280322944501Smrg * \param fd file descriptor. 280422944501Smrg * \param busnum bus number. 280522944501Smrg * \param devnum device number. 280622944501Smrg * \param funcnum function number. 2807fe517fc9Smrg * 280822944501Smrg * \return IRQ number on success, or a negative value on failure. 2809fe517fc9Smrg * 281022944501Smrg * \internal 281122944501Smrg * This function is a wrapper around the DRM_IOCTL_IRQ_BUSID ioctl, passing the 281222944501Smrg * arguments in a drm_irq_busid structure. 281322944501Smrg */ 28146260e5d5Smrgdrm_public int drmGetInterruptFromBusID(int fd, int busnum, int devnum, 28156260e5d5Smrg int funcnum) 281622944501Smrg{ 281722944501Smrg drm_irq_busid_t p; 281822944501Smrg 2819424e9256Smrg memclear(p); 282022944501Smrg p.busnum = busnum; 282122944501Smrg p.devnum = devnum; 282222944501Smrg p.funcnum = funcnum; 282322944501Smrg if (drmIoctl(fd, DRM_IOCTL_IRQ_BUSID, &p)) 2824fe517fc9Smrg return -errno; 282522944501Smrg return p.irq; 282622944501Smrg} 282722944501Smrg 28286260e5d5Smrgdrm_public int drmAddContextTag(int fd, drm_context_t context, void *tag) 282922944501Smrg{ 283022944501Smrg drmHashEntry *entry = drmGetEntry(fd); 283122944501Smrg 283222944501Smrg if (drmHashInsert(entry->tagTable, context, tag)) { 2833fe517fc9Smrg drmHashDelete(entry->tagTable, context); 2834fe517fc9Smrg drmHashInsert(entry->tagTable, context, tag); 283522944501Smrg } 283622944501Smrg return 0; 283722944501Smrg} 283822944501Smrg 28396260e5d5Smrgdrm_public int drmDelContextTag(int fd, drm_context_t context) 284022944501Smrg{ 284122944501Smrg drmHashEntry *entry = drmGetEntry(fd); 284222944501Smrg 284322944501Smrg return drmHashDelete(entry->tagTable, context); 284422944501Smrg} 284522944501Smrg 28466260e5d5Smrgdrm_public void *drmGetContextTag(int fd, drm_context_t context) 284722944501Smrg{ 284822944501Smrg drmHashEntry *entry = drmGetEntry(fd); 284922944501Smrg void *value; 285022944501Smrg 285122944501Smrg if (drmHashLookup(entry->tagTable, context, &value)) 2852fe517fc9Smrg return NULL; 285322944501Smrg 285422944501Smrg return value; 285522944501Smrg} 285622944501Smrg 28576260e5d5Smrgdrm_public int drmAddContextPrivateMapping(int fd, drm_context_t ctx_id, 28586260e5d5Smrg drm_handle_t handle) 285922944501Smrg{ 286022944501Smrg drm_ctx_priv_map_t map; 286122944501Smrg 2862424e9256Smrg memclear(map); 286322944501Smrg map.ctx_id = ctx_id; 286420131375Smrg map.handle = (void *)(uintptr_t)handle; 286522944501Smrg 286622944501Smrg if (drmIoctl(fd, DRM_IOCTL_SET_SAREA_CTX, &map)) 2867fe517fc9Smrg return -errno; 286822944501Smrg return 0; 286922944501Smrg} 287022944501Smrg 28716260e5d5Smrgdrm_public int drmGetContextPrivateMapping(int fd, drm_context_t ctx_id, 28726260e5d5Smrg drm_handle_t *handle) 287322944501Smrg{ 287422944501Smrg drm_ctx_priv_map_t map; 287522944501Smrg 2876424e9256Smrg memclear(map); 287722944501Smrg map.ctx_id = ctx_id; 287822944501Smrg 287922944501Smrg if (drmIoctl(fd, DRM_IOCTL_GET_SAREA_CTX, &map)) 2880fe517fc9Smrg return -errno; 288122944501Smrg if (handle) 2882fe517fc9Smrg *handle = (drm_handle_t)(uintptr_t)map.handle; 288322944501Smrg 288422944501Smrg return 0; 288522944501Smrg} 288622944501Smrg 28876260e5d5Smrgdrm_public int drmGetMap(int fd, int idx, drm_handle_t *offset, drmSize *size, 28886260e5d5Smrg drmMapType *type, drmMapFlags *flags, 28896260e5d5Smrg drm_handle_t *handle, int *mtrr) 289022944501Smrg{ 289122944501Smrg drm_map_t map; 289222944501Smrg 2893424e9256Smrg memclear(map); 289422944501Smrg map.offset = idx; 289522944501Smrg if (drmIoctl(fd, DRM_IOCTL_GET_MAP, &map)) 2896fe517fc9Smrg return -errno; 289722944501Smrg *offset = map.offset; 289822944501Smrg *size = map.size; 2899adfa0b0cSmrg *type = (drmMapType)map.type; 2900adfa0b0cSmrg *flags = (drmMapFlags)map.flags; 290122944501Smrg *handle = (unsigned long)map.handle; 290222944501Smrg *mtrr = map.mtrr; 290322944501Smrg return 0; 290422944501Smrg} 290522944501Smrg 29066260e5d5Smrgdrm_public int drmGetClient(int fd, int idx, int *auth, int *pid, int *uid, 29076260e5d5Smrg unsigned long *magic, unsigned long *iocs) 290822944501Smrg{ 290922944501Smrg drm_client_t client; 291022944501Smrg 2911424e9256Smrg memclear(client); 291222944501Smrg client.idx = idx; 291322944501Smrg if (drmIoctl(fd, DRM_IOCTL_GET_CLIENT, &client)) 2914fe517fc9Smrg return -errno; 291522944501Smrg *auth = client.auth; 291622944501Smrg *pid = client.pid; 291722944501Smrg *uid = client.uid; 291822944501Smrg *magic = client.magic; 291922944501Smrg *iocs = client.iocs; 292022944501Smrg return 0; 292122944501Smrg} 292222944501Smrg 29236260e5d5Smrgdrm_public int drmGetStats(int fd, drmStatsT *stats) 292422944501Smrg{ 292522944501Smrg drm_stats_t s; 2926424e9256Smrg unsigned i; 292722944501Smrg 2928424e9256Smrg memclear(s); 292922944501Smrg if (drmIoctl(fd, DRM_IOCTL_GET_STATS, &s)) 2930fe517fc9Smrg return -errno; 293122944501Smrg 293222944501Smrg stats->count = 0; 293322944501Smrg memset(stats, 0, sizeof(*stats)); 293422944501Smrg if (s.count > sizeof(stats->data)/sizeof(stats->data[0])) 2935fe517fc9Smrg return -1; 293622944501Smrg 293722944501Smrg#define SET_VALUE \ 293822944501Smrg stats->data[i].long_format = "%-20.20s"; \ 293922944501Smrg stats->data[i].rate_format = "%8.8s"; \ 294022944501Smrg stats->data[i].isvalue = 1; \ 294122944501Smrg stats->data[i].verbose = 0 294222944501Smrg 294322944501Smrg#define SET_COUNT \ 294422944501Smrg stats->data[i].long_format = "%-20.20s"; \ 294522944501Smrg stats->data[i].rate_format = "%5.5s"; \ 294622944501Smrg stats->data[i].isvalue = 0; \ 294722944501Smrg stats->data[i].mult_names = "kgm"; \ 294822944501Smrg stats->data[i].mult = 1000; \ 294922944501Smrg stats->data[i].verbose = 0 295022944501Smrg 295122944501Smrg#define SET_BYTE \ 295222944501Smrg stats->data[i].long_format = "%-20.20s"; \ 295322944501Smrg stats->data[i].rate_format = "%5.5s"; \ 295422944501Smrg stats->data[i].isvalue = 0; \ 295522944501Smrg stats->data[i].mult_names = "KGM"; \ 295622944501Smrg stats->data[i].mult = 1024; \ 295722944501Smrg stats->data[i].verbose = 0 295822944501Smrg 295922944501Smrg 296022944501Smrg stats->count = s.count; 296122944501Smrg for (i = 0; i < s.count; i++) { 2962fe517fc9Smrg stats->data[i].value = s.data[i].value; 2963fe517fc9Smrg switch (s.data[i].type) { 2964fe517fc9Smrg case _DRM_STAT_LOCK: 2965fe517fc9Smrg stats->data[i].long_name = "Lock"; 2966fe517fc9Smrg stats->data[i].rate_name = "Lock"; 2967fe517fc9Smrg SET_VALUE; 2968fe517fc9Smrg break; 2969fe517fc9Smrg case _DRM_STAT_OPENS: 2970fe517fc9Smrg stats->data[i].long_name = "Opens"; 2971fe517fc9Smrg stats->data[i].rate_name = "O"; 2972fe517fc9Smrg SET_COUNT; 2973fe517fc9Smrg stats->data[i].verbose = 1; 2974fe517fc9Smrg break; 2975fe517fc9Smrg case _DRM_STAT_CLOSES: 2976fe517fc9Smrg stats->data[i].long_name = "Closes"; 2977fe517fc9Smrg stats->data[i].rate_name = "Lock"; 2978fe517fc9Smrg SET_COUNT; 2979fe517fc9Smrg stats->data[i].verbose = 1; 2980fe517fc9Smrg break; 2981fe517fc9Smrg case _DRM_STAT_IOCTLS: 2982fe517fc9Smrg stats->data[i].long_name = "Ioctls"; 2983fe517fc9Smrg stats->data[i].rate_name = "Ioc/s"; 2984fe517fc9Smrg SET_COUNT; 2985fe517fc9Smrg break; 2986fe517fc9Smrg case _DRM_STAT_LOCKS: 2987fe517fc9Smrg stats->data[i].long_name = "Locks"; 2988fe517fc9Smrg stats->data[i].rate_name = "Lck/s"; 2989fe517fc9Smrg SET_COUNT; 2990fe517fc9Smrg break; 2991fe517fc9Smrg case _DRM_STAT_UNLOCKS: 2992fe517fc9Smrg stats->data[i].long_name = "Unlocks"; 2993fe517fc9Smrg stats->data[i].rate_name = "Unl/s"; 2994fe517fc9Smrg SET_COUNT; 2995fe517fc9Smrg break; 2996fe517fc9Smrg case _DRM_STAT_IRQ: 2997fe517fc9Smrg stats->data[i].long_name = "IRQs"; 2998fe517fc9Smrg stats->data[i].rate_name = "IRQ/s"; 2999fe517fc9Smrg SET_COUNT; 3000fe517fc9Smrg break; 3001fe517fc9Smrg case _DRM_STAT_PRIMARY: 3002fe517fc9Smrg stats->data[i].long_name = "Primary Bytes"; 3003fe517fc9Smrg stats->data[i].rate_name = "PB/s"; 3004fe517fc9Smrg SET_BYTE; 3005fe517fc9Smrg break; 3006fe517fc9Smrg case _DRM_STAT_SECONDARY: 3007fe517fc9Smrg stats->data[i].long_name = "Secondary Bytes"; 3008fe517fc9Smrg stats->data[i].rate_name = "SB/s"; 3009fe517fc9Smrg SET_BYTE; 3010fe517fc9Smrg break; 3011fe517fc9Smrg case _DRM_STAT_DMA: 3012fe517fc9Smrg stats->data[i].long_name = "DMA"; 3013fe517fc9Smrg stats->data[i].rate_name = "DMA/s"; 3014fe517fc9Smrg SET_COUNT; 3015fe517fc9Smrg break; 3016fe517fc9Smrg case _DRM_STAT_SPECIAL: 3017fe517fc9Smrg stats->data[i].long_name = "Special DMA"; 3018fe517fc9Smrg stats->data[i].rate_name = "dma/s"; 3019fe517fc9Smrg SET_COUNT; 3020fe517fc9Smrg break; 3021fe517fc9Smrg case _DRM_STAT_MISSED: 3022fe517fc9Smrg stats->data[i].long_name = "Miss"; 3023fe517fc9Smrg stats->data[i].rate_name = "Ms/s"; 3024fe517fc9Smrg SET_COUNT; 3025fe517fc9Smrg break; 3026fe517fc9Smrg case _DRM_STAT_VALUE: 3027fe517fc9Smrg stats->data[i].long_name = "Value"; 3028fe517fc9Smrg stats->data[i].rate_name = "Value"; 3029fe517fc9Smrg SET_VALUE; 3030fe517fc9Smrg break; 3031fe517fc9Smrg case _DRM_STAT_BYTE: 3032fe517fc9Smrg stats->data[i].long_name = "Bytes"; 3033fe517fc9Smrg stats->data[i].rate_name = "B/s"; 3034fe517fc9Smrg SET_BYTE; 3035fe517fc9Smrg break; 3036fe517fc9Smrg case _DRM_STAT_COUNT: 3037fe517fc9Smrg default: 3038fe517fc9Smrg stats->data[i].long_name = "Count"; 3039fe517fc9Smrg stats->data[i].rate_name = "Cnt/s"; 3040fe517fc9Smrg SET_COUNT; 3041fe517fc9Smrg break; 3042fe517fc9Smrg } 304322944501Smrg } 304422944501Smrg return 0; 304522944501Smrg} 304622944501Smrg 304722944501Smrg/** 304822944501Smrg * Issue a set-version ioctl. 304922944501Smrg * 305022944501Smrg * \param fd file descriptor. 3051fe517fc9Smrg * \param drmCommandIndex command index 305222944501Smrg * \param data source pointer of the data to be read and written. 305322944501Smrg * \param size size of the data to be read and written. 3054fe517fc9Smrg * 305522944501Smrg * \return zero on success, or a negative value on failure. 3056fe517fc9Smrg * 305722944501Smrg * \internal 3058fe517fc9Smrg * It issues a read-write ioctl given by 305922944501Smrg * \code DRM_COMMAND_BASE + drmCommandIndex \endcode. 306022944501Smrg */ 30616260e5d5Smrgdrm_public int drmSetInterfaceVersion(int fd, drmSetVersion *version) 306222944501Smrg{ 306322944501Smrg int retcode = 0; 306422944501Smrg drm_set_version_t sv; 306522944501Smrg 3066424e9256Smrg memclear(sv); 306722944501Smrg sv.drm_di_major = version->drm_di_major; 306822944501Smrg sv.drm_di_minor = version->drm_di_minor; 306922944501Smrg sv.drm_dd_major = version->drm_dd_major; 307022944501Smrg sv.drm_dd_minor = version->drm_dd_minor; 307122944501Smrg 307222944501Smrg if (drmIoctl(fd, DRM_IOCTL_SET_VERSION, &sv)) { 3073fe517fc9Smrg retcode = -errno; 307422944501Smrg } 307522944501Smrg 307622944501Smrg version->drm_di_major = sv.drm_di_major; 307722944501Smrg version->drm_di_minor = sv.drm_di_minor; 307822944501Smrg version->drm_dd_major = sv.drm_dd_major; 307922944501Smrg version->drm_dd_minor = sv.drm_dd_minor; 308022944501Smrg 308122944501Smrg return retcode; 308222944501Smrg} 308322944501Smrg 308422944501Smrg/** 308522944501Smrg * Send a device-specific command. 308622944501Smrg * 308722944501Smrg * \param fd file descriptor. 3088fe517fc9Smrg * \param drmCommandIndex command index 3089fe517fc9Smrg * 309022944501Smrg * \return zero on success, or a negative value on failure. 3091fe517fc9Smrg * 309222944501Smrg * \internal 3093fe517fc9Smrg * It issues a ioctl given by 309422944501Smrg * \code DRM_COMMAND_BASE + drmCommandIndex \endcode. 309522944501Smrg */ 30966260e5d5Smrgdrm_public int drmCommandNone(int fd, unsigned long drmCommandIndex) 309722944501Smrg{ 309822944501Smrg unsigned long request; 309922944501Smrg 310022944501Smrg request = DRM_IO( DRM_COMMAND_BASE + drmCommandIndex); 310122944501Smrg 3102424e9256Smrg if (drmIoctl(fd, request, NULL)) { 3103fe517fc9Smrg return -errno; 310422944501Smrg } 310522944501Smrg return 0; 310622944501Smrg} 310722944501Smrg 310822944501Smrg 310922944501Smrg/** 311022944501Smrg * Send a device-specific read command. 311122944501Smrg * 311222944501Smrg * \param fd file descriptor. 3113fe517fc9Smrg * \param drmCommandIndex command index 311422944501Smrg * \param data destination pointer of the data to be read. 311522944501Smrg * \param size size of the data to be read. 3116fe517fc9Smrg * 311722944501Smrg * \return zero on success, or a negative value on failure. 311822944501Smrg * 311922944501Smrg * \internal 3120fe517fc9Smrg * It issues a read ioctl given by 312122944501Smrg * \code DRM_COMMAND_BASE + drmCommandIndex \endcode. 312222944501Smrg */ 31236260e5d5Smrgdrm_public int drmCommandRead(int fd, unsigned long drmCommandIndex, 31246260e5d5Smrg void *data, unsigned long size) 312522944501Smrg{ 312622944501Smrg unsigned long request; 312722944501Smrg 3128fe517fc9Smrg request = DRM_IOC( DRM_IOC_READ, DRM_IOCTL_BASE, 3129fe517fc9Smrg DRM_COMMAND_BASE + drmCommandIndex, size); 313022944501Smrg 313122944501Smrg if (drmIoctl(fd, request, data)) { 3132fe517fc9Smrg return -errno; 313322944501Smrg } 313422944501Smrg return 0; 313522944501Smrg} 313622944501Smrg 313722944501Smrg 313822944501Smrg/** 313922944501Smrg * Send a device-specific write command. 314022944501Smrg * 314122944501Smrg * \param fd file descriptor. 3142fe517fc9Smrg * \param drmCommandIndex command index 314322944501Smrg * \param data source pointer of the data to be written. 314422944501Smrg * \param size size of the data to be written. 3145fe517fc9Smrg * 314622944501Smrg * \return zero on success, or a negative value on failure. 3147fe517fc9Smrg * 314822944501Smrg * \internal 3149fe517fc9Smrg * It issues a write ioctl given by 315022944501Smrg * \code DRM_COMMAND_BASE + drmCommandIndex \endcode. 315122944501Smrg */ 31526260e5d5Smrgdrm_public int drmCommandWrite(int fd, unsigned long drmCommandIndex, 31536260e5d5Smrg void *data, unsigned long size) 315422944501Smrg{ 315522944501Smrg unsigned long request; 315622944501Smrg 3157fe517fc9Smrg request = DRM_IOC( DRM_IOC_WRITE, DRM_IOCTL_BASE, 3158fe517fc9Smrg DRM_COMMAND_BASE + drmCommandIndex, size); 315922944501Smrg 316022944501Smrg if (drmIoctl(fd, request, data)) { 3161fe517fc9Smrg return -errno; 316222944501Smrg } 316322944501Smrg return 0; 316422944501Smrg} 316522944501Smrg 316622944501Smrg 316722944501Smrg/** 316822944501Smrg * Send a device-specific read-write command. 316922944501Smrg * 317022944501Smrg * \param fd file descriptor. 3171fe517fc9Smrg * \param drmCommandIndex command index 317222944501Smrg * \param data source pointer of the data to be read and written. 317322944501Smrg * \param size size of the data to be read and written. 3174fe517fc9Smrg * 317522944501Smrg * \return zero on success, or a negative value on failure. 3176fe517fc9Smrg * 317722944501Smrg * \internal 3178fe517fc9Smrg * It issues a read-write ioctl given by 317922944501Smrg * \code DRM_COMMAND_BASE + drmCommandIndex \endcode. 318022944501Smrg */ 31816260e5d5Smrgdrm_public int drmCommandWriteRead(int fd, unsigned long drmCommandIndex, 31826260e5d5Smrg void *data, unsigned long size) 318322944501Smrg{ 318422944501Smrg unsigned long request; 318522944501Smrg 3186fe517fc9Smrg request = DRM_IOC( DRM_IOC_READ|DRM_IOC_WRITE, DRM_IOCTL_BASE, 3187fe517fc9Smrg DRM_COMMAND_BASE + drmCommandIndex, size); 318822944501Smrg 318922944501Smrg if (drmIoctl(fd, request, data)) 3190fe517fc9Smrg return -errno; 319122944501Smrg return 0; 319222944501Smrg} 319322944501Smrg 319422944501Smrg#define DRM_MAX_FDS 16 319522944501Smrgstatic struct { 319622944501Smrg char *BusID; 319722944501Smrg int fd; 319822944501Smrg int refcount; 3199424e9256Smrg int type; 320022944501Smrg} connection[DRM_MAX_FDS]; 320122944501Smrg 320222944501Smrgstatic int nr_fds = 0; 320322944501Smrg 32046260e5d5Smrgdrm_public int drmOpenOnce(void *unused, const char *BusID, int *newlyopened) 3205424e9256Smrg{ 3206424e9256Smrg return drmOpenOnceWithType(BusID, newlyopened, DRM_NODE_PRIMARY); 3207424e9256Smrg} 3208424e9256Smrg 32096260e5d5Smrgdrm_public int drmOpenOnceWithType(const char *BusID, int *newlyopened, 32106260e5d5Smrg int type) 321122944501Smrg{ 321222944501Smrg int i; 321322944501Smrg int fd; 3214fe517fc9Smrg 321522944501Smrg for (i = 0; i < nr_fds; i++) 3216fe517fc9Smrg if ((strcmp(BusID, connection[i].BusID) == 0) && 3217fe517fc9Smrg (connection[i].type == type)) { 3218fe517fc9Smrg connection[i].refcount++; 3219fe517fc9Smrg *newlyopened = 0; 3220fe517fc9Smrg return connection[i].fd; 3221fe517fc9Smrg } 322222944501Smrg 3223424e9256Smrg fd = drmOpenWithType(NULL, BusID, type); 3224fe517fc9Smrg if (fd < 0 || nr_fds == DRM_MAX_FDS) 3225fe517fc9Smrg return fd; 3226fe517fc9Smrg 322722944501Smrg connection[nr_fds].BusID = strdup(BusID); 322822944501Smrg connection[nr_fds].fd = fd; 322922944501Smrg connection[nr_fds].refcount = 1; 3230424e9256Smrg connection[nr_fds].type = type; 323122944501Smrg *newlyopened = 1; 323222944501Smrg 323322944501Smrg if (0) 3234fe517fc9Smrg fprintf(stderr, "saved connection %d for %s %d\n", 3235fe517fc9Smrg nr_fds, connection[nr_fds].BusID, 3236fe517fc9Smrg strcmp(BusID, connection[nr_fds].BusID)); 323722944501Smrg 323822944501Smrg nr_fds++; 323922944501Smrg 324022944501Smrg return fd; 324122944501Smrg} 324222944501Smrg 32436260e5d5Smrgdrm_public void drmCloseOnce(int fd) 324422944501Smrg{ 324522944501Smrg int i; 324622944501Smrg 324722944501Smrg for (i = 0; i < nr_fds; i++) { 3248fe517fc9Smrg if (fd == connection[i].fd) { 3249fe517fc9Smrg if (--connection[i].refcount == 0) { 3250fe517fc9Smrg drmClose(connection[i].fd); 3251fe517fc9Smrg free(connection[i].BusID); 3252fe517fc9Smrg 3253fe517fc9Smrg if (i < --nr_fds) 3254fe517fc9Smrg connection[i] = connection[nr_fds]; 3255fe517fc9Smrg 3256fe517fc9Smrg return; 3257fe517fc9Smrg } 3258fe517fc9Smrg } 325922944501Smrg } 326022944501Smrg} 326122944501Smrg 32626260e5d5Smrgdrm_public int drmSetMaster(int fd) 326322944501Smrg{ 3264fe517fc9Smrg return drmIoctl(fd, DRM_IOCTL_SET_MASTER, NULL); 326522944501Smrg} 326622944501Smrg 32676260e5d5Smrgdrm_public int drmDropMaster(int fd) 326822944501Smrg{ 3269fe517fc9Smrg return drmIoctl(fd, DRM_IOCTL_DROP_MASTER, NULL); 327022944501Smrg} 327122944501Smrg 3272bf6cc7dcSmrgdrm_public int drmIsMaster(int fd) 3273bf6cc7dcSmrg{ 3274bf6cc7dcSmrg /* Detect master by attempting something that requires master. 3275bf6cc7dcSmrg * 3276bf6cc7dcSmrg * Authenticating magic tokens requires master and 0 is an 3277bf6cc7dcSmrg * internal kernel detail which we could use. Attempting this on 3278bf6cc7dcSmrg * a master fd would fail therefore fail with EINVAL because 0 3279bf6cc7dcSmrg * is invalid. 3280bf6cc7dcSmrg * 3281bf6cc7dcSmrg * A non-master fd will fail with EACCES, as the kernel checks 3282bf6cc7dcSmrg * for master before attempting to do anything else. 3283bf6cc7dcSmrg * 3284bf6cc7dcSmrg * Since we don't want to leak implementation details, use 3285bf6cc7dcSmrg * EACCES. 3286bf6cc7dcSmrg */ 3287bf6cc7dcSmrg return drmAuthMagic(fd, 0) != -EACCES; 3288bf6cc7dcSmrg} 3289bf6cc7dcSmrg 32906260e5d5Smrgdrm_public char *drmGetDeviceNameFromFd(int fd) 329122944501Smrg{ 329287bf8e7cSmrg#ifdef __FreeBSD__ 329387bf8e7cSmrg struct stat sbuf; 329487bf8e7cSmrg int maj, min; 329587bf8e7cSmrg int nodetype; 329687bf8e7cSmrg 329787bf8e7cSmrg if (fstat(fd, &sbuf)) 329887bf8e7cSmrg return NULL; 329987bf8e7cSmrg 330087bf8e7cSmrg maj = major(sbuf.st_rdev); 330187bf8e7cSmrg min = minor(sbuf.st_rdev); 330287bf8e7cSmrg nodetype = drmGetMinorType(maj, min); 330387bf8e7cSmrg return drmGetMinorNameForFD(fd, nodetype); 330487bf8e7cSmrg#else 3305fe517fc9Smrg char name[128]; 3306fe517fc9Smrg struct stat sbuf; 3307fe517fc9Smrg dev_t d; 3308fe517fc9Smrg int i; 330922944501Smrg 3310fe517fc9Smrg /* The whole drmOpen thing is a fiasco and we need to find a way 3311fe517fc9Smrg * back to just using open(2). For now, however, lets just make 3312fe517fc9Smrg * things worse with even more ad hoc directory walking code to 3313fe517fc9Smrg * discover the device file name. */ 331422944501Smrg 3315fe517fc9Smrg fstat(fd, &sbuf); 3316fe517fc9Smrg d = sbuf.st_rdev; 331722944501Smrg 3318fe517fc9Smrg for (i = 0; i < DRM_MAX_MINOR; i++) { 3319fe517fc9Smrg snprintf(name, sizeof name, DRM_DEV_NAME, DRM_DIR_NAME, i); 3320fe517fc9Smrg if (stat(name, &sbuf) == 0 && sbuf.st_rdev == d) 3321fe517fc9Smrg break; 3322fe517fc9Smrg } 3323fe517fc9Smrg if (i == DRM_MAX_MINOR) 3324fe517fc9Smrg return NULL; 332522944501Smrg 3326fe517fc9Smrg return strdup(name); 332787bf8e7cSmrg#endif 332822944501Smrg} 332920131375Smrg 33306260e5d5Smrgstatic bool drmNodeIsDRM(int maj, int min) 33316260e5d5Smrg{ 33326260e5d5Smrg#ifdef __linux__ 33336260e5d5Smrg char path[64]; 33346260e5d5Smrg struct stat sbuf; 33356260e5d5Smrg 33366260e5d5Smrg snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device/drm", 33376260e5d5Smrg maj, min); 33386260e5d5Smrg return stat(path, &sbuf) == 0; 33394b3d3f37Smrg#elif defined(__FreeBSD__) 334087bf8e7cSmrg char name[SPECNAMELEN]; 334187bf8e7cSmrg 334287bf8e7cSmrg if (!devname_r(makedev(maj, min), S_IFCHR, name, sizeof(name))) 334387bf8e7cSmrg return 0; 334487bf8e7cSmrg /* Handle drm/ and dri/ as both are present in different FreeBSD version 334587bf8e7cSmrg * FreeBSD on amd64/i386/powerpc external kernel modules create node in 334687bf8e7cSmrg * in /dev/drm/ and links in /dev/dri while a WIP in kernel driver creates 334787bf8e7cSmrg * only device nodes in /dev/dri/ */ 334887bf8e7cSmrg return (!strncmp(name, "drm/", 4) || !strncmp(name, "dri/", 4)); 33496260e5d5Smrg#else 33506260e5d5Smrg return maj == DRM_MAJOR; 33516260e5d5Smrg#endif 33526260e5d5Smrg} 33536260e5d5Smrg 33546260e5d5Smrgdrm_public int drmGetNodeTypeFromFd(int fd) 3355424e9256Smrg{ 3356fe517fc9Smrg struct stat sbuf; 3357fe517fc9Smrg int maj, min, type; 3358424e9256Smrg 3359fe517fc9Smrg if (fstat(fd, &sbuf)) 3360fe517fc9Smrg return -1; 3361424e9256Smrg 3362fe517fc9Smrg maj = major(sbuf.st_rdev); 3363fe517fc9Smrg min = minor(sbuf.st_rdev); 3364424e9256Smrg 33656260e5d5Smrg if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode)) { 3366fe517fc9Smrg errno = EINVAL; 3367fe517fc9Smrg return -1; 3368fe517fc9Smrg } 3369424e9256Smrg 337087bf8e7cSmrg type = drmGetMinorType(maj, min); 3371fe517fc9Smrg if (type == -1) 3372fe517fc9Smrg errno = ENODEV; 3373fe517fc9Smrg return type; 3374424e9256Smrg} 3375424e9256Smrg 33766260e5d5Smrgdrm_public int drmPrimeHandleToFD(int fd, uint32_t handle, uint32_t flags, 33776260e5d5Smrg int *prime_fd) 337820131375Smrg{ 3379fe517fc9Smrg struct drm_prime_handle args; 3380fe517fc9Smrg int ret; 338120131375Smrg 3382fe517fc9Smrg memclear(args); 3383fe517fc9Smrg args.fd = -1; 3384fe517fc9Smrg args.handle = handle; 3385fe517fc9Smrg args.flags = flags; 3386fe517fc9Smrg ret = drmIoctl(fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &args); 3387fe517fc9Smrg if (ret) 3388fe517fc9Smrg return ret; 338920131375Smrg 3390fe517fc9Smrg *prime_fd = args.fd; 3391fe517fc9Smrg return 0; 339220131375Smrg} 339320131375Smrg 33946260e5d5Smrgdrm_public int drmPrimeFDToHandle(int fd, int prime_fd, uint32_t *handle) 339520131375Smrg{ 3396fe517fc9Smrg struct drm_prime_handle args; 3397fe517fc9Smrg int ret; 339820131375Smrg 3399fe517fc9Smrg memclear(args); 3400fe517fc9Smrg args.fd = prime_fd; 3401fe517fc9Smrg ret = drmIoctl(fd, DRM_IOCTL_PRIME_FD_TO_HANDLE, &args); 3402fe517fc9Smrg if (ret) 3403fe517fc9Smrg return ret; 340420131375Smrg 3405fe517fc9Smrg *handle = args.handle; 3406fe517fc9Smrg return 0; 340720131375Smrg} 3408424e9256Smrg 3409adfa0b0cSmrgdrm_public int drmCloseBufferHandle(int fd, uint32_t handle) 3410adfa0b0cSmrg{ 3411adfa0b0cSmrg struct drm_gem_close args; 3412adfa0b0cSmrg 3413adfa0b0cSmrg memclear(args); 3414adfa0b0cSmrg args.handle = handle; 3415adfa0b0cSmrg return drmIoctl(fd, DRM_IOCTL_GEM_CLOSE, &args); 3416adfa0b0cSmrg} 3417adfa0b0cSmrg 3418424e9256Smrgstatic char *drmGetMinorNameForFD(int fd, int type) 3419424e9256Smrg{ 3420424e9256Smrg#ifdef __linux__ 3421fe517fc9Smrg DIR *sysdir; 34226260e5d5Smrg struct dirent *ent; 3423fe517fc9Smrg struct stat sbuf; 3424fe517fc9Smrg const char *name = drmGetMinorName(type); 3425fe517fc9Smrg int len; 3426fe517fc9Smrg char dev_name[64], buf[64]; 3427fe517fc9Smrg int maj, min; 3428fe517fc9Smrg 3429fe517fc9Smrg if (!name) 3430fe517fc9Smrg return NULL; 3431424e9256Smrg 3432fe517fc9Smrg len = strlen(name); 3433424e9256Smrg 3434fe517fc9Smrg if (fstat(fd, &sbuf)) 3435fe517fc9Smrg return NULL; 3436424e9256Smrg 3437fe517fc9Smrg maj = major(sbuf.st_rdev); 3438fe517fc9Smrg min = minor(sbuf.st_rdev); 3439424e9256Smrg 34406260e5d5Smrg if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode)) 3441fe517fc9Smrg return NULL; 3442424e9256Smrg 3443fe517fc9Smrg snprintf(buf, sizeof(buf), "/sys/dev/char/%d:%d/device/drm", maj, min); 3444424e9256Smrg 3445fe517fc9Smrg sysdir = opendir(buf); 3446fe517fc9Smrg if (!sysdir) 3447fe517fc9Smrg return NULL; 3448424e9256Smrg 34496260e5d5Smrg while ((ent = readdir(sysdir))) { 3450fe517fc9Smrg if (strncmp(ent->d_name, name, len) == 0) { 3451adfa0b0cSmrg if (snprintf(dev_name, sizeof(dev_name), DRM_DIR_NAME "/%s", 3452adfa0b0cSmrg ent->d_name) < 0) 3453adfa0b0cSmrg return NULL; 3454424e9256Smrg 3455fe517fc9Smrg closedir(sysdir); 3456fe517fc9Smrg return strdup(dev_name); 3457fe517fc9Smrg } 3458fe517fc9Smrg } 3459424e9256Smrg 3460fe517fc9Smrg closedir(sysdir); 34616260e5d5Smrg return NULL; 34624b3d3f37Smrg#elif defined(__FreeBSD__) 346387bf8e7cSmrg struct stat sbuf; 346487bf8e7cSmrg char dname[SPECNAMELEN]; 346587bf8e7cSmrg const char *mname; 346687bf8e7cSmrg char name[SPECNAMELEN]; 346787bf8e7cSmrg int id, maj, min, nodetype, i; 346887bf8e7cSmrg 346987bf8e7cSmrg if (fstat(fd, &sbuf)) 347087bf8e7cSmrg return NULL; 347187bf8e7cSmrg 347287bf8e7cSmrg maj = major(sbuf.st_rdev); 347387bf8e7cSmrg min = minor(sbuf.st_rdev); 347487bf8e7cSmrg 347587bf8e7cSmrg if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode)) 347687bf8e7cSmrg return NULL; 347787bf8e7cSmrg 347887bf8e7cSmrg if (!devname_r(sbuf.st_rdev, S_IFCHR, dname, sizeof(dname))) 347987bf8e7cSmrg return NULL; 348087bf8e7cSmrg 348187bf8e7cSmrg /* Handle both /dev/drm and /dev/dri 348287bf8e7cSmrg * FreeBSD on amd64/i386/powerpc external kernel modules create node in 348387bf8e7cSmrg * in /dev/drm/ and links in /dev/dri while a WIP in kernel driver creates 348487bf8e7cSmrg * only device nodes in /dev/dri/ */ 348587bf8e7cSmrg 348687bf8e7cSmrg /* Get the node type represented by fd so we can deduce the target name */ 348787bf8e7cSmrg nodetype = drmGetMinorType(maj, min); 348887bf8e7cSmrg if (nodetype == -1) 348987bf8e7cSmrg return (NULL); 349087bf8e7cSmrg mname = drmGetMinorName(type); 349187bf8e7cSmrg 349287bf8e7cSmrg for (i = 0; i < SPECNAMELEN; i++) { 349387bf8e7cSmrg if (isalpha(dname[i]) == 0 && dname[i] != '/') 349487bf8e7cSmrg break; 349587bf8e7cSmrg } 349687bf8e7cSmrg if (dname[i] == '\0') 349787bf8e7cSmrg return (NULL); 349887bf8e7cSmrg 349987bf8e7cSmrg id = (int)strtol(&dname[i], NULL, 10); 350087bf8e7cSmrg id -= drmGetMinorBase(nodetype); 350187bf8e7cSmrg snprintf(name, sizeof(name), DRM_DIR_NAME "/%s%d", mname, 350287bf8e7cSmrg id + drmGetMinorBase(type)); 350387bf8e7cSmrg 350487bf8e7cSmrg return strdup(name); 3505fe517fc9Smrg#else 35062ee35494Smrg struct stat sbuf; 35072ee35494Smrg char buf[PATH_MAX + 1]; 350882025ec7Smrg const char *dev_name = drmGetDeviceName(type); 35092ee35494Smrg unsigned int maj, min; 351082025ec7Smrg int n; 35112ee35494Smrg 35122ee35494Smrg if (fstat(fd, &sbuf)) 35132ee35494Smrg return NULL; 35142ee35494Smrg 35152ee35494Smrg maj = major(sbuf.st_rdev); 35162ee35494Smrg min = minor(sbuf.st_rdev); 35172ee35494Smrg 35186260e5d5Smrg if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode)) 35192ee35494Smrg return NULL; 35202ee35494Smrg 352182025ec7Smrg if (!dev_name) 35222ee35494Smrg return NULL; 35232ee35494Smrg 352482025ec7Smrg n = snprintf(buf, sizeof(buf), dev_name, DRM_DIR_NAME, min); 35252ee35494Smrg if (n == -1 || n >= sizeof(buf)) 35262ee35494Smrg return NULL; 35272ee35494Smrg 35282ee35494Smrg return strdup(buf); 3529424e9256Smrg#endif 3530424e9256Smrg} 3531424e9256Smrg 35326260e5d5Smrgdrm_public char *drmGetPrimaryDeviceNameFromFd(int fd) 3533424e9256Smrg{ 3534fe517fc9Smrg return drmGetMinorNameForFD(fd, DRM_NODE_PRIMARY); 3535424e9256Smrg} 3536424e9256Smrg 35376260e5d5Smrgdrm_public char *drmGetRenderDeviceNameFromFd(int fd) 3538424e9256Smrg{ 3539fe517fc9Smrg return drmGetMinorNameForFD(fd, DRM_NODE_RENDER); 3540fe517fc9Smrg} 3541fe517fc9Smrg 35422ee35494Smrg#ifdef __linux__ 35432ee35494Smrgstatic char * DRM_PRINTFLIKE(2, 3) 35442ee35494Smrgsysfs_uevent_get(const char *path, const char *fmt, ...) 35452ee35494Smrg{ 35462ee35494Smrg char filename[PATH_MAX + 1], *key, *line = NULL, *value = NULL; 35472ee35494Smrg size_t size = 0, len; 35482ee35494Smrg ssize_t num; 35492ee35494Smrg va_list ap; 35502ee35494Smrg FILE *fp; 35512ee35494Smrg 35522ee35494Smrg va_start(ap, fmt); 35532ee35494Smrg num = vasprintf(&key, fmt, ap); 35542ee35494Smrg va_end(ap); 35552ee35494Smrg len = num; 35562ee35494Smrg 35572ee35494Smrg snprintf(filename, sizeof(filename), "%s/uevent", path); 35582ee35494Smrg 35592ee35494Smrg fp = fopen(filename, "r"); 35602ee35494Smrg if (!fp) { 35612ee35494Smrg free(key); 35622ee35494Smrg return NULL; 35632ee35494Smrg } 35642ee35494Smrg 35652ee35494Smrg while ((num = getline(&line, &size, fp)) >= 0) { 35662ee35494Smrg if ((strncmp(line, key, len) == 0) && (line[len] == '=')) { 35672ee35494Smrg char *start = line + len + 1, *end = line + num - 1; 35682ee35494Smrg 35692ee35494Smrg if (*end != '\n') 35702ee35494Smrg end++; 35712ee35494Smrg 35722ee35494Smrg value = strndup(start, end - start); 35732ee35494Smrg break; 35742ee35494Smrg } 35752ee35494Smrg } 35762ee35494Smrg 35772ee35494Smrg free(line); 35782ee35494Smrg fclose(fp); 35792ee35494Smrg 35802ee35494Smrg free(key); 35812ee35494Smrg 35822ee35494Smrg return value; 35832ee35494Smrg} 35842ee35494Smrg#endif 35852ee35494Smrg 35866260e5d5Smrg/* Little white lie to avoid major rework of the existing code */ 35876260e5d5Smrg#define DRM_BUS_VIRTIO 0x10 35886260e5d5Smrg 3589fe517fc9Smrg#ifdef __linux__ 359087bf8e7cSmrgstatic int get_subsystem_type(const char *device_path) 359187bf8e7cSmrg{ 359287bf8e7cSmrg char path[PATH_MAX + 1] = ""; 3593fe517fc9Smrg char link[PATH_MAX + 1] = ""; 3594fe517fc9Smrg char *name; 35954545e80cSmrg struct { 35964545e80cSmrg const char *name; 35974545e80cSmrg int bus_type; 35984545e80cSmrg } bus_types[] = { 35994545e80cSmrg { "/pci", DRM_BUS_PCI }, 36004545e80cSmrg { "/usb", DRM_BUS_USB }, 36014545e80cSmrg { "/platform", DRM_BUS_PLATFORM }, 36024545e80cSmrg { "/spi", DRM_BUS_PLATFORM }, 36034545e80cSmrg { "/host1x", DRM_BUS_HOST1X }, 36044545e80cSmrg { "/virtio", DRM_BUS_VIRTIO }, 36054545e80cSmrg }; 3606fe517fc9Smrg 360787bf8e7cSmrg strncpy(path, device_path, PATH_MAX); 360887bf8e7cSmrg strncat(path, "/subsystem", PATH_MAX); 3609fe517fc9Smrg 3610fe517fc9Smrg if (readlink(path, link, PATH_MAX) < 0) 3611fe517fc9Smrg return -errno; 3612fe517fc9Smrg 3613fe517fc9Smrg name = strrchr(link, '/'); 3614fe517fc9Smrg if (!name) 3615fe517fc9Smrg return -EINVAL; 3616fe517fc9Smrg 36174545e80cSmrg for (unsigned i = 0; i < ARRAY_SIZE(bus_types); i++) { 36184545e80cSmrg if (strncmp(name, bus_types[i].name, strlen(bus_types[i].name)) == 0) 36194545e80cSmrg return bus_types[i].bus_type; 36204545e80cSmrg } 36216260e5d5Smrg 3622fe517fc9Smrg return -EINVAL; 362387bf8e7cSmrg} 362487bf8e7cSmrg#endif 362587bf8e7cSmrg 362687bf8e7cSmrgstatic int drmParseSubsystemType(int maj, int min) 362787bf8e7cSmrg{ 362887bf8e7cSmrg#ifdef __linux__ 362987bf8e7cSmrg char path[PATH_MAX + 1] = ""; 363087bf8e7cSmrg char real_path[PATH_MAX + 1] = ""; 363187bf8e7cSmrg int subsystem_type; 363287bf8e7cSmrg 363387bf8e7cSmrg snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min); 363487bf8e7cSmrg 363587bf8e7cSmrg subsystem_type = get_subsystem_type(path); 363687bf8e7cSmrg /* Try to get the parent (underlying) device type */ 363787bf8e7cSmrg if (subsystem_type == DRM_BUS_VIRTIO) { 363887bf8e7cSmrg /* Assume virtio-pci on error */ 363987bf8e7cSmrg if (!realpath(path, real_path)) 364087bf8e7cSmrg return DRM_BUS_VIRTIO; 364187bf8e7cSmrg strncat(path, "/..", PATH_MAX); 364287bf8e7cSmrg subsystem_type = get_subsystem_type(path); 364387bf8e7cSmrg if (subsystem_type < 0) 364487bf8e7cSmrg return DRM_BUS_VIRTIO; 364587bf8e7cSmrg } 3646a970b457Sriastradh#elif defined(__NetBSD__) 3647a970b457Sriastradh int type, fd; 3648a970b457Sriastradh drmSetVersion sv; 3649a970b457Sriastradh char *buf; 3650a970b457Sriastradh unsigned domain, bus, dev; 3651a970b457Sriastradh int func; 3652a970b457Sriastradh int ret; 3653a970b457Sriastradh 3654a970b457Sriastradh /* Get the type of device we're looking for to pick the right pathname. */ 365577e87e13Smrg type = drmGetMinorType(maj, min); 3656a970b457Sriastradh if (type == -1) 3657a970b457Sriastradh return -ENODEV; 3658a970b457Sriastradh 3659a970b457Sriastradh /* Open the device. Don't try to create it if it's not there. */ 3660a970b457Sriastradh fd = drmOpenMinor(min, 0, type); 3661a970b457Sriastradh if (fd < 0) 3662a970b457Sriastradh return -errno; 3663a970b457Sriastradh 3664a970b457Sriastradh /* 3665a970b457Sriastradh * Set the interface version to 1.4 or 1.1, which has the effect of 3666a970b457Sriastradh * populating the bus id for us. 3667a970b457Sriastradh */ 3668a970b457Sriastradh sv.drm_di_major = 1; 3669a970b457Sriastradh sv.drm_di_minor = 4; 3670a970b457Sriastradh sv.drm_dd_major = -1; 3671a970b457Sriastradh sv.drm_dd_minor = -1; 3672a970b457Sriastradh if (drmSetInterfaceVersion(fd, &sv)) { 3673a970b457Sriastradh sv.drm_di_major = 1; 3674a970b457Sriastradh sv.drm_di_minor = 1; 3675a970b457Sriastradh sv.drm_dd_major = -1; 3676a970b457Sriastradh sv.drm_dd_minor = -1; 3677a970b457Sriastradh if (drmSetInterfaceVersion(fd, &sv)) { 36785046d36bSriastradh /* 36795046d36bSriastradh * We're probably not the master. Hope the master already 36805046d36bSriastradh * set the version to >=1.1 so that we can get the busid. 36815046d36bSriastradh */ 3682a970b457Sriastradh } 3683a970b457Sriastradh } 3684a970b457Sriastradh 3685a970b457Sriastradh /* Get the bus id. */ 3686a970b457Sriastradh buf = drmGetBusid(fd); 3687a970b457Sriastradh 3688a970b457Sriastradh /* We're done with the device now. */ 3689a970b457Sriastradh (void)close(fd); 3690a970b457Sriastradh 3691a970b457Sriastradh /* If there is no bus id, fail. */ 3692a970b457Sriastradh if (buf == NULL) 3693a970b457Sriastradh return -ENODEV; 3694a970b457Sriastradh 3695a970b457Sriastradh /* Find a string we know about; otherwise -EINVAL. */ 3696a970b457Sriastradh ret = -EINVAL; 369748994cb0Sriastradh if (strncmp(buf, "pci:", 4) == 0) 3698a970b457Sriastradh ret = DRM_BUS_PCI; 3699a970b457Sriastradh 3700a970b457Sriastradh /* We're done with the bus id. */ 3701a970b457Sriastradh free(buf); 3702a970b457Sriastradh 3703a970b457Sriastradh /* Success or not, we're done. */ 3704a970b457Sriastradh return ret; 37054545e80cSmrg#elif defined(__OpenBSD__) || defined(__DragonFly__) 37062ee35494Smrg return DRM_BUS_PCI; 3707fe517fc9Smrg#else 3708fe517fc9Smrg#warning "Missing implementation of drmParseSubsystemType" 3709fe517fc9Smrg return -EINVAL; 3710fe517fc9Smrg#endif 3711fe517fc9Smrg} 3712fe517fc9Smrg 371387bf8e7cSmrg#ifdef __linux__ 37146260e5d5Smrgstatic void 37156260e5d5Smrgget_pci_path(int maj, int min, char *pci_path) 37166260e5d5Smrg{ 37176260e5d5Smrg char path[PATH_MAX + 1], *term; 37186260e5d5Smrg 37196260e5d5Smrg snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min); 37206260e5d5Smrg if (!realpath(path, pci_path)) { 37216260e5d5Smrg strcpy(pci_path, path); 37226260e5d5Smrg return; 37236260e5d5Smrg } 37246260e5d5Smrg 37256260e5d5Smrg term = strrchr(pci_path, '/'); 37266260e5d5Smrg if (term && strncmp(term, "/virtio", 7) == 0) 37276260e5d5Smrg *term = 0; 37286260e5d5Smrg} 372987bf8e7cSmrg#endif 373087bf8e7cSmrg 373187bf8e7cSmrg#ifdef __FreeBSD__ 373287bf8e7cSmrgstatic int get_sysctl_pci_bus_info(int maj, int min, drmPciBusInfoPtr info) 373387bf8e7cSmrg{ 373487bf8e7cSmrg char dname[SPECNAMELEN]; 373587bf8e7cSmrg char sysctl_name[16]; 373687bf8e7cSmrg char sysctl_val[256]; 373787bf8e7cSmrg size_t sysctl_len; 373887bf8e7cSmrg int id, type, nelem; 373987bf8e7cSmrg unsigned int rdev, majmin, domain, bus, dev, func; 374087bf8e7cSmrg 374187bf8e7cSmrg rdev = makedev(maj, min); 374287bf8e7cSmrg if (!devname_r(rdev, S_IFCHR, dname, sizeof(dname))) 374387bf8e7cSmrg return -EINVAL; 374487bf8e7cSmrg 374587bf8e7cSmrg if (sscanf(dname, "drm/%d\n", &id) != 1) 374687bf8e7cSmrg return -EINVAL; 374787bf8e7cSmrg type = drmGetMinorType(maj, min); 374887bf8e7cSmrg if (type == -1) 374987bf8e7cSmrg return -EINVAL; 375087bf8e7cSmrg 375187bf8e7cSmrg /* BUG: This above section is iffy, since it mandates that a driver will 375287bf8e7cSmrg * create both card and render node. 375387bf8e7cSmrg * If it does not, the next DRM device will create card#X and 375487bf8e7cSmrg * renderD#(128+X)-1. 375587bf8e7cSmrg * This is a possibility in FreeBSD but for now there is no good way for 375687bf8e7cSmrg * obtaining the info. 375787bf8e7cSmrg */ 375887bf8e7cSmrg switch (type) { 375987bf8e7cSmrg case DRM_NODE_PRIMARY: 376087bf8e7cSmrg break; 376187bf8e7cSmrg case DRM_NODE_RENDER: 376287bf8e7cSmrg id -= 128; 376348246ce7Smrg break; 376487bf8e7cSmrg } 376587bf8e7cSmrg if (id < 0) 376687bf8e7cSmrg return -EINVAL; 376787bf8e7cSmrg 376887bf8e7cSmrg if (snprintf(sysctl_name, sizeof(sysctl_name), "hw.dri.%d.busid", id) <= 0) 376987bf8e7cSmrg return -EINVAL; 377087bf8e7cSmrg sysctl_len = sizeof(sysctl_val); 377187bf8e7cSmrg if (sysctlbyname(sysctl_name, sysctl_val, &sysctl_len, NULL, 0)) 377287bf8e7cSmrg return -EINVAL; 377387bf8e7cSmrg 377487bf8e7cSmrg #define bus_fmt "pci:%04x:%02x:%02x.%u" 377587bf8e7cSmrg 377687bf8e7cSmrg nelem = sscanf(sysctl_val, bus_fmt, &domain, &bus, &dev, &func); 377787bf8e7cSmrg if (nelem != 4) 377887bf8e7cSmrg return -EINVAL; 377987bf8e7cSmrg info->domain = domain; 378087bf8e7cSmrg info->bus = bus; 378187bf8e7cSmrg info->dev = dev; 378287bf8e7cSmrg info->func = func; 378387bf8e7cSmrg 378487bf8e7cSmrg return 0; 378587bf8e7cSmrg} 378687bf8e7cSmrg#endif 37876260e5d5Smrg 3788fe517fc9Smrgstatic int drmParsePciBusInfo(int maj, int min, drmPciBusInfoPtr info) 3789fe517fc9Smrg{ 3790fe517fc9Smrg#ifdef __linux__ 37912ee35494Smrg unsigned int domain, bus, dev, func; 37926260e5d5Smrg char pci_path[PATH_MAX + 1], *value; 37932ee35494Smrg int num; 3794fe517fc9Smrg 37956260e5d5Smrg get_pci_path(maj, min, pci_path); 3796fe517fc9Smrg 37976260e5d5Smrg value = sysfs_uevent_get(pci_path, "PCI_SLOT_NAME"); 37982ee35494Smrg if (!value) 37992ee35494Smrg return -ENOENT; 3800fe517fc9Smrg 38012ee35494Smrg num = sscanf(value, "%04x:%02x:%02x.%1u", &domain, &bus, &dev, &func); 38022ee35494Smrg free(value); 3803fe517fc9Smrg 38042ee35494Smrg if (num != 4) 3805fe517fc9Smrg return -EINVAL; 3806fe517fc9Smrg 3807fe517fc9Smrg info->domain = domain; 3808fe517fc9Smrg info->bus = bus; 3809fe517fc9Smrg info->dev = dev; 3810fe517fc9Smrg info->func = func; 3811fe517fc9Smrg 3812a970b457Sriastradh return 0; 3813a970b457Sriastradh#elif defined(__NetBSD__) 3814a970b457Sriastradh int type, fd; 3815a970b457Sriastradh drmSetVersion sv; 3816a970b457Sriastradh char *buf; 3817a970b457Sriastradh unsigned domain, bus, dev; 3818a970b457Sriastradh int func; 3819a970b457Sriastradh int ret; 3820a970b457Sriastradh 3821a970b457Sriastradh /* Get the type of device we're looking for to pick the right pathname. */ 382277e87e13Smrg type = drmGetMinorType(maj, min); 3823a970b457Sriastradh if (type == -1) 3824a970b457Sriastradh return -ENODEV; 3825a970b457Sriastradh 3826a970b457Sriastradh /* Open the device. Don't try to create it if it's not there. */ 3827a970b457Sriastradh fd = drmOpenMinor(min, 0, type); 3828a970b457Sriastradh if (fd < 0) 3829a970b457Sriastradh return -errno; 3830a970b457Sriastradh 3831a970b457Sriastradh /* 3832a970b457Sriastradh * Set the interface version to 1.4 or 1.1, which has the effect of 3833a970b457Sriastradh * populating the bus id for us. 3834a970b457Sriastradh */ 3835a970b457Sriastradh sv.drm_di_major = 1; 3836a970b457Sriastradh sv.drm_di_minor = 4; 3837a970b457Sriastradh sv.drm_dd_major = -1; 3838a970b457Sriastradh sv.drm_dd_minor = -1; 3839a970b457Sriastradh if (drmSetInterfaceVersion(fd, &sv)) { 3840a970b457Sriastradh sv.drm_di_major = 1; 3841a970b457Sriastradh sv.drm_di_minor = 1; 3842a970b457Sriastradh sv.drm_dd_major = -1; 3843a970b457Sriastradh sv.drm_dd_minor = -1; 3844a970b457Sriastradh if (drmSetInterfaceVersion(fd, &sv)) { 384506815bcbSmaya /* 384606815bcbSmaya * We're probably not the master. Hope the master already 384706815bcbSmaya * set the version to >=1.1 so that we can get the busid. 384806815bcbSmaya */ 3849a970b457Sriastradh } 3850a970b457Sriastradh } 3851a970b457Sriastradh 3852a970b457Sriastradh /* Get the bus id. */ 3853a970b457Sriastradh buf = drmGetBusid(fd); 3854a970b457Sriastradh 3855a970b457Sriastradh /* We're done with the device now. */ 3856a970b457Sriastradh (void)close(fd); 3857a970b457Sriastradh 3858a970b457Sriastradh /* If there is no bus id, fail. */ 3859a970b457Sriastradh if (buf == NULL) 3860a970b457Sriastradh return -ENODEV; 3861a970b457Sriastradh 3862a970b457Sriastradh /* Parse the bus id. */ 3863a970b457Sriastradh ret = sscanf(buf, "pci:%04x:%02x:%02x.%d", &domain, &bus, &dev, &func); 3864a970b457Sriastradh 3865a970b457Sriastradh /* We're done with the bus id. */ 3866a970b457Sriastradh free(buf); 3867a970b457Sriastradh 3868a970b457Sriastradh /* If scanf didn't return 4 -- domain, bus, dev, func -- then fail. */ 3869a970b457Sriastradh if (ret != 4) 3870a970b457Sriastradh return -ENODEV; 3871a970b457Sriastradh 3872a970b457Sriastradh /* Populate the results. */ 3873a970b457Sriastradh info->domain = domain; 3874a970b457Sriastradh info->bus = bus; 3875a970b457Sriastradh info->dev = dev; 3876a970b457Sriastradh info->func = func; 3877a970b457Sriastradh 3878a970b457Sriastradh /* Success! */ 38792ee35494Smrg return 0; 38804545e80cSmrg#elif defined(__OpenBSD__) || defined(__DragonFly__) 38812ee35494Smrg struct drm_pciinfo pinfo; 38822ee35494Smrg int fd, type; 38832ee35494Smrg 388487bf8e7cSmrg type = drmGetMinorType(maj, min); 38852ee35494Smrg if (type == -1) 38862ee35494Smrg return -ENODEV; 38872ee35494Smrg 38882ee35494Smrg fd = drmOpenMinor(min, 0, type); 38892ee35494Smrg if (fd < 0) 38902ee35494Smrg return -errno; 38912ee35494Smrg 38922ee35494Smrg if (drmIoctl(fd, DRM_IOCTL_GET_PCIINFO, &pinfo)) { 38932ee35494Smrg close(fd); 38942ee35494Smrg return -errno; 38952ee35494Smrg } 38962ee35494Smrg close(fd); 38972ee35494Smrg 38982ee35494Smrg info->domain = pinfo.domain; 38992ee35494Smrg info->bus = pinfo.bus; 39002ee35494Smrg info->dev = pinfo.dev; 39012ee35494Smrg info->func = pinfo.func; 39022ee35494Smrg 3903fe517fc9Smrg return 0; 39044b3d3f37Smrg#elif defined(__FreeBSD__) 390587bf8e7cSmrg return get_sysctl_pci_bus_info(maj, min, info); 3906fe517fc9Smrg#else 3907fe517fc9Smrg#warning "Missing implementation of drmParsePciBusInfo" 3908fe517fc9Smrg return -EINVAL; 3909fe517fc9Smrg#endif 3910fe517fc9Smrg} 3911fe517fc9Smrg 39126260e5d5Smrgdrm_public int drmDevicesEqual(drmDevicePtr a, drmDevicePtr b) 3913fe517fc9Smrg{ 3914fe517fc9Smrg if (a == NULL || b == NULL) 39150655efefSmrg return 0; 3916fe517fc9Smrg 3917fe517fc9Smrg if (a->bustype != b->bustype) 39180655efefSmrg return 0; 3919fe517fc9Smrg 3920fe517fc9Smrg switch (a->bustype) { 3921fe517fc9Smrg case DRM_BUS_PCI: 39220655efefSmrg return memcmp(a->businfo.pci, b->businfo.pci, sizeof(drmPciBusInfo)) == 0; 39232ee35494Smrg 39242ee35494Smrg case DRM_BUS_USB: 39250655efefSmrg return memcmp(a->businfo.usb, b->businfo.usb, sizeof(drmUsbBusInfo)) == 0; 39262ee35494Smrg 39272ee35494Smrg case DRM_BUS_PLATFORM: 39280655efefSmrg return memcmp(a->businfo.platform, b->businfo.platform, sizeof(drmPlatformBusInfo)) == 0; 39292ee35494Smrg 39302ee35494Smrg case DRM_BUS_HOST1X: 39310655efefSmrg return memcmp(a->businfo.host1x, b->businfo.host1x, sizeof(drmHost1xBusInfo)) == 0; 39322ee35494Smrg 3933fe517fc9Smrg default: 3934fe517fc9Smrg break; 3935fe517fc9Smrg } 3936fe517fc9Smrg 39370655efefSmrg return 0; 3938fe517fc9Smrg} 3939fe517fc9Smrg 3940fe517fc9Smrgstatic int drmGetNodeType(const char *name) 3941fe517fc9Smrg{ 3942fe517fc9Smrg if (strncmp(name, DRM_RENDER_MINOR_NAME, 3943fe517fc9Smrg sizeof(DRM_RENDER_MINOR_NAME) - 1) == 0) 3944fe517fc9Smrg return DRM_NODE_RENDER; 3945fe517fc9Smrg 394682025ec7Smrg if (strncmp(name, DRM_PRIMARY_MINOR_NAME, 394782025ec7Smrg sizeof(DRM_PRIMARY_MINOR_NAME) - 1) == 0) 394882025ec7Smrg return DRM_NODE_PRIMARY; 394982025ec7Smrg 3950fe517fc9Smrg return -EINVAL; 3951fe517fc9Smrg} 3952fe517fc9Smrg 3953fe517fc9Smrgstatic int drmGetMaxNodeName(void) 3954fe517fc9Smrg{ 3955fe517fc9Smrg return sizeof(DRM_DIR_NAME) + 3956fe517fc9Smrg MAX3(sizeof(DRM_PRIMARY_MINOR_NAME), 3957fe517fc9Smrg sizeof(DRM_CONTROL_MINOR_NAME), 3958fe517fc9Smrg sizeof(DRM_RENDER_MINOR_NAME)) + 3959fe517fc9Smrg 3 /* length of the node number */; 3960fe517fc9Smrg} 3961fe517fc9Smrg 3962fe517fc9Smrg#ifdef __linux__ 39632ee35494Smrgstatic int parse_separate_sysfs_files(int maj, int min, 39642ee35494Smrg drmPciDeviceInfoPtr device, 39652ee35494Smrg bool ignore_revision) 39662ee35494Smrg{ 39672ee35494Smrg static const char *attrs[] = { 39682ee35494Smrg "revision", /* Older kernels are missing the file, so check for it first */ 39692ee35494Smrg "vendor", 39702ee35494Smrg "device", 39712ee35494Smrg "subsystem_vendor", 39722ee35494Smrg "subsystem_device", 39732ee35494Smrg }; 39746260e5d5Smrg char path[PATH_MAX + 1], pci_path[PATH_MAX + 1]; 39752ee35494Smrg unsigned int data[ARRAY_SIZE(attrs)]; 39762ee35494Smrg FILE *fp; 39772ee35494Smrg int ret; 39782ee35494Smrg 39796260e5d5Smrg get_pci_path(maj, min, pci_path); 39806260e5d5Smrg 39812ee35494Smrg for (unsigned i = ignore_revision ? 1 : 0; i < ARRAY_SIZE(attrs); i++) { 3982adfa0b0cSmrg if (snprintf(path, PATH_MAX, "%s/%s", pci_path, attrs[i]) < 0) 3983adfa0b0cSmrg return -errno; 3984adfa0b0cSmrg 39852ee35494Smrg fp = fopen(path, "r"); 39862ee35494Smrg if (!fp) 39872ee35494Smrg return -errno; 39882ee35494Smrg 39892ee35494Smrg ret = fscanf(fp, "%x", &data[i]); 39902ee35494Smrg fclose(fp); 39912ee35494Smrg if (ret != 1) 39922ee35494Smrg return -errno; 39932ee35494Smrg 39942ee35494Smrg } 39952ee35494Smrg 39962ee35494Smrg device->revision_id = ignore_revision ? 0xff : data[0] & 0xff; 39972ee35494Smrg device->vendor_id = data[1] & 0xffff; 39982ee35494Smrg device->device_id = data[2] & 0xffff; 39992ee35494Smrg device->subvendor_id = data[3] & 0xffff; 40002ee35494Smrg device->subdevice_id = data[4] & 0xffff; 40012ee35494Smrg 40022ee35494Smrg return 0; 40032ee35494Smrg} 40042ee35494Smrg 40052ee35494Smrgstatic int parse_config_sysfs_file(int maj, int min, 40062ee35494Smrg drmPciDeviceInfoPtr device) 40072ee35494Smrg{ 40086260e5d5Smrg char path[PATH_MAX + 1], pci_path[PATH_MAX + 1]; 4009fe517fc9Smrg unsigned char config[64]; 4010fe517fc9Smrg int fd, ret; 4011fe517fc9Smrg 40126260e5d5Smrg get_pci_path(maj, min, pci_path); 40136260e5d5Smrg 4014adfa0b0cSmrg if (snprintf(path, PATH_MAX, "%s/config", pci_path) < 0) 4015adfa0b0cSmrg return -errno; 4016adfa0b0cSmrg 4017fe517fc9Smrg fd = open(path, O_RDONLY); 4018fe517fc9Smrg if (fd < 0) 4019fe517fc9Smrg return -errno; 4020fe517fc9Smrg 4021fe517fc9Smrg ret = read(fd, config, sizeof(config)); 4022fe517fc9Smrg close(fd); 4023fe517fc9Smrg if (ret < 0) 4024fe517fc9Smrg return -errno; 4025fe517fc9Smrg 4026fe517fc9Smrg device->vendor_id = config[0] | (config[1] << 8); 4027fe517fc9Smrg device->device_id = config[2] | (config[3] << 8); 4028fe517fc9Smrg device->revision_id = config[8]; 4029fe517fc9Smrg device->subvendor_id = config[44] | (config[45] << 8); 4030fe517fc9Smrg device->subdevice_id = config[46] | (config[47] << 8); 4031fe517fc9Smrg 40322ee35494Smrg return 0; 40332ee35494Smrg} 40342ee35494Smrg#endif 40352ee35494Smrg 40362ee35494Smrgstatic int drmParsePciDeviceInfo(int maj, int min, 40372ee35494Smrg drmPciDeviceInfoPtr device, 40382ee35494Smrg uint32_t flags) 40392ee35494Smrg{ 40402ee35494Smrg#ifdef __linux__ 40412ee35494Smrg if (!(flags & DRM_DEVICE_GET_PCI_REVISION)) 40422ee35494Smrg return parse_separate_sysfs_files(maj, min, device, true); 40432ee35494Smrg 40442ee35494Smrg if (parse_separate_sysfs_files(maj, min, device, false)) 40452ee35494Smrg return parse_config_sysfs_file(maj, min, device); 40462ee35494Smrg 40472ee35494Smrg return 0; 4048a970b457Sriastradh#elif defined(__NetBSD__) 4049a970b457Sriastradh drmPciBusInfo businfo; 4050a970b457Sriastradh char fname[PATH_MAX]; 4051a970b457Sriastradh int pcifd; 4052a970b457Sriastradh pcireg_t id, class, subsys; 4053a970b457Sriastradh int ret; 4054a970b457Sriastradh 4055a970b457Sriastradh /* Find where on the bus the device lives. */ 4056a970b457Sriastradh ret = drmParsePciBusInfo(maj, min, &businfo); 4057a970b457Sriastradh if (ret) 4058a970b457Sriastradh return ret; 4059a970b457Sriastradh 4060a970b457Sriastradh /* Open the pciN device node to get at its config registers. */ 4061a970b457Sriastradh if (snprintf(fname, sizeof fname, "/dev/pci%u", businfo.domain) 4062a970b457Sriastradh >= sizeof fname) 4063a970b457Sriastradh return -ENODEV; 4064a970b457Sriastradh if ((pcifd = open(fname, O_RDONLY)) == -1) 4065a970b457Sriastradh return -errno; 4066a970b457Sriastradh 4067f8b67707Schristos ret = -1; 4068a970b457Sriastradh /* Read the id and class pci config registers. */ 4069a970b457Sriastradh if (pcibus_conf_read(pcifd, businfo.bus, businfo.dev, businfo.func, 4070a970b457Sriastradh PCI_ID_REG, &id) == -1) 4071f8b67707Schristos goto out; 4072a970b457Sriastradh if (pcibus_conf_read(pcifd, businfo.bus, businfo.dev, businfo.func, 4073a970b457Sriastradh PCI_CLASS_REG, &class) == -1) 4074f8b67707Schristos goto out; 4075a970b457Sriastradh if (pcibus_conf_read(pcifd, businfo.bus, businfo.dev, businfo.func, 4076a970b457Sriastradh PCI_SUBSYS_ID_REG, &subsys) == -1) 4077f8b67707Schristos goto out; 4078a970b457Sriastradh 4079f8b67707Schristos ret = 0; 4080a970b457Sriastradh device->vendor_id = PCI_VENDOR(id); 4081a970b457Sriastradh device->device_id = PCI_PRODUCT(id); 4082a970b457Sriastradh device->subvendor_id = PCI_SUBSYS_VENDOR(subsys); 4083a970b457Sriastradh device->subdevice_id = PCI_SUBSYS_ID(subsys); 4084a970b457Sriastradh device->revision_id = PCI_REVISION(class); 4085f8b67707Schristosout: 4086f8b67707Schristos if (ret == -1) 4087f8b67707Schristos ret = -errno; 4088f8b67707Schristos close(pcifd); 4089f8b67707Schristos return ret; 40904545e80cSmrg#elif defined(__OpenBSD__) || defined(__DragonFly__) 40912ee35494Smrg struct drm_pciinfo pinfo; 40922ee35494Smrg int fd, type; 40932ee35494Smrg 409487bf8e7cSmrg type = drmGetMinorType(maj, min); 40952ee35494Smrg if (type == -1) 40962ee35494Smrg return -ENODEV; 40972ee35494Smrg 40982ee35494Smrg fd = drmOpenMinor(min, 0, type); 40992ee35494Smrg if (fd < 0) 41002ee35494Smrg return -errno; 41012ee35494Smrg 41022ee35494Smrg if (drmIoctl(fd, DRM_IOCTL_GET_PCIINFO, &pinfo)) { 41032ee35494Smrg close(fd); 41042ee35494Smrg return -errno; 41052ee35494Smrg } 41062ee35494Smrg close(fd); 41072ee35494Smrg 41082ee35494Smrg device->vendor_id = pinfo.vendor_id; 41092ee35494Smrg device->device_id = pinfo.device_id; 41102ee35494Smrg device->revision_id = pinfo.revision_id; 41112ee35494Smrg device->subvendor_id = pinfo.subvendor_id; 41122ee35494Smrg device->subdevice_id = pinfo.subdevice_id; 41132ee35494Smrg 411487bf8e7cSmrg return 0; 41154b3d3f37Smrg#elif defined(__FreeBSD__) 411687bf8e7cSmrg drmPciBusInfo info; 411787bf8e7cSmrg struct pci_conf_io pc; 411887bf8e7cSmrg struct pci_match_conf patterns[1]; 411987bf8e7cSmrg struct pci_conf results[1]; 412087bf8e7cSmrg int fd, error; 412187bf8e7cSmrg 412287bf8e7cSmrg if (get_sysctl_pci_bus_info(maj, min, &info) != 0) 412387bf8e7cSmrg return -EINVAL; 412487bf8e7cSmrg 41253b115362Smrg fd = open("/dev/pci", O_RDONLY); 412687bf8e7cSmrg if (fd < 0) 412787bf8e7cSmrg return -errno; 412887bf8e7cSmrg 412987bf8e7cSmrg bzero(&patterns, sizeof(patterns)); 413087bf8e7cSmrg patterns[0].pc_sel.pc_domain = info.domain; 413187bf8e7cSmrg patterns[0].pc_sel.pc_bus = info.bus; 413287bf8e7cSmrg patterns[0].pc_sel.pc_dev = info.dev; 413387bf8e7cSmrg patterns[0].pc_sel.pc_func = info.func; 413487bf8e7cSmrg patterns[0].flags = PCI_GETCONF_MATCH_DOMAIN | PCI_GETCONF_MATCH_BUS 413587bf8e7cSmrg | PCI_GETCONF_MATCH_DEV | PCI_GETCONF_MATCH_FUNC; 413687bf8e7cSmrg bzero(&pc, sizeof(struct pci_conf_io)); 413787bf8e7cSmrg pc.num_patterns = 1; 413887bf8e7cSmrg pc.pat_buf_len = sizeof(patterns); 413987bf8e7cSmrg pc.patterns = patterns; 414087bf8e7cSmrg pc.match_buf_len = sizeof(results); 414187bf8e7cSmrg pc.matches = results; 414287bf8e7cSmrg 414387bf8e7cSmrg if (ioctl(fd, PCIOCGETCONF, &pc) || pc.status == PCI_GETCONF_ERROR) { 414487bf8e7cSmrg error = errno; 414587bf8e7cSmrg close(fd); 414687bf8e7cSmrg return -error; 414787bf8e7cSmrg } 414887bf8e7cSmrg close(fd); 414987bf8e7cSmrg 415087bf8e7cSmrg device->vendor_id = results[0].pc_vendor; 415187bf8e7cSmrg device->device_id = results[0].pc_device; 415287bf8e7cSmrg device->subvendor_id = results[0].pc_subvendor; 415387bf8e7cSmrg device->subdevice_id = results[0].pc_subdevice; 415487bf8e7cSmrg device->revision_id = results[0].pc_revid; 415587bf8e7cSmrg 4156fe517fc9Smrg return 0; 4157fe517fc9Smrg#else 4158fe517fc9Smrg#warning "Missing implementation of drmParsePciDeviceInfo" 4159fe517fc9Smrg return -EINVAL; 4160fe517fc9Smrg#endif 4161fe517fc9Smrg} 4162fe517fc9Smrg 41632ee35494Smrgstatic void drmFreePlatformDevice(drmDevicePtr device) 41642ee35494Smrg{ 41652ee35494Smrg if (device->deviceinfo.platform) { 41662ee35494Smrg if (device->deviceinfo.platform->compatible) { 41672ee35494Smrg char **compatible = device->deviceinfo.platform->compatible; 41682ee35494Smrg 41692ee35494Smrg while (*compatible) { 41702ee35494Smrg free(*compatible); 41712ee35494Smrg compatible++; 41722ee35494Smrg } 41732ee35494Smrg 41742ee35494Smrg free(device->deviceinfo.platform->compatible); 41752ee35494Smrg } 41762ee35494Smrg } 41772ee35494Smrg} 41782ee35494Smrg 41792ee35494Smrgstatic void drmFreeHost1xDevice(drmDevicePtr device) 41802ee35494Smrg{ 41812ee35494Smrg if (device->deviceinfo.host1x) { 41822ee35494Smrg if (device->deviceinfo.host1x->compatible) { 41832ee35494Smrg char **compatible = device->deviceinfo.host1x->compatible; 41842ee35494Smrg 41852ee35494Smrg while (*compatible) { 41862ee35494Smrg free(*compatible); 41872ee35494Smrg compatible++; 41882ee35494Smrg } 41892ee35494Smrg 41902ee35494Smrg free(device->deviceinfo.host1x->compatible); 41912ee35494Smrg } 41922ee35494Smrg } 41932ee35494Smrg} 41942ee35494Smrg 41956260e5d5Smrgdrm_public void drmFreeDevice(drmDevicePtr *device) 4196fe517fc9Smrg{ 4197fe517fc9Smrg if (device == NULL) 4198fe517fc9Smrg return; 4199fe517fc9Smrg 42002ee35494Smrg if (*device) { 42012ee35494Smrg switch ((*device)->bustype) { 42022ee35494Smrg case DRM_BUS_PLATFORM: 42032ee35494Smrg drmFreePlatformDevice(*device); 42042ee35494Smrg break; 42052ee35494Smrg 42062ee35494Smrg case DRM_BUS_HOST1X: 42072ee35494Smrg drmFreeHost1xDevice(*device); 42082ee35494Smrg break; 42092ee35494Smrg } 42102ee35494Smrg } 42112ee35494Smrg 4212fe517fc9Smrg free(*device); 4213fe517fc9Smrg *device = NULL; 4214fe517fc9Smrg} 4215fe517fc9Smrg 42166260e5d5Smrgdrm_public void drmFreeDevices(drmDevicePtr devices[], int count) 4217fe517fc9Smrg{ 4218fe517fc9Smrg int i; 4219fe517fc9Smrg 4220fe517fc9Smrg if (devices == NULL) 4221fe517fc9Smrg return; 4222fe517fc9Smrg 4223fe517fc9Smrg for (i = 0; i < count; i++) 4224fe517fc9Smrg if (devices[i]) 4225fe517fc9Smrg drmFreeDevice(&devices[i]); 4226fe517fc9Smrg} 4227fe517fc9Smrg 42282ee35494Smrgstatic drmDevicePtr drmDeviceAlloc(unsigned int type, const char *node, 42292ee35494Smrg size_t bus_size, size_t device_size, 42302ee35494Smrg char **ptrp) 4231fe517fc9Smrg{ 42322ee35494Smrg size_t max_node_length, extra, size; 42332ee35494Smrg drmDevicePtr device; 42342ee35494Smrg unsigned int i; 42352ee35494Smrg char *ptr; 4236fe517fc9Smrg 42372ee35494Smrg max_node_length = ALIGN(drmGetMaxNodeName(), sizeof(void *)); 42382ee35494Smrg extra = DRM_NODE_MAX * (sizeof(void *) + max_node_length); 4239fe517fc9Smrg 42402ee35494Smrg size = sizeof(*device) + extra + bus_size + device_size; 4241fe517fc9Smrg 42422ee35494Smrg device = calloc(1, size); 42432ee35494Smrg if (!device) 42442ee35494Smrg return NULL; 42452ee35494Smrg 42462ee35494Smrg device->available_nodes = 1 << type; 4247fe517fc9Smrg 42482ee35494Smrg ptr = (char *)device + sizeof(*device); 42492ee35494Smrg device->nodes = (char **)ptr; 42502ee35494Smrg 42512ee35494Smrg ptr += DRM_NODE_MAX * sizeof(void *); 4252fe517fc9Smrg 4253fe517fc9Smrg for (i = 0; i < DRM_NODE_MAX; i++) { 42542ee35494Smrg device->nodes[i] = ptr; 42552ee35494Smrg ptr += max_node_length; 4256fe517fc9Smrg } 4257fe517fc9Smrg 42582ee35494Smrg memcpy(device->nodes[type], node, max_node_length); 42592ee35494Smrg 42602ee35494Smrg *ptrp = ptr; 42612ee35494Smrg 42622ee35494Smrg return device; 42632ee35494Smrg} 42642ee35494Smrg 42652ee35494Smrgstatic int drmProcessPciDevice(drmDevicePtr *device, 42662ee35494Smrg const char *node, int node_type, 42672ee35494Smrg int maj, int min, bool fetch_deviceinfo, 42682ee35494Smrg uint32_t flags) 42692ee35494Smrg{ 42702ee35494Smrg drmDevicePtr dev; 42712ee35494Smrg char *addr; 42722ee35494Smrg int ret; 42732ee35494Smrg 42742ee35494Smrg dev = drmDeviceAlloc(node_type, node, sizeof(drmPciBusInfo), 42752ee35494Smrg sizeof(drmPciDeviceInfo), &addr); 42762ee35494Smrg if (!dev) 42772ee35494Smrg return -ENOMEM; 42782ee35494Smrg 42792ee35494Smrg dev->bustype = DRM_BUS_PCI; 4280fe517fc9Smrg 42812ee35494Smrg dev->businfo.pci = (drmPciBusInfoPtr)addr; 42822ee35494Smrg 42832ee35494Smrg ret = drmParsePciBusInfo(maj, min, dev->businfo.pci); 4284fe517fc9Smrg if (ret) 4285fe517fc9Smrg goto free_device; 4286fe517fc9Smrg 4287fe517fc9Smrg // Fetch the device info if the user has requested it 4288fe517fc9Smrg if (fetch_deviceinfo) { 4289fe517fc9Smrg addr += sizeof(drmPciBusInfo); 42902ee35494Smrg dev->deviceinfo.pci = (drmPciDeviceInfoPtr)addr; 4291fe517fc9Smrg 42922ee35494Smrg ret = drmParsePciDeviceInfo(maj, min, dev->deviceinfo.pci, flags); 4293fe517fc9Smrg if (ret) 4294fe517fc9Smrg goto free_device; 4295fe517fc9Smrg } 42962ee35494Smrg 42972ee35494Smrg *device = dev; 42982ee35494Smrg 4299fe517fc9Smrg return 0; 4300fe517fc9Smrg 4301fe517fc9Smrgfree_device: 43022ee35494Smrg free(dev); 43032ee35494Smrg return ret; 43042ee35494Smrg} 43052ee35494Smrg 430687bf8e7cSmrg#ifdef __linux__ 430787bf8e7cSmrgstatic int drm_usb_dev_path(int maj, int min, char *path, size_t len) 430887bf8e7cSmrg{ 430987bf8e7cSmrg char *value, *tmp_path, *slash; 4310adfa0b0cSmrg bool usb_device, usb_interface; 431187bf8e7cSmrg 431287bf8e7cSmrg snprintf(path, len, "/sys/dev/char/%d:%d/device", maj, min); 431387bf8e7cSmrg 431487bf8e7cSmrg value = sysfs_uevent_get(path, "DEVTYPE"); 431587bf8e7cSmrg if (!value) 431687bf8e7cSmrg return -ENOENT; 431787bf8e7cSmrg 4318adfa0b0cSmrg usb_device = strcmp(value, "usb_device") == 0; 4319adfa0b0cSmrg usb_interface = strcmp(value, "usb_interface") == 0; 4320adfa0b0cSmrg free(value); 4321adfa0b0cSmrg 4322adfa0b0cSmrg if (usb_device) 432387bf8e7cSmrg return 0; 4324adfa0b0cSmrg if (!usb_interface) 432587bf8e7cSmrg return -ENOTSUP; 432687bf8e7cSmrg 432787bf8e7cSmrg /* The parent of a usb_interface is a usb_device */ 432887bf8e7cSmrg 432987bf8e7cSmrg tmp_path = realpath(path, NULL); 433087bf8e7cSmrg if (!tmp_path) 433187bf8e7cSmrg return -errno; 433287bf8e7cSmrg 433387bf8e7cSmrg slash = strrchr(tmp_path, '/'); 433487bf8e7cSmrg if (!slash) { 433587bf8e7cSmrg free(tmp_path); 433687bf8e7cSmrg return -EINVAL; 433787bf8e7cSmrg } 433887bf8e7cSmrg 433987bf8e7cSmrg *slash = '\0'; 434087bf8e7cSmrg 434187bf8e7cSmrg if (snprintf(path, len, "%s", tmp_path) >= (int)len) { 434287bf8e7cSmrg free(tmp_path); 434387bf8e7cSmrg return -EINVAL; 434487bf8e7cSmrg } 434587bf8e7cSmrg 434687bf8e7cSmrg free(tmp_path); 434787bf8e7cSmrg return 0; 434887bf8e7cSmrg} 434987bf8e7cSmrg#endif 435087bf8e7cSmrg 43512ee35494Smrgstatic int drmParseUsbBusInfo(int maj, int min, drmUsbBusInfoPtr info) 43522ee35494Smrg{ 43532ee35494Smrg#ifdef __linux__ 43542ee35494Smrg char path[PATH_MAX + 1], *value; 43552ee35494Smrg unsigned int bus, dev; 43562ee35494Smrg int ret; 43572ee35494Smrg 435887bf8e7cSmrg ret = drm_usb_dev_path(maj, min, path, sizeof(path)); 435987bf8e7cSmrg if (ret < 0) 436087bf8e7cSmrg return ret; 43612ee35494Smrg 43622ee35494Smrg value = sysfs_uevent_get(path, "BUSNUM"); 43632ee35494Smrg if (!value) 43642ee35494Smrg return -ENOENT; 43652ee35494Smrg 43662ee35494Smrg ret = sscanf(value, "%03u", &bus); 43672ee35494Smrg free(value); 43682ee35494Smrg 43692ee35494Smrg if (ret <= 0) 43702ee35494Smrg return -errno; 43712ee35494Smrg 43722ee35494Smrg value = sysfs_uevent_get(path, "DEVNUM"); 43732ee35494Smrg if (!value) 43742ee35494Smrg return -ENOENT; 43752ee35494Smrg 43762ee35494Smrg ret = sscanf(value, "%03u", &dev); 43772ee35494Smrg free(value); 43782ee35494Smrg 43792ee35494Smrg if (ret <= 0) 43802ee35494Smrg return -errno; 43812ee35494Smrg 43822ee35494Smrg info->bus = bus; 43832ee35494Smrg info->dev = dev; 43842ee35494Smrg 43852ee35494Smrg return 0; 43862ee35494Smrg#else 43872ee35494Smrg#warning "Missing implementation of drmParseUsbBusInfo" 43882ee35494Smrg return -EINVAL; 43892ee35494Smrg#endif 43902ee35494Smrg} 43912ee35494Smrg 43922ee35494Smrgstatic int drmParseUsbDeviceInfo(int maj, int min, drmUsbDeviceInfoPtr info) 43932ee35494Smrg{ 43942ee35494Smrg#ifdef __linux__ 43952ee35494Smrg char path[PATH_MAX + 1], *value; 43962ee35494Smrg unsigned int vendor, product; 43972ee35494Smrg int ret; 43982ee35494Smrg 439987bf8e7cSmrg ret = drm_usb_dev_path(maj, min, path, sizeof(path)); 440087bf8e7cSmrg if (ret < 0) 440187bf8e7cSmrg return ret; 44022ee35494Smrg 44032ee35494Smrg value = sysfs_uevent_get(path, "PRODUCT"); 44042ee35494Smrg if (!value) 44052ee35494Smrg return -ENOENT; 44062ee35494Smrg 44072ee35494Smrg ret = sscanf(value, "%x/%x", &vendor, &product); 44082ee35494Smrg free(value); 44092ee35494Smrg 44102ee35494Smrg if (ret <= 0) 44112ee35494Smrg return -errno; 44122ee35494Smrg 44132ee35494Smrg info->vendor = vendor; 44142ee35494Smrg info->product = product; 44152ee35494Smrg 44162ee35494Smrg return 0; 44172ee35494Smrg#else 44182ee35494Smrg#warning "Missing implementation of drmParseUsbDeviceInfo" 44192ee35494Smrg return -EINVAL; 44202ee35494Smrg#endif 44212ee35494Smrg} 44222ee35494Smrg 44232ee35494Smrgstatic int drmProcessUsbDevice(drmDevicePtr *device, const char *node, 44242ee35494Smrg int node_type, int maj, int min, 44252ee35494Smrg bool fetch_deviceinfo, uint32_t flags) 44262ee35494Smrg{ 44272ee35494Smrg drmDevicePtr dev; 44282ee35494Smrg char *ptr; 44292ee35494Smrg int ret; 44302ee35494Smrg 44312ee35494Smrg dev = drmDeviceAlloc(node_type, node, sizeof(drmUsbBusInfo), 44322ee35494Smrg sizeof(drmUsbDeviceInfo), &ptr); 44332ee35494Smrg if (!dev) 44342ee35494Smrg return -ENOMEM; 44352ee35494Smrg 44362ee35494Smrg dev->bustype = DRM_BUS_USB; 44372ee35494Smrg 44382ee35494Smrg dev->businfo.usb = (drmUsbBusInfoPtr)ptr; 44392ee35494Smrg 44402ee35494Smrg ret = drmParseUsbBusInfo(maj, min, dev->businfo.usb); 44412ee35494Smrg if (ret < 0) 44422ee35494Smrg goto free_device; 44432ee35494Smrg 44442ee35494Smrg if (fetch_deviceinfo) { 44452ee35494Smrg ptr += sizeof(drmUsbBusInfo); 44462ee35494Smrg dev->deviceinfo.usb = (drmUsbDeviceInfoPtr)ptr; 44472ee35494Smrg 44482ee35494Smrg ret = drmParseUsbDeviceInfo(maj, min, dev->deviceinfo.usb); 44492ee35494Smrg if (ret < 0) 44502ee35494Smrg goto free_device; 44512ee35494Smrg } 44522ee35494Smrg 44532ee35494Smrg *device = dev; 44542ee35494Smrg 44552ee35494Smrg return 0; 44562ee35494Smrg 44572ee35494Smrgfree_device: 44582ee35494Smrg free(dev); 44592ee35494Smrg return ret; 44602ee35494Smrg} 44612ee35494Smrg 4462bf6cc7dcSmrgstatic int drmParseOFBusInfo(int maj, int min, char *fullname) 44632ee35494Smrg{ 44642ee35494Smrg#ifdef __linux__ 4465bf6cc7dcSmrg char path[PATH_MAX + 1], *name, *tmp_name; 44662ee35494Smrg 44672ee35494Smrg snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min); 44682ee35494Smrg 44692ee35494Smrg name = sysfs_uevent_get(path, "OF_FULLNAME"); 4470bf6cc7dcSmrg tmp_name = name; 4471bf6cc7dcSmrg if (!name) { 4472bf6cc7dcSmrg /* If the device lacks OF data, pick the MODALIAS info */ 4473bf6cc7dcSmrg name = sysfs_uevent_get(path, "MODALIAS"); 4474bf6cc7dcSmrg if (!name) 4475bf6cc7dcSmrg return -ENOENT; 4476bf6cc7dcSmrg 4477bf6cc7dcSmrg /* .. and strip the MODALIAS=[platform,usb...]: part. */ 4478bf6cc7dcSmrg tmp_name = strrchr(name, ':'); 4479bf6cc7dcSmrg if (!tmp_name) { 4480bf6cc7dcSmrg free(name); 4481bf6cc7dcSmrg return -ENOENT; 4482bf6cc7dcSmrg } 4483bf6cc7dcSmrg tmp_name++; 4484bf6cc7dcSmrg } 44852ee35494Smrg 4486bf6cc7dcSmrg strncpy(fullname, tmp_name, DRM_PLATFORM_DEVICE_NAME_LEN); 4487bf6cc7dcSmrg fullname[DRM_PLATFORM_DEVICE_NAME_LEN - 1] = '\0'; 44882ee35494Smrg free(name); 44892ee35494Smrg 44902ee35494Smrg return 0; 44912ee35494Smrg#else 4492bf6cc7dcSmrg#warning "Missing implementation of drmParseOFBusInfo" 44932ee35494Smrg return -EINVAL; 44942ee35494Smrg#endif 44952ee35494Smrg} 44962ee35494Smrg 4497bf6cc7dcSmrgstatic int drmParseOFDeviceInfo(int maj, int min, char ***compatible) 44982ee35494Smrg{ 44992ee35494Smrg#ifdef __linux__ 4500bf6cc7dcSmrg char path[PATH_MAX + 1], *value, *tmp_name; 45012ee35494Smrg unsigned int count, i; 45022ee35494Smrg int err; 45032ee35494Smrg 45042ee35494Smrg snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min); 45052ee35494Smrg 45062ee35494Smrg value = sysfs_uevent_get(path, "OF_COMPATIBLE_N"); 4507bf6cc7dcSmrg if (value) { 4508bf6cc7dcSmrg sscanf(value, "%u", &count); 4509bf6cc7dcSmrg free(value); 4510bf6cc7dcSmrg } else { 4511bf6cc7dcSmrg /* Assume one entry if the device lack OF data */ 4512bf6cc7dcSmrg count = 1; 4513bf6cc7dcSmrg } 45142ee35494Smrg 4515bf6cc7dcSmrg *compatible = calloc(count + 1, sizeof(char *)); 4516bf6cc7dcSmrg if (!*compatible) 45172ee35494Smrg return -ENOMEM; 45182ee35494Smrg 45192ee35494Smrg for (i = 0; i < count; i++) { 45202ee35494Smrg value = sysfs_uevent_get(path, "OF_COMPATIBLE_%u", i); 4521bf6cc7dcSmrg tmp_name = value; 45222ee35494Smrg if (!value) { 4523bf6cc7dcSmrg /* If the device lacks OF data, pick the MODALIAS info */ 4524bf6cc7dcSmrg value = sysfs_uevent_get(path, "MODALIAS"); 4525bf6cc7dcSmrg if (!value) { 4526bf6cc7dcSmrg err = -ENOENT; 4527bf6cc7dcSmrg goto free; 4528bf6cc7dcSmrg } 4529bf6cc7dcSmrg 4530bf6cc7dcSmrg /* .. and strip the MODALIAS=[platform,usb...]: part. */ 4531bf6cc7dcSmrg tmp_name = strrchr(value, ':'); 4532bf6cc7dcSmrg if (!tmp_name) { 4533bf6cc7dcSmrg free(value); 4534bf6cc7dcSmrg return -ENOENT; 4535bf6cc7dcSmrg } 4536bf6cc7dcSmrg tmp_name = strdup(tmp_name + 1); 4537bf6cc7dcSmrg free(value); 45382ee35494Smrg } 45392ee35494Smrg 4540bf6cc7dcSmrg (*compatible)[i] = tmp_name; 45412ee35494Smrg } 45422ee35494Smrg 45432ee35494Smrg return 0; 45442ee35494Smrg 45452ee35494Smrgfree: 45462ee35494Smrg while (i--) 4547bf6cc7dcSmrg free((*compatible)[i]); 45482ee35494Smrg 4549bf6cc7dcSmrg free(*compatible); 45502ee35494Smrg return err; 45512ee35494Smrg#else 4552bf6cc7dcSmrg#warning "Missing implementation of drmParseOFDeviceInfo" 45532ee35494Smrg return -EINVAL; 45542ee35494Smrg#endif 45552ee35494Smrg} 45562ee35494Smrg 45572ee35494Smrgstatic int drmProcessPlatformDevice(drmDevicePtr *device, 45582ee35494Smrg const char *node, int node_type, 45592ee35494Smrg int maj, int min, bool fetch_deviceinfo, 45602ee35494Smrg uint32_t flags) 45612ee35494Smrg{ 45622ee35494Smrg drmDevicePtr dev; 45632ee35494Smrg char *ptr; 45642ee35494Smrg int ret; 45652ee35494Smrg 45662ee35494Smrg dev = drmDeviceAlloc(node_type, node, sizeof(drmPlatformBusInfo), 45672ee35494Smrg sizeof(drmPlatformDeviceInfo), &ptr); 45682ee35494Smrg if (!dev) 45692ee35494Smrg return -ENOMEM; 45702ee35494Smrg 45712ee35494Smrg dev->bustype = DRM_BUS_PLATFORM; 45722ee35494Smrg 45732ee35494Smrg dev->businfo.platform = (drmPlatformBusInfoPtr)ptr; 45742ee35494Smrg 4575bf6cc7dcSmrg ret = drmParseOFBusInfo(maj, min, dev->businfo.platform->fullname); 45762ee35494Smrg if (ret < 0) 45772ee35494Smrg goto free_device; 45782ee35494Smrg 45792ee35494Smrg if (fetch_deviceinfo) { 45802ee35494Smrg ptr += sizeof(drmPlatformBusInfo); 45812ee35494Smrg dev->deviceinfo.platform = (drmPlatformDeviceInfoPtr)ptr; 45822ee35494Smrg 4583bf6cc7dcSmrg ret = drmParseOFDeviceInfo(maj, min, &dev->deviceinfo.platform->compatible); 45842ee35494Smrg if (ret < 0) 45852ee35494Smrg goto free_device; 45862ee35494Smrg } 45872ee35494Smrg 45882ee35494Smrg *device = dev; 45892ee35494Smrg 45902ee35494Smrg return 0; 45912ee35494Smrg 45922ee35494Smrgfree_device: 45932ee35494Smrg free(dev); 45942ee35494Smrg return ret; 45952ee35494Smrg} 45962ee35494Smrg 45972ee35494Smrgstatic int drmProcessHost1xDevice(drmDevicePtr *device, 45982ee35494Smrg const char *node, int node_type, 45992ee35494Smrg int maj, int min, bool fetch_deviceinfo, 46002ee35494Smrg uint32_t flags) 46012ee35494Smrg{ 46022ee35494Smrg drmDevicePtr dev; 46032ee35494Smrg char *ptr; 46042ee35494Smrg int ret; 46052ee35494Smrg 46062ee35494Smrg dev = drmDeviceAlloc(node_type, node, sizeof(drmHost1xBusInfo), 46072ee35494Smrg sizeof(drmHost1xDeviceInfo), &ptr); 46082ee35494Smrg if (!dev) 46092ee35494Smrg return -ENOMEM; 46102ee35494Smrg 46112ee35494Smrg dev->bustype = DRM_BUS_HOST1X; 46122ee35494Smrg 46132ee35494Smrg dev->businfo.host1x = (drmHost1xBusInfoPtr)ptr; 46142ee35494Smrg 4615bf6cc7dcSmrg ret = drmParseOFBusInfo(maj, min, dev->businfo.host1x->fullname); 46162ee35494Smrg if (ret < 0) 46172ee35494Smrg goto free_device; 46182ee35494Smrg 46192ee35494Smrg if (fetch_deviceinfo) { 46202ee35494Smrg ptr += sizeof(drmHost1xBusInfo); 46212ee35494Smrg dev->deviceinfo.host1x = (drmHost1xDeviceInfoPtr)ptr; 46222ee35494Smrg 4623bf6cc7dcSmrg ret = drmParseOFDeviceInfo(maj, min, &dev->deviceinfo.host1x->compatible); 46242ee35494Smrg if (ret < 0) 46252ee35494Smrg goto free_device; 46262ee35494Smrg } 46272ee35494Smrg 46282ee35494Smrg *device = dev; 46292ee35494Smrg 46302ee35494Smrg return 0; 46312ee35494Smrg 46322ee35494Smrgfree_device: 46332ee35494Smrg free(dev); 4634fe517fc9Smrg return ret; 4635fe517fc9Smrg} 4636fe517fc9Smrg 46376260e5d5Smrgstatic int 46386260e5d5Smrgprocess_device(drmDevicePtr *device, const char *d_name, 46396260e5d5Smrg int req_subsystem_type, 46406260e5d5Smrg bool fetch_deviceinfo, uint32_t flags) 46416260e5d5Smrg{ 46426260e5d5Smrg struct stat sbuf; 46436260e5d5Smrg char node[PATH_MAX + 1]; 464448246ce7Smrg int node_type, subsystem_type, written; 46456260e5d5Smrg unsigned int maj, min; 464648246ce7Smrg const int max_node_length = ALIGN(drmGetMaxNodeName(), sizeof(void *)); 46476260e5d5Smrg 46486260e5d5Smrg node_type = drmGetNodeType(d_name); 46496260e5d5Smrg if (node_type < 0) 46506260e5d5Smrg return -1; 46516260e5d5Smrg 465248246ce7Smrg written = snprintf(node, PATH_MAX, "%s/%s", DRM_DIR_NAME, d_name); 465348246ce7Smrg if (written < 0) 465448246ce7Smrg return -1; 465548246ce7Smrg 465648246ce7Smrg /* anything longer than this will be truncated in drmDeviceAlloc. 465748246ce7Smrg * Account for NULL byte 465848246ce7Smrg */ 465948246ce7Smrg if (written + 1 > max_node_length) 466048246ce7Smrg return -1; 466148246ce7Smrg 46626260e5d5Smrg if (stat(node, &sbuf)) 46636260e5d5Smrg return -1; 46646260e5d5Smrg 46656260e5d5Smrg maj = major(sbuf.st_rdev); 46666260e5d5Smrg min = minor(sbuf.st_rdev); 46676260e5d5Smrg 46686260e5d5Smrg if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode)) 46696260e5d5Smrg return -1; 46706260e5d5Smrg 46716260e5d5Smrg subsystem_type = drmParseSubsystemType(maj, min); 46726260e5d5Smrg if (req_subsystem_type != -1 && req_subsystem_type != subsystem_type) 46736260e5d5Smrg return -1; 46746260e5d5Smrg 46756260e5d5Smrg switch (subsystem_type) { 46766260e5d5Smrg case DRM_BUS_PCI: 46776260e5d5Smrg case DRM_BUS_VIRTIO: 46786260e5d5Smrg return drmProcessPciDevice(device, node, node_type, maj, min, 46796260e5d5Smrg fetch_deviceinfo, flags); 46806260e5d5Smrg case DRM_BUS_USB: 46816260e5d5Smrg return drmProcessUsbDevice(device, node, node_type, maj, min, 46826260e5d5Smrg fetch_deviceinfo, flags); 46836260e5d5Smrg case DRM_BUS_PLATFORM: 46846260e5d5Smrg return drmProcessPlatformDevice(device, node, node_type, maj, min, 46856260e5d5Smrg fetch_deviceinfo, flags); 46866260e5d5Smrg case DRM_BUS_HOST1X: 46876260e5d5Smrg return drmProcessHost1xDevice(device, node, node_type, maj, min, 46886260e5d5Smrg fetch_deviceinfo, flags); 46896260e5d5Smrg default: 46906260e5d5Smrg return -1; 46916260e5d5Smrg } 46926260e5d5Smrg} 46936260e5d5Smrg 4694fe517fc9Smrg/* Consider devices located on the same bus as duplicate and fold the respective 4695fe517fc9Smrg * entries into a single one. 4696fe517fc9Smrg * 4697fe517fc9Smrg * Note: this leaves "gaps" in the array, while preserving the length. 4698fe517fc9Smrg */ 4699fe517fc9Smrgstatic void drmFoldDuplicatedDevices(drmDevicePtr local_devices[], int count) 4700fe517fc9Smrg{ 4701fe517fc9Smrg int node_type, i, j; 4702fe517fc9Smrg 4703fe517fc9Smrg for (i = 0; i < count; i++) { 4704fe517fc9Smrg for (j = i + 1; j < count; j++) { 47050655efefSmrg if (drmDevicesEqual(local_devices[i], local_devices[j])) { 4706fe517fc9Smrg local_devices[i]->available_nodes |= local_devices[j]->available_nodes; 47074b3d3f37Smrg node_type = log2_int(local_devices[j]->available_nodes); 4708fe517fc9Smrg memcpy(local_devices[i]->nodes[node_type], 4709fe517fc9Smrg local_devices[j]->nodes[node_type], drmGetMaxNodeName()); 4710fe517fc9Smrg drmFreeDevice(&local_devices[j]); 4711fe517fc9Smrg } 4712fe517fc9Smrg } 4713fe517fc9Smrg } 4714fe517fc9Smrg} 4715fe517fc9Smrg 47162ee35494Smrg/* Check that the given flags are valid returning 0 on success */ 47172ee35494Smrgstatic int 47182ee35494Smrgdrm_device_validate_flags(uint32_t flags) 47192ee35494Smrg{ 47202ee35494Smrg return (flags & ~DRM_DEVICE_GET_PCI_REVISION); 47212ee35494Smrg} 47222ee35494Smrg 47236260e5d5Smrgstatic bool 47246260e5d5Smrgdrm_device_has_rdev(drmDevicePtr device, dev_t find_rdev) 47256260e5d5Smrg{ 47266260e5d5Smrg struct stat sbuf; 47276260e5d5Smrg 47286260e5d5Smrg for (int i = 0; i < DRM_NODE_MAX; i++) { 47296260e5d5Smrg if (device->available_nodes & 1 << i) { 47306260e5d5Smrg if (stat(device->nodes[i], &sbuf) == 0 && 47316260e5d5Smrg sbuf.st_rdev == find_rdev) 47326260e5d5Smrg return true; 47336260e5d5Smrg } 47346260e5d5Smrg } 47356260e5d5Smrg return false; 47366260e5d5Smrg} 47376260e5d5Smrg 47386260e5d5Smrg/* 47396260e5d5Smrg * The kernel drm core has a number of places that assume maximum of 47406260e5d5Smrg * 3x64 devices nodes. That's 64 for each of primary, control and 47416260e5d5Smrg * render nodes. Rounded it up to 256 for simplicity. 47426260e5d5Smrg */ 47436260e5d5Smrg#define MAX_DRM_NODES 256 47446260e5d5Smrg 4745fe517fc9Smrg/** 4746adfa0b0cSmrg * Get information about a device from its dev_t identifier 4747fe517fc9Smrg * 4748adfa0b0cSmrg * \param find_rdev dev_t identifier of the device 47492ee35494Smrg * \param flags feature/behaviour bitmask 4750fe517fc9Smrg * \param device the address of a drmDevicePtr where the information 4751fe517fc9Smrg * will be allocated in stored 4752fe517fc9Smrg * 4753fe517fc9Smrg * \return zero on success, negative error code otherwise. 4754fe517fc9Smrg */ 4755adfa0b0cSmrgdrm_public int drmGetDeviceFromDevId(dev_t find_rdev, uint32_t flags, drmDevicePtr *device) 4756fe517fc9Smrg{ 47572ee35494Smrg#ifdef __OpenBSD__ 47582ee35494Smrg /* 47592ee35494Smrg * DRI device nodes on OpenBSD are not in their own directory, they reside 47602ee35494Smrg * in /dev along with a large number of statically generated /dev nodes. 47612ee35494Smrg * Avoid stat'ing all of /dev needlessly by implementing this custom path. 47622ee35494Smrg */ 47632ee35494Smrg drmDevicePtr d; 47642ee35494Smrg char node[PATH_MAX + 1]; 47652ee35494Smrg const char *dev_name; 47662ee35494Smrg int node_type, subsystem_type; 476782025ec7Smrg int maj, min, n, ret; 476848246ce7Smrg const int max_node_length = ALIGN(drmGetMaxNodeName(), sizeof(void *)); 476948246ce7Smrg struct stat sbuf; 47702ee35494Smrg 4771adfa0b0cSmrg if (device == NULL) 47722ee35494Smrg return -EINVAL; 47732ee35494Smrg 4774adfa0b0cSmrg maj = major(find_rdev); 4775adfa0b0cSmrg min = minor(find_rdev); 47762ee35494Smrg 4777adfa0b0cSmrg if (!drmNodeIsDRM(maj, min)) 47782ee35494Smrg return -EINVAL; 47792ee35494Smrg 478087bf8e7cSmrg node_type = drmGetMinorType(maj, min); 47812ee35494Smrg if (node_type == -1) 47822ee35494Smrg return -ENODEV; 47832ee35494Smrg 478482025ec7Smrg dev_name = drmGetDeviceName(node_type); 478582025ec7Smrg if (!dev_name) 47862ee35494Smrg return -EINVAL; 47872ee35494Smrg 478848246ce7Smrg /* anything longer than this will be truncated in drmDeviceAlloc. 478948246ce7Smrg * Account for NULL byte 479048246ce7Smrg */ 479182025ec7Smrg n = snprintf(node, PATH_MAX, dev_name, DRM_DIR_NAME, min); 47922ee35494Smrg if (n == -1 || n >= PATH_MAX) 47932ee35494Smrg return -errno; 479448246ce7Smrg if (n + 1 > max_node_length) 479548246ce7Smrg return -EINVAL; 47962ee35494Smrg if (stat(node, &sbuf)) 47972ee35494Smrg return -EINVAL; 47982ee35494Smrg 47992ee35494Smrg subsystem_type = drmParseSubsystemType(maj, min); 48002ee35494Smrg if (subsystem_type != DRM_BUS_PCI) 48012ee35494Smrg return -ENODEV; 48022ee35494Smrg 48032ee35494Smrg ret = drmProcessPciDevice(&d, node, node_type, maj, min, true, flags); 48042ee35494Smrg if (ret) 48052ee35494Smrg return ret; 48062ee35494Smrg 48072ee35494Smrg *device = d; 48082ee35494Smrg 48092ee35494Smrg return 0; 48102ee35494Smrg#else 48116260e5d5Smrg drmDevicePtr local_devices[MAX_DRM_NODES]; 4812fe517fc9Smrg drmDevicePtr d; 4813fe517fc9Smrg DIR *sysdir; 4814fe517fc9Smrg struct dirent *dent; 48156260e5d5Smrg int subsystem_type; 4816fe517fc9Smrg int maj, min; 4817fe517fc9Smrg int ret, i, node_count; 4818fe517fc9Smrg 48192ee35494Smrg if (drm_device_validate_flags(flags)) 48202ee35494Smrg return -EINVAL; 48212ee35494Smrg 4822adfa0b0cSmrg if (device == NULL) 4823fe517fc9Smrg return -EINVAL; 4824fe517fc9Smrg 4825adfa0b0cSmrg maj = major(find_rdev); 4826adfa0b0cSmrg min = minor(find_rdev); 4827fe517fc9Smrg 4828adfa0b0cSmrg if (!drmNodeIsDRM(maj, min)) 4829fe517fc9Smrg return -EINVAL; 4830fe517fc9Smrg 4831fe517fc9Smrg subsystem_type = drmParseSubsystemType(maj, min); 48326260e5d5Smrg if (subsystem_type < 0) 48336260e5d5Smrg return subsystem_type; 4834fe517fc9Smrg 4835fe517fc9Smrg sysdir = opendir(DRM_DIR_NAME); 48366260e5d5Smrg if (!sysdir) 48376260e5d5Smrg return -errno; 4838fe517fc9Smrg 4839fe517fc9Smrg i = 0; 4840fe517fc9Smrg while ((dent = readdir(sysdir))) { 48416260e5d5Smrg ret = process_device(&d, dent->d_name, subsystem_type, true, flags); 48426260e5d5Smrg if (ret) 4843fe517fc9Smrg continue; 4844fe517fc9Smrg 48456260e5d5Smrg if (i >= MAX_DRM_NODES) { 48466260e5d5Smrg fprintf(stderr, "More than %d drm nodes detected. " 48476260e5d5Smrg "Please report a bug - that should not happen.\n" 48486260e5d5Smrg "Skipping extra nodes\n", MAX_DRM_NODES); 4849fe517fc9Smrg break; 4850fe517fc9Smrg } 48516260e5d5Smrg local_devices[i] = d; 4852fe517fc9Smrg i++; 4853fe517fc9Smrg } 4854fe517fc9Smrg node_count = i; 4855fe517fc9Smrg 4856fe517fc9Smrg drmFoldDuplicatedDevices(local_devices, node_count); 4857fe517fc9Smrg 48586260e5d5Smrg *device = NULL; 48596260e5d5Smrg 48606260e5d5Smrg for (i = 0; i < node_count; i++) { 48616260e5d5Smrg if (!local_devices[i]) 48626260e5d5Smrg continue; 48636260e5d5Smrg 48646260e5d5Smrg if (drm_device_has_rdev(local_devices[i], find_rdev)) 48656260e5d5Smrg *device = local_devices[i]; 48666260e5d5Smrg else 48676260e5d5Smrg drmFreeDevice(&local_devices[i]); 48686260e5d5Smrg } 4869fe517fc9Smrg 4870fe517fc9Smrg closedir(sysdir); 48712ee35494Smrg if (*device == NULL) 48722ee35494Smrg return -ENODEV; 4873fe517fc9Smrg return 0; 48742ee35494Smrg#endif 48752ee35494Smrg} 48762ee35494Smrg 487748246ce7Smrgdrm_public int drmGetNodeTypeFromDevId(dev_t devid) 487848246ce7Smrg{ 487948246ce7Smrg int maj, min, node_type; 488048246ce7Smrg 488148246ce7Smrg maj = major(devid); 488248246ce7Smrg min = minor(devid); 488348246ce7Smrg 488448246ce7Smrg if (!drmNodeIsDRM(maj, min)) 488548246ce7Smrg return -EINVAL; 488648246ce7Smrg 488748246ce7Smrg node_type = drmGetMinorType(maj, min); 488848246ce7Smrg if (node_type == -1) 488948246ce7Smrg return -ENODEV; 489048246ce7Smrg 489148246ce7Smrg return node_type; 489248246ce7Smrg} 489348246ce7Smrg 4894adfa0b0cSmrg/** 4895adfa0b0cSmrg * Get information about the opened drm device 4896adfa0b0cSmrg * 4897adfa0b0cSmrg * \param fd file descriptor of the drm device 4898adfa0b0cSmrg * \param flags feature/behaviour bitmask 4899adfa0b0cSmrg * \param device the address of a drmDevicePtr where the information 4900adfa0b0cSmrg * will be allocated in stored 4901adfa0b0cSmrg * 4902adfa0b0cSmrg * \return zero on success, negative error code otherwise. 4903adfa0b0cSmrg * 4904adfa0b0cSmrg * \note Unlike drmGetDevice it does not retrieve the pci device revision field 4905adfa0b0cSmrg * unless the DRM_DEVICE_GET_PCI_REVISION \p flag is set. 4906adfa0b0cSmrg */ 4907adfa0b0cSmrgdrm_public int drmGetDevice2(int fd, uint32_t flags, drmDevicePtr *device) 4908adfa0b0cSmrg{ 4909adfa0b0cSmrg struct stat sbuf; 4910adfa0b0cSmrg 4911adfa0b0cSmrg if (fd == -1) 4912adfa0b0cSmrg return -EINVAL; 4913adfa0b0cSmrg 4914adfa0b0cSmrg if (fstat(fd, &sbuf)) 4915adfa0b0cSmrg return -errno; 4916adfa0b0cSmrg 4917adfa0b0cSmrg if (!S_ISCHR(sbuf.st_mode)) 4918adfa0b0cSmrg return -EINVAL; 4919adfa0b0cSmrg 4920adfa0b0cSmrg return drmGetDeviceFromDevId(sbuf.st_rdev, flags, device); 4921adfa0b0cSmrg} 4922adfa0b0cSmrg 49232ee35494Smrg/** 49242ee35494Smrg * Get information about the opened drm device 49252ee35494Smrg * 49262ee35494Smrg * \param fd file descriptor of the drm device 49272ee35494Smrg * \param device the address of a drmDevicePtr where the information 49282ee35494Smrg * will be allocated in stored 49292ee35494Smrg * 49302ee35494Smrg * \return zero on success, negative error code otherwise. 49312ee35494Smrg */ 49326260e5d5Smrgdrm_public int drmGetDevice(int fd, drmDevicePtr *device) 49332ee35494Smrg{ 49342ee35494Smrg return drmGetDevice2(fd, DRM_DEVICE_GET_PCI_REVISION, device); 4935fe517fc9Smrg} 4936fe517fc9Smrg 4937fe517fc9Smrg/** 4938fe517fc9Smrg * Get drm devices on the system 4939fe517fc9Smrg * 49402ee35494Smrg * \param flags feature/behaviour bitmask 4941fe517fc9Smrg * \param devices the array of devices with drmDevicePtr elements 4942fe517fc9Smrg * can be NULL to get the device number first 4943fe517fc9Smrg * \param max_devices the maximum number of devices for the array 4944fe517fc9Smrg * 4945fe517fc9Smrg * \return on error - negative error code, 4946fe517fc9Smrg * if devices is NULL - total number of devices available on the system, 4947fe517fc9Smrg * alternatively the number of devices stored in devices[], which is 4948fe517fc9Smrg * capped by the max_devices. 49492ee35494Smrg * 49502ee35494Smrg * \note Unlike drmGetDevices it does not retrieve the pci device revision field 49512ee35494Smrg * unless the DRM_DEVICE_GET_PCI_REVISION \p flag is set. 4952fe517fc9Smrg */ 49536260e5d5Smrgdrm_public int drmGetDevices2(uint32_t flags, drmDevicePtr devices[], 49546260e5d5Smrg int max_devices) 4955fe517fc9Smrg{ 49566260e5d5Smrg drmDevicePtr local_devices[MAX_DRM_NODES]; 4957fe517fc9Smrg drmDevicePtr device; 4958fe517fc9Smrg DIR *sysdir; 4959fe517fc9Smrg struct dirent *dent; 4960fe517fc9Smrg int ret, i, node_count, device_count; 4961fe517fc9Smrg 49622ee35494Smrg if (drm_device_validate_flags(flags)) 49632ee35494Smrg return -EINVAL; 49642ee35494Smrg 4965fe517fc9Smrg sysdir = opendir(DRM_DIR_NAME); 49666260e5d5Smrg if (!sysdir) 49676260e5d5Smrg return -errno; 4968fe517fc9Smrg 4969fe517fc9Smrg i = 0; 4970fe517fc9Smrg while ((dent = readdir(sysdir))) { 49716260e5d5Smrg ret = process_device(&device, dent->d_name, -1, devices != NULL, flags); 49726260e5d5Smrg if (ret) 4973fe517fc9Smrg continue; 4974fe517fc9Smrg 49756260e5d5Smrg if (i >= MAX_DRM_NODES) { 49766260e5d5Smrg fprintf(stderr, "More than %d drm nodes detected. " 49776260e5d5Smrg "Please report a bug - that should not happen.\n" 49786260e5d5Smrg "Skipping extra nodes\n", MAX_DRM_NODES); 49792ee35494Smrg break; 4980fe517fc9Smrg } 4981fe517fc9Smrg local_devices[i] = device; 4982fe517fc9Smrg i++; 4983fe517fc9Smrg } 4984fe517fc9Smrg node_count = i; 4985fe517fc9Smrg 4986fe517fc9Smrg drmFoldDuplicatedDevices(local_devices, node_count); 4987fe517fc9Smrg 4988fe517fc9Smrg device_count = 0; 4989fe517fc9Smrg for (i = 0; i < node_count; i++) { 4990fe517fc9Smrg if (!local_devices[i]) 4991fe517fc9Smrg continue; 4992fe517fc9Smrg 4993fe517fc9Smrg if ((devices != NULL) && (device_count < max_devices)) 4994fe517fc9Smrg devices[device_count] = local_devices[i]; 4995fe517fc9Smrg else 4996fe517fc9Smrg drmFreeDevice(&local_devices[i]); 4997fe517fc9Smrg 4998fe517fc9Smrg device_count++; 4999fe517fc9Smrg } 5000fe517fc9Smrg 5001fe517fc9Smrg closedir(sysdir); 50024b3d3f37Smrg 50034b3d3f37Smrg if (devices != NULL) 50044b3d3f37Smrg return MIN2(device_count, max_devices); 50054b3d3f37Smrg 5006fe517fc9Smrg return device_count; 5007424e9256Smrg} 50082ee35494Smrg 50092ee35494Smrg/** 50102ee35494Smrg * Get drm devices on the system 50112ee35494Smrg * 50122ee35494Smrg * \param devices the array of devices with drmDevicePtr elements 50132ee35494Smrg * can be NULL to get the device number first 50142ee35494Smrg * \param max_devices the maximum number of devices for the array 50152ee35494Smrg * 50162ee35494Smrg * \return on error - negative error code, 50172ee35494Smrg * if devices is NULL - total number of devices available on the system, 50182ee35494Smrg * alternatively the number of devices stored in devices[], which is 50192ee35494Smrg * capped by the max_devices. 50202ee35494Smrg */ 50216260e5d5Smrgdrm_public int drmGetDevices(drmDevicePtr devices[], int max_devices) 50222ee35494Smrg{ 50232ee35494Smrg return drmGetDevices2(DRM_DEVICE_GET_PCI_REVISION, devices, max_devices); 50242ee35494Smrg} 50252ee35494Smrg 50266260e5d5Smrgdrm_public char *drmGetDeviceNameFromFd2(int fd) 50272ee35494Smrg{ 50282ee35494Smrg#ifdef __linux__ 50292ee35494Smrg struct stat sbuf; 50302ee35494Smrg char path[PATH_MAX + 1], *value; 50312ee35494Smrg unsigned int maj, min; 50322ee35494Smrg 50332ee35494Smrg if (fstat(fd, &sbuf)) 50342ee35494Smrg return NULL; 50352ee35494Smrg 50362ee35494Smrg maj = major(sbuf.st_rdev); 50372ee35494Smrg min = minor(sbuf.st_rdev); 50382ee35494Smrg 50396260e5d5Smrg if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode)) 50402ee35494Smrg return NULL; 50412ee35494Smrg 50422ee35494Smrg snprintf(path, sizeof(path), "/sys/dev/char/%d:%d", maj, min); 50432ee35494Smrg 50442ee35494Smrg value = sysfs_uevent_get(path, "DEVNAME"); 50452ee35494Smrg if (!value) 50462ee35494Smrg return NULL; 50472ee35494Smrg 50482ee35494Smrg snprintf(path, sizeof(path), "/dev/%s", value); 50492ee35494Smrg free(value); 50502ee35494Smrg 50512ee35494Smrg return strdup(path); 50524b3d3f37Smrg#elif defined(__FreeBSD__) 505387bf8e7cSmrg return drmGetDeviceNameFromFd(fd); 50542ee35494Smrg#else 50552ee35494Smrg struct stat sbuf; 50562ee35494Smrg char node[PATH_MAX + 1]; 50572ee35494Smrg const char *dev_name; 50582ee35494Smrg int node_type; 505982025ec7Smrg int maj, min, n; 50602ee35494Smrg 50612ee35494Smrg if (fstat(fd, &sbuf)) 50622ee35494Smrg return NULL; 50632ee35494Smrg 50642ee35494Smrg maj = major(sbuf.st_rdev); 50652ee35494Smrg min = minor(sbuf.st_rdev); 50662ee35494Smrg 50676260e5d5Smrg if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode)) 50682ee35494Smrg return NULL; 50692ee35494Smrg 507087bf8e7cSmrg node_type = drmGetMinorType(maj, min); 50712ee35494Smrg if (node_type == -1) 50722ee35494Smrg return NULL; 50732ee35494Smrg 507482025ec7Smrg dev_name = drmGetDeviceName(node_type); 507582025ec7Smrg if (!dev_name) 50762ee35494Smrg return NULL; 50772ee35494Smrg 507882025ec7Smrg n = snprintf(node, PATH_MAX, dev_name, DRM_DIR_NAME, min); 50792ee35494Smrg if (n == -1 || n >= PATH_MAX) 50802ee35494Smrg return NULL; 50812ee35494Smrg 50822ee35494Smrg return strdup(node); 50832ee35494Smrg#endif 50842ee35494Smrg} 50850655efefSmrg 50866260e5d5Smrgdrm_public int drmSyncobjCreate(int fd, uint32_t flags, uint32_t *handle) 50870655efefSmrg{ 50880655efefSmrg struct drm_syncobj_create args; 50890655efefSmrg int ret; 50900655efefSmrg 50910655efefSmrg memclear(args); 50920655efefSmrg args.flags = flags; 50930655efefSmrg args.handle = 0; 50940655efefSmrg ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_CREATE, &args); 50950655efefSmrg if (ret) 50962b90624aSmrg return ret; 50970655efefSmrg *handle = args.handle; 50980655efefSmrg return 0; 50990655efefSmrg} 51000655efefSmrg 51016260e5d5Smrgdrm_public int drmSyncobjDestroy(int fd, uint32_t handle) 51020655efefSmrg{ 51030655efefSmrg struct drm_syncobj_destroy args; 51040655efefSmrg 51050655efefSmrg memclear(args); 51060655efefSmrg args.handle = handle; 51070655efefSmrg return drmIoctl(fd, DRM_IOCTL_SYNCOBJ_DESTROY, &args); 51080655efefSmrg} 51090655efefSmrg 51106260e5d5Smrgdrm_public int drmSyncobjHandleToFD(int fd, uint32_t handle, int *obj_fd) 51110655efefSmrg{ 51120655efefSmrg struct drm_syncobj_handle args; 51130655efefSmrg int ret; 51140655efefSmrg 51150655efefSmrg memclear(args); 51160655efefSmrg args.fd = -1; 51170655efefSmrg args.handle = handle; 51180655efefSmrg ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD, &args); 51190655efefSmrg if (ret) 51202b90624aSmrg return ret; 51210655efefSmrg *obj_fd = args.fd; 51220655efefSmrg return 0; 51230655efefSmrg} 51240655efefSmrg 51256260e5d5Smrgdrm_public int drmSyncobjFDToHandle(int fd, int obj_fd, uint32_t *handle) 51260655efefSmrg{ 51270655efefSmrg struct drm_syncobj_handle args; 51280655efefSmrg int ret; 51290655efefSmrg 51300655efefSmrg memclear(args); 51310655efefSmrg args.fd = obj_fd; 51320655efefSmrg args.handle = 0; 51330655efefSmrg ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE, &args); 51340655efefSmrg if (ret) 51352b90624aSmrg return ret; 51360655efefSmrg *handle = args.handle; 51370655efefSmrg return 0; 51380655efefSmrg} 51390655efefSmrg 51406260e5d5Smrgdrm_public int drmSyncobjImportSyncFile(int fd, uint32_t handle, 51416260e5d5Smrg int sync_file_fd) 51420655efefSmrg{ 51430655efefSmrg struct drm_syncobj_handle args; 51440655efefSmrg 51450655efefSmrg memclear(args); 51460655efefSmrg args.fd = sync_file_fd; 51470655efefSmrg args.handle = handle; 51480655efefSmrg args.flags = DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_IMPORT_SYNC_FILE; 51490655efefSmrg return drmIoctl(fd, DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE, &args); 51500655efefSmrg} 51510655efefSmrg 51526260e5d5Smrgdrm_public int drmSyncobjExportSyncFile(int fd, uint32_t handle, 51536260e5d5Smrg int *sync_file_fd) 51540655efefSmrg{ 51550655efefSmrg struct drm_syncobj_handle args; 51560655efefSmrg int ret; 51570655efefSmrg 51580655efefSmrg memclear(args); 51590655efefSmrg args.fd = -1; 51600655efefSmrg args.handle = handle; 51610655efefSmrg args.flags = DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_EXPORT_SYNC_FILE; 51620655efefSmrg ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD, &args); 51630655efefSmrg if (ret) 51642b90624aSmrg return ret; 51650655efefSmrg *sync_file_fd = args.fd; 51660655efefSmrg return 0; 51670655efefSmrg} 51682b90624aSmrg 51696260e5d5Smrgdrm_public int drmSyncobjWait(int fd, uint32_t *handles, unsigned num_handles, 51706260e5d5Smrg int64_t timeout_nsec, unsigned flags, 51716260e5d5Smrg uint32_t *first_signaled) 51722b90624aSmrg{ 51732b90624aSmrg struct drm_syncobj_wait args; 51742b90624aSmrg int ret; 51752b90624aSmrg 51762b90624aSmrg memclear(args); 51772b90624aSmrg args.handles = (uintptr_t)handles; 51782b90624aSmrg args.timeout_nsec = timeout_nsec; 51792b90624aSmrg args.count_handles = num_handles; 51802b90624aSmrg args.flags = flags; 51812b90624aSmrg 51822b90624aSmrg ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_WAIT, &args); 51832b90624aSmrg if (ret < 0) 51842b90624aSmrg return -errno; 51852b90624aSmrg 51862b90624aSmrg if (first_signaled) 51872b90624aSmrg *first_signaled = args.first_signaled; 51882b90624aSmrg return ret; 51892b90624aSmrg} 51902b90624aSmrg 51916260e5d5Smrgdrm_public int drmSyncobjReset(int fd, const uint32_t *handles, 51926260e5d5Smrg uint32_t handle_count) 51932b90624aSmrg{ 51942b90624aSmrg struct drm_syncobj_array args; 51952b90624aSmrg int ret; 51962b90624aSmrg 51972b90624aSmrg memclear(args); 51982b90624aSmrg args.handles = (uintptr_t)handles; 51992b90624aSmrg args.count_handles = handle_count; 52002b90624aSmrg 52012b90624aSmrg ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_RESET, &args); 52022b90624aSmrg return ret; 52032b90624aSmrg} 52042b90624aSmrg 52056260e5d5Smrgdrm_public int drmSyncobjSignal(int fd, const uint32_t *handles, 52066260e5d5Smrg uint32_t handle_count) 52072b90624aSmrg{ 52082b90624aSmrg struct drm_syncobj_array args; 52092b90624aSmrg int ret; 52102b90624aSmrg 52112b90624aSmrg memclear(args); 52122b90624aSmrg args.handles = (uintptr_t)handles; 52132b90624aSmrg args.count_handles = handle_count; 52142b90624aSmrg 52152b90624aSmrg ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_SIGNAL, &args); 52162b90624aSmrg return ret; 52172b90624aSmrg} 5218bf6cc7dcSmrg 5219bf6cc7dcSmrgdrm_public int drmSyncobjTimelineSignal(int fd, const uint32_t *handles, 5220bf6cc7dcSmrg uint64_t *points, uint32_t handle_count) 5221bf6cc7dcSmrg{ 5222bf6cc7dcSmrg struct drm_syncobj_timeline_array args; 5223bf6cc7dcSmrg int ret; 5224bf6cc7dcSmrg 5225bf6cc7dcSmrg memclear(args); 5226bf6cc7dcSmrg args.handles = (uintptr_t)handles; 5227bf6cc7dcSmrg args.points = (uintptr_t)points; 5228bf6cc7dcSmrg args.count_handles = handle_count; 5229bf6cc7dcSmrg 5230bf6cc7dcSmrg ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_TIMELINE_SIGNAL, &args); 5231bf6cc7dcSmrg return ret; 5232bf6cc7dcSmrg} 5233bf6cc7dcSmrg 5234bf6cc7dcSmrgdrm_public int drmSyncobjTimelineWait(int fd, uint32_t *handles, uint64_t *points, 5235bf6cc7dcSmrg unsigned num_handles, 5236bf6cc7dcSmrg int64_t timeout_nsec, unsigned flags, 5237bf6cc7dcSmrg uint32_t *first_signaled) 5238bf6cc7dcSmrg{ 5239bf6cc7dcSmrg struct drm_syncobj_timeline_wait args; 5240bf6cc7dcSmrg int ret; 5241bf6cc7dcSmrg 5242bf6cc7dcSmrg memclear(args); 5243bf6cc7dcSmrg args.handles = (uintptr_t)handles; 5244bf6cc7dcSmrg args.points = (uintptr_t)points; 5245bf6cc7dcSmrg args.timeout_nsec = timeout_nsec; 5246bf6cc7dcSmrg args.count_handles = num_handles; 5247bf6cc7dcSmrg args.flags = flags; 5248bf6cc7dcSmrg 5249bf6cc7dcSmrg ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_TIMELINE_WAIT, &args); 5250bf6cc7dcSmrg if (ret < 0) 5251bf6cc7dcSmrg return -errno; 5252bf6cc7dcSmrg 5253bf6cc7dcSmrg if (first_signaled) 5254bf6cc7dcSmrg *first_signaled = args.first_signaled; 5255bf6cc7dcSmrg return ret; 5256bf6cc7dcSmrg} 5257bf6cc7dcSmrg 5258bf6cc7dcSmrg 5259bf6cc7dcSmrgdrm_public int drmSyncobjQuery(int fd, uint32_t *handles, uint64_t *points, 5260bf6cc7dcSmrg uint32_t handle_count) 5261bf6cc7dcSmrg{ 5262bf6cc7dcSmrg struct drm_syncobj_timeline_array args; 5263bf6cc7dcSmrg int ret; 5264bf6cc7dcSmrg 5265bf6cc7dcSmrg memclear(args); 5266bf6cc7dcSmrg args.handles = (uintptr_t)handles; 5267bf6cc7dcSmrg args.points = (uintptr_t)points; 5268bf6cc7dcSmrg args.count_handles = handle_count; 5269bf6cc7dcSmrg 5270bf6cc7dcSmrg ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_QUERY, &args); 5271bf6cc7dcSmrg if (ret) 5272bf6cc7dcSmrg return ret; 5273bf6cc7dcSmrg return 0; 5274bf6cc7dcSmrg} 5275bf6cc7dcSmrg 527687bf8e7cSmrgdrm_public int drmSyncobjQuery2(int fd, uint32_t *handles, uint64_t *points, 527787bf8e7cSmrg uint32_t handle_count, uint32_t flags) 527887bf8e7cSmrg{ 527987bf8e7cSmrg struct drm_syncobj_timeline_array args; 528087bf8e7cSmrg 528187bf8e7cSmrg memclear(args); 528287bf8e7cSmrg args.handles = (uintptr_t)handles; 528387bf8e7cSmrg args.points = (uintptr_t)points; 528487bf8e7cSmrg args.count_handles = handle_count; 528587bf8e7cSmrg args.flags = flags; 528687bf8e7cSmrg 528787bf8e7cSmrg return drmIoctl(fd, DRM_IOCTL_SYNCOBJ_QUERY, &args); 528887bf8e7cSmrg} 528987bf8e7cSmrg 529087bf8e7cSmrg 5291bf6cc7dcSmrgdrm_public int drmSyncobjTransfer(int fd, 5292bf6cc7dcSmrg uint32_t dst_handle, uint64_t dst_point, 5293bf6cc7dcSmrg uint32_t src_handle, uint64_t src_point, 5294bf6cc7dcSmrg uint32_t flags) 5295bf6cc7dcSmrg{ 5296bf6cc7dcSmrg struct drm_syncobj_transfer args; 5297bf6cc7dcSmrg int ret; 5298bf6cc7dcSmrg 5299bf6cc7dcSmrg memclear(args); 5300bf6cc7dcSmrg args.src_handle = src_handle; 5301bf6cc7dcSmrg args.dst_handle = dst_handle; 5302bf6cc7dcSmrg args.src_point = src_point; 5303bf6cc7dcSmrg args.dst_point = dst_point; 5304bf6cc7dcSmrg args.flags = flags; 5305bf6cc7dcSmrg 5306bf6cc7dcSmrg ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_TRANSFER, &args); 5307bf6cc7dcSmrg 5308bf6cc7dcSmrg return ret; 5309bf6cc7dcSmrg} 5310636d5e9fSmrg 531148246ce7Smrgdrm_public int drmSyncobjEventfd(int fd, uint32_t handle, uint64_t point, int ev_fd, 531248246ce7Smrg uint32_t flags) 531348246ce7Smrg{ 531448246ce7Smrg struct drm_syncobj_eventfd args; 531548246ce7Smrg 531648246ce7Smrg memclear(args); 531748246ce7Smrg args.handle = handle; 531848246ce7Smrg args.point = point; 531948246ce7Smrg args.fd = ev_fd; 532048246ce7Smrg args.flags = flags; 532148246ce7Smrg 532248246ce7Smrg return drmIoctl(fd, DRM_IOCTL_SYNCOBJ_EVENTFD, &args); 532348246ce7Smrg} 532448246ce7Smrg 5325636d5e9fSmrgstatic char * 5326636d5e9fSmrgdrmGetFormatModifierFromSimpleTokens(uint64_t modifier) 5327636d5e9fSmrg{ 5328636d5e9fSmrg unsigned int i; 5329636d5e9fSmrg 5330636d5e9fSmrg for (i = 0; i < ARRAY_SIZE(drm_format_modifier_table); i++) { 5331636d5e9fSmrg if (drm_format_modifier_table[i].modifier == modifier) 5332636d5e9fSmrg return strdup(drm_format_modifier_table[i].modifier_name); 5333636d5e9fSmrg } 5334636d5e9fSmrg 5335636d5e9fSmrg return NULL; 5336636d5e9fSmrg} 5337636d5e9fSmrg 5338636d5e9fSmrg/** Retrieves a human-readable representation of a vendor (as a string) from 5339636d5e9fSmrg * the format token modifier 5340636d5e9fSmrg * 5341636d5e9fSmrg * \param modifier the format modifier token 5342636d5e9fSmrg * \return a char pointer to the human-readable form of the vendor. Caller is 5343636d5e9fSmrg * responsible for freeing it. 5344636d5e9fSmrg */ 5345636d5e9fSmrgdrm_public char * 5346636d5e9fSmrgdrmGetFormatModifierVendor(uint64_t modifier) 5347636d5e9fSmrg{ 5348636d5e9fSmrg unsigned int i; 5349636d5e9fSmrg uint8_t vendor = fourcc_mod_get_vendor(modifier); 5350636d5e9fSmrg 5351636d5e9fSmrg for (i = 0; i < ARRAY_SIZE(drm_format_modifier_vendor_table); i++) { 5352636d5e9fSmrg if (drm_format_modifier_vendor_table[i].vendor == vendor) 5353636d5e9fSmrg return strdup(drm_format_modifier_vendor_table[i].vendor_name); 5354636d5e9fSmrg } 5355636d5e9fSmrg 5356636d5e9fSmrg return NULL; 5357636d5e9fSmrg} 5358636d5e9fSmrg 5359636d5e9fSmrg/** Retrieves a human-readable representation string from a format token 5360636d5e9fSmrg * modifier 5361636d5e9fSmrg * 5362636d5e9fSmrg * If the dedicated function was not able to extract a valid name or searching 5363636d5e9fSmrg * the format modifier was not in the table, this function would return NULL. 5364636d5e9fSmrg * 5365636d5e9fSmrg * \param modifier the token format 5366636d5e9fSmrg * \return a malloc'ed string representation of the modifier. Caller is 5367636d5e9fSmrg * responsible for freeing the string returned. 5368636d5e9fSmrg * 5369636d5e9fSmrg */ 5370636d5e9fSmrgdrm_public char * 5371636d5e9fSmrgdrmGetFormatModifierName(uint64_t modifier) 5372636d5e9fSmrg{ 5373636d5e9fSmrg uint8_t vendorid = fourcc_mod_get_vendor(modifier); 5374636d5e9fSmrg char *modifier_found = NULL; 5375636d5e9fSmrg unsigned int i; 5376636d5e9fSmrg 5377636d5e9fSmrg for (i = 0; i < ARRAY_SIZE(modifier_format_vendor_table); i++) { 5378636d5e9fSmrg if (modifier_format_vendor_table[i].vendor == vendorid) 5379636d5e9fSmrg modifier_found = modifier_format_vendor_table[i].vendor_cb(modifier); 5380636d5e9fSmrg } 5381636d5e9fSmrg 5382636d5e9fSmrg if (!modifier_found) 5383636d5e9fSmrg return drmGetFormatModifierFromSimpleTokens(modifier); 5384636d5e9fSmrg 5385636d5e9fSmrg return modifier_found; 5386636d5e9fSmrg} 53873b115362Smrg 53883b115362Smrg/** 53893b115362Smrg * Get a human-readable name for a DRM FourCC format. 53903b115362Smrg * 53913b115362Smrg * \param format The format. 53923b115362Smrg * \return A malloc'ed string containing the format name. Caller is responsible 53933b115362Smrg * for freeing it. 53943b115362Smrg */ 53953b115362Smrgdrm_public char * 53963b115362SmrgdrmGetFormatName(uint32_t format) 53973b115362Smrg{ 53983b115362Smrg char *str, code[5]; 53993b115362Smrg const char *be; 54003b115362Smrg size_t str_size, i; 54013b115362Smrg 54023b115362Smrg be = (format & DRM_FORMAT_BIG_ENDIAN) ? "_BE" : ""; 54033b115362Smrg format &= ~DRM_FORMAT_BIG_ENDIAN; 54043b115362Smrg 54053b115362Smrg if (format == DRM_FORMAT_INVALID) 54063b115362Smrg return strdup("INVALID"); 54073b115362Smrg 54083b115362Smrg code[0] = (char) ((format >> 0) & 0xFF); 54093b115362Smrg code[1] = (char) ((format >> 8) & 0xFF); 54103b115362Smrg code[2] = (char) ((format >> 16) & 0xFF); 54113b115362Smrg code[3] = (char) ((format >> 24) & 0xFF); 54123b115362Smrg code[4] = '\0'; 54133b115362Smrg 54143b115362Smrg /* Trim spaces at the end */ 54153b115362Smrg for (i = 3; i > 0 && code[i] == ' '; i--) 54163b115362Smrg code[i] = '\0'; 54173b115362Smrg 54183b115362Smrg str_size = strlen(code) + strlen(be) + 1; 54193b115362Smrg str = malloc(str_size); 54203b115362Smrg if (!str) 54213b115362Smrg return NULL; 54223b115362Smrg 54233b115362Smrg snprintf(str, str_size, "%s%s", code, be); 54243b115362Smrg 54253b115362Smrg return str; 54263b115362Smrg} 5427