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 208adfa0b0cSmrgstatic bool 209adfa0b0cSmrgdrmGetAfbcFormatModifierNameFromArm(uint64_t modifier, FILE *fp) 210636d5e9fSmrg{ 211636d5e9fSmrg uint64_t mode_value = modifier & AFBC_FORMAT_MOD_MODE_VALUE_MASK; 212636d5e9fSmrg uint64_t block_size = mode_value & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK; 213636d5e9fSmrg 214636d5e9fSmrg const char *block = NULL; 215636d5e9fSmrg const char *mode = NULL; 216636d5e9fSmrg bool did_print_mode = false; 217636d5e9fSmrg 218636d5e9fSmrg /* add block, can only have a (single) block */ 219636d5e9fSmrg switch (block_size) { 220636d5e9fSmrg case AFBC_FORMAT_MOD_BLOCK_SIZE_16x16: 221636d5e9fSmrg block = "16x16"; 222636d5e9fSmrg break; 223636d5e9fSmrg case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8: 224636d5e9fSmrg block = "32x8"; 225636d5e9fSmrg break; 226636d5e9fSmrg case AFBC_FORMAT_MOD_BLOCK_SIZE_64x4: 227636d5e9fSmrg block = "64x4"; 228636d5e9fSmrg break; 229636d5e9fSmrg case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8_64x4: 230636d5e9fSmrg block = "32x8_64x4"; 231636d5e9fSmrg break; 232636d5e9fSmrg } 233636d5e9fSmrg 234636d5e9fSmrg if (!block) { 235adfa0b0cSmrg return false; 236636d5e9fSmrg } 237636d5e9fSmrg 238636d5e9fSmrg fprintf(fp, "BLOCK_SIZE=%s,", block); 239636d5e9fSmrg 240636d5e9fSmrg /* add mode */ 241adfa0b0cSmrg for (unsigned int i = 0; i < ARRAY_SIZE(arm_mode_value_table); i++) { 242636d5e9fSmrg if (arm_mode_value_table[i].modifier & mode_value) { 243636d5e9fSmrg mode = arm_mode_value_table[i].modifier_name; 244636d5e9fSmrg if (!did_print_mode) { 245636d5e9fSmrg fprintf(fp, "MODE=%s", mode); 246636d5e9fSmrg did_print_mode = true; 247636d5e9fSmrg } else { 248636d5e9fSmrg fprintf(fp, "|%s", mode); 249636d5e9fSmrg } 250636d5e9fSmrg } 251636d5e9fSmrg } 252636d5e9fSmrg 253adfa0b0cSmrg return true; 254adfa0b0cSmrg} 255adfa0b0cSmrg 256adfa0b0cSmrgstatic bool 257adfa0b0cSmrgdrmGetAfrcFormatModifierNameFromArm(uint64_t modifier, FILE *fp) 258adfa0b0cSmrg{ 25950027b5bSmrg bool scan_layout; 260adfa0b0cSmrg for (unsigned int i = 0; i < 2; ++i) { 261adfa0b0cSmrg uint64_t coding_unit_block = 262adfa0b0cSmrg (modifier >> (i * 4)) & AFRC_FORMAT_MOD_CU_SIZE_MASK; 263adfa0b0cSmrg const char *coding_unit_size = NULL; 264adfa0b0cSmrg 265adfa0b0cSmrg switch (coding_unit_block) { 266adfa0b0cSmrg case AFRC_FORMAT_MOD_CU_SIZE_16: 267adfa0b0cSmrg coding_unit_size = "CU_16"; 268adfa0b0cSmrg break; 269adfa0b0cSmrg case AFRC_FORMAT_MOD_CU_SIZE_24: 270adfa0b0cSmrg coding_unit_size = "CU_24"; 271adfa0b0cSmrg break; 272adfa0b0cSmrg case AFRC_FORMAT_MOD_CU_SIZE_32: 273adfa0b0cSmrg coding_unit_size = "CU_32"; 274adfa0b0cSmrg break; 275adfa0b0cSmrg } 276adfa0b0cSmrg 277adfa0b0cSmrg if (!coding_unit_size) { 278adfa0b0cSmrg if (i == 0) { 279adfa0b0cSmrg return false; 280adfa0b0cSmrg } 281adfa0b0cSmrg break; 282adfa0b0cSmrg } 283adfa0b0cSmrg 284adfa0b0cSmrg if (i == 0) { 285adfa0b0cSmrg fprintf(fp, "P0=%s,", coding_unit_size); 286adfa0b0cSmrg } else { 287adfa0b0cSmrg fprintf(fp, "P12=%s,", coding_unit_size); 288adfa0b0cSmrg } 289adfa0b0cSmrg } 290adfa0b0cSmrg 29150027b5bSmrg scan_layout = 292adfa0b0cSmrg (modifier & AFRC_FORMAT_MOD_LAYOUT_SCAN) == AFRC_FORMAT_MOD_LAYOUT_SCAN; 293adfa0b0cSmrg if (scan_layout) { 294adfa0b0cSmrg fprintf(fp, "SCAN"); 295adfa0b0cSmrg } else { 296adfa0b0cSmrg fprintf(fp, "ROT"); 297adfa0b0cSmrg } 298adfa0b0cSmrg return true; 299adfa0b0cSmrg} 300adfa0b0cSmrg 301adfa0b0cSmrgstatic char * 302adfa0b0cSmrgdrmGetFormatModifierNameFromArm(uint64_t modifier) 303adfa0b0cSmrg{ 304adfa0b0cSmrg uint64_t type = (modifier >> 52) & 0xf; 305adfa0b0cSmrg 306adfa0b0cSmrg FILE *fp; 307adfa0b0cSmrg size_t size = 0; 308adfa0b0cSmrg char *modifier_name = NULL; 309adfa0b0cSmrg bool result = false; 310adfa0b0cSmrg 311adfa0b0cSmrg fp = open_memstream(&modifier_name, &size); 312adfa0b0cSmrg if (!fp) 313adfa0b0cSmrg return NULL; 314adfa0b0cSmrg 315adfa0b0cSmrg switch (type) { 316adfa0b0cSmrg case DRM_FORMAT_MOD_ARM_TYPE_AFBC: 317adfa0b0cSmrg result = drmGetAfbcFormatModifierNameFromArm(modifier, fp); 318adfa0b0cSmrg break; 319adfa0b0cSmrg case DRM_FORMAT_MOD_ARM_TYPE_AFRC: 320adfa0b0cSmrg result = drmGetAfrcFormatModifierNameFromArm(modifier, fp); 321adfa0b0cSmrg break; 322adfa0b0cSmrg /* misc type is already handled by the static table */ 323adfa0b0cSmrg case DRM_FORMAT_MOD_ARM_TYPE_MISC: 324adfa0b0cSmrg default: 325adfa0b0cSmrg result = false; 326adfa0b0cSmrg break; 327adfa0b0cSmrg } 328adfa0b0cSmrg 329636d5e9fSmrg fclose(fp); 330adfa0b0cSmrg if (!result) { 331adfa0b0cSmrg free(modifier_name); 332adfa0b0cSmrg return NULL; 333adfa0b0cSmrg } 334adfa0b0cSmrg 335636d5e9fSmrg return modifier_name; 336636d5e9fSmrg} 337636d5e9fSmrg 338636d5e9fSmrgstatic char * 339636d5e9fSmrgdrmGetFormatModifierNameFromNvidia(uint64_t modifier) 340636d5e9fSmrg{ 341636d5e9fSmrg uint64_t height, kind, gen, sector, compression; 342636d5e9fSmrg 343636d5e9fSmrg height = modifier & 0xf; 344636d5e9fSmrg kind = (modifier >> 12) & 0xff; 345636d5e9fSmrg 346636d5e9fSmrg gen = (modifier >> 20) & 0x3; 347636d5e9fSmrg sector = (modifier >> 22) & 0x1; 348636d5e9fSmrg compression = (modifier >> 23) & 0x7; 349636d5e9fSmrg 350636d5e9fSmrg /* just in case there could other simpler modifiers, not yet added, avoid 351636d5e9fSmrg * testing against TEGRA_TILE */ 352636d5e9fSmrg if ((modifier & 0x10) == 0x10) { 353636d5e9fSmrg char *mod_nvidia; 354636d5e9fSmrg asprintf(&mod_nvidia, "BLOCK_LINEAR_2D,HEIGHT=%"PRIu64",KIND=%"PRIu64"," 355636d5e9fSmrg "GEN=%"PRIu64",SECTOR=%"PRIu64",COMPRESSION=%"PRIu64"", height, 356636d5e9fSmrg kind, gen, sector, compression); 357636d5e9fSmrg return mod_nvidia; 358636d5e9fSmrg } 359636d5e9fSmrg 360636d5e9fSmrg return NULL; 361636d5e9fSmrg} 362636d5e9fSmrg 363636d5e9fSmrgstatic char * 364636d5e9fSmrgdrmGetFormatModifierNameFromAmd(uint64_t modifier) 365636d5e9fSmrg{ 366b0b61055Smrg static const char *gfx9_gfx11_tile_strings[32] = { 367b0b61055Smrg "LINEAR", 368b0b61055Smrg "256B_S", 369b0b61055Smrg "256B_D", 370b0b61055Smrg "256B_R", 371b0b61055Smrg "4KB_Z", 372b0b61055Smrg "4KB_S", 373b0b61055Smrg "4KB_D", 374b0b61055Smrg "4KB_R", 375b0b61055Smrg "64KB_Z", 376b0b61055Smrg "64KB_S", 377b0b61055Smrg "64KB_D", 378b0b61055Smrg "64KB_R", 379b0b61055Smrg "INVALID12", 380b0b61055Smrg "INVALID13", 381b0b61055Smrg "INVALID14", 382b0b61055Smrg "INVALID15", 383b0b61055Smrg "64KB_Z_T", 384b0b61055Smrg "64KB_S_T", 385b0b61055Smrg "64KB_D_T", 386b0b61055Smrg "64KB_R_T", 387b0b61055Smrg "4KB_Z_X", 388b0b61055Smrg "4KB_S_X", 389b0b61055Smrg "4KB_D_X", 390b0b61055Smrg "4KB_R_X", 391b0b61055Smrg "64KB_Z_X", 392b0b61055Smrg "64KB_S_X", 393b0b61055Smrg "64KB_D_X", 394b0b61055Smrg "64KB_R_X", 395b0b61055Smrg "256KB_Z_X", 396b0b61055Smrg "256KB_S_X", 397b0b61055Smrg "256KB_D_X", 398b0b61055Smrg "256KB_R_X", 399b0b61055Smrg }; 400b0b61055Smrg static const char *gfx12_tile_strings[32] = { 401b0b61055Smrg "LINEAR", 402b0b61055Smrg "256B_2D", 403b0b61055Smrg "4KB_2D", 404b0b61055Smrg "64KB_2D", 405b0b61055Smrg "256KB_2D", 406b0b61055Smrg "4KB_3D", 407b0b61055Smrg "64KB_3D", 408b0b61055Smrg "256KB_3D", 409b0b61055Smrg /* other values are unused */ 410b0b61055Smrg }; 411b0b61055Smrg uint64_t tile_version = AMD_FMT_MOD_GET(TILE_VERSION, modifier); 412636d5e9fSmrg FILE *fp; 413636d5e9fSmrg char *mod_amd = NULL; 414636d5e9fSmrg size_t size = 0; 415636d5e9fSmrg 416636d5e9fSmrg fp = open_memstream(&mod_amd, &size); 417636d5e9fSmrg if (!fp) 418636d5e9fSmrg return NULL; 419636d5e9fSmrg 420636d5e9fSmrg switch (tile_version) { 421636d5e9fSmrg case AMD_FMT_MOD_TILE_VER_GFX9: 422b0b61055Smrg fprintf(fp, "GFX9"); 423636d5e9fSmrg break; 424636d5e9fSmrg case AMD_FMT_MOD_TILE_VER_GFX10: 425b0b61055Smrg fprintf(fp, "GFX10"); 426636d5e9fSmrg break; 427636d5e9fSmrg case AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS: 428b0b61055Smrg fprintf(fp, "GFX10_RBPLUS"); 429636d5e9fSmrg break; 43048246ce7Smrg case AMD_FMT_MOD_TILE_VER_GFX11: 431b0b61055Smrg fprintf(fp, "GFX11"); 43248246ce7Smrg break; 433b0b61055Smrg case AMD_FMT_MOD_TILE_VER_GFX12: 434b0b61055Smrg fprintf(fp, "GFX12"); 435b0b61055Smrg break; 436b0b61055Smrg default: 437636d5e9fSmrg fclose(fp); 438636d5e9fSmrg free(mod_amd); 439636d5e9fSmrg return NULL; 440636d5e9fSmrg } 441636d5e9fSmrg 442b0b61055Smrg if (tile_version >= AMD_FMT_MOD_TILE_VER_GFX12) { 443b0b61055Smrg unsigned tile = AMD_FMT_MOD_GET(TILE, modifier); 444b0b61055Smrg 445b0b61055Smrg fprintf(fp, ",%s", gfx12_tile_strings[tile]); 446636d5e9fSmrg 447b0b61055Smrg if (AMD_FMT_MOD_GET(DCC, modifier)) { 448b0b61055Smrg fprintf(fp, ",DCC,DCC_MAX_COMPRESSED_BLOCK=%uB", 449b0b61055Smrg 64 << AMD_FMT_MOD_GET(DCC_MAX_COMPRESSED_BLOCK, modifier)); 450b0b61055Smrg 451b0b61055Smrg /* Other DCC fields are unused by GFX12. */ 452b0b61055Smrg } 453b0b61055Smrg } else { 454b0b61055Smrg unsigned tile = AMD_FMT_MOD_GET(TILE, modifier); 455b0b61055Smrg 456b0b61055Smrg fprintf(fp, ",%s", gfx9_gfx11_tile_strings[tile]); 457b0b61055Smrg 458b0b61055Smrg /* All *_T and *_X modes are affected by chip-specific fields. */ 459b0b61055Smrg if (tile >= 16) { 460b0b61055Smrg fprintf(fp, ",PIPE_XOR_BITS=%u", 461b0b61055Smrg (unsigned)AMD_FMT_MOD_GET(PIPE_XOR_BITS, modifier)); 462b0b61055Smrg 463b0b61055Smrg switch (tile_version) { 464b0b61055Smrg case AMD_FMT_MOD_TILE_VER_GFX9: 465b0b61055Smrg fprintf(fp, ",BANK_XOR_BITS=%u", 466b0b61055Smrg (unsigned)AMD_FMT_MOD_GET(BANK_XOR_BITS, modifier)); 467b0b61055Smrg break; 468b0b61055Smrg 469b0b61055Smrg case AMD_FMT_MOD_TILE_VER_GFX10: 470b0b61055Smrg /* Nothing else for GFX10. */ 471b0b61055Smrg break; 472b0b61055Smrg 473b0b61055Smrg case AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS: 474b0b61055Smrg case AMD_FMT_MOD_TILE_VER_GFX11: 475b0b61055Smrg /* This also determines the DCC layout, but DCC is only legal 476b0b61055Smrg * with tile=27 and tile=31 (*_R_X modes). 477b0b61055Smrg */ 478b0b61055Smrg fprintf(fp, ",PACKERS=%u", 479b0b61055Smrg (unsigned)AMD_FMT_MOD_GET(PACKERS, modifier)); 480b0b61055Smrg break; 481b0b61055Smrg } 482b0b61055Smrg } 483636d5e9fSmrg 484b0b61055Smrg if (AMD_FMT_MOD_GET(DCC, modifier)) { 485b0b61055Smrg if (tile_version == AMD_FMT_MOD_TILE_VER_GFX9 && 486b0b61055Smrg (AMD_FMT_MOD_GET(DCC_PIPE_ALIGN, modifier) || 487b0b61055Smrg AMD_FMT_MOD_GET(DCC_RETILE, modifier))) { 488b0b61055Smrg /* These two only determine the layout of 489b0b61055Smrg * the non-displayable DCC plane. 490b0b61055Smrg */ 491b0b61055Smrg fprintf(fp, ",RB=%u", 492b0b61055Smrg (unsigned)AMD_FMT_MOD_GET(RB, modifier)); 493b0b61055Smrg fprintf(fp, ",PIPE=%u", 494b0b61055Smrg (unsigned)AMD_FMT_MOD_GET(PIPE, modifier)); 495b0b61055Smrg } 496636d5e9fSmrg 497b0b61055Smrg fprintf(fp, ",DCC,DCC_MAX_COMPRESSED_BLOCK=%uB", 498b0b61055Smrg 64 << AMD_FMT_MOD_GET(DCC_MAX_COMPRESSED_BLOCK, modifier)); 499b0b61055Smrg 500b0b61055Smrg if (AMD_FMT_MOD_GET(DCC_INDEPENDENT_64B, modifier)) 501b0b61055Smrg fprintf(fp, ",DCC_INDEPENDENT_64B"); 502b0b61055Smrg 503b0b61055Smrg if (AMD_FMT_MOD_GET(DCC_INDEPENDENT_128B, modifier)) 504b0b61055Smrg fprintf(fp, ",DCC_INDEPENDENT_128B"); 505b0b61055Smrg 506b0b61055Smrg if (AMD_FMT_MOD_GET(DCC_CONSTANT_ENCODE, modifier)) 507b0b61055Smrg fprintf(fp, ",DCC_CONSTANT_ENCODE"); 508b0b61055Smrg 509b0b61055Smrg if (AMD_FMT_MOD_GET(DCC_PIPE_ALIGN, modifier)) 510b0b61055Smrg fprintf(fp, ",DCC_PIPE_ALIGN"); 511b0b61055Smrg 512b0b61055Smrg if (AMD_FMT_MOD_GET(DCC_RETILE, modifier)) 513b0b61055Smrg fprintf(fp, ",DCC_RETILE"); 514b0b61055Smrg } 515b0b61055Smrg } 516636d5e9fSmrg 517636d5e9fSmrg fclose(fp); 518636d5e9fSmrg return mod_amd; 519636d5e9fSmrg} 520636d5e9fSmrg 521636d5e9fSmrgstatic char * 522636d5e9fSmrgdrmGetFormatModifierNameFromAmlogic(uint64_t modifier) 523636d5e9fSmrg{ 524636d5e9fSmrg uint64_t layout = modifier & 0xff; 525636d5e9fSmrg uint64_t options = (modifier >> 8) & 0xff; 526636d5e9fSmrg char *mod_amlogic = NULL; 527636d5e9fSmrg 528636d5e9fSmrg const char *layout_str; 529636d5e9fSmrg const char *opts_str; 530636d5e9fSmrg 531636d5e9fSmrg switch (layout) { 532636d5e9fSmrg case AMLOGIC_FBC_LAYOUT_BASIC: 533636d5e9fSmrg layout_str = "BASIC"; 534636d5e9fSmrg break; 535636d5e9fSmrg case AMLOGIC_FBC_LAYOUT_SCATTER: 536636d5e9fSmrg layout_str = "SCATTER"; 537636d5e9fSmrg break; 538636d5e9fSmrg default: 539636d5e9fSmrg layout_str = "INVALID_LAYOUT"; 540636d5e9fSmrg break; 541636d5e9fSmrg } 542636d5e9fSmrg 543636d5e9fSmrg if (options & AMLOGIC_FBC_OPTION_MEM_SAVING) 544636d5e9fSmrg opts_str = "MEM_SAVING"; 545636d5e9fSmrg else 546636d5e9fSmrg opts_str = "0"; 547636d5e9fSmrg 548636d5e9fSmrg asprintf(&mod_amlogic, "FBC,LAYOUT=%s,OPTIONS=%s", layout_str, opts_str); 549636d5e9fSmrg return mod_amlogic; 550636d5e9fSmrg} 551636d5e9fSmrg 55248246ce7Smrgstatic char * 55348246ce7SmrgdrmGetFormatModifierNameFromVivante(uint64_t modifier) 55448246ce7Smrg{ 55548246ce7Smrg const char *color_tiling, *tile_status, *compression; 55648246ce7Smrg char *mod_vivante = NULL; 55748246ce7Smrg 55848246ce7Smrg switch (modifier & VIVANTE_MOD_TS_MASK) { 55948246ce7Smrg case 0: 56048246ce7Smrg tile_status = ""; 56148246ce7Smrg break; 56248246ce7Smrg case VIVANTE_MOD_TS_64_4: 56348246ce7Smrg tile_status = ",TS=64B_4"; 56448246ce7Smrg break; 56548246ce7Smrg case VIVANTE_MOD_TS_64_2: 56648246ce7Smrg tile_status = ",TS=64B_2"; 56748246ce7Smrg break; 56848246ce7Smrg case VIVANTE_MOD_TS_128_4: 56948246ce7Smrg tile_status = ",TS=128B_4"; 57048246ce7Smrg break; 57148246ce7Smrg case VIVANTE_MOD_TS_256_4: 57248246ce7Smrg tile_status = ",TS=256B_4"; 57348246ce7Smrg break; 57448246ce7Smrg default: 57548246ce7Smrg tile_status = ",TS=UNKNOWN"; 57648246ce7Smrg break; 57748246ce7Smrg } 57848246ce7Smrg 57948246ce7Smrg switch (modifier & VIVANTE_MOD_COMP_MASK) { 58048246ce7Smrg case 0: 58148246ce7Smrg compression = ""; 58248246ce7Smrg break; 58348246ce7Smrg case VIVANTE_MOD_COMP_DEC400: 58448246ce7Smrg compression = ",COMP=DEC400"; 58548246ce7Smrg break; 58648246ce7Smrg default: 58748246ce7Smrg compression = ",COMP=UNKNOWN"; 58848246ce7Smrg break; 58948246ce7Smrg } 59048246ce7Smrg 59148246ce7Smrg switch (modifier & ~VIVANTE_MOD_EXT_MASK) { 59248246ce7Smrg case 0: 59348246ce7Smrg color_tiling = "LINEAR"; 59448246ce7Smrg break; 59548246ce7Smrg case DRM_FORMAT_MOD_VIVANTE_TILED: 59648246ce7Smrg color_tiling = "TILED"; 59748246ce7Smrg break; 59848246ce7Smrg case DRM_FORMAT_MOD_VIVANTE_SUPER_TILED: 59948246ce7Smrg color_tiling = "SUPER_TILED"; 60048246ce7Smrg break; 60148246ce7Smrg case DRM_FORMAT_MOD_VIVANTE_SPLIT_TILED: 60248246ce7Smrg color_tiling = "SPLIT_TILED"; 60348246ce7Smrg break; 60448246ce7Smrg case DRM_FORMAT_MOD_VIVANTE_SPLIT_SUPER_TILED: 60548246ce7Smrg color_tiling = "SPLIT_SUPER_TILED"; 60648246ce7Smrg break; 60748246ce7Smrg default: 60848246ce7Smrg color_tiling = "UNKNOWN"; 60948246ce7Smrg break; 61048246ce7Smrg } 61148246ce7Smrg 61248246ce7Smrg asprintf(&mod_vivante, "%s%s%s", color_tiling, tile_status, compression); 61348246ce7Smrg return mod_vivante; 61448246ce7Smrg} 61548246ce7Smrg 6164b3d3f37Smrgstatic unsigned log2_int(unsigned x) 6174b3d3f37Smrg{ 6184b3d3f37Smrg unsigned l; 6194b3d3f37Smrg 6204b3d3f37Smrg if (x < 2) { 6214b3d3f37Smrg return 0; 6224b3d3f37Smrg } 6234b3d3f37Smrg for (l = 2; ; l++) { 6244b3d3f37Smrg if ((unsigned)(1 << l) > x) { 6254b3d3f37Smrg return l - 1; 6264b3d3f37Smrg } 6274b3d3f37Smrg } 6284b3d3f37Smrg return 0; 6294b3d3f37Smrg} 6304b3d3f37Smrg 6314b3d3f37Smrg 6326260e5d5Smrgdrm_public void drmSetServerInfo(drmServerInfoPtr info) 63322944501Smrg{ 63422944501Smrg drm_server_info = info; 63522944501Smrg} 63622944501Smrg 63722944501Smrg/** 63822944501Smrg * Output a message to stderr. 63922944501Smrg * 64022944501Smrg * \param format printf() like format string. 64122944501Smrg * 64222944501Smrg * \internal 64322944501Smrg * This function is a wrapper around vfprintf(). 64422944501Smrg */ 64522944501Smrg 646a7d7de1eSmrgstatic int DRM_PRINTFLIKE(1, 0) 647a7d7de1eSmrgdrmDebugPrint(const char *format, va_list ap) 64822944501Smrg{ 64922944501Smrg return vfprintf(stderr, format, ap); 65022944501Smrg} 65122944501Smrg 6526260e5d5Smrgdrm_public void 65322944501SmrgdrmMsg(const char *format, ...) 65422944501Smrg{ 655fe517fc9Smrg va_list ap; 65622944501Smrg const char *env; 657fe517fc9Smrg if (((env = getenv("LIBGL_DEBUG")) && strstr(env, "verbose")) || 658fe517fc9Smrg (drm_server_info && drm_server_info->debug_print)) 65922944501Smrg { 660fe517fc9Smrg va_start(ap, format); 661fe517fc9Smrg if (drm_server_info) { 662fe517fc9Smrg drm_server_info->debug_print(format,ap); 663fe517fc9Smrg } else { 664fe517fc9Smrg drmDebugPrint(format, ap); 665fe517fc9Smrg } 666fe517fc9Smrg va_end(ap); 66722944501Smrg } 66822944501Smrg} 66922944501Smrg 67022944501Smrgstatic void *drmHashTable = NULL; /* Context switch callbacks */ 67122944501Smrg 6726260e5d5Smrgdrm_public void *drmGetHashTable(void) 67322944501Smrg{ 67422944501Smrg return drmHashTable; 67522944501Smrg} 67622944501Smrg 6776260e5d5Smrgdrm_public void *drmMalloc(int size) 67822944501Smrg{ 679424e9256Smrg return calloc(1, size); 68022944501Smrg} 68122944501Smrg 6826260e5d5Smrgdrm_public void drmFree(void *pt) 68322944501Smrg{ 684424e9256Smrg free(pt); 68522944501Smrg} 68622944501Smrg 68722944501Smrg/** 688bf6cc7dcSmrg * Call ioctl, restarting if it is interrupted 68922944501Smrg */ 6906260e5d5Smrgdrm_public int 69122944501SmrgdrmIoctl(int fd, unsigned long request, void *arg) 69222944501Smrg{ 693fe517fc9Smrg int ret; 69422944501Smrg 69522944501Smrg do { 696fe517fc9Smrg ret = ioctl(fd, request, arg); 69722944501Smrg } while (ret == -1 && (errno == EINTR || errno == EAGAIN)); 69822944501Smrg return ret; 69922944501Smrg} 70022944501Smrg 70122944501Smrgstatic unsigned long drmGetKeyFromFd(int fd) 70222944501Smrg{ 70322944501Smrg stat_t st; 70422944501Smrg 70522944501Smrg st.st_rdev = 0; 70622944501Smrg fstat(fd, &st); 70722944501Smrg return st.st_rdev; 70822944501Smrg} 70922944501Smrg 7106260e5d5Smrgdrm_public drmHashEntry *drmGetEntry(int fd) 71122944501Smrg{ 71222944501Smrg unsigned long key = drmGetKeyFromFd(fd); 71322944501Smrg void *value; 71422944501Smrg drmHashEntry *entry; 71522944501Smrg 71622944501Smrg if (!drmHashTable) 717fe517fc9Smrg drmHashTable = drmHashCreate(); 71822944501Smrg 71922944501Smrg if (drmHashLookup(drmHashTable, key, &value)) { 720fe517fc9Smrg entry = drmMalloc(sizeof(*entry)); 721fe517fc9Smrg entry->fd = fd; 722fe517fc9Smrg entry->f = NULL; 723fe517fc9Smrg entry->tagTable = drmHashCreate(); 724fe517fc9Smrg drmHashInsert(drmHashTable, key, entry); 72522944501Smrg } else { 726fe517fc9Smrg entry = value; 72722944501Smrg } 72822944501Smrg return entry; 72922944501Smrg} 73022944501Smrg 73122944501Smrg/** 73222944501Smrg * Compare two busid strings 73322944501Smrg * 73422944501Smrg * \param first 73522944501Smrg * \param second 73622944501Smrg * 73722944501Smrg * \return 1 if matched. 73822944501Smrg * 73922944501Smrg * \internal 74022944501Smrg * This function compares two bus ID strings. It understands the older 74122944501Smrg * PCI:b:d:f format and the newer pci:oooo:bb:dd.f format. In the format, o is 74222944501Smrg * domain, b is bus, d is device, f is function. 74322944501Smrg */ 7446d98c517Smrgstatic int drmMatchBusID(const char *id1, const char *id2, int pci_domain_ok) 74522944501Smrg{ 74622944501Smrg /* First, check if the IDs are exactly the same */ 74722944501Smrg if (strcasecmp(id1, id2) == 0) 748fe517fc9Smrg return 1; 74922944501Smrg 75022944501Smrg /* Try to match old/new-style PCI bus IDs. */ 75122944501Smrg if (strncasecmp(id1, "pci", 3) == 0) { 752fe517fc9Smrg unsigned int o1, b1, d1, f1; 753fe517fc9Smrg unsigned int o2, b2, d2, f2; 754fe517fc9Smrg int ret; 755fe517fc9Smrg 756fe517fc9Smrg ret = sscanf(id1, "pci:%04x:%02x:%02x.%u", &o1, &b1, &d1, &f1); 757fe517fc9Smrg if (ret != 4) { 758fe517fc9Smrg o1 = 0; 759fe517fc9Smrg ret = sscanf(id1, "PCI:%u:%u:%u", &b1, &d1, &f1); 760fe517fc9Smrg if (ret != 3) 761fe517fc9Smrg return 0; 762fe517fc9Smrg } 763fe517fc9Smrg 764fe517fc9Smrg ret = sscanf(id2, "pci:%04x:%02x:%02x.%u", &o2, &b2, &d2, &f2); 765fe517fc9Smrg if (ret != 4) { 766fe517fc9Smrg o2 = 0; 767fe517fc9Smrg ret = sscanf(id2, "PCI:%u:%u:%u", &b2, &d2, &f2); 768fe517fc9Smrg if (ret != 3) 769fe517fc9Smrg return 0; 770fe517fc9Smrg } 771fe517fc9Smrg 772fe517fc9Smrg /* If domains aren't properly supported by the kernel interface, 773fe517fc9Smrg * just ignore them, which sucks less than picking a totally random 774fe517fc9Smrg * card with "open by name" 775fe517fc9Smrg */ 776fe517fc9Smrg if (!pci_domain_ok) 777fe517fc9Smrg o1 = o2 = 0; 778fe517fc9Smrg 779fe517fc9Smrg if ((o1 != o2) || (b1 != b2) || (d1 != d2) || (f1 != f2)) 780fe517fc9Smrg return 0; 781fe517fc9Smrg else 782fe517fc9Smrg return 1; 78322944501Smrg } 78422944501Smrg return 0; 78522944501Smrg} 78622944501Smrg 78722944501Smrg/** 78822944501Smrg * Handles error checking for chown call. 78922944501Smrg * 79022944501Smrg * \param path to file. 79122944501Smrg * \param id of the new owner. 79222944501Smrg * \param id of the new group. 79322944501Smrg * 79422944501Smrg * \return zero if success or -1 if failure. 79522944501Smrg * 79622944501Smrg * \internal 79722944501Smrg * Checks for failure. If failure was caused by signal call chown again. 798bf6cc7dcSmrg * If any other failure happened then it will output error message using 79922944501Smrg * drmMsg() call. 80022944501Smrg */ 8016260e5d5Smrg#if !UDEV 80222944501Smrgstatic int chown_check_return(const char *path, uid_t owner, gid_t group) 80322944501Smrg{ 804fe517fc9Smrg int rv; 80522944501Smrg 806fe517fc9Smrg do { 807fe517fc9Smrg rv = chown(path, owner, group); 808fe517fc9Smrg } while (rv != 0 && errno == EINTR); 80922944501Smrg 810fe517fc9Smrg if (rv == 0) 811fe517fc9Smrg return 0; 81222944501Smrg 813fe517fc9Smrg drmMsg("Failed to change owner or group for file %s! %d: %s\n", 814fe517fc9Smrg path, errno, strerror(errno)); 815fe517fc9Smrg return -1; 81622944501Smrg} 817424e9256Smrg#endif 81822944501Smrg 81982025ec7Smrgstatic const char *drmGetDeviceName(int type) 82082025ec7Smrg{ 82182025ec7Smrg switch (type) { 82282025ec7Smrg case DRM_NODE_PRIMARY: 82382025ec7Smrg return DRM_DEV_NAME; 82482025ec7Smrg case DRM_NODE_RENDER: 82582025ec7Smrg return DRM_RENDER_DEV_NAME; 82682025ec7Smrg } 82782025ec7Smrg return NULL; 82882025ec7Smrg} 82982025ec7Smrg 83022944501Smrg/** 83122944501Smrg * Open the DRM device, creating it if necessary. 83222944501Smrg * 83322944501Smrg * \param dev major and minor numbers of the device. 83422944501Smrg * \param minor minor number of the device. 835fe517fc9Smrg * 83622944501Smrg * \return a file descriptor on success, or a negative value on error. 83722944501Smrg * 83822944501Smrg * \internal 83922944501Smrg * Assembles the device name from \p minor and opens it, creating the device 84022944501Smrg * special file node with the major and minor numbers specified by \p dev and 84122944501Smrg * parent directory if necessary and was called by root. 84222944501Smrg */ 843424e9256Smrgstatic int drmOpenDevice(dev_t dev, int minor, int type) 84422944501Smrg{ 84522944501Smrg stat_t st; 84682025ec7Smrg const char *dev_name = drmGetDeviceName(type); 84782025ec7Smrg char buf[DRM_NODE_NAME_MAX]; 84822944501Smrg int fd; 84922944501Smrg mode_t devmode = DRM_DEV_MODE, serv_mode; 850424e9256Smrg gid_t serv_group; 8516260e5d5Smrg#if !UDEV 85222944501Smrg int isroot = !geteuid(); 85322944501Smrg uid_t user = DRM_DEV_UID; 854424e9256Smrg gid_t group = DRM_DEV_GID; 855424e9256Smrg#endif 856424e9256Smrg 85782025ec7Smrg if (!dev_name) 858fe517fc9Smrg return -EINVAL; 859424e9256Smrg 860424e9256Smrg sprintf(buf, dev_name, DRM_DIR_NAME, minor); 86122944501Smrg drmMsg("drmOpenDevice: node name is %s\n", buf); 86222944501Smrg 863fe517fc9Smrg if (drm_server_info && drm_server_info->get_perms) { 864fe517fc9Smrg drm_server_info->get_perms(&serv_group, &serv_mode); 865fe517fc9Smrg devmode = serv_mode ? serv_mode : DRM_DEV_MODE; 866fe517fc9Smrg devmode &= ~(S_IXUSR|S_IXGRP|S_IXOTH); 86722944501Smrg } 86822944501Smrg 8696260e5d5Smrg#if !UDEV 87022944501Smrg if (stat(DRM_DIR_NAME, &st)) { 871fe517fc9Smrg if (!isroot) 872fe517fc9Smrg return DRM_ERR_NOT_ROOT; 873fe517fc9Smrg mkdir(DRM_DIR_NAME, DRM_DEV_DIRMODE); 874fe517fc9Smrg chown_check_return(DRM_DIR_NAME, 0, 0); /* root:root */ 875fe517fc9Smrg chmod(DRM_DIR_NAME, DRM_DEV_DIRMODE); 87622944501Smrg } 87722944501Smrg 87822944501Smrg /* Check if the device node exists and create it if necessary. */ 87922944501Smrg if (stat(buf, &st)) { 880fe517fc9Smrg if (!isroot) 881fe517fc9Smrg return DRM_ERR_NOT_ROOT; 882fe517fc9Smrg remove(buf); 883fe517fc9Smrg mknod(buf, S_IFCHR | devmode, dev); 88422944501Smrg } 88522944501Smrg 886fe517fc9Smrg if (drm_server_info && drm_server_info->get_perms) { 887fe517fc9Smrg group = ((int)serv_group >= 0) ? serv_group : DRM_DEV_GID; 888fe517fc9Smrg chown_check_return(buf, user, group); 889fe517fc9Smrg chmod(buf, devmode); 89022944501Smrg } 89122944501Smrg#else 89222944501Smrg /* if we modprobed then wait for udev */ 89322944501Smrg { 894fe517fc9Smrg int udev_count = 0; 89522944501Smrgwait_for_udev: 89622944501Smrg if (stat(DRM_DIR_NAME, &st)) { 897fe517fc9Smrg usleep(20); 898fe517fc9Smrg udev_count++; 899fe517fc9Smrg 900fe517fc9Smrg if (udev_count == 50) 901fe517fc9Smrg return -1; 902fe517fc9Smrg goto wait_for_udev; 903fe517fc9Smrg } 904fe517fc9Smrg 905fe517fc9Smrg if (stat(buf, &st)) { 906fe517fc9Smrg usleep(20); 907fe517fc9Smrg udev_count++; 908fe517fc9Smrg 909fe517fc9Smrg if (udev_count == 50) 910fe517fc9Smrg return -1; 911fe517fc9Smrg goto wait_for_udev; 912fe517fc9Smrg } 91322944501Smrg } 91422944501Smrg#endif 91522944501Smrg 9163b115362Smrg fd = open(buf, O_RDWR | O_CLOEXEC); 91722944501Smrg drmMsg("drmOpenDevice: open result is %d, (%s)\n", 918fe517fc9Smrg fd, fd < 0 ? strerror(errno) : "OK"); 91922944501Smrg if (fd >= 0) 920fe517fc9Smrg return fd; 92122944501Smrg 9226260e5d5Smrg#if !UDEV 92322944501Smrg /* Check if the device node is not what we expect it to be, and recreate it 92422944501Smrg * and try again if so. 92522944501Smrg */ 92622944501Smrg if (st.st_rdev != dev) { 927fe517fc9Smrg if (!isroot) 928fe517fc9Smrg return DRM_ERR_NOT_ROOT; 929fe517fc9Smrg remove(buf); 930fe517fc9Smrg mknod(buf, S_IFCHR | devmode, dev); 931fe517fc9Smrg if (drm_server_info && drm_server_info->get_perms) { 932fe517fc9Smrg chown_check_return(buf, user, group); 933fe517fc9Smrg chmod(buf, devmode); 934fe517fc9Smrg } 93522944501Smrg } 9363b115362Smrg fd = open(buf, O_RDWR | O_CLOEXEC); 93722944501Smrg drmMsg("drmOpenDevice: open result is %d, (%s)\n", 938fe517fc9Smrg fd, fd < 0 ? strerror(errno) : "OK"); 93922944501Smrg if (fd >= 0) 940fe517fc9Smrg return fd; 94122944501Smrg 94222944501Smrg drmMsg("drmOpenDevice: Open failed\n"); 94322944501Smrg remove(buf); 9449ce4edccSmrg#endif 94522944501Smrg return -errno; 94622944501Smrg} 94722944501Smrg 94822944501Smrg 94922944501Smrg/** 95022944501Smrg * Open the DRM device 95122944501Smrg * 95222944501Smrg * \param minor device minor number. 95322944501Smrg * \param create allow to create the device if set. 95422944501Smrg * 95522944501Smrg * \return a file descriptor on success, or a negative value on error. 956fe517fc9Smrg * 95722944501Smrg * \internal 95822944501Smrg * Calls drmOpenDevice() if \p create is set, otherwise assembles the device 95922944501Smrg * name from \p minor and opens it. 96022944501Smrg */ 96122944501Smrgstatic int drmOpenMinor(int minor, int create, int type) 96222944501Smrg{ 96322944501Smrg int fd; 96482025ec7Smrg char buf[DRM_NODE_NAME_MAX]; 96582025ec7Smrg const char *dev_name = drmGetDeviceName(type); 966fe517fc9Smrg 96722944501Smrg if (create) 968fe517fc9Smrg return drmOpenDevice(makedev(DRM_MAJOR, minor), minor, type); 969fe517fc9Smrg 97082025ec7Smrg if (!dev_name) 971fe517fc9Smrg return -EINVAL; 972424e9256Smrg 973424e9256Smrg sprintf(buf, dev_name, DRM_DIR_NAME, minor); 9743b115362Smrg if ((fd = open(buf, O_RDWR | O_CLOEXEC)) >= 0) 975fe517fc9Smrg return fd; 97622944501Smrg return -errno; 97722944501Smrg} 97822944501Smrg 97922944501Smrg 98022944501Smrg/** 98122944501Smrg * Determine whether the DRM kernel driver has been loaded. 982fe517fc9Smrg * 98322944501Smrg * \return 1 if the DRM driver is loaded, 0 otherwise. 98422944501Smrg * 985fe517fc9Smrg * \internal 98622944501Smrg * Determine the presence of the kernel driver by attempting to open the 0 98722944501Smrg * minor and get version information. For backward compatibility with older 98822944501Smrg * Linux implementations, /proc/dri is also checked. 98922944501Smrg */ 9906260e5d5Smrgdrm_public int drmAvailable(void) 99122944501Smrg{ 99222944501Smrg drmVersionPtr version; 99322944501Smrg int retval = 0; 99422944501Smrg int fd; 99522944501Smrg 996424e9256Smrg if ((fd = drmOpenMinor(0, 1, DRM_NODE_PRIMARY)) < 0) { 99722944501Smrg#ifdef __linux__ 998fe517fc9Smrg /* Try proc for backward Linux compatibility */ 999fe517fc9Smrg if (!access("/proc/dri/0", R_OK)) 1000fe517fc9Smrg return 1; 100122944501Smrg#endif 1002fe517fc9Smrg return 0; 100322944501Smrg } 1004fe517fc9Smrg 100522944501Smrg if ((version = drmGetVersion(fd))) { 1006fe517fc9Smrg retval = 1; 1007fe517fc9Smrg drmFreeVersion(version); 100822944501Smrg } 100922944501Smrg close(fd); 101022944501Smrg 101122944501Smrg return retval; 101222944501Smrg} 101322944501Smrg 1014424e9256Smrgstatic int drmGetMinorBase(int type) 1015424e9256Smrg{ 1016424e9256Smrg switch (type) { 1017424e9256Smrg case DRM_NODE_PRIMARY: 1018424e9256Smrg return 0; 1019424e9256Smrg case DRM_NODE_RENDER: 1020424e9256Smrg return 128; 1021424e9256Smrg default: 1022424e9256Smrg return -1; 1023424e9256Smrg }; 1024424e9256Smrg} 1025424e9256Smrg 102687bf8e7cSmrgstatic int drmGetMinorType(int major, int minor) 1027424e9256Smrg{ 102887bf8e7cSmrg#ifdef __FreeBSD__ 102987bf8e7cSmrg char name[SPECNAMELEN]; 103087bf8e7cSmrg int id; 103187bf8e7cSmrg 103287bf8e7cSmrg if (!devname_r(makedev(major, minor), S_IFCHR, name, sizeof(name))) 103387bf8e7cSmrg return -1; 103487bf8e7cSmrg 103587bf8e7cSmrg if (sscanf(name, "drm/%d", &id) != 1) { 103687bf8e7cSmrg // If not in /dev/drm/ we have the type in the name 103787bf8e7cSmrg if (sscanf(name, "dri/card%d\n", &id) >= 1) 103887bf8e7cSmrg return DRM_NODE_PRIMARY; 103987bf8e7cSmrg else if (sscanf(name, "dri/renderD%d\n", &id) >= 1) 104087bf8e7cSmrg return DRM_NODE_RENDER; 104187bf8e7cSmrg return -1; 104287bf8e7cSmrg } 104387bf8e7cSmrg 104487bf8e7cSmrg minor = id; 104587bf8e7cSmrg#endif 104648246ce7Smrg char path[DRM_NODE_NAME_MAX]; 104748246ce7Smrg const char *dev_name; 104848246ce7Smrg int i; 1049424e9256Smrg 105048246ce7Smrg for (i = DRM_NODE_PRIMARY; i < DRM_NODE_MAX; i++) { 105148246ce7Smrg dev_name = drmGetDeviceName(i); 105248246ce7Smrg if (!dev_name) 105348246ce7Smrg continue; 105448246ce7Smrg snprintf(path, sizeof(path), dev_name, DRM_DIR_NAME, minor); 105548246ce7Smrg if (!access(path, F_OK)) 105648246ce7Smrg return i; 1057424e9256Smrg } 105848246ce7Smrg 105948246ce7Smrg return -1; 1060424e9256Smrg} 1061424e9256Smrg 1062424e9256Smrgstatic const char *drmGetMinorName(int type) 1063424e9256Smrg{ 1064424e9256Smrg switch (type) { 1065424e9256Smrg case DRM_NODE_PRIMARY: 1066fe517fc9Smrg return DRM_PRIMARY_MINOR_NAME; 1067424e9256Smrg case DRM_NODE_RENDER: 1068fe517fc9Smrg return DRM_RENDER_MINOR_NAME; 1069424e9256Smrg default: 1070424e9256Smrg return NULL; 1071424e9256Smrg } 1072424e9256Smrg} 107322944501Smrg 107422944501Smrg/** 107522944501Smrg * Open the device by bus ID. 107622944501Smrg * 107722944501Smrg * \param busid bus ID. 1078424e9256Smrg * \param type device node type. 107922944501Smrg * 108022944501Smrg * \return a file descriptor on success, or a negative value on error. 108122944501Smrg * 108222944501Smrg * \internal 108322944501Smrg * This function attempts to open every possible minor (up to DRM_MAX_MINOR), 108422944501Smrg * comparing the device bus ID with the one supplied. 108522944501Smrg * 108622944501Smrg * \sa drmOpenMinor() and drmGetBusid(). 108722944501Smrg */ 1088424e9256Smrgstatic int drmOpenByBusid(const char *busid, int type) 108922944501Smrg{ 10906d98c517Smrg int i, pci_domain_ok = 1; 109122944501Smrg int fd; 109222944501Smrg const char *buf; 109322944501Smrg drmSetVersion sv; 1094424e9256Smrg int base = drmGetMinorBase(type); 1095424e9256Smrg 1096424e9256Smrg if (base < 0) 1097424e9256Smrg return -1; 109822944501Smrg 109922944501Smrg drmMsg("drmOpenByBusid: Searching for BusID %s\n", busid); 1100424e9256Smrg for (i = base; i < base + DRM_MAX_MINOR; i++) { 1101fe517fc9Smrg fd = drmOpenMinor(i, 1, type); 1102fe517fc9Smrg drmMsg("drmOpenByBusid: drmOpenMinor returns %d\n", fd); 1103fe517fc9Smrg if (fd >= 0) { 1104fe517fc9Smrg /* We need to try for 1.4 first for proper PCI domain support 1105fe517fc9Smrg * and if that fails, we know the kernel is busted 1106fe517fc9Smrg */ 1107fe517fc9Smrg sv.drm_di_major = 1; 1108fe517fc9Smrg sv.drm_di_minor = 4; 1109fe517fc9Smrg sv.drm_dd_major = -1; /* Don't care */ 1110fe517fc9Smrg sv.drm_dd_minor = -1; /* Don't care */ 1111fe517fc9Smrg if (drmSetInterfaceVersion(fd, &sv)) { 11126d98c517Smrg#ifndef __alpha__ 1113fe517fc9Smrg pci_domain_ok = 0; 11146d98c517Smrg#endif 1115fe517fc9Smrg sv.drm_di_major = 1; 1116fe517fc9Smrg sv.drm_di_minor = 1; 1117fe517fc9Smrg sv.drm_dd_major = -1; /* Don't care */ 1118fe517fc9Smrg sv.drm_dd_minor = -1; /* Don't care */ 1119fe517fc9Smrg drmMsg("drmOpenByBusid: Interface 1.4 failed, trying 1.1\n"); 1120fe517fc9Smrg drmSetInterfaceVersion(fd, &sv); 1121fe517fc9Smrg } 1122fe517fc9Smrg buf = drmGetBusid(fd); 1123fe517fc9Smrg drmMsg("drmOpenByBusid: drmGetBusid reports %s\n", buf); 1124fe517fc9Smrg if (buf && drmMatchBusID(buf, busid, pci_domain_ok)) { 1125fe517fc9Smrg drmFreeBusid(buf); 1126fe517fc9Smrg return fd; 1127fe517fc9Smrg } 1128fe517fc9Smrg if (buf) 1129fe517fc9Smrg drmFreeBusid(buf); 1130fe517fc9Smrg close(fd); 1131fe517fc9Smrg } 113222944501Smrg } 113322944501Smrg return -1; 113422944501Smrg} 113522944501Smrg 113622944501Smrg 113722944501Smrg/** 113822944501Smrg * Open the device by name. 113922944501Smrg * 114022944501Smrg * \param name driver name. 1141424e9256Smrg * \param type the device node type. 1142fe517fc9Smrg * 114322944501Smrg * \return a file descriptor on success, or a negative value on error. 1144fe517fc9Smrg * 114522944501Smrg * \internal 114622944501Smrg * This function opens the first minor number that matches the driver name and 114722944501Smrg * isn't already in use. If it's in use it then it will already have a bus ID 114822944501Smrg * assigned. 1149fe517fc9Smrg * 115022944501Smrg * \sa drmOpenMinor(), drmGetVersion() and drmGetBusid(). 115122944501Smrg */ 1152424e9256Smrgstatic int drmOpenByName(const char *name, int type) 115322944501Smrg{ 115422944501Smrg int i; 115522944501Smrg int fd; 115622944501Smrg drmVersionPtr version; 115722944501Smrg char * id; 1158424e9256Smrg int base = drmGetMinorBase(type); 1159424e9256Smrg 1160424e9256Smrg if (base < 0) 1161424e9256Smrg return -1; 116222944501Smrg 116322944501Smrg /* 116422944501Smrg * Open the first minor number that matches the driver name and isn't 116522944501Smrg * already in use. If it's in use it will have a busid assigned already. 116622944501Smrg */ 1167424e9256Smrg for (i = base; i < base + DRM_MAX_MINOR; i++) { 1168fe517fc9Smrg if ((fd = drmOpenMinor(i, 1, type)) >= 0) { 1169fe517fc9Smrg if ((version = drmGetVersion(fd))) { 1170fe517fc9Smrg if (!strcmp(version->name, name)) { 1171fe517fc9Smrg drmFreeVersion(version); 1172fe517fc9Smrg id = drmGetBusid(fd); 1173fe517fc9Smrg drmMsg("drmGetBusid returned '%s'\n", id ? id : "NULL"); 1174fe517fc9Smrg if (!id || !*id) { 1175fe517fc9Smrg if (id) 1176fe517fc9Smrg drmFreeBusid(id); 1177fe517fc9Smrg return fd; 1178fe517fc9Smrg } else { 1179fe517fc9Smrg drmFreeBusid(id); 1180fe517fc9Smrg } 1181fe517fc9Smrg } else { 1182fe517fc9Smrg drmFreeVersion(version); 1183fe517fc9Smrg } 1184fe517fc9Smrg } 1185fe517fc9Smrg close(fd); 1186fe517fc9Smrg } 118722944501Smrg } 118822944501Smrg 118922944501Smrg#ifdef __linux__ 119022944501Smrg /* Backward-compatibility /proc support */ 119122944501Smrg for (i = 0; i < 8; i++) { 1192fe517fc9Smrg char proc_name[64], buf[512]; 1193fe517fc9Smrg char *driver, *pt, *devstring; 1194fe517fc9Smrg int retcode; 1195fe517fc9Smrg 1196fe517fc9Smrg sprintf(proc_name, "/proc/dri/%d/name", i); 11973b115362Smrg if ((fd = open(proc_name, O_RDONLY)) >= 0) { 1198fe517fc9Smrg retcode = read(fd, buf, sizeof(buf)-1); 1199fe517fc9Smrg close(fd); 1200fe517fc9Smrg if (retcode) { 1201fe517fc9Smrg buf[retcode-1] = '\0'; 1202fe517fc9Smrg for (driver = pt = buf; *pt && *pt != ' '; ++pt) 1203fe517fc9Smrg ; 1204fe517fc9Smrg if (*pt) { /* Device is next */ 1205fe517fc9Smrg *pt = '\0'; 1206fe517fc9Smrg if (!strcmp(driver, name)) { /* Match */ 1207fe517fc9Smrg for (devstring = ++pt; *pt && *pt != ' '; ++pt) 1208fe517fc9Smrg ; 1209fe517fc9Smrg if (*pt) { /* Found busid */ 1210fe517fc9Smrg return drmOpenByBusid(++pt, type); 1211fe517fc9Smrg } else { /* No busid */ 1212fe517fc9Smrg return drmOpenDevice(strtol(devstring, NULL, 0),i, type); 1213fe517fc9Smrg } 1214fe517fc9Smrg } 1215fe517fc9Smrg } 1216fe517fc9Smrg } 1217fe517fc9Smrg } 121822944501Smrg } 121922944501Smrg#endif 122022944501Smrg 122122944501Smrg return -1; 122222944501Smrg} 122322944501Smrg 122422944501Smrg 122522944501Smrg/** 122622944501Smrg * Open the DRM device. 122722944501Smrg * 122822944501Smrg * Looks up the specified name and bus ID, and opens the device found. The 122922944501Smrg * entry in /dev/dri is created if necessary and if called by root. 123022944501Smrg * 123122944501Smrg * \param name driver name. Not referenced if bus ID is supplied. 123222944501Smrg * \param busid bus ID. Zero if not known. 1233fe517fc9Smrg * 123422944501Smrg * \return a file descriptor on success, or a negative value on error. 1235fe517fc9Smrg * 123622944501Smrg * \internal 123722944501Smrg * It calls drmOpenByBusid() if \p busid is specified or drmOpenByName() 123822944501Smrg * otherwise. 123922944501Smrg */ 12406260e5d5Smrgdrm_public int drmOpen(const char *name, const char *busid) 1241424e9256Smrg{ 1242424e9256Smrg return drmOpenWithType(name, busid, DRM_NODE_PRIMARY); 1243424e9256Smrg} 1244424e9256Smrg 1245424e9256Smrg/** 1246424e9256Smrg * Open the DRM device with specified type. 1247424e9256Smrg * 1248424e9256Smrg * Looks up the specified name and bus ID, and opens the device found. The 1249424e9256Smrg * entry in /dev/dri is created if necessary and if called by root. 1250424e9256Smrg * 1251424e9256Smrg * \param name driver name. Not referenced if bus ID is supplied. 1252424e9256Smrg * \param busid bus ID. Zero if not known. 125348246ce7Smrg * \param type the device node type to open, PRIMARY or RENDER 1254424e9256Smrg * 1255424e9256Smrg * \return a file descriptor on success, or a negative value on error. 1256424e9256Smrg * 1257424e9256Smrg * \internal 1258424e9256Smrg * It calls drmOpenByBusid() if \p busid is specified or drmOpenByName() 1259424e9256Smrg * otherwise. 1260424e9256Smrg */ 12616260e5d5Smrgdrm_public int drmOpenWithType(const char *name, const char *busid, int type) 126222944501Smrg{ 1263bf6cc7dcSmrg if (name != NULL && drm_server_info && 1264bf6cc7dcSmrg drm_server_info->load_module && !drmAvailable()) { 1265fe517fc9Smrg /* try to load the kernel module */ 1266fe517fc9Smrg if (!drm_server_info->load_module(name)) { 1267fe517fc9Smrg drmMsg("[drm] failed to load kernel module \"%s\"\n", name); 1268fe517fc9Smrg return -1; 1269fe517fc9Smrg } 127022944501Smrg } 127122944501Smrg 127222944501Smrg if (busid) { 1273fe517fc9Smrg int fd = drmOpenByBusid(busid, type); 1274fe517fc9Smrg if (fd >= 0) 1275fe517fc9Smrg return fd; 127622944501Smrg } 1277fe517fc9Smrg 127822944501Smrg if (name) 1279fe517fc9Smrg return drmOpenByName(name, type); 128022944501Smrg 128122944501Smrg return -1; 128222944501Smrg} 128322944501Smrg 12846260e5d5Smrgdrm_public int drmOpenControl(int minor) 128522944501Smrg{ 128648246ce7Smrg return -EINVAL; 128722944501Smrg} 128822944501Smrg 12896260e5d5Smrgdrm_public int drmOpenRender(int minor) 1290424e9256Smrg{ 1291424e9256Smrg return drmOpenMinor(minor, 0, DRM_NODE_RENDER); 1292424e9256Smrg} 1293424e9256Smrg 129422944501Smrg/** 129522944501Smrg * Free the version information returned by drmGetVersion(). 129622944501Smrg * 129722944501Smrg * \param v pointer to the version information. 129822944501Smrg * 129922944501Smrg * \internal 130022944501Smrg * It frees the memory pointed by \p %v as well as all the non-null strings 130122944501Smrg * pointers in it. 130222944501Smrg */ 13036260e5d5Smrgdrm_public void drmFreeVersion(drmVersionPtr v) 130422944501Smrg{ 130522944501Smrg if (!v) 1306fe517fc9Smrg return; 130722944501Smrg drmFree(v->name); 130822944501Smrg drmFree(v->date); 130922944501Smrg drmFree(v->desc); 131022944501Smrg drmFree(v); 131122944501Smrg} 131222944501Smrg 131322944501Smrg 131422944501Smrg/** 131522944501Smrg * Free the non-public version information returned by the kernel. 131622944501Smrg * 131722944501Smrg * \param v pointer to the version information. 131822944501Smrg * 131922944501Smrg * \internal 132022944501Smrg * Used by drmGetVersion() to free the memory pointed by \p %v as well as all 132122944501Smrg * the non-null strings pointers in it. 132222944501Smrg */ 132322944501Smrgstatic void drmFreeKernelVersion(drm_version_t *v) 132422944501Smrg{ 132522944501Smrg if (!v) 1326fe517fc9Smrg return; 132722944501Smrg drmFree(v->name); 132822944501Smrg drmFree(v->date); 132922944501Smrg drmFree(v->desc); 133022944501Smrg drmFree(v); 133122944501Smrg} 133222944501Smrg 133322944501Smrg 133422944501Smrg/** 133522944501Smrg * Copy version information. 1336fe517fc9Smrg * 133722944501Smrg * \param d destination pointer. 133822944501Smrg * \param s source pointer. 1339fe517fc9Smrg * 134022944501Smrg * \internal 134122944501Smrg * Used by drmGetVersion() to translate the information returned by the ioctl 134222944501Smrg * interface in a private structure into the public structure counterpart. 134322944501Smrg */ 134422944501Smrgstatic void drmCopyVersion(drmVersionPtr d, const drm_version_t *s) 134522944501Smrg{ 134622944501Smrg d->version_major = s->version_major; 134722944501Smrg d->version_minor = s->version_minor; 134822944501Smrg d->version_patchlevel = s->version_patchlevel; 134922944501Smrg d->name_len = s->name_len; 13509ce4edccSmrg d->name = strdup(s->name); 135122944501Smrg d->date_len = s->date_len; 13529ce4edccSmrg d->date = strdup(s->date); 135322944501Smrg d->desc_len = s->desc_len; 13549ce4edccSmrg d->desc = strdup(s->desc); 135522944501Smrg} 135622944501Smrg 135722944501Smrg 135822944501Smrg/** 135922944501Smrg * Query the driver version information. 136022944501Smrg * 136122944501Smrg * \param fd file descriptor. 1362fe517fc9Smrg * 136322944501Smrg * \return pointer to a drmVersion structure which should be freed with 136422944501Smrg * drmFreeVersion(). 1365fe517fc9Smrg * 136622944501Smrg * \note Similar information is available via /proc/dri. 1367fe517fc9Smrg * 136822944501Smrg * \internal 136922944501Smrg * It gets the version information via successive DRM_IOCTL_VERSION ioctls, 137022944501Smrg * first with zeros to get the string lengths, and then the actually strings. 137122944501Smrg * It also null-terminates them since they might not be already. 137222944501Smrg */ 13736260e5d5Smrgdrm_public drmVersionPtr drmGetVersion(int fd) 137422944501Smrg{ 137522944501Smrg drmVersionPtr retval; 137622944501Smrg drm_version_t *version = drmMalloc(sizeof(*version)); 137722944501Smrg 137822944501Smrg if (drmIoctl(fd, DRM_IOCTL_VERSION, version)) { 1379fe517fc9Smrg drmFreeKernelVersion(version); 1380fe517fc9Smrg return NULL; 138122944501Smrg } 138222944501Smrg 138322944501Smrg if (version->name_len) 1384fe517fc9Smrg version->name = drmMalloc(version->name_len + 1); 138522944501Smrg if (version->date_len) 1386fe517fc9Smrg version->date = drmMalloc(version->date_len + 1); 138722944501Smrg if (version->desc_len) 1388fe517fc9Smrg version->desc = drmMalloc(version->desc_len + 1); 138922944501Smrg 139022944501Smrg if (drmIoctl(fd, DRM_IOCTL_VERSION, version)) { 1391fe517fc9Smrg drmMsg("DRM_IOCTL_VERSION: %s\n", strerror(errno)); 1392fe517fc9Smrg drmFreeKernelVersion(version); 1393fe517fc9Smrg return NULL; 139422944501Smrg } 139522944501Smrg 139622944501Smrg /* The results might not be null-terminated strings, so terminate them. */ 139722944501Smrg if (version->name_len) version->name[version->name_len] = '\0'; 139822944501Smrg if (version->date_len) version->date[version->date_len] = '\0'; 139922944501Smrg if (version->desc_len) version->desc[version->desc_len] = '\0'; 140022944501Smrg 140122944501Smrg retval = drmMalloc(sizeof(*retval)); 140222944501Smrg drmCopyVersion(retval, version); 140322944501Smrg drmFreeKernelVersion(version); 140422944501Smrg return retval; 140522944501Smrg} 140622944501Smrg 140722944501Smrg 140822944501Smrg/** 140922944501Smrg * Get version information for the DRM user space library. 1410fe517fc9Smrg * 141122944501Smrg * This version number is driver independent. 1412fe517fc9Smrg * 141322944501Smrg * \param fd file descriptor. 141422944501Smrg * 141522944501Smrg * \return version information. 1416fe517fc9Smrg * 141722944501Smrg * \internal 141822944501Smrg * This function allocates and fills a drm_version structure with a hard coded 141922944501Smrg * version number. 142022944501Smrg */ 14216260e5d5Smrgdrm_public drmVersionPtr drmGetLibVersion(int fd) 142222944501Smrg{ 142322944501Smrg drm_version_t *version = drmMalloc(sizeof(*version)); 142422944501Smrg 142522944501Smrg /* Version history: 142622944501Smrg * NOTE THIS MUST NOT GO ABOVE VERSION 1.X due to drivers needing it 142722944501Smrg * revision 1.0.x = original DRM interface with no drmGetLibVersion 142822944501Smrg * entry point and many drm<Device> extensions 142922944501Smrg * revision 1.1.x = added drmCommand entry points for device extensions 143022944501Smrg * added drmGetLibVersion to identify libdrm.a version 143122944501Smrg * revision 1.2.x = added drmSetInterfaceVersion 143222944501Smrg * modified drmOpen to handle both busid and name 143322944501Smrg * revision 1.3.x = added server + memory manager 143422944501Smrg */ 143522944501Smrg version->version_major = 1; 143622944501Smrg version->version_minor = 3; 143722944501Smrg version->version_patchlevel = 0; 143822944501Smrg 143922944501Smrg return (drmVersionPtr)version; 144022944501Smrg} 144122944501Smrg 14426260e5d5Smrgdrm_public int drmGetCap(int fd, uint64_t capability, uint64_t *value) 144320131375Smrg{ 1444fe517fc9Smrg struct drm_get_cap cap; 1445fe517fc9Smrg int ret; 144620131375Smrg 1447fe517fc9Smrg memclear(cap); 1448fe517fc9Smrg cap.capability = capability; 1449424e9256Smrg 1450fe517fc9Smrg ret = drmIoctl(fd, DRM_IOCTL_GET_CAP, &cap); 1451fe517fc9Smrg if (ret) 1452fe517fc9Smrg return ret; 145320131375Smrg 1454fe517fc9Smrg *value = cap.value; 1455fe517fc9Smrg return 0; 145620131375Smrg} 145720131375Smrg 14586260e5d5Smrgdrm_public int drmSetClientCap(int fd, uint64_t capability, uint64_t value) 145920131375Smrg{ 1460fe517fc9Smrg struct drm_set_client_cap cap; 1461424e9256Smrg 1462fe517fc9Smrg memclear(cap); 1463fe517fc9Smrg cap.capability = capability; 1464fe517fc9Smrg cap.value = value; 146520131375Smrg 1466fe517fc9Smrg return drmIoctl(fd, DRM_IOCTL_SET_CLIENT_CAP, &cap); 146720131375Smrg} 146822944501Smrg 146922944501Smrg/** 147022944501Smrg * Free the bus ID information. 147122944501Smrg * 147222944501Smrg * \param busid bus ID information string as given by drmGetBusid(). 147322944501Smrg * 147422944501Smrg * \internal 147522944501Smrg * This function is just frees the memory pointed by \p busid. 147622944501Smrg */ 14776260e5d5Smrgdrm_public void drmFreeBusid(const char *busid) 147822944501Smrg{ 147922944501Smrg drmFree((void *)busid); 148022944501Smrg} 148122944501Smrg 148222944501Smrg 148322944501Smrg/** 148422944501Smrg * Get the bus ID of the device. 148522944501Smrg * 148622944501Smrg * \param fd file descriptor. 148722944501Smrg * 148822944501Smrg * \return bus ID string. 148922944501Smrg * 149022944501Smrg * \internal 149122944501Smrg * This function gets the bus ID via successive DRM_IOCTL_GET_UNIQUE ioctls to 149222944501Smrg * get the string length and data, passing the arguments in a drm_unique 149322944501Smrg * structure. 149422944501Smrg */ 14956260e5d5Smrgdrm_public char *drmGetBusid(int fd) 149622944501Smrg{ 149722944501Smrg drm_unique_t u; 149822944501Smrg 1499424e9256Smrg memclear(u); 150022944501Smrg 150122944501Smrg if (drmIoctl(fd, DRM_IOCTL_GET_UNIQUE, &u)) 1502fe517fc9Smrg return NULL; 150322944501Smrg u.unique = drmMalloc(u.unique_len + 1); 15040655efefSmrg if (drmIoctl(fd, DRM_IOCTL_GET_UNIQUE, &u)) { 15050655efefSmrg drmFree(u.unique); 1506fe517fc9Smrg return NULL; 15070655efefSmrg } 150822944501Smrg u.unique[u.unique_len] = '\0'; 150922944501Smrg 151022944501Smrg return u.unique; 151122944501Smrg} 151222944501Smrg 151322944501Smrg 151422944501Smrg/** 151522944501Smrg * Set the bus ID of the device. 151622944501Smrg * 151722944501Smrg * \param fd file descriptor. 151822944501Smrg * \param busid bus ID string. 151922944501Smrg * 152022944501Smrg * \return zero on success, negative on failure. 152122944501Smrg * 152222944501Smrg * \internal 152322944501Smrg * This function is a wrapper around the DRM_IOCTL_SET_UNIQUE ioctl, passing 152422944501Smrg * the arguments in a drm_unique structure. 152522944501Smrg */ 15266260e5d5Smrgdrm_public int drmSetBusid(int fd, const char *busid) 152722944501Smrg{ 152822944501Smrg drm_unique_t u; 152922944501Smrg 1530424e9256Smrg memclear(u); 153122944501Smrg u.unique = (char *)busid; 153222944501Smrg u.unique_len = strlen(busid); 153322944501Smrg 153422944501Smrg if (drmIoctl(fd, DRM_IOCTL_SET_UNIQUE, &u)) { 1535fe517fc9Smrg return -errno; 153622944501Smrg } 153722944501Smrg return 0; 153822944501Smrg} 153922944501Smrg 15406260e5d5Smrgdrm_public int drmGetMagic(int fd, drm_magic_t * magic) 154122944501Smrg{ 154222944501Smrg drm_auth_t auth; 154322944501Smrg 1544424e9256Smrg memclear(auth); 1545424e9256Smrg 154622944501Smrg *magic = 0; 154722944501Smrg if (drmIoctl(fd, DRM_IOCTL_GET_MAGIC, &auth)) 1548fe517fc9Smrg return -errno; 154922944501Smrg *magic = auth.magic; 155022944501Smrg return 0; 155122944501Smrg} 155222944501Smrg 15536260e5d5Smrgdrm_public int drmAuthMagic(int fd, drm_magic_t magic) 155422944501Smrg{ 155522944501Smrg drm_auth_t auth; 155622944501Smrg 1557424e9256Smrg memclear(auth); 155822944501Smrg auth.magic = magic; 155922944501Smrg if (drmIoctl(fd, DRM_IOCTL_AUTH_MAGIC, &auth)) 1560fe517fc9Smrg return -errno; 156122944501Smrg return 0; 156222944501Smrg} 156322944501Smrg 156422944501Smrg/** 156522944501Smrg * Specifies a range of memory that is available for mapping by a 156622944501Smrg * non-root process. 156722944501Smrg * 156822944501Smrg * \param fd file descriptor. 156922944501Smrg * \param offset usually the physical address. The actual meaning depends of 157022944501Smrg * the \p type parameter. See below. 157122944501Smrg * \param size of the memory in bytes. 157222944501Smrg * \param type type of the memory to be mapped. 157322944501Smrg * \param flags combination of several flags to modify the function actions. 157422944501Smrg * \param handle will be set to a value that may be used as the offset 157522944501Smrg * parameter for mmap(). 1576fe517fc9Smrg * 157722944501Smrg * \return zero on success or a negative value on error. 157822944501Smrg * 157922944501Smrg * \par Mapping the frame buffer 158022944501Smrg * For the frame buffer 158122944501Smrg * - \p offset will be the physical address of the start of the frame buffer, 158222944501Smrg * - \p size will be the size of the frame buffer in bytes, and 158322944501Smrg * - \p type will be DRM_FRAME_BUFFER. 158422944501Smrg * 158522944501Smrg * \par 158622944501Smrg * The area mapped will be uncached. If MTRR support is available in the 1587fe517fc9Smrg * kernel, the frame buffer area will be set to write combining. 158822944501Smrg * 158922944501Smrg * \par Mapping the MMIO register area 159022944501Smrg * For the MMIO register area, 159122944501Smrg * - \p offset will be the physical address of the start of the register area, 159222944501Smrg * - \p size will be the size of the register area bytes, and 159322944501Smrg * - \p type will be DRM_REGISTERS. 159422944501Smrg * \par 1595fe517fc9Smrg * The area mapped will be uncached. 1596fe517fc9Smrg * 159722944501Smrg * \par Mapping the SAREA 159822944501Smrg * For the SAREA, 159922944501Smrg * - \p offset will be ignored and should be set to zero, 160022944501Smrg * - \p size will be the desired size of the SAREA in bytes, 160122944501Smrg * - \p type will be DRM_SHM. 1602fe517fc9Smrg * 160322944501Smrg * \par 160422944501Smrg * A shared memory area of the requested size will be created and locked in 160522944501Smrg * kernel memory. This area may be mapped into client-space by using the handle 1606fe517fc9Smrg * returned. 1607fe517fc9Smrg * 160822944501Smrg * \note May only be called by root. 160922944501Smrg * 161022944501Smrg * \internal 161122944501Smrg * This function is a wrapper around the DRM_IOCTL_ADD_MAP ioctl, passing 161222944501Smrg * the arguments in a drm_map structure. 161322944501Smrg */ 16146260e5d5Smrgdrm_public int drmAddMap(int fd, drm_handle_t offset, drmSize size, drmMapType type, 16156260e5d5Smrg drmMapFlags flags, drm_handle_t *handle) 161622944501Smrg{ 161722944501Smrg drm_map_t map; 161822944501Smrg 1619424e9256Smrg memclear(map); 162022944501Smrg map.offset = offset; 162122944501Smrg map.size = size; 1622adfa0b0cSmrg map.type = (enum drm_map_type)type; 1623adfa0b0cSmrg map.flags = (enum drm_map_flags)flags; 162422944501Smrg if (drmIoctl(fd, DRM_IOCTL_ADD_MAP, &map)) 1625fe517fc9Smrg return -errno; 162622944501Smrg if (handle) 1627fe517fc9Smrg *handle = (drm_handle_t)(uintptr_t)map.handle; 162822944501Smrg return 0; 162922944501Smrg} 163022944501Smrg 16316260e5d5Smrgdrm_public int drmRmMap(int fd, drm_handle_t handle) 163222944501Smrg{ 163322944501Smrg drm_map_t map; 163422944501Smrg 1635424e9256Smrg memclear(map); 163620131375Smrg map.handle = (void *)(uintptr_t)handle; 163722944501Smrg 163822944501Smrg if(drmIoctl(fd, DRM_IOCTL_RM_MAP, &map)) 1639fe517fc9Smrg return -errno; 164022944501Smrg return 0; 164122944501Smrg} 164222944501Smrg 164322944501Smrg/** 164422944501Smrg * Make buffers available for DMA transfers. 1645fe517fc9Smrg * 164622944501Smrg * \param fd file descriptor. 164722944501Smrg * \param count number of buffers. 164822944501Smrg * \param size size of each buffer. 164922944501Smrg * \param flags buffer allocation flags. 1650fe517fc9Smrg * \param agp_offset offset in the AGP aperture 165122944501Smrg * 165222944501Smrg * \return number of buffers allocated, negative on error. 165322944501Smrg * 165422944501Smrg * \internal 165522944501Smrg * This function is a wrapper around DRM_IOCTL_ADD_BUFS ioctl. 165622944501Smrg * 165722944501Smrg * \sa drm_buf_desc. 165822944501Smrg */ 16596260e5d5Smrgdrm_public int drmAddBufs(int fd, int count, int size, drmBufDescFlags flags, 16606260e5d5Smrg int agp_offset) 166122944501Smrg{ 166222944501Smrg drm_buf_desc_t request; 166322944501Smrg 1664424e9256Smrg memclear(request); 166522944501Smrg request.count = count; 166622944501Smrg request.size = size; 1667adfa0b0cSmrg request.flags = (int)flags; 166822944501Smrg request.agp_start = agp_offset; 166922944501Smrg 167022944501Smrg if (drmIoctl(fd, DRM_IOCTL_ADD_BUFS, &request)) 1671fe517fc9Smrg return -errno; 167222944501Smrg return request.count; 167322944501Smrg} 167422944501Smrg 16756260e5d5Smrgdrm_public int drmMarkBufs(int fd, double low, double high) 167622944501Smrg{ 167722944501Smrg drm_buf_info_t info; 167822944501Smrg int i; 167922944501Smrg 1680424e9256Smrg memclear(info); 168122944501Smrg 168222944501Smrg if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info)) 1683fe517fc9Smrg return -EINVAL; 168422944501Smrg 168522944501Smrg if (!info.count) 1686fe517fc9Smrg return -EINVAL; 168722944501Smrg 168822944501Smrg if (!(info.list = drmMalloc(info.count * sizeof(*info.list)))) 1689fe517fc9Smrg return -ENOMEM; 169022944501Smrg 169122944501Smrg if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info)) { 1692fe517fc9Smrg int retval = -errno; 1693fe517fc9Smrg drmFree(info.list); 1694fe517fc9Smrg return retval; 169522944501Smrg } 169622944501Smrg 169722944501Smrg for (i = 0; i < info.count; i++) { 1698fe517fc9Smrg info.list[i].low_mark = low * info.list[i].count; 1699fe517fc9Smrg info.list[i].high_mark = high * info.list[i].count; 1700fe517fc9Smrg if (drmIoctl(fd, DRM_IOCTL_MARK_BUFS, &info.list[i])) { 1701fe517fc9Smrg int retval = -errno; 1702fe517fc9Smrg drmFree(info.list); 1703fe517fc9Smrg return retval; 1704fe517fc9Smrg } 170522944501Smrg } 170622944501Smrg drmFree(info.list); 170722944501Smrg 170822944501Smrg return 0; 170922944501Smrg} 171022944501Smrg 171122944501Smrg/** 171222944501Smrg * Free buffers. 171322944501Smrg * 171422944501Smrg * \param fd file descriptor. 171522944501Smrg * \param count number of buffers to free. 171622944501Smrg * \param list list of buffers to be freed. 171722944501Smrg * 171822944501Smrg * \return zero on success, or a negative value on failure. 1719fe517fc9Smrg * 172022944501Smrg * \note This function is primarily used for debugging. 1721fe517fc9Smrg * 172222944501Smrg * \internal 172322944501Smrg * This function is a wrapper around the DRM_IOCTL_FREE_BUFS ioctl, passing 172422944501Smrg * the arguments in a drm_buf_free structure. 172522944501Smrg */ 17266260e5d5Smrgdrm_public int drmFreeBufs(int fd, int count, int *list) 172722944501Smrg{ 172822944501Smrg drm_buf_free_t request; 172922944501Smrg 1730424e9256Smrg memclear(request); 173122944501Smrg request.count = count; 173222944501Smrg request.list = list; 173322944501Smrg if (drmIoctl(fd, DRM_IOCTL_FREE_BUFS, &request)) 1734fe517fc9Smrg return -errno; 173522944501Smrg return 0; 173622944501Smrg} 173722944501Smrg 173822944501Smrg 173922944501Smrg/** 174022944501Smrg * Close the device. 174122944501Smrg * 174222944501Smrg * \param fd file descriptor. 174322944501Smrg * 174422944501Smrg * \internal 174522944501Smrg * This function closes the file descriptor. 174622944501Smrg */ 17476260e5d5Smrgdrm_public int drmClose(int fd) 174822944501Smrg{ 174922944501Smrg unsigned long key = drmGetKeyFromFd(fd); 175022944501Smrg drmHashEntry *entry = drmGetEntry(fd); 175122944501Smrg 175222944501Smrg drmHashDestroy(entry->tagTable); 175322944501Smrg entry->fd = 0; 175422944501Smrg entry->f = NULL; 175522944501Smrg entry->tagTable = NULL; 175622944501Smrg 175722944501Smrg drmHashDelete(drmHashTable, key); 175822944501Smrg drmFree(entry); 175922944501Smrg 176022944501Smrg return close(fd); 176122944501Smrg} 176222944501Smrg 176322944501Smrg 176422944501Smrg/** 176522944501Smrg * Map a region of memory. 176622944501Smrg * 176722944501Smrg * \param fd file descriptor. 176822944501Smrg * \param handle handle returned by drmAddMap(). 176922944501Smrg * \param size size in bytes. Must match the size used by drmAddMap(). 177022944501Smrg * \param address will contain the user-space virtual address where the mapping 177122944501Smrg * begins. 177222944501Smrg * 177322944501Smrg * \return zero on success, or a negative value on failure. 1774fe517fc9Smrg * 177522944501Smrg * \internal 177622944501Smrg * This function is a wrapper for mmap(). 177722944501Smrg */ 17786260e5d5Smrgdrm_public int drmMap(int fd, drm_handle_t handle, drmSize size, 17796260e5d5Smrg drmAddressPtr address) 178022944501Smrg{ 178122944501Smrg static unsigned long pagesize_mask = 0; 178222944501Smrg 178322944501Smrg if (fd < 0) 1784fe517fc9Smrg return -EINVAL; 178522944501Smrg 178622944501Smrg if (!pagesize_mask) 1787fe517fc9Smrg pagesize_mask = getpagesize() - 1; 178822944501Smrg 178922944501Smrg size = (size + pagesize_mask) & ~pagesize_mask; 179022944501Smrg 1791a884aba1Smrg *address = drm_mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, handle); 179222944501Smrg if (*address == MAP_FAILED) 1793fe517fc9Smrg return -errno; 179422944501Smrg return 0; 179522944501Smrg} 179622944501Smrg 179722944501Smrg 179822944501Smrg/** 179922944501Smrg * Unmap mappings obtained with drmMap(). 180022944501Smrg * 180122944501Smrg * \param address address as given by drmMap(). 180222944501Smrg * \param size size in bytes. Must match the size used by drmMap(). 1803fe517fc9Smrg * 180422944501Smrg * \return zero on success, or a negative value on failure. 180522944501Smrg * 180622944501Smrg * \internal 180722944501Smrg * This function is a wrapper for munmap(). 180822944501Smrg */ 18096260e5d5Smrgdrm_public int drmUnmap(drmAddress address, drmSize size) 181022944501Smrg{ 1811a884aba1Smrg return drm_munmap(address, size); 181222944501Smrg} 181322944501Smrg 18146260e5d5Smrgdrm_public drmBufInfoPtr drmGetBufInfo(int fd) 181522944501Smrg{ 181622944501Smrg drm_buf_info_t info; 181722944501Smrg drmBufInfoPtr retval; 181822944501Smrg int i; 181922944501Smrg 1820424e9256Smrg memclear(info); 182122944501Smrg 182222944501Smrg if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info)) 1823fe517fc9Smrg return NULL; 182422944501Smrg 182522944501Smrg if (info.count) { 1826fe517fc9Smrg if (!(info.list = drmMalloc(info.count * sizeof(*info.list)))) 1827fe517fc9Smrg return NULL; 1828fe517fc9Smrg 1829fe517fc9Smrg if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info)) { 1830fe517fc9Smrg drmFree(info.list); 1831fe517fc9Smrg return NULL; 1832fe517fc9Smrg } 1833fe517fc9Smrg 1834fe517fc9Smrg retval = drmMalloc(sizeof(*retval)); 1835fe517fc9Smrg retval->count = info.count; 18364b3d3f37Smrg if (!(retval->list = drmMalloc(info.count * sizeof(*retval->list)))) { 18374b3d3f37Smrg drmFree(retval); 18384b3d3f37Smrg drmFree(info.list); 18394b3d3f37Smrg return NULL; 18404b3d3f37Smrg } 18414b3d3f37Smrg 1842fe517fc9Smrg for (i = 0; i < info.count; i++) { 1843fe517fc9Smrg retval->list[i].count = info.list[i].count; 1844fe517fc9Smrg retval->list[i].size = info.list[i].size; 1845fe517fc9Smrg retval->list[i].low_mark = info.list[i].low_mark; 1846fe517fc9Smrg retval->list[i].high_mark = info.list[i].high_mark; 1847fe517fc9Smrg } 1848fe517fc9Smrg drmFree(info.list); 1849fe517fc9Smrg return retval; 185022944501Smrg } 185122944501Smrg return NULL; 185222944501Smrg} 185322944501Smrg 185422944501Smrg/** 185522944501Smrg * Map all DMA buffers into client-virtual space. 185622944501Smrg * 185722944501Smrg * \param fd file descriptor. 185822944501Smrg * 185922944501Smrg * \return a pointer to a ::drmBufMap structure. 186022944501Smrg * 186122944501Smrg * \note The client may not use these buffers until obtaining buffer indices 186222944501Smrg * with drmDMA(). 1863fe517fc9Smrg * 186422944501Smrg * \internal 186522944501Smrg * This function calls the DRM_IOCTL_MAP_BUFS ioctl and copies the returned 186622944501Smrg * information about the buffers in a drm_buf_map structure into the 186722944501Smrg * client-visible data structures. 1868fe517fc9Smrg */ 18696260e5d5Smrgdrm_public drmBufMapPtr drmMapBufs(int fd) 187022944501Smrg{ 187122944501Smrg drm_buf_map_t bufs; 187222944501Smrg drmBufMapPtr retval; 187322944501Smrg int i; 187422944501Smrg 1875424e9256Smrg memclear(bufs); 187622944501Smrg if (drmIoctl(fd, DRM_IOCTL_MAP_BUFS, &bufs)) 1877fe517fc9Smrg return NULL; 187822944501Smrg 187922944501Smrg if (!bufs.count) 1880fe517fc9Smrg return NULL; 188122944501Smrg 1882fe517fc9Smrg if (!(bufs.list = drmMalloc(bufs.count * sizeof(*bufs.list)))) 1883fe517fc9Smrg return NULL; 188422944501Smrg 1885fe517fc9Smrg if (drmIoctl(fd, DRM_IOCTL_MAP_BUFS, &bufs)) { 1886fe517fc9Smrg drmFree(bufs.list); 1887fe517fc9Smrg return NULL; 1888fe517fc9Smrg } 188922944501Smrg 1890fe517fc9Smrg retval = drmMalloc(sizeof(*retval)); 1891fe517fc9Smrg retval->count = bufs.count; 1892fe517fc9Smrg retval->list = drmMalloc(bufs.count * sizeof(*retval->list)); 1893fe517fc9Smrg for (i = 0; i < bufs.count; i++) { 1894fe517fc9Smrg retval->list[i].idx = bufs.list[i].idx; 1895fe517fc9Smrg retval->list[i].total = bufs.list[i].total; 1896fe517fc9Smrg retval->list[i].used = 0; 1897fe517fc9Smrg retval->list[i].address = bufs.list[i].address; 1898fe517fc9Smrg } 189922944501Smrg 1900fe517fc9Smrg drmFree(bufs.list); 1901fe517fc9Smrg return retval; 190222944501Smrg} 190322944501Smrg 190422944501Smrg 190522944501Smrg/** 190622944501Smrg * Unmap buffers allocated with drmMapBufs(). 190722944501Smrg * 190822944501Smrg * \return zero on success, or negative value on failure. 190922944501Smrg * 191022944501Smrg * \internal 191122944501Smrg * Calls munmap() for every buffer stored in \p bufs and frees the 191222944501Smrg * memory allocated by drmMapBufs(). 191322944501Smrg */ 19146260e5d5Smrgdrm_public int drmUnmapBufs(drmBufMapPtr bufs) 191522944501Smrg{ 191622944501Smrg int i; 191722944501Smrg 191822944501Smrg for (i = 0; i < bufs->count; i++) { 1919fe517fc9Smrg drm_munmap(bufs->list[i].address, bufs->list[i].total); 192022944501Smrg } 192122944501Smrg 192222944501Smrg drmFree(bufs->list); 192322944501Smrg drmFree(bufs); 192422944501Smrg return 0; 192522944501Smrg} 192622944501Smrg 192722944501Smrg 1928fe517fc9Smrg#define DRM_DMA_RETRY 16 192922944501Smrg 193022944501Smrg/** 193122944501Smrg * Reserve DMA buffers. 193222944501Smrg * 193322944501Smrg * \param fd file descriptor. 1934fe517fc9Smrg * \param request 1935fe517fc9Smrg * 193622944501Smrg * \return zero on success, or a negative value on failure. 193722944501Smrg * 193822944501Smrg * \internal 193922944501Smrg * Assemble the arguments into a drm_dma structure and keeps issuing the 194022944501Smrg * DRM_IOCTL_DMA ioctl until success or until maximum number of retries. 194122944501Smrg */ 19426260e5d5Smrgdrm_public int drmDMA(int fd, drmDMAReqPtr request) 194322944501Smrg{ 194422944501Smrg drm_dma_t dma; 194522944501Smrg int ret, i = 0; 194622944501Smrg 194722944501Smrg dma.context = request->context; 194822944501Smrg dma.send_count = request->send_count; 194922944501Smrg dma.send_indices = request->send_list; 195022944501Smrg dma.send_sizes = request->send_sizes; 1951adfa0b0cSmrg dma.flags = (enum drm_dma_flags)request->flags; 195222944501Smrg dma.request_count = request->request_count; 195322944501Smrg dma.request_size = request->request_size; 195422944501Smrg dma.request_indices = request->request_list; 195522944501Smrg dma.request_sizes = request->request_sizes; 195622944501Smrg dma.granted_count = 0; 195722944501Smrg 195822944501Smrg do { 1959fe517fc9Smrg ret = ioctl( fd, DRM_IOCTL_DMA, &dma ); 196022944501Smrg } while ( ret && errno == EAGAIN && i++ < DRM_DMA_RETRY ); 196122944501Smrg 196222944501Smrg if ( ret == 0 ) { 1963fe517fc9Smrg request->granted_count = dma.granted_count; 1964fe517fc9Smrg return 0; 196522944501Smrg } else { 1966fe517fc9Smrg return -errno; 196722944501Smrg } 196822944501Smrg} 196922944501Smrg 197022944501Smrg 197122944501Smrg/** 197222944501Smrg * Obtain heavyweight hardware lock. 197322944501Smrg * 197422944501Smrg * \param fd file descriptor. 197522944501Smrg * \param context context. 1976bf6cc7dcSmrg * \param flags flags that determine the state of the hardware when the function 197722944501Smrg * returns. 1978fe517fc9Smrg * 197922944501Smrg * \return always zero. 1980fe517fc9Smrg * 198122944501Smrg * \internal 198222944501Smrg * This function translates the arguments into a drm_lock structure and issue 198322944501Smrg * the DRM_IOCTL_LOCK ioctl until the lock is successfully acquired. 198422944501Smrg */ 19856260e5d5Smrgdrm_public int drmGetLock(int fd, drm_context_t context, drmLockFlags flags) 198622944501Smrg{ 198722944501Smrg drm_lock_t lock; 198822944501Smrg 1989424e9256Smrg memclear(lock); 199022944501Smrg lock.context = context; 199122944501Smrg lock.flags = 0; 199222944501Smrg if (flags & DRM_LOCK_READY) lock.flags |= _DRM_LOCK_READY; 199322944501Smrg if (flags & DRM_LOCK_QUIESCENT) lock.flags |= _DRM_LOCK_QUIESCENT; 199422944501Smrg if (flags & DRM_LOCK_FLUSH) lock.flags |= _DRM_LOCK_FLUSH; 199522944501Smrg if (flags & DRM_LOCK_FLUSH_ALL) lock.flags |= _DRM_LOCK_FLUSH_ALL; 199622944501Smrg if (flags & DRM_HALT_ALL_QUEUES) lock.flags |= _DRM_HALT_ALL_QUEUES; 199722944501Smrg if (flags & DRM_HALT_CUR_QUEUES) lock.flags |= _DRM_HALT_CUR_QUEUES; 199822944501Smrg 199922944501Smrg while (drmIoctl(fd, DRM_IOCTL_LOCK, &lock)) 2000fe517fc9Smrg ; 200122944501Smrg return 0; 200222944501Smrg} 200322944501Smrg 200422944501Smrg/** 200522944501Smrg * Release the hardware lock. 200622944501Smrg * 200722944501Smrg * \param fd file descriptor. 200822944501Smrg * \param context context. 2009fe517fc9Smrg * 201022944501Smrg * \return zero on success, or a negative value on failure. 2011fe517fc9Smrg * 201222944501Smrg * \internal 201322944501Smrg * This function is a wrapper around the DRM_IOCTL_UNLOCK ioctl, passing the 201422944501Smrg * argument in a drm_lock structure. 201522944501Smrg */ 20166260e5d5Smrgdrm_public int drmUnlock(int fd, drm_context_t context) 201722944501Smrg{ 201822944501Smrg drm_lock_t lock; 201922944501Smrg 2020424e9256Smrg memclear(lock); 202122944501Smrg lock.context = context; 202222944501Smrg return drmIoctl(fd, DRM_IOCTL_UNLOCK, &lock); 202322944501Smrg} 202422944501Smrg 20256260e5d5Smrgdrm_public drm_context_t *drmGetReservedContextList(int fd, int *count) 202622944501Smrg{ 202722944501Smrg drm_ctx_res_t res; 202822944501Smrg drm_ctx_t *list; 202922944501Smrg drm_context_t * retval; 203022944501Smrg int i; 203122944501Smrg 2032424e9256Smrg memclear(res); 203322944501Smrg if (drmIoctl(fd, DRM_IOCTL_RES_CTX, &res)) 2034fe517fc9Smrg return NULL; 203522944501Smrg 203622944501Smrg if (!res.count) 2037fe517fc9Smrg return NULL; 203822944501Smrg 203922944501Smrg if (!(list = drmMalloc(res.count * sizeof(*list)))) 2040fe517fc9Smrg return NULL; 20410655efefSmrg if (!(retval = drmMalloc(res.count * sizeof(*retval)))) 20420655efefSmrg goto err_free_list; 204322944501Smrg 204422944501Smrg res.contexts = list; 204522944501Smrg if (drmIoctl(fd, DRM_IOCTL_RES_CTX, &res)) 20460655efefSmrg goto err_free_context; 204722944501Smrg 204822944501Smrg for (i = 0; i < res.count; i++) 2049fe517fc9Smrg retval[i] = list[i].handle; 205022944501Smrg drmFree(list); 205122944501Smrg 205222944501Smrg *count = res.count; 205322944501Smrg return retval; 20540655efefSmrg 20550655efefSmrgerr_free_list: 20560655efefSmrg drmFree(list); 20570655efefSmrgerr_free_context: 20580655efefSmrg drmFree(retval); 20590655efefSmrg return NULL; 206022944501Smrg} 206122944501Smrg 20626260e5d5Smrgdrm_public void drmFreeReservedContextList(drm_context_t *pt) 206322944501Smrg{ 206422944501Smrg drmFree(pt); 206522944501Smrg} 206622944501Smrg 206722944501Smrg/** 206822944501Smrg * Create context. 206922944501Smrg * 207022944501Smrg * Used by the X server during GLXContext initialization. This causes 207122944501Smrg * per-context kernel-level resources to be allocated. 207222944501Smrg * 207322944501Smrg * \param fd file descriptor. 207422944501Smrg * \param handle is set on success. To be used by the client when requesting DMA 207522944501Smrg * dispatch with drmDMA(). 2076fe517fc9Smrg * 207722944501Smrg * \return zero on success, or a negative value on failure. 2078fe517fc9Smrg * 207922944501Smrg * \note May only be called by root. 2080fe517fc9Smrg * 208122944501Smrg * \internal 208222944501Smrg * This function is a wrapper around the DRM_IOCTL_ADD_CTX ioctl, passing the 208322944501Smrg * argument in a drm_ctx structure. 208422944501Smrg */ 20856260e5d5Smrgdrm_public int drmCreateContext(int fd, drm_context_t *handle) 208622944501Smrg{ 208722944501Smrg drm_ctx_t ctx; 208822944501Smrg 2089424e9256Smrg memclear(ctx); 209022944501Smrg if (drmIoctl(fd, DRM_IOCTL_ADD_CTX, &ctx)) 2091fe517fc9Smrg return -errno; 209222944501Smrg *handle = ctx.handle; 209322944501Smrg return 0; 209422944501Smrg} 209522944501Smrg 20966260e5d5Smrgdrm_public int drmSwitchToContext(int fd, drm_context_t context) 209722944501Smrg{ 209822944501Smrg drm_ctx_t ctx; 209922944501Smrg 2100424e9256Smrg memclear(ctx); 210122944501Smrg ctx.handle = context; 210222944501Smrg if (drmIoctl(fd, DRM_IOCTL_SWITCH_CTX, &ctx)) 2103fe517fc9Smrg return -errno; 210422944501Smrg return 0; 210522944501Smrg} 210622944501Smrg 21076260e5d5Smrgdrm_public int drmSetContextFlags(int fd, drm_context_t context, 21086260e5d5Smrg drm_context_tFlags flags) 210922944501Smrg{ 211022944501Smrg drm_ctx_t ctx; 211122944501Smrg 211222944501Smrg /* 211322944501Smrg * Context preserving means that no context switches are done between DMA 211422944501Smrg * buffers from one context and the next. This is suitable for use in the 211522944501Smrg * X server (which promises to maintain hardware context), or in the 211622944501Smrg * client-side library when buffers are swapped on behalf of two threads. 211722944501Smrg */ 2118424e9256Smrg memclear(ctx); 211922944501Smrg ctx.handle = context; 212022944501Smrg if (flags & DRM_CONTEXT_PRESERVED) 2121fe517fc9Smrg ctx.flags |= _DRM_CONTEXT_PRESERVED; 212222944501Smrg if (flags & DRM_CONTEXT_2DONLY) 2123fe517fc9Smrg ctx.flags |= _DRM_CONTEXT_2DONLY; 212422944501Smrg if (drmIoctl(fd, DRM_IOCTL_MOD_CTX, &ctx)) 2125fe517fc9Smrg return -errno; 212622944501Smrg return 0; 212722944501Smrg} 212822944501Smrg 21296260e5d5Smrgdrm_public int drmGetContextFlags(int fd, drm_context_t context, 21306260e5d5Smrg drm_context_tFlagsPtr flags) 213122944501Smrg{ 213222944501Smrg drm_ctx_t ctx; 213322944501Smrg 2134424e9256Smrg memclear(ctx); 213522944501Smrg ctx.handle = context; 213622944501Smrg if (drmIoctl(fd, DRM_IOCTL_GET_CTX, &ctx)) 2137fe517fc9Smrg return -errno; 213822944501Smrg *flags = 0; 213922944501Smrg if (ctx.flags & _DRM_CONTEXT_PRESERVED) 2140fe517fc9Smrg *flags |= DRM_CONTEXT_PRESERVED; 214122944501Smrg if (ctx.flags & _DRM_CONTEXT_2DONLY) 2142fe517fc9Smrg *flags |= DRM_CONTEXT_2DONLY; 214322944501Smrg return 0; 214422944501Smrg} 214522944501Smrg 214622944501Smrg/** 214722944501Smrg * Destroy context. 214822944501Smrg * 214922944501Smrg * Free any kernel-level resources allocated with drmCreateContext() associated 215022944501Smrg * with the context. 2151fe517fc9Smrg * 215222944501Smrg * \param fd file descriptor. 215322944501Smrg * \param handle handle given by drmCreateContext(). 2154fe517fc9Smrg * 215522944501Smrg * \return zero on success, or a negative value on failure. 2156fe517fc9Smrg * 215722944501Smrg * \note May only be called by root. 2158fe517fc9Smrg * 215922944501Smrg * \internal 216022944501Smrg * This function is a wrapper around the DRM_IOCTL_RM_CTX ioctl, passing the 216122944501Smrg * argument in a drm_ctx structure. 216222944501Smrg */ 21636260e5d5Smrgdrm_public int drmDestroyContext(int fd, drm_context_t handle) 216422944501Smrg{ 216522944501Smrg drm_ctx_t ctx; 2166424e9256Smrg 2167424e9256Smrg memclear(ctx); 216822944501Smrg ctx.handle = handle; 216922944501Smrg if (drmIoctl(fd, DRM_IOCTL_RM_CTX, &ctx)) 2170fe517fc9Smrg return -errno; 217122944501Smrg return 0; 217222944501Smrg} 217322944501Smrg 21746260e5d5Smrgdrm_public int drmCreateDrawable(int fd, drm_drawable_t *handle) 217522944501Smrg{ 217622944501Smrg drm_draw_t draw; 2177424e9256Smrg 2178424e9256Smrg memclear(draw); 217922944501Smrg if (drmIoctl(fd, DRM_IOCTL_ADD_DRAW, &draw)) 2180fe517fc9Smrg return -errno; 218122944501Smrg *handle = draw.handle; 218222944501Smrg return 0; 218322944501Smrg} 218422944501Smrg 21856260e5d5Smrgdrm_public int drmDestroyDrawable(int fd, drm_drawable_t handle) 218622944501Smrg{ 218722944501Smrg drm_draw_t draw; 2188424e9256Smrg 2189424e9256Smrg memclear(draw); 219022944501Smrg draw.handle = handle; 219122944501Smrg if (drmIoctl(fd, DRM_IOCTL_RM_DRAW, &draw)) 2192fe517fc9Smrg return -errno; 219322944501Smrg return 0; 219422944501Smrg} 219522944501Smrg 21966260e5d5Smrgdrm_public int drmUpdateDrawableInfo(int fd, drm_drawable_t handle, 21976260e5d5Smrg drm_drawable_info_type_t type, 21986260e5d5Smrg unsigned int num, void *data) 219922944501Smrg{ 220022944501Smrg drm_update_draw_t update; 220122944501Smrg 2202424e9256Smrg memclear(update); 220322944501Smrg update.handle = handle; 220422944501Smrg update.type = type; 220522944501Smrg update.num = num; 220622944501Smrg update.data = (unsigned long long)(unsigned long)data; 220722944501Smrg 220822944501Smrg if (drmIoctl(fd, DRM_IOCTL_UPDATE_DRAW, &update)) 2209fe517fc9Smrg return -errno; 221022944501Smrg 221122944501Smrg return 0; 221222944501Smrg} 221322944501Smrg 22146260e5d5Smrgdrm_public int drmCrtcGetSequence(int fd, uint32_t crtcId, uint64_t *sequence, 22156260e5d5Smrg uint64_t *ns) 22162b90624aSmrg{ 22172b90624aSmrg struct drm_crtc_get_sequence get_seq; 22182b90624aSmrg int ret; 22192b90624aSmrg 22202b90624aSmrg memclear(get_seq); 22212b90624aSmrg get_seq.crtc_id = crtcId; 22222b90624aSmrg ret = drmIoctl(fd, DRM_IOCTL_CRTC_GET_SEQUENCE, &get_seq); 22232b90624aSmrg if (ret) 22242b90624aSmrg return ret; 22252b90624aSmrg 22262b90624aSmrg if (sequence) 22272b90624aSmrg *sequence = get_seq.sequence; 22282b90624aSmrg if (ns) 22292b90624aSmrg *ns = get_seq.sequence_ns; 22302b90624aSmrg return 0; 22312b90624aSmrg} 22322b90624aSmrg 22336260e5d5Smrgdrm_public int drmCrtcQueueSequence(int fd, uint32_t crtcId, uint32_t flags, 22346260e5d5Smrg uint64_t sequence, 22356260e5d5Smrg uint64_t *sequence_queued, 22366260e5d5Smrg uint64_t user_data) 22372b90624aSmrg{ 22382b90624aSmrg struct drm_crtc_queue_sequence queue_seq; 22392b90624aSmrg int ret; 22402b90624aSmrg 22412b90624aSmrg memclear(queue_seq); 22422b90624aSmrg queue_seq.crtc_id = crtcId; 22432b90624aSmrg queue_seq.flags = flags; 22442b90624aSmrg queue_seq.sequence = sequence; 22452b90624aSmrg queue_seq.user_data = user_data; 22462b90624aSmrg 22472b90624aSmrg ret = drmIoctl(fd, DRM_IOCTL_CRTC_QUEUE_SEQUENCE, &queue_seq); 22482b90624aSmrg if (ret == 0 && sequence_queued) 22492b90624aSmrg *sequence_queued = queue_seq.sequence; 22502b90624aSmrg 22512b90624aSmrg return ret; 22522b90624aSmrg} 22532b90624aSmrg 225422944501Smrg/** 225522944501Smrg * Acquire the AGP device. 225622944501Smrg * 225722944501Smrg * Must be called before any of the other AGP related calls. 225822944501Smrg * 225922944501Smrg * \param fd file descriptor. 2260fe517fc9Smrg * 226122944501Smrg * \return zero on success, or a negative value on failure. 2262fe517fc9Smrg * 226322944501Smrg * \internal 226422944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_ACQUIRE ioctl. 226522944501Smrg */ 22666260e5d5Smrgdrm_public int drmAgpAcquire(int fd) 226722944501Smrg{ 226822944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_ACQUIRE, NULL)) 2269fe517fc9Smrg return -errno; 227022944501Smrg return 0; 227122944501Smrg} 227222944501Smrg 227322944501Smrg 227422944501Smrg/** 227522944501Smrg * Release the AGP device. 227622944501Smrg * 227722944501Smrg * \param fd file descriptor. 2278fe517fc9Smrg * 227922944501Smrg * \return zero on success, or a negative value on failure. 2280fe517fc9Smrg * 228122944501Smrg * \internal 228222944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_RELEASE ioctl. 228322944501Smrg */ 22846260e5d5Smrgdrm_public int drmAgpRelease(int fd) 228522944501Smrg{ 228622944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_RELEASE, NULL)) 2287fe517fc9Smrg return -errno; 228822944501Smrg return 0; 228922944501Smrg} 229022944501Smrg 229122944501Smrg 229222944501Smrg/** 229322944501Smrg * Set the AGP mode. 229422944501Smrg * 229522944501Smrg * \param fd file descriptor. 229622944501Smrg * \param mode AGP mode. 2297fe517fc9Smrg * 229822944501Smrg * \return zero on success, or a negative value on failure. 2299fe517fc9Smrg * 230022944501Smrg * \internal 230122944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_ENABLE ioctl, passing the 230222944501Smrg * argument in a drm_agp_mode structure. 230322944501Smrg */ 23046260e5d5Smrgdrm_public int drmAgpEnable(int fd, unsigned long mode) 230522944501Smrg{ 230622944501Smrg drm_agp_mode_t m; 230722944501Smrg 2308424e9256Smrg memclear(m); 230922944501Smrg m.mode = mode; 231022944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_ENABLE, &m)) 2311fe517fc9Smrg return -errno; 231222944501Smrg return 0; 231322944501Smrg} 231422944501Smrg 231522944501Smrg 231622944501Smrg/** 231722944501Smrg * Allocate a chunk of AGP memory. 231822944501Smrg * 231922944501Smrg * \param fd file descriptor. 232022944501Smrg * \param size requested memory size in bytes. Will be rounded to page boundary. 232122944501Smrg * \param type type of memory to allocate. 232222944501Smrg * \param address if not zero, will be set to the physical address of the 232322944501Smrg * allocated memory. 232422944501Smrg * \param handle on success will be set to a handle of the allocated memory. 2325fe517fc9Smrg * 232622944501Smrg * \return zero on success, or a negative value on failure. 2327fe517fc9Smrg * 232822944501Smrg * \internal 232922944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_ALLOC ioctl, passing the 233022944501Smrg * arguments in a drm_agp_buffer structure. 233122944501Smrg */ 23326260e5d5Smrgdrm_public int drmAgpAlloc(int fd, unsigned long size, unsigned long type, 23336260e5d5Smrg unsigned long *address, drm_handle_t *handle) 233422944501Smrg{ 233522944501Smrg drm_agp_buffer_t b; 233622944501Smrg 2337424e9256Smrg memclear(b); 233822944501Smrg *handle = DRM_AGP_NO_HANDLE; 233922944501Smrg b.size = size; 234022944501Smrg b.type = type; 234122944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_ALLOC, &b)) 2342fe517fc9Smrg return -errno; 234322944501Smrg if (address != 0UL) 2344fe517fc9Smrg *address = b.physical; 234522944501Smrg *handle = b.handle; 234622944501Smrg return 0; 234722944501Smrg} 234822944501Smrg 234922944501Smrg 235022944501Smrg/** 235122944501Smrg * Free a chunk of AGP memory. 235222944501Smrg * 235322944501Smrg * \param fd file descriptor. 235422944501Smrg * \param handle handle to the allocated memory, as given by drmAgpAllocate(). 2355fe517fc9Smrg * 235622944501Smrg * \return zero on success, or a negative value on failure. 2357fe517fc9Smrg * 235822944501Smrg * \internal 235922944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_FREE ioctl, passing the 236022944501Smrg * argument in a drm_agp_buffer structure. 236122944501Smrg */ 23626260e5d5Smrgdrm_public int drmAgpFree(int fd, drm_handle_t handle) 236322944501Smrg{ 236422944501Smrg drm_agp_buffer_t b; 236522944501Smrg 2366424e9256Smrg memclear(b); 236722944501Smrg b.handle = handle; 236822944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_FREE, &b)) 2369fe517fc9Smrg return -errno; 237022944501Smrg return 0; 237122944501Smrg} 237222944501Smrg 237322944501Smrg 237422944501Smrg/** 237522944501Smrg * Bind a chunk of AGP memory. 237622944501Smrg * 237722944501Smrg * \param fd file descriptor. 237822944501Smrg * \param handle handle to the allocated memory, as given by drmAgpAllocate(). 237922944501Smrg * \param offset offset in bytes. It will round to page boundary. 2380fe517fc9Smrg * 238122944501Smrg * \return zero on success, or a negative value on failure. 2382fe517fc9Smrg * 238322944501Smrg * \internal 238422944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_BIND ioctl, passing the 238522944501Smrg * argument in a drm_agp_binding structure. 238622944501Smrg */ 23876260e5d5Smrgdrm_public int drmAgpBind(int fd, drm_handle_t handle, unsigned long offset) 238822944501Smrg{ 238922944501Smrg drm_agp_binding_t b; 239022944501Smrg 2391424e9256Smrg memclear(b); 239222944501Smrg b.handle = handle; 239322944501Smrg b.offset = offset; 239422944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_BIND, &b)) 2395fe517fc9Smrg return -errno; 239622944501Smrg return 0; 239722944501Smrg} 239822944501Smrg 239922944501Smrg 240022944501Smrg/** 240122944501Smrg * Unbind a chunk of AGP memory. 240222944501Smrg * 240322944501Smrg * \param fd file descriptor. 240422944501Smrg * \param handle handle to the allocated memory, as given by drmAgpAllocate(). 2405fe517fc9Smrg * 240622944501Smrg * \return zero on success, or a negative value on failure. 2407fe517fc9Smrg * 240822944501Smrg * \internal 240922944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_UNBIND ioctl, passing 241022944501Smrg * the argument in a drm_agp_binding structure. 241122944501Smrg */ 24126260e5d5Smrgdrm_public int drmAgpUnbind(int fd, drm_handle_t handle) 241322944501Smrg{ 241422944501Smrg drm_agp_binding_t b; 241522944501Smrg 2416424e9256Smrg memclear(b); 241722944501Smrg b.handle = handle; 241822944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_UNBIND, &b)) 2419fe517fc9Smrg return -errno; 242022944501Smrg return 0; 242122944501Smrg} 242222944501Smrg 242322944501Smrg 242422944501Smrg/** 242522944501Smrg * Get AGP driver major version number. 242622944501Smrg * 242722944501Smrg * \param fd file descriptor. 2428fe517fc9Smrg * 242922944501Smrg * \return major version number on success, or a negative value on failure.. 2430fe517fc9Smrg * 243122944501Smrg * \internal 243222944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the 243322944501Smrg * necessary information in a drm_agp_info structure. 243422944501Smrg */ 24356260e5d5Smrgdrm_public int drmAgpVersionMajor(int fd) 243622944501Smrg{ 243722944501Smrg drm_agp_info_t i; 243822944501Smrg 2439424e9256Smrg memclear(i); 2440424e9256Smrg 244122944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i)) 2442fe517fc9Smrg return -errno; 244322944501Smrg return i.agp_version_major; 244422944501Smrg} 244522944501Smrg 244622944501Smrg 244722944501Smrg/** 244822944501Smrg * Get AGP driver minor version number. 244922944501Smrg * 245022944501Smrg * \param fd file descriptor. 2451fe517fc9Smrg * 245222944501Smrg * \return minor version number on success, or a negative value on failure. 2453fe517fc9Smrg * 245422944501Smrg * \internal 245522944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the 245622944501Smrg * necessary information in a drm_agp_info structure. 245722944501Smrg */ 24586260e5d5Smrgdrm_public int drmAgpVersionMinor(int fd) 245922944501Smrg{ 246022944501Smrg drm_agp_info_t i; 246122944501Smrg 2462424e9256Smrg memclear(i); 2463424e9256Smrg 246422944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i)) 2465fe517fc9Smrg return -errno; 246622944501Smrg return i.agp_version_minor; 246722944501Smrg} 246822944501Smrg 246922944501Smrg 247022944501Smrg/** 247122944501Smrg * Get AGP mode. 247222944501Smrg * 247322944501Smrg * \param fd file descriptor. 2474fe517fc9Smrg * 247522944501Smrg * \return mode on success, or zero on failure. 2476fe517fc9Smrg * 247722944501Smrg * \internal 247822944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the 247922944501Smrg * necessary information in a drm_agp_info structure. 248022944501Smrg */ 24816260e5d5Smrgdrm_public unsigned long drmAgpGetMode(int fd) 248222944501Smrg{ 248322944501Smrg drm_agp_info_t i; 248422944501Smrg 2485424e9256Smrg memclear(i); 2486424e9256Smrg 248722944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i)) 2488fe517fc9Smrg return 0; 248922944501Smrg return i.mode; 249022944501Smrg} 249122944501Smrg 249222944501Smrg 249322944501Smrg/** 249422944501Smrg * Get AGP aperture base. 249522944501Smrg * 249622944501Smrg * \param fd file descriptor. 2497fe517fc9Smrg * 249822944501Smrg * \return aperture base on success, zero on failure. 2499fe517fc9Smrg * 250022944501Smrg * \internal 250122944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the 250222944501Smrg * necessary information in a drm_agp_info structure. 250322944501Smrg */ 25046260e5d5Smrgdrm_public unsigned long drmAgpBase(int fd) 250522944501Smrg{ 250622944501Smrg drm_agp_info_t i; 250722944501Smrg 2508424e9256Smrg memclear(i); 2509424e9256Smrg 251022944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i)) 2511fe517fc9Smrg return 0; 251222944501Smrg return i.aperture_base; 251322944501Smrg} 251422944501Smrg 251522944501Smrg 251622944501Smrg/** 251722944501Smrg * Get AGP aperture size. 251822944501Smrg * 251922944501Smrg * \param fd file descriptor. 2520fe517fc9Smrg * 252122944501Smrg * \return aperture size on success, zero on failure. 2522fe517fc9Smrg * 252322944501Smrg * \internal 252422944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the 252522944501Smrg * necessary information in a drm_agp_info structure. 252622944501Smrg */ 25276260e5d5Smrgdrm_public unsigned long drmAgpSize(int fd) 252822944501Smrg{ 252922944501Smrg drm_agp_info_t i; 253022944501Smrg 2531424e9256Smrg memclear(i); 2532424e9256Smrg 253322944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i)) 2534fe517fc9Smrg return 0; 253522944501Smrg return i.aperture_size; 253622944501Smrg} 253722944501Smrg 253822944501Smrg 253922944501Smrg/** 254022944501Smrg * Get used AGP memory. 254122944501Smrg * 254222944501Smrg * \param fd file descriptor. 2543fe517fc9Smrg * 254422944501Smrg * \return memory used on success, or zero on failure. 2545fe517fc9Smrg * 254622944501Smrg * \internal 254722944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the 254822944501Smrg * necessary information in a drm_agp_info structure. 254922944501Smrg */ 25506260e5d5Smrgdrm_public unsigned long drmAgpMemoryUsed(int fd) 255122944501Smrg{ 255222944501Smrg drm_agp_info_t i; 255322944501Smrg 2554424e9256Smrg memclear(i); 2555424e9256Smrg 255622944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i)) 2557fe517fc9Smrg return 0; 255822944501Smrg return i.memory_used; 255922944501Smrg} 256022944501Smrg 256122944501Smrg 256222944501Smrg/** 256322944501Smrg * Get available AGP memory. 256422944501Smrg * 256522944501Smrg * \param fd file descriptor. 2566fe517fc9Smrg * 256722944501Smrg * \return memory available on success, or zero on failure. 2568fe517fc9Smrg * 256922944501Smrg * \internal 257022944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the 257122944501Smrg * necessary information in a drm_agp_info structure. 257222944501Smrg */ 25736260e5d5Smrgdrm_public unsigned long drmAgpMemoryAvail(int fd) 257422944501Smrg{ 257522944501Smrg drm_agp_info_t i; 257622944501Smrg 2577424e9256Smrg memclear(i); 2578424e9256Smrg 257922944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i)) 2580fe517fc9Smrg return 0; 258122944501Smrg return i.memory_allowed; 258222944501Smrg} 258322944501Smrg 258422944501Smrg 258522944501Smrg/** 258622944501Smrg * Get hardware vendor ID. 258722944501Smrg * 258822944501Smrg * \param fd file descriptor. 2589fe517fc9Smrg * 259022944501Smrg * \return vendor ID on success, or zero on failure. 2591fe517fc9Smrg * 259222944501Smrg * \internal 259322944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the 259422944501Smrg * necessary information in a drm_agp_info structure. 259522944501Smrg */ 25966260e5d5Smrgdrm_public unsigned int drmAgpVendorId(int fd) 259722944501Smrg{ 259822944501Smrg drm_agp_info_t i; 259922944501Smrg 2600424e9256Smrg memclear(i); 2601424e9256Smrg 260222944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i)) 2603fe517fc9Smrg return 0; 260422944501Smrg return i.id_vendor; 260522944501Smrg} 260622944501Smrg 260722944501Smrg 260822944501Smrg/** 260922944501Smrg * Get hardware device ID. 261022944501Smrg * 261122944501Smrg * \param fd file descriptor. 2612fe517fc9Smrg * 261322944501Smrg * \return zero on success, or zero on failure. 2614fe517fc9Smrg * 261522944501Smrg * \internal 261622944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the 261722944501Smrg * necessary information in a drm_agp_info structure. 261822944501Smrg */ 26196260e5d5Smrgdrm_public unsigned int drmAgpDeviceId(int fd) 262022944501Smrg{ 262122944501Smrg drm_agp_info_t i; 262222944501Smrg 2623424e9256Smrg memclear(i); 2624424e9256Smrg 262522944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i)) 2626fe517fc9Smrg return 0; 262722944501Smrg return i.id_device; 262822944501Smrg} 262922944501Smrg 26306260e5d5Smrgdrm_public int drmScatterGatherAlloc(int fd, unsigned long size, 26316260e5d5Smrg drm_handle_t *handle) 263222944501Smrg{ 263322944501Smrg drm_scatter_gather_t sg; 263422944501Smrg 2635424e9256Smrg memclear(sg); 2636424e9256Smrg 263722944501Smrg *handle = 0; 263822944501Smrg sg.size = size; 263922944501Smrg if (drmIoctl(fd, DRM_IOCTL_SG_ALLOC, &sg)) 2640fe517fc9Smrg return -errno; 264122944501Smrg *handle = sg.handle; 264222944501Smrg return 0; 264322944501Smrg} 264422944501Smrg 26456260e5d5Smrgdrm_public int drmScatterGatherFree(int fd, drm_handle_t handle) 264622944501Smrg{ 264722944501Smrg drm_scatter_gather_t sg; 264822944501Smrg 2649424e9256Smrg memclear(sg); 265022944501Smrg sg.handle = handle; 265122944501Smrg if (drmIoctl(fd, DRM_IOCTL_SG_FREE, &sg)) 2652fe517fc9Smrg return -errno; 265322944501Smrg return 0; 265422944501Smrg} 265522944501Smrg 265622944501Smrg/** 265722944501Smrg * Wait for VBLANK. 265822944501Smrg * 265922944501Smrg * \param fd file descriptor. 266022944501Smrg * \param vbl pointer to a drmVBlank structure. 2661fe517fc9Smrg * 266222944501Smrg * \return zero on success, or a negative value on failure. 2663fe517fc9Smrg * 266422944501Smrg * \internal 266522944501Smrg * This function is a wrapper around the DRM_IOCTL_WAIT_VBLANK ioctl. 266622944501Smrg */ 26676260e5d5Smrgdrm_public int drmWaitVBlank(int fd, drmVBlankPtr vbl) 266822944501Smrg{ 266922944501Smrg struct timespec timeout, cur; 267022944501Smrg int ret; 267122944501Smrg 267222944501Smrg ret = clock_gettime(CLOCK_MONOTONIC, &timeout); 267322944501Smrg if (ret < 0) { 2674fe517fc9Smrg fprintf(stderr, "clock_gettime failed: %s\n", strerror(errno)); 2675fe517fc9Smrg goto out; 267622944501Smrg } 267722944501Smrg timeout.tv_sec++; 267822944501Smrg 267922944501Smrg do { 268022944501Smrg ret = ioctl(fd, DRM_IOCTL_WAIT_VBLANK, vbl); 268122944501Smrg vbl->request.type &= ~DRM_VBLANK_RELATIVE; 268222944501Smrg if (ret && errno == EINTR) { 2683fe517fc9Smrg clock_gettime(CLOCK_MONOTONIC, &cur); 2684fe517fc9Smrg /* Timeout after 1s */ 2685fe517fc9Smrg if (cur.tv_sec > timeout.tv_sec + 1 || 2686fe517fc9Smrg (cur.tv_sec == timeout.tv_sec && cur.tv_nsec >= 2687fe517fc9Smrg timeout.tv_nsec)) { 2688fe517fc9Smrg errno = EBUSY; 2689fe517fc9Smrg ret = -1; 2690fe517fc9Smrg break; 2691fe517fc9Smrg } 269222944501Smrg } 269322944501Smrg } while (ret && errno == EINTR); 269422944501Smrg 269522944501Smrgout: 269622944501Smrg return ret; 269722944501Smrg} 269822944501Smrg 26996260e5d5Smrgdrm_public int drmError(int err, const char *label) 270022944501Smrg{ 270122944501Smrg switch (err) { 270222944501Smrg case DRM_ERR_NO_DEVICE: 2703fe517fc9Smrg fprintf(stderr, "%s: no device\n", label); 2704fe517fc9Smrg break; 270522944501Smrg case DRM_ERR_NO_ACCESS: 2706fe517fc9Smrg fprintf(stderr, "%s: no access\n", label); 2707fe517fc9Smrg break; 270822944501Smrg case DRM_ERR_NOT_ROOT: 2709fe517fc9Smrg fprintf(stderr, "%s: not root\n", label); 2710fe517fc9Smrg break; 271122944501Smrg case DRM_ERR_INVALID: 2712fe517fc9Smrg fprintf(stderr, "%s: invalid args\n", label); 2713fe517fc9Smrg break; 271422944501Smrg default: 2715fe517fc9Smrg if (err < 0) 2716fe517fc9Smrg err = -err; 2717fe517fc9Smrg fprintf( stderr, "%s: error %d (%s)\n", label, err, strerror(err) ); 2718fe517fc9Smrg break; 271922944501Smrg } 272022944501Smrg 272122944501Smrg return 1; 272222944501Smrg} 272322944501Smrg 272422944501Smrg/** 272522944501Smrg * Install IRQ handler. 272622944501Smrg * 272722944501Smrg * \param fd file descriptor. 272822944501Smrg * \param irq IRQ number. 2729fe517fc9Smrg * 273022944501Smrg * \return zero on success, or a negative value on failure. 2731fe517fc9Smrg * 273222944501Smrg * \internal 273322944501Smrg * This function is a wrapper around the DRM_IOCTL_CONTROL ioctl, passing the 273422944501Smrg * argument in a drm_control structure. 273522944501Smrg */ 27366260e5d5Smrgdrm_public int drmCtlInstHandler(int fd, int irq) 273722944501Smrg{ 273822944501Smrg drm_control_t ctl; 273922944501Smrg 2740424e9256Smrg memclear(ctl); 274122944501Smrg ctl.func = DRM_INST_HANDLER; 274222944501Smrg ctl.irq = irq; 274322944501Smrg if (drmIoctl(fd, DRM_IOCTL_CONTROL, &ctl)) 2744fe517fc9Smrg return -errno; 274522944501Smrg return 0; 274622944501Smrg} 274722944501Smrg 274822944501Smrg 274922944501Smrg/** 275022944501Smrg * Uninstall IRQ handler. 275122944501Smrg * 275222944501Smrg * \param fd file descriptor. 2753fe517fc9Smrg * 275422944501Smrg * \return zero on success, or a negative value on failure. 2755fe517fc9Smrg * 275622944501Smrg * \internal 275722944501Smrg * This function is a wrapper around the DRM_IOCTL_CONTROL ioctl, passing the 275822944501Smrg * argument in a drm_control structure. 275922944501Smrg */ 27606260e5d5Smrgdrm_public int drmCtlUninstHandler(int fd) 276122944501Smrg{ 276222944501Smrg drm_control_t ctl; 276322944501Smrg 2764424e9256Smrg memclear(ctl); 276522944501Smrg ctl.func = DRM_UNINST_HANDLER; 276622944501Smrg ctl.irq = 0; 276722944501Smrg if (drmIoctl(fd, DRM_IOCTL_CONTROL, &ctl)) 2768fe517fc9Smrg return -errno; 276922944501Smrg return 0; 277022944501Smrg} 277122944501Smrg 27726260e5d5Smrgdrm_public int drmFinish(int fd, int context, drmLockFlags flags) 277322944501Smrg{ 277422944501Smrg drm_lock_t lock; 277522944501Smrg 2776424e9256Smrg memclear(lock); 277722944501Smrg lock.context = context; 277822944501Smrg if (flags & DRM_LOCK_READY) lock.flags |= _DRM_LOCK_READY; 277922944501Smrg if (flags & DRM_LOCK_QUIESCENT) lock.flags |= _DRM_LOCK_QUIESCENT; 278022944501Smrg if (flags & DRM_LOCK_FLUSH) lock.flags |= _DRM_LOCK_FLUSH; 278122944501Smrg if (flags & DRM_LOCK_FLUSH_ALL) lock.flags |= _DRM_LOCK_FLUSH_ALL; 278222944501Smrg if (flags & DRM_HALT_ALL_QUEUES) lock.flags |= _DRM_HALT_ALL_QUEUES; 278322944501Smrg if (flags & DRM_HALT_CUR_QUEUES) lock.flags |= _DRM_HALT_CUR_QUEUES; 278422944501Smrg if (drmIoctl(fd, DRM_IOCTL_FINISH, &lock)) 2785fe517fc9Smrg return -errno; 278622944501Smrg return 0; 278722944501Smrg} 278822944501Smrg 278922944501Smrg/** 279022944501Smrg * Get IRQ from bus ID. 279122944501Smrg * 279222944501Smrg * \param fd file descriptor. 279322944501Smrg * \param busnum bus number. 279422944501Smrg * \param devnum device number. 279522944501Smrg * \param funcnum function number. 2796fe517fc9Smrg * 279722944501Smrg * \return IRQ number on success, or a negative value on failure. 2798fe517fc9Smrg * 279922944501Smrg * \internal 280022944501Smrg * This function is a wrapper around the DRM_IOCTL_IRQ_BUSID ioctl, passing the 280122944501Smrg * arguments in a drm_irq_busid structure. 280222944501Smrg */ 28036260e5d5Smrgdrm_public int drmGetInterruptFromBusID(int fd, int busnum, int devnum, 28046260e5d5Smrg int funcnum) 280522944501Smrg{ 280622944501Smrg drm_irq_busid_t p; 280722944501Smrg 2808424e9256Smrg memclear(p); 280922944501Smrg p.busnum = busnum; 281022944501Smrg p.devnum = devnum; 281122944501Smrg p.funcnum = funcnum; 281222944501Smrg if (drmIoctl(fd, DRM_IOCTL_IRQ_BUSID, &p)) 2813fe517fc9Smrg return -errno; 281422944501Smrg return p.irq; 281522944501Smrg} 281622944501Smrg 28176260e5d5Smrgdrm_public int drmAddContextTag(int fd, drm_context_t context, void *tag) 281822944501Smrg{ 281922944501Smrg drmHashEntry *entry = drmGetEntry(fd); 282022944501Smrg 282122944501Smrg if (drmHashInsert(entry->tagTable, context, tag)) { 2822fe517fc9Smrg drmHashDelete(entry->tagTable, context); 2823fe517fc9Smrg drmHashInsert(entry->tagTable, context, tag); 282422944501Smrg } 282522944501Smrg return 0; 282622944501Smrg} 282722944501Smrg 28286260e5d5Smrgdrm_public int drmDelContextTag(int fd, drm_context_t context) 282922944501Smrg{ 283022944501Smrg drmHashEntry *entry = drmGetEntry(fd); 283122944501Smrg 283222944501Smrg return drmHashDelete(entry->tagTable, context); 283322944501Smrg} 283422944501Smrg 28356260e5d5Smrgdrm_public void *drmGetContextTag(int fd, drm_context_t context) 283622944501Smrg{ 283722944501Smrg drmHashEntry *entry = drmGetEntry(fd); 283822944501Smrg void *value; 283922944501Smrg 284022944501Smrg if (drmHashLookup(entry->tagTable, context, &value)) 2841fe517fc9Smrg return NULL; 284222944501Smrg 284322944501Smrg return value; 284422944501Smrg} 284522944501Smrg 28466260e5d5Smrgdrm_public int drmAddContextPrivateMapping(int fd, drm_context_t ctx_id, 28476260e5d5Smrg drm_handle_t handle) 284822944501Smrg{ 284922944501Smrg drm_ctx_priv_map_t map; 285022944501Smrg 2851424e9256Smrg memclear(map); 285222944501Smrg map.ctx_id = ctx_id; 285320131375Smrg map.handle = (void *)(uintptr_t)handle; 285422944501Smrg 285522944501Smrg if (drmIoctl(fd, DRM_IOCTL_SET_SAREA_CTX, &map)) 2856fe517fc9Smrg return -errno; 285722944501Smrg return 0; 285822944501Smrg} 285922944501Smrg 28606260e5d5Smrgdrm_public int drmGetContextPrivateMapping(int fd, drm_context_t ctx_id, 28616260e5d5Smrg drm_handle_t *handle) 286222944501Smrg{ 286322944501Smrg drm_ctx_priv_map_t map; 286422944501Smrg 2865424e9256Smrg memclear(map); 286622944501Smrg map.ctx_id = ctx_id; 286722944501Smrg 286822944501Smrg if (drmIoctl(fd, DRM_IOCTL_GET_SAREA_CTX, &map)) 2869fe517fc9Smrg return -errno; 287022944501Smrg if (handle) 2871fe517fc9Smrg *handle = (drm_handle_t)(uintptr_t)map.handle; 287222944501Smrg 287322944501Smrg return 0; 287422944501Smrg} 287522944501Smrg 28766260e5d5Smrgdrm_public int drmGetMap(int fd, int idx, drm_handle_t *offset, drmSize *size, 28776260e5d5Smrg drmMapType *type, drmMapFlags *flags, 28786260e5d5Smrg drm_handle_t *handle, int *mtrr) 287922944501Smrg{ 288022944501Smrg drm_map_t map; 288122944501Smrg 2882424e9256Smrg memclear(map); 288322944501Smrg map.offset = idx; 288422944501Smrg if (drmIoctl(fd, DRM_IOCTL_GET_MAP, &map)) 2885fe517fc9Smrg return -errno; 288622944501Smrg *offset = map.offset; 288722944501Smrg *size = map.size; 2888adfa0b0cSmrg *type = (drmMapType)map.type; 2889adfa0b0cSmrg *flags = (drmMapFlags)map.flags; 289022944501Smrg *handle = (unsigned long)map.handle; 289122944501Smrg *mtrr = map.mtrr; 289222944501Smrg return 0; 289322944501Smrg} 289422944501Smrg 28956260e5d5Smrgdrm_public int drmGetClient(int fd, int idx, int *auth, int *pid, int *uid, 28966260e5d5Smrg unsigned long *magic, unsigned long *iocs) 289722944501Smrg{ 289822944501Smrg drm_client_t client; 289922944501Smrg 2900424e9256Smrg memclear(client); 290122944501Smrg client.idx = idx; 290222944501Smrg if (drmIoctl(fd, DRM_IOCTL_GET_CLIENT, &client)) 2903fe517fc9Smrg return -errno; 290422944501Smrg *auth = client.auth; 290522944501Smrg *pid = client.pid; 290622944501Smrg *uid = client.uid; 290722944501Smrg *magic = client.magic; 290822944501Smrg *iocs = client.iocs; 290922944501Smrg return 0; 291022944501Smrg} 291122944501Smrg 29126260e5d5Smrgdrm_public int drmGetStats(int fd, drmStatsT *stats) 291322944501Smrg{ 291422944501Smrg drm_stats_t s; 2915424e9256Smrg unsigned i; 291622944501Smrg 2917424e9256Smrg memclear(s); 291822944501Smrg if (drmIoctl(fd, DRM_IOCTL_GET_STATS, &s)) 2919fe517fc9Smrg return -errno; 292022944501Smrg 292122944501Smrg stats->count = 0; 292222944501Smrg memset(stats, 0, sizeof(*stats)); 292322944501Smrg if (s.count > sizeof(stats->data)/sizeof(stats->data[0])) 2924fe517fc9Smrg return -1; 292522944501Smrg 292622944501Smrg#define SET_VALUE \ 292722944501Smrg stats->data[i].long_format = "%-20.20s"; \ 292822944501Smrg stats->data[i].rate_format = "%8.8s"; \ 292922944501Smrg stats->data[i].isvalue = 1; \ 293022944501Smrg stats->data[i].verbose = 0 293122944501Smrg 293222944501Smrg#define SET_COUNT \ 293322944501Smrg stats->data[i].long_format = "%-20.20s"; \ 293422944501Smrg stats->data[i].rate_format = "%5.5s"; \ 293522944501Smrg stats->data[i].isvalue = 0; \ 293622944501Smrg stats->data[i].mult_names = "kgm"; \ 293722944501Smrg stats->data[i].mult = 1000; \ 293822944501Smrg stats->data[i].verbose = 0 293922944501Smrg 294022944501Smrg#define SET_BYTE \ 294122944501Smrg stats->data[i].long_format = "%-20.20s"; \ 294222944501Smrg stats->data[i].rate_format = "%5.5s"; \ 294322944501Smrg stats->data[i].isvalue = 0; \ 294422944501Smrg stats->data[i].mult_names = "KGM"; \ 294522944501Smrg stats->data[i].mult = 1024; \ 294622944501Smrg stats->data[i].verbose = 0 294722944501Smrg 294822944501Smrg 294922944501Smrg stats->count = s.count; 295022944501Smrg for (i = 0; i < s.count; i++) { 2951fe517fc9Smrg stats->data[i].value = s.data[i].value; 2952fe517fc9Smrg switch (s.data[i].type) { 2953fe517fc9Smrg case _DRM_STAT_LOCK: 2954fe517fc9Smrg stats->data[i].long_name = "Lock"; 2955fe517fc9Smrg stats->data[i].rate_name = "Lock"; 2956fe517fc9Smrg SET_VALUE; 2957fe517fc9Smrg break; 2958fe517fc9Smrg case _DRM_STAT_OPENS: 2959fe517fc9Smrg stats->data[i].long_name = "Opens"; 2960fe517fc9Smrg stats->data[i].rate_name = "O"; 2961fe517fc9Smrg SET_COUNT; 2962fe517fc9Smrg stats->data[i].verbose = 1; 2963fe517fc9Smrg break; 2964fe517fc9Smrg case _DRM_STAT_CLOSES: 2965fe517fc9Smrg stats->data[i].long_name = "Closes"; 2966fe517fc9Smrg stats->data[i].rate_name = "Lock"; 2967fe517fc9Smrg SET_COUNT; 2968fe517fc9Smrg stats->data[i].verbose = 1; 2969fe517fc9Smrg break; 2970fe517fc9Smrg case _DRM_STAT_IOCTLS: 2971fe517fc9Smrg stats->data[i].long_name = "Ioctls"; 2972fe517fc9Smrg stats->data[i].rate_name = "Ioc/s"; 2973fe517fc9Smrg SET_COUNT; 2974fe517fc9Smrg break; 2975fe517fc9Smrg case _DRM_STAT_LOCKS: 2976fe517fc9Smrg stats->data[i].long_name = "Locks"; 2977fe517fc9Smrg stats->data[i].rate_name = "Lck/s"; 2978fe517fc9Smrg SET_COUNT; 2979fe517fc9Smrg break; 2980fe517fc9Smrg case _DRM_STAT_UNLOCKS: 2981fe517fc9Smrg stats->data[i].long_name = "Unlocks"; 2982fe517fc9Smrg stats->data[i].rate_name = "Unl/s"; 2983fe517fc9Smrg SET_COUNT; 2984fe517fc9Smrg break; 2985fe517fc9Smrg case _DRM_STAT_IRQ: 2986fe517fc9Smrg stats->data[i].long_name = "IRQs"; 2987fe517fc9Smrg stats->data[i].rate_name = "IRQ/s"; 2988fe517fc9Smrg SET_COUNT; 2989fe517fc9Smrg break; 2990fe517fc9Smrg case _DRM_STAT_PRIMARY: 2991fe517fc9Smrg stats->data[i].long_name = "Primary Bytes"; 2992fe517fc9Smrg stats->data[i].rate_name = "PB/s"; 2993fe517fc9Smrg SET_BYTE; 2994fe517fc9Smrg break; 2995fe517fc9Smrg case _DRM_STAT_SECONDARY: 2996fe517fc9Smrg stats->data[i].long_name = "Secondary Bytes"; 2997fe517fc9Smrg stats->data[i].rate_name = "SB/s"; 2998fe517fc9Smrg SET_BYTE; 2999fe517fc9Smrg break; 3000fe517fc9Smrg case _DRM_STAT_DMA: 3001fe517fc9Smrg stats->data[i].long_name = "DMA"; 3002fe517fc9Smrg stats->data[i].rate_name = "DMA/s"; 3003fe517fc9Smrg SET_COUNT; 3004fe517fc9Smrg break; 3005fe517fc9Smrg case _DRM_STAT_SPECIAL: 3006fe517fc9Smrg stats->data[i].long_name = "Special DMA"; 3007fe517fc9Smrg stats->data[i].rate_name = "dma/s"; 3008fe517fc9Smrg SET_COUNT; 3009fe517fc9Smrg break; 3010fe517fc9Smrg case _DRM_STAT_MISSED: 3011fe517fc9Smrg stats->data[i].long_name = "Miss"; 3012fe517fc9Smrg stats->data[i].rate_name = "Ms/s"; 3013fe517fc9Smrg SET_COUNT; 3014fe517fc9Smrg break; 3015fe517fc9Smrg case _DRM_STAT_VALUE: 3016fe517fc9Smrg stats->data[i].long_name = "Value"; 3017fe517fc9Smrg stats->data[i].rate_name = "Value"; 3018fe517fc9Smrg SET_VALUE; 3019fe517fc9Smrg break; 3020fe517fc9Smrg case _DRM_STAT_BYTE: 3021fe517fc9Smrg stats->data[i].long_name = "Bytes"; 3022fe517fc9Smrg stats->data[i].rate_name = "B/s"; 3023fe517fc9Smrg SET_BYTE; 3024fe517fc9Smrg break; 3025fe517fc9Smrg case _DRM_STAT_COUNT: 3026fe517fc9Smrg default: 3027fe517fc9Smrg stats->data[i].long_name = "Count"; 3028fe517fc9Smrg stats->data[i].rate_name = "Cnt/s"; 3029fe517fc9Smrg SET_COUNT; 3030fe517fc9Smrg break; 3031fe517fc9Smrg } 303222944501Smrg } 303322944501Smrg return 0; 303422944501Smrg} 303522944501Smrg 303622944501Smrg/** 303722944501Smrg * Issue a set-version ioctl. 303822944501Smrg * 303922944501Smrg * \param fd file descriptor. 3040fe517fc9Smrg * \param drmCommandIndex command index 304122944501Smrg * \param data source pointer of the data to be read and written. 304222944501Smrg * \param size size of the data to be read and written. 3043fe517fc9Smrg * 304422944501Smrg * \return zero on success, or a negative value on failure. 3045fe517fc9Smrg * 304622944501Smrg * \internal 3047fe517fc9Smrg * It issues a read-write ioctl given by 304822944501Smrg * \code DRM_COMMAND_BASE + drmCommandIndex \endcode. 304922944501Smrg */ 30506260e5d5Smrgdrm_public int drmSetInterfaceVersion(int fd, drmSetVersion *version) 305122944501Smrg{ 305222944501Smrg int retcode = 0; 305322944501Smrg drm_set_version_t sv; 305422944501Smrg 3055424e9256Smrg memclear(sv); 305622944501Smrg sv.drm_di_major = version->drm_di_major; 305722944501Smrg sv.drm_di_minor = version->drm_di_minor; 305822944501Smrg sv.drm_dd_major = version->drm_dd_major; 305922944501Smrg sv.drm_dd_minor = version->drm_dd_minor; 306022944501Smrg 306122944501Smrg if (drmIoctl(fd, DRM_IOCTL_SET_VERSION, &sv)) { 3062fe517fc9Smrg retcode = -errno; 306322944501Smrg } 306422944501Smrg 306522944501Smrg version->drm_di_major = sv.drm_di_major; 306622944501Smrg version->drm_di_minor = sv.drm_di_minor; 306722944501Smrg version->drm_dd_major = sv.drm_dd_major; 306822944501Smrg version->drm_dd_minor = sv.drm_dd_minor; 306922944501Smrg 307022944501Smrg return retcode; 307122944501Smrg} 307222944501Smrg 307322944501Smrg/** 307422944501Smrg * Send a device-specific command. 307522944501Smrg * 307622944501Smrg * \param fd file descriptor. 3077fe517fc9Smrg * \param drmCommandIndex command index 3078fe517fc9Smrg * 307922944501Smrg * \return zero on success, or a negative value on failure. 3080fe517fc9Smrg * 308122944501Smrg * \internal 3082fe517fc9Smrg * It issues a ioctl given by 308322944501Smrg * \code DRM_COMMAND_BASE + drmCommandIndex \endcode. 308422944501Smrg */ 30856260e5d5Smrgdrm_public int drmCommandNone(int fd, unsigned long drmCommandIndex) 308622944501Smrg{ 308722944501Smrg unsigned long request; 308822944501Smrg 308922944501Smrg request = DRM_IO( DRM_COMMAND_BASE + drmCommandIndex); 309022944501Smrg 3091424e9256Smrg if (drmIoctl(fd, request, NULL)) { 3092fe517fc9Smrg return -errno; 309322944501Smrg } 309422944501Smrg return 0; 309522944501Smrg} 309622944501Smrg 309722944501Smrg 309822944501Smrg/** 309922944501Smrg * Send a device-specific read command. 310022944501Smrg * 310122944501Smrg * \param fd file descriptor. 3102fe517fc9Smrg * \param drmCommandIndex command index 310322944501Smrg * \param data destination pointer of the data to be read. 310422944501Smrg * \param size size of the data to be read. 3105fe517fc9Smrg * 310622944501Smrg * \return zero on success, or a negative value on failure. 310722944501Smrg * 310822944501Smrg * \internal 3109fe517fc9Smrg * It issues a read ioctl given by 311022944501Smrg * \code DRM_COMMAND_BASE + drmCommandIndex \endcode. 311122944501Smrg */ 31126260e5d5Smrgdrm_public int drmCommandRead(int fd, unsigned long drmCommandIndex, 31136260e5d5Smrg void *data, unsigned long size) 311422944501Smrg{ 311522944501Smrg unsigned long request; 311622944501Smrg 3117fe517fc9Smrg request = DRM_IOC( DRM_IOC_READ, DRM_IOCTL_BASE, 3118fe517fc9Smrg DRM_COMMAND_BASE + drmCommandIndex, size); 311922944501Smrg 312022944501Smrg if (drmIoctl(fd, request, data)) { 3121fe517fc9Smrg return -errno; 312222944501Smrg } 312322944501Smrg return 0; 312422944501Smrg} 312522944501Smrg 312622944501Smrg 312722944501Smrg/** 312822944501Smrg * Send a device-specific write command. 312922944501Smrg * 313022944501Smrg * \param fd file descriptor. 3131fe517fc9Smrg * \param drmCommandIndex command index 313222944501Smrg * \param data source pointer of the data to be written. 313322944501Smrg * \param size size of the data to be written. 3134fe517fc9Smrg * 313522944501Smrg * \return zero on success, or a negative value on failure. 3136fe517fc9Smrg * 313722944501Smrg * \internal 3138fe517fc9Smrg * It issues a write ioctl given by 313922944501Smrg * \code DRM_COMMAND_BASE + drmCommandIndex \endcode. 314022944501Smrg */ 31416260e5d5Smrgdrm_public int drmCommandWrite(int fd, unsigned long drmCommandIndex, 31426260e5d5Smrg void *data, unsigned long size) 314322944501Smrg{ 314422944501Smrg unsigned long request; 314522944501Smrg 3146fe517fc9Smrg request = DRM_IOC( DRM_IOC_WRITE, DRM_IOCTL_BASE, 3147fe517fc9Smrg DRM_COMMAND_BASE + drmCommandIndex, size); 314822944501Smrg 314922944501Smrg if (drmIoctl(fd, request, data)) { 3150fe517fc9Smrg return -errno; 315122944501Smrg } 315222944501Smrg return 0; 315322944501Smrg} 315422944501Smrg 315522944501Smrg 315622944501Smrg/** 315722944501Smrg * Send a device-specific read-write command. 315822944501Smrg * 315922944501Smrg * \param fd file descriptor. 3160fe517fc9Smrg * \param drmCommandIndex command index 316122944501Smrg * \param data source pointer of the data to be read and written. 316222944501Smrg * \param size size of the data to be read and written. 3163fe517fc9Smrg * 316422944501Smrg * \return zero on success, or a negative value on failure. 3165fe517fc9Smrg * 316622944501Smrg * \internal 3167fe517fc9Smrg * It issues a read-write ioctl given by 316822944501Smrg * \code DRM_COMMAND_BASE + drmCommandIndex \endcode. 316922944501Smrg */ 31706260e5d5Smrgdrm_public int drmCommandWriteRead(int fd, unsigned long drmCommandIndex, 31716260e5d5Smrg void *data, unsigned long size) 317222944501Smrg{ 317322944501Smrg unsigned long request; 317422944501Smrg 3175fe517fc9Smrg request = DRM_IOC( DRM_IOC_READ|DRM_IOC_WRITE, DRM_IOCTL_BASE, 3176fe517fc9Smrg DRM_COMMAND_BASE + drmCommandIndex, size); 317722944501Smrg 317822944501Smrg if (drmIoctl(fd, request, data)) 3179fe517fc9Smrg return -errno; 318022944501Smrg return 0; 318122944501Smrg} 318222944501Smrg 318322944501Smrg#define DRM_MAX_FDS 16 318422944501Smrgstatic struct { 318522944501Smrg char *BusID; 318622944501Smrg int fd; 318722944501Smrg int refcount; 3188424e9256Smrg int type; 318922944501Smrg} connection[DRM_MAX_FDS]; 319022944501Smrg 319122944501Smrgstatic int nr_fds = 0; 319222944501Smrg 31936260e5d5Smrgdrm_public int drmOpenOnce(void *unused, const char *BusID, int *newlyopened) 3194424e9256Smrg{ 3195424e9256Smrg return drmOpenOnceWithType(BusID, newlyopened, DRM_NODE_PRIMARY); 3196424e9256Smrg} 3197424e9256Smrg 31986260e5d5Smrgdrm_public int drmOpenOnceWithType(const char *BusID, int *newlyopened, 31996260e5d5Smrg int type) 320022944501Smrg{ 320122944501Smrg int i; 320222944501Smrg int fd; 3203fe517fc9Smrg 320422944501Smrg for (i = 0; i < nr_fds; i++) 3205fe517fc9Smrg if ((strcmp(BusID, connection[i].BusID) == 0) && 3206fe517fc9Smrg (connection[i].type == type)) { 3207fe517fc9Smrg connection[i].refcount++; 3208fe517fc9Smrg *newlyopened = 0; 3209fe517fc9Smrg return connection[i].fd; 3210fe517fc9Smrg } 321122944501Smrg 3212424e9256Smrg fd = drmOpenWithType(NULL, BusID, type); 3213fe517fc9Smrg if (fd < 0 || nr_fds == DRM_MAX_FDS) 3214fe517fc9Smrg return fd; 3215fe517fc9Smrg 321622944501Smrg connection[nr_fds].BusID = strdup(BusID); 321722944501Smrg connection[nr_fds].fd = fd; 321822944501Smrg connection[nr_fds].refcount = 1; 3219424e9256Smrg connection[nr_fds].type = type; 322022944501Smrg *newlyopened = 1; 322122944501Smrg 322222944501Smrg if (0) 3223fe517fc9Smrg fprintf(stderr, "saved connection %d for %s %d\n", 3224fe517fc9Smrg nr_fds, connection[nr_fds].BusID, 3225fe517fc9Smrg strcmp(BusID, connection[nr_fds].BusID)); 322622944501Smrg 322722944501Smrg nr_fds++; 322822944501Smrg 322922944501Smrg return fd; 323022944501Smrg} 323122944501Smrg 32326260e5d5Smrgdrm_public void drmCloseOnce(int fd) 323322944501Smrg{ 323422944501Smrg int i; 323522944501Smrg 323622944501Smrg for (i = 0; i < nr_fds; i++) { 3237fe517fc9Smrg if (fd == connection[i].fd) { 3238fe517fc9Smrg if (--connection[i].refcount == 0) { 3239fe517fc9Smrg drmClose(connection[i].fd); 3240fe517fc9Smrg free(connection[i].BusID); 3241fe517fc9Smrg 3242fe517fc9Smrg if (i < --nr_fds) 3243fe517fc9Smrg connection[i] = connection[nr_fds]; 3244fe517fc9Smrg 3245fe517fc9Smrg return; 3246fe517fc9Smrg } 3247fe517fc9Smrg } 324822944501Smrg } 324922944501Smrg} 325022944501Smrg 32516260e5d5Smrgdrm_public int drmSetMaster(int fd) 325222944501Smrg{ 3253fe517fc9Smrg return drmIoctl(fd, DRM_IOCTL_SET_MASTER, NULL); 325422944501Smrg} 325522944501Smrg 32566260e5d5Smrgdrm_public int drmDropMaster(int fd) 325722944501Smrg{ 3258fe517fc9Smrg return drmIoctl(fd, DRM_IOCTL_DROP_MASTER, NULL); 325922944501Smrg} 326022944501Smrg 3261bf6cc7dcSmrgdrm_public int drmIsMaster(int fd) 3262bf6cc7dcSmrg{ 3263bf6cc7dcSmrg /* Detect master by attempting something that requires master. 3264bf6cc7dcSmrg * 3265bf6cc7dcSmrg * Authenticating magic tokens requires master and 0 is an 3266bf6cc7dcSmrg * internal kernel detail which we could use. Attempting this on 3267bf6cc7dcSmrg * a master fd would fail therefore fail with EINVAL because 0 3268bf6cc7dcSmrg * is invalid. 3269bf6cc7dcSmrg * 3270bf6cc7dcSmrg * A non-master fd will fail with EACCES, as the kernel checks 3271bf6cc7dcSmrg * for master before attempting to do anything else. 3272bf6cc7dcSmrg * 3273bf6cc7dcSmrg * Since we don't want to leak implementation details, use 3274bf6cc7dcSmrg * EACCES. 3275bf6cc7dcSmrg */ 3276bf6cc7dcSmrg return drmAuthMagic(fd, 0) != -EACCES; 3277bf6cc7dcSmrg} 3278bf6cc7dcSmrg 32796260e5d5Smrgdrm_public char *drmGetDeviceNameFromFd(int fd) 328022944501Smrg{ 328187bf8e7cSmrg#ifdef __FreeBSD__ 328287bf8e7cSmrg struct stat sbuf; 328387bf8e7cSmrg int maj, min; 328487bf8e7cSmrg int nodetype; 328587bf8e7cSmrg 328687bf8e7cSmrg if (fstat(fd, &sbuf)) 328787bf8e7cSmrg return NULL; 328887bf8e7cSmrg 328987bf8e7cSmrg maj = major(sbuf.st_rdev); 329087bf8e7cSmrg min = minor(sbuf.st_rdev); 329187bf8e7cSmrg nodetype = drmGetMinorType(maj, min); 329287bf8e7cSmrg return drmGetMinorNameForFD(fd, nodetype); 329387bf8e7cSmrg#else 3294fe517fc9Smrg char name[128]; 3295fe517fc9Smrg struct stat sbuf; 3296fe517fc9Smrg dev_t d; 3297fe517fc9Smrg int i; 329822944501Smrg 3299fe517fc9Smrg /* The whole drmOpen thing is a fiasco and we need to find a way 3300fe517fc9Smrg * back to just using open(2). For now, however, lets just make 3301fe517fc9Smrg * things worse with even more ad hoc directory walking code to 3302fe517fc9Smrg * discover the device file name. */ 330322944501Smrg 3304fe517fc9Smrg fstat(fd, &sbuf); 3305fe517fc9Smrg d = sbuf.st_rdev; 330622944501Smrg 3307fe517fc9Smrg for (i = 0; i < DRM_MAX_MINOR; i++) { 3308fe517fc9Smrg snprintf(name, sizeof name, DRM_DEV_NAME, DRM_DIR_NAME, i); 3309fe517fc9Smrg if (stat(name, &sbuf) == 0 && sbuf.st_rdev == d) 3310fe517fc9Smrg break; 3311fe517fc9Smrg } 3312fe517fc9Smrg if (i == DRM_MAX_MINOR) 3313fe517fc9Smrg return NULL; 331422944501Smrg 3315fe517fc9Smrg return strdup(name); 331687bf8e7cSmrg#endif 331722944501Smrg} 331820131375Smrg 33196260e5d5Smrgstatic bool drmNodeIsDRM(int maj, int min) 33206260e5d5Smrg{ 33216260e5d5Smrg#ifdef __linux__ 33226260e5d5Smrg char path[64]; 33236260e5d5Smrg struct stat sbuf; 33246260e5d5Smrg 33256260e5d5Smrg snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device/drm", 33266260e5d5Smrg maj, min); 33276260e5d5Smrg return stat(path, &sbuf) == 0; 33284b3d3f37Smrg#elif defined(__FreeBSD__) 332987bf8e7cSmrg char name[SPECNAMELEN]; 333087bf8e7cSmrg 333187bf8e7cSmrg if (!devname_r(makedev(maj, min), S_IFCHR, name, sizeof(name))) 333287bf8e7cSmrg return 0; 333387bf8e7cSmrg /* Handle drm/ and dri/ as both are present in different FreeBSD version 333487bf8e7cSmrg * FreeBSD on amd64/i386/powerpc external kernel modules create node in 333587bf8e7cSmrg * in /dev/drm/ and links in /dev/dri while a WIP in kernel driver creates 333687bf8e7cSmrg * only device nodes in /dev/dri/ */ 333787bf8e7cSmrg return (!strncmp(name, "drm/", 4) || !strncmp(name, "dri/", 4)); 33386260e5d5Smrg#else 33396260e5d5Smrg return maj == DRM_MAJOR; 33406260e5d5Smrg#endif 33416260e5d5Smrg} 33426260e5d5Smrg 33436260e5d5Smrgdrm_public int drmGetNodeTypeFromFd(int fd) 3344424e9256Smrg{ 3345fe517fc9Smrg struct stat sbuf; 3346fe517fc9Smrg int maj, min, type; 3347424e9256Smrg 3348fe517fc9Smrg if (fstat(fd, &sbuf)) 3349fe517fc9Smrg return -1; 3350424e9256Smrg 3351fe517fc9Smrg maj = major(sbuf.st_rdev); 3352fe517fc9Smrg min = minor(sbuf.st_rdev); 3353424e9256Smrg 33546260e5d5Smrg if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode)) { 3355fe517fc9Smrg errno = EINVAL; 3356fe517fc9Smrg return -1; 3357fe517fc9Smrg } 3358424e9256Smrg 335987bf8e7cSmrg type = drmGetMinorType(maj, min); 3360fe517fc9Smrg if (type == -1) 3361fe517fc9Smrg errno = ENODEV; 3362fe517fc9Smrg return type; 3363424e9256Smrg} 3364424e9256Smrg 33656260e5d5Smrgdrm_public int drmPrimeHandleToFD(int fd, uint32_t handle, uint32_t flags, 33666260e5d5Smrg int *prime_fd) 336720131375Smrg{ 3368fe517fc9Smrg struct drm_prime_handle args; 3369fe517fc9Smrg int ret; 337020131375Smrg 3371fe517fc9Smrg memclear(args); 3372fe517fc9Smrg args.fd = -1; 3373fe517fc9Smrg args.handle = handle; 3374fe517fc9Smrg args.flags = flags; 3375fe517fc9Smrg ret = drmIoctl(fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &args); 3376fe517fc9Smrg if (ret) 3377fe517fc9Smrg return ret; 337820131375Smrg 3379fe517fc9Smrg *prime_fd = args.fd; 3380fe517fc9Smrg return 0; 338120131375Smrg} 338220131375Smrg 33836260e5d5Smrgdrm_public int drmPrimeFDToHandle(int fd, int prime_fd, uint32_t *handle) 338420131375Smrg{ 3385fe517fc9Smrg struct drm_prime_handle args; 3386fe517fc9Smrg int ret; 338720131375Smrg 3388fe517fc9Smrg memclear(args); 3389fe517fc9Smrg args.fd = prime_fd; 3390fe517fc9Smrg ret = drmIoctl(fd, DRM_IOCTL_PRIME_FD_TO_HANDLE, &args); 3391fe517fc9Smrg if (ret) 3392fe517fc9Smrg return ret; 339320131375Smrg 3394fe517fc9Smrg *handle = args.handle; 3395fe517fc9Smrg return 0; 339620131375Smrg} 3397424e9256Smrg 3398adfa0b0cSmrgdrm_public int drmCloseBufferHandle(int fd, uint32_t handle) 3399adfa0b0cSmrg{ 3400adfa0b0cSmrg struct drm_gem_close args; 3401adfa0b0cSmrg 3402adfa0b0cSmrg memclear(args); 3403adfa0b0cSmrg args.handle = handle; 3404adfa0b0cSmrg return drmIoctl(fd, DRM_IOCTL_GEM_CLOSE, &args); 3405adfa0b0cSmrg} 3406adfa0b0cSmrg 3407424e9256Smrgstatic char *drmGetMinorNameForFD(int fd, int type) 3408424e9256Smrg{ 3409424e9256Smrg#ifdef __linux__ 3410fe517fc9Smrg DIR *sysdir; 34116260e5d5Smrg struct dirent *ent; 3412fe517fc9Smrg struct stat sbuf; 3413fe517fc9Smrg const char *name = drmGetMinorName(type); 3414fe517fc9Smrg int len; 3415fe517fc9Smrg char dev_name[64], buf[64]; 3416fe517fc9Smrg int maj, min; 3417fe517fc9Smrg 3418fe517fc9Smrg if (!name) 3419fe517fc9Smrg return NULL; 3420424e9256Smrg 3421fe517fc9Smrg len = strlen(name); 3422424e9256Smrg 3423fe517fc9Smrg if (fstat(fd, &sbuf)) 3424fe517fc9Smrg return NULL; 3425424e9256Smrg 3426fe517fc9Smrg maj = major(sbuf.st_rdev); 3427fe517fc9Smrg min = minor(sbuf.st_rdev); 3428424e9256Smrg 34296260e5d5Smrg if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode)) 3430fe517fc9Smrg return NULL; 3431424e9256Smrg 3432fe517fc9Smrg snprintf(buf, sizeof(buf), "/sys/dev/char/%d:%d/device/drm", maj, min); 3433424e9256Smrg 3434fe517fc9Smrg sysdir = opendir(buf); 3435fe517fc9Smrg if (!sysdir) 3436fe517fc9Smrg return NULL; 3437424e9256Smrg 34386260e5d5Smrg while ((ent = readdir(sysdir))) { 3439fe517fc9Smrg if (strncmp(ent->d_name, name, len) == 0) { 3440adfa0b0cSmrg if (snprintf(dev_name, sizeof(dev_name), DRM_DIR_NAME "/%s", 3441adfa0b0cSmrg ent->d_name) < 0) 3442adfa0b0cSmrg return NULL; 3443424e9256Smrg 3444fe517fc9Smrg closedir(sysdir); 3445fe517fc9Smrg return strdup(dev_name); 3446fe517fc9Smrg } 3447fe517fc9Smrg } 3448424e9256Smrg 3449fe517fc9Smrg closedir(sysdir); 34506260e5d5Smrg return NULL; 34514b3d3f37Smrg#elif defined(__FreeBSD__) 345287bf8e7cSmrg struct stat sbuf; 345387bf8e7cSmrg char dname[SPECNAMELEN]; 345487bf8e7cSmrg const char *mname; 345587bf8e7cSmrg char name[SPECNAMELEN]; 345687bf8e7cSmrg int id, maj, min, nodetype, i; 345787bf8e7cSmrg 345887bf8e7cSmrg if (fstat(fd, &sbuf)) 345987bf8e7cSmrg return NULL; 346087bf8e7cSmrg 346187bf8e7cSmrg maj = major(sbuf.st_rdev); 346287bf8e7cSmrg min = minor(sbuf.st_rdev); 346387bf8e7cSmrg 346487bf8e7cSmrg if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode)) 346587bf8e7cSmrg return NULL; 346687bf8e7cSmrg 346787bf8e7cSmrg if (!devname_r(sbuf.st_rdev, S_IFCHR, dname, sizeof(dname))) 346887bf8e7cSmrg return NULL; 346987bf8e7cSmrg 347087bf8e7cSmrg /* Handle both /dev/drm and /dev/dri 347187bf8e7cSmrg * FreeBSD on amd64/i386/powerpc external kernel modules create node in 347287bf8e7cSmrg * in /dev/drm/ and links in /dev/dri while a WIP in kernel driver creates 347387bf8e7cSmrg * only device nodes in /dev/dri/ */ 347487bf8e7cSmrg 347587bf8e7cSmrg /* Get the node type represented by fd so we can deduce the target name */ 347687bf8e7cSmrg nodetype = drmGetMinorType(maj, min); 347787bf8e7cSmrg if (nodetype == -1) 347887bf8e7cSmrg return (NULL); 347987bf8e7cSmrg mname = drmGetMinorName(type); 348087bf8e7cSmrg 348187bf8e7cSmrg for (i = 0; i < SPECNAMELEN; i++) { 348287bf8e7cSmrg if (isalpha(dname[i]) == 0 && dname[i] != '/') 348387bf8e7cSmrg break; 348487bf8e7cSmrg } 348587bf8e7cSmrg if (dname[i] == '\0') 348687bf8e7cSmrg return (NULL); 348787bf8e7cSmrg 348887bf8e7cSmrg id = (int)strtol(&dname[i], NULL, 10); 348987bf8e7cSmrg id -= drmGetMinorBase(nodetype); 349087bf8e7cSmrg snprintf(name, sizeof(name), DRM_DIR_NAME "/%s%d", mname, 349187bf8e7cSmrg id + drmGetMinorBase(type)); 349287bf8e7cSmrg 349387bf8e7cSmrg return strdup(name); 3494fe517fc9Smrg#else 34952ee35494Smrg struct stat sbuf; 34962ee35494Smrg char buf[PATH_MAX + 1]; 349782025ec7Smrg const char *dev_name = drmGetDeviceName(type); 34982ee35494Smrg unsigned int maj, min; 349982025ec7Smrg int n; 35002ee35494Smrg 35012ee35494Smrg if (fstat(fd, &sbuf)) 35022ee35494Smrg return NULL; 35032ee35494Smrg 35042ee35494Smrg maj = major(sbuf.st_rdev); 35052ee35494Smrg min = minor(sbuf.st_rdev); 35062ee35494Smrg 35076260e5d5Smrg if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode)) 35082ee35494Smrg return NULL; 35092ee35494Smrg 351082025ec7Smrg if (!dev_name) 35112ee35494Smrg return NULL; 35122ee35494Smrg 351382025ec7Smrg n = snprintf(buf, sizeof(buf), dev_name, DRM_DIR_NAME, min); 35142ee35494Smrg if (n == -1 || n >= sizeof(buf)) 35152ee35494Smrg return NULL; 35162ee35494Smrg 35172ee35494Smrg return strdup(buf); 3518424e9256Smrg#endif 3519424e9256Smrg} 3520424e9256Smrg 35216260e5d5Smrgdrm_public char *drmGetPrimaryDeviceNameFromFd(int fd) 3522424e9256Smrg{ 3523fe517fc9Smrg return drmGetMinorNameForFD(fd, DRM_NODE_PRIMARY); 3524424e9256Smrg} 3525424e9256Smrg 35266260e5d5Smrgdrm_public char *drmGetRenderDeviceNameFromFd(int fd) 3527424e9256Smrg{ 3528fe517fc9Smrg return drmGetMinorNameForFD(fd, DRM_NODE_RENDER); 3529fe517fc9Smrg} 3530fe517fc9Smrg 35312ee35494Smrg#ifdef __linux__ 35322ee35494Smrgstatic char * DRM_PRINTFLIKE(2, 3) 35332ee35494Smrgsysfs_uevent_get(const char *path, const char *fmt, ...) 35342ee35494Smrg{ 35352ee35494Smrg char filename[PATH_MAX + 1], *key, *line = NULL, *value = NULL; 35362ee35494Smrg size_t size = 0, len; 35372ee35494Smrg ssize_t num; 35382ee35494Smrg va_list ap; 35392ee35494Smrg FILE *fp; 35402ee35494Smrg 35412ee35494Smrg va_start(ap, fmt); 35422ee35494Smrg num = vasprintf(&key, fmt, ap); 35432ee35494Smrg va_end(ap); 35442ee35494Smrg len = num; 35452ee35494Smrg 35462ee35494Smrg snprintf(filename, sizeof(filename), "%s/uevent", path); 35472ee35494Smrg 35482ee35494Smrg fp = fopen(filename, "r"); 35492ee35494Smrg if (!fp) { 35502ee35494Smrg free(key); 35512ee35494Smrg return NULL; 35522ee35494Smrg } 35532ee35494Smrg 35542ee35494Smrg while ((num = getline(&line, &size, fp)) >= 0) { 35552ee35494Smrg if ((strncmp(line, key, len) == 0) && (line[len] == '=')) { 35562ee35494Smrg char *start = line + len + 1, *end = line + num - 1; 35572ee35494Smrg 35582ee35494Smrg if (*end != '\n') 35592ee35494Smrg end++; 35602ee35494Smrg 35612ee35494Smrg value = strndup(start, end - start); 35622ee35494Smrg break; 35632ee35494Smrg } 35642ee35494Smrg } 35652ee35494Smrg 35662ee35494Smrg free(line); 35672ee35494Smrg fclose(fp); 35682ee35494Smrg 35692ee35494Smrg free(key); 35702ee35494Smrg 35712ee35494Smrg return value; 35722ee35494Smrg} 35732ee35494Smrg#endif 35742ee35494Smrg 35756260e5d5Smrg/* Little white lie to avoid major rework of the existing code */ 35766260e5d5Smrg#define DRM_BUS_VIRTIO 0x10 35776260e5d5Smrg 3578fe517fc9Smrg#ifdef __linux__ 357987bf8e7cSmrgstatic int get_subsystem_type(const char *device_path) 358087bf8e7cSmrg{ 358187bf8e7cSmrg char path[PATH_MAX + 1] = ""; 3582fe517fc9Smrg char link[PATH_MAX + 1] = ""; 3583fe517fc9Smrg char *name; 35844545e80cSmrg struct { 35854545e80cSmrg const char *name; 35864545e80cSmrg int bus_type; 35874545e80cSmrg } bus_types[] = { 35884545e80cSmrg { "/pci", DRM_BUS_PCI }, 35894545e80cSmrg { "/usb", DRM_BUS_USB }, 35904545e80cSmrg { "/platform", DRM_BUS_PLATFORM }, 35914545e80cSmrg { "/spi", DRM_BUS_PLATFORM }, 35924545e80cSmrg { "/host1x", DRM_BUS_HOST1X }, 35934545e80cSmrg { "/virtio", DRM_BUS_VIRTIO }, 35944545e80cSmrg }; 3595fe517fc9Smrg 359687bf8e7cSmrg strncpy(path, device_path, PATH_MAX); 359787bf8e7cSmrg strncat(path, "/subsystem", PATH_MAX); 3598fe517fc9Smrg 3599fe517fc9Smrg if (readlink(path, link, PATH_MAX) < 0) 3600fe517fc9Smrg return -errno; 3601fe517fc9Smrg 3602fe517fc9Smrg name = strrchr(link, '/'); 3603fe517fc9Smrg if (!name) 3604fe517fc9Smrg return -EINVAL; 3605fe517fc9Smrg 36064545e80cSmrg for (unsigned i = 0; i < ARRAY_SIZE(bus_types); i++) { 36074545e80cSmrg if (strncmp(name, bus_types[i].name, strlen(bus_types[i].name)) == 0) 36084545e80cSmrg return bus_types[i].bus_type; 36094545e80cSmrg } 36106260e5d5Smrg 3611fe517fc9Smrg return -EINVAL; 361287bf8e7cSmrg} 361387bf8e7cSmrg#endif 361487bf8e7cSmrg 361587bf8e7cSmrgstatic int drmParseSubsystemType(int maj, int min) 361687bf8e7cSmrg{ 361787bf8e7cSmrg#ifdef __linux__ 361887bf8e7cSmrg char path[PATH_MAX + 1] = ""; 361987bf8e7cSmrg char real_path[PATH_MAX + 1] = ""; 362087bf8e7cSmrg int subsystem_type; 362187bf8e7cSmrg 362287bf8e7cSmrg snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min); 362387bf8e7cSmrg 362487bf8e7cSmrg subsystem_type = get_subsystem_type(path); 362587bf8e7cSmrg /* Try to get the parent (underlying) device type */ 362687bf8e7cSmrg if (subsystem_type == DRM_BUS_VIRTIO) { 362787bf8e7cSmrg /* Assume virtio-pci on error */ 362887bf8e7cSmrg if (!realpath(path, real_path)) 362987bf8e7cSmrg return DRM_BUS_VIRTIO; 363087bf8e7cSmrg strncat(path, "/..", PATH_MAX); 363187bf8e7cSmrg subsystem_type = get_subsystem_type(path); 363287bf8e7cSmrg if (subsystem_type < 0) 363387bf8e7cSmrg return DRM_BUS_VIRTIO; 363487bf8e7cSmrg } 3635a970b457Sriastradh#elif defined(__NetBSD__) 3636a970b457Sriastradh int type, fd; 3637a970b457Sriastradh drmSetVersion sv; 3638a970b457Sriastradh char *buf; 3639a970b457Sriastradh unsigned domain, bus, dev; 3640a970b457Sriastradh int func; 3641a970b457Sriastradh int ret; 3642a970b457Sriastradh 3643a970b457Sriastradh /* Get the type of device we're looking for to pick the right pathname. */ 364477e87e13Smrg type = drmGetMinorType(maj, min); 3645a970b457Sriastradh if (type == -1) 3646a970b457Sriastradh return -ENODEV; 3647a970b457Sriastradh 3648a970b457Sriastradh /* Open the device. Don't try to create it if it's not there. */ 3649a970b457Sriastradh fd = drmOpenMinor(min, 0, type); 3650a970b457Sriastradh if (fd < 0) 3651a970b457Sriastradh return -errno; 3652a970b457Sriastradh 3653a970b457Sriastradh /* 3654a970b457Sriastradh * Set the interface version to 1.4 or 1.1, which has the effect of 3655a970b457Sriastradh * populating the bus id for us. 3656a970b457Sriastradh */ 3657a970b457Sriastradh sv.drm_di_major = 1; 3658a970b457Sriastradh sv.drm_di_minor = 4; 3659a970b457Sriastradh sv.drm_dd_major = -1; 3660a970b457Sriastradh sv.drm_dd_minor = -1; 3661a970b457Sriastradh if (drmSetInterfaceVersion(fd, &sv)) { 3662a970b457Sriastradh sv.drm_di_major = 1; 3663a970b457Sriastradh sv.drm_di_minor = 1; 3664a970b457Sriastradh sv.drm_dd_major = -1; 3665a970b457Sriastradh sv.drm_dd_minor = -1; 3666a970b457Sriastradh if (drmSetInterfaceVersion(fd, &sv)) { 36675046d36bSriastradh /* 36685046d36bSriastradh * We're probably not the master. Hope the master already 36695046d36bSriastradh * set the version to >=1.1 so that we can get the busid. 36705046d36bSriastradh */ 3671a970b457Sriastradh } 3672a970b457Sriastradh } 3673a970b457Sriastradh 3674a970b457Sriastradh /* Get the bus id. */ 3675a970b457Sriastradh buf = drmGetBusid(fd); 3676a970b457Sriastradh 3677a970b457Sriastradh /* We're done with the device now. */ 3678a970b457Sriastradh (void)close(fd); 3679a970b457Sriastradh 3680a970b457Sriastradh /* If there is no bus id, fail. */ 3681a970b457Sriastradh if (buf == NULL) 3682a970b457Sriastradh return -ENODEV; 3683a970b457Sriastradh 3684a970b457Sriastradh /* Find a string we know about; otherwise -EINVAL. */ 3685a970b457Sriastradh ret = -EINVAL; 368648994cb0Sriastradh if (strncmp(buf, "pci:", 4) == 0) 3687a970b457Sriastradh ret = DRM_BUS_PCI; 3688a970b457Sriastradh 3689a970b457Sriastradh /* We're done with the bus id. */ 3690a970b457Sriastradh free(buf); 3691a970b457Sriastradh 3692a970b457Sriastradh /* Success or not, we're done. */ 3693a970b457Sriastradh return ret; 36944545e80cSmrg#elif defined(__OpenBSD__) || defined(__DragonFly__) 36952ee35494Smrg return DRM_BUS_PCI; 3696fe517fc9Smrg#else 3697fe517fc9Smrg#warning "Missing implementation of drmParseSubsystemType" 3698fe517fc9Smrg return -EINVAL; 3699fe517fc9Smrg#endif 3700fe517fc9Smrg} 3701fe517fc9Smrg 370287bf8e7cSmrg#ifdef __linux__ 37036260e5d5Smrgstatic void 37046260e5d5Smrgget_pci_path(int maj, int min, char *pci_path) 37056260e5d5Smrg{ 37066260e5d5Smrg char path[PATH_MAX + 1], *term; 37076260e5d5Smrg 37086260e5d5Smrg snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min); 37096260e5d5Smrg if (!realpath(path, pci_path)) { 37106260e5d5Smrg strcpy(pci_path, path); 37116260e5d5Smrg return; 37126260e5d5Smrg } 37136260e5d5Smrg 37146260e5d5Smrg term = strrchr(pci_path, '/'); 37156260e5d5Smrg if (term && strncmp(term, "/virtio", 7) == 0) 37166260e5d5Smrg *term = 0; 37176260e5d5Smrg} 371887bf8e7cSmrg#endif 371987bf8e7cSmrg 372087bf8e7cSmrg#ifdef __FreeBSD__ 372187bf8e7cSmrgstatic int get_sysctl_pci_bus_info(int maj, int min, drmPciBusInfoPtr info) 372287bf8e7cSmrg{ 372387bf8e7cSmrg char dname[SPECNAMELEN]; 372487bf8e7cSmrg char sysctl_name[16]; 372587bf8e7cSmrg char sysctl_val[256]; 372687bf8e7cSmrg size_t sysctl_len; 372787bf8e7cSmrg int id, type, nelem; 372887bf8e7cSmrg unsigned int rdev, majmin, domain, bus, dev, func; 372987bf8e7cSmrg 373087bf8e7cSmrg rdev = makedev(maj, min); 373187bf8e7cSmrg if (!devname_r(rdev, S_IFCHR, dname, sizeof(dname))) 373287bf8e7cSmrg return -EINVAL; 373387bf8e7cSmrg 373487bf8e7cSmrg if (sscanf(dname, "drm/%d\n", &id) != 1) 373587bf8e7cSmrg return -EINVAL; 373687bf8e7cSmrg type = drmGetMinorType(maj, min); 373787bf8e7cSmrg if (type == -1) 373887bf8e7cSmrg return -EINVAL; 373987bf8e7cSmrg 374087bf8e7cSmrg /* BUG: This above section is iffy, since it mandates that a driver will 374187bf8e7cSmrg * create both card and render node. 374287bf8e7cSmrg * If it does not, the next DRM device will create card#X and 374387bf8e7cSmrg * renderD#(128+X)-1. 374487bf8e7cSmrg * This is a possibility in FreeBSD but for now there is no good way for 374587bf8e7cSmrg * obtaining the info. 374687bf8e7cSmrg */ 374787bf8e7cSmrg switch (type) { 374887bf8e7cSmrg case DRM_NODE_PRIMARY: 374987bf8e7cSmrg break; 375087bf8e7cSmrg case DRM_NODE_RENDER: 375187bf8e7cSmrg id -= 128; 375248246ce7Smrg break; 375387bf8e7cSmrg } 375487bf8e7cSmrg if (id < 0) 375587bf8e7cSmrg return -EINVAL; 375687bf8e7cSmrg 375787bf8e7cSmrg if (snprintf(sysctl_name, sizeof(sysctl_name), "hw.dri.%d.busid", id) <= 0) 375887bf8e7cSmrg return -EINVAL; 375987bf8e7cSmrg sysctl_len = sizeof(sysctl_val); 376087bf8e7cSmrg if (sysctlbyname(sysctl_name, sysctl_val, &sysctl_len, NULL, 0)) 376187bf8e7cSmrg return -EINVAL; 376287bf8e7cSmrg 376387bf8e7cSmrg #define bus_fmt "pci:%04x:%02x:%02x.%u" 376487bf8e7cSmrg 376587bf8e7cSmrg nelem = sscanf(sysctl_val, bus_fmt, &domain, &bus, &dev, &func); 376687bf8e7cSmrg if (nelem != 4) 376787bf8e7cSmrg return -EINVAL; 376887bf8e7cSmrg info->domain = domain; 376987bf8e7cSmrg info->bus = bus; 377087bf8e7cSmrg info->dev = dev; 377187bf8e7cSmrg info->func = func; 377287bf8e7cSmrg 377387bf8e7cSmrg return 0; 377487bf8e7cSmrg} 377587bf8e7cSmrg#endif 37766260e5d5Smrg 3777fe517fc9Smrgstatic int drmParsePciBusInfo(int maj, int min, drmPciBusInfoPtr info) 3778fe517fc9Smrg{ 3779fe517fc9Smrg#ifdef __linux__ 37802ee35494Smrg unsigned int domain, bus, dev, func; 37816260e5d5Smrg char pci_path[PATH_MAX + 1], *value; 37822ee35494Smrg int num; 3783fe517fc9Smrg 37846260e5d5Smrg get_pci_path(maj, min, pci_path); 3785fe517fc9Smrg 37866260e5d5Smrg value = sysfs_uevent_get(pci_path, "PCI_SLOT_NAME"); 37872ee35494Smrg if (!value) 37882ee35494Smrg return -ENOENT; 3789fe517fc9Smrg 37902ee35494Smrg num = sscanf(value, "%04x:%02x:%02x.%1u", &domain, &bus, &dev, &func); 37912ee35494Smrg free(value); 3792fe517fc9Smrg 37932ee35494Smrg if (num != 4) 3794fe517fc9Smrg return -EINVAL; 3795fe517fc9Smrg 3796fe517fc9Smrg info->domain = domain; 3797fe517fc9Smrg info->bus = bus; 3798fe517fc9Smrg info->dev = dev; 3799fe517fc9Smrg info->func = func; 3800fe517fc9Smrg 3801a970b457Sriastradh return 0; 3802a970b457Sriastradh#elif defined(__NetBSD__) 3803a970b457Sriastradh int type, fd; 3804a970b457Sriastradh drmSetVersion sv; 3805a970b457Sriastradh char *buf; 3806a970b457Sriastradh unsigned domain, bus, dev; 3807a970b457Sriastradh int func; 3808a970b457Sriastradh int ret; 3809a970b457Sriastradh 3810a970b457Sriastradh /* Get the type of device we're looking for to pick the right pathname. */ 381177e87e13Smrg type = drmGetMinorType(maj, min); 3812a970b457Sriastradh if (type == -1) 3813a970b457Sriastradh return -ENODEV; 3814a970b457Sriastradh 3815a970b457Sriastradh /* Open the device. Don't try to create it if it's not there. */ 3816a970b457Sriastradh fd = drmOpenMinor(min, 0, type); 3817a970b457Sriastradh if (fd < 0) 3818a970b457Sriastradh return -errno; 3819a970b457Sriastradh 3820a970b457Sriastradh /* 3821a970b457Sriastradh * Set the interface version to 1.4 or 1.1, which has the effect of 3822a970b457Sriastradh * populating the bus id for us. 3823a970b457Sriastradh */ 3824a970b457Sriastradh sv.drm_di_major = 1; 3825a970b457Sriastradh sv.drm_di_minor = 4; 3826a970b457Sriastradh sv.drm_dd_major = -1; 3827a970b457Sriastradh sv.drm_dd_minor = -1; 3828a970b457Sriastradh if (drmSetInterfaceVersion(fd, &sv)) { 3829a970b457Sriastradh sv.drm_di_major = 1; 3830a970b457Sriastradh sv.drm_di_minor = 1; 3831a970b457Sriastradh sv.drm_dd_major = -1; 3832a970b457Sriastradh sv.drm_dd_minor = -1; 3833a970b457Sriastradh if (drmSetInterfaceVersion(fd, &sv)) { 383406815bcbSmaya /* 383506815bcbSmaya * We're probably not the master. Hope the master already 383606815bcbSmaya * set the version to >=1.1 so that we can get the busid. 383706815bcbSmaya */ 3838a970b457Sriastradh } 3839a970b457Sriastradh } 3840a970b457Sriastradh 3841a970b457Sriastradh /* Get the bus id. */ 3842a970b457Sriastradh buf = drmGetBusid(fd); 3843a970b457Sriastradh 3844a970b457Sriastradh /* We're done with the device now. */ 3845a970b457Sriastradh (void)close(fd); 3846a970b457Sriastradh 3847a970b457Sriastradh /* If there is no bus id, fail. */ 3848a970b457Sriastradh if (buf == NULL) 3849a970b457Sriastradh return -ENODEV; 3850a970b457Sriastradh 3851a970b457Sriastradh /* Parse the bus id. */ 3852a970b457Sriastradh ret = sscanf(buf, "pci:%04x:%02x:%02x.%d", &domain, &bus, &dev, &func); 3853a970b457Sriastradh 3854a970b457Sriastradh /* We're done with the bus id. */ 3855a970b457Sriastradh free(buf); 3856a970b457Sriastradh 3857a970b457Sriastradh /* If scanf didn't return 4 -- domain, bus, dev, func -- then fail. */ 3858a970b457Sriastradh if (ret != 4) 3859a970b457Sriastradh return -ENODEV; 3860a970b457Sriastradh 3861a970b457Sriastradh /* Populate the results. */ 3862a970b457Sriastradh info->domain = domain; 3863a970b457Sriastradh info->bus = bus; 3864a970b457Sriastradh info->dev = dev; 3865a970b457Sriastradh info->func = func; 3866a970b457Sriastradh 3867a970b457Sriastradh /* Success! */ 38682ee35494Smrg return 0; 38694545e80cSmrg#elif defined(__OpenBSD__) || defined(__DragonFly__) 38702ee35494Smrg struct drm_pciinfo pinfo; 38712ee35494Smrg int fd, type; 38722ee35494Smrg 387387bf8e7cSmrg type = drmGetMinorType(maj, min); 38742ee35494Smrg if (type == -1) 38752ee35494Smrg return -ENODEV; 38762ee35494Smrg 38772ee35494Smrg fd = drmOpenMinor(min, 0, type); 38782ee35494Smrg if (fd < 0) 38792ee35494Smrg return -errno; 38802ee35494Smrg 38812ee35494Smrg if (drmIoctl(fd, DRM_IOCTL_GET_PCIINFO, &pinfo)) { 38822ee35494Smrg close(fd); 38832ee35494Smrg return -errno; 38842ee35494Smrg } 38852ee35494Smrg close(fd); 38862ee35494Smrg 38872ee35494Smrg info->domain = pinfo.domain; 38882ee35494Smrg info->bus = pinfo.bus; 38892ee35494Smrg info->dev = pinfo.dev; 38902ee35494Smrg info->func = pinfo.func; 38912ee35494Smrg 3892fe517fc9Smrg return 0; 38934b3d3f37Smrg#elif defined(__FreeBSD__) 389487bf8e7cSmrg return get_sysctl_pci_bus_info(maj, min, info); 3895fe517fc9Smrg#else 3896fe517fc9Smrg#warning "Missing implementation of drmParsePciBusInfo" 3897fe517fc9Smrg return -EINVAL; 3898fe517fc9Smrg#endif 3899fe517fc9Smrg} 3900fe517fc9Smrg 39016260e5d5Smrgdrm_public int drmDevicesEqual(drmDevicePtr a, drmDevicePtr b) 3902fe517fc9Smrg{ 3903fe517fc9Smrg if (a == NULL || b == NULL) 39040655efefSmrg return 0; 3905fe517fc9Smrg 3906fe517fc9Smrg if (a->bustype != b->bustype) 39070655efefSmrg return 0; 3908fe517fc9Smrg 3909fe517fc9Smrg switch (a->bustype) { 3910fe517fc9Smrg case DRM_BUS_PCI: 39110655efefSmrg return memcmp(a->businfo.pci, b->businfo.pci, sizeof(drmPciBusInfo)) == 0; 39122ee35494Smrg 39132ee35494Smrg case DRM_BUS_USB: 39140655efefSmrg return memcmp(a->businfo.usb, b->businfo.usb, sizeof(drmUsbBusInfo)) == 0; 39152ee35494Smrg 39162ee35494Smrg case DRM_BUS_PLATFORM: 39170655efefSmrg return memcmp(a->businfo.platform, b->businfo.platform, sizeof(drmPlatformBusInfo)) == 0; 39182ee35494Smrg 39192ee35494Smrg case DRM_BUS_HOST1X: 39200655efefSmrg return memcmp(a->businfo.host1x, b->businfo.host1x, sizeof(drmHost1xBusInfo)) == 0; 39212ee35494Smrg 3922fe517fc9Smrg default: 3923fe517fc9Smrg break; 3924fe517fc9Smrg } 3925fe517fc9Smrg 39260655efefSmrg return 0; 3927fe517fc9Smrg} 3928fe517fc9Smrg 3929fe517fc9Smrgstatic int drmGetNodeType(const char *name) 3930fe517fc9Smrg{ 3931fe517fc9Smrg if (strncmp(name, DRM_RENDER_MINOR_NAME, 3932fe517fc9Smrg sizeof(DRM_RENDER_MINOR_NAME) - 1) == 0) 3933fe517fc9Smrg return DRM_NODE_RENDER; 3934fe517fc9Smrg 393582025ec7Smrg if (strncmp(name, DRM_PRIMARY_MINOR_NAME, 393682025ec7Smrg sizeof(DRM_PRIMARY_MINOR_NAME) - 1) == 0) 393782025ec7Smrg return DRM_NODE_PRIMARY; 393882025ec7Smrg 3939fe517fc9Smrg return -EINVAL; 3940fe517fc9Smrg} 3941fe517fc9Smrg 3942fe517fc9Smrgstatic int drmGetMaxNodeName(void) 3943fe517fc9Smrg{ 3944fe517fc9Smrg return sizeof(DRM_DIR_NAME) + 3945fe517fc9Smrg MAX3(sizeof(DRM_PRIMARY_MINOR_NAME), 3946fe517fc9Smrg sizeof(DRM_CONTROL_MINOR_NAME), 3947fe517fc9Smrg sizeof(DRM_RENDER_MINOR_NAME)) + 3948fe517fc9Smrg 3 /* length of the node number */; 3949fe517fc9Smrg} 3950fe517fc9Smrg 3951fe517fc9Smrg#ifdef __linux__ 39522ee35494Smrgstatic int parse_separate_sysfs_files(int maj, int min, 39532ee35494Smrg drmPciDeviceInfoPtr device, 39542ee35494Smrg bool ignore_revision) 39552ee35494Smrg{ 39562ee35494Smrg static const char *attrs[] = { 39572ee35494Smrg "revision", /* Older kernels are missing the file, so check for it first */ 39582ee35494Smrg "vendor", 39592ee35494Smrg "device", 39602ee35494Smrg "subsystem_vendor", 39612ee35494Smrg "subsystem_device", 39622ee35494Smrg }; 39636260e5d5Smrg char path[PATH_MAX + 1], pci_path[PATH_MAX + 1]; 39642ee35494Smrg unsigned int data[ARRAY_SIZE(attrs)]; 39652ee35494Smrg FILE *fp; 39662ee35494Smrg int ret; 39672ee35494Smrg 39686260e5d5Smrg get_pci_path(maj, min, pci_path); 39696260e5d5Smrg 39702ee35494Smrg for (unsigned i = ignore_revision ? 1 : 0; i < ARRAY_SIZE(attrs); i++) { 3971adfa0b0cSmrg if (snprintf(path, PATH_MAX, "%s/%s", pci_path, attrs[i]) < 0) 3972adfa0b0cSmrg return -errno; 3973adfa0b0cSmrg 39742ee35494Smrg fp = fopen(path, "r"); 39752ee35494Smrg if (!fp) 39762ee35494Smrg return -errno; 39772ee35494Smrg 39782ee35494Smrg ret = fscanf(fp, "%x", &data[i]); 39792ee35494Smrg fclose(fp); 39802ee35494Smrg if (ret != 1) 39812ee35494Smrg return -errno; 39822ee35494Smrg 39832ee35494Smrg } 39842ee35494Smrg 39852ee35494Smrg device->revision_id = ignore_revision ? 0xff : data[0] & 0xff; 39862ee35494Smrg device->vendor_id = data[1] & 0xffff; 39872ee35494Smrg device->device_id = data[2] & 0xffff; 39882ee35494Smrg device->subvendor_id = data[3] & 0xffff; 39892ee35494Smrg device->subdevice_id = data[4] & 0xffff; 39902ee35494Smrg 39912ee35494Smrg return 0; 39922ee35494Smrg} 39932ee35494Smrg 39942ee35494Smrgstatic int parse_config_sysfs_file(int maj, int min, 39952ee35494Smrg drmPciDeviceInfoPtr device) 39962ee35494Smrg{ 39976260e5d5Smrg char path[PATH_MAX + 1], pci_path[PATH_MAX + 1]; 3998fe517fc9Smrg unsigned char config[64]; 3999fe517fc9Smrg int fd, ret; 4000fe517fc9Smrg 40016260e5d5Smrg get_pci_path(maj, min, pci_path); 40026260e5d5Smrg 4003adfa0b0cSmrg if (snprintf(path, PATH_MAX, "%s/config", pci_path) < 0) 4004adfa0b0cSmrg return -errno; 4005adfa0b0cSmrg 4006fe517fc9Smrg fd = open(path, O_RDONLY); 4007fe517fc9Smrg if (fd < 0) 4008fe517fc9Smrg return -errno; 4009fe517fc9Smrg 4010fe517fc9Smrg ret = read(fd, config, sizeof(config)); 4011fe517fc9Smrg close(fd); 4012fe517fc9Smrg if (ret < 0) 4013fe517fc9Smrg return -errno; 4014fe517fc9Smrg 4015fe517fc9Smrg device->vendor_id = config[0] | (config[1] << 8); 4016fe517fc9Smrg device->device_id = config[2] | (config[3] << 8); 4017fe517fc9Smrg device->revision_id = config[8]; 4018fe517fc9Smrg device->subvendor_id = config[44] | (config[45] << 8); 4019fe517fc9Smrg device->subdevice_id = config[46] | (config[47] << 8); 4020fe517fc9Smrg 40212ee35494Smrg return 0; 40222ee35494Smrg} 40232ee35494Smrg#endif 40242ee35494Smrg 40252ee35494Smrgstatic int drmParsePciDeviceInfo(int maj, int min, 40262ee35494Smrg drmPciDeviceInfoPtr device, 40272ee35494Smrg uint32_t flags) 40282ee35494Smrg{ 40292ee35494Smrg#ifdef __linux__ 40302ee35494Smrg if (!(flags & DRM_DEVICE_GET_PCI_REVISION)) 40312ee35494Smrg return parse_separate_sysfs_files(maj, min, device, true); 40322ee35494Smrg 40332ee35494Smrg if (parse_separate_sysfs_files(maj, min, device, false)) 40342ee35494Smrg return parse_config_sysfs_file(maj, min, device); 40352ee35494Smrg 40362ee35494Smrg return 0; 4037a970b457Sriastradh#elif defined(__NetBSD__) 4038a970b457Sriastradh drmPciBusInfo businfo; 4039a970b457Sriastradh char fname[PATH_MAX]; 4040a970b457Sriastradh int pcifd; 4041a970b457Sriastradh pcireg_t id, class, subsys; 4042a970b457Sriastradh int ret; 4043a970b457Sriastradh 4044a970b457Sriastradh /* Find where on the bus the device lives. */ 4045a970b457Sriastradh ret = drmParsePciBusInfo(maj, min, &businfo); 4046a970b457Sriastradh if (ret) 4047a970b457Sriastradh return ret; 4048a970b457Sriastradh 4049a970b457Sriastradh /* Open the pciN device node to get at its config registers. */ 4050a970b457Sriastradh if (snprintf(fname, sizeof fname, "/dev/pci%u", businfo.domain) 4051a970b457Sriastradh >= sizeof fname) 4052a970b457Sriastradh return -ENODEV; 4053a970b457Sriastradh if ((pcifd = open(fname, O_RDONLY)) == -1) 4054a970b457Sriastradh return -errno; 4055a970b457Sriastradh 4056f8b67707Schristos ret = -1; 4057a970b457Sriastradh /* Read the id and class pci config registers. */ 4058a970b457Sriastradh if (pcibus_conf_read(pcifd, businfo.bus, businfo.dev, businfo.func, 4059a970b457Sriastradh PCI_ID_REG, &id) == -1) 4060f8b67707Schristos goto out; 4061a970b457Sriastradh if (pcibus_conf_read(pcifd, businfo.bus, businfo.dev, businfo.func, 4062a970b457Sriastradh PCI_CLASS_REG, &class) == -1) 4063f8b67707Schristos goto out; 4064a970b457Sriastradh if (pcibus_conf_read(pcifd, businfo.bus, businfo.dev, businfo.func, 4065a970b457Sriastradh PCI_SUBSYS_ID_REG, &subsys) == -1) 4066f8b67707Schristos goto out; 4067a970b457Sriastradh 4068f8b67707Schristos ret = 0; 4069a970b457Sriastradh device->vendor_id = PCI_VENDOR(id); 4070a970b457Sriastradh device->device_id = PCI_PRODUCT(id); 4071a970b457Sriastradh device->subvendor_id = PCI_SUBSYS_VENDOR(subsys); 4072a970b457Sriastradh device->subdevice_id = PCI_SUBSYS_ID(subsys); 4073a970b457Sriastradh device->revision_id = PCI_REVISION(class); 4074f8b67707Schristosout: 4075f8b67707Schristos if (ret == -1) 4076f8b67707Schristos ret = -errno; 4077f8b67707Schristos close(pcifd); 4078f8b67707Schristos return ret; 40794545e80cSmrg#elif defined(__OpenBSD__) || defined(__DragonFly__) 40802ee35494Smrg struct drm_pciinfo pinfo; 40812ee35494Smrg int fd, type; 40822ee35494Smrg 408387bf8e7cSmrg type = drmGetMinorType(maj, min); 40842ee35494Smrg if (type == -1) 40852ee35494Smrg return -ENODEV; 40862ee35494Smrg 40872ee35494Smrg fd = drmOpenMinor(min, 0, type); 40882ee35494Smrg if (fd < 0) 40892ee35494Smrg return -errno; 40902ee35494Smrg 40912ee35494Smrg if (drmIoctl(fd, DRM_IOCTL_GET_PCIINFO, &pinfo)) { 40922ee35494Smrg close(fd); 40932ee35494Smrg return -errno; 40942ee35494Smrg } 40952ee35494Smrg close(fd); 40962ee35494Smrg 40972ee35494Smrg device->vendor_id = pinfo.vendor_id; 40982ee35494Smrg device->device_id = pinfo.device_id; 40992ee35494Smrg device->revision_id = pinfo.revision_id; 41002ee35494Smrg device->subvendor_id = pinfo.subvendor_id; 41012ee35494Smrg device->subdevice_id = pinfo.subdevice_id; 41022ee35494Smrg 410387bf8e7cSmrg return 0; 41044b3d3f37Smrg#elif defined(__FreeBSD__) 410587bf8e7cSmrg drmPciBusInfo info; 410687bf8e7cSmrg struct pci_conf_io pc; 410787bf8e7cSmrg struct pci_match_conf patterns[1]; 410887bf8e7cSmrg struct pci_conf results[1]; 410987bf8e7cSmrg int fd, error; 411087bf8e7cSmrg 411187bf8e7cSmrg if (get_sysctl_pci_bus_info(maj, min, &info) != 0) 411287bf8e7cSmrg return -EINVAL; 411387bf8e7cSmrg 41143b115362Smrg fd = open("/dev/pci", O_RDONLY); 411587bf8e7cSmrg if (fd < 0) 411687bf8e7cSmrg return -errno; 411787bf8e7cSmrg 411887bf8e7cSmrg bzero(&patterns, sizeof(patterns)); 411987bf8e7cSmrg patterns[0].pc_sel.pc_domain = info.domain; 412087bf8e7cSmrg patterns[0].pc_sel.pc_bus = info.bus; 412187bf8e7cSmrg patterns[0].pc_sel.pc_dev = info.dev; 412287bf8e7cSmrg patterns[0].pc_sel.pc_func = info.func; 412387bf8e7cSmrg patterns[0].flags = PCI_GETCONF_MATCH_DOMAIN | PCI_GETCONF_MATCH_BUS 412487bf8e7cSmrg | PCI_GETCONF_MATCH_DEV | PCI_GETCONF_MATCH_FUNC; 412587bf8e7cSmrg bzero(&pc, sizeof(struct pci_conf_io)); 412687bf8e7cSmrg pc.num_patterns = 1; 412787bf8e7cSmrg pc.pat_buf_len = sizeof(patterns); 412887bf8e7cSmrg pc.patterns = patterns; 412987bf8e7cSmrg pc.match_buf_len = sizeof(results); 413087bf8e7cSmrg pc.matches = results; 413187bf8e7cSmrg 413287bf8e7cSmrg if (ioctl(fd, PCIOCGETCONF, &pc) || pc.status == PCI_GETCONF_ERROR) { 413387bf8e7cSmrg error = errno; 413487bf8e7cSmrg close(fd); 413587bf8e7cSmrg return -error; 413687bf8e7cSmrg } 413787bf8e7cSmrg close(fd); 413887bf8e7cSmrg 413987bf8e7cSmrg device->vendor_id = results[0].pc_vendor; 414087bf8e7cSmrg device->device_id = results[0].pc_device; 414187bf8e7cSmrg device->subvendor_id = results[0].pc_subvendor; 414287bf8e7cSmrg device->subdevice_id = results[0].pc_subdevice; 414387bf8e7cSmrg device->revision_id = results[0].pc_revid; 414487bf8e7cSmrg 4145fe517fc9Smrg return 0; 4146fe517fc9Smrg#else 4147fe517fc9Smrg#warning "Missing implementation of drmParsePciDeviceInfo" 4148fe517fc9Smrg return -EINVAL; 4149fe517fc9Smrg#endif 4150fe517fc9Smrg} 4151fe517fc9Smrg 41522ee35494Smrgstatic void drmFreePlatformDevice(drmDevicePtr device) 41532ee35494Smrg{ 41542ee35494Smrg if (device->deviceinfo.platform) { 41552ee35494Smrg if (device->deviceinfo.platform->compatible) { 41562ee35494Smrg char **compatible = device->deviceinfo.platform->compatible; 41572ee35494Smrg 41582ee35494Smrg while (*compatible) { 41592ee35494Smrg free(*compatible); 41602ee35494Smrg compatible++; 41612ee35494Smrg } 41622ee35494Smrg 41632ee35494Smrg free(device->deviceinfo.platform->compatible); 41642ee35494Smrg } 41652ee35494Smrg } 41662ee35494Smrg} 41672ee35494Smrg 41682ee35494Smrgstatic void drmFreeHost1xDevice(drmDevicePtr device) 41692ee35494Smrg{ 41702ee35494Smrg if (device->deviceinfo.host1x) { 41712ee35494Smrg if (device->deviceinfo.host1x->compatible) { 41722ee35494Smrg char **compatible = device->deviceinfo.host1x->compatible; 41732ee35494Smrg 41742ee35494Smrg while (*compatible) { 41752ee35494Smrg free(*compatible); 41762ee35494Smrg compatible++; 41772ee35494Smrg } 41782ee35494Smrg 41792ee35494Smrg free(device->deviceinfo.host1x->compatible); 41802ee35494Smrg } 41812ee35494Smrg } 41822ee35494Smrg} 41832ee35494Smrg 41846260e5d5Smrgdrm_public void drmFreeDevice(drmDevicePtr *device) 4185fe517fc9Smrg{ 4186fe517fc9Smrg if (device == NULL) 4187fe517fc9Smrg return; 4188fe517fc9Smrg 41892ee35494Smrg if (*device) { 41902ee35494Smrg switch ((*device)->bustype) { 41912ee35494Smrg case DRM_BUS_PLATFORM: 41922ee35494Smrg drmFreePlatformDevice(*device); 41932ee35494Smrg break; 41942ee35494Smrg 41952ee35494Smrg case DRM_BUS_HOST1X: 41962ee35494Smrg drmFreeHost1xDevice(*device); 41972ee35494Smrg break; 41982ee35494Smrg } 41992ee35494Smrg } 42002ee35494Smrg 4201fe517fc9Smrg free(*device); 4202fe517fc9Smrg *device = NULL; 4203fe517fc9Smrg} 4204fe517fc9Smrg 42056260e5d5Smrgdrm_public void drmFreeDevices(drmDevicePtr devices[], int count) 4206fe517fc9Smrg{ 4207fe517fc9Smrg int i; 4208fe517fc9Smrg 4209fe517fc9Smrg if (devices == NULL) 4210fe517fc9Smrg return; 4211fe517fc9Smrg 4212fe517fc9Smrg for (i = 0; i < count; i++) 4213fe517fc9Smrg if (devices[i]) 4214fe517fc9Smrg drmFreeDevice(&devices[i]); 4215fe517fc9Smrg} 4216fe517fc9Smrg 42172ee35494Smrgstatic drmDevicePtr drmDeviceAlloc(unsigned int type, const char *node, 42182ee35494Smrg size_t bus_size, size_t device_size, 42192ee35494Smrg char **ptrp) 4220fe517fc9Smrg{ 42212ee35494Smrg size_t max_node_length, extra, size; 42222ee35494Smrg drmDevicePtr device; 42232ee35494Smrg unsigned int i; 42242ee35494Smrg char *ptr; 4225fe517fc9Smrg 42262ee35494Smrg max_node_length = ALIGN(drmGetMaxNodeName(), sizeof(void *)); 42272ee35494Smrg extra = DRM_NODE_MAX * (sizeof(void *) + max_node_length); 4228fe517fc9Smrg 42292ee35494Smrg size = sizeof(*device) + extra + bus_size + device_size; 4230fe517fc9Smrg 42312ee35494Smrg device = calloc(1, size); 42322ee35494Smrg if (!device) 42332ee35494Smrg return NULL; 42342ee35494Smrg 42352ee35494Smrg device->available_nodes = 1 << type; 4236fe517fc9Smrg 42372ee35494Smrg ptr = (char *)device + sizeof(*device); 42382ee35494Smrg device->nodes = (char **)ptr; 42392ee35494Smrg 42402ee35494Smrg ptr += DRM_NODE_MAX * sizeof(void *); 4241fe517fc9Smrg 4242fe517fc9Smrg for (i = 0; i < DRM_NODE_MAX; i++) { 42432ee35494Smrg device->nodes[i] = ptr; 42442ee35494Smrg ptr += max_node_length; 4245fe517fc9Smrg } 4246fe517fc9Smrg 42472ee35494Smrg memcpy(device->nodes[type], node, max_node_length); 42482ee35494Smrg 42492ee35494Smrg *ptrp = ptr; 42502ee35494Smrg 42512ee35494Smrg return device; 42522ee35494Smrg} 42532ee35494Smrg 42542ee35494Smrgstatic int drmProcessPciDevice(drmDevicePtr *device, 42552ee35494Smrg const char *node, int node_type, 42562ee35494Smrg int maj, int min, bool fetch_deviceinfo, 42572ee35494Smrg uint32_t flags) 42582ee35494Smrg{ 42592ee35494Smrg drmDevicePtr dev; 42602ee35494Smrg char *addr; 42612ee35494Smrg int ret; 42622ee35494Smrg 42632ee35494Smrg dev = drmDeviceAlloc(node_type, node, sizeof(drmPciBusInfo), 42642ee35494Smrg sizeof(drmPciDeviceInfo), &addr); 42652ee35494Smrg if (!dev) 42662ee35494Smrg return -ENOMEM; 42672ee35494Smrg 42682ee35494Smrg dev->bustype = DRM_BUS_PCI; 4269fe517fc9Smrg 42702ee35494Smrg dev->businfo.pci = (drmPciBusInfoPtr)addr; 42712ee35494Smrg 42722ee35494Smrg ret = drmParsePciBusInfo(maj, min, dev->businfo.pci); 4273fe517fc9Smrg if (ret) 4274fe517fc9Smrg goto free_device; 4275fe517fc9Smrg 4276fe517fc9Smrg // Fetch the device info if the user has requested it 4277fe517fc9Smrg if (fetch_deviceinfo) { 4278fe517fc9Smrg addr += sizeof(drmPciBusInfo); 42792ee35494Smrg dev->deviceinfo.pci = (drmPciDeviceInfoPtr)addr; 4280fe517fc9Smrg 42812ee35494Smrg ret = drmParsePciDeviceInfo(maj, min, dev->deviceinfo.pci, flags); 4282fe517fc9Smrg if (ret) 4283fe517fc9Smrg goto free_device; 4284fe517fc9Smrg } 42852ee35494Smrg 42862ee35494Smrg *device = dev; 42872ee35494Smrg 4288fe517fc9Smrg return 0; 4289fe517fc9Smrg 4290fe517fc9Smrgfree_device: 42912ee35494Smrg free(dev); 42922ee35494Smrg return ret; 42932ee35494Smrg} 42942ee35494Smrg 429587bf8e7cSmrg#ifdef __linux__ 429687bf8e7cSmrgstatic int drm_usb_dev_path(int maj, int min, char *path, size_t len) 429787bf8e7cSmrg{ 429887bf8e7cSmrg char *value, *tmp_path, *slash; 4299adfa0b0cSmrg bool usb_device, usb_interface; 430087bf8e7cSmrg 430187bf8e7cSmrg snprintf(path, len, "/sys/dev/char/%d:%d/device", maj, min); 430287bf8e7cSmrg 430387bf8e7cSmrg value = sysfs_uevent_get(path, "DEVTYPE"); 430487bf8e7cSmrg if (!value) 430587bf8e7cSmrg return -ENOENT; 430687bf8e7cSmrg 4307adfa0b0cSmrg usb_device = strcmp(value, "usb_device") == 0; 4308adfa0b0cSmrg usb_interface = strcmp(value, "usb_interface") == 0; 4309adfa0b0cSmrg free(value); 4310adfa0b0cSmrg 4311adfa0b0cSmrg if (usb_device) 431287bf8e7cSmrg return 0; 4313adfa0b0cSmrg if (!usb_interface) 431487bf8e7cSmrg return -ENOTSUP; 431587bf8e7cSmrg 431687bf8e7cSmrg /* The parent of a usb_interface is a usb_device */ 431787bf8e7cSmrg 431887bf8e7cSmrg tmp_path = realpath(path, NULL); 431987bf8e7cSmrg if (!tmp_path) 432087bf8e7cSmrg return -errno; 432187bf8e7cSmrg 432287bf8e7cSmrg slash = strrchr(tmp_path, '/'); 432387bf8e7cSmrg if (!slash) { 432487bf8e7cSmrg free(tmp_path); 432587bf8e7cSmrg return -EINVAL; 432687bf8e7cSmrg } 432787bf8e7cSmrg 432887bf8e7cSmrg *slash = '\0'; 432987bf8e7cSmrg 433087bf8e7cSmrg if (snprintf(path, len, "%s", tmp_path) >= (int)len) { 433187bf8e7cSmrg free(tmp_path); 433287bf8e7cSmrg return -EINVAL; 433387bf8e7cSmrg } 433487bf8e7cSmrg 433587bf8e7cSmrg free(tmp_path); 433687bf8e7cSmrg return 0; 433787bf8e7cSmrg} 433887bf8e7cSmrg#endif 433987bf8e7cSmrg 43402ee35494Smrgstatic int drmParseUsbBusInfo(int maj, int min, drmUsbBusInfoPtr info) 43412ee35494Smrg{ 43422ee35494Smrg#ifdef __linux__ 43432ee35494Smrg char path[PATH_MAX + 1], *value; 43442ee35494Smrg unsigned int bus, dev; 43452ee35494Smrg int ret; 43462ee35494Smrg 434787bf8e7cSmrg ret = drm_usb_dev_path(maj, min, path, sizeof(path)); 434887bf8e7cSmrg if (ret < 0) 434987bf8e7cSmrg return ret; 43502ee35494Smrg 43512ee35494Smrg value = sysfs_uevent_get(path, "BUSNUM"); 43522ee35494Smrg if (!value) 43532ee35494Smrg return -ENOENT; 43542ee35494Smrg 43552ee35494Smrg ret = sscanf(value, "%03u", &bus); 43562ee35494Smrg free(value); 43572ee35494Smrg 43582ee35494Smrg if (ret <= 0) 43592ee35494Smrg return -errno; 43602ee35494Smrg 43612ee35494Smrg value = sysfs_uevent_get(path, "DEVNUM"); 43622ee35494Smrg if (!value) 43632ee35494Smrg return -ENOENT; 43642ee35494Smrg 43652ee35494Smrg ret = sscanf(value, "%03u", &dev); 43662ee35494Smrg free(value); 43672ee35494Smrg 43682ee35494Smrg if (ret <= 0) 43692ee35494Smrg return -errno; 43702ee35494Smrg 43712ee35494Smrg info->bus = bus; 43722ee35494Smrg info->dev = dev; 43732ee35494Smrg 43742ee35494Smrg return 0; 43752ee35494Smrg#else 43762ee35494Smrg#warning "Missing implementation of drmParseUsbBusInfo" 43772ee35494Smrg return -EINVAL; 43782ee35494Smrg#endif 43792ee35494Smrg} 43802ee35494Smrg 43812ee35494Smrgstatic int drmParseUsbDeviceInfo(int maj, int min, drmUsbDeviceInfoPtr info) 43822ee35494Smrg{ 43832ee35494Smrg#ifdef __linux__ 43842ee35494Smrg char path[PATH_MAX + 1], *value; 43852ee35494Smrg unsigned int vendor, product; 43862ee35494Smrg int ret; 43872ee35494Smrg 438887bf8e7cSmrg ret = drm_usb_dev_path(maj, min, path, sizeof(path)); 438987bf8e7cSmrg if (ret < 0) 439087bf8e7cSmrg return ret; 43912ee35494Smrg 43922ee35494Smrg value = sysfs_uevent_get(path, "PRODUCT"); 43932ee35494Smrg if (!value) 43942ee35494Smrg return -ENOENT; 43952ee35494Smrg 43962ee35494Smrg ret = sscanf(value, "%x/%x", &vendor, &product); 43972ee35494Smrg free(value); 43982ee35494Smrg 43992ee35494Smrg if (ret <= 0) 44002ee35494Smrg return -errno; 44012ee35494Smrg 44022ee35494Smrg info->vendor = vendor; 44032ee35494Smrg info->product = product; 44042ee35494Smrg 44052ee35494Smrg return 0; 44062ee35494Smrg#else 44072ee35494Smrg#warning "Missing implementation of drmParseUsbDeviceInfo" 44082ee35494Smrg return -EINVAL; 44092ee35494Smrg#endif 44102ee35494Smrg} 44112ee35494Smrg 44122ee35494Smrgstatic int drmProcessUsbDevice(drmDevicePtr *device, const char *node, 44132ee35494Smrg int node_type, int maj, int min, 44142ee35494Smrg bool fetch_deviceinfo, uint32_t flags) 44152ee35494Smrg{ 44162ee35494Smrg drmDevicePtr dev; 44172ee35494Smrg char *ptr; 44182ee35494Smrg int ret; 44192ee35494Smrg 44202ee35494Smrg dev = drmDeviceAlloc(node_type, node, sizeof(drmUsbBusInfo), 44212ee35494Smrg sizeof(drmUsbDeviceInfo), &ptr); 44222ee35494Smrg if (!dev) 44232ee35494Smrg return -ENOMEM; 44242ee35494Smrg 44252ee35494Smrg dev->bustype = DRM_BUS_USB; 44262ee35494Smrg 44272ee35494Smrg dev->businfo.usb = (drmUsbBusInfoPtr)ptr; 44282ee35494Smrg 44292ee35494Smrg ret = drmParseUsbBusInfo(maj, min, dev->businfo.usb); 44302ee35494Smrg if (ret < 0) 44312ee35494Smrg goto free_device; 44322ee35494Smrg 44332ee35494Smrg if (fetch_deviceinfo) { 44342ee35494Smrg ptr += sizeof(drmUsbBusInfo); 44352ee35494Smrg dev->deviceinfo.usb = (drmUsbDeviceInfoPtr)ptr; 44362ee35494Smrg 44372ee35494Smrg ret = drmParseUsbDeviceInfo(maj, min, dev->deviceinfo.usb); 44382ee35494Smrg if (ret < 0) 44392ee35494Smrg goto free_device; 44402ee35494Smrg } 44412ee35494Smrg 44422ee35494Smrg *device = dev; 44432ee35494Smrg 44442ee35494Smrg return 0; 44452ee35494Smrg 44462ee35494Smrgfree_device: 44472ee35494Smrg free(dev); 44482ee35494Smrg return ret; 44492ee35494Smrg} 44502ee35494Smrg 4451bf6cc7dcSmrgstatic int drmParseOFBusInfo(int maj, int min, char *fullname) 44522ee35494Smrg{ 44532ee35494Smrg#ifdef __linux__ 4454bf6cc7dcSmrg char path[PATH_MAX + 1], *name, *tmp_name; 44552ee35494Smrg 44562ee35494Smrg snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min); 44572ee35494Smrg 44582ee35494Smrg name = sysfs_uevent_get(path, "OF_FULLNAME"); 4459bf6cc7dcSmrg tmp_name = name; 4460bf6cc7dcSmrg if (!name) { 4461bf6cc7dcSmrg /* If the device lacks OF data, pick the MODALIAS info */ 4462bf6cc7dcSmrg name = sysfs_uevent_get(path, "MODALIAS"); 4463bf6cc7dcSmrg if (!name) 4464bf6cc7dcSmrg return -ENOENT; 4465bf6cc7dcSmrg 4466bf6cc7dcSmrg /* .. and strip the MODALIAS=[platform,usb...]: part. */ 4467bf6cc7dcSmrg tmp_name = strrchr(name, ':'); 4468bf6cc7dcSmrg if (!tmp_name) { 4469bf6cc7dcSmrg free(name); 4470bf6cc7dcSmrg return -ENOENT; 4471bf6cc7dcSmrg } 4472bf6cc7dcSmrg tmp_name++; 4473bf6cc7dcSmrg } 44742ee35494Smrg 4475bf6cc7dcSmrg strncpy(fullname, tmp_name, DRM_PLATFORM_DEVICE_NAME_LEN); 4476bf6cc7dcSmrg fullname[DRM_PLATFORM_DEVICE_NAME_LEN - 1] = '\0'; 44772ee35494Smrg free(name); 44782ee35494Smrg 44792ee35494Smrg return 0; 44802ee35494Smrg#else 4481bf6cc7dcSmrg#warning "Missing implementation of drmParseOFBusInfo" 44822ee35494Smrg return -EINVAL; 44832ee35494Smrg#endif 44842ee35494Smrg} 44852ee35494Smrg 4486bf6cc7dcSmrgstatic int drmParseOFDeviceInfo(int maj, int min, char ***compatible) 44872ee35494Smrg{ 44882ee35494Smrg#ifdef __linux__ 4489bf6cc7dcSmrg char path[PATH_MAX + 1], *value, *tmp_name; 44902ee35494Smrg unsigned int count, i; 44912ee35494Smrg int err; 44922ee35494Smrg 44932ee35494Smrg snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min); 44942ee35494Smrg 44952ee35494Smrg value = sysfs_uevent_get(path, "OF_COMPATIBLE_N"); 4496bf6cc7dcSmrg if (value) { 4497bf6cc7dcSmrg sscanf(value, "%u", &count); 4498bf6cc7dcSmrg free(value); 4499bf6cc7dcSmrg } else { 4500bf6cc7dcSmrg /* Assume one entry if the device lack OF data */ 4501bf6cc7dcSmrg count = 1; 4502bf6cc7dcSmrg } 45032ee35494Smrg 4504bf6cc7dcSmrg *compatible = calloc(count + 1, sizeof(char *)); 4505bf6cc7dcSmrg if (!*compatible) 45062ee35494Smrg return -ENOMEM; 45072ee35494Smrg 45082ee35494Smrg for (i = 0; i < count; i++) { 45092ee35494Smrg value = sysfs_uevent_get(path, "OF_COMPATIBLE_%u", i); 4510bf6cc7dcSmrg tmp_name = value; 45112ee35494Smrg if (!value) { 4512bf6cc7dcSmrg /* If the device lacks OF data, pick the MODALIAS info */ 4513bf6cc7dcSmrg value = sysfs_uevent_get(path, "MODALIAS"); 4514bf6cc7dcSmrg if (!value) { 4515bf6cc7dcSmrg err = -ENOENT; 4516bf6cc7dcSmrg goto free; 4517bf6cc7dcSmrg } 4518bf6cc7dcSmrg 4519bf6cc7dcSmrg /* .. and strip the MODALIAS=[platform,usb...]: part. */ 4520bf6cc7dcSmrg tmp_name = strrchr(value, ':'); 4521bf6cc7dcSmrg if (!tmp_name) { 4522bf6cc7dcSmrg free(value); 4523bf6cc7dcSmrg return -ENOENT; 4524bf6cc7dcSmrg } 4525bf6cc7dcSmrg tmp_name = strdup(tmp_name + 1); 4526bf6cc7dcSmrg free(value); 45272ee35494Smrg } 45282ee35494Smrg 4529bf6cc7dcSmrg (*compatible)[i] = tmp_name; 45302ee35494Smrg } 45312ee35494Smrg 45322ee35494Smrg return 0; 45332ee35494Smrg 45342ee35494Smrgfree: 45352ee35494Smrg while (i--) 4536bf6cc7dcSmrg free((*compatible)[i]); 45372ee35494Smrg 4538bf6cc7dcSmrg free(*compatible); 45392ee35494Smrg return err; 45402ee35494Smrg#else 4541bf6cc7dcSmrg#warning "Missing implementation of drmParseOFDeviceInfo" 45422ee35494Smrg return -EINVAL; 45432ee35494Smrg#endif 45442ee35494Smrg} 45452ee35494Smrg 45462ee35494Smrgstatic int drmProcessPlatformDevice(drmDevicePtr *device, 45472ee35494Smrg const char *node, int node_type, 45482ee35494Smrg int maj, int min, bool fetch_deviceinfo, 45492ee35494Smrg uint32_t flags) 45502ee35494Smrg{ 45512ee35494Smrg drmDevicePtr dev; 45522ee35494Smrg char *ptr; 45532ee35494Smrg int ret; 45542ee35494Smrg 45552ee35494Smrg dev = drmDeviceAlloc(node_type, node, sizeof(drmPlatformBusInfo), 45562ee35494Smrg sizeof(drmPlatformDeviceInfo), &ptr); 45572ee35494Smrg if (!dev) 45582ee35494Smrg return -ENOMEM; 45592ee35494Smrg 45602ee35494Smrg dev->bustype = DRM_BUS_PLATFORM; 45612ee35494Smrg 45622ee35494Smrg dev->businfo.platform = (drmPlatformBusInfoPtr)ptr; 45632ee35494Smrg 4564bf6cc7dcSmrg ret = drmParseOFBusInfo(maj, min, dev->businfo.platform->fullname); 45652ee35494Smrg if (ret < 0) 45662ee35494Smrg goto free_device; 45672ee35494Smrg 45682ee35494Smrg if (fetch_deviceinfo) { 45692ee35494Smrg ptr += sizeof(drmPlatformBusInfo); 45702ee35494Smrg dev->deviceinfo.platform = (drmPlatformDeviceInfoPtr)ptr; 45712ee35494Smrg 4572bf6cc7dcSmrg ret = drmParseOFDeviceInfo(maj, min, &dev->deviceinfo.platform->compatible); 45732ee35494Smrg if (ret < 0) 45742ee35494Smrg goto free_device; 45752ee35494Smrg } 45762ee35494Smrg 45772ee35494Smrg *device = dev; 45782ee35494Smrg 45792ee35494Smrg return 0; 45802ee35494Smrg 45812ee35494Smrgfree_device: 45822ee35494Smrg free(dev); 45832ee35494Smrg return ret; 45842ee35494Smrg} 45852ee35494Smrg 45862ee35494Smrgstatic int drmProcessHost1xDevice(drmDevicePtr *device, 45872ee35494Smrg const char *node, int node_type, 45882ee35494Smrg int maj, int min, bool fetch_deviceinfo, 45892ee35494Smrg uint32_t flags) 45902ee35494Smrg{ 45912ee35494Smrg drmDevicePtr dev; 45922ee35494Smrg char *ptr; 45932ee35494Smrg int ret; 45942ee35494Smrg 45952ee35494Smrg dev = drmDeviceAlloc(node_type, node, sizeof(drmHost1xBusInfo), 45962ee35494Smrg sizeof(drmHost1xDeviceInfo), &ptr); 45972ee35494Smrg if (!dev) 45982ee35494Smrg return -ENOMEM; 45992ee35494Smrg 46002ee35494Smrg dev->bustype = DRM_BUS_HOST1X; 46012ee35494Smrg 46022ee35494Smrg dev->businfo.host1x = (drmHost1xBusInfoPtr)ptr; 46032ee35494Smrg 4604bf6cc7dcSmrg ret = drmParseOFBusInfo(maj, min, dev->businfo.host1x->fullname); 46052ee35494Smrg if (ret < 0) 46062ee35494Smrg goto free_device; 46072ee35494Smrg 46082ee35494Smrg if (fetch_deviceinfo) { 46092ee35494Smrg ptr += sizeof(drmHost1xBusInfo); 46102ee35494Smrg dev->deviceinfo.host1x = (drmHost1xDeviceInfoPtr)ptr; 46112ee35494Smrg 4612bf6cc7dcSmrg ret = drmParseOFDeviceInfo(maj, min, &dev->deviceinfo.host1x->compatible); 46132ee35494Smrg if (ret < 0) 46142ee35494Smrg goto free_device; 46152ee35494Smrg } 46162ee35494Smrg 46172ee35494Smrg *device = dev; 46182ee35494Smrg 46192ee35494Smrg return 0; 46202ee35494Smrg 46212ee35494Smrgfree_device: 46222ee35494Smrg free(dev); 4623fe517fc9Smrg return ret; 4624fe517fc9Smrg} 4625fe517fc9Smrg 46266260e5d5Smrgstatic int 46276260e5d5Smrgprocess_device(drmDevicePtr *device, const char *d_name, 46286260e5d5Smrg int req_subsystem_type, 46296260e5d5Smrg bool fetch_deviceinfo, uint32_t flags) 46306260e5d5Smrg{ 46316260e5d5Smrg struct stat sbuf; 46326260e5d5Smrg char node[PATH_MAX + 1]; 463348246ce7Smrg int node_type, subsystem_type, written; 46346260e5d5Smrg unsigned int maj, min; 463548246ce7Smrg const int max_node_length = ALIGN(drmGetMaxNodeName(), sizeof(void *)); 46366260e5d5Smrg 46376260e5d5Smrg node_type = drmGetNodeType(d_name); 46386260e5d5Smrg if (node_type < 0) 46396260e5d5Smrg return -1; 46406260e5d5Smrg 464148246ce7Smrg written = snprintf(node, PATH_MAX, "%s/%s", DRM_DIR_NAME, d_name); 464248246ce7Smrg if (written < 0) 464348246ce7Smrg return -1; 464448246ce7Smrg 464548246ce7Smrg /* anything longer than this will be truncated in drmDeviceAlloc. 464648246ce7Smrg * Account for NULL byte 464748246ce7Smrg */ 464848246ce7Smrg if (written + 1 > max_node_length) 464948246ce7Smrg return -1; 465048246ce7Smrg 46516260e5d5Smrg if (stat(node, &sbuf)) 46526260e5d5Smrg return -1; 46536260e5d5Smrg 46546260e5d5Smrg maj = major(sbuf.st_rdev); 46556260e5d5Smrg min = minor(sbuf.st_rdev); 46566260e5d5Smrg 46576260e5d5Smrg if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode)) 46586260e5d5Smrg return -1; 46596260e5d5Smrg 46606260e5d5Smrg subsystem_type = drmParseSubsystemType(maj, min); 46616260e5d5Smrg if (req_subsystem_type != -1 && req_subsystem_type != subsystem_type) 46626260e5d5Smrg return -1; 46636260e5d5Smrg 46646260e5d5Smrg switch (subsystem_type) { 46656260e5d5Smrg case DRM_BUS_PCI: 46666260e5d5Smrg case DRM_BUS_VIRTIO: 46676260e5d5Smrg return drmProcessPciDevice(device, node, node_type, maj, min, 46686260e5d5Smrg fetch_deviceinfo, flags); 46696260e5d5Smrg case DRM_BUS_USB: 46706260e5d5Smrg return drmProcessUsbDevice(device, node, node_type, maj, min, 46716260e5d5Smrg fetch_deviceinfo, flags); 46726260e5d5Smrg case DRM_BUS_PLATFORM: 46736260e5d5Smrg return drmProcessPlatformDevice(device, node, node_type, maj, min, 46746260e5d5Smrg fetch_deviceinfo, flags); 46756260e5d5Smrg case DRM_BUS_HOST1X: 46766260e5d5Smrg return drmProcessHost1xDevice(device, node, node_type, maj, min, 46776260e5d5Smrg fetch_deviceinfo, flags); 46786260e5d5Smrg default: 46796260e5d5Smrg return -1; 46806260e5d5Smrg } 46816260e5d5Smrg} 46826260e5d5Smrg 4683fe517fc9Smrg/* Consider devices located on the same bus as duplicate and fold the respective 4684fe517fc9Smrg * entries into a single one. 4685fe517fc9Smrg * 4686fe517fc9Smrg * Note: this leaves "gaps" in the array, while preserving the length. 4687fe517fc9Smrg */ 4688fe517fc9Smrgstatic void drmFoldDuplicatedDevices(drmDevicePtr local_devices[], int count) 4689fe517fc9Smrg{ 4690fe517fc9Smrg int node_type, i, j; 4691fe517fc9Smrg 4692fe517fc9Smrg for (i = 0; i < count; i++) { 4693fe517fc9Smrg for (j = i + 1; j < count; j++) { 46940655efefSmrg if (drmDevicesEqual(local_devices[i], local_devices[j])) { 4695fe517fc9Smrg local_devices[i]->available_nodes |= local_devices[j]->available_nodes; 46964b3d3f37Smrg node_type = log2_int(local_devices[j]->available_nodes); 4697fe517fc9Smrg memcpy(local_devices[i]->nodes[node_type], 4698fe517fc9Smrg local_devices[j]->nodes[node_type], drmGetMaxNodeName()); 4699fe517fc9Smrg drmFreeDevice(&local_devices[j]); 4700fe517fc9Smrg } 4701fe517fc9Smrg } 4702fe517fc9Smrg } 4703fe517fc9Smrg} 4704fe517fc9Smrg 47052ee35494Smrg/* Check that the given flags are valid returning 0 on success */ 47062ee35494Smrgstatic int 47072ee35494Smrgdrm_device_validate_flags(uint32_t flags) 47082ee35494Smrg{ 47092ee35494Smrg return (flags & ~DRM_DEVICE_GET_PCI_REVISION); 47102ee35494Smrg} 47112ee35494Smrg 47126260e5d5Smrgstatic bool 47136260e5d5Smrgdrm_device_has_rdev(drmDevicePtr device, dev_t find_rdev) 47146260e5d5Smrg{ 47156260e5d5Smrg struct stat sbuf; 47166260e5d5Smrg 47176260e5d5Smrg for (int i = 0; i < DRM_NODE_MAX; i++) { 47186260e5d5Smrg if (device->available_nodes & 1 << i) { 47196260e5d5Smrg if (stat(device->nodes[i], &sbuf) == 0 && 47206260e5d5Smrg sbuf.st_rdev == find_rdev) 47216260e5d5Smrg return true; 47226260e5d5Smrg } 47236260e5d5Smrg } 47246260e5d5Smrg return false; 47256260e5d5Smrg} 47266260e5d5Smrg 47276260e5d5Smrg/* 47286260e5d5Smrg * The kernel drm core has a number of places that assume maximum of 47296260e5d5Smrg * 3x64 devices nodes. That's 64 for each of primary, control and 47306260e5d5Smrg * render nodes. Rounded it up to 256 for simplicity. 47316260e5d5Smrg */ 47326260e5d5Smrg#define MAX_DRM_NODES 256 47336260e5d5Smrg 4734fe517fc9Smrg/** 4735adfa0b0cSmrg * Get information about a device from its dev_t identifier 4736fe517fc9Smrg * 4737adfa0b0cSmrg * \param find_rdev dev_t identifier of the device 47382ee35494Smrg * \param flags feature/behaviour bitmask 4739fe517fc9Smrg * \param device the address of a drmDevicePtr where the information 4740fe517fc9Smrg * will be allocated in stored 4741fe517fc9Smrg * 4742fe517fc9Smrg * \return zero on success, negative error code otherwise. 4743fe517fc9Smrg */ 4744adfa0b0cSmrgdrm_public int drmGetDeviceFromDevId(dev_t find_rdev, uint32_t flags, drmDevicePtr *device) 4745fe517fc9Smrg{ 47462ee35494Smrg#ifdef __OpenBSD__ 47472ee35494Smrg /* 47482ee35494Smrg * DRI device nodes on OpenBSD are not in their own directory, they reside 47492ee35494Smrg * in /dev along with a large number of statically generated /dev nodes. 47502ee35494Smrg * Avoid stat'ing all of /dev needlessly by implementing this custom path. 47512ee35494Smrg */ 47522ee35494Smrg drmDevicePtr d; 47532ee35494Smrg char node[PATH_MAX + 1]; 47542ee35494Smrg const char *dev_name; 47552ee35494Smrg int node_type, subsystem_type; 475682025ec7Smrg int maj, min, n, ret; 475748246ce7Smrg const int max_node_length = ALIGN(drmGetMaxNodeName(), sizeof(void *)); 475848246ce7Smrg struct stat sbuf; 47592ee35494Smrg 4760adfa0b0cSmrg if (device == NULL) 47612ee35494Smrg return -EINVAL; 47622ee35494Smrg 4763adfa0b0cSmrg maj = major(find_rdev); 4764adfa0b0cSmrg min = minor(find_rdev); 47652ee35494Smrg 4766adfa0b0cSmrg if (!drmNodeIsDRM(maj, min)) 47672ee35494Smrg return -EINVAL; 47682ee35494Smrg 476987bf8e7cSmrg node_type = drmGetMinorType(maj, min); 47702ee35494Smrg if (node_type == -1) 47712ee35494Smrg return -ENODEV; 47722ee35494Smrg 477382025ec7Smrg dev_name = drmGetDeviceName(node_type); 477482025ec7Smrg if (!dev_name) 47752ee35494Smrg return -EINVAL; 47762ee35494Smrg 477748246ce7Smrg /* anything longer than this will be truncated in drmDeviceAlloc. 477848246ce7Smrg * Account for NULL byte 477948246ce7Smrg */ 478082025ec7Smrg n = snprintf(node, PATH_MAX, dev_name, DRM_DIR_NAME, min); 47812ee35494Smrg if (n == -1 || n >= PATH_MAX) 47822ee35494Smrg return -errno; 478348246ce7Smrg if (n + 1 > max_node_length) 478448246ce7Smrg return -EINVAL; 47852ee35494Smrg if (stat(node, &sbuf)) 47862ee35494Smrg return -EINVAL; 47872ee35494Smrg 47882ee35494Smrg subsystem_type = drmParseSubsystemType(maj, min); 47892ee35494Smrg if (subsystem_type != DRM_BUS_PCI) 47902ee35494Smrg return -ENODEV; 47912ee35494Smrg 47922ee35494Smrg ret = drmProcessPciDevice(&d, node, node_type, maj, min, true, flags); 47932ee35494Smrg if (ret) 47942ee35494Smrg return ret; 47952ee35494Smrg 47962ee35494Smrg *device = d; 47972ee35494Smrg 47982ee35494Smrg return 0; 47992ee35494Smrg#else 48006260e5d5Smrg drmDevicePtr local_devices[MAX_DRM_NODES]; 4801fe517fc9Smrg drmDevicePtr d; 4802fe517fc9Smrg DIR *sysdir; 4803fe517fc9Smrg struct dirent *dent; 48046260e5d5Smrg int subsystem_type; 4805fe517fc9Smrg int maj, min; 4806fe517fc9Smrg int ret, i, node_count; 4807fe517fc9Smrg 48082ee35494Smrg if (drm_device_validate_flags(flags)) 48092ee35494Smrg return -EINVAL; 48102ee35494Smrg 4811adfa0b0cSmrg if (device == NULL) 4812fe517fc9Smrg return -EINVAL; 4813fe517fc9Smrg 4814adfa0b0cSmrg maj = major(find_rdev); 4815adfa0b0cSmrg min = minor(find_rdev); 4816fe517fc9Smrg 4817adfa0b0cSmrg if (!drmNodeIsDRM(maj, min)) 4818fe517fc9Smrg return -EINVAL; 4819fe517fc9Smrg 4820fe517fc9Smrg subsystem_type = drmParseSubsystemType(maj, min); 48216260e5d5Smrg if (subsystem_type < 0) 48226260e5d5Smrg return subsystem_type; 4823fe517fc9Smrg 4824fe517fc9Smrg sysdir = opendir(DRM_DIR_NAME); 48256260e5d5Smrg if (!sysdir) 48266260e5d5Smrg return -errno; 4827fe517fc9Smrg 4828fe517fc9Smrg i = 0; 4829fe517fc9Smrg while ((dent = readdir(sysdir))) { 48306260e5d5Smrg ret = process_device(&d, dent->d_name, subsystem_type, true, flags); 48316260e5d5Smrg if (ret) 4832fe517fc9Smrg continue; 4833fe517fc9Smrg 48346260e5d5Smrg if (i >= MAX_DRM_NODES) { 48356260e5d5Smrg fprintf(stderr, "More than %d drm nodes detected. " 48366260e5d5Smrg "Please report a bug - that should not happen.\n" 48376260e5d5Smrg "Skipping extra nodes\n", MAX_DRM_NODES); 4838fe517fc9Smrg break; 4839fe517fc9Smrg } 48406260e5d5Smrg local_devices[i] = d; 4841fe517fc9Smrg i++; 4842fe517fc9Smrg } 4843fe517fc9Smrg node_count = i; 4844fe517fc9Smrg 4845fe517fc9Smrg drmFoldDuplicatedDevices(local_devices, node_count); 4846fe517fc9Smrg 48476260e5d5Smrg *device = NULL; 48486260e5d5Smrg 48496260e5d5Smrg for (i = 0; i < node_count; i++) { 48506260e5d5Smrg if (!local_devices[i]) 48516260e5d5Smrg continue; 48526260e5d5Smrg 48536260e5d5Smrg if (drm_device_has_rdev(local_devices[i], find_rdev)) 48546260e5d5Smrg *device = local_devices[i]; 48556260e5d5Smrg else 48566260e5d5Smrg drmFreeDevice(&local_devices[i]); 48576260e5d5Smrg } 4858fe517fc9Smrg 4859fe517fc9Smrg closedir(sysdir); 48602ee35494Smrg if (*device == NULL) 48612ee35494Smrg return -ENODEV; 4862fe517fc9Smrg return 0; 48632ee35494Smrg#endif 48642ee35494Smrg} 48652ee35494Smrg 486648246ce7Smrgdrm_public int drmGetNodeTypeFromDevId(dev_t devid) 486748246ce7Smrg{ 486848246ce7Smrg int maj, min, node_type; 486948246ce7Smrg 487048246ce7Smrg maj = major(devid); 487148246ce7Smrg min = minor(devid); 487248246ce7Smrg 487348246ce7Smrg if (!drmNodeIsDRM(maj, min)) 487448246ce7Smrg return -EINVAL; 487548246ce7Smrg 487648246ce7Smrg node_type = drmGetMinorType(maj, min); 487748246ce7Smrg if (node_type == -1) 487848246ce7Smrg return -ENODEV; 487948246ce7Smrg 488048246ce7Smrg return node_type; 488148246ce7Smrg} 488248246ce7Smrg 4883adfa0b0cSmrg/** 4884adfa0b0cSmrg * Get information about the opened drm device 4885adfa0b0cSmrg * 4886adfa0b0cSmrg * \param fd file descriptor of the drm device 4887adfa0b0cSmrg * \param flags feature/behaviour bitmask 4888adfa0b0cSmrg * \param device the address of a drmDevicePtr where the information 4889adfa0b0cSmrg * will be allocated in stored 4890adfa0b0cSmrg * 4891adfa0b0cSmrg * \return zero on success, negative error code otherwise. 4892adfa0b0cSmrg * 4893adfa0b0cSmrg * \note Unlike drmGetDevice it does not retrieve the pci device revision field 4894adfa0b0cSmrg * unless the DRM_DEVICE_GET_PCI_REVISION \p flag is set. 4895adfa0b0cSmrg */ 4896adfa0b0cSmrgdrm_public int drmGetDevice2(int fd, uint32_t flags, drmDevicePtr *device) 4897adfa0b0cSmrg{ 4898adfa0b0cSmrg struct stat sbuf; 4899adfa0b0cSmrg 4900adfa0b0cSmrg if (fd == -1) 4901adfa0b0cSmrg return -EINVAL; 4902adfa0b0cSmrg 4903adfa0b0cSmrg if (fstat(fd, &sbuf)) 4904adfa0b0cSmrg return -errno; 4905adfa0b0cSmrg 4906adfa0b0cSmrg if (!S_ISCHR(sbuf.st_mode)) 4907adfa0b0cSmrg return -EINVAL; 4908adfa0b0cSmrg 4909adfa0b0cSmrg return drmGetDeviceFromDevId(sbuf.st_rdev, flags, device); 4910adfa0b0cSmrg} 4911adfa0b0cSmrg 49122ee35494Smrg/** 49132ee35494Smrg * Get information about the opened drm device 49142ee35494Smrg * 49152ee35494Smrg * \param fd file descriptor of the drm device 49162ee35494Smrg * \param device the address of a drmDevicePtr where the information 49172ee35494Smrg * will be allocated in stored 49182ee35494Smrg * 49192ee35494Smrg * \return zero on success, negative error code otherwise. 49202ee35494Smrg */ 49216260e5d5Smrgdrm_public int drmGetDevice(int fd, drmDevicePtr *device) 49222ee35494Smrg{ 49232ee35494Smrg return drmGetDevice2(fd, DRM_DEVICE_GET_PCI_REVISION, device); 4924fe517fc9Smrg} 4925fe517fc9Smrg 4926fe517fc9Smrg/** 4927fe517fc9Smrg * Get drm devices on the system 4928fe517fc9Smrg * 49292ee35494Smrg * \param flags feature/behaviour bitmask 4930fe517fc9Smrg * \param devices the array of devices with drmDevicePtr elements 4931fe517fc9Smrg * can be NULL to get the device number first 4932fe517fc9Smrg * \param max_devices the maximum number of devices for the array 4933fe517fc9Smrg * 4934fe517fc9Smrg * \return on error - negative error code, 4935fe517fc9Smrg * if devices is NULL - total number of devices available on the system, 4936fe517fc9Smrg * alternatively the number of devices stored in devices[], which is 4937fe517fc9Smrg * capped by the max_devices. 49382ee35494Smrg * 49392ee35494Smrg * \note Unlike drmGetDevices it does not retrieve the pci device revision field 49402ee35494Smrg * unless the DRM_DEVICE_GET_PCI_REVISION \p flag is set. 4941fe517fc9Smrg */ 49426260e5d5Smrgdrm_public int drmGetDevices2(uint32_t flags, drmDevicePtr devices[], 49436260e5d5Smrg int max_devices) 4944fe517fc9Smrg{ 49456260e5d5Smrg drmDevicePtr local_devices[MAX_DRM_NODES]; 4946fe517fc9Smrg drmDevicePtr device; 4947fe517fc9Smrg DIR *sysdir; 4948fe517fc9Smrg struct dirent *dent; 4949fe517fc9Smrg int ret, i, node_count, device_count; 4950fe517fc9Smrg 49512ee35494Smrg if (drm_device_validate_flags(flags)) 49522ee35494Smrg return -EINVAL; 49532ee35494Smrg 4954fe517fc9Smrg sysdir = opendir(DRM_DIR_NAME); 49556260e5d5Smrg if (!sysdir) 49566260e5d5Smrg return -errno; 4957fe517fc9Smrg 4958fe517fc9Smrg i = 0; 4959fe517fc9Smrg while ((dent = readdir(sysdir))) { 49606260e5d5Smrg ret = process_device(&device, dent->d_name, -1, devices != NULL, flags); 49616260e5d5Smrg if (ret) 4962fe517fc9Smrg continue; 4963fe517fc9Smrg 49646260e5d5Smrg if (i >= MAX_DRM_NODES) { 49656260e5d5Smrg fprintf(stderr, "More than %d drm nodes detected. " 49666260e5d5Smrg "Please report a bug - that should not happen.\n" 49676260e5d5Smrg "Skipping extra nodes\n", MAX_DRM_NODES); 49682ee35494Smrg break; 4969fe517fc9Smrg } 4970fe517fc9Smrg local_devices[i] = device; 4971fe517fc9Smrg i++; 4972fe517fc9Smrg } 4973fe517fc9Smrg node_count = i; 4974fe517fc9Smrg 4975fe517fc9Smrg drmFoldDuplicatedDevices(local_devices, node_count); 4976fe517fc9Smrg 4977fe517fc9Smrg device_count = 0; 4978fe517fc9Smrg for (i = 0; i < node_count; i++) { 4979fe517fc9Smrg if (!local_devices[i]) 4980fe517fc9Smrg continue; 4981fe517fc9Smrg 4982fe517fc9Smrg if ((devices != NULL) && (device_count < max_devices)) 4983fe517fc9Smrg devices[device_count] = local_devices[i]; 4984fe517fc9Smrg else 4985fe517fc9Smrg drmFreeDevice(&local_devices[i]); 4986fe517fc9Smrg 4987fe517fc9Smrg device_count++; 4988fe517fc9Smrg } 4989fe517fc9Smrg 4990fe517fc9Smrg closedir(sysdir); 49914b3d3f37Smrg 49924b3d3f37Smrg if (devices != NULL) 49934b3d3f37Smrg return MIN2(device_count, max_devices); 49944b3d3f37Smrg 4995fe517fc9Smrg return device_count; 4996424e9256Smrg} 49972ee35494Smrg 49982ee35494Smrg/** 49992ee35494Smrg * Get drm devices on the system 50002ee35494Smrg * 50012ee35494Smrg * \param devices the array of devices with drmDevicePtr elements 50022ee35494Smrg * can be NULL to get the device number first 50032ee35494Smrg * \param max_devices the maximum number of devices for the array 50042ee35494Smrg * 50052ee35494Smrg * \return on error - negative error code, 50062ee35494Smrg * if devices is NULL - total number of devices available on the system, 50072ee35494Smrg * alternatively the number of devices stored in devices[], which is 50082ee35494Smrg * capped by the max_devices. 50092ee35494Smrg */ 50106260e5d5Smrgdrm_public int drmGetDevices(drmDevicePtr devices[], int max_devices) 50112ee35494Smrg{ 50122ee35494Smrg return drmGetDevices2(DRM_DEVICE_GET_PCI_REVISION, devices, max_devices); 50132ee35494Smrg} 50142ee35494Smrg 50156260e5d5Smrgdrm_public char *drmGetDeviceNameFromFd2(int fd) 50162ee35494Smrg{ 50172ee35494Smrg#ifdef __linux__ 50182ee35494Smrg struct stat sbuf; 50192ee35494Smrg char path[PATH_MAX + 1], *value; 50202ee35494Smrg unsigned int maj, min; 50212ee35494Smrg 50222ee35494Smrg if (fstat(fd, &sbuf)) 50232ee35494Smrg return NULL; 50242ee35494Smrg 50252ee35494Smrg maj = major(sbuf.st_rdev); 50262ee35494Smrg min = minor(sbuf.st_rdev); 50272ee35494Smrg 50286260e5d5Smrg if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode)) 50292ee35494Smrg return NULL; 50302ee35494Smrg 50312ee35494Smrg snprintf(path, sizeof(path), "/sys/dev/char/%d:%d", maj, min); 50322ee35494Smrg 50332ee35494Smrg value = sysfs_uevent_get(path, "DEVNAME"); 50342ee35494Smrg if (!value) 50352ee35494Smrg return NULL; 50362ee35494Smrg 50372ee35494Smrg snprintf(path, sizeof(path), "/dev/%s", value); 50382ee35494Smrg free(value); 50392ee35494Smrg 50402ee35494Smrg return strdup(path); 50414b3d3f37Smrg#elif defined(__FreeBSD__) 504287bf8e7cSmrg return drmGetDeviceNameFromFd(fd); 50432ee35494Smrg#else 50442ee35494Smrg struct stat sbuf; 50452ee35494Smrg char node[PATH_MAX + 1]; 50462ee35494Smrg const char *dev_name; 50472ee35494Smrg int node_type; 504882025ec7Smrg int maj, min, n; 50492ee35494Smrg 50502ee35494Smrg if (fstat(fd, &sbuf)) 50512ee35494Smrg return NULL; 50522ee35494Smrg 50532ee35494Smrg maj = major(sbuf.st_rdev); 50542ee35494Smrg min = minor(sbuf.st_rdev); 50552ee35494Smrg 50566260e5d5Smrg if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode)) 50572ee35494Smrg return NULL; 50582ee35494Smrg 505987bf8e7cSmrg node_type = drmGetMinorType(maj, min); 50602ee35494Smrg if (node_type == -1) 50612ee35494Smrg return NULL; 50622ee35494Smrg 506382025ec7Smrg dev_name = drmGetDeviceName(node_type); 506482025ec7Smrg if (!dev_name) 50652ee35494Smrg return NULL; 50662ee35494Smrg 506782025ec7Smrg n = snprintf(node, PATH_MAX, dev_name, DRM_DIR_NAME, min); 50682ee35494Smrg if (n == -1 || n >= PATH_MAX) 50692ee35494Smrg return NULL; 50702ee35494Smrg 50712ee35494Smrg return strdup(node); 50722ee35494Smrg#endif 50732ee35494Smrg} 50740655efefSmrg 50756260e5d5Smrgdrm_public int drmSyncobjCreate(int fd, uint32_t flags, uint32_t *handle) 50760655efefSmrg{ 50770655efefSmrg struct drm_syncobj_create args; 50780655efefSmrg int ret; 50790655efefSmrg 50800655efefSmrg memclear(args); 50810655efefSmrg args.flags = flags; 50820655efefSmrg args.handle = 0; 50830655efefSmrg ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_CREATE, &args); 50840655efefSmrg if (ret) 50852b90624aSmrg return ret; 50860655efefSmrg *handle = args.handle; 50870655efefSmrg return 0; 50880655efefSmrg} 50890655efefSmrg 50906260e5d5Smrgdrm_public int drmSyncobjDestroy(int fd, uint32_t handle) 50910655efefSmrg{ 50920655efefSmrg struct drm_syncobj_destroy args; 50930655efefSmrg 50940655efefSmrg memclear(args); 50950655efefSmrg args.handle = handle; 50960655efefSmrg return drmIoctl(fd, DRM_IOCTL_SYNCOBJ_DESTROY, &args); 50970655efefSmrg} 50980655efefSmrg 50996260e5d5Smrgdrm_public int drmSyncobjHandleToFD(int fd, uint32_t handle, int *obj_fd) 51000655efefSmrg{ 51010655efefSmrg struct drm_syncobj_handle args; 51020655efefSmrg int ret; 51030655efefSmrg 51040655efefSmrg memclear(args); 51050655efefSmrg args.fd = -1; 51060655efefSmrg args.handle = handle; 51070655efefSmrg ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD, &args); 51080655efefSmrg if (ret) 51092b90624aSmrg return ret; 51100655efefSmrg *obj_fd = args.fd; 51110655efefSmrg return 0; 51120655efefSmrg} 51130655efefSmrg 51146260e5d5Smrgdrm_public int drmSyncobjFDToHandle(int fd, int obj_fd, uint32_t *handle) 51150655efefSmrg{ 51160655efefSmrg struct drm_syncobj_handle args; 51170655efefSmrg int ret; 51180655efefSmrg 51190655efefSmrg memclear(args); 51200655efefSmrg args.fd = obj_fd; 51210655efefSmrg args.handle = 0; 51220655efefSmrg ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE, &args); 51230655efefSmrg if (ret) 51242b90624aSmrg return ret; 51250655efefSmrg *handle = args.handle; 51260655efefSmrg return 0; 51270655efefSmrg} 51280655efefSmrg 51296260e5d5Smrgdrm_public int drmSyncobjImportSyncFile(int fd, uint32_t handle, 51306260e5d5Smrg int sync_file_fd) 51310655efefSmrg{ 51320655efefSmrg struct drm_syncobj_handle args; 51330655efefSmrg 51340655efefSmrg memclear(args); 51350655efefSmrg args.fd = sync_file_fd; 51360655efefSmrg args.handle = handle; 51370655efefSmrg args.flags = DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_IMPORT_SYNC_FILE; 51380655efefSmrg return drmIoctl(fd, DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE, &args); 51390655efefSmrg} 51400655efefSmrg 51416260e5d5Smrgdrm_public int drmSyncobjExportSyncFile(int fd, uint32_t handle, 51426260e5d5Smrg int *sync_file_fd) 51430655efefSmrg{ 51440655efefSmrg struct drm_syncobj_handle args; 51450655efefSmrg int ret; 51460655efefSmrg 51470655efefSmrg memclear(args); 51480655efefSmrg args.fd = -1; 51490655efefSmrg args.handle = handle; 51500655efefSmrg args.flags = DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_EXPORT_SYNC_FILE; 51510655efefSmrg ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD, &args); 51520655efefSmrg if (ret) 51532b90624aSmrg return ret; 51540655efefSmrg *sync_file_fd = args.fd; 51550655efefSmrg return 0; 51560655efefSmrg} 51572b90624aSmrg 51586260e5d5Smrgdrm_public int drmSyncobjWait(int fd, uint32_t *handles, unsigned num_handles, 51596260e5d5Smrg int64_t timeout_nsec, unsigned flags, 51606260e5d5Smrg uint32_t *first_signaled) 51612b90624aSmrg{ 51622b90624aSmrg struct drm_syncobj_wait args; 51632b90624aSmrg int ret; 51642b90624aSmrg 51652b90624aSmrg memclear(args); 51662b90624aSmrg args.handles = (uintptr_t)handles; 51672b90624aSmrg args.timeout_nsec = timeout_nsec; 51682b90624aSmrg args.count_handles = num_handles; 51692b90624aSmrg args.flags = flags; 51702b90624aSmrg 51712b90624aSmrg ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_WAIT, &args); 51722b90624aSmrg if (ret < 0) 51732b90624aSmrg return -errno; 51742b90624aSmrg 51752b90624aSmrg if (first_signaled) 51762b90624aSmrg *first_signaled = args.first_signaled; 51772b90624aSmrg return ret; 51782b90624aSmrg} 51792b90624aSmrg 51806260e5d5Smrgdrm_public int drmSyncobjReset(int fd, const uint32_t *handles, 51816260e5d5Smrg uint32_t handle_count) 51822b90624aSmrg{ 51832b90624aSmrg struct drm_syncobj_array args; 51842b90624aSmrg int ret; 51852b90624aSmrg 51862b90624aSmrg memclear(args); 51872b90624aSmrg args.handles = (uintptr_t)handles; 51882b90624aSmrg args.count_handles = handle_count; 51892b90624aSmrg 51902b90624aSmrg ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_RESET, &args); 51912b90624aSmrg return ret; 51922b90624aSmrg} 51932b90624aSmrg 51946260e5d5Smrgdrm_public int drmSyncobjSignal(int fd, const uint32_t *handles, 51956260e5d5Smrg uint32_t handle_count) 51962b90624aSmrg{ 51972b90624aSmrg struct drm_syncobj_array args; 51982b90624aSmrg int ret; 51992b90624aSmrg 52002b90624aSmrg memclear(args); 52012b90624aSmrg args.handles = (uintptr_t)handles; 52022b90624aSmrg args.count_handles = handle_count; 52032b90624aSmrg 52042b90624aSmrg ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_SIGNAL, &args); 52052b90624aSmrg return ret; 52062b90624aSmrg} 5207bf6cc7dcSmrg 5208bf6cc7dcSmrgdrm_public int drmSyncobjTimelineSignal(int fd, const uint32_t *handles, 5209bf6cc7dcSmrg uint64_t *points, uint32_t handle_count) 5210bf6cc7dcSmrg{ 5211bf6cc7dcSmrg struct drm_syncobj_timeline_array args; 5212bf6cc7dcSmrg int ret; 5213bf6cc7dcSmrg 5214bf6cc7dcSmrg memclear(args); 5215bf6cc7dcSmrg args.handles = (uintptr_t)handles; 5216bf6cc7dcSmrg args.points = (uintptr_t)points; 5217bf6cc7dcSmrg args.count_handles = handle_count; 5218bf6cc7dcSmrg 5219bf6cc7dcSmrg ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_TIMELINE_SIGNAL, &args); 5220bf6cc7dcSmrg return ret; 5221bf6cc7dcSmrg} 5222bf6cc7dcSmrg 5223bf6cc7dcSmrgdrm_public int drmSyncobjTimelineWait(int fd, uint32_t *handles, uint64_t *points, 5224bf6cc7dcSmrg unsigned num_handles, 5225bf6cc7dcSmrg int64_t timeout_nsec, unsigned flags, 5226bf6cc7dcSmrg uint32_t *first_signaled) 5227bf6cc7dcSmrg{ 5228bf6cc7dcSmrg struct drm_syncobj_timeline_wait args; 5229bf6cc7dcSmrg int ret; 5230bf6cc7dcSmrg 5231bf6cc7dcSmrg memclear(args); 5232bf6cc7dcSmrg args.handles = (uintptr_t)handles; 5233bf6cc7dcSmrg args.points = (uintptr_t)points; 5234bf6cc7dcSmrg args.timeout_nsec = timeout_nsec; 5235bf6cc7dcSmrg args.count_handles = num_handles; 5236bf6cc7dcSmrg args.flags = flags; 5237bf6cc7dcSmrg 5238bf6cc7dcSmrg ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_TIMELINE_WAIT, &args); 5239bf6cc7dcSmrg if (ret < 0) 5240bf6cc7dcSmrg return -errno; 5241bf6cc7dcSmrg 5242bf6cc7dcSmrg if (first_signaled) 5243bf6cc7dcSmrg *first_signaled = args.first_signaled; 5244bf6cc7dcSmrg return ret; 5245bf6cc7dcSmrg} 5246bf6cc7dcSmrg 5247bf6cc7dcSmrg 5248bf6cc7dcSmrgdrm_public int drmSyncobjQuery(int fd, uint32_t *handles, uint64_t *points, 5249bf6cc7dcSmrg uint32_t handle_count) 5250bf6cc7dcSmrg{ 5251bf6cc7dcSmrg struct drm_syncobj_timeline_array args; 5252bf6cc7dcSmrg int ret; 5253bf6cc7dcSmrg 5254bf6cc7dcSmrg memclear(args); 5255bf6cc7dcSmrg args.handles = (uintptr_t)handles; 5256bf6cc7dcSmrg args.points = (uintptr_t)points; 5257bf6cc7dcSmrg args.count_handles = handle_count; 5258bf6cc7dcSmrg 5259bf6cc7dcSmrg ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_QUERY, &args); 5260bf6cc7dcSmrg if (ret) 5261bf6cc7dcSmrg return ret; 5262bf6cc7dcSmrg return 0; 5263bf6cc7dcSmrg} 5264bf6cc7dcSmrg 526587bf8e7cSmrgdrm_public int drmSyncobjQuery2(int fd, uint32_t *handles, uint64_t *points, 526687bf8e7cSmrg uint32_t handle_count, uint32_t flags) 526787bf8e7cSmrg{ 526887bf8e7cSmrg struct drm_syncobj_timeline_array args; 526987bf8e7cSmrg 527087bf8e7cSmrg memclear(args); 527187bf8e7cSmrg args.handles = (uintptr_t)handles; 527287bf8e7cSmrg args.points = (uintptr_t)points; 527387bf8e7cSmrg args.count_handles = handle_count; 527487bf8e7cSmrg args.flags = flags; 527587bf8e7cSmrg 527687bf8e7cSmrg return drmIoctl(fd, DRM_IOCTL_SYNCOBJ_QUERY, &args); 527787bf8e7cSmrg} 527887bf8e7cSmrg 527987bf8e7cSmrg 5280bf6cc7dcSmrgdrm_public int drmSyncobjTransfer(int fd, 5281bf6cc7dcSmrg uint32_t dst_handle, uint64_t dst_point, 5282bf6cc7dcSmrg uint32_t src_handle, uint64_t src_point, 5283bf6cc7dcSmrg uint32_t flags) 5284bf6cc7dcSmrg{ 5285bf6cc7dcSmrg struct drm_syncobj_transfer args; 5286bf6cc7dcSmrg int ret; 5287bf6cc7dcSmrg 5288bf6cc7dcSmrg memclear(args); 5289bf6cc7dcSmrg args.src_handle = src_handle; 5290bf6cc7dcSmrg args.dst_handle = dst_handle; 5291bf6cc7dcSmrg args.src_point = src_point; 5292bf6cc7dcSmrg args.dst_point = dst_point; 5293bf6cc7dcSmrg args.flags = flags; 5294bf6cc7dcSmrg 5295bf6cc7dcSmrg ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_TRANSFER, &args); 5296bf6cc7dcSmrg 5297bf6cc7dcSmrg return ret; 5298bf6cc7dcSmrg} 5299636d5e9fSmrg 530048246ce7Smrgdrm_public int drmSyncobjEventfd(int fd, uint32_t handle, uint64_t point, int ev_fd, 530148246ce7Smrg uint32_t flags) 530248246ce7Smrg{ 530348246ce7Smrg struct drm_syncobj_eventfd args; 530448246ce7Smrg 530548246ce7Smrg memclear(args); 530648246ce7Smrg args.handle = handle; 530748246ce7Smrg args.point = point; 530848246ce7Smrg args.fd = ev_fd; 530948246ce7Smrg args.flags = flags; 531048246ce7Smrg 531148246ce7Smrg return drmIoctl(fd, DRM_IOCTL_SYNCOBJ_EVENTFD, &args); 531248246ce7Smrg} 531348246ce7Smrg 5314636d5e9fSmrgstatic char * 5315636d5e9fSmrgdrmGetFormatModifierFromSimpleTokens(uint64_t modifier) 5316636d5e9fSmrg{ 5317636d5e9fSmrg unsigned int i; 5318636d5e9fSmrg 5319636d5e9fSmrg for (i = 0; i < ARRAY_SIZE(drm_format_modifier_table); i++) { 5320636d5e9fSmrg if (drm_format_modifier_table[i].modifier == modifier) 5321636d5e9fSmrg return strdup(drm_format_modifier_table[i].modifier_name); 5322636d5e9fSmrg } 5323636d5e9fSmrg 5324636d5e9fSmrg return NULL; 5325636d5e9fSmrg} 5326636d5e9fSmrg 5327636d5e9fSmrg/** Retrieves a human-readable representation of a vendor (as a string) from 5328636d5e9fSmrg * the format token modifier 5329636d5e9fSmrg * 5330636d5e9fSmrg * \param modifier the format modifier token 5331636d5e9fSmrg * \return a char pointer to the human-readable form of the vendor. Caller is 5332636d5e9fSmrg * responsible for freeing it. 5333636d5e9fSmrg */ 5334636d5e9fSmrgdrm_public char * 5335636d5e9fSmrgdrmGetFormatModifierVendor(uint64_t modifier) 5336636d5e9fSmrg{ 5337636d5e9fSmrg unsigned int i; 5338636d5e9fSmrg uint8_t vendor = fourcc_mod_get_vendor(modifier); 5339636d5e9fSmrg 5340636d5e9fSmrg for (i = 0; i < ARRAY_SIZE(drm_format_modifier_vendor_table); i++) { 5341636d5e9fSmrg if (drm_format_modifier_vendor_table[i].vendor == vendor) 5342636d5e9fSmrg return strdup(drm_format_modifier_vendor_table[i].vendor_name); 5343636d5e9fSmrg } 5344636d5e9fSmrg 5345636d5e9fSmrg return NULL; 5346636d5e9fSmrg} 5347636d5e9fSmrg 5348636d5e9fSmrg/** Retrieves a human-readable representation string from a format token 5349636d5e9fSmrg * modifier 5350636d5e9fSmrg * 5351636d5e9fSmrg * If the dedicated function was not able to extract a valid name or searching 5352636d5e9fSmrg * the format modifier was not in the table, this function would return NULL. 5353636d5e9fSmrg * 5354636d5e9fSmrg * \param modifier the token format 5355636d5e9fSmrg * \return a malloc'ed string representation of the modifier. Caller is 5356636d5e9fSmrg * responsible for freeing the string returned. 5357636d5e9fSmrg * 5358636d5e9fSmrg */ 5359636d5e9fSmrgdrm_public char * 5360636d5e9fSmrgdrmGetFormatModifierName(uint64_t modifier) 5361636d5e9fSmrg{ 5362636d5e9fSmrg uint8_t vendorid = fourcc_mod_get_vendor(modifier); 5363636d5e9fSmrg char *modifier_found = NULL; 5364636d5e9fSmrg unsigned int i; 5365636d5e9fSmrg 5366636d5e9fSmrg for (i = 0; i < ARRAY_SIZE(modifier_format_vendor_table); i++) { 5367636d5e9fSmrg if (modifier_format_vendor_table[i].vendor == vendorid) 5368636d5e9fSmrg modifier_found = modifier_format_vendor_table[i].vendor_cb(modifier); 5369636d5e9fSmrg } 5370636d5e9fSmrg 5371636d5e9fSmrg if (!modifier_found) 5372636d5e9fSmrg return drmGetFormatModifierFromSimpleTokens(modifier); 5373636d5e9fSmrg 5374636d5e9fSmrg return modifier_found; 5375636d5e9fSmrg} 53763b115362Smrg 53773b115362Smrg/** 53783b115362Smrg * Get a human-readable name for a DRM FourCC format. 53793b115362Smrg * 53803b115362Smrg * \param format The format. 53813b115362Smrg * \return A malloc'ed string containing the format name. Caller is responsible 53823b115362Smrg * for freeing it. 53833b115362Smrg */ 53843b115362Smrgdrm_public char * 53853b115362SmrgdrmGetFormatName(uint32_t format) 53863b115362Smrg{ 53873b115362Smrg char *str, code[5]; 53883b115362Smrg const char *be; 53893b115362Smrg size_t str_size, i; 53903b115362Smrg 53913b115362Smrg be = (format & DRM_FORMAT_BIG_ENDIAN) ? "_BE" : ""; 53923b115362Smrg format &= ~DRM_FORMAT_BIG_ENDIAN; 53933b115362Smrg 53943b115362Smrg if (format == DRM_FORMAT_INVALID) 53953b115362Smrg return strdup("INVALID"); 53963b115362Smrg 53973b115362Smrg code[0] = (char) ((format >> 0) & 0xFF); 53983b115362Smrg code[1] = (char) ((format >> 8) & 0xFF); 53993b115362Smrg code[2] = (char) ((format >> 16) & 0xFF); 54003b115362Smrg code[3] = (char) ((format >> 24) & 0xFF); 54013b115362Smrg code[4] = '\0'; 54023b115362Smrg 54033b115362Smrg /* Trim spaces at the end */ 54043b115362Smrg for (i = 3; i > 0 && code[i] == ' '; i--) 54053b115362Smrg code[i] = '\0'; 54063b115362Smrg 54073b115362Smrg str_size = strlen(code) + strlen(be) + 1; 54083b115362Smrg str = malloc(str_size); 54093b115362Smrg if (!str) 54103b115362Smrg return NULL; 54113b115362Smrg 54123b115362Smrg snprintf(str, str_size, "%s%s", code, be); 54133b115362Smrg 54143b115362Smrg return str; 54153b115362Smrg} 5416