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