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