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