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