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