xf86drm.c revision 48246ce7
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
208636d5e9fSmrgstatic bool is_x_t_amd_gfx9_tile(uint64_t tile)
209636d5e9fSmrg{
210636d5e9fSmrg    switch (tile) {
211636d5e9fSmrg    case AMD_FMT_MOD_TILE_GFX9_64K_S_X:
212636d5e9fSmrg    case AMD_FMT_MOD_TILE_GFX9_64K_D_X:
213636d5e9fSmrg    case AMD_FMT_MOD_TILE_GFX9_64K_R_X:
214636d5e9fSmrg           return true;
215636d5e9fSmrg    }
216636d5e9fSmrg
217636d5e9fSmrg    return false;
218636d5e9fSmrg}
219636d5e9fSmrg
220adfa0b0cSmrgstatic bool
221adfa0b0cSmrgdrmGetAfbcFormatModifierNameFromArm(uint64_t modifier, FILE *fp)
222636d5e9fSmrg{
223636d5e9fSmrg    uint64_t mode_value = modifier & AFBC_FORMAT_MOD_MODE_VALUE_MASK;
224636d5e9fSmrg    uint64_t block_size = mode_value & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK;
225636d5e9fSmrg
226636d5e9fSmrg    const char *block = NULL;
227636d5e9fSmrg    const char *mode = NULL;
228636d5e9fSmrg    bool did_print_mode = false;
229636d5e9fSmrg
230636d5e9fSmrg    /* add block, can only have a (single) block */
231636d5e9fSmrg    switch (block_size) {
232636d5e9fSmrg    case AFBC_FORMAT_MOD_BLOCK_SIZE_16x16:
233636d5e9fSmrg        block = "16x16";
234636d5e9fSmrg        break;
235636d5e9fSmrg    case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8:
236636d5e9fSmrg        block = "32x8";
237636d5e9fSmrg        break;
238636d5e9fSmrg    case AFBC_FORMAT_MOD_BLOCK_SIZE_64x4:
239636d5e9fSmrg        block = "64x4";
240636d5e9fSmrg        break;
241636d5e9fSmrg    case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8_64x4:
242636d5e9fSmrg        block = "32x8_64x4";
243636d5e9fSmrg        break;
244636d5e9fSmrg    }
245636d5e9fSmrg
246636d5e9fSmrg    if (!block) {
247adfa0b0cSmrg        return false;
248636d5e9fSmrg    }
249636d5e9fSmrg
250636d5e9fSmrg    fprintf(fp, "BLOCK_SIZE=%s,", block);
251636d5e9fSmrg
252636d5e9fSmrg    /* add mode */
253adfa0b0cSmrg    for (unsigned int i = 0; i < ARRAY_SIZE(arm_mode_value_table); i++) {
254636d5e9fSmrg        if (arm_mode_value_table[i].modifier & mode_value) {
255636d5e9fSmrg            mode = arm_mode_value_table[i].modifier_name;
256636d5e9fSmrg            if (!did_print_mode) {
257636d5e9fSmrg                fprintf(fp, "MODE=%s", mode);
258636d5e9fSmrg                did_print_mode = true;
259636d5e9fSmrg            } else {
260636d5e9fSmrg                fprintf(fp, "|%s", mode);
261636d5e9fSmrg            }
262636d5e9fSmrg        }
263636d5e9fSmrg    }
264636d5e9fSmrg
265adfa0b0cSmrg    return true;
266adfa0b0cSmrg}
267adfa0b0cSmrg
268adfa0b0cSmrgstatic bool
269adfa0b0cSmrgdrmGetAfrcFormatModifierNameFromArm(uint64_t modifier, FILE *fp)
270adfa0b0cSmrg{
27150027b5bSmrg    bool scan_layout;
272adfa0b0cSmrg    for (unsigned int i = 0; i < 2; ++i) {
273adfa0b0cSmrg        uint64_t coding_unit_block =
274adfa0b0cSmrg          (modifier >> (i * 4)) & AFRC_FORMAT_MOD_CU_SIZE_MASK;
275adfa0b0cSmrg        const char *coding_unit_size = NULL;
276adfa0b0cSmrg
277adfa0b0cSmrg        switch (coding_unit_block) {
278adfa0b0cSmrg        case AFRC_FORMAT_MOD_CU_SIZE_16:
279adfa0b0cSmrg            coding_unit_size = "CU_16";
280adfa0b0cSmrg            break;
281adfa0b0cSmrg        case AFRC_FORMAT_MOD_CU_SIZE_24:
282adfa0b0cSmrg            coding_unit_size = "CU_24";
283adfa0b0cSmrg            break;
284adfa0b0cSmrg        case AFRC_FORMAT_MOD_CU_SIZE_32:
285adfa0b0cSmrg            coding_unit_size = "CU_32";
286adfa0b0cSmrg            break;
287adfa0b0cSmrg        }
288adfa0b0cSmrg
289adfa0b0cSmrg        if (!coding_unit_size) {
290adfa0b0cSmrg            if (i == 0) {
291adfa0b0cSmrg                return false;
292adfa0b0cSmrg            }
293adfa0b0cSmrg            break;
294adfa0b0cSmrg        }
295adfa0b0cSmrg
296adfa0b0cSmrg        if (i == 0) {
297adfa0b0cSmrg            fprintf(fp, "P0=%s,", coding_unit_size);
298adfa0b0cSmrg        } else {
299adfa0b0cSmrg            fprintf(fp, "P12=%s,", coding_unit_size);
300adfa0b0cSmrg        }
301adfa0b0cSmrg    }
302adfa0b0cSmrg
30350027b5bSmrg    scan_layout =
304adfa0b0cSmrg        (modifier & AFRC_FORMAT_MOD_LAYOUT_SCAN) == AFRC_FORMAT_MOD_LAYOUT_SCAN;
305adfa0b0cSmrg    if (scan_layout) {
306adfa0b0cSmrg        fprintf(fp, "SCAN");
307adfa0b0cSmrg    } else {
308adfa0b0cSmrg        fprintf(fp, "ROT");
309adfa0b0cSmrg    }
310adfa0b0cSmrg    return true;
311adfa0b0cSmrg}
312adfa0b0cSmrg
313adfa0b0cSmrgstatic char *
314adfa0b0cSmrgdrmGetFormatModifierNameFromArm(uint64_t modifier)
315adfa0b0cSmrg{
316adfa0b0cSmrg    uint64_t type = (modifier >> 52) & 0xf;
317adfa0b0cSmrg
318adfa0b0cSmrg    FILE *fp;
319adfa0b0cSmrg    size_t size = 0;
320adfa0b0cSmrg    char *modifier_name = NULL;
321adfa0b0cSmrg    bool result = false;
322adfa0b0cSmrg
323adfa0b0cSmrg    fp = open_memstream(&modifier_name, &size);
324adfa0b0cSmrg    if (!fp)
325adfa0b0cSmrg        return NULL;
326adfa0b0cSmrg
327adfa0b0cSmrg    switch (type) {
328adfa0b0cSmrg    case DRM_FORMAT_MOD_ARM_TYPE_AFBC:
329adfa0b0cSmrg        result = drmGetAfbcFormatModifierNameFromArm(modifier, fp);
330adfa0b0cSmrg        break;
331adfa0b0cSmrg    case DRM_FORMAT_MOD_ARM_TYPE_AFRC:
332adfa0b0cSmrg        result = drmGetAfrcFormatModifierNameFromArm(modifier, fp);
333adfa0b0cSmrg        break;
334adfa0b0cSmrg    /* misc type is already handled by the static table */
335adfa0b0cSmrg    case DRM_FORMAT_MOD_ARM_TYPE_MISC:
336adfa0b0cSmrg    default:
337adfa0b0cSmrg        result = false;
338adfa0b0cSmrg        break;
339adfa0b0cSmrg    }
340adfa0b0cSmrg
341636d5e9fSmrg    fclose(fp);
342adfa0b0cSmrg    if (!result) {
343adfa0b0cSmrg        free(modifier_name);
344adfa0b0cSmrg        return NULL;
345adfa0b0cSmrg    }
346adfa0b0cSmrg
347636d5e9fSmrg    return modifier_name;
348636d5e9fSmrg}
349636d5e9fSmrg
350636d5e9fSmrgstatic char *
351636d5e9fSmrgdrmGetFormatModifierNameFromNvidia(uint64_t modifier)
352636d5e9fSmrg{
353636d5e9fSmrg    uint64_t height, kind, gen, sector, compression;
354636d5e9fSmrg
355636d5e9fSmrg    height = modifier & 0xf;
356636d5e9fSmrg    kind = (modifier >> 12) & 0xff;
357636d5e9fSmrg
358636d5e9fSmrg    gen = (modifier >> 20) & 0x3;
359636d5e9fSmrg    sector = (modifier >> 22) & 0x1;
360636d5e9fSmrg    compression = (modifier >> 23) & 0x7;
361636d5e9fSmrg
362636d5e9fSmrg    /* just in case there could other simpler modifiers, not yet added, avoid
363636d5e9fSmrg     * testing against TEGRA_TILE */
364636d5e9fSmrg    if ((modifier & 0x10) == 0x10) {
365636d5e9fSmrg        char *mod_nvidia;
366636d5e9fSmrg        asprintf(&mod_nvidia, "BLOCK_LINEAR_2D,HEIGHT=%"PRIu64",KIND=%"PRIu64","
367636d5e9fSmrg                 "GEN=%"PRIu64",SECTOR=%"PRIu64",COMPRESSION=%"PRIu64"", height,
368636d5e9fSmrg                 kind, gen, sector, compression);
369636d5e9fSmrg        return mod_nvidia;
370636d5e9fSmrg    }
371636d5e9fSmrg
372636d5e9fSmrg    return  NULL;
373636d5e9fSmrg}
374636d5e9fSmrg
375636d5e9fSmrgstatic void
376636d5e9fSmrgdrmGetFormatModifierNameFromAmdDcc(uint64_t modifier, FILE *fp)
377636d5e9fSmrg{
378636d5e9fSmrg    uint64_t dcc_max_compressed_block =
379636d5e9fSmrg                AMD_FMT_MOD_GET(DCC_MAX_COMPRESSED_BLOCK, modifier);
380636d5e9fSmrg    uint64_t dcc_retile = AMD_FMT_MOD_GET(DCC_RETILE, modifier);
381636d5e9fSmrg
382636d5e9fSmrg    const char *dcc_max_compressed_block_str = NULL;
383636d5e9fSmrg
384636d5e9fSmrg    fprintf(fp, ",DCC");
385636d5e9fSmrg
386636d5e9fSmrg    if (dcc_retile)
387636d5e9fSmrg        fprintf(fp, ",DCC_RETILE");
388636d5e9fSmrg
389636d5e9fSmrg    if (!dcc_retile && AMD_FMT_MOD_GET(DCC_PIPE_ALIGN, modifier))
390636d5e9fSmrg        fprintf(fp, ",DCC_PIPE_ALIGN");
391636d5e9fSmrg
392636d5e9fSmrg    if (AMD_FMT_MOD_GET(DCC_INDEPENDENT_64B, modifier))
393636d5e9fSmrg        fprintf(fp, ",DCC_INDEPENDENT_64B");
394636d5e9fSmrg
395636d5e9fSmrg    if (AMD_FMT_MOD_GET(DCC_INDEPENDENT_128B, modifier))
396636d5e9fSmrg        fprintf(fp, ",DCC_INDEPENDENT_128B");
397636d5e9fSmrg
398636d5e9fSmrg    switch (dcc_max_compressed_block) {
399636d5e9fSmrg    case AMD_FMT_MOD_DCC_BLOCK_64B:
400636d5e9fSmrg        dcc_max_compressed_block_str = "64B";
401636d5e9fSmrg        break;
402636d5e9fSmrg    case AMD_FMT_MOD_DCC_BLOCK_128B:
403636d5e9fSmrg        dcc_max_compressed_block_str = "128B";
404636d5e9fSmrg        break;
405636d5e9fSmrg    case AMD_FMT_MOD_DCC_BLOCK_256B:
406636d5e9fSmrg        dcc_max_compressed_block_str = "256B";
407636d5e9fSmrg        break;
408636d5e9fSmrg    }
409636d5e9fSmrg
410636d5e9fSmrg    if (dcc_max_compressed_block_str)
411636d5e9fSmrg        fprintf(fp, ",DCC_MAX_COMPRESSED_BLOCK=%s",
412636d5e9fSmrg                dcc_max_compressed_block_str);
413636d5e9fSmrg
414636d5e9fSmrg    if (AMD_FMT_MOD_GET(DCC_CONSTANT_ENCODE, modifier))
415636d5e9fSmrg        fprintf(fp, ",DCC_CONSTANT_ENCODE");
416636d5e9fSmrg}
417636d5e9fSmrg
418636d5e9fSmrgstatic void
419636d5e9fSmrgdrmGetFormatModifierNameFromAmdTile(uint64_t modifier, FILE *fp)
420636d5e9fSmrg{
421636d5e9fSmrg    uint64_t pipe_xor_bits, bank_xor_bits, packers, rb;
422636d5e9fSmrg    uint64_t pipe, pipe_align, dcc, dcc_retile, tile_version;
423636d5e9fSmrg
424636d5e9fSmrg    pipe_align = AMD_FMT_MOD_GET(DCC_PIPE_ALIGN, modifier);
425636d5e9fSmrg    pipe_xor_bits = AMD_FMT_MOD_GET(PIPE_XOR_BITS, modifier);
426636d5e9fSmrg    dcc = AMD_FMT_MOD_GET(DCC, modifier);
427636d5e9fSmrg    dcc_retile = AMD_FMT_MOD_GET(DCC_RETILE, modifier);
428636d5e9fSmrg    tile_version = AMD_FMT_MOD_GET(TILE_VERSION, modifier);
429636d5e9fSmrg
430636d5e9fSmrg    fprintf(fp, ",PIPE_XOR_BITS=%"PRIu64, pipe_xor_bits);
431636d5e9fSmrg
432636d5e9fSmrg    if (tile_version == AMD_FMT_MOD_TILE_VER_GFX9) {
433636d5e9fSmrg        bank_xor_bits = AMD_FMT_MOD_GET(BANK_XOR_BITS, modifier);
434636d5e9fSmrg        fprintf(fp, ",BANK_XOR_BITS=%"PRIu64, bank_xor_bits);
435636d5e9fSmrg    }
436636d5e9fSmrg
437636d5e9fSmrg    if (tile_version == AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS) {
438636d5e9fSmrg        packers = AMD_FMT_MOD_GET(PACKERS, modifier);
439636d5e9fSmrg        fprintf(fp, ",PACKERS=%"PRIu64, packers);
440636d5e9fSmrg    }
441636d5e9fSmrg
442636d5e9fSmrg    if (dcc && tile_version == AMD_FMT_MOD_TILE_VER_GFX9) {
443636d5e9fSmrg        rb = AMD_FMT_MOD_GET(RB, modifier);
444636d5e9fSmrg        fprintf(fp, ",RB=%"PRIu64, rb);
445636d5e9fSmrg    }
446636d5e9fSmrg
447636d5e9fSmrg    if (dcc && tile_version == AMD_FMT_MOD_TILE_VER_GFX9 &&
448636d5e9fSmrg        (dcc_retile || pipe_align)) {
449636d5e9fSmrg        pipe = AMD_FMT_MOD_GET(PIPE, modifier);
450636d5e9fSmrg        fprintf(fp, ",PIPE_%"PRIu64, pipe);
451636d5e9fSmrg    }
452636d5e9fSmrg}
453636d5e9fSmrg
454636d5e9fSmrgstatic char *
455636d5e9fSmrgdrmGetFormatModifierNameFromAmd(uint64_t modifier)
456636d5e9fSmrg{
457636d5e9fSmrg    uint64_t tile, tile_version, dcc;
458636d5e9fSmrg    FILE *fp;
459636d5e9fSmrg    char *mod_amd = NULL;
460636d5e9fSmrg    size_t size = 0;
461636d5e9fSmrg
462636d5e9fSmrg    const char *str_tile = NULL;
463636d5e9fSmrg    const char *str_tile_version = NULL;
464636d5e9fSmrg
465636d5e9fSmrg    tile = AMD_FMT_MOD_GET(TILE, modifier);
466636d5e9fSmrg    tile_version = AMD_FMT_MOD_GET(TILE_VERSION, modifier);
467636d5e9fSmrg    dcc = AMD_FMT_MOD_GET(DCC, modifier);
468636d5e9fSmrg
469636d5e9fSmrg    fp = open_memstream(&mod_amd, &size);
470636d5e9fSmrg    if (!fp)
471636d5e9fSmrg        return NULL;
472636d5e9fSmrg
473636d5e9fSmrg    /* add tile  */
474636d5e9fSmrg    switch (tile_version) {
475636d5e9fSmrg    case AMD_FMT_MOD_TILE_VER_GFX9:
476636d5e9fSmrg        str_tile_version = "GFX9";
477636d5e9fSmrg        break;
478636d5e9fSmrg    case AMD_FMT_MOD_TILE_VER_GFX10:
479636d5e9fSmrg        str_tile_version = "GFX10";
480636d5e9fSmrg        break;
481636d5e9fSmrg    case AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS:
482636d5e9fSmrg        str_tile_version = "GFX10_RBPLUS";
483636d5e9fSmrg        break;
48448246ce7Smrg    case AMD_FMT_MOD_TILE_VER_GFX11:
48548246ce7Smrg        str_tile_version = "GFX11";
48648246ce7Smrg        break;
487636d5e9fSmrg    }
488636d5e9fSmrg
489636d5e9fSmrg    if (str_tile_version) {
490636d5e9fSmrg        fprintf(fp, "%s", str_tile_version);
491636d5e9fSmrg    } else {
492636d5e9fSmrg        fclose(fp);
493636d5e9fSmrg        free(mod_amd);
494636d5e9fSmrg        return NULL;
495636d5e9fSmrg    }
496636d5e9fSmrg
497636d5e9fSmrg    /* add tile str */
498636d5e9fSmrg    switch (tile) {
499636d5e9fSmrg    case AMD_FMT_MOD_TILE_GFX9_64K_S:
500636d5e9fSmrg        str_tile = "GFX9_64K_S";
501636d5e9fSmrg        break;
502636d5e9fSmrg    case AMD_FMT_MOD_TILE_GFX9_64K_D:
503636d5e9fSmrg        str_tile = "GFX9_64K_D";
504636d5e9fSmrg        break;
505636d5e9fSmrg    case AMD_FMT_MOD_TILE_GFX9_64K_S_X:
506636d5e9fSmrg        str_tile = "GFX9_64K_S_X";
507636d5e9fSmrg        break;
508636d5e9fSmrg    case AMD_FMT_MOD_TILE_GFX9_64K_D_X:
509636d5e9fSmrg        str_tile = "GFX9_64K_D_X";
510636d5e9fSmrg        break;
511636d5e9fSmrg    case AMD_FMT_MOD_TILE_GFX9_64K_R_X:
512636d5e9fSmrg        str_tile = "GFX9_64K_R_X";
513636d5e9fSmrg        break;
51448246ce7Smrg    case AMD_FMT_MOD_TILE_GFX11_256K_R_X:
51548246ce7Smrg        str_tile = "GFX11_256K_R_X";
51648246ce7Smrg        break;
517636d5e9fSmrg    }
518636d5e9fSmrg
519636d5e9fSmrg    if (str_tile)
520636d5e9fSmrg        fprintf(fp, ",%s", str_tile);
521636d5e9fSmrg
522636d5e9fSmrg    if (dcc)
523636d5e9fSmrg        drmGetFormatModifierNameFromAmdDcc(modifier, fp);
524636d5e9fSmrg
525636d5e9fSmrg    if (tile_version >= AMD_FMT_MOD_TILE_VER_GFX9 && is_x_t_amd_gfx9_tile(tile))
526636d5e9fSmrg        drmGetFormatModifierNameFromAmdTile(modifier, fp);
527636d5e9fSmrg
528636d5e9fSmrg    fclose(fp);
529636d5e9fSmrg    return mod_amd;
530636d5e9fSmrg}
531636d5e9fSmrg
532636d5e9fSmrgstatic char *
533636d5e9fSmrgdrmGetFormatModifierNameFromAmlogic(uint64_t modifier)
534636d5e9fSmrg{
535636d5e9fSmrg    uint64_t layout = modifier & 0xff;
536636d5e9fSmrg    uint64_t options = (modifier >> 8) & 0xff;
537636d5e9fSmrg    char *mod_amlogic = NULL;
538636d5e9fSmrg
539636d5e9fSmrg    const char *layout_str;
540636d5e9fSmrg    const char *opts_str;
541636d5e9fSmrg
542636d5e9fSmrg    switch (layout) {
543636d5e9fSmrg    case AMLOGIC_FBC_LAYOUT_BASIC:
544636d5e9fSmrg       layout_str = "BASIC";
545636d5e9fSmrg       break;
546636d5e9fSmrg    case AMLOGIC_FBC_LAYOUT_SCATTER:
547636d5e9fSmrg       layout_str = "SCATTER";
548636d5e9fSmrg       break;
549636d5e9fSmrg    default:
550636d5e9fSmrg       layout_str = "INVALID_LAYOUT";
551636d5e9fSmrg       break;
552636d5e9fSmrg    }
553636d5e9fSmrg
554636d5e9fSmrg    if (options & AMLOGIC_FBC_OPTION_MEM_SAVING)
555636d5e9fSmrg        opts_str = "MEM_SAVING";
556636d5e9fSmrg    else
557636d5e9fSmrg        opts_str = "0";
558636d5e9fSmrg
559636d5e9fSmrg    asprintf(&mod_amlogic, "FBC,LAYOUT=%s,OPTIONS=%s", layout_str, opts_str);
560636d5e9fSmrg    return mod_amlogic;
561636d5e9fSmrg}
562636d5e9fSmrg
56348246ce7Smrgstatic char *
56448246ce7SmrgdrmGetFormatModifierNameFromVivante(uint64_t modifier)
56548246ce7Smrg{
56648246ce7Smrg    const char *color_tiling, *tile_status, *compression;
56748246ce7Smrg    char *mod_vivante = NULL;
56848246ce7Smrg
56948246ce7Smrg    switch (modifier & VIVANTE_MOD_TS_MASK) {
57048246ce7Smrg    case 0:
57148246ce7Smrg        tile_status = "";
57248246ce7Smrg        break;
57348246ce7Smrg    case VIVANTE_MOD_TS_64_4:
57448246ce7Smrg        tile_status = ",TS=64B_4";
57548246ce7Smrg        break;
57648246ce7Smrg    case VIVANTE_MOD_TS_64_2:
57748246ce7Smrg        tile_status = ",TS=64B_2";
57848246ce7Smrg        break;
57948246ce7Smrg    case VIVANTE_MOD_TS_128_4:
58048246ce7Smrg        tile_status = ",TS=128B_4";
58148246ce7Smrg        break;
58248246ce7Smrg    case VIVANTE_MOD_TS_256_4:
58348246ce7Smrg        tile_status = ",TS=256B_4";
58448246ce7Smrg        break;
58548246ce7Smrg    default:
58648246ce7Smrg        tile_status = ",TS=UNKNOWN";
58748246ce7Smrg        break;
58848246ce7Smrg    }
58948246ce7Smrg
59048246ce7Smrg    switch (modifier & VIVANTE_MOD_COMP_MASK) {
59148246ce7Smrg    case 0:
59248246ce7Smrg        compression = "";
59348246ce7Smrg        break;
59448246ce7Smrg    case VIVANTE_MOD_COMP_DEC400:
59548246ce7Smrg        compression = ",COMP=DEC400";
59648246ce7Smrg        break;
59748246ce7Smrg    default:
59848246ce7Smrg        compression = ",COMP=UNKNOWN";
59948246ce7Smrg	break;
60048246ce7Smrg    }
60148246ce7Smrg
60248246ce7Smrg    switch (modifier & ~VIVANTE_MOD_EXT_MASK) {
60348246ce7Smrg    case 0:
60448246ce7Smrg        color_tiling = "LINEAR";
60548246ce7Smrg	break;
60648246ce7Smrg    case DRM_FORMAT_MOD_VIVANTE_TILED:
60748246ce7Smrg        color_tiling = "TILED";
60848246ce7Smrg	break;
60948246ce7Smrg    case DRM_FORMAT_MOD_VIVANTE_SUPER_TILED:
61048246ce7Smrg        color_tiling = "SUPER_TILED";
61148246ce7Smrg	break;
61248246ce7Smrg    case DRM_FORMAT_MOD_VIVANTE_SPLIT_TILED:
61348246ce7Smrg        color_tiling = "SPLIT_TILED";
61448246ce7Smrg	break;
61548246ce7Smrg    case DRM_FORMAT_MOD_VIVANTE_SPLIT_SUPER_TILED:
61648246ce7Smrg        color_tiling = "SPLIT_SUPER_TILED";
61748246ce7Smrg	break;
61848246ce7Smrg    default:
61948246ce7Smrg        color_tiling = "UNKNOWN";
62048246ce7Smrg	break;
62148246ce7Smrg    }
62248246ce7Smrg
62348246ce7Smrg    asprintf(&mod_vivante, "%s%s%s", color_tiling, tile_status, compression);
62448246ce7Smrg    return mod_vivante;
62548246ce7Smrg}
62648246ce7Smrg
6274b3d3f37Smrgstatic unsigned log2_int(unsigned x)
6284b3d3f37Smrg{
6294b3d3f37Smrg    unsigned l;
6304b3d3f37Smrg
6314b3d3f37Smrg    if (x < 2) {
6324b3d3f37Smrg        return 0;
6334b3d3f37Smrg    }
6344b3d3f37Smrg    for (l = 2; ; l++) {
6354b3d3f37Smrg        if ((unsigned)(1 << l) > x) {
6364b3d3f37Smrg            return l - 1;
6374b3d3f37Smrg        }
6384b3d3f37Smrg    }
6394b3d3f37Smrg    return 0;
6404b3d3f37Smrg}
6414b3d3f37Smrg
6424b3d3f37Smrg
6436260e5d5Smrgdrm_public void drmSetServerInfo(drmServerInfoPtr info)
64422944501Smrg{
64522944501Smrg    drm_server_info = info;
64622944501Smrg}
64722944501Smrg
64822944501Smrg/**
64922944501Smrg * Output a message to stderr.
65022944501Smrg *
65122944501Smrg * \param format printf() like format string.
65222944501Smrg *
65322944501Smrg * \internal
65422944501Smrg * This function is a wrapper around vfprintf().
65522944501Smrg */
65622944501Smrg
657a7d7de1eSmrgstatic int DRM_PRINTFLIKE(1, 0)
658a7d7de1eSmrgdrmDebugPrint(const char *format, va_list ap)
65922944501Smrg{
66022944501Smrg    return vfprintf(stderr, format, ap);
66122944501Smrg}
66222944501Smrg
6636260e5d5Smrgdrm_public void
66422944501SmrgdrmMsg(const char *format, ...)
66522944501Smrg{
666fe517fc9Smrg    va_list ap;
66722944501Smrg    const char *env;
668fe517fc9Smrg    if (((env = getenv("LIBGL_DEBUG")) && strstr(env, "verbose")) ||
669fe517fc9Smrg        (drm_server_info && drm_server_info->debug_print))
67022944501Smrg    {
671fe517fc9Smrg        va_start(ap, format);
672fe517fc9Smrg        if (drm_server_info) {
673fe517fc9Smrg            drm_server_info->debug_print(format,ap);
674fe517fc9Smrg        } else {
675fe517fc9Smrg            drmDebugPrint(format, ap);
676fe517fc9Smrg        }
677fe517fc9Smrg        va_end(ap);
67822944501Smrg    }
67922944501Smrg}
68022944501Smrg
68122944501Smrgstatic void *drmHashTable = NULL; /* Context switch callbacks */
68222944501Smrg
6836260e5d5Smrgdrm_public void *drmGetHashTable(void)
68422944501Smrg{
68522944501Smrg    return drmHashTable;
68622944501Smrg}
68722944501Smrg
6886260e5d5Smrgdrm_public void *drmMalloc(int size)
68922944501Smrg{
690424e9256Smrg    return calloc(1, size);
69122944501Smrg}
69222944501Smrg
6936260e5d5Smrgdrm_public void drmFree(void *pt)
69422944501Smrg{
695424e9256Smrg    free(pt);
69622944501Smrg}
69722944501Smrg
69822944501Smrg/**
699bf6cc7dcSmrg * Call ioctl, restarting if it is interrupted
70022944501Smrg */
7016260e5d5Smrgdrm_public int
70222944501SmrgdrmIoctl(int fd, unsigned long request, void *arg)
70322944501Smrg{
704fe517fc9Smrg    int ret;
70522944501Smrg
70622944501Smrg    do {
707fe517fc9Smrg        ret = ioctl(fd, request, arg);
70822944501Smrg    } while (ret == -1 && (errno == EINTR || errno == EAGAIN));
70922944501Smrg    return ret;
71022944501Smrg}
71122944501Smrg
71222944501Smrgstatic unsigned long drmGetKeyFromFd(int fd)
71322944501Smrg{
71422944501Smrg    stat_t     st;
71522944501Smrg
71622944501Smrg    st.st_rdev = 0;
71722944501Smrg    fstat(fd, &st);
71822944501Smrg    return st.st_rdev;
71922944501Smrg}
72022944501Smrg
7216260e5d5Smrgdrm_public drmHashEntry *drmGetEntry(int fd)
72222944501Smrg{
72322944501Smrg    unsigned long key = drmGetKeyFromFd(fd);
72422944501Smrg    void          *value;
72522944501Smrg    drmHashEntry  *entry;
72622944501Smrg
72722944501Smrg    if (!drmHashTable)
728fe517fc9Smrg        drmHashTable = drmHashCreate();
72922944501Smrg
73022944501Smrg    if (drmHashLookup(drmHashTable, key, &value)) {
731fe517fc9Smrg        entry           = drmMalloc(sizeof(*entry));
732fe517fc9Smrg        entry->fd       = fd;
733fe517fc9Smrg        entry->f        = NULL;
734fe517fc9Smrg        entry->tagTable = drmHashCreate();
735fe517fc9Smrg        drmHashInsert(drmHashTable, key, entry);
73622944501Smrg    } else {
737fe517fc9Smrg        entry = value;
73822944501Smrg    }
73922944501Smrg    return entry;
74022944501Smrg}
74122944501Smrg
74222944501Smrg/**
74322944501Smrg * Compare two busid strings
74422944501Smrg *
74522944501Smrg * \param first
74622944501Smrg * \param second
74722944501Smrg *
74822944501Smrg * \return 1 if matched.
74922944501Smrg *
75022944501Smrg * \internal
75122944501Smrg * This function compares two bus ID strings.  It understands the older
75222944501Smrg * PCI:b:d:f format and the newer pci:oooo:bb:dd.f format.  In the format, o is
75322944501Smrg * domain, b is bus, d is device, f is function.
75422944501Smrg */
7556d98c517Smrgstatic int drmMatchBusID(const char *id1, const char *id2, int pci_domain_ok)
75622944501Smrg{
75722944501Smrg    /* First, check if the IDs are exactly the same */
75822944501Smrg    if (strcasecmp(id1, id2) == 0)
759fe517fc9Smrg        return 1;
76022944501Smrg
76122944501Smrg    /* Try to match old/new-style PCI bus IDs. */
76222944501Smrg    if (strncasecmp(id1, "pci", 3) == 0) {
763fe517fc9Smrg        unsigned int o1, b1, d1, f1;
764fe517fc9Smrg        unsigned int o2, b2, d2, f2;
765fe517fc9Smrg        int ret;
766fe517fc9Smrg
767fe517fc9Smrg        ret = sscanf(id1, "pci:%04x:%02x:%02x.%u", &o1, &b1, &d1, &f1);
768fe517fc9Smrg        if (ret != 4) {
769fe517fc9Smrg            o1 = 0;
770fe517fc9Smrg            ret = sscanf(id1, "PCI:%u:%u:%u", &b1, &d1, &f1);
771fe517fc9Smrg            if (ret != 3)
772fe517fc9Smrg                return 0;
773fe517fc9Smrg        }
774fe517fc9Smrg
775fe517fc9Smrg        ret = sscanf(id2, "pci:%04x:%02x:%02x.%u", &o2, &b2, &d2, &f2);
776fe517fc9Smrg        if (ret != 4) {
777fe517fc9Smrg            o2 = 0;
778fe517fc9Smrg            ret = sscanf(id2, "PCI:%u:%u:%u", &b2, &d2, &f2);
779fe517fc9Smrg            if (ret != 3)
780fe517fc9Smrg                return 0;
781fe517fc9Smrg        }
782fe517fc9Smrg
783fe517fc9Smrg        /* If domains aren't properly supported by the kernel interface,
784fe517fc9Smrg         * just ignore them, which sucks less than picking a totally random
785fe517fc9Smrg         * card with "open by name"
786fe517fc9Smrg         */
787fe517fc9Smrg        if (!pci_domain_ok)
788fe517fc9Smrg            o1 = o2 = 0;
789fe517fc9Smrg
790fe517fc9Smrg        if ((o1 != o2) || (b1 != b2) || (d1 != d2) || (f1 != f2))
791fe517fc9Smrg            return 0;
792fe517fc9Smrg        else
793fe517fc9Smrg            return 1;
79422944501Smrg    }
79522944501Smrg    return 0;
79622944501Smrg}
79722944501Smrg
79822944501Smrg/**
79922944501Smrg * Handles error checking for chown call.
80022944501Smrg *
80122944501Smrg * \param path to file.
80222944501Smrg * \param id of the new owner.
80322944501Smrg * \param id of the new group.
80422944501Smrg *
80522944501Smrg * \return zero if success or -1 if failure.
80622944501Smrg *
80722944501Smrg * \internal
80822944501Smrg * Checks for failure. If failure was caused by signal call chown again.
809bf6cc7dcSmrg * If any other failure happened then it will output error message using
81022944501Smrg * drmMsg() call.
81122944501Smrg */
8126260e5d5Smrg#if !UDEV
81322944501Smrgstatic int chown_check_return(const char *path, uid_t owner, gid_t group)
81422944501Smrg{
815fe517fc9Smrg        int rv;
81622944501Smrg
817fe517fc9Smrg        do {
818fe517fc9Smrg            rv = chown(path, owner, group);
819fe517fc9Smrg        } while (rv != 0 && errno == EINTR);
82022944501Smrg
821fe517fc9Smrg        if (rv == 0)
822fe517fc9Smrg            return 0;
82322944501Smrg
824fe517fc9Smrg        drmMsg("Failed to change owner or group for file %s! %d: %s\n",
825fe517fc9Smrg               path, errno, strerror(errno));
826fe517fc9Smrg        return -1;
82722944501Smrg}
828424e9256Smrg#endif
82922944501Smrg
83082025ec7Smrgstatic const char *drmGetDeviceName(int type)
83182025ec7Smrg{
83282025ec7Smrg    switch (type) {
83382025ec7Smrg    case DRM_NODE_PRIMARY:
83482025ec7Smrg        return DRM_DEV_NAME;
83582025ec7Smrg    case DRM_NODE_RENDER:
83682025ec7Smrg        return DRM_RENDER_DEV_NAME;
83782025ec7Smrg    }
83882025ec7Smrg    return NULL;
83982025ec7Smrg}
84082025ec7Smrg
84122944501Smrg/**
84222944501Smrg * Open the DRM device, creating it if necessary.
84322944501Smrg *
84422944501Smrg * \param dev major and minor numbers of the device.
84522944501Smrg * \param minor minor number of the device.
846fe517fc9Smrg *
84722944501Smrg * \return a file descriptor on success, or a negative value on error.
84822944501Smrg *
84922944501Smrg * \internal
85022944501Smrg * Assembles the device name from \p minor and opens it, creating the device
85122944501Smrg * special file node with the major and minor numbers specified by \p dev and
85222944501Smrg * parent directory if necessary and was called by root.
85322944501Smrg */
854424e9256Smrgstatic int drmOpenDevice(dev_t dev, int minor, int type)
85522944501Smrg{
85622944501Smrg    stat_t          st;
85782025ec7Smrg    const char      *dev_name = drmGetDeviceName(type);
85882025ec7Smrg    char            buf[DRM_NODE_NAME_MAX];
85922944501Smrg    int             fd;
86022944501Smrg    mode_t          devmode = DRM_DEV_MODE, serv_mode;
861424e9256Smrg    gid_t           serv_group;
8626260e5d5Smrg#if !UDEV
86322944501Smrg    int             isroot  = !geteuid();
86422944501Smrg    uid_t           user    = DRM_DEV_UID;
865424e9256Smrg    gid_t           group   = DRM_DEV_GID;
866424e9256Smrg#endif
867424e9256Smrg
86882025ec7Smrg    if (!dev_name)
869fe517fc9Smrg        return -EINVAL;
870424e9256Smrg
871424e9256Smrg    sprintf(buf, dev_name, DRM_DIR_NAME, minor);
87222944501Smrg    drmMsg("drmOpenDevice: node name is %s\n", buf);
87322944501Smrg
874fe517fc9Smrg    if (drm_server_info && drm_server_info->get_perms) {
875fe517fc9Smrg        drm_server_info->get_perms(&serv_group, &serv_mode);
876fe517fc9Smrg        devmode  = serv_mode ? serv_mode : DRM_DEV_MODE;
877fe517fc9Smrg        devmode &= ~(S_IXUSR|S_IXGRP|S_IXOTH);
87822944501Smrg    }
87922944501Smrg
8806260e5d5Smrg#if !UDEV
88122944501Smrg    if (stat(DRM_DIR_NAME, &st)) {
882fe517fc9Smrg        if (!isroot)
883fe517fc9Smrg            return DRM_ERR_NOT_ROOT;
884fe517fc9Smrg        mkdir(DRM_DIR_NAME, DRM_DEV_DIRMODE);
885fe517fc9Smrg        chown_check_return(DRM_DIR_NAME, 0, 0); /* root:root */
886fe517fc9Smrg        chmod(DRM_DIR_NAME, DRM_DEV_DIRMODE);
88722944501Smrg    }
88822944501Smrg
88922944501Smrg    /* Check if the device node exists and create it if necessary. */
89022944501Smrg    if (stat(buf, &st)) {
891fe517fc9Smrg        if (!isroot)
892fe517fc9Smrg            return DRM_ERR_NOT_ROOT;
893fe517fc9Smrg        remove(buf);
894fe517fc9Smrg        mknod(buf, S_IFCHR | devmode, dev);
89522944501Smrg    }
89622944501Smrg
897fe517fc9Smrg    if (drm_server_info && drm_server_info->get_perms) {
898fe517fc9Smrg        group = ((int)serv_group >= 0) ? serv_group : DRM_DEV_GID;
899fe517fc9Smrg        chown_check_return(buf, user, group);
900fe517fc9Smrg        chmod(buf, devmode);
90122944501Smrg    }
90222944501Smrg#else
90322944501Smrg    /* if we modprobed then wait for udev */
90422944501Smrg    {
905fe517fc9Smrg        int udev_count = 0;
90622944501Smrgwait_for_udev:
90722944501Smrg        if (stat(DRM_DIR_NAME, &st)) {
908fe517fc9Smrg            usleep(20);
909fe517fc9Smrg            udev_count++;
910fe517fc9Smrg
911fe517fc9Smrg            if (udev_count == 50)
912fe517fc9Smrg                return -1;
913fe517fc9Smrg            goto wait_for_udev;
914fe517fc9Smrg        }
915fe517fc9Smrg
916fe517fc9Smrg        if (stat(buf, &st)) {
917fe517fc9Smrg            usleep(20);
918fe517fc9Smrg            udev_count++;
919fe517fc9Smrg
920fe517fc9Smrg            if (udev_count == 50)
921fe517fc9Smrg                return -1;
922fe517fc9Smrg            goto wait_for_udev;
923fe517fc9Smrg        }
92422944501Smrg    }
92522944501Smrg#endif
92622944501Smrg
9273b115362Smrg    fd = open(buf, O_RDWR | O_CLOEXEC);
92822944501Smrg    drmMsg("drmOpenDevice: open result is %d, (%s)\n",
929fe517fc9Smrg           fd, fd < 0 ? strerror(errno) : "OK");
93022944501Smrg    if (fd >= 0)
931fe517fc9Smrg        return fd;
93222944501Smrg
9336260e5d5Smrg#if !UDEV
93422944501Smrg    /* Check if the device node is not what we expect it to be, and recreate it
93522944501Smrg     * and try again if so.
93622944501Smrg     */
93722944501Smrg    if (st.st_rdev != dev) {
938fe517fc9Smrg        if (!isroot)
939fe517fc9Smrg            return DRM_ERR_NOT_ROOT;
940fe517fc9Smrg        remove(buf);
941fe517fc9Smrg        mknod(buf, S_IFCHR | devmode, dev);
942fe517fc9Smrg        if (drm_server_info && drm_server_info->get_perms) {
943fe517fc9Smrg            chown_check_return(buf, user, group);
944fe517fc9Smrg            chmod(buf, devmode);
945fe517fc9Smrg        }
94622944501Smrg    }
9473b115362Smrg    fd = open(buf, O_RDWR | O_CLOEXEC);
94822944501Smrg    drmMsg("drmOpenDevice: open result is %d, (%s)\n",
949fe517fc9Smrg           fd, fd < 0 ? strerror(errno) : "OK");
95022944501Smrg    if (fd >= 0)
951fe517fc9Smrg        return fd;
95222944501Smrg
95322944501Smrg    drmMsg("drmOpenDevice: Open failed\n");
95422944501Smrg    remove(buf);
9559ce4edccSmrg#endif
95622944501Smrg    return -errno;
95722944501Smrg}
95822944501Smrg
95922944501Smrg
96022944501Smrg/**
96122944501Smrg * Open the DRM device
96222944501Smrg *
96322944501Smrg * \param minor device minor number.
96422944501Smrg * \param create allow to create the device if set.
96522944501Smrg *
96622944501Smrg * \return a file descriptor on success, or a negative value on error.
967fe517fc9Smrg *
96822944501Smrg * \internal
96922944501Smrg * Calls drmOpenDevice() if \p create is set, otherwise assembles the device
97022944501Smrg * name from \p minor and opens it.
97122944501Smrg */
97222944501Smrgstatic int drmOpenMinor(int minor, int create, int type)
97322944501Smrg{
97422944501Smrg    int  fd;
97582025ec7Smrg    char buf[DRM_NODE_NAME_MAX];
97682025ec7Smrg    const char *dev_name = drmGetDeviceName(type);
977fe517fc9Smrg
97822944501Smrg    if (create)
979fe517fc9Smrg        return drmOpenDevice(makedev(DRM_MAJOR, minor), minor, type);
980fe517fc9Smrg
98182025ec7Smrg    if (!dev_name)
982fe517fc9Smrg        return -EINVAL;
983424e9256Smrg
984424e9256Smrg    sprintf(buf, dev_name, DRM_DIR_NAME, minor);
9853b115362Smrg    if ((fd = open(buf, O_RDWR | O_CLOEXEC)) >= 0)
986fe517fc9Smrg        return fd;
98722944501Smrg    return -errno;
98822944501Smrg}
98922944501Smrg
99022944501Smrg
99122944501Smrg/**
99222944501Smrg * Determine whether the DRM kernel driver has been loaded.
993fe517fc9Smrg *
99422944501Smrg * \return 1 if the DRM driver is loaded, 0 otherwise.
99522944501Smrg *
996fe517fc9Smrg * \internal
99722944501Smrg * Determine the presence of the kernel driver by attempting to open the 0
99822944501Smrg * minor and get version information.  For backward compatibility with older
99922944501Smrg * Linux implementations, /proc/dri is also checked.
100022944501Smrg */
10016260e5d5Smrgdrm_public int drmAvailable(void)
100222944501Smrg{
100322944501Smrg    drmVersionPtr version;
100422944501Smrg    int           retval = 0;
100522944501Smrg    int           fd;
100622944501Smrg
1007424e9256Smrg    if ((fd = drmOpenMinor(0, 1, DRM_NODE_PRIMARY)) < 0) {
100822944501Smrg#ifdef __linux__
1009fe517fc9Smrg        /* Try proc for backward Linux compatibility */
1010fe517fc9Smrg        if (!access("/proc/dri/0", R_OK))
1011fe517fc9Smrg            return 1;
101222944501Smrg#endif
1013fe517fc9Smrg        return 0;
101422944501Smrg    }
1015fe517fc9Smrg
101622944501Smrg    if ((version = drmGetVersion(fd))) {
1017fe517fc9Smrg        retval = 1;
1018fe517fc9Smrg        drmFreeVersion(version);
101922944501Smrg    }
102022944501Smrg    close(fd);
102122944501Smrg
102222944501Smrg    return retval;
102322944501Smrg}
102422944501Smrg
1025424e9256Smrgstatic int drmGetMinorBase(int type)
1026424e9256Smrg{
1027424e9256Smrg    switch (type) {
1028424e9256Smrg    case DRM_NODE_PRIMARY:
1029424e9256Smrg        return 0;
1030424e9256Smrg    case DRM_NODE_RENDER:
1031424e9256Smrg        return 128;
1032424e9256Smrg    default:
1033424e9256Smrg        return -1;
1034424e9256Smrg    };
1035424e9256Smrg}
1036424e9256Smrg
103787bf8e7cSmrgstatic int drmGetMinorType(int major, int minor)
1038424e9256Smrg{
103987bf8e7cSmrg#ifdef __FreeBSD__
104087bf8e7cSmrg    char name[SPECNAMELEN];
104187bf8e7cSmrg    int id;
104287bf8e7cSmrg
104387bf8e7cSmrg    if (!devname_r(makedev(major, minor), S_IFCHR, name, sizeof(name)))
104487bf8e7cSmrg        return -1;
104587bf8e7cSmrg
104687bf8e7cSmrg    if (sscanf(name, "drm/%d", &id) != 1) {
104787bf8e7cSmrg        // If not in /dev/drm/ we have the type in the name
104887bf8e7cSmrg        if (sscanf(name, "dri/card%d\n", &id) >= 1)
104987bf8e7cSmrg           return DRM_NODE_PRIMARY;
105087bf8e7cSmrg        else if (sscanf(name, "dri/renderD%d\n", &id) >= 1)
105187bf8e7cSmrg           return DRM_NODE_RENDER;
105287bf8e7cSmrg        return -1;
105387bf8e7cSmrg    }
105487bf8e7cSmrg
105587bf8e7cSmrg    minor = id;
105687bf8e7cSmrg#endif
105748246ce7Smrg    char path[DRM_NODE_NAME_MAX];
105848246ce7Smrg    const char *dev_name;
105948246ce7Smrg    int i;
1060424e9256Smrg
106148246ce7Smrg    for (i = DRM_NODE_PRIMARY; i < DRM_NODE_MAX; i++) {
106248246ce7Smrg        dev_name = drmGetDeviceName(i);
106348246ce7Smrg        if (!dev_name)
106448246ce7Smrg           continue;
106548246ce7Smrg        snprintf(path, sizeof(path), dev_name, DRM_DIR_NAME, minor);
106648246ce7Smrg        if (!access(path, F_OK))
106748246ce7Smrg           return i;
1068424e9256Smrg    }
106948246ce7Smrg
107048246ce7Smrg    return -1;
1071424e9256Smrg}
1072424e9256Smrg
1073424e9256Smrgstatic const char *drmGetMinorName(int type)
1074424e9256Smrg{
1075424e9256Smrg    switch (type) {
1076424e9256Smrg    case DRM_NODE_PRIMARY:
1077fe517fc9Smrg        return DRM_PRIMARY_MINOR_NAME;
1078424e9256Smrg    case DRM_NODE_RENDER:
1079fe517fc9Smrg        return DRM_RENDER_MINOR_NAME;
1080424e9256Smrg    default:
1081424e9256Smrg        return NULL;
1082424e9256Smrg    }
1083424e9256Smrg}
108422944501Smrg
108522944501Smrg/**
108622944501Smrg * Open the device by bus ID.
108722944501Smrg *
108822944501Smrg * \param busid bus ID.
1089424e9256Smrg * \param type device node type.
109022944501Smrg *
109122944501Smrg * \return a file descriptor on success, or a negative value on error.
109222944501Smrg *
109322944501Smrg * \internal
109422944501Smrg * This function attempts to open every possible minor (up to DRM_MAX_MINOR),
109522944501Smrg * comparing the device bus ID with the one supplied.
109622944501Smrg *
109722944501Smrg * \sa drmOpenMinor() and drmGetBusid().
109822944501Smrg */
1099424e9256Smrgstatic int drmOpenByBusid(const char *busid, int type)
110022944501Smrg{
11016d98c517Smrg    int        i, pci_domain_ok = 1;
110222944501Smrg    int        fd;
110322944501Smrg    const char *buf;
110422944501Smrg    drmSetVersion sv;
1105424e9256Smrg    int        base = drmGetMinorBase(type);
1106424e9256Smrg
1107424e9256Smrg    if (base < 0)
1108424e9256Smrg        return -1;
110922944501Smrg
111022944501Smrg    drmMsg("drmOpenByBusid: Searching for BusID %s\n", busid);
1111424e9256Smrg    for (i = base; i < base + DRM_MAX_MINOR; i++) {
1112fe517fc9Smrg        fd = drmOpenMinor(i, 1, type);
1113fe517fc9Smrg        drmMsg("drmOpenByBusid: drmOpenMinor returns %d\n", fd);
1114fe517fc9Smrg        if (fd >= 0) {
1115fe517fc9Smrg            /* We need to try for 1.4 first for proper PCI domain support
1116fe517fc9Smrg             * and if that fails, we know the kernel is busted
1117fe517fc9Smrg             */
1118fe517fc9Smrg            sv.drm_di_major = 1;
1119fe517fc9Smrg            sv.drm_di_minor = 4;
1120fe517fc9Smrg            sv.drm_dd_major = -1;        /* Don't care */
1121fe517fc9Smrg            sv.drm_dd_minor = -1;        /* Don't care */
1122fe517fc9Smrg            if (drmSetInterfaceVersion(fd, &sv)) {
11236d98c517Smrg#ifndef __alpha__
1124fe517fc9Smrg                pci_domain_ok = 0;
11256d98c517Smrg#endif
1126fe517fc9Smrg                sv.drm_di_major = 1;
1127fe517fc9Smrg                sv.drm_di_minor = 1;
1128fe517fc9Smrg                sv.drm_dd_major = -1;       /* Don't care */
1129fe517fc9Smrg                sv.drm_dd_minor = -1;       /* Don't care */
1130fe517fc9Smrg                drmMsg("drmOpenByBusid: Interface 1.4 failed, trying 1.1\n");
1131fe517fc9Smrg                drmSetInterfaceVersion(fd, &sv);
1132fe517fc9Smrg            }
1133fe517fc9Smrg            buf = drmGetBusid(fd);
1134fe517fc9Smrg            drmMsg("drmOpenByBusid: drmGetBusid reports %s\n", buf);
1135fe517fc9Smrg            if (buf && drmMatchBusID(buf, busid, pci_domain_ok)) {
1136fe517fc9Smrg                drmFreeBusid(buf);
1137fe517fc9Smrg                return fd;
1138fe517fc9Smrg            }
1139fe517fc9Smrg            if (buf)
1140fe517fc9Smrg                drmFreeBusid(buf);
1141fe517fc9Smrg            close(fd);
1142fe517fc9Smrg        }
114322944501Smrg    }
114422944501Smrg    return -1;
114522944501Smrg}
114622944501Smrg
114722944501Smrg
114822944501Smrg/**
114922944501Smrg * Open the device by name.
115022944501Smrg *
115122944501Smrg * \param name driver name.
1152424e9256Smrg * \param type the device node type.
1153fe517fc9Smrg *
115422944501Smrg * \return a file descriptor on success, or a negative value on error.
1155fe517fc9Smrg *
115622944501Smrg * \internal
115722944501Smrg * This function opens the first minor number that matches the driver name and
115822944501Smrg * isn't already in use.  If it's in use it then it will already have a bus ID
115922944501Smrg * assigned.
1160fe517fc9Smrg *
116122944501Smrg * \sa drmOpenMinor(), drmGetVersion() and drmGetBusid().
116222944501Smrg */
1163424e9256Smrgstatic int drmOpenByName(const char *name, int type)
116422944501Smrg{
116522944501Smrg    int           i;
116622944501Smrg    int           fd;
116722944501Smrg    drmVersionPtr version;
116822944501Smrg    char *        id;
1169424e9256Smrg    int           base = drmGetMinorBase(type);
1170424e9256Smrg
1171424e9256Smrg    if (base < 0)
1172424e9256Smrg        return -1;
117322944501Smrg
117422944501Smrg    /*
117522944501Smrg     * Open the first minor number that matches the driver name and isn't
117622944501Smrg     * already in use.  If it's in use it will have a busid assigned already.
117722944501Smrg     */
1178424e9256Smrg    for (i = base; i < base + DRM_MAX_MINOR; i++) {
1179fe517fc9Smrg        if ((fd = drmOpenMinor(i, 1, type)) >= 0) {
1180fe517fc9Smrg            if ((version = drmGetVersion(fd))) {
1181fe517fc9Smrg                if (!strcmp(version->name, name)) {
1182fe517fc9Smrg                    drmFreeVersion(version);
1183fe517fc9Smrg                    id = drmGetBusid(fd);
1184fe517fc9Smrg                    drmMsg("drmGetBusid returned '%s'\n", id ? id : "NULL");
1185fe517fc9Smrg                    if (!id || !*id) {
1186fe517fc9Smrg                        if (id)
1187fe517fc9Smrg                            drmFreeBusid(id);
1188fe517fc9Smrg                        return fd;
1189fe517fc9Smrg                    } else {
1190fe517fc9Smrg                        drmFreeBusid(id);
1191fe517fc9Smrg                    }
1192fe517fc9Smrg                } else {
1193fe517fc9Smrg                    drmFreeVersion(version);
1194fe517fc9Smrg                }
1195fe517fc9Smrg            }
1196fe517fc9Smrg            close(fd);
1197fe517fc9Smrg        }
119822944501Smrg    }
119922944501Smrg
120022944501Smrg#ifdef __linux__
120122944501Smrg    /* Backward-compatibility /proc support */
120222944501Smrg    for (i = 0; i < 8; i++) {
1203fe517fc9Smrg        char proc_name[64], buf[512];
1204fe517fc9Smrg        char *driver, *pt, *devstring;
1205fe517fc9Smrg        int  retcode;
1206fe517fc9Smrg
1207fe517fc9Smrg        sprintf(proc_name, "/proc/dri/%d/name", i);
12083b115362Smrg        if ((fd = open(proc_name, O_RDONLY)) >= 0) {
1209fe517fc9Smrg            retcode = read(fd, buf, sizeof(buf)-1);
1210fe517fc9Smrg            close(fd);
1211fe517fc9Smrg            if (retcode) {
1212fe517fc9Smrg                buf[retcode-1] = '\0';
1213fe517fc9Smrg                for (driver = pt = buf; *pt && *pt != ' '; ++pt)
1214fe517fc9Smrg                    ;
1215fe517fc9Smrg                if (*pt) { /* Device is next */
1216fe517fc9Smrg                    *pt = '\0';
1217fe517fc9Smrg                    if (!strcmp(driver, name)) { /* Match */
1218fe517fc9Smrg                        for (devstring = ++pt; *pt && *pt != ' '; ++pt)
1219fe517fc9Smrg                            ;
1220fe517fc9Smrg                        if (*pt) { /* Found busid */
1221fe517fc9Smrg                            return drmOpenByBusid(++pt, type);
1222fe517fc9Smrg                        } else { /* No busid */
1223fe517fc9Smrg                            return drmOpenDevice(strtol(devstring, NULL, 0),i, type);
1224fe517fc9Smrg                        }
1225fe517fc9Smrg                    }
1226fe517fc9Smrg                }
1227fe517fc9Smrg            }
1228fe517fc9Smrg        }
122922944501Smrg    }
123022944501Smrg#endif
123122944501Smrg
123222944501Smrg    return -1;
123322944501Smrg}
123422944501Smrg
123522944501Smrg
123622944501Smrg/**
123722944501Smrg * Open the DRM device.
123822944501Smrg *
123922944501Smrg * Looks up the specified name and bus ID, and opens the device found.  The
124022944501Smrg * entry in /dev/dri is created if necessary and if called by root.
124122944501Smrg *
124222944501Smrg * \param name driver name. Not referenced if bus ID is supplied.
124322944501Smrg * \param busid bus ID. Zero if not known.
1244fe517fc9Smrg *
124522944501Smrg * \return a file descriptor on success, or a negative value on error.
1246fe517fc9Smrg *
124722944501Smrg * \internal
124822944501Smrg * It calls drmOpenByBusid() if \p busid is specified or drmOpenByName()
124922944501Smrg * otherwise.
125022944501Smrg */
12516260e5d5Smrgdrm_public int drmOpen(const char *name, const char *busid)
1252424e9256Smrg{
1253424e9256Smrg    return drmOpenWithType(name, busid, DRM_NODE_PRIMARY);
1254424e9256Smrg}
1255424e9256Smrg
1256424e9256Smrg/**
1257424e9256Smrg * Open the DRM device with specified type.
1258424e9256Smrg *
1259424e9256Smrg * Looks up the specified name and bus ID, and opens the device found.  The
1260424e9256Smrg * entry in /dev/dri is created if necessary and if called by root.
1261424e9256Smrg *
1262424e9256Smrg * \param name driver name. Not referenced if bus ID is supplied.
1263424e9256Smrg * \param busid bus ID. Zero if not known.
126448246ce7Smrg * \param type the device node type to open, PRIMARY or RENDER
1265424e9256Smrg *
1266424e9256Smrg * \return a file descriptor on success, or a negative value on error.
1267424e9256Smrg *
1268424e9256Smrg * \internal
1269424e9256Smrg * It calls drmOpenByBusid() if \p busid is specified or drmOpenByName()
1270424e9256Smrg * otherwise.
1271424e9256Smrg */
12726260e5d5Smrgdrm_public int drmOpenWithType(const char *name, const char *busid, int type)
127322944501Smrg{
1274bf6cc7dcSmrg    if (name != NULL && drm_server_info &&
1275bf6cc7dcSmrg        drm_server_info->load_module && !drmAvailable()) {
1276fe517fc9Smrg        /* try to load the kernel module */
1277fe517fc9Smrg        if (!drm_server_info->load_module(name)) {
1278fe517fc9Smrg            drmMsg("[drm] failed to load kernel module \"%s\"\n", name);
1279fe517fc9Smrg            return -1;
1280fe517fc9Smrg        }
128122944501Smrg    }
128222944501Smrg
128322944501Smrg    if (busid) {
1284fe517fc9Smrg        int fd = drmOpenByBusid(busid, type);
1285fe517fc9Smrg        if (fd >= 0)
1286fe517fc9Smrg            return fd;
128722944501Smrg    }
1288fe517fc9Smrg
128922944501Smrg    if (name)
1290fe517fc9Smrg        return drmOpenByName(name, type);
129122944501Smrg
129222944501Smrg    return -1;
129322944501Smrg}
129422944501Smrg
12956260e5d5Smrgdrm_public int drmOpenControl(int minor)
129622944501Smrg{
129748246ce7Smrg    return -EINVAL;
129822944501Smrg}
129922944501Smrg
13006260e5d5Smrgdrm_public int drmOpenRender(int minor)
1301424e9256Smrg{
1302424e9256Smrg    return drmOpenMinor(minor, 0, DRM_NODE_RENDER);
1303424e9256Smrg}
1304424e9256Smrg
130522944501Smrg/**
130622944501Smrg * Free the version information returned by drmGetVersion().
130722944501Smrg *
130822944501Smrg * \param v pointer to the version information.
130922944501Smrg *
131022944501Smrg * \internal
131122944501Smrg * It frees the memory pointed by \p %v as well as all the non-null strings
131222944501Smrg * pointers in it.
131322944501Smrg */
13146260e5d5Smrgdrm_public void drmFreeVersion(drmVersionPtr v)
131522944501Smrg{
131622944501Smrg    if (!v)
1317fe517fc9Smrg        return;
131822944501Smrg    drmFree(v->name);
131922944501Smrg    drmFree(v->date);
132022944501Smrg    drmFree(v->desc);
132122944501Smrg    drmFree(v);
132222944501Smrg}
132322944501Smrg
132422944501Smrg
132522944501Smrg/**
132622944501Smrg * Free the non-public version information returned by the kernel.
132722944501Smrg *
132822944501Smrg * \param v pointer to the version information.
132922944501Smrg *
133022944501Smrg * \internal
133122944501Smrg * Used by drmGetVersion() to free the memory pointed by \p %v as well as all
133222944501Smrg * the non-null strings pointers in it.
133322944501Smrg */
133422944501Smrgstatic void drmFreeKernelVersion(drm_version_t *v)
133522944501Smrg{
133622944501Smrg    if (!v)
1337fe517fc9Smrg        return;
133822944501Smrg    drmFree(v->name);
133922944501Smrg    drmFree(v->date);
134022944501Smrg    drmFree(v->desc);
134122944501Smrg    drmFree(v);
134222944501Smrg}
134322944501Smrg
134422944501Smrg
134522944501Smrg/**
134622944501Smrg * Copy version information.
1347fe517fc9Smrg *
134822944501Smrg * \param d destination pointer.
134922944501Smrg * \param s source pointer.
1350fe517fc9Smrg *
135122944501Smrg * \internal
135222944501Smrg * Used by drmGetVersion() to translate the information returned by the ioctl
135322944501Smrg * interface in a private structure into the public structure counterpart.
135422944501Smrg */
135522944501Smrgstatic void drmCopyVersion(drmVersionPtr d, const drm_version_t *s)
135622944501Smrg{
135722944501Smrg    d->version_major      = s->version_major;
135822944501Smrg    d->version_minor      = s->version_minor;
135922944501Smrg    d->version_patchlevel = s->version_patchlevel;
136022944501Smrg    d->name_len           = s->name_len;
13619ce4edccSmrg    d->name               = strdup(s->name);
136222944501Smrg    d->date_len           = s->date_len;
13639ce4edccSmrg    d->date               = strdup(s->date);
136422944501Smrg    d->desc_len           = s->desc_len;
13659ce4edccSmrg    d->desc               = strdup(s->desc);
136622944501Smrg}
136722944501Smrg
136822944501Smrg
136922944501Smrg/**
137022944501Smrg * Query the driver version information.
137122944501Smrg *
137222944501Smrg * \param fd file descriptor.
1373fe517fc9Smrg *
137422944501Smrg * \return pointer to a drmVersion structure which should be freed with
137522944501Smrg * drmFreeVersion().
1376fe517fc9Smrg *
137722944501Smrg * \note Similar information is available via /proc/dri.
1378fe517fc9Smrg *
137922944501Smrg * \internal
138022944501Smrg * It gets the version information via successive DRM_IOCTL_VERSION ioctls,
138122944501Smrg * first with zeros to get the string lengths, and then the actually strings.
138222944501Smrg * It also null-terminates them since they might not be already.
138322944501Smrg */
13846260e5d5Smrgdrm_public drmVersionPtr drmGetVersion(int fd)
138522944501Smrg{
138622944501Smrg    drmVersionPtr retval;
138722944501Smrg    drm_version_t *version = drmMalloc(sizeof(*version));
138822944501Smrg
138922944501Smrg    if (drmIoctl(fd, DRM_IOCTL_VERSION, version)) {
1390fe517fc9Smrg        drmFreeKernelVersion(version);
1391fe517fc9Smrg        return NULL;
139222944501Smrg    }
139322944501Smrg
139422944501Smrg    if (version->name_len)
1395fe517fc9Smrg        version->name    = drmMalloc(version->name_len + 1);
139622944501Smrg    if (version->date_len)
1397fe517fc9Smrg        version->date    = drmMalloc(version->date_len + 1);
139822944501Smrg    if (version->desc_len)
1399fe517fc9Smrg        version->desc    = drmMalloc(version->desc_len + 1);
140022944501Smrg
140122944501Smrg    if (drmIoctl(fd, DRM_IOCTL_VERSION, version)) {
1402fe517fc9Smrg        drmMsg("DRM_IOCTL_VERSION: %s\n", strerror(errno));
1403fe517fc9Smrg        drmFreeKernelVersion(version);
1404fe517fc9Smrg        return NULL;
140522944501Smrg    }
140622944501Smrg
140722944501Smrg    /* The results might not be null-terminated strings, so terminate them. */
140822944501Smrg    if (version->name_len) version->name[version->name_len] = '\0';
140922944501Smrg    if (version->date_len) version->date[version->date_len] = '\0';
141022944501Smrg    if (version->desc_len) version->desc[version->desc_len] = '\0';
141122944501Smrg
141222944501Smrg    retval = drmMalloc(sizeof(*retval));
141322944501Smrg    drmCopyVersion(retval, version);
141422944501Smrg    drmFreeKernelVersion(version);
141522944501Smrg    return retval;
141622944501Smrg}
141722944501Smrg
141822944501Smrg
141922944501Smrg/**
142022944501Smrg * Get version information for the DRM user space library.
1421fe517fc9Smrg *
142222944501Smrg * This version number is driver independent.
1423fe517fc9Smrg *
142422944501Smrg * \param fd file descriptor.
142522944501Smrg *
142622944501Smrg * \return version information.
1427fe517fc9Smrg *
142822944501Smrg * \internal
142922944501Smrg * This function allocates and fills a drm_version structure with a hard coded
143022944501Smrg * version number.
143122944501Smrg */
14326260e5d5Smrgdrm_public drmVersionPtr drmGetLibVersion(int fd)
143322944501Smrg{
143422944501Smrg    drm_version_t *version = drmMalloc(sizeof(*version));
143522944501Smrg
143622944501Smrg    /* Version history:
143722944501Smrg     *   NOTE THIS MUST NOT GO ABOVE VERSION 1.X due to drivers needing it
143822944501Smrg     *   revision 1.0.x = original DRM interface with no drmGetLibVersion
143922944501Smrg     *                    entry point and many drm<Device> extensions
144022944501Smrg     *   revision 1.1.x = added drmCommand entry points for device extensions
144122944501Smrg     *                    added drmGetLibVersion to identify libdrm.a version
144222944501Smrg     *   revision 1.2.x = added drmSetInterfaceVersion
144322944501Smrg     *                    modified drmOpen to handle both busid and name
144422944501Smrg     *   revision 1.3.x = added server + memory manager
144522944501Smrg     */
144622944501Smrg    version->version_major      = 1;
144722944501Smrg    version->version_minor      = 3;
144822944501Smrg    version->version_patchlevel = 0;
144922944501Smrg
145022944501Smrg    return (drmVersionPtr)version;
145122944501Smrg}
145222944501Smrg
14536260e5d5Smrgdrm_public int drmGetCap(int fd, uint64_t capability, uint64_t *value)
145420131375Smrg{
1455fe517fc9Smrg    struct drm_get_cap cap;
1456fe517fc9Smrg    int ret;
145720131375Smrg
1458fe517fc9Smrg    memclear(cap);
1459fe517fc9Smrg    cap.capability = capability;
1460424e9256Smrg
1461fe517fc9Smrg    ret = drmIoctl(fd, DRM_IOCTL_GET_CAP, &cap);
1462fe517fc9Smrg    if (ret)
1463fe517fc9Smrg        return ret;
146420131375Smrg
1465fe517fc9Smrg    *value = cap.value;
1466fe517fc9Smrg    return 0;
146720131375Smrg}
146820131375Smrg
14696260e5d5Smrgdrm_public int drmSetClientCap(int fd, uint64_t capability, uint64_t value)
147020131375Smrg{
1471fe517fc9Smrg    struct drm_set_client_cap cap;
1472424e9256Smrg
1473fe517fc9Smrg    memclear(cap);
1474fe517fc9Smrg    cap.capability = capability;
1475fe517fc9Smrg    cap.value = value;
147620131375Smrg
1477fe517fc9Smrg    return drmIoctl(fd, DRM_IOCTL_SET_CLIENT_CAP, &cap);
147820131375Smrg}
147922944501Smrg
148022944501Smrg/**
148122944501Smrg * Free the bus ID information.
148222944501Smrg *
148322944501Smrg * \param busid bus ID information string as given by drmGetBusid().
148422944501Smrg *
148522944501Smrg * \internal
148622944501Smrg * This function is just frees the memory pointed by \p busid.
148722944501Smrg */
14886260e5d5Smrgdrm_public void drmFreeBusid(const char *busid)
148922944501Smrg{
149022944501Smrg    drmFree((void *)busid);
149122944501Smrg}
149222944501Smrg
149322944501Smrg
149422944501Smrg/**
149522944501Smrg * Get the bus ID of the device.
149622944501Smrg *
149722944501Smrg * \param fd file descriptor.
149822944501Smrg *
149922944501Smrg * \return bus ID string.
150022944501Smrg *
150122944501Smrg * \internal
150222944501Smrg * This function gets the bus ID via successive DRM_IOCTL_GET_UNIQUE ioctls to
150322944501Smrg * get the string length and data, passing the arguments in a drm_unique
150422944501Smrg * structure.
150522944501Smrg */
15066260e5d5Smrgdrm_public char *drmGetBusid(int fd)
150722944501Smrg{
150822944501Smrg    drm_unique_t u;
150922944501Smrg
1510424e9256Smrg    memclear(u);
151122944501Smrg
151222944501Smrg    if (drmIoctl(fd, DRM_IOCTL_GET_UNIQUE, &u))
1513fe517fc9Smrg        return NULL;
151422944501Smrg    u.unique = drmMalloc(u.unique_len + 1);
15150655efefSmrg    if (drmIoctl(fd, DRM_IOCTL_GET_UNIQUE, &u)) {
15160655efefSmrg        drmFree(u.unique);
1517fe517fc9Smrg        return NULL;
15180655efefSmrg    }
151922944501Smrg    u.unique[u.unique_len] = '\0';
152022944501Smrg
152122944501Smrg    return u.unique;
152222944501Smrg}
152322944501Smrg
152422944501Smrg
152522944501Smrg/**
152622944501Smrg * Set the bus ID of the device.
152722944501Smrg *
152822944501Smrg * \param fd file descriptor.
152922944501Smrg * \param busid bus ID string.
153022944501Smrg *
153122944501Smrg * \return zero on success, negative on failure.
153222944501Smrg *
153322944501Smrg * \internal
153422944501Smrg * This function is a wrapper around the DRM_IOCTL_SET_UNIQUE ioctl, passing
153522944501Smrg * the arguments in a drm_unique structure.
153622944501Smrg */
15376260e5d5Smrgdrm_public int drmSetBusid(int fd, const char *busid)
153822944501Smrg{
153922944501Smrg    drm_unique_t u;
154022944501Smrg
1541424e9256Smrg    memclear(u);
154222944501Smrg    u.unique     = (char *)busid;
154322944501Smrg    u.unique_len = strlen(busid);
154422944501Smrg
154522944501Smrg    if (drmIoctl(fd, DRM_IOCTL_SET_UNIQUE, &u)) {
1546fe517fc9Smrg        return -errno;
154722944501Smrg    }
154822944501Smrg    return 0;
154922944501Smrg}
155022944501Smrg
15516260e5d5Smrgdrm_public int drmGetMagic(int fd, drm_magic_t * magic)
155222944501Smrg{
155322944501Smrg    drm_auth_t auth;
155422944501Smrg
1555424e9256Smrg    memclear(auth);
1556424e9256Smrg
155722944501Smrg    *magic = 0;
155822944501Smrg    if (drmIoctl(fd, DRM_IOCTL_GET_MAGIC, &auth))
1559fe517fc9Smrg        return -errno;
156022944501Smrg    *magic = auth.magic;
156122944501Smrg    return 0;
156222944501Smrg}
156322944501Smrg
15646260e5d5Smrgdrm_public int drmAuthMagic(int fd, drm_magic_t magic)
156522944501Smrg{
156622944501Smrg    drm_auth_t auth;
156722944501Smrg
1568424e9256Smrg    memclear(auth);
156922944501Smrg    auth.magic = magic;
157022944501Smrg    if (drmIoctl(fd, DRM_IOCTL_AUTH_MAGIC, &auth))
1571fe517fc9Smrg        return -errno;
157222944501Smrg    return 0;
157322944501Smrg}
157422944501Smrg
157522944501Smrg/**
157622944501Smrg * Specifies a range of memory that is available for mapping by a
157722944501Smrg * non-root process.
157822944501Smrg *
157922944501Smrg * \param fd file descriptor.
158022944501Smrg * \param offset usually the physical address. The actual meaning depends of
158122944501Smrg * the \p type parameter. See below.
158222944501Smrg * \param size of the memory in bytes.
158322944501Smrg * \param type type of the memory to be mapped.
158422944501Smrg * \param flags combination of several flags to modify the function actions.
158522944501Smrg * \param handle will be set to a value that may be used as the offset
158622944501Smrg * parameter for mmap().
1587fe517fc9Smrg *
158822944501Smrg * \return zero on success or a negative value on error.
158922944501Smrg *
159022944501Smrg * \par Mapping the frame buffer
159122944501Smrg * For the frame buffer
159222944501Smrg * - \p offset will be the physical address of the start of the frame buffer,
159322944501Smrg * - \p size will be the size of the frame buffer in bytes, and
159422944501Smrg * - \p type will be DRM_FRAME_BUFFER.
159522944501Smrg *
159622944501Smrg * \par
159722944501Smrg * The area mapped will be uncached. If MTRR support is available in the
1598fe517fc9Smrg * kernel, the frame buffer area will be set to write combining.
159922944501Smrg *
160022944501Smrg * \par Mapping the MMIO register area
160122944501Smrg * For the MMIO register area,
160222944501Smrg * - \p offset will be the physical address of the start of the register area,
160322944501Smrg * - \p size will be the size of the register area bytes, and
160422944501Smrg * - \p type will be DRM_REGISTERS.
160522944501Smrg * \par
1606fe517fc9Smrg * The area mapped will be uncached.
1607fe517fc9Smrg *
160822944501Smrg * \par Mapping the SAREA
160922944501Smrg * For the SAREA,
161022944501Smrg * - \p offset will be ignored and should be set to zero,
161122944501Smrg * - \p size will be the desired size of the SAREA in bytes,
161222944501Smrg * - \p type will be DRM_SHM.
1613fe517fc9Smrg *
161422944501Smrg * \par
161522944501Smrg * A shared memory area of the requested size will be created and locked in
161622944501Smrg * kernel memory. This area may be mapped into client-space by using the handle
1617fe517fc9Smrg * returned.
1618fe517fc9Smrg *
161922944501Smrg * \note May only be called by root.
162022944501Smrg *
162122944501Smrg * \internal
162222944501Smrg * This function is a wrapper around the DRM_IOCTL_ADD_MAP ioctl, passing
162322944501Smrg * the arguments in a drm_map structure.
162422944501Smrg */
16256260e5d5Smrgdrm_public int drmAddMap(int fd, drm_handle_t offset, drmSize size, drmMapType type,
16266260e5d5Smrg                         drmMapFlags flags, drm_handle_t *handle)
162722944501Smrg{
162822944501Smrg    drm_map_t map;
162922944501Smrg
1630424e9256Smrg    memclear(map);
163122944501Smrg    map.offset  = offset;
163222944501Smrg    map.size    = size;
1633adfa0b0cSmrg    map.type    = (enum drm_map_type)type;
1634adfa0b0cSmrg    map.flags   = (enum drm_map_flags)flags;
163522944501Smrg    if (drmIoctl(fd, DRM_IOCTL_ADD_MAP, &map))
1636fe517fc9Smrg        return -errno;
163722944501Smrg    if (handle)
1638fe517fc9Smrg        *handle = (drm_handle_t)(uintptr_t)map.handle;
163922944501Smrg    return 0;
164022944501Smrg}
164122944501Smrg
16426260e5d5Smrgdrm_public int drmRmMap(int fd, drm_handle_t handle)
164322944501Smrg{
164422944501Smrg    drm_map_t map;
164522944501Smrg
1646424e9256Smrg    memclear(map);
164720131375Smrg    map.handle = (void *)(uintptr_t)handle;
164822944501Smrg
164922944501Smrg    if(drmIoctl(fd, DRM_IOCTL_RM_MAP, &map))
1650fe517fc9Smrg        return -errno;
165122944501Smrg    return 0;
165222944501Smrg}
165322944501Smrg
165422944501Smrg/**
165522944501Smrg * Make buffers available for DMA transfers.
1656fe517fc9Smrg *
165722944501Smrg * \param fd file descriptor.
165822944501Smrg * \param count number of buffers.
165922944501Smrg * \param size size of each buffer.
166022944501Smrg * \param flags buffer allocation flags.
1661fe517fc9Smrg * \param agp_offset offset in the AGP aperture
166222944501Smrg *
166322944501Smrg * \return number of buffers allocated, negative on error.
166422944501Smrg *
166522944501Smrg * \internal
166622944501Smrg * This function is a wrapper around DRM_IOCTL_ADD_BUFS ioctl.
166722944501Smrg *
166822944501Smrg * \sa drm_buf_desc.
166922944501Smrg */
16706260e5d5Smrgdrm_public int drmAddBufs(int fd, int count, int size, drmBufDescFlags flags,
16716260e5d5Smrg                          int agp_offset)
167222944501Smrg{
167322944501Smrg    drm_buf_desc_t request;
167422944501Smrg
1675424e9256Smrg    memclear(request);
167622944501Smrg    request.count     = count;
167722944501Smrg    request.size      = size;
1678adfa0b0cSmrg    request.flags     = (int)flags;
167922944501Smrg    request.agp_start = agp_offset;
168022944501Smrg
168122944501Smrg    if (drmIoctl(fd, DRM_IOCTL_ADD_BUFS, &request))
1682fe517fc9Smrg        return -errno;
168322944501Smrg    return request.count;
168422944501Smrg}
168522944501Smrg
16866260e5d5Smrgdrm_public int drmMarkBufs(int fd, double low, double high)
168722944501Smrg{
168822944501Smrg    drm_buf_info_t info;
168922944501Smrg    int            i;
169022944501Smrg
1691424e9256Smrg    memclear(info);
169222944501Smrg
169322944501Smrg    if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info))
1694fe517fc9Smrg        return -EINVAL;
169522944501Smrg
169622944501Smrg    if (!info.count)
1697fe517fc9Smrg        return -EINVAL;
169822944501Smrg
169922944501Smrg    if (!(info.list = drmMalloc(info.count * sizeof(*info.list))))
1700fe517fc9Smrg        return -ENOMEM;
170122944501Smrg
170222944501Smrg    if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info)) {
1703fe517fc9Smrg        int retval = -errno;
1704fe517fc9Smrg        drmFree(info.list);
1705fe517fc9Smrg        return retval;
170622944501Smrg    }
170722944501Smrg
170822944501Smrg    for (i = 0; i < info.count; i++) {
1709fe517fc9Smrg        info.list[i].low_mark  = low  * info.list[i].count;
1710fe517fc9Smrg        info.list[i].high_mark = high * info.list[i].count;
1711fe517fc9Smrg        if (drmIoctl(fd, DRM_IOCTL_MARK_BUFS, &info.list[i])) {
1712fe517fc9Smrg            int retval = -errno;
1713fe517fc9Smrg            drmFree(info.list);
1714fe517fc9Smrg            return retval;
1715fe517fc9Smrg        }
171622944501Smrg    }
171722944501Smrg    drmFree(info.list);
171822944501Smrg
171922944501Smrg    return 0;
172022944501Smrg}
172122944501Smrg
172222944501Smrg/**
172322944501Smrg * Free buffers.
172422944501Smrg *
172522944501Smrg * \param fd file descriptor.
172622944501Smrg * \param count number of buffers to free.
172722944501Smrg * \param list list of buffers to be freed.
172822944501Smrg *
172922944501Smrg * \return zero on success, or a negative value on failure.
1730fe517fc9Smrg *
173122944501Smrg * \note This function is primarily used for debugging.
1732fe517fc9Smrg *
173322944501Smrg * \internal
173422944501Smrg * This function is a wrapper around the DRM_IOCTL_FREE_BUFS ioctl, passing
173522944501Smrg * the arguments in a drm_buf_free structure.
173622944501Smrg */
17376260e5d5Smrgdrm_public int drmFreeBufs(int fd, int count, int *list)
173822944501Smrg{
173922944501Smrg    drm_buf_free_t request;
174022944501Smrg
1741424e9256Smrg    memclear(request);
174222944501Smrg    request.count = count;
174322944501Smrg    request.list  = list;
174422944501Smrg    if (drmIoctl(fd, DRM_IOCTL_FREE_BUFS, &request))
1745fe517fc9Smrg        return -errno;
174622944501Smrg    return 0;
174722944501Smrg}
174822944501Smrg
174922944501Smrg
175022944501Smrg/**
175122944501Smrg * Close the device.
175222944501Smrg *
175322944501Smrg * \param fd file descriptor.
175422944501Smrg *
175522944501Smrg * \internal
175622944501Smrg * This function closes the file descriptor.
175722944501Smrg */
17586260e5d5Smrgdrm_public int drmClose(int fd)
175922944501Smrg{
176022944501Smrg    unsigned long key    = drmGetKeyFromFd(fd);
176122944501Smrg    drmHashEntry  *entry = drmGetEntry(fd);
176222944501Smrg
176322944501Smrg    drmHashDestroy(entry->tagTable);
176422944501Smrg    entry->fd       = 0;
176522944501Smrg    entry->f        = NULL;
176622944501Smrg    entry->tagTable = NULL;
176722944501Smrg
176822944501Smrg    drmHashDelete(drmHashTable, key);
176922944501Smrg    drmFree(entry);
177022944501Smrg
177122944501Smrg    return close(fd);
177222944501Smrg}
177322944501Smrg
177422944501Smrg
177522944501Smrg/**
177622944501Smrg * Map a region of memory.
177722944501Smrg *
177822944501Smrg * \param fd file descriptor.
177922944501Smrg * \param handle handle returned by drmAddMap().
178022944501Smrg * \param size size in bytes. Must match the size used by drmAddMap().
178122944501Smrg * \param address will contain the user-space virtual address where the mapping
178222944501Smrg * begins.
178322944501Smrg *
178422944501Smrg * \return zero on success, or a negative value on failure.
1785fe517fc9Smrg *
178622944501Smrg * \internal
178722944501Smrg * This function is a wrapper for mmap().
178822944501Smrg */
17896260e5d5Smrgdrm_public int drmMap(int fd, drm_handle_t handle, drmSize size,
17906260e5d5Smrg                      drmAddressPtr address)
179122944501Smrg{
179222944501Smrg    static unsigned long pagesize_mask = 0;
179322944501Smrg
179422944501Smrg    if (fd < 0)
1795fe517fc9Smrg        return -EINVAL;
179622944501Smrg
179722944501Smrg    if (!pagesize_mask)
1798fe517fc9Smrg        pagesize_mask = getpagesize() - 1;
179922944501Smrg
180022944501Smrg    size = (size + pagesize_mask) & ~pagesize_mask;
180122944501Smrg
1802a884aba1Smrg    *address = drm_mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, handle);
180322944501Smrg    if (*address == MAP_FAILED)
1804fe517fc9Smrg        return -errno;
180522944501Smrg    return 0;
180622944501Smrg}
180722944501Smrg
180822944501Smrg
180922944501Smrg/**
181022944501Smrg * Unmap mappings obtained with drmMap().
181122944501Smrg *
181222944501Smrg * \param address address as given by drmMap().
181322944501Smrg * \param size size in bytes. Must match the size used by drmMap().
1814fe517fc9Smrg *
181522944501Smrg * \return zero on success, or a negative value on failure.
181622944501Smrg *
181722944501Smrg * \internal
181822944501Smrg * This function is a wrapper for munmap().
181922944501Smrg */
18206260e5d5Smrgdrm_public int drmUnmap(drmAddress address, drmSize size)
182122944501Smrg{
1822a884aba1Smrg    return drm_munmap(address, size);
182322944501Smrg}
182422944501Smrg
18256260e5d5Smrgdrm_public drmBufInfoPtr drmGetBufInfo(int fd)
182622944501Smrg{
182722944501Smrg    drm_buf_info_t info;
182822944501Smrg    drmBufInfoPtr  retval;
182922944501Smrg    int            i;
183022944501Smrg
1831424e9256Smrg    memclear(info);
183222944501Smrg
183322944501Smrg    if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info))
1834fe517fc9Smrg        return NULL;
183522944501Smrg
183622944501Smrg    if (info.count) {
1837fe517fc9Smrg        if (!(info.list = drmMalloc(info.count * sizeof(*info.list))))
1838fe517fc9Smrg            return NULL;
1839fe517fc9Smrg
1840fe517fc9Smrg        if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info)) {
1841fe517fc9Smrg            drmFree(info.list);
1842fe517fc9Smrg            return NULL;
1843fe517fc9Smrg        }
1844fe517fc9Smrg
1845fe517fc9Smrg        retval = drmMalloc(sizeof(*retval));
1846fe517fc9Smrg        retval->count = info.count;
18474b3d3f37Smrg        if (!(retval->list = drmMalloc(info.count * sizeof(*retval->list)))) {
18484b3d3f37Smrg                drmFree(retval);
18494b3d3f37Smrg                drmFree(info.list);
18504b3d3f37Smrg                return NULL;
18514b3d3f37Smrg        }
18524b3d3f37Smrg
1853fe517fc9Smrg        for (i = 0; i < info.count; i++) {
1854fe517fc9Smrg            retval->list[i].count     = info.list[i].count;
1855fe517fc9Smrg            retval->list[i].size      = info.list[i].size;
1856fe517fc9Smrg            retval->list[i].low_mark  = info.list[i].low_mark;
1857fe517fc9Smrg            retval->list[i].high_mark = info.list[i].high_mark;
1858fe517fc9Smrg        }
1859fe517fc9Smrg        drmFree(info.list);
1860fe517fc9Smrg        return retval;
186122944501Smrg    }
186222944501Smrg    return NULL;
186322944501Smrg}
186422944501Smrg
186522944501Smrg/**
186622944501Smrg * Map all DMA buffers into client-virtual space.
186722944501Smrg *
186822944501Smrg * \param fd file descriptor.
186922944501Smrg *
187022944501Smrg * \return a pointer to a ::drmBufMap structure.
187122944501Smrg *
187222944501Smrg * \note The client may not use these buffers until obtaining buffer indices
187322944501Smrg * with drmDMA().
1874fe517fc9Smrg *
187522944501Smrg * \internal
187622944501Smrg * This function calls the DRM_IOCTL_MAP_BUFS ioctl and copies the returned
187722944501Smrg * information about the buffers in a drm_buf_map structure into the
187822944501Smrg * client-visible data structures.
1879fe517fc9Smrg */
18806260e5d5Smrgdrm_public drmBufMapPtr drmMapBufs(int fd)
188122944501Smrg{
188222944501Smrg    drm_buf_map_t bufs;
188322944501Smrg    drmBufMapPtr  retval;
188422944501Smrg    int           i;
188522944501Smrg
1886424e9256Smrg    memclear(bufs);
188722944501Smrg    if (drmIoctl(fd, DRM_IOCTL_MAP_BUFS, &bufs))
1888fe517fc9Smrg        return NULL;
188922944501Smrg
189022944501Smrg    if (!bufs.count)
1891fe517fc9Smrg        return NULL;
189222944501Smrg
1893fe517fc9Smrg    if (!(bufs.list = drmMalloc(bufs.count * sizeof(*bufs.list))))
1894fe517fc9Smrg        return NULL;
189522944501Smrg
1896fe517fc9Smrg    if (drmIoctl(fd, DRM_IOCTL_MAP_BUFS, &bufs)) {
1897fe517fc9Smrg        drmFree(bufs.list);
1898fe517fc9Smrg        return NULL;
1899fe517fc9Smrg    }
190022944501Smrg
1901fe517fc9Smrg    retval = drmMalloc(sizeof(*retval));
1902fe517fc9Smrg    retval->count = bufs.count;
1903fe517fc9Smrg    retval->list  = drmMalloc(bufs.count * sizeof(*retval->list));
1904fe517fc9Smrg    for (i = 0; i < bufs.count; i++) {
1905fe517fc9Smrg        retval->list[i].idx     = bufs.list[i].idx;
1906fe517fc9Smrg        retval->list[i].total   = bufs.list[i].total;
1907fe517fc9Smrg        retval->list[i].used    = 0;
1908fe517fc9Smrg        retval->list[i].address = bufs.list[i].address;
1909fe517fc9Smrg    }
191022944501Smrg
1911fe517fc9Smrg    drmFree(bufs.list);
1912fe517fc9Smrg    return retval;
191322944501Smrg}
191422944501Smrg
191522944501Smrg
191622944501Smrg/**
191722944501Smrg * Unmap buffers allocated with drmMapBufs().
191822944501Smrg *
191922944501Smrg * \return zero on success, or negative value on failure.
192022944501Smrg *
192122944501Smrg * \internal
192222944501Smrg * Calls munmap() for every buffer stored in \p bufs and frees the
192322944501Smrg * memory allocated by drmMapBufs().
192422944501Smrg */
19256260e5d5Smrgdrm_public int drmUnmapBufs(drmBufMapPtr bufs)
192622944501Smrg{
192722944501Smrg    int i;
192822944501Smrg
192922944501Smrg    for (i = 0; i < bufs->count; i++) {
1930fe517fc9Smrg        drm_munmap(bufs->list[i].address, bufs->list[i].total);
193122944501Smrg    }
193222944501Smrg
193322944501Smrg    drmFree(bufs->list);
193422944501Smrg    drmFree(bufs);
193522944501Smrg    return 0;
193622944501Smrg}
193722944501Smrg
193822944501Smrg
1939fe517fc9Smrg#define DRM_DMA_RETRY  16
194022944501Smrg
194122944501Smrg/**
194222944501Smrg * Reserve DMA buffers.
194322944501Smrg *
194422944501Smrg * \param fd file descriptor.
1945fe517fc9Smrg * \param request
1946fe517fc9Smrg *
194722944501Smrg * \return zero on success, or a negative value on failure.
194822944501Smrg *
194922944501Smrg * \internal
195022944501Smrg * Assemble the arguments into a drm_dma structure and keeps issuing the
195122944501Smrg * DRM_IOCTL_DMA ioctl until success or until maximum number of retries.
195222944501Smrg */
19536260e5d5Smrgdrm_public int drmDMA(int fd, drmDMAReqPtr request)
195422944501Smrg{
195522944501Smrg    drm_dma_t dma;
195622944501Smrg    int ret, i = 0;
195722944501Smrg
195822944501Smrg    dma.context         = request->context;
195922944501Smrg    dma.send_count      = request->send_count;
196022944501Smrg    dma.send_indices    = request->send_list;
196122944501Smrg    dma.send_sizes      = request->send_sizes;
1962adfa0b0cSmrg    dma.flags           = (enum drm_dma_flags)request->flags;
196322944501Smrg    dma.request_count   = request->request_count;
196422944501Smrg    dma.request_size    = request->request_size;
196522944501Smrg    dma.request_indices = request->request_list;
196622944501Smrg    dma.request_sizes   = request->request_sizes;
196722944501Smrg    dma.granted_count   = 0;
196822944501Smrg
196922944501Smrg    do {
1970fe517fc9Smrg        ret = ioctl( fd, DRM_IOCTL_DMA, &dma );
197122944501Smrg    } while ( ret && errno == EAGAIN && i++ < DRM_DMA_RETRY );
197222944501Smrg
197322944501Smrg    if ( ret == 0 ) {
1974fe517fc9Smrg        request->granted_count = dma.granted_count;
1975fe517fc9Smrg        return 0;
197622944501Smrg    } else {
1977fe517fc9Smrg        return -errno;
197822944501Smrg    }
197922944501Smrg}
198022944501Smrg
198122944501Smrg
198222944501Smrg/**
198322944501Smrg * Obtain heavyweight hardware lock.
198422944501Smrg *
198522944501Smrg * \param fd file descriptor.
198622944501Smrg * \param context context.
1987bf6cc7dcSmrg * \param flags flags that determine the state of the hardware when the function
198822944501Smrg * returns.
1989fe517fc9Smrg *
199022944501Smrg * \return always zero.
1991fe517fc9Smrg *
199222944501Smrg * \internal
199322944501Smrg * This function translates the arguments into a drm_lock structure and issue
199422944501Smrg * the DRM_IOCTL_LOCK ioctl until the lock is successfully acquired.
199522944501Smrg */
19966260e5d5Smrgdrm_public int drmGetLock(int fd, drm_context_t context, drmLockFlags flags)
199722944501Smrg{
199822944501Smrg    drm_lock_t lock;
199922944501Smrg
2000424e9256Smrg    memclear(lock);
200122944501Smrg    lock.context = context;
200222944501Smrg    lock.flags   = 0;
200322944501Smrg    if (flags & DRM_LOCK_READY)      lock.flags |= _DRM_LOCK_READY;
200422944501Smrg    if (flags & DRM_LOCK_QUIESCENT)  lock.flags |= _DRM_LOCK_QUIESCENT;
200522944501Smrg    if (flags & DRM_LOCK_FLUSH)      lock.flags |= _DRM_LOCK_FLUSH;
200622944501Smrg    if (flags & DRM_LOCK_FLUSH_ALL)  lock.flags |= _DRM_LOCK_FLUSH_ALL;
200722944501Smrg    if (flags & DRM_HALT_ALL_QUEUES) lock.flags |= _DRM_HALT_ALL_QUEUES;
200822944501Smrg    if (flags & DRM_HALT_CUR_QUEUES) lock.flags |= _DRM_HALT_CUR_QUEUES;
200922944501Smrg
201022944501Smrg    while (drmIoctl(fd, DRM_IOCTL_LOCK, &lock))
2011fe517fc9Smrg        ;
201222944501Smrg    return 0;
201322944501Smrg}
201422944501Smrg
201522944501Smrg/**
201622944501Smrg * Release the hardware lock.
201722944501Smrg *
201822944501Smrg * \param fd file descriptor.
201922944501Smrg * \param context context.
2020fe517fc9Smrg *
202122944501Smrg * \return zero on success, or a negative value on failure.
2022fe517fc9Smrg *
202322944501Smrg * \internal
202422944501Smrg * This function is a wrapper around the DRM_IOCTL_UNLOCK ioctl, passing the
202522944501Smrg * argument in a drm_lock structure.
202622944501Smrg */
20276260e5d5Smrgdrm_public int drmUnlock(int fd, drm_context_t context)
202822944501Smrg{
202922944501Smrg    drm_lock_t lock;
203022944501Smrg
2031424e9256Smrg    memclear(lock);
203222944501Smrg    lock.context = context;
203322944501Smrg    return drmIoctl(fd, DRM_IOCTL_UNLOCK, &lock);
203422944501Smrg}
203522944501Smrg
20366260e5d5Smrgdrm_public drm_context_t *drmGetReservedContextList(int fd, int *count)
203722944501Smrg{
203822944501Smrg    drm_ctx_res_t res;
203922944501Smrg    drm_ctx_t     *list;
204022944501Smrg    drm_context_t * retval;
204122944501Smrg    int           i;
204222944501Smrg
2043424e9256Smrg    memclear(res);
204422944501Smrg    if (drmIoctl(fd, DRM_IOCTL_RES_CTX, &res))
2045fe517fc9Smrg        return NULL;
204622944501Smrg
204722944501Smrg    if (!res.count)
2048fe517fc9Smrg        return NULL;
204922944501Smrg
205022944501Smrg    if (!(list   = drmMalloc(res.count * sizeof(*list))))
2051fe517fc9Smrg        return NULL;
20520655efefSmrg    if (!(retval = drmMalloc(res.count * sizeof(*retval))))
20530655efefSmrg        goto err_free_list;
205422944501Smrg
205522944501Smrg    res.contexts = list;
205622944501Smrg    if (drmIoctl(fd, DRM_IOCTL_RES_CTX, &res))
20570655efefSmrg        goto err_free_context;
205822944501Smrg
205922944501Smrg    for (i = 0; i < res.count; i++)
2060fe517fc9Smrg        retval[i] = list[i].handle;
206122944501Smrg    drmFree(list);
206222944501Smrg
206322944501Smrg    *count = res.count;
206422944501Smrg    return retval;
20650655efefSmrg
20660655efefSmrgerr_free_list:
20670655efefSmrg    drmFree(list);
20680655efefSmrgerr_free_context:
20690655efefSmrg    drmFree(retval);
20700655efefSmrg    return NULL;
207122944501Smrg}
207222944501Smrg
20736260e5d5Smrgdrm_public void drmFreeReservedContextList(drm_context_t *pt)
207422944501Smrg{
207522944501Smrg    drmFree(pt);
207622944501Smrg}
207722944501Smrg
207822944501Smrg/**
207922944501Smrg * Create context.
208022944501Smrg *
208122944501Smrg * Used by the X server during GLXContext initialization. This causes
208222944501Smrg * per-context kernel-level resources to be allocated.
208322944501Smrg *
208422944501Smrg * \param fd file descriptor.
208522944501Smrg * \param handle is set on success. To be used by the client when requesting DMA
208622944501Smrg * dispatch with drmDMA().
2087fe517fc9Smrg *
208822944501Smrg * \return zero on success, or a negative value on failure.
2089fe517fc9Smrg *
209022944501Smrg * \note May only be called by root.
2091fe517fc9Smrg *
209222944501Smrg * \internal
209322944501Smrg * This function is a wrapper around the DRM_IOCTL_ADD_CTX ioctl, passing the
209422944501Smrg * argument in a drm_ctx structure.
209522944501Smrg */
20966260e5d5Smrgdrm_public int drmCreateContext(int fd, drm_context_t *handle)
209722944501Smrg{
209822944501Smrg    drm_ctx_t ctx;
209922944501Smrg
2100424e9256Smrg    memclear(ctx);
210122944501Smrg    if (drmIoctl(fd, DRM_IOCTL_ADD_CTX, &ctx))
2102fe517fc9Smrg        return -errno;
210322944501Smrg    *handle = ctx.handle;
210422944501Smrg    return 0;
210522944501Smrg}
210622944501Smrg
21076260e5d5Smrgdrm_public int drmSwitchToContext(int fd, drm_context_t context)
210822944501Smrg{
210922944501Smrg    drm_ctx_t ctx;
211022944501Smrg
2111424e9256Smrg    memclear(ctx);
211222944501Smrg    ctx.handle = context;
211322944501Smrg    if (drmIoctl(fd, DRM_IOCTL_SWITCH_CTX, &ctx))
2114fe517fc9Smrg        return -errno;
211522944501Smrg    return 0;
211622944501Smrg}
211722944501Smrg
21186260e5d5Smrgdrm_public int drmSetContextFlags(int fd, drm_context_t context,
21196260e5d5Smrg                                  drm_context_tFlags flags)
212022944501Smrg{
212122944501Smrg    drm_ctx_t ctx;
212222944501Smrg
212322944501Smrg    /*
212422944501Smrg     * Context preserving means that no context switches are done between DMA
212522944501Smrg     * buffers from one context and the next.  This is suitable for use in the
212622944501Smrg     * X server (which promises to maintain hardware context), or in the
212722944501Smrg     * client-side library when buffers are swapped on behalf of two threads.
212822944501Smrg     */
2129424e9256Smrg    memclear(ctx);
213022944501Smrg    ctx.handle = context;
213122944501Smrg    if (flags & DRM_CONTEXT_PRESERVED)
2132fe517fc9Smrg        ctx.flags |= _DRM_CONTEXT_PRESERVED;
213322944501Smrg    if (flags & DRM_CONTEXT_2DONLY)
2134fe517fc9Smrg        ctx.flags |= _DRM_CONTEXT_2DONLY;
213522944501Smrg    if (drmIoctl(fd, DRM_IOCTL_MOD_CTX, &ctx))
2136fe517fc9Smrg        return -errno;
213722944501Smrg    return 0;
213822944501Smrg}
213922944501Smrg
21406260e5d5Smrgdrm_public int drmGetContextFlags(int fd, drm_context_t context,
21416260e5d5Smrg                                  drm_context_tFlagsPtr flags)
214222944501Smrg{
214322944501Smrg    drm_ctx_t ctx;
214422944501Smrg
2145424e9256Smrg    memclear(ctx);
214622944501Smrg    ctx.handle = context;
214722944501Smrg    if (drmIoctl(fd, DRM_IOCTL_GET_CTX, &ctx))
2148fe517fc9Smrg        return -errno;
214922944501Smrg    *flags = 0;
215022944501Smrg    if (ctx.flags & _DRM_CONTEXT_PRESERVED)
2151fe517fc9Smrg        *flags |= DRM_CONTEXT_PRESERVED;
215222944501Smrg    if (ctx.flags & _DRM_CONTEXT_2DONLY)
2153fe517fc9Smrg        *flags |= DRM_CONTEXT_2DONLY;
215422944501Smrg    return 0;
215522944501Smrg}
215622944501Smrg
215722944501Smrg/**
215822944501Smrg * Destroy context.
215922944501Smrg *
216022944501Smrg * Free any kernel-level resources allocated with drmCreateContext() associated
216122944501Smrg * with the context.
2162fe517fc9Smrg *
216322944501Smrg * \param fd file descriptor.
216422944501Smrg * \param handle handle given by drmCreateContext().
2165fe517fc9Smrg *
216622944501Smrg * \return zero on success, or a negative value on failure.
2167fe517fc9Smrg *
216822944501Smrg * \note May only be called by root.
2169fe517fc9Smrg *
217022944501Smrg * \internal
217122944501Smrg * This function is a wrapper around the DRM_IOCTL_RM_CTX ioctl, passing the
217222944501Smrg * argument in a drm_ctx structure.
217322944501Smrg */
21746260e5d5Smrgdrm_public int drmDestroyContext(int fd, drm_context_t handle)
217522944501Smrg{
217622944501Smrg    drm_ctx_t ctx;
2177424e9256Smrg
2178424e9256Smrg    memclear(ctx);
217922944501Smrg    ctx.handle = handle;
218022944501Smrg    if (drmIoctl(fd, DRM_IOCTL_RM_CTX, &ctx))
2181fe517fc9Smrg        return -errno;
218222944501Smrg    return 0;
218322944501Smrg}
218422944501Smrg
21856260e5d5Smrgdrm_public int drmCreateDrawable(int fd, drm_drawable_t *handle)
218622944501Smrg{
218722944501Smrg    drm_draw_t draw;
2188424e9256Smrg
2189424e9256Smrg    memclear(draw);
219022944501Smrg    if (drmIoctl(fd, DRM_IOCTL_ADD_DRAW, &draw))
2191fe517fc9Smrg        return -errno;
219222944501Smrg    *handle = draw.handle;
219322944501Smrg    return 0;
219422944501Smrg}
219522944501Smrg
21966260e5d5Smrgdrm_public int drmDestroyDrawable(int fd, drm_drawable_t handle)
219722944501Smrg{
219822944501Smrg    drm_draw_t draw;
2199424e9256Smrg
2200424e9256Smrg    memclear(draw);
220122944501Smrg    draw.handle = handle;
220222944501Smrg    if (drmIoctl(fd, DRM_IOCTL_RM_DRAW, &draw))
2203fe517fc9Smrg        return -errno;
220422944501Smrg    return 0;
220522944501Smrg}
220622944501Smrg
22076260e5d5Smrgdrm_public int drmUpdateDrawableInfo(int fd, drm_drawable_t handle,
22086260e5d5Smrg                                     drm_drawable_info_type_t type,
22096260e5d5Smrg                                     unsigned int num, void *data)
221022944501Smrg{
221122944501Smrg    drm_update_draw_t update;
221222944501Smrg
2213424e9256Smrg    memclear(update);
221422944501Smrg    update.handle = handle;
221522944501Smrg    update.type = type;
221622944501Smrg    update.num = num;
221722944501Smrg    update.data = (unsigned long long)(unsigned long)data;
221822944501Smrg
221922944501Smrg    if (drmIoctl(fd, DRM_IOCTL_UPDATE_DRAW, &update))
2220fe517fc9Smrg        return -errno;
222122944501Smrg
222222944501Smrg    return 0;
222322944501Smrg}
222422944501Smrg
22256260e5d5Smrgdrm_public int drmCrtcGetSequence(int fd, uint32_t crtcId, uint64_t *sequence,
22266260e5d5Smrg                                  uint64_t *ns)
22272b90624aSmrg{
22282b90624aSmrg    struct drm_crtc_get_sequence get_seq;
22292b90624aSmrg    int ret;
22302b90624aSmrg
22312b90624aSmrg    memclear(get_seq);
22322b90624aSmrg    get_seq.crtc_id = crtcId;
22332b90624aSmrg    ret = drmIoctl(fd, DRM_IOCTL_CRTC_GET_SEQUENCE, &get_seq);
22342b90624aSmrg    if (ret)
22352b90624aSmrg        return ret;
22362b90624aSmrg
22372b90624aSmrg    if (sequence)
22382b90624aSmrg        *sequence = get_seq.sequence;
22392b90624aSmrg    if (ns)
22402b90624aSmrg        *ns = get_seq.sequence_ns;
22412b90624aSmrg    return 0;
22422b90624aSmrg}
22432b90624aSmrg
22446260e5d5Smrgdrm_public int drmCrtcQueueSequence(int fd, uint32_t crtcId, uint32_t flags,
22456260e5d5Smrg                                    uint64_t sequence,
22466260e5d5Smrg                                    uint64_t *sequence_queued,
22476260e5d5Smrg                                    uint64_t user_data)
22482b90624aSmrg{
22492b90624aSmrg    struct drm_crtc_queue_sequence queue_seq;
22502b90624aSmrg    int ret;
22512b90624aSmrg
22522b90624aSmrg    memclear(queue_seq);
22532b90624aSmrg    queue_seq.crtc_id = crtcId;
22542b90624aSmrg    queue_seq.flags = flags;
22552b90624aSmrg    queue_seq.sequence = sequence;
22562b90624aSmrg    queue_seq.user_data = user_data;
22572b90624aSmrg
22582b90624aSmrg    ret = drmIoctl(fd, DRM_IOCTL_CRTC_QUEUE_SEQUENCE, &queue_seq);
22592b90624aSmrg    if (ret == 0 && sequence_queued)
22602b90624aSmrg        *sequence_queued = queue_seq.sequence;
22612b90624aSmrg
22622b90624aSmrg    return ret;
22632b90624aSmrg}
22642b90624aSmrg
226522944501Smrg/**
226622944501Smrg * Acquire the AGP device.
226722944501Smrg *
226822944501Smrg * Must be called before any of the other AGP related calls.
226922944501Smrg *
227022944501Smrg * \param fd file descriptor.
2271fe517fc9Smrg *
227222944501Smrg * \return zero on success, or a negative value on failure.
2273fe517fc9Smrg *
227422944501Smrg * \internal
227522944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_ACQUIRE ioctl.
227622944501Smrg */
22776260e5d5Smrgdrm_public int drmAgpAcquire(int fd)
227822944501Smrg{
227922944501Smrg    if (drmIoctl(fd, DRM_IOCTL_AGP_ACQUIRE, NULL))
2280fe517fc9Smrg        return -errno;
228122944501Smrg    return 0;
228222944501Smrg}
228322944501Smrg
228422944501Smrg
228522944501Smrg/**
228622944501Smrg * Release the AGP device.
228722944501Smrg *
228822944501Smrg * \param fd file descriptor.
2289fe517fc9Smrg *
229022944501Smrg * \return zero on success, or a negative value on failure.
2291fe517fc9Smrg *
229222944501Smrg * \internal
229322944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_RELEASE ioctl.
229422944501Smrg */
22956260e5d5Smrgdrm_public int drmAgpRelease(int fd)
229622944501Smrg{
229722944501Smrg    if (drmIoctl(fd, DRM_IOCTL_AGP_RELEASE, NULL))
2298fe517fc9Smrg        return -errno;
229922944501Smrg    return 0;
230022944501Smrg}
230122944501Smrg
230222944501Smrg
230322944501Smrg/**
230422944501Smrg * Set the AGP mode.
230522944501Smrg *
230622944501Smrg * \param fd file descriptor.
230722944501Smrg * \param mode AGP mode.
2308fe517fc9Smrg *
230922944501Smrg * \return zero on success, or a negative value on failure.
2310fe517fc9Smrg *
231122944501Smrg * \internal
231222944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_ENABLE ioctl, passing the
231322944501Smrg * argument in a drm_agp_mode structure.
231422944501Smrg */
23156260e5d5Smrgdrm_public int drmAgpEnable(int fd, unsigned long mode)
231622944501Smrg{
231722944501Smrg    drm_agp_mode_t m;
231822944501Smrg
2319424e9256Smrg    memclear(m);
232022944501Smrg    m.mode = mode;
232122944501Smrg    if (drmIoctl(fd, DRM_IOCTL_AGP_ENABLE, &m))
2322fe517fc9Smrg        return -errno;
232322944501Smrg    return 0;
232422944501Smrg}
232522944501Smrg
232622944501Smrg
232722944501Smrg/**
232822944501Smrg * Allocate a chunk of AGP memory.
232922944501Smrg *
233022944501Smrg * \param fd file descriptor.
233122944501Smrg * \param size requested memory size in bytes. Will be rounded to page boundary.
233222944501Smrg * \param type type of memory to allocate.
233322944501Smrg * \param address if not zero, will be set to the physical address of the
233422944501Smrg * allocated memory.
233522944501Smrg * \param handle on success will be set to a handle of the allocated memory.
2336fe517fc9Smrg *
233722944501Smrg * \return zero on success, or a negative value on failure.
2338fe517fc9Smrg *
233922944501Smrg * \internal
234022944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_ALLOC ioctl, passing the
234122944501Smrg * arguments in a drm_agp_buffer structure.
234222944501Smrg */
23436260e5d5Smrgdrm_public int drmAgpAlloc(int fd, unsigned long size, unsigned long type,
23446260e5d5Smrg                           unsigned long *address, drm_handle_t *handle)
234522944501Smrg{
234622944501Smrg    drm_agp_buffer_t b;
234722944501Smrg
2348424e9256Smrg    memclear(b);
234922944501Smrg    *handle = DRM_AGP_NO_HANDLE;
235022944501Smrg    b.size   = size;
235122944501Smrg    b.type   = type;
235222944501Smrg    if (drmIoctl(fd, DRM_IOCTL_AGP_ALLOC, &b))
2353fe517fc9Smrg        return -errno;
235422944501Smrg    if (address != 0UL)
2355fe517fc9Smrg        *address = b.physical;
235622944501Smrg    *handle = b.handle;
235722944501Smrg    return 0;
235822944501Smrg}
235922944501Smrg
236022944501Smrg
236122944501Smrg/**
236222944501Smrg * Free a chunk of AGP memory.
236322944501Smrg *
236422944501Smrg * \param fd file descriptor.
236522944501Smrg * \param handle handle to the allocated memory, as given by drmAgpAllocate().
2366fe517fc9Smrg *
236722944501Smrg * \return zero on success, or a negative value on failure.
2368fe517fc9Smrg *
236922944501Smrg * \internal
237022944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_FREE ioctl, passing the
237122944501Smrg * argument in a drm_agp_buffer structure.
237222944501Smrg */
23736260e5d5Smrgdrm_public int drmAgpFree(int fd, drm_handle_t handle)
237422944501Smrg{
237522944501Smrg    drm_agp_buffer_t b;
237622944501Smrg
2377424e9256Smrg    memclear(b);
237822944501Smrg    b.handle = handle;
237922944501Smrg    if (drmIoctl(fd, DRM_IOCTL_AGP_FREE, &b))
2380fe517fc9Smrg        return -errno;
238122944501Smrg    return 0;
238222944501Smrg}
238322944501Smrg
238422944501Smrg
238522944501Smrg/**
238622944501Smrg * Bind a chunk of AGP memory.
238722944501Smrg *
238822944501Smrg * \param fd file descriptor.
238922944501Smrg * \param handle handle to the allocated memory, as given by drmAgpAllocate().
239022944501Smrg * \param offset offset in bytes. It will round to page boundary.
2391fe517fc9Smrg *
239222944501Smrg * \return zero on success, or a negative value on failure.
2393fe517fc9Smrg *
239422944501Smrg * \internal
239522944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_BIND ioctl, passing the
239622944501Smrg * argument in a drm_agp_binding structure.
239722944501Smrg */
23986260e5d5Smrgdrm_public int drmAgpBind(int fd, drm_handle_t handle, unsigned long offset)
239922944501Smrg{
240022944501Smrg    drm_agp_binding_t b;
240122944501Smrg
2402424e9256Smrg    memclear(b);
240322944501Smrg    b.handle = handle;
240422944501Smrg    b.offset = offset;
240522944501Smrg    if (drmIoctl(fd, DRM_IOCTL_AGP_BIND, &b))
2406fe517fc9Smrg        return -errno;
240722944501Smrg    return 0;
240822944501Smrg}
240922944501Smrg
241022944501Smrg
241122944501Smrg/**
241222944501Smrg * Unbind a chunk of AGP memory.
241322944501Smrg *
241422944501Smrg * \param fd file descriptor.
241522944501Smrg * \param handle handle to the allocated memory, as given by drmAgpAllocate().
2416fe517fc9Smrg *
241722944501Smrg * \return zero on success, or a negative value on failure.
2418fe517fc9Smrg *
241922944501Smrg * \internal
242022944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_UNBIND ioctl, passing
242122944501Smrg * the argument in a drm_agp_binding structure.
242222944501Smrg */
24236260e5d5Smrgdrm_public int drmAgpUnbind(int fd, drm_handle_t handle)
242422944501Smrg{
242522944501Smrg    drm_agp_binding_t b;
242622944501Smrg
2427424e9256Smrg    memclear(b);
242822944501Smrg    b.handle = handle;
242922944501Smrg    if (drmIoctl(fd, DRM_IOCTL_AGP_UNBIND, &b))
2430fe517fc9Smrg        return -errno;
243122944501Smrg    return 0;
243222944501Smrg}
243322944501Smrg
243422944501Smrg
243522944501Smrg/**
243622944501Smrg * Get AGP driver major version number.
243722944501Smrg *
243822944501Smrg * \param fd file descriptor.
2439fe517fc9Smrg *
244022944501Smrg * \return major version number on success, or a negative value on failure..
2441fe517fc9Smrg *
244222944501Smrg * \internal
244322944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
244422944501Smrg * necessary information in a drm_agp_info structure.
244522944501Smrg */
24466260e5d5Smrgdrm_public int drmAgpVersionMajor(int fd)
244722944501Smrg{
244822944501Smrg    drm_agp_info_t i;
244922944501Smrg
2450424e9256Smrg    memclear(i);
2451424e9256Smrg
245222944501Smrg    if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
2453fe517fc9Smrg        return -errno;
245422944501Smrg    return i.agp_version_major;
245522944501Smrg}
245622944501Smrg
245722944501Smrg
245822944501Smrg/**
245922944501Smrg * Get AGP driver minor version number.
246022944501Smrg *
246122944501Smrg * \param fd file descriptor.
2462fe517fc9Smrg *
246322944501Smrg * \return minor version number on success, or a negative value on failure.
2464fe517fc9Smrg *
246522944501Smrg * \internal
246622944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
246722944501Smrg * necessary information in a drm_agp_info structure.
246822944501Smrg */
24696260e5d5Smrgdrm_public int drmAgpVersionMinor(int fd)
247022944501Smrg{
247122944501Smrg    drm_agp_info_t i;
247222944501Smrg
2473424e9256Smrg    memclear(i);
2474424e9256Smrg
247522944501Smrg    if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
2476fe517fc9Smrg        return -errno;
247722944501Smrg    return i.agp_version_minor;
247822944501Smrg}
247922944501Smrg
248022944501Smrg
248122944501Smrg/**
248222944501Smrg * Get AGP mode.
248322944501Smrg *
248422944501Smrg * \param fd file descriptor.
2485fe517fc9Smrg *
248622944501Smrg * \return mode on success, or zero on failure.
2487fe517fc9Smrg *
248822944501Smrg * \internal
248922944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
249022944501Smrg * necessary information in a drm_agp_info structure.
249122944501Smrg */
24926260e5d5Smrgdrm_public unsigned long drmAgpGetMode(int fd)
249322944501Smrg{
249422944501Smrg    drm_agp_info_t i;
249522944501Smrg
2496424e9256Smrg    memclear(i);
2497424e9256Smrg
249822944501Smrg    if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
2499fe517fc9Smrg        return 0;
250022944501Smrg    return i.mode;
250122944501Smrg}
250222944501Smrg
250322944501Smrg
250422944501Smrg/**
250522944501Smrg * Get AGP aperture base.
250622944501Smrg *
250722944501Smrg * \param fd file descriptor.
2508fe517fc9Smrg *
250922944501Smrg * \return aperture base on success, zero on failure.
2510fe517fc9Smrg *
251122944501Smrg * \internal
251222944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
251322944501Smrg * necessary information in a drm_agp_info structure.
251422944501Smrg */
25156260e5d5Smrgdrm_public unsigned long drmAgpBase(int fd)
251622944501Smrg{
251722944501Smrg    drm_agp_info_t i;
251822944501Smrg
2519424e9256Smrg    memclear(i);
2520424e9256Smrg
252122944501Smrg    if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
2522fe517fc9Smrg        return 0;
252322944501Smrg    return i.aperture_base;
252422944501Smrg}
252522944501Smrg
252622944501Smrg
252722944501Smrg/**
252822944501Smrg * Get AGP aperture size.
252922944501Smrg *
253022944501Smrg * \param fd file descriptor.
2531fe517fc9Smrg *
253222944501Smrg * \return aperture size on success, zero on failure.
2533fe517fc9Smrg *
253422944501Smrg * \internal
253522944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
253622944501Smrg * necessary information in a drm_agp_info structure.
253722944501Smrg */
25386260e5d5Smrgdrm_public unsigned long drmAgpSize(int fd)
253922944501Smrg{
254022944501Smrg    drm_agp_info_t i;
254122944501Smrg
2542424e9256Smrg    memclear(i);
2543424e9256Smrg
254422944501Smrg    if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
2545fe517fc9Smrg        return 0;
254622944501Smrg    return i.aperture_size;
254722944501Smrg}
254822944501Smrg
254922944501Smrg
255022944501Smrg/**
255122944501Smrg * Get used AGP memory.
255222944501Smrg *
255322944501Smrg * \param fd file descriptor.
2554fe517fc9Smrg *
255522944501Smrg * \return memory used on success, or zero on failure.
2556fe517fc9Smrg *
255722944501Smrg * \internal
255822944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
255922944501Smrg * necessary information in a drm_agp_info structure.
256022944501Smrg */
25616260e5d5Smrgdrm_public unsigned long drmAgpMemoryUsed(int fd)
256222944501Smrg{
256322944501Smrg    drm_agp_info_t i;
256422944501Smrg
2565424e9256Smrg    memclear(i);
2566424e9256Smrg
256722944501Smrg    if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
2568fe517fc9Smrg        return 0;
256922944501Smrg    return i.memory_used;
257022944501Smrg}
257122944501Smrg
257222944501Smrg
257322944501Smrg/**
257422944501Smrg * Get available AGP memory.
257522944501Smrg *
257622944501Smrg * \param fd file descriptor.
2577fe517fc9Smrg *
257822944501Smrg * \return memory available on success, or zero on failure.
2579fe517fc9Smrg *
258022944501Smrg * \internal
258122944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
258222944501Smrg * necessary information in a drm_agp_info structure.
258322944501Smrg */
25846260e5d5Smrgdrm_public unsigned long drmAgpMemoryAvail(int fd)
258522944501Smrg{
258622944501Smrg    drm_agp_info_t i;
258722944501Smrg
2588424e9256Smrg    memclear(i);
2589424e9256Smrg
259022944501Smrg    if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
2591fe517fc9Smrg        return 0;
259222944501Smrg    return i.memory_allowed;
259322944501Smrg}
259422944501Smrg
259522944501Smrg
259622944501Smrg/**
259722944501Smrg * Get hardware vendor ID.
259822944501Smrg *
259922944501Smrg * \param fd file descriptor.
2600fe517fc9Smrg *
260122944501Smrg * \return vendor ID on success, or zero on failure.
2602fe517fc9Smrg *
260322944501Smrg * \internal
260422944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
260522944501Smrg * necessary information in a drm_agp_info structure.
260622944501Smrg */
26076260e5d5Smrgdrm_public unsigned int drmAgpVendorId(int fd)
260822944501Smrg{
260922944501Smrg    drm_agp_info_t i;
261022944501Smrg
2611424e9256Smrg    memclear(i);
2612424e9256Smrg
261322944501Smrg    if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
2614fe517fc9Smrg        return 0;
261522944501Smrg    return i.id_vendor;
261622944501Smrg}
261722944501Smrg
261822944501Smrg
261922944501Smrg/**
262022944501Smrg * Get hardware device ID.
262122944501Smrg *
262222944501Smrg * \param fd file descriptor.
2623fe517fc9Smrg *
262422944501Smrg * \return zero on success, or zero on failure.
2625fe517fc9Smrg *
262622944501Smrg * \internal
262722944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
262822944501Smrg * necessary information in a drm_agp_info structure.
262922944501Smrg */
26306260e5d5Smrgdrm_public unsigned int drmAgpDeviceId(int fd)
263122944501Smrg{
263222944501Smrg    drm_agp_info_t i;
263322944501Smrg
2634424e9256Smrg    memclear(i);
2635424e9256Smrg
263622944501Smrg    if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
2637fe517fc9Smrg        return 0;
263822944501Smrg    return i.id_device;
263922944501Smrg}
264022944501Smrg
26416260e5d5Smrgdrm_public int drmScatterGatherAlloc(int fd, unsigned long size,
26426260e5d5Smrg                                     drm_handle_t *handle)
264322944501Smrg{
264422944501Smrg    drm_scatter_gather_t sg;
264522944501Smrg
2646424e9256Smrg    memclear(sg);
2647424e9256Smrg
264822944501Smrg    *handle = 0;
264922944501Smrg    sg.size   = size;
265022944501Smrg    if (drmIoctl(fd, DRM_IOCTL_SG_ALLOC, &sg))
2651fe517fc9Smrg        return -errno;
265222944501Smrg    *handle = sg.handle;
265322944501Smrg    return 0;
265422944501Smrg}
265522944501Smrg
26566260e5d5Smrgdrm_public int drmScatterGatherFree(int fd, drm_handle_t handle)
265722944501Smrg{
265822944501Smrg    drm_scatter_gather_t sg;
265922944501Smrg
2660424e9256Smrg    memclear(sg);
266122944501Smrg    sg.handle = handle;
266222944501Smrg    if (drmIoctl(fd, DRM_IOCTL_SG_FREE, &sg))
2663fe517fc9Smrg        return -errno;
266422944501Smrg    return 0;
266522944501Smrg}
266622944501Smrg
266722944501Smrg/**
266822944501Smrg * Wait for VBLANK.
266922944501Smrg *
267022944501Smrg * \param fd file descriptor.
267122944501Smrg * \param vbl pointer to a drmVBlank structure.
2672fe517fc9Smrg *
267322944501Smrg * \return zero on success, or a negative value on failure.
2674fe517fc9Smrg *
267522944501Smrg * \internal
267622944501Smrg * This function is a wrapper around the DRM_IOCTL_WAIT_VBLANK ioctl.
267722944501Smrg */
26786260e5d5Smrgdrm_public int drmWaitVBlank(int fd, drmVBlankPtr vbl)
267922944501Smrg{
268022944501Smrg    struct timespec timeout, cur;
268122944501Smrg    int ret;
268222944501Smrg
268322944501Smrg    ret = clock_gettime(CLOCK_MONOTONIC, &timeout);
268422944501Smrg    if (ret < 0) {
2685fe517fc9Smrg        fprintf(stderr, "clock_gettime failed: %s\n", strerror(errno));
2686fe517fc9Smrg        goto out;
268722944501Smrg    }
268822944501Smrg    timeout.tv_sec++;
268922944501Smrg
269022944501Smrg    do {
269122944501Smrg       ret = ioctl(fd, DRM_IOCTL_WAIT_VBLANK, vbl);
269222944501Smrg       vbl->request.type &= ~DRM_VBLANK_RELATIVE;
269322944501Smrg       if (ret && errno == EINTR) {
2694fe517fc9Smrg           clock_gettime(CLOCK_MONOTONIC, &cur);
2695fe517fc9Smrg           /* Timeout after 1s */
2696fe517fc9Smrg           if (cur.tv_sec > timeout.tv_sec + 1 ||
2697fe517fc9Smrg               (cur.tv_sec == timeout.tv_sec && cur.tv_nsec >=
2698fe517fc9Smrg                timeout.tv_nsec)) {
2699fe517fc9Smrg                   errno = EBUSY;
2700fe517fc9Smrg                   ret = -1;
2701fe517fc9Smrg                   break;
2702fe517fc9Smrg           }
270322944501Smrg       }
270422944501Smrg    } while (ret && errno == EINTR);
270522944501Smrg
270622944501Smrgout:
270722944501Smrg    return ret;
270822944501Smrg}
270922944501Smrg
27106260e5d5Smrgdrm_public int drmError(int err, const char *label)
271122944501Smrg{
271222944501Smrg    switch (err) {
271322944501Smrg    case DRM_ERR_NO_DEVICE:
2714fe517fc9Smrg        fprintf(stderr, "%s: no device\n", label);
2715fe517fc9Smrg        break;
271622944501Smrg    case DRM_ERR_NO_ACCESS:
2717fe517fc9Smrg        fprintf(stderr, "%s: no access\n", label);
2718fe517fc9Smrg        break;
271922944501Smrg    case DRM_ERR_NOT_ROOT:
2720fe517fc9Smrg        fprintf(stderr, "%s: not root\n", label);
2721fe517fc9Smrg        break;
272222944501Smrg    case DRM_ERR_INVALID:
2723fe517fc9Smrg        fprintf(stderr, "%s: invalid args\n", label);
2724fe517fc9Smrg        break;
272522944501Smrg    default:
2726fe517fc9Smrg        if (err < 0)
2727fe517fc9Smrg            err = -err;
2728fe517fc9Smrg        fprintf( stderr, "%s: error %d (%s)\n", label, err, strerror(err) );
2729fe517fc9Smrg        break;
273022944501Smrg    }
273122944501Smrg
273222944501Smrg    return 1;
273322944501Smrg}
273422944501Smrg
273522944501Smrg/**
273622944501Smrg * Install IRQ handler.
273722944501Smrg *
273822944501Smrg * \param fd file descriptor.
273922944501Smrg * \param irq IRQ number.
2740fe517fc9Smrg *
274122944501Smrg * \return zero on success, or a negative value on failure.
2742fe517fc9Smrg *
274322944501Smrg * \internal
274422944501Smrg * This function is a wrapper around the DRM_IOCTL_CONTROL ioctl, passing the
274522944501Smrg * argument in a drm_control structure.
274622944501Smrg */
27476260e5d5Smrgdrm_public int drmCtlInstHandler(int fd, int irq)
274822944501Smrg{
274922944501Smrg    drm_control_t ctl;
275022944501Smrg
2751424e9256Smrg    memclear(ctl);
275222944501Smrg    ctl.func  = DRM_INST_HANDLER;
275322944501Smrg    ctl.irq   = irq;
275422944501Smrg    if (drmIoctl(fd, DRM_IOCTL_CONTROL, &ctl))
2755fe517fc9Smrg        return -errno;
275622944501Smrg    return 0;
275722944501Smrg}
275822944501Smrg
275922944501Smrg
276022944501Smrg/**
276122944501Smrg * Uninstall IRQ handler.
276222944501Smrg *
276322944501Smrg * \param fd file descriptor.
2764fe517fc9Smrg *
276522944501Smrg * \return zero on success, or a negative value on failure.
2766fe517fc9Smrg *
276722944501Smrg * \internal
276822944501Smrg * This function is a wrapper around the DRM_IOCTL_CONTROL ioctl, passing the
276922944501Smrg * argument in a drm_control structure.
277022944501Smrg */
27716260e5d5Smrgdrm_public int drmCtlUninstHandler(int fd)
277222944501Smrg{
277322944501Smrg    drm_control_t ctl;
277422944501Smrg
2775424e9256Smrg    memclear(ctl);
277622944501Smrg    ctl.func  = DRM_UNINST_HANDLER;
277722944501Smrg    ctl.irq   = 0;
277822944501Smrg    if (drmIoctl(fd, DRM_IOCTL_CONTROL, &ctl))
2779fe517fc9Smrg        return -errno;
278022944501Smrg    return 0;
278122944501Smrg}
278222944501Smrg
27836260e5d5Smrgdrm_public int drmFinish(int fd, int context, drmLockFlags flags)
278422944501Smrg{
278522944501Smrg    drm_lock_t lock;
278622944501Smrg
2787424e9256Smrg    memclear(lock);
278822944501Smrg    lock.context = context;
278922944501Smrg    if (flags & DRM_LOCK_READY)      lock.flags |= _DRM_LOCK_READY;
279022944501Smrg    if (flags & DRM_LOCK_QUIESCENT)  lock.flags |= _DRM_LOCK_QUIESCENT;
279122944501Smrg    if (flags & DRM_LOCK_FLUSH)      lock.flags |= _DRM_LOCK_FLUSH;
279222944501Smrg    if (flags & DRM_LOCK_FLUSH_ALL)  lock.flags |= _DRM_LOCK_FLUSH_ALL;
279322944501Smrg    if (flags & DRM_HALT_ALL_QUEUES) lock.flags |= _DRM_HALT_ALL_QUEUES;
279422944501Smrg    if (flags & DRM_HALT_CUR_QUEUES) lock.flags |= _DRM_HALT_CUR_QUEUES;
279522944501Smrg    if (drmIoctl(fd, DRM_IOCTL_FINISH, &lock))
2796fe517fc9Smrg        return -errno;
279722944501Smrg    return 0;
279822944501Smrg}
279922944501Smrg
280022944501Smrg/**
280122944501Smrg * Get IRQ from bus ID.
280222944501Smrg *
280322944501Smrg * \param fd file descriptor.
280422944501Smrg * \param busnum bus number.
280522944501Smrg * \param devnum device number.
280622944501Smrg * \param funcnum function number.
2807fe517fc9Smrg *
280822944501Smrg * \return IRQ number on success, or a negative value on failure.
2809fe517fc9Smrg *
281022944501Smrg * \internal
281122944501Smrg * This function is a wrapper around the DRM_IOCTL_IRQ_BUSID ioctl, passing the
281222944501Smrg * arguments in a drm_irq_busid structure.
281322944501Smrg */
28146260e5d5Smrgdrm_public int drmGetInterruptFromBusID(int fd, int busnum, int devnum,
28156260e5d5Smrg                                        int funcnum)
281622944501Smrg{
281722944501Smrg    drm_irq_busid_t p;
281822944501Smrg
2819424e9256Smrg    memclear(p);
282022944501Smrg    p.busnum  = busnum;
282122944501Smrg    p.devnum  = devnum;
282222944501Smrg    p.funcnum = funcnum;
282322944501Smrg    if (drmIoctl(fd, DRM_IOCTL_IRQ_BUSID, &p))
2824fe517fc9Smrg        return -errno;
282522944501Smrg    return p.irq;
282622944501Smrg}
282722944501Smrg
28286260e5d5Smrgdrm_public int drmAddContextTag(int fd, drm_context_t context, void *tag)
282922944501Smrg{
283022944501Smrg    drmHashEntry  *entry = drmGetEntry(fd);
283122944501Smrg
283222944501Smrg    if (drmHashInsert(entry->tagTable, context, tag)) {
2833fe517fc9Smrg        drmHashDelete(entry->tagTable, context);
2834fe517fc9Smrg        drmHashInsert(entry->tagTable, context, tag);
283522944501Smrg    }
283622944501Smrg    return 0;
283722944501Smrg}
283822944501Smrg
28396260e5d5Smrgdrm_public int drmDelContextTag(int fd, drm_context_t context)
284022944501Smrg{
284122944501Smrg    drmHashEntry  *entry = drmGetEntry(fd);
284222944501Smrg
284322944501Smrg    return drmHashDelete(entry->tagTable, context);
284422944501Smrg}
284522944501Smrg
28466260e5d5Smrgdrm_public void *drmGetContextTag(int fd, drm_context_t context)
284722944501Smrg{
284822944501Smrg    drmHashEntry  *entry = drmGetEntry(fd);
284922944501Smrg    void          *value;
285022944501Smrg
285122944501Smrg    if (drmHashLookup(entry->tagTable, context, &value))
2852fe517fc9Smrg        return NULL;
285322944501Smrg
285422944501Smrg    return value;
285522944501Smrg}
285622944501Smrg
28576260e5d5Smrgdrm_public int drmAddContextPrivateMapping(int fd, drm_context_t ctx_id,
28586260e5d5Smrg                                           drm_handle_t handle)
285922944501Smrg{
286022944501Smrg    drm_ctx_priv_map_t map;
286122944501Smrg
2862424e9256Smrg    memclear(map);
286322944501Smrg    map.ctx_id = ctx_id;
286420131375Smrg    map.handle = (void *)(uintptr_t)handle;
286522944501Smrg
286622944501Smrg    if (drmIoctl(fd, DRM_IOCTL_SET_SAREA_CTX, &map))
2867fe517fc9Smrg        return -errno;
286822944501Smrg    return 0;
286922944501Smrg}
287022944501Smrg
28716260e5d5Smrgdrm_public int drmGetContextPrivateMapping(int fd, drm_context_t ctx_id,
28726260e5d5Smrg                                           drm_handle_t *handle)
287322944501Smrg{
287422944501Smrg    drm_ctx_priv_map_t map;
287522944501Smrg
2876424e9256Smrg    memclear(map);
287722944501Smrg    map.ctx_id = ctx_id;
287822944501Smrg
287922944501Smrg    if (drmIoctl(fd, DRM_IOCTL_GET_SAREA_CTX, &map))
2880fe517fc9Smrg        return -errno;
288122944501Smrg    if (handle)
2882fe517fc9Smrg        *handle = (drm_handle_t)(uintptr_t)map.handle;
288322944501Smrg
288422944501Smrg    return 0;
288522944501Smrg}
288622944501Smrg
28876260e5d5Smrgdrm_public int drmGetMap(int fd, int idx, drm_handle_t *offset, drmSize *size,
28886260e5d5Smrg                         drmMapType *type, drmMapFlags *flags,
28896260e5d5Smrg                         drm_handle_t *handle, int *mtrr)
289022944501Smrg{
289122944501Smrg    drm_map_t map;
289222944501Smrg
2893424e9256Smrg    memclear(map);
289422944501Smrg    map.offset = idx;
289522944501Smrg    if (drmIoctl(fd, DRM_IOCTL_GET_MAP, &map))
2896fe517fc9Smrg        return -errno;
289722944501Smrg    *offset = map.offset;
289822944501Smrg    *size   = map.size;
2899adfa0b0cSmrg    *type   = (drmMapType)map.type;
2900adfa0b0cSmrg    *flags  = (drmMapFlags)map.flags;
290122944501Smrg    *handle = (unsigned long)map.handle;
290222944501Smrg    *mtrr   = map.mtrr;
290322944501Smrg    return 0;
290422944501Smrg}
290522944501Smrg
29066260e5d5Smrgdrm_public int drmGetClient(int fd, int idx, int *auth, int *pid, int *uid,
29076260e5d5Smrg                            unsigned long *magic, unsigned long *iocs)
290822944501Smrg{
290922944501Smrg    drm_client_t client;
291022944501Smrg
2911424e9256Smrg    memclear(client);
291222944501Smrg    client.idx = idx;
291322944501Smrg    if (drmIoctl(fd, DRM_IOCTL_GET_CLIENT, &client))
2914fe517fc9Smrg        return -errno;
291522944501Smrg    *auth      = client.auth;
291622944501Smrg    *pid       = client.pid;
291722944501Smrg    *uid       = client.uid;
291822944501Smrg    *magic     = client.magic;
291922944501Smrg    *iocs      = client.iocs;
292022944501Smrg    return 0;
292122944501Smrg}
292222944501Smrg
29236260e5d5Smrgdrm_public int drmGetStats(int fd, drmStatsT *stats)
292422944501Smrg{
292522944501Smrg    drm_stats_t s;
2926424e9256Smrg    unsigned    i;
292722944501Smrg
2928424e9256Smrg    memclear(s);
292922944501Smrg    if (drmIoctl(fd, DRM_IOCTL_GET_STATS, &s))
2930fe517fc9Smrg        return -errno;
293122944501Smrg
293222944501Smrg    stats->count = 0;
293322944501Smrg    memset(stats, 0, sizeof(*stats));
293422944501Smrg    if (s.count > sizeof(stats->data)/sizeof(stats->data[0]))
2935fe517fc9Smrg        return -1;
293622944501Smrg
293722944501Smrg#define SET_VALUE                              \
293822944501Smrg    stats->data[i].long_format = "%-20.20s";   \
293922944501Smrg    stats->data[i].rate_format = "%8.8s";      \
294022944501Smrg    stats->data[i].isvalue     = 1;            \
294122944501Smrg    stats->data[i].verbose     = 0
294222944501Smrg
294322944501Smrg#define SET_COUNT                              \
294422944501Smrg    stats->data[i].long_format = "%-20.20s";   \
294522944501Smrg    stats->data[i].rate_format = "%5.5s";      \
294622944501Smrg    stats->data[i].isvalue     = 0;            \
294722944501Smrg    stats->data[i].mult_names  = "kgm";        \
294822944501Smrg    stats->data[i].mult        = 1000;         \
294922944501Smrg    stats->data[i].verbose     = 0
295022944501Smrg
295122944501Smrg#define SET_BYTE                               \
295222944501Smrg    stats->data[i].long_format = "%-20.20s";   \
295322944501Smrg    stats->data[i].rate_format = "%5.5s";      \
295422944501Smrg    stats->data[i].isvalue     = 0;            \
295522944501Smrg    stats->data[i].mult_names  = "KGM";        \
295622944501Smrg    stats->data[i].mult        = 1024;         \
295722944501Smrg    stats->data[i].verbose     = 0
295822944501Smrg
295922944501Smrg
296022944501Smrg    stats->count = s.count;
296122944501Smrg    for (i = 0; i < s.count; i++) {
2962fe517fc9Smrg        stats->data[i].value = s.data[i].value;
2963fe517fc9Smrg        switch (s.data[i].type) {
2964fe517fc9Smrg        case _DRM_STAT_LOCK:
2965fe517fc9Smrg            stats->data[i].long_name = "Lock";
2966fe517fc9Smrg            stats->data[i].rate_name = "Lock";
2967fe517fc9Smrg            SET_VALUE;
2968fe517fc9Smrg            break;
2969fe517fc9Smrg        case _DRM_STAT_OPENS:
2970fe517fc9Smrg            stats->data[i].long_name = "Opens";
2971fe517fc9Smrg            stats->data[i].rate_name = "O";
2972fe517fc9Smrg            SET_COUNT;
2973fe517fc9Smrg            stats->data[i].verbose   = 1;
2974fe517fc9Smrg            break;
2975fe517fc9Smrg        case _DRM_STAT_CLOSES:
2976fe517fc9Smrg            stats->data[i].long_name = "Closes";
2977fe517fc9Smrg            stats->data[i].rate_name = "Lock";
2978fe517fc9Smrg            SET_COUNT;
2979fe517fc9Smrg            stats->data[i].verbose   = 1;
2980fe517fc9Smrg            break;
2981fe517fc9Smrg        case _DRM_STAT_IOCTLS:
2982fe517fc9Smrg            stats->data[i].long_name = "Ioctls";
2983fe517fc9Smrg            stats->data[i].rate_name = "Ioc/s";
2984fe517fc9Smrg            SET_COUNT;
2985fe517fc9Smrg            break;
2986fe517fc9Smrg        case _DRM_STAT_LOCKS:
2987fe517fc9Smrg            stats->data[i].long_name = "Locks";
2988fe517fc9Smrg            stats->data[i].rate_name = "Lck/s";
2989fe517fc9Smrg            SET_COUNT;
2990fe517fc9Smrg            break;
2991fe517fc9Smrg        case _DRM_STAT_UNLOCKS:
2992fe517fc9Smrg            stats->data[i].long_name = "Unlocks";
2993fe517fc9Smrg            stats->data[i].rate_name = "Unl/s";
2994fe517fc9Smrg            SET_COUNT;
2995fe517fc9Smrg            break;
2996fe517fc9Smrg        case _DRM_STAT_IRQ:
2997fe517fc9Smrg            stats->data[i].long_name = "IRQs";
2998fe517fc9Smrg            stats->data[i].rate_name = "IRQ/s";
2999fe517fc9Smrg            SET_COUNT;
3000fe517fc9Smrg            break;
3001fe517fc9Smrg        case _DRM_STAT_PRIMARY:
3002fe517fc9Smrg            stats->data[i].long_name = "Primary Bytes";
3003fe517fc9Smrg            stats->data[i].rate_name = "PB/s";
3004fe517fc9Smrg            SET_BYTE;
3005fe517fc9Smrg            break;
3006fe517fc9Smrg        case _DRM_STAT_SECONDARY:
3007fe517fc9Smrg            stats->data[i].long_name = "Secondary Bytes";
3008fe517fc9Smrg            stats->data[i].rate_name = "SB/s";
3009fe517fc9Smrg            SET_BYTE;
3010fe517fc9Smrg            break;
3011fe517fc9Smrg        case _DRM_STAT_DMA:
3012fe517fc9Smrg            stats->data[i].long_name = "DMA";
3013fe517fc9Smrg            stats->data[i].rate_name = "DMA/s";
3014fe517fc9Smrg            SET_COUNT;
3015fe517fc9Smrg            break;
3016fe517fc9Smrg        case _DRM_STAT_SPECIAL:
3017fe517fc9Smrg            stats->data[i].long_name = "Special DMA";
3018fe517fc9Smrg            stats->data[i].rate_name = "dma/s";
3019fe517fc9Smrg            SET_COUNT;
3020fe517fc9Smrg            break;
3021fe517fc9Smrg        case _DRM_STAT_MISSED:
3022fe517fc9Smrg            stats->data[i].long_name = "Miss";
3023fe517fc9Smrg            stats->data[i].rate_name = "Ms/s";
3024fe517fc9Smrg            SET_COUNT;
3025fe517fc9Smrg            break;
3026fe517fc9Smrg        case _DRM_STAT_VALUE:
3027fe517fc9Smrg            stats->data[i].long_name = "Value";
3028fe517fc9Smrg            stats->data[i].rate_name = "Value";
3029fe517fc9Smrg            SET_VALUE;
3030fe517fc9Smrg            break;
3031fe517fc9Smrg        case _DRM_STAT_BYTE:
3032fe517fc9Smrg            stats->data[i].long_name = "Bytes";
3033fe517fc9Smrg            stats->data[i].rate_name = "B/s";
3034fe517fc9Smrg            SET_BYTE;
3035fe517fc9Smrg            break;
3036fe517fc9Smrg        case _DRM_STAT_COUNT:
3037fe517fc9Smrg        default:
3038fe517fc9Smrg            stats->data[i].long_name = "Count";
3039fe517fc9Smrg            stats->data[i].rate_name = "Cnt/s";
3040fe517fc9Smrg            SET_COUNT;
3041fe517fc9Smrg            break;
3042fe517fc9Smrg        }
304322944501Smrg    }
304422944501Smrg    return 0;
304522944501Smrg}
304622944501Smrg
304722944501Smrg/**
304822944501Smrg * Issue a set-version ioctl.
304922944501Smrg *
305022944501Smrg * \param fd file descriptor.
3051fe517fc9Smrg * \param drmCommandIndex command index
305222944501Smrg * \param data source pointer of the data to be read and written.
305322944501Smrg * \param size size of the data to be read and written.
3054fe517fc9Smrg *
305522944501Smrg * \return zero on success, or a negative value on failure.
3056fe517fc9Smrg *
305722944501Smrg * \internal
3058fe517fc9Smrg * It issues a read-write ioctl given by
305922944501Smrg * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
306022944501Smrg */
30616260e5d5Smrgdrm_public int drmSetInterfaceVersion(int fd, drmSetVersion *version)
306222944501Smrg{
306322944501Smrg    int retcode = 0;
306422944501Smrg    drm_set_version_t sv;
306522944501Smrg
3066424e9256Smrg    memclear(sv);
306722944501Smrg    sv.drm_di_major = version->drm_di_major;
306822944501Smrg    sv.drm_di_minor = version->drm_di_minor;
306922944501Smrg    sv.drm_dd_major = version->drm_dd_major;
307022944501Smrg    sv.drm_dd_minor = version->drm_dd_minor;
307122944501Smrg
307222944501Smrg    if (drmIoctl(fd, DRM_IOCTL_SET_VERSION, &sv)) {
3073fe517fc9Smrg        retcode = -errno;
307422944501Smrg    }
307522944501Smrg
307622944501Smrg    version->drm_di_major = sv.drm_di_major;
307722944501Smrg    version->drm_di_minor = sv.drm_di_minor;
307822944501Smrg    version->drm_dd_major = sv.drm_dd_major;
307922944501Smrg    version->drm_dd_minor = sv.drm_dd_minor;
308022944501Smrg
308122944501Smrg    return retcode;
308222944501Smrg}
308322944501Smrg
308422944501Smrg/**
308522944501Smrg * Send a device-specific command.
308622944501Smrg *
308722944501Smrg * \param fd file descriptor.
3088fe517fc9Smrg * \param drmCommandIndex command index
3089fe517fc9Smrg *
309022944501Smrg * \return zero on success, or a negative value on failure.
3091fe517fc9Smrg *
309222944501Smrg * \internal
3093fe517fc9Smrg * It issues a ioctl given by
309422944501Smrg * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
309522944501Smrg */
30966260e5d5Smrgdrm_public int drmCommandNone(int fd, unsigned long drmCommandIndex)
309722944501Smrg{
309822944501Smrg    unsigned long request;
309922944501Smrg
310022944501Smrg    request = DRM_IO( DRM_COMMAND_BASE + drmCommandIndex);
310122944501Smrg
3102424e9256Smrg    if (drmIoctl(fd, request, NULL)) {
3103fe517fc9Smrg        return -errno;
310422944501Smrg    }
310522944501Smrg    return 0;
310622944501Smrg}
310722944501Smrg
310822944501Smrg
310922944501Smrg/**
311022944501Smrg * Send a device-specific read command.
311122944501Smrg *
311222944501Smrg * \param fd file descriptor.
3113fe517fc9Smrg * \param drmCommandIndex command index
311422944501Smrg * \param data destination pointer of the data to be read.
311522944501Smrg * \param size size of the data to be read.
3116fe517fc9Smrg *
311722944501Smrg * \return zero on success, or a negative value on failure.
311822944501Smrg *
311922944501Smrg * \internal
3120fe517fc9Smrg * It issues a read ioctl given by
312122944501Smrg * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
312222944501Smrg */
31236260e5d5Smrgdrm_public int drmCommandRead(int fd, unsigned long drmCommandIndex,
31246260e5d5Smrg                              void *data, unsigned long size)
312522944501Smrg{
312622944501Smrg    unsigned long request;
312722944501Smrg
3128fe517fc9Smrg    request = DRM_IOC( DRM_IOC_READ, DRM_IOCTL_BASE,
3129fe517fc9Smrg        DRM_COMMAND_BASE + drmCommandIndex, size);
313022944501Smrg
313122944501Smrg    if (drmIoctl(fd, request, data)) {
3132fe517fc9Smrg        return -errno;
313322944501Smrg    }
313422944501Smrg    return 0;
313522944501Smrg}
313622944501Smrg
313722944501Smrg
313822944501Smrg/**
313922944501Smrg * Send a device-specific write command.
314022944501Smrg *
314122944501Smrg * \param fd file descriptor.
3142fe517fc9Smrg * \param drmCommandIndex command index
314322944501Smrg * \param data source pointer of the data to be written.
314422944501Smrg * \param size size of the data to be written.
3145fe517fc9Smrg *
314622944501Smrg * \return zero on success, or a negative value on failure.
3147fe517fc9Smrg *
314822944501Smrg * \internal
3149fe517fc9Smrg * It issues a write ioctl given by
315022944501Smrg * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
315122944501Smrg */
31526260e5d5Smrgdrm_public int drmCommandWrite(int fd, unsigned long drmCommandIndex,
31536260e5d5Smrg                               void *data, unsigned long size)
315422944501Smrg{
315522944501Smrg    unsigned long request;
315622944501Smrg
3157fe517fc9Smrg    request = DRM_IOC( DRM_IOC_WRITE, DRM_IOCTL_BASE,
3158fe517fc9Smrg        DRM_COMMAND_BASE + drmCommandIndex, size);
315922944501Smrg
316022944501Smrg    if (drmIoctl(fd, request, data)) {
3161fe517fc9Smrg        return -errno;
316222944501Smrg    }
316322944501Smrg    return 0;
316422944501Smrg}
316522944501Smrg
316622944501Smrg
316722944501Smrg/**
316822944501Smrg * Send a device-specific read-write command.
316922944501Smrg *
317022944501Smrg * \param fd file descriptor.
3171fe517fc9Smrg * \param drmCommandIndex command index
317222944501Smrg * \param data source pointer of the data to be read and written.
317322944501Smrg * \param size size of the data to be read and written.
3174fe517fc9Smrg *
317522944501Smrg * \return zero on success, or a negative value on failure.
3176fe517fc9Smrg *
317722944501Smrg * \internal
3178fe517fc9Smrg * It issues a read-write ioctl given by
317922944501Smrg * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
318022944501Smrg */
31816260e5d5Smrgdrm_public int drmCommandWriteRead(int fd, unsigned long drmCommandIndex,
31826260e5d5Smrg                                   void *data, unsigned long size)
318322944501Smrg{
318422944501Smrg    unsigned long request;
318522944501Smrg
3186fe517fc9Smrg    request = DRM_IOC( DRM_IOC_READ|DRM_IOC_WRITE, DRM_IOCTL_BASE,
3187fe517fc9Smrg        DRM_COMMAND_BASE + drmCommandIndex, size);
318822944501Smrg
318922944501Smrg    if (drmIoctl(fd, request, data))
3190fe517fc9Smrg        return -errno;
319122944501Smrg    return 0;
319222944501Smrg}
319322944501Smrg
319422944501Smrg#define DRM_MAX_FDS 16
319522944501Smrgstatic struct {
319622944501Smrg    char *BusID;
319722944501Smrg    int fd;
319822944501Smrg    int refcount;
3199424e9256Smrg    int type;
320022944501Smrg} connection[DRM_MAX_FDS];
320122944501Smrg
320222944501Smrgstatic int nr_fds = 0;
320322944501Smrg
32046260e5d5Smrgdrm_public int drmOpenOnce(void *unused, const char *BusID, int *newlyopened)
3205424e9256Smrg{
3206424e9256Smrg    return drmOpenOnceWithType(BusID, newlyopened, DRM_NODE_PRIMARY);
3207424e9256Smrg}
3208424e9256Smrg
32096260e5d5Smrgdrm_public int drmOpenOnceWithType(const char *BusID, int *newlyopened,
32106260e5d5Smrg                                   int type)
321122944501Smrg{
321222944501Smrg    int i;
321322944501Smrg    int fd;
3214fe517fc9Smrg
321522944501Smrg    for (i = 0; i < nr_fds; i++)
3216fe517fc9Smrg        if ((strcmp(BusID, connection[i].BusID) == 0) &&
3217fe517fc9Smrg            (connection[i].type == type)) {
3218fe517fc9Smrg            connection[i].refcount++;
3219fe517fc9Smrg            *newlyopened = 0;
3220fe517fc9Smrg            return connection[i].fd;
3221fe517fc9Smrg        }
322222944501Smrg
3223424e9256Smrg    fd = drmOpenWithType(NULL, BusID, type);
3224fe517fc9Smrg    if (fd < 0 || nr_fds == DRM_MAX_FDS)
3225fe517fc9Smrg        return fd;
3226fe517fc9Smrg
322722944501Smrg    connection[nr_fds].BusID = strdup(BusID);
322822944501Smrg    connection[nr_fds].fd = fd;
322922944501Smrg    connection[nr_fds].refcount = 1;
3230424e9256Smrg    connection[nr_fds].type = type;
323122944501Smrg    *newlyopened = 1;
323222944501Smrg
323322944501Smrg    if (0)
3234fe517fc9Smrg        fprintf(stderr, "saved connection %d for %s %d\n",
3235fe517fc9Smrg                nr_fds, connection[nr_fds].BusID,
3236fe517fc9Smrg                strcmp(BusID, connection[nr_fds].BusID));
323722944501Smrg
323822944501Smrg    nr_fds++;
323922944501Smrg
324022944501Smrg    return fd;
324122944501Smrg}
324222944501Smrg
32436260e5d5Smrgdrm_public void drmCloseOnce(int fd)
324422944501Smrg{
324522944501Smrg    int i;
324622944501Smrg
324722944501Smrg    for (i = 0; i < nr_fds; i++) {
3248fe517fc9Smrg        if (fd == connection[i].fd) {
3249fe517fc9Smrg            if (--connection[i].refcount == 0) {
3250fe517fc9Smrg                drmClose(connection[i].fd);
3251fe517fc9Smrg                free(connection[i].BusID);
3252fe517fc9Smrg
3253fe517fc9Smrg                if (i < --nr_fds)
3254fe517fc9Smrg                    connection[i] = connection[nr_fds];
3255fe517fc9Smrg
3256fe517fc9Smrg                return;
3257fe517fc9Smrg            }
3258fe517fc9Smrg        }
325922944501Smrg    }
326022944501Smrg}
326122944501Smrg
32626260e5d5Smrgdrm_public int drmSetMaster(int fd)
326322944501Smrg{
3264fe517fc9Smrg        return drmIoctl(fd, DRM_IOCTL_SET_MASTER, NULL);
326522944501Smrg}
326622944501Smrg
32676260e5d5Smrgdrm_public int drmDropMaster(int fd)
326822944501Smrg{
3269fe517fc9Smrg        return drmIoctl(fd, DRM_IOCTL_DROP_MASTER, NULL);
327022944501Smrg}
327122944501Smrg
3272bf6cc7dcSmrgdrm_public int drmIsMaster(int fd)
3273bf6cc7dcSmrg{
3274bf6cc7dcSmrg        /* Detect master by attempting something that requires master.
3275bf6cc7dcSmrg         *
3276bf6cc7dcSmrg         * Authenticating magic tokens requires master and 0 is an
3277bf6cc7dcSmrg         * internal kernel detail which we could use. Attempting this on
3278bf6cc7dcSmrg         * a master fd would fail therefore fail with EINVAL because 0
3279bf6cc7dcSmrg         * is invalid.
3280bf6cc7dcSmrg         *
3281bf6cc7dcSmrg         * A non-master fd will fail with EACCES, as the kernel checks
3282bf6cc7dcSmrg         * for master before attempting to do anything else.
3283bf6cc7dcSmrg         *
3284bf6cc7dcSmrg         * Since we don't want to leak implementation details, use
3285bf6cc7dcSmrg         * EACCES.
3286bf6cc7dcSmrg         */
3287bf6cc7dcSmrg        return drmAuthMagic(fd, 0) != -EACCES;
3288bf6cc7dcSmrg}
3289bf6cc7dcSmrg
32906260e5d5Smrgdrm_public char *drmGetDeviceNameFromFd(int fd)
329122944501Smrg{
329287bf8e7cSmrg#ifdef __FreeBSD__
329387bf8e7cSmrg    struct stat sbuf;
329487bf8e7cSmrg    int maj, min;
329587bf8e7cSmrg    int nodetype;
329687bf8e7cSmrg
329787bf8e7cSmrg    if (fstat(fd, &sbuf))
329887bf8e7cSmrg        return NULL;
329987bf8e7cSmrg
330087bf8e7cSmrg    maj = major(sbuf.st_rdev);
330187bf8e7cSmrg    min = minor(sbuf.st_rdev);
330287bf8e7cSmrg    nodetype = drmGetMinorType(maj, min);
330387bf8e7cSmrg    return drmGetMinorNameForFD(fd, nodetype);
330487bf8e7cSmrg#else
3305fe517fc9Smrg    char name[128];
3306fe517fc9Smrg    struct stat sbuf;
3307fe517fc9Smrg    dev_t d;
3308fe517fc9Smrg    int i;
330922944501Smrg
3310fe517fc9Smrg    /* The whole drmOpen thing is a fiasco and we need to find a way
3311fe517fc9Smrg     * back to just using open(2).  For now, however, lets just make
3312fe517fc9Smrg     * things worse with even more ad hoc directory walking code to
3313fe517fc9Smrg     * discover the device file name. */
331422944501Smrg
3315fe517fc9Smrg    fstat(fd, &sbuf);
3316fe517fc9Smrg    d = sbuf.st_rdev;
331722944501Smrg
3318fe517fc9Smrg    for (i = 0; i < DRM_MAX_MINOR; i++) {
3319fe517fc9Smrg        snprintf(name, sizeof name, DRM_DEV_NAME, DRM_DIR_NAME, i);
3320fe517fc9Smrg        if (stat(name, &sbuf) == 0 && sbuf.st_rdev == d)
3321fe517fc9Smrg            break;
3322fe517fc9Smrg    }
3323fe517fc9Smrg    if (i == DRM_MAX_MINOR)
3324fe517fc9Smrg        return NULL;
332522944501Smrg
3326fe517fc9Smrg    return strdup(name);
332787bf8e7cSmrg#endif
332822944501Smrg}
332920131375Smrg
33306260e5d5Smrgstatic bool drmNodeIsDRM(int maj, int min)
33316260e5d5Smrg{
33326260e5d5Smrg#ifdef __linux__
33336260e5d5Smrg    char path[64];
33346260e5d5Smrg    struct stat sbuf;
33356260e5d5Smrg
33366260e5d5Smrg    snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device/drm",
33376260e5d5Smrg             maj, min);
33386260e5d5Smrg    return stat(path, &sbuf) == 0;
33394b3d3f37Smrg#elif defined(__FreeBSD__)
334087bf8e7cSmrg    char name[SPECNAMELEN];
334187bf8e7cSmrg
334287bf8e7cSmrg    if (!devname_r(makedev(maj, min), S_IFCHR, name, sizeof(name)))
334387bf8e7cSmrg      return 0;
334487bf8e7cSmrg    /* Handle drm/ and dri/ as both are present in different FreeBSD version
334587bf8e7cSmrg     * FreeBSD on amd64/i386/powerpc external kernel modules create node in
334687bf8e7cSmrg     * in /dev/drm/ and links in /dev/dri while a WIP in kernel driver creates
334787bf8e7cSmrg     * only device nodes in /dev/dri/ */
334887bf8e7cSmrg    return (!strncmp(name, "drm/", 4) || !strncmp(name, "dri/", 4));
33496260e5d5Smrg#else
33506260e5d5Smrg    return maj == DRM_MAJOR;
33516260e5d5Smrg#endif
33526260e5d5Smrg}
33536260e5d5Smrg
33546260e5d5Smrgdrm_public int drmGetNodeTypeFromFd(int fd)
3355424e9256Smrg{
3356fe517fc9Smrg    struct stat sbuf;
3357fe517fc9Smrg    int maj, min, type;
3358424e9256Smrg
3359fe517fc9Smrg    if (fstat(fd, &sbuf))
3360fe517fc9Smrg        return -1;
3361424e9256Smrg
3362fe517fc9Smrg    maj = major(sbuf.st_rdev);
3363fe517fc9Smrg    min = minor(sbuf.st_rdev);
3364424e9256Smrg
33656260e5d5Smrg    if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode)) {
3366fe517fc9Smrg        errno = EINVAL;
3367fe517fc9Smrg        return -1;
3368fe517fc9Smrg    }
3369424e9256Smrg
337087bf8e7cSmrg    type = drmGetMinorType(maj, min);
3371fe517fc9Smrg    if (type == -1)
3372fe517fc9Smrg        errno = ENODEV;
3373fe517fc9Smrg    return type;
3374424e9256Smrg}
3375424e9256Smrg
33766260e5d5Smrgdrm_public int drmPrimeHandleToFD(int fd, uint32_t handle, uint32_t flags,
33776260e5d5Smrg                                  int *prime_fd)
337820131375Smrg{
3379fe517fc9Smrg    struct drm_prime_handle args;
3380fe517fc9Smrg    int ret;
338120131375Smrg
3382fe517fc9Smrg    memclear(args);
3383fe517fc9Smrg    args.fd = -1;
3384fe517fc9Smrg    args.handle = handle;
3385fe517fc9Smrg    args.flags = flags;
3386fe517fc9Smrg    ret = drmIoctl(fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &args);
3387fe517fc9Smrg    if (ret)
3388fe517fc9Smrg        return ret;
338920131375Smrg
3390fe517fc9Smrg    *prime_fd = args.fd;
3391fe517fc9Smrg    return 0;
339220131375Smrg}
339320131375Smrg
33946260e5d5Smrgdrm_public int drmPrimeFDToHandle(int fd, int prime_fd, uint32_t *handle)
339520131375Smrg{
3396fe517fc9Smrg    struct drm_prime_handle args;
3397fe517fc9Smrg    int ret;
339820131375Smrg
3399fe517fc9Smrg    memclear(args);
3400fe517fc9Smrg    args.fd = prime_fd;
3401fe517fc9Smrg    ret = drmIoctl(fd, DRM_IOCTL_PRIME_FD_TO_HANDLE, &args);
3402fe517fc9Smrg    if (ret)
3403fe517fc9Smrg        return ret;
340420131375Smrg
3405fe517fc9Smrg    *handle = args.handle;
3406fe517fc9Smrg    return 0;
340720131375Smrg}
3408424e9256Smrg
3409adfa0b0cSmrgdrm_public int drmCloseBufferHandle(int fd, uint32_t handle)
3410adfa0b0cSmrg{
3411adfa0b0cSmrg    struct drm_gem_close args;
3412adfa0b0cSmrg
3413adfa0b0cSmrg    memclear(args);
3414adfa0b0cSmrg    args.handle = handle;
3415adfa0b0cSmrg    return drmIoctl(fd, DRM_IOCTL_GEM_CLOSE, &args);
3416adfa0b0cSmrg}
3417adfa0b0cSmrg
3418424e9256Smrgstatic char *drmGetMinorNameForFD(int fd, int type)
3419424e9256Smrg{
3420424e9256Smrg#ifdef __linux__
3421fe517fc9Smrg    DIR *sysdir;
34226260e5d5Smrg    struct dirent *ent;
3423fe517fc9Smrg    struct stat sbuf;
3424fe517fc9Smrg    const char *name = drmGetMinorName(type);
3425fe517fc9Smrg    int len;
3426fe517fc9Smrg    char dev_name[64], buf[64];
3427fe517fc9Smrg    int maj, min;
3428fe517fc9Smrg
3429fe517fc9Smrg    if (!name)
3430fe517fc9Smrg        return NULL;
3431424e9256Smrg
3432fe517fc9Smrg    len = strlen(name);
3433424e9256Smrg
3434fe517fc9Smrg    if (fstat(fd, &sbuf))
3435fe517fc9Smrg        return NULL;
3436424e9256Smrg
3437fe517fc9Smrg    maj = major(sbuf.st_rdev);
3438fe517fc9Smrg    min = minor(sbuf.st_rdev);
3439424e9256Smrg
34406260e5d5Smrg    if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode))
3441fe517fc9Smrg        return NULL;
3442424e9256Smrg
3443fe517fc9Smrg    snprintf(buf, sizeof(buf), "/sys/dev/char/%d:%d/device/drm", maj, min);
3444424e9256Smrg
3445fe517fc9Smrg    sysdir = opendir(buf);
3446fe517fc9Smrg    if (!sysdir)
3447fe517fc9Smrg        return NULL;
3448424e9256Smrg
34496260e5d5Smrg    while ((ent = readdir(sysdir))) {
3450fe517fc9Smrg        if (strncmp(ent->d_name, name, len) == 0) {
3451adfa0b0cSmrg            if (snprintf(dev_name, sizeof(dev_name), DRM_DIR_NAME "/%s",
3452adfa0b0cSmrg                        ent->d_name) < 0)
3453adfa0b0cSmrg                return NULL;
3454424e9256Smrg
3455fe517fc9Smrg            closedir(sysdir);
3456fe517fc9Smrg            return strdup(dev_name);
3457fe517fc9Smrg        }
3458fe517fc9Smrg    }
3459424e9256Smrg
3460fe517fc9Smrg    closedir(sysdir);
34616260e5d5Smrg    return NULL;
34624b3d3f37Smrg#elif defined(__FreeBSD__)
346387bf8e7cSmrg    struct stat sbuf;
346487bf8e7cSmrg    char dname[SPECNAMELEN];
346587bf8e7cSmrg    const char *mname;
346687bf8e7cSmrg    char name[SPECNAMELEN];
346787bf8e7cSmrg    int id, maj, min, nodetype, i;
346887bf8e7cSmrg
346987bf8e7cSmrg    if (fstat(fd, &sbuf))
347087bf8e7cSmrg        return NULL;
347187bf8e7cSmrg
347287bf8e7cSmrg    maj = major(sbuf.st_rdev);
347387bf8e7cSmrg    min = minor(sbuf.st_rdev);
347487bf8e7cSmrg
347587bf8e7cSmrg    if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode))
347687bf8e7cSmrg        return NULL;
347787bf8e7cSmrg
347887bf8e7cSmrg    if (!devname_r(sbuf.st_rdev, S_IFCHR, dname, sizeof(dname)))
347987bf8e7cSmrg        return NULL;
348087bf8e7cSmrg
348187bf8e7cSmrg    /* Handle both /dev/drm and /dev/dri
348287bf8e7cSmrg     * FreeBSD on amd64/i386/powerpc external kernel modules create node in
348387bf8e7cSmrg     * in /dev/drm/ and links in /dev/dri while a WIP in kernel driver creates
348487bf8e7cSmrg     * only device nodes in /dev/dri/ */
348587bf8e7cSmrg
348687bf8e7cSmrg    /* Get the node type represented by fd so we can deduce the target name */
348787bf8e7cSmrg    nodetype = drmGetMinorType(maj, min);
348887bf8e7cSmrg    if (nodetype == -1)
348987bf8e7cSmrg        return (NULL);
349087bf8e7cSmrg    mname = drmGetMinorName(type);
349187bf8e7cSmrg
349287bf8e7cSmrg    for (i = 0; i < SPECNAMELEN; i++) {
349387bf8e7cSmrg        if (isalpha(dname[i]) == 0 && dname[i] != '/')
349487bf8e7cSmrg           break;
349587bf8e7cSmrg    }
349687bf8e7cSmrg    if (dname[i] == '\0')
349787bf8e7cSmrg        return (NULL);
349887bf8e7cSmrg
349987bf8e7cSmrg    id = (int)strtol(&dname[i], NULL, 10);
350087bf8e7cSmrg    id -= drmGetMinorBase(nodetype);
350187bf8e7cSmrg    snprintf(name, sizeof(name), DRM_DIR_NAME "/%s%d", mname,
350287bf8e7cSmrg         id + drmGetMinorBase(type));
350387bf8e7cSmrg
350487bf8e7cSmrg    return strdup(name);
3505fe517fc9Smrg#else
35062ee35494Smrg    struct stat sbuf;
35072ee35494Smrg    char buf[PATH_MAX + 1];
350882025ec7Smrg    const char *dev_name = drmGetDeviceName(type);
35092ee35494Smrg    unsigned int maj, min;
351082025ec7Smrg    int n;
35112ee35494Smrg
35122ee35494Smrg    if (fstat(fd, &sbuf))
35132ee35494Smrg        return NULL;
35142ee35494Smrg
35152ee35494Smrg    maj = major(sbuf.st_rdev);
35162ee35494Smrg    min = minor(sbuf.st_rdev);
35172ee35494Smrg
35186260e5d5Smrg    if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode))
35192ee35494Smrg        return NULL;
35202ee35494Smrg
352182025ec7Smrg    if (!dev_name)
35222ee35494Smrg        return NULL;
35232ee35494Smrg
352482025ec7Smrg    n = snprintf(buf, sizeof(buf), dev_name, DRM_DIR_NAME, min);
35252ee35494Smrg    if (n == -1 || n >= sizeof(buf))
35262ee35494Smrg        return NULL;
35272ee35494Smrg
35282ee35494Smrg    return strdup(buf);
3529424e9256Smrg#endif
3530424e9256Smrg}
3531424e9256Smrg
35326260e5d5Smrgdrm_public char *drmGetPrimaryDeviceNameFromFd(int fd)
3533424e9256Smrg{
3534fe517fc9Smrg    return drmGetMinorNameForFD(fd, DRM_NODE_PRIMARY);
3535424e9256Smrg}
3536424e9256Smrg
35376260e5d5Smrgdrm_public char *drmGetRenderDeviceNameFromFd(int fd)
3538424e9256Smrg{
3539fe517fc9Smrg    return drmGetMinorNameForFD(fd, DRM_NODE_RENDER);
3540fe517fc9Smrg}
3541fe517fc9Smrg
35422ee35494Smrg#ifdef __linux__
35432ee35494Smrgstatic char * DRM_PRINTFLIKE(2, 3)
35442ee35494Smrgsysfs_uevent_get(const char *path, const char *fmt, ...)
35452ee35494Smrg{
35462ee35494Smrg    char filename[PATH_MAX + 1], *key, *line = NULL, *value = NULL;
35472ee35494Smrg    size_t size = 0, len;
35482ee35494Smrg    ssize_t num;
35492ee35494Smrg    va_list ap;
35502ee35494Smrg    FILE *fp;
35512ee35494Smrg
35522ee35494Smrg    va_start(ap, fmt);
35532ee35494Smrg    num = vasprintf(&key, fmt, ap);
35542ee35494Smrg    va_end(ap);
35552ee35494Smrg    len = num;
35562ee35494Smrg
35572ee35494Smrg    snprintf(filename, sizeof(filename), "%s/uevent", path);
35582ee35494Smrg
35592ee35494Smrg    fp = fopen(filename, "r");
35602ee35494Smrg    if (!fp) {
35612ee35494Smrg        free(key);
35622ee35494Smrg        return NULL;
35632ee35494Smrg    }
35642ee35494Smrg
35652ee35494Smrg    while ((num = getline(&line, &size, fp)) >= 0) {
35662ee35494Smrg        if ((strncmp(line, key, len) == 0) && (line[len] == '=')) {
35672ee35494Smrg            char *start = line + len + 1, *end = line + num - 1;
35682ee35494Smrg
35692ee35494Smrg            if (*end != '\n')
35702ee35494Smrg                end++;
35712ee35494Smrg
35722ee35494Smrg            value = strndup(start, end - start);
35732ee35494Smrg            break;
35742ee35494Smrg        }
35752ee35494Smrg    }
35762ee35494Smrg
35772ee35494Smrg    free(line);
35782ee35494Smrg    fclose(fp);
35792ee35494Smrg
35802ee35494Smrg    free(key);
35812ee35494Smrg
35822ee35494Smrg    return value;
35832ee35494Smrg}
35842ee35494Smrg#endif
35852ee35494Smrg
35866260e5d5Smrg/* Little white lie to avoid major rework of the existing code */
35876260e5d5Smrg#define DRM_BUS_VIRTIO 0x10
35886260e5d5Smrg
3589fe517fc9Smrg#ifdef __linux__
359087bf8e7cSmrgstatic int get_subsystem_type(const char *device_path)
359187bf8e7cSmrg{
359287bf8e7cSmrg    char path[PATH_MAX + 1] = "";
3593fe517fc9Smrg    char link[PATH_MAX + 1] = "";
3594fe517fc9Smrg    char *name;
35954545e80cSmrg    struct {
35964545e80cSmrg        const char *name;
35974545e80cSmrg        int bus_type;
35984545e80cSmrg    } bus_types[] = {
35994545e80cSmrg        { "/pci", DRM_BUS_PCI },
36004545e80cSmrg        { "/usb", DRM_BUS_USB },
36014545e80cSmrg        { "/platform", DRM_BUS_PLATFORM },
36024545e80cSmrg        { "/spi", DRM_BUS_PLATFORM },
36034545e80cSmrg        { "/host1x", DRM_BUS_HOST1X },
36044545e80cSmrg        { "/virtio", DRM_BUS_VIRTIO },
36054545e80cSmrg    };
3606fe517fc9Smrg
360787bf8e7cSmrg    strncpy(path, device_path, PATH_MAX);
360887bf8e7cSmrg    strncat(path, "/subsystem", PATH_MAX);
3609fe517fc9Smrg
3610fe517fc9Smrg    if (readlink(path, link, PATH_MAX) < 0)
3611fe517fc9Smrg        return -errno;
3612fe517fc9Smrg
3613fe517fc9Smrg    name = strrchr(link, '/');
3614fe517fc9Smrg    if (!name)
3615fe517fc9Smrg        return -EINVAL;
3616fe517fc9Smrg
36174545e80cSmrg    for (unsigned i = 0; i < ARRAY_SIZE(bus_types); i++) {
36184545e80cSmrg        if (strncmp(name, bus_types[i].name, strlen(bus_types[i].name)) == 0)
36194545e80cSmrg            return bus_types[i].bus_type;
36204545e80cSmrg    }
36216260e5d5Smrg
3622fe517fc9Smrg    return -EINVAL;
362387bf8e7cSmrg}
362487bf8e7cSmrg#endif
362587bf8e7cSmrg
362687bf8e7cSmrgstatic int drmParseSubsystemType(int maj, int min)
362787bf8e7cSmrg{
362887bf8e7cSmrg#ifdef __linux__
362987bf8e7cSmrg    char path[PATH_MAX + 1] = "";
363087bf8e7cSmrg    char real_path[PATH_MAX + 1] = "";
363187bf8e7cSmrg    int subsystem_type;
363287bf8e7cSmrg
363387bf8e7cSmrg    snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min);
363487bf8e7cSmrg
363587bf8e7cSmrg    subsystem_type = get_subsystem_type(path);
363687bf8e7cSmrg    /* Try to get the parent (underlying) device type */
363787bf8e7cSmrg    if (subsystem_type == DRM_BUS_VIRTIO) {
363887bf8e7cSmrg        /* Assume virtio-pci on error */
363987bf8e7cSmrg        if (!realpath(path, real_path))
364087bf8e7cSmrg            return DRM_BUS_VIRTIO;
364187bf8e7cSmrg        strncat(path, "/..", PATH_MAX);
364287bf8e7cSmrg        subsystem_type = get_subsystem_type(path);
364387bf8e7cSmrg        if (subsystem_type < 0)
364487bf8e7cSmrg            return DRM_BUS_VIRTIO;
364587bf8e7cSmrg     }
3646a970b457Sriastradh#elif defined(__NetBSD__)
3647a970b457Sriastradh    int type, fd;
3648a970b457Sriastradh    drmSetVersion sv;
3649a970b457Sriastradh    char *buf;
3650a970b457Sriastradh    unsigned domain, bus, dev;
3651a970b457Sriastradh    int func;
3652a970b457Sriastradh    int ret;
3653a970b457Sriastradh
3654a970b457Sriastradh    /* Get the type of device we're looking for to pick the right pathname.  */
365577e87e13Smrg    type = drmGetMinorType(maj, min);
3656a970b457Sriastradh    if (type == -1)
3657a970b457Sriastradh	return -ENODEV;
3658a970b457Sriastradh
3659a970b457Sriastradh    /* Open the device.  Don't try to create it if it's not there.  */
3660a970b457Sriastradh    fd = drmOpenMinor(min, 0, type);
3661a970b457Sriastradh    if (fd < 0)
3662a970b457Sriastradh	return -errno;
3663a970b457Sriastradh
3664a970b457Sriastradh    /*
3665a970b457Sriastradh     * Set the interface version to 1.4 or 1.1, which has the effect of
3666a970b457Sriastradh     * populating the bus id for us.
3667a970b457Sriastradh     */
3668a970b457Sriastradh    sv.drm_di_major = 1;
3669a970b457Sriastradh    sv.drm_di_minor = 4;
3670a970b457Sriastradh    sv.drm_dd_major = -1;
3671a970b457Sriastradh    sv.drm_dd_minor = -1;
3672a970b457Sriastradh    if (drmSetInterfaceVersion(fd, &sv)) {
3673a970b457Sriastradh	sv.drm_di_major = 1;
3674a970b457Sriastradh	sv.drm_di_minor = 1;
3675a970b457Sriastradh	sv.drm_dd_major = -1;
3676a970b457Sriastradh	sv.drm_dd_minor = -1;
3677a970b457Sriastradh	if (drmSetInterfaceVersion(fd, &sv)) {
36785046d36bSriastradh	    /*
36795046d36bSriastradh	     * We're probably not the master.  Hope the master already
36805046d36bSriastradh	     * set the version to >=1.1 so that we can get the busid.
36815046d36bSriastradh	     */
3682a970b457Sriastradh	}
3683a970b457Sriastradh    }
3684a970b457Sriastradh
3685a970b457Sriastradh    /* Get the bus id.  */
3686a970b457Sriastradh    buf = drmGetBusid(fd);
3687a970b457Sriastradh
3688a970b457Sriastradh    /* We're done with the device now.  */
3689a970b457Sriastradh    (void)close(fd);
3690a970b457Sriastradh
3691a970b457Sriastradh    /* If there is no bus id, fail.  */
3692a970b457Sriastradh    if (buf == NULL)
3693a970b457Sriastradh	return -ENODEV;
3694a970b457Sriastradh
3695a970b457Sriastradh    /* Find a string we know about; otherwise -EINVAL.  */
3696a970b457Sriastradh    ret = -EINVAL;
369748994cb0Sriastradh    if (strncmp(buf, "pci:", 4) == 0)
3698a970b457Sriastradh	ret = DRM_BUS_PCI;
3699a970b457Sriastradh
3700a970b457Sriastradh    /* We're done with the bus id.  */
3701a970b457Sriastradh    free(buf);
3702a970b457Sriastradh
3703a970b457Sriastradh    /* Success or not, we're done.  */
3704a970b457Sriastradh    return ret;
37054545e80cSmrg#elif defined(__OpenBSD__) || defined(__DragonFly__)
37062ee35494Smrg    return DRM_BUS_PCI;
3707fe517fc9Smrg#else
3708fe517fc9Smrg#warning "Missing implementation of drmParseSubsystemType"
3709fe517fc9Smrg    return -EINVAL;
3710fe517fc9Smrg#endif
3711fe517fc9Smrg}
3712fe517fc9Smrg
371387bf8e7cSmrg#ifdef __linux__
37146260e5d5Smrgstatic void
37156260e5d5Smrgget_pci_path(int maj, int min, char *pci_path)
37166260e5d5Smrg{
37176260e5d5Smrg    char path[PATH_MAX + 1], *term;
37186260e5d5Smrg
37196260e5d5Smrg    snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min);
37206260e5d5Smrg    if (!realpath(path, pci_path)) {
37216260e5d5Smrg        strcpy(pci_path, path);
37226260e5d5Smrg        return;
37236260e5d5Smrg    }
37246260e5d5Smrg
37256260e5d5Smrg    term = strrchr(pci_path, '/');
37266260e5d5Smrg    if (term && strncmp(term, "/virtio", 7) == 0)
37276260e5d5Smrg        *term = 0;
37286260e5d5Smrg}
372987bf8e7cSmrg#endif
373087bf8e7cSmrg
373187bf8e7cSmrg#ifdef __FreeBSD__
373287bf8e7cSmrgstatic int get_sysctl_pci_bus_info(int maj, int min, drmPciBusInfoPtr info)
373387bf8e7cSmrg{
373487bf8e7cSmrg    char dname[SPECNAMELEN];
373587bf8e7cSmrg    char sysctl_name[16];
373687bf8e7cSmrg    char sysctl_val[256];
373787bf8e7cSmrg    size_t sysctl_len;
373887bf8e7cSmrg    int id, type, nelem;
373987bf8e7cSmrg    unsigned int rdev, majmin, domain, bus, dev, func;
374087bf8e7cSmrg
374187bf8e7cSmrg    rdev = makedev(maj, min);
374287bf8e7cSmrg    if (!devname_r(rdev, S_IFCHR, dname, sizeof(dname)))
374387bf8e7cSmrg      return -EINVAL;
374487bf8e7cSmrg
374587bf8e7cSmrg    if (sscanf(dname, "drm/%d\n", &id) != 1)
374687bf8e7cSmrg        return -EINVAL;
374787bf8e7cSmrg    type = drmGetMinorType(maj, min);
374887bf8e7cSmrg    if (type == -1)
374987bf8e7cSmrg        return -EINVAL;
375087bf8e7cSmrg
375187bf8e7cSmrg    /* BUG: This above section is iffy, since it mandates that a driver will
375287bf8e7cSmrg     * create both card and render node.
375387bf8e7cSmrg     * If it does not, the next DRM device will create card#X and
375487bf8e7cSmrg     * renderD#(128+X)-1.
375587bf8e7cSmrg     * This is a possibility in FreeBSD but for now there is no good way for
375687bf8e7cSmrg     * obtaining the info.
375787bf8e7cSmrg     */
375887bf8e7cSmrg    switch (type) {
375987bf8e7cSmrg    case DRM_NODE_PRIMARY:
376087bf8e7cSmrg         break;
376187bf8e7cSmrg    case DRM_NODE_RENDER:
376287bf8e7cSmrg         id -= 128;
376348246ce7Smrg         break;
376487bf8e7cSmrg    }
376587bf8e7cSmrg    if (id < 0)
376687bf8e7cSmrg        return -EINVAL;
376787bf8e7cSmrg
376887bf8e7cSmrg    if (snprintf(sysctl_name, sizeof(sysctl_name), "hw.dri.%d.busid", id) <= 0)
376987bf8e7cSmrg      return -EINVAL;
377087bf8e7cSmrg    sysctl_len = sizeof(sysctl_val);
377187bf8e7cSmrg    if (sysctlbyname(sysctl_name, sysctl_val, &sysctl_len, NULL, 0))
377287bf8e7cSmrg      return -EINVAL;
377387bf8e7cSmrg
377487bf8e7cSmrg    #define bus_fmt "pci:%04x:%02x:%02x.%u"
377587bf8e7cSmrg
377687bf8e7cSmrg    nelem = sscanf(sysctl_val, bus_fmt, &domain, &bus, &dev, &func);
377787bf8e7cSmrg    if (nelem != 4)
377887bf8e7cSmrg      return -EINVAL;
377987bf8e7cSmrg    info->domain = domain;
378087bf8e7cSmrg    info->bus = bus;
378187bf8e7cSmrg    info->dev = dev;
378287bf8e7cSmrg    info->func = func;
378387bf8e7cSmrg
378487bf8e7cSmrg    return 0;
378587bf8e7cSmrg}
378687bf8e7cSmrg#endif
37876260e5d5Smrg
3788fe517fc9Smrgstatic int drmParsePciBusInfo(int maj, int min, drmPciBusInfoPtr info)
3789fe517fc9Smrg{
3790fe517fc9Smrg#ifdef __linux__
37912ee35494Smrg    unsigned int domain, bus, dev, func;
37926260e5d5Smrg    char pci_path[PATH_MAX + 1], *value;
37932ee35494Smrg    int num;
3794fe517fc9Smrg
37956260e5d5Smrg    get_pci_path(maj, min, pci_path);
3796fe517fc9Smrg
37976260e5d5Smrg    value = sysfs_uevent_get(pci_path, "PCI_SLOT_NAME");
37982ee35494Smrg    if (!value)
37992ee35494Smrg        return -ENOENT;
3800fe517fc9Smrg
38012ee35494Smrg    num = sscanf(value, "%04x:%02x:%02x.%1u", &domain, &bus, &dev, &func);
38022ee35494Smrg    free(value);
3803fe517fc9Smrg
38042ee35494Smrg    if (num != 4)
3805fe517fc9Smrg        return -EINVAL;
3806fe517fc9Smrg
3807fe517fc9Smrg    info->domain = domain;
3808fe517fc9Smrg    info->bus = bus;
3809fe517fc9Smrg    info->dev = dev;
3810fe517fc9Smrg    info->func = func;
3811fe517fc9Smrg
3812a970b457Sriastradh    return 0;
3813a970b457Sriastradh#elif defined(__NetBSD__)
3814a970b457Sriastradh    int type, fd;
3815a970b457Sriastradh    drmSetVersion sv;
3816a970b457Sriastradh    char *buf;
3817a970b457Sriastradh    unsigned domain, bus, dev;
3818a970b457Sriastradh    int func;
3819a970b457Sriastradh    int ret;
3820a970b457Sriastradh
3821a970b457Sriastradh    /* Get the type of device we're looking for to pick the right pathname.  */
382277e87e13Smrg    type = drmGetMinorType(maj, min);
3823a970b457Sriastradh    if (type == -1)
3824a970b457Sriastradh	return -ENODEV;
3825a970b457Sriastradh
3826a970b457Sriastradh    /* Open the device.  Don't try to create it if it's not there.  */
3827a970b457Sriastradh    fd = drmOpenMinor(min, 0, type);
3828a970b457Sriastradh    if (fd < 0)
3829a970b457Sriastradh	return -errno;
3830a970b457Sriastradh
3831a970b457Sriastradh    /*
3832a970b457Sriastradh     * Set the interface version to 1.4 or 1.1, which has the effect of
3833a970b457Sriastradh     * populating the bus id for us.
3834a970b457Sriastradh     */
3835a970b457Sriastradh    sv.drm_di_major = 1;
3836a970b457Sriastradh    sv.drm_di_minor = 4;
3837a970b457Sriastradh    sv.drm_dd_major = -1;
3838a970b457Sriastradh    sv.drm_dd_minor = -1;
3839a970b457Sriastradh    if (drmSetInterfaceVersion(fd, &sv)) {
3840a970b457Sriastradh	sv.drm_di_major = 1;
3841a970b457Sriastradh	sv.drm_di_minor = 1;
3842a970b457Sriastradh	sv.drm_dd_major = -1;
3843a970b457Sriastradh	sv.drm_dd_minor = -1;
3844a970b457Sriastradh	if (drmSetInterfaceVersion(fd, &sv)) {
384506815bcbSmaya            /*
384606815bcbSmaya	     * We're probably not the master.  Hope the master already
384706815bcbSmaya	     * set the version to >=1.1 so that we can get the busid.
384806815bcbSmaya	     */
3849a970b457Sriastradh	}
3850a970b457Sriastradh    }
3851a970b457Sriastradh
3852a970b457Sriastradh    /* Get the bus id.  */
3853a970b457Sriastradh    buf = drmGetBusid(fd);
3854a970b457Sriastradh
3855a970b457Sriastradh    /* We're done with the device now.  */
3856a970b457Sriastradh    (void)close(fd);
3857a970b457Sriastradh
3858a970b457Sriastradh    /* If there is no bus id, fail.  */
3859a970b457Sriastradh    if (buf == NULL)
3860a970b457Sriastradh	return -ENODEV;
3861a970b457Sriastradh
3862a970b457Sriastradh    /* Parse the bus id.  */
3863a970b457Sriastradh    ret = sscanf(buf, "pci:%04x:%02x:%02x.%d", &domain, &bus, &dev, &func);
3864a970b457Sriastradh
3865a970b457Sriastradh    /* We're done with the bus id.  */
3866a970b457Sriastradh    free(buf);
3867a970b457Sriastradh
3868a970b457Sriastradh    /* If scanf didn't return 4 -- domain, bus, dev, func -- then fail.  */
3869a970b457Sriastradh    if (ret != 4)
3870a970b457Sriastradh	return -ENODEV;
3871a970b457Sriastradh
3872a970b457Sriastradh    /* Populate the results.  */
3873a970b457Sriastradh    info->domain = domain;
3874a970b457Sriastradh    info->bus = bus;
3875a970b457Sriastradh    info->dev = dev;
3876a970b457Sriastradh    info->func = func;
3877a970b457Sriastradh
3878a970b457Sriastradh    /* Success!  */
38792ee35494Smrg    return 0;
38804545e80cSmrg#elif defined(__OpenBSD__) || defined(__DragonFly__)
38812ee35494Smrg    struct drm_pciinfo pinfo;
38822ee35494Smrg    int fd, type;
38832ee35494Smrg
388487bf8e7cSmrg    type = drmGetMinorType(maj, min);
38852ee35494Smrg    if (type == -1)
38862ee35494Smrg        return -ENODEV;
38872ee35494Smrg
38882ee35494Smrg    fd = drmOpenMinor(min, 0, type);
38892ee35494Smrg    if (fd < 0)
38902ee35494Smrg        return -errno;
38912ee35494Smrg
38922ee35494Smrg    if (drmIoctl(fd, DRM_IOCTL_GET_PCIINFO, &pinfo)) {
38932ee35494Smrg        close(fd);
38942ee35494Smrg        return -errno;
38952ee35494Smrg    }
38962ee35494Smrg    close(fd);
38972ee35494Smrg
38982ee35494Smrg    info->domain = pinfo.domain;
38992ee35494Smrg    info->bus = pinfo.bus;
39002ee35494Smrg    info->dev = pinfo.dev;
39012ee35494Smrg    info->func = pinfo.func;
39022ee35494Smrg
3903fe517fc9Smrg    return 0;
39044b3d3f37Smrg#elif defined(__FreeBSD__)
390587bf8e7cSmrg    return get_sysctl_pci_bus_info(maj, min, info);
3906fe517fc9Smrg#else
3907fe517fc9Smrg#warning "Missing implementation of drmParsePciBusInfo"
3908fe517fc9Smrg    return -EINVAL;
3909fe517fc9Smrg#endif
3910fe517fc9Smrg}
3911fe517fc9Smrg
39126260e5d5Smrgdrm_public int drmDevicesEqual(drmDevicePtr a, drmDevicePtr b)
3913fe517fc9Smrg{
3914fe517fc9Smrg    if (a == NULL || b == NULL)
39150655efefSmrg        return 0;
3916fe517fc9Smrg
3917fe517fc9Smrg    if (a->bustype != b->bustype)
39180655efefSmrg        return 0;
3919fe517fc9Smrg
3920fe517fc9Smrg    switch (a->bustype) {
3921fe517fc9Smrg    case DRM_BUS_PCI:
39220655efefSmrg        return memcmp(a->businfo.pci, b->businfo.pci, sizeof(drmPciBusInfo)) == 0;
39232ee35494Smrg
39242ee35494Smrg    case DRM_BUS_USB:
39250655efefSmrg        return memcmp(a->businfo.usb, b->businfo.usb, sizeof(drmUsbBusInfo)) == 0;
39262ee35494Smrg
39272ee35494Smrg    case DRM_BUS_PLATFORM:
39280655efefSmrg        return memcmp(a->businfo.platform, b->businfo.platform, sizeof(drmPlatformBusInfo)) == 0;
39292ee35494Smrg
39302ee35494Smrg    case DRM_BUS_HOST1X:
39310655efefSmrg        return memcmp(a->businfo.host1x, b->businfo.host1x, sizeof(drmHost1xBusInfo)) == 0;
39322ee35494Smrg
3933fe517fc9Smrg    default:
3934fe517fc9Smrg        break;
3935fe517fc9Smrg    }
3936fe517fc9Smrg
39370655efefSmrg    return 0;
3938fe517fc9Smrg}
3939fe517fc9Smrg
3940fe517fc9Smrgstatic int drmGetNodeType(const char *name)
3941fe517fc9Smrg{
3942fe517fc9Smrg    if (strncmp(name, DRM_RENDER_MINOR_NAME,
3943fe517fc9Smrg        sizeof(DRM_RENDER_MINOR_NAME) - 1) == 0)
3944fe517fc9Smrg        return DRM_NODE_RENDER;
3945fe517fc9Smrg
394682025ec7Smrg    if (strncmp(name, DRM_PRIMARY_MINOR_NAME,
394782025ec7Smrg        sizeof(DRM_PRIMARY_MINOR_NAME) - 1) == 0)
394882025ec7Smrg        return DRM_NODE_PRIMARY;
394982025ec7Smrg
3950fe517fc9Smrg    return -EINVAL;
3951fe517fc9Smrg}
3952fe517fc9Smrg
3953fe517fc9Smrgstatic int drmGetMaxNodeName(void)
3954fe517fc9Smrg{
3955fe517fc9Smrg    return sizeof(DRM_DIR_NAME) +
3956fe517fc9Smrg           MAX3(sizeof(DRM_PRIMARY_MINOR_NAME),
3957fe517fc9Smrg                sizeof(DRM_CONTROL_MINOR_NAME),
3958fe517fc9Smrg                sizeof(DRM_RENDER_MINOR_NAME)) +
3959fe517fc9Smrg           3 /* length of the node number */;
3960fe517fc9Smrg}
3961fe517fc9Smrg
3962fe517fc9Smrg#ifdef __linux__
39632ee35494Smrgstatic int parse_separate_sysfs_files(int maj, int min,
39642ee35494Smrg                                      drmPciDeviceInfoPtr device,
39652ee35494Smrg                                      bool ignore_revision)
39662ee35494Smrg{
39672ee35494Smrg    static const char *attrs[] = {
39682ee35494Smrg      "revision", /* Older kernels are missing the file, so check for it first */
39692ee35494Smrg      "vendor",
39702ee35494Smrg      "device",
39712ee35494Smrg      "subsystem_vendor",
39722ee35494Smrg      "subsystem_device",
39732ee35494Smrg    };
39746260e5d5Smrg    char path[PATH_MAX + 1], pci_path[PATH_MAX + 1];
39752ee35494Smrg    unsigned int data[ARRAY_SIZE(attrs)];
39762ee35494Smrg    FILE *fp;
39772ee35494Smrg    int ret;
39782ee35494Smrg
39796260e5d5Smrg    get_pci_path(maj, min, pci_path);
39806260e5d5Smrg
39812ee35494Smrg    for (unsigned i = ignore_revision ? 1 : 0; i < ARRAY_SIZE(attrs); i++) {
3982adfa0b0cSmrg        if (snprintf(path, PATH_MAX, "%s/%s", pci_path, attrs[i]) < 0)
3983adfa0b0cSmrg            return -errno;
3984adfa0b0cSmrg
39852ee35494Smrg        fp = fopen(path, "r");
39862ee35494Smrg        if (!fp)
39872ee35494Smrg            return -errno;
39882ee35494Smrg
39892ee35494Smrg        ret = fscanf(fp, "%x", &data[i]);
39902ee35494Smrg        fclose(fp);
39912ee35494Smrg        if (ret != 1)
39922ee35494Smrg            return -errno;
39932ee35494Smrg
39942ee35494Smrg    }
39952ee35494Smrg
39962ee35494Smrg    device->revision_id = ignore_revision ? 0xff : data[0] & 0xff;
39972ee35494Smrg    device->vendor_id = data[1] & 0xffff;
39982ee35494Smrg    device->device_id = data[2] & 0xffff;
39992ee35494Smrg    device->subvendor_id = data[3] & 0xffff;
40002ee35494Smrg    device->subdevice_id = data[4] & 0xffff;
40012ee35494Smrg
40022ee35494Smrg    return 0;
40032ee35494Smrg}
40042ee35494Smrg
40052ee35494Smrgstatic int parse_config_sysfs_file(int maj, int min,
40062ee35494Smrg                                   drmPciDeviceInfoPtr device)
40072ee35494Smrg{
40086260e5d5Smrg    char path[PATH_MAX + 1], pci_path[PATH_MAX + 1];
4009fe517fc9Smrg    unsigned char config[64];
4010fe517fc9Smrg    int fd, ret;
4011fe517fc9Smrg
40126260e5d5Smrg    get_pci_path(maj, min, pci_path);
40136260e5d5Smrg
4014adfa0b0cSmrg    if (snprintf(path, PATH_MAX, "%s/config", pci_path) < 0)
4015adfa0b0cSmrg        return -errno;
4016adfa0b0cSmrg
4017fe517fc9Smrg    fd = open(path, O_RDONLY);
4018fe517fc9Smrg    if (fd < 0)
4019fe517fc9Smrg        return -errno;
4020fe517fc9Smrg
4021fe517fc9Smrg    ret = read(fd, config, sizeof(config));
4022fe517fc9Smrg    close(fd);
4023fe517fc9Smrg    if (ret < 0)
4024fe517fc9Smrg        return -errno;
4025fe517fc9Smrg
4026fe517fc9Smrg    device->vendor_id = config[0] | (config[1] << 8);
4027fe517fc9Smrg    device->device_id = config[2] | (config[3] << 8);
4028fe517fc9Smrg    device->revision_id = config[8];
4029fe517fc9Smrg    device->subvendor_id = config[44] | (config[45] << 8);
4030fe517fc9Smrg    device->subdevice_id = config[46] | (config[47] << 8);
4031fe517fc9Smrg
40322ee35494Smrg    return 0;
40332ee35494Smrg}
40342ee35494Smrg#endif
40352ee35494Smrg
40362ee35494Smrgstatic int drmParsePciDeviceInfo(int maj, int min,
40372ee35494Smrg                                 drmPciDeviceInfoPtr device,
40382ee35494Smrg                                 uint32_t flags)
40392ee35494Smrg{
40402ee35494Smrg#ifdef __linux__
40412ee35494Smrg    if (!(flags & DRM_DEVICE_GET_PCI_REVISION))
40422ee35494Smrg        return parse_separate_sysfs_files(maj, min, device, true);
40432ee35494Smrg
40442ee35494Smrg    if (parse_separate_sysfs_files(maj, min, device, false))
40452ee35494Smrg        return parse_config_sysfs_file(maj, min, device);
40462ee35494Smrg
40472ee35494Smrg    return 0;
4048a970b457Sriastradh#elif defined(__NetBSD__)
4049a970b457Sriastradh    drmPciBusInfo businfo;
4050a970b457Sriastradh    char fname[PATH_MAX];
4051a970b457Sriastradh    int pcifd;
4052a970b457Sriastradh    pcireg_t id, class, subsys;
4053a970b457Sriastradh    int ret;
4054a970b457Sriastradh
4055a970b457Sriastradh    /* Find where on the bus the device lives.  */
4056a970b457Sriastradh    ret = drmParsePciBusInfo(maj, min, &businfo);
4057a970b457Sriastradh    if (ret)
4058a970b457Sriastradh	return ret;
4059a970b457Sriastradh
4060a970b457Sriastradh    /* Open the pciN device node to get at its config registers.  */
4061a970b457Sriastradh    if (snprintf(fname, sizeof fname, "/dev/pci%u", businfo.domain)
4062a970b457Sriastradh	>= sizeof fname)
4063a970b457Sriastradh	return -ENODEV;
4064a970b457Sriastradh    if ((pcifd = open(fname, O_RDONLY)) == -1)
4065a970b457Sriastradh	return -errno;
4066a970b457Sriastradh
4067f8b67707Schristos    ret = -1;
4068a970b457Sriastradh    /* Read the id and class pci config registers.  */
4069a970b457Sriastradh    if (pcibus_conf_read(pcifd, businfo.bus, businfo.dev, businfo.func,
4070a970b457Sriastradh	    PCI_ID_REG, &id) == -1)
4071f8b67707Schristos	goto out;
4072a970b457Sriastradh    if (pcibus_conf_read(pcifd, businfo.bus, businfo.dev, businfo.func,
4073a970b457Sriastradh	    PCI_CLASS_REG, &class) == -1)
4074f8b67707Schristos	goto out;
4075a970b457Sriastradh    if (pcibus_conf_read(pcifd, businfo.bus, businfo.dev, businfo.func,
4076a970b457Sriastradh	    PCI_SUBSYS_ID_REG, &subsys) == -1)
4077f8b67707Schristos	goto out;
4078a970b457Sriastradh
4079f8b67707Schristos    ret = 0;
4080a970b457Sriastradh    device->vendor_id = PCI_VENDOR(id);
4081a970b457Sriastradh    device->device_id = PCI_PRODUCT(id);
4082a970b457Sriastradh    device->subvendor_id = PCI_SUBSYS_VENDOR(subsys);
4083a970b457Sriastradh    device->subdevice_id = PCI_SUBSYS_ID(subsys);
4084a970b457Sriastradh    device->revision_id = PCI_REVISION(class);
4085f8b67707Schristosout:
4086f8b67707Schristos    if (ret == -1)
4087f8b67707Schristos	ret = -errno;
4088f8b67707Schristos    close(pcifd);
4089f8b67707Schristos    return ret;
40904545e80cSmrg#elif defined(__OpenBSD__) || defined(__DragonFly__)
40912ee35494Smrg    struct drm_pciinfo pinfo;
40922ee35494Smrg    int fd, type;
40932ee35494Smrg
409487bf8e7cSmrg    type = drmGetMinorType(maj, min);
40952ee35494Smrg    if (type == -1)
40962ee35494Smrg        return -ENODEV;
40972ee35494Smrg
40982ee35494Smrg    fd = drmOpenMinor(min, 0, type);
40992ee35494Smrg    if (fd < 0)
41002ee35494Smrg        return -errno;
41012ee35494Smrg
41022ee35494Smrg    if (drmIoctl(fd, DRM_IOCTL_GET_PCIINFO, &pinfo)) {
41032ee35494Smrg        close(fd);
41042ee35494Smrg        return -errno;
41052ee35494Smrg    }
41062ee35494Smrg    close(fd);
41072ee35494Smrg
41082ee35494Smrg    device->vendor_id = pinfo.vendor_id;
41092ee35494Smrg    device->device_id = pinfo.device_id;
41102ee35494Smrg    device->revision_id = pinfo.revision_id;
41112ee35494Smrg    device->subvendor_id = pinfo.subvendor_id;
41122ee35494Smrg    device->subdevice_id = pinfo.subdevice_id;
41132ee35494Smrg
411487bf8e7cSmrg    return 0;
41154b3d3f37Smrg#elif defined(__FreeBSD__)
411687bf8e7cSmrg    drmPciBusInfo info;
411787bf8e7cSmrg    struct pci_conf_io pc;
411887bf8e7cSmrg    struct pci_match_conf patterns[1];
411987bf8e7cSmrg    struct pci_conf results[1];
412087bf8e7cSmrg    int fd, error;
412187bf8e7cSmrg
412287bf8e7cSmrg    if (get_sysctl_pci_bus_info(maj, min, &info) != 0)
412387bf8e7cSmrg        return -EINVAL;
412487bf8e7cSmrg
41253b115362Smrg    fd = open("/dev/pci", O_RDONLY);
412687bf8e7cSmrg    if (fd < 0)
412787bf8e7cSmrg        return -errno;
412887bf8e7cSmrg
412987bf8e7cSmrg    bzero(&patterns, sizeof(patterns));
413087bf8e7cSmrg    patterns[0].pc_sel.pc_domain = info.domain;
413187bf8e7cSmrg    patterns[0].pc_sel.pc_bus = info.bus;
413287bf8e7cSmrg    patterns[0].pc_sel.pc_dev = info.dev;
413387bf8e7cSmrg    patterns[0].pc_sel.pc_func = info.func;
413487bf8e7cSmrg    patterns[0].flags = PCI_GETCONF_MATCH_DOMAIN | PCI_GETCONF_MATCH_BUS
413587bf8e7cSmrg                      | PCI_GETCONF_MATCH_DEV | PCI_GETCONF_MATCH_FUNC;
413687bf8e7cSmrg    bzero(&pc, sizeof(struct pci_conf_io));
413787bf8e7cSmrg    pc.num_patterns = 1;
413887bf8e7cSmrg    pc.pat_buf_len = sizeof(patterns);
413987bf8e7cSmrg    pc.patterns = patterns;
414087bf8e7cSmrg    pc.match_buf_len = sizeof(results);
414187bf8e7cSmrg    pc.matches = results;
414287bf8e7cSmrg
414387bf8e7cSmrg    if (ioctl(fd, PCIOCGETCONF, &pc) || pc.status == PCI_GETCONF_ERROR) {
414487bf8e7cSmrg        error = errno;
414587bf8e7cSmrg        close(fd);
414687bf8e7cSmrg        return -error;
414787bf8e7cSmrg    }
414887bf8e7cSmrg    close(fd);
414987bf8e7cSmrg
415087bf8e7cSmrg    device->vendor_id = results[0].pc_vendor;
415187bf8e7cSmrg    device->device_id = results[0].pc_device;
415287bf8e7cSmrg    device->subvendor_id = results[0].pc_subvendor;
415387bf8e7cSmrg    device->subdevice_id = results[0].pc_subdevice;
415487bf8e7cSmrg    device->revision_id = results[0].pc_revid;
415587bf8e7cSmrg
4156fe517fc9Smrg    return 0;
4157fe517fc9Smrg#else
4158fe517fc9Smrg#warning "Missing implementation of drmParsePciDeviceInfo"
4159fe517fc9Smrg    return -EINVAL;
4160fe517fc9Smrg#endif
4161fe517fc9Smrg}
4162fe517fc9Smrg
41632ee35494Smrgstatic void drmFreePlatformDevice(drmDevicePtr device)
41642ee35494Smrg{
41652ee35494Smrg    if (device->deviceinfo.platform) {
41662ee35494Smrg        if (device->deviceinfo.platform->compatible) {
41672ee35494Smrg            char **compatible = device->deviceinfo.platform->compatible;
41682ee35494Smrg
41692ee35494Smrg            while (*compatible) {
41702ee35494Smrg                free(*compatible);
41712ee35494Smrg                compatible++;
41722ee35494Smrg            }
41732ee35494Smrg
41742ee35494Smrg            free(device->deviceinfo.platform->compatible);
41752ee35494Smrg        }
41762ee35494Smrg    }
41772ee35494Smrg}
41782ee35494Smrg
41792ee35494Smrgstatic void drmFreeHost1xDevice(drmDevicePtr device)
41802ee35494Smrg{
41812ee35494Smrg    if (device->deviceinfo.host1x) {
41822ee35494Smrg        if (device->deviceinfo.host1x->compatible) {
41832ee35494Smrg            char **compatible = device->deviceinfo.host1x->compatible;
41842ee35494Smrg
41852ee35494Smrg            while (*compatible) {
41862ee35494Smrg                free(*compatible);
41872ee35494Smrg                compatible++;
41882ee35494Smrg            }
41892ee35494Smrg
41902ee35494Smrg            free(device->deviceinfo.host1x->compatible);
41912ee35494Smrg        }
41922ee35494Smrg    }
41932ee35494Smrg}
41942ee35494Smrg
41956260e5d5Smrgdrm_public void drmFreeDevice(drmDevicePtr *device)
4196fe517fc9Smrg{
4197fe517fc9Smrg    if (device == NULL)
4198fe517fc9Smrg        return;
4199fe517fc9Smrg
42002ee35494Smrg    if (*device) {
42012ee35494Smrg        switch ((*device)->bustype) {
42022ee35494Smrg        case DRM_BUS_PLATFORM:
42032ee35494Smrg            drmFreePlatformDevice(*device);
42042ee35494Smrg            break;
42052ee35494Smrg
42062ee35494Smrg        case DRM_BUS_HOST1X:
42072ee35494Smrg            drmFreeHost1xDevice(*device);
42082ee35494Smrg            break;
42092ee35494Smrg        }
42102ee35494Smrg    }
42112ee35494Smrg
4212fe517fc9Smrg    free(*device);
4213fe517fc9Smrg    *device = NULL;
4214fe517fc9Smrg}
4215fe517fc9Smrg
42166260e5d5Smrgdrm_public void drmFreeDevices(drmDevicePtr devices[], int count)
4217fe517fc9Smrg{
4218fe517fc9Smrg    int i;
4219fe517fc9Smrg
4220fe517fc9Smrg    if (devices == NULL)
4221fe517fc9Smrg        return;
4222fe517fc9Smrg
4223fe517fc9Smrg    for (i = 0; i < count; i++)
4224fe517fc9Smrg        if (devices[i])
4225fe517fc9Smrg            drmFreeDevice(&devices[i]);
4226fe517fc9Smrg}
4227fe517fc9Smrg
42282ee35494Smrgstatic drmDevicePtr drmDeviceAlloc(unsigned int type, const char *node,
42292ee35494Smrg                                   size_t bus_size, size_t device_size,
42302ee35494Smrg                                   char **ptrp)
4231fe517fc9Smrg{
42322ee35494Smrg    size_t max_node_length, extra, size;
42332ee35494Smrg    drmDevicePtr device;
42342ee35494Smrg    unsigned int i;
42352ee35494Smrg    char *ptr;
4236fe517fc9Smrg
42372ee35494Smrg    max_node_length = ALIGN(drmGetMaxNodeName(), sizeof(void *));
42382ee35494Smrg    extra = DRM_NODE_MAX * (sizeof(void *) + max_node_length);
4239fe517fc9Smrg
42402ee35494Smrg    size = sizeof(*device) + extra + bus_size + device_size;
4241fe517fc9Smrg
42422ee35494Smrg    device = calloc(1, size);
42432ee35494Smrg    if (!device)
42442ee35494Smrg        return NULL;
42452ee35494Smrg
42462ee35494Smrg    device->available_nodes = 1 << type;
4247fe517fc9Smrg
42482ee35494Smrg    ptr = (char *)device + sizeof(*device);
42492ee35494Smrg    device->nodes = (char **)ptr;
42502ee35494Smrg
42512ee35494Smrg    ptr += DRM_NODE_MAX * sizeof(void *);
4252fe517fc9Smrg
4253fe517fc9Smrg    for (i = 0; i < DRM_NODE_MAX; i++) {
42542ee35494Smrg        device->nodes[i] = ptr;
42552ee35494Smrg        ptr += max_node_length;
4256fe517fc9Smrg    }
4257fe517fc9Smrg
42582ee35494Smrg    memcpy(device->nodes[type], node, max_node_length);
42592ee35494Smrg
42602ee35494Smrg    *ptrp = ptr;
42612ee35494Smrg
42622ee35494Smrg    return device;
42632ee35494Smrg}
42642ee35494Smrg
42652ee35494Smrgstatic int drmProcessPciDevice(drmDevicePtr *device,
42662ee35494Smrg                               const char *node, int node_type,
42672ee35494Smrg                               int maj, int min, bool fetch_deviceinfo,
42682ee35494Smrg                               uint32_t flags)
42692ee35494Smrg{
42702ee35494Smrg    drmDevicePtr dev;
42712ee35494Smrg    char *addr;
42722ee35494Smrg    int ret;
42732ee35494Smrg
42742ee35494Smrg    dev = drmDeviceAlloc(node_type, node, sizeof(drmPciBusInfo),
42752ee35494Smrg                         sizeof(drmPciDeviceInfo), &addr);
42762ee35494Smrg    if (!dev)
42772ee35494Smrg        return -ENOMEM;
42782ee35494Smrg
42792ee35494Smrg    dev->bustype = DRM_BUS_PCI;
4280fe517fc9Smrg
42812ee35494Smrg    dev->businfo.pci = (drmPciBusInfoPtr)addr;
42822ee35494Smrg
42832ee35494Smrg    ret = drmParsePciBusInfo(maj, min, dev->businfo.pci);
4284fe517fc9Smrg    if (ret)
4285fe517fc9Smrg        goto free_device;
4286fe517fc9Smrg
4287fe517fc9Smrg    // Fetch the device info if the user has requested it
4288fe517fc9Smrg    if (fetch_deviceinfo) {
4289fe517fc9Smrg        addr += sizeof(drmPciBusInfo);
42902ee35494Smrg        dev->deviceinfo.pci = (drmPciDeviceInfoPtr)addr;
4291fe517fc9Smrg
42922ee35494Smrg        ret = drmParsePciDeviceInfo(maj, min, dev->deviceinfo.pci, flags);
4293fe517fc9Smrg        if (ret)
4294fe517fc9Smrg            goto free_device;
4295fe517fc9Smrg    }
42962ee35494Smrg
42972ee35494Smrg    *device = dev;
42982ee35494Smrg
4299fe517fc9Smrg    return 0;
4300fe517fc9Smrg
4301fe517fc9Smrgfree_device:
43022ee35494Smrg    free(dev);
43032ee35494Smrg    return ret;
43042ee35494Smrg}
43052ee35494Smrg
430687bf8e7cSmrg#ifdef __linux__
430787bf8e7cSmrgstatic int drm_usb_dev_path(int maj, int min, char *path, size_t len)
430887bf8e7cSmrg{
430987bf8e7cSmrg    char *value, *tmp_path, *slash;
4310adfa0b0cSmrg    bool usb_device, usb_interface;
431187bf8e7cSmrg
431287bf8e7cSmrg    snprintf(path, len, "/sys/dev/char/%d:%d/device", maj, min);
431387bf8e7cSmrg
431487bf8e7cSmrg    value = sysfs_uevent_get(path, "DEVTYPE");
431587bf8e7cSmrg    if (!value)
431687bf8e7cSmrg        return -ENOENT;
431787bf8e7cSmrg
4318adfa0b0cSmrg    usb_device = strcmp(value, "usb_device") == 0;
4319adfa0b0cSmrg    usb_interface = strcmp(value, "usb_interface") == 0;
4320adfa0b0cSmrg    free(value);
4321adfa0b0cSmrg
4322adfa0b0cSmrg    if (usb_device)
432387bf8e7cSmrg        return 0;
4324adfa0b0cSmrg    if (!usb_interface)
432587bf8e7cSmrg        return -ENOTSUP;
432687bf8e7cSmrg
432787bf8e7cSmrg    /* The parent of a usb_interface is a usb_device */
432887bf8e7cSmrg
432987bf8e7cSmrg    tmp_path = realpath(path, NULL);
433087bf8e7cSmrg    if (!tmp_path)
433187bf8e7cSmrg        return -errno;
433287bf8e7cSmrg
433387bf8e7cSmrg    slash = strrchr(tmp_path, '/');
433487bf8e7cSmrg    if (!slash) {
433587bf8e7cSmrg        free(tmp_path);
433687bf8e7cSmrg        return -EINVAL;
433787bf8e7cSmrg    }
433887bf8e7cSmrg
433987bf8e7cSmrg    *slash = '\0';
434087bf8e7cSmrg
434187bf8e7cSmrg    if (snprintf(path, len, "%s", tmp_path) >= (int)len) {
434287bf8e7cSmrg        free(tmp_path);
434387bf8e7cSmrg        return -EINVAL;
434487bf8e7cSmrg    }
434587bf8e7cSmrg
434687bf8e7cSmrg    free(tmp_path);
434787bf8e7cSmrg    return 0;
434887bf8e7cSmrg}
434987bf8e7cSmrg#endif
435087bf8e7cSmrg
43512ee35494Smrgstatic int drmParseUsbBusInfo(int maj, int min, drmUsbBusInfoPtr info)
43522ee35494Smrg{
43532ee35494Smrg#ifdef __linux__
43542ee35494Smrg    char path[PATH_MAX + 1], *value;
43552ee35494Smrg    unsigned int bus, dev;
43562ee35494Smrg    int ret;
43572ee35494Smrg
435887bf8e7cSmrg    ret = drm_usb_dev_path(maj, min, path, sizeof(path));
435987bf8e7cSmrg    if (ret < 0)
436087bf8e7cSmrg        return ret;
43612ee35494Smrg
43622ee35494Smrg    value = sysfs_uevent_get(path, "BUSNUM");
43632ee35494Smrg    if (!value)
43642ee35494Smrg        return -ENOENT;
43652ee35494Smrg
43662ee35494Smrg    ret = sscanf(value, "%03u", &bus);
43672ee35494Smrg    free(value);
43682ee35494Smrg
43692ee35494Smrg    if (ret <= 0)
43702ee35494Smrg        return -errno;
43712ee35494Smrg
43722ee35494Smrg    value = sysfs_uevent_get(path, "DEVNUM");
43732ee35494Smrg    if (!value)
43742ee35494Smrg        return -ENOENT;
43752ee35494Smrg
43762ee35494Smrg    ret = sscanf(value, "%03u", &dev);
43772ee35494Smrg    free(value);
43782ee35494Smrg
43792ee35494Smrg    if (ret <= 0)
43802ee35494Smrg        return -errno;
43812ee35494Smrg
43822ee35494Smrg    info->bus = bus;
43832ee35494Smrg    info->dev = dev;
43842ee35494Smrg
43852ee35494Smrg    return 0;
43862ee35494Smrg#else
43872ee35494Smrg#warning "Missing implementation of drmParseUsbBusInfo"
43882ee35494Smrg    return -EINVAL;
43892ee35494Smrg#endif
43902ee35494Smrg}
43912ee35494Smrg
43922ee35494Smrgstatic int drmParseUsbDeviceInfo(int maj, int min, drmUsbDeviceInfoPtr info)
43932ee35494Smrg{
43942ee35494Smrg#ifdef __linux__
43952ee35494Smrg    char path[PATH_MAX + 1], *value;
43962ee35494Smrg    unsigned int vendor, product;
43972ee35494Smrg    int ret;
43982ee35494Smrg
439987bf8e7cSmrg    ret = drm_usb_dev_path(maj, min, path, sizeof(path));
440087bf8e7cSmrg    if (ret < 0)
440187bf8e7cSmrg        return ret;
44022ee35494Smrg
44032ee35494Smrg    value = sysfs_uevent_get(path, "PRODUCT");
44042ee35494Smrg    if (!value)
44052ee35494Smrg        return -ENOENT;
44062ee35494Smrg
44072ee35494Smrg    ret = sscanf(value, "%x/%x", &vendor, &product);
44082ee35494Smrg    free(value);
44092ee35494Smrg
44102ee35494Smrg    if (ret <= 0)
44112ee35494Smrg        return -errno;
44122ee35494Smrg
44132ee35494Smrg    info->vendor = vendor;
44142ee35494Smrg    info->product = product;
44152ee35494Smrg
44162ee35494Smrg    return 0;
44172ee35494Smrg#else
44182ee35494Smrg#warning "Missing implementation of drmParseUsbDeviceInfo"
44192ee35494Smrg    return -EINVAL;
44202ee35494Smrg#endif
44212ee35494Smrg}
44222ee35494Smrg
44232ee35494Smrgstatic int drmProcessUsbDevice(drmDevicePtr *device, const char *node,
44242ee35494Smrg                               int node_type, int maj, int min,
44252ee35494Smrg                               bool fetch_deviceinfo, uint32_t flags)
44262ee35494Smrg{
44272ee35494Smrg    drmDevicePtr dev;
44282ee35494Smrg    char *ptr;
44292ee35494Smrg    int ret;
44302ee35494Smrg
44312ee35494Smrg    dev = drmDeviceAlloc(node_type, node, sizeof(drmUsbBusInfo),
44322ee35494Smrg                         sizeof(drmUsbDeviceInfo), &ptr);
44332ee35494Smrg    if (!dev)
44342ee35494Smrg        return -ENOMEM;
44352ee35494Smrg
44362ee35494Smrg    dev->bustype = DRM_BUS_USB;
44372ee35494Smrg
44382ee35494Smrg    dev->businfo.usb = (drmUsbBusInfoPtr)ptr;
44392ee35494Smrg
44402ee35494Smrg    ret = drmParseUsbBusInfo(maj, min, dev->businfo.usb);
44412ee35494Smrg    if (ret < 0)
44422ee35494Smrg        goto free_device;
44432ee35494Smrg
44442ee35494Smrg    if (fetch_deviceinfo) {
44452ee35494Smrg        ptr += sizeof(drmUsbBusInfo);
44462ee35494Smrg        dev->deviceinfo.usb = (drmUsbDeviceInfoPtr)ptr;
44472ee35494Smrg
44482ee35494Smrg        ret = drmParseUsbDeviceInfo(maj, min, dev->deviceinfo.usb);
44492ee35494Smrg        if (ret < 0)
44502ee35494Smrg            goto free_device;
44512ee35494Smrg    }
44522ee35494Smrg
44532ee35494Smrg    *device = dev;
44542ee35494Smrg
44552ee35494Smrg    return 0;
44562ee35494Smrg
44572ee35494Smrgfree_device:
44582ee35494Smrg    free(dev);
44592ee35494Smrg    return ret;
44602ee35494Smrg}
44612ee35494Smrg
4462bf6cc7dcSmrgstatic int drmParseOFBusInfo(int maj, int min, char *fullname)
44632ee35494Smrg{
44642ee35494Smrg#ifdef __linux__
4465bf6cc7dcSmrg    char path[PATH_MAX + 1], *name, *tmp_name;
44662ee35494Smrg
44672ee35494Smrg    snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min);
44682ee35494Smrg
44692ee35494Smrg    name = sysfs_uevent_get(path, "OF_FULLNAME");
4470bf6cc7dcSmrg    tmp_name = name;
4471bf6cc7dcSmrg    if (!name) {
4472bf6cc7dcSmrg        /* If the device lacks OF data, pick the MODALIAS info */
4473bf6cc7dcSmrg        name = sysfs_uevent_get(path, "MODALIAS");
4474bf6cc7dcSmrg        if (!name)
4475bf6cc7dcSmrg            return -ENOENT;
4476bf6cc7dcSmrg
4477bf6cc7dcSmrg        /* .. and strip the MODALIAS=[platform,usb...]: part. */
4478bf6cc7dcSmrg        tmp_name = strrchr(name, ':');
4479bf6cc7dcSmrg        if (!tmp_name) {
4480bf6cc7dcSmrg            free(name);
4481bf6cc7dcSmrg            return -ENOENT;
4482bf6cc7dcSmrg        }
4483bf6cc7dcSmrg        tmp_name++;
4484bf6cc7dcSmrg    }
44852ee35494Smrg
4486bf6cc7dcSmrg    strncpy(fullname, tmp_name, DRM_PLATFORM_DEVICE_NAME_LEN);
4487bf6cc7dcSmrg    fullname[DRM_PLATFORM_DEVICE_NAME_LEN - 1] = '\0';
44882ee35494Smrg    free(name);
44892ee35494Smrg
44902ee35494Smrg    return 0;
44912ee35494Smrg#else
4492bf6cc7dcSmrg#warning "Missing implementation of drmParseOFBusInfo"
44932ee35494Smrg    return -EINVAL;
44942ee35494Smrg#endif
44952ee35494Smrg}
44962ee35494Smrg
4497bf6cc7dcSmrgstatic int drmParseOFDeviceInfo(int maj, int min, char ***compatible)
44982ee35494Smrg{
44992ee35494Smrg#ifdef __linux__
4500bf6cc7dcSmrg    char path[PATH_MAX + 1], *value, *tmp_name;
45012ee35494Smrg    unsigned int count, i;
45022ee35494Smrg    int err;
45032ee35494Smrg
45042ee35494Smrg    snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min);
45052ee35494Smrg
45062ee35494Smrg    value = sysfs_uevent_get(path, "OF_COMPATIBLE_N");
4507bf6cc7dcSmrg    if (value) {
4508bf6cc7dcSmrg        sscanf(value, "%u", &count);
4509bf6cc7dcSmrg        free(value);
4510bf6cc7dcSmrg    } else {
4511bf6cc7dcSmrg        /* Assume one entry if the device lack OF data */
4512bf6cc7dcSmrg        count = 1;
4513bf6cc7dcSmrg    }
45142ee35494Smrg
4515bf6cc7dcSmrg    *compatible = calloc(count + 1, sizeof(char *));
4516bf6cc7dcSmrg    if (!*compatible)
45172ee35494Smrg        return -ENOMEM;
45182ee35494Smrg
45192ee35494Smrg    for (i = 0; i < count; i++) {
45202ee35494Smrg        value = sysfs_uevent_get(path, "OF_COMPATIBLE_%u", i);
4521bf6cc7dcSmrg        tmp_name = value;
45222ee35494Smrg        if (!value) {
4523bf6cc7dcSmrg            /* If the device lacks OF data, pick the MODALIAS info */
4524bf6cc7dcSmrg            value = sysfs_uevent_get(path, "MODALIAS");
4525bf6cc7dcSmrg            if (!value) {
4526bf6cc7dcSmrg                err = -ENOENT;
4527bf6cc7dcSmrg                goto free;
4528bf6cc7dcSmrg            }
4529bf6cc7dcSmrg
4530bf6cc7dcSmrg            /* .. and strip the MODALIAS=[platform,usb...]: part. */
4531bf6cc7dcSmrg            tmp_name = strrchr(value, ':');
4532bf6cc7dcSmrg            if (!tmp_name) {
4533bf6cc7dcSmrg                free(value);
4534bf6cc7dcSmrg                return -ENOENT;
4535bf6cc7dcSmrg            }
4536bf6cc7dcSmrg            tmp_name = strdup(tmp_name + 1);
4537bf6cc7dcSmrg            free(value);
45382ee35494Smrg        }
45392ee35494Smrg
4540bf6cc7dcSmrg        (*compatible)[i] = tmp_name;
45412ee35494Smrg    }
45422ee35494Smrg
45432ee35494Smrg    return 0;
45442ee35494Smrg
45452ee35494Smrgfree:
45462ee35494Smrg    while (i--)
4547bf6cc7dcSmrg        free((*compatible)[i]);
45482ee35494Smrg
4549bf6cc7dcSmrg    free(*compatible);
45502ee35494Smrg    return err;
45512ee35494Smrg#else
4552bf6cc7dcSmrg#warning "Missing implementation of drmParseOFDeviceInfo"
45532ee35494Smrg    return -EINVAL;
45542ee35494Smrg#endif
45552ee35494Smrg}
45562ee35494Smrg
45572ee35494Smrgstatic int drmProcessPlatformDevice(drmDevicePtr *device,
45582ee35494Smrg                                    const char *node, int node_type,
45592ee35494Smrg                                    int maj, int min, bool fetch_deviceinfo,
45602ee35494Smrg                                    uint32_t flags)
45612ee35494Smrg{
45622ee35494Smrg    drmDevicePtr dev;
45632ee35494Smrg    char *ptr;
45642ee35494Smrg    int ret;
45652ee35494Smrg
45662ee35494Smrg    dev = drmDeviceAlloc(node_type, node, sizeof(drmPlatformBusInfo),
45672ee35494Smrg                         sizeof(drmPlatformDeviceInfo), &ptr);
45682ee35494Smrg    if (!dev)
45692ee35494Smrg        return -ENOMEM;
45702ee35494Smrg
45712ee35494Smrg    dev->bustype = DRM_BUS_PLATFORM;
45722ee35494Smrg
45732ee35494Smrg    dev->businfo.platform = (drmPlatformBusInfoPtr)ptr;
45742ee35494Smrg
4575bf6cc7dcSmrg    ret = drmParseOFBusInfo(maj, min, dev->businfo.platform->fullname);
45762ee35494Smrg    if (ret < 0)
45772ee35494Smrg        goto free_device;
45782ee35494Smrg
45792ee35494Smrg    if (fetch_deviceinfo) {
45802ee35494Smrg        ptr += sizeof(drmPlatformBusInfo);
45812ee35494Smrg        dev->deviceinfo.platform = (drmPlatformDeviceInfoPtr)ptr;
45822ee35494Smrg
4583bf6cc7dcSmrg        ret = drmParseOFDeviceInfo(maj, min, &dev->deviceinfo.platform->compatible);
45842ee35494Smrg        if (ret < 0)
45852ee35494Smrg            goto free_device;
45862ee35494Smrg    }
45872ee35494Smrg
45882ee35494Smrg    *device = dev;
45892ee35494Smrg
45902ee35494Smrg    return 0;
45912ee35494Smrg
45922ee35494Smrgfree_device:
45932ee35494Smrg    free(dev);
45942ee35494Smrg    return ret;
45952ee35494Smrg}
45962ee35494Smrg
45972ee35494Smrgstatic int drmProcessHost1xDevice(drmDevicePtr *device,
45982ee35494Smrg                                  const char *node, int node_type,
45992ee35494Smrg                                  int maj, int min, bool fetch_deviceinfo,
46002ee35494Smrg                                  uint32_t flags)
46012ee35494Smrg{
46022ee35494Smrg    drmDevicePtr dev;
46032ee35494Smrg    char *ptr;
46042ee35494Smrg    int ret;
46052ee35494Smrg
46062ee35494Smrg    dev = drmDeviceAlloc(node_type, node, sizeof(drmHost1xBusInfo),
46072ee35494Smrg                         sizeof(drmHost1xDeviceInfo), &ptr);
46082ee35494Smrg    if (!dev)
46092ee35494Smrg        return -ENOMEM;
46102ee35494Smrg
46112ee35494Smrg    dev->bustype = DRM_BUS_HOST1X;
46122ee35494Smrg
46132ee35494Smrg    dev->businfo.host1x = (drmHost1xBusInfoPtr)ptr;
46142ee35494Smrg
4615bf6cc7dcSmrg    ret = drmParseOFBusInfo(maj, min, dev->businfo.host1x->fullname);
46162ee35494Smrg    if (ret < 0)
46172ee35494Smrg        goto free_device;
46182ee35494Smrg
46192ee35494Smrg    if (fetch_deviceinfo) {
46202ee35494Smrg        ptr += sizeof(drmHost1xBusInfo);
46212ee35494Smrg        dev->deviceinfo.host1x = (drmHost1xDeviceInfoPtr)ptr;
46222ee35494Smrg
4623bf6cc7dcSmrg        ret = drmParseOFDeviceInfo(maj, min, &dev->deviceinfo.host1x->compatible);
46242ee35494Smrg        if (ret < 0)
46252ee35494Smrg            goto free_device;
46262ee35494Smrg    }
46272ee35494Smrg
46282ee35494Smrg    *device = dev;
46292ee35494Smrg
46302ee35494Smrg    return 0;
46312ee35494Smrg
46322ee35494Smrgfree_device:
46332ee35494Smrg    free(dev);
4634fe517fc9Smrg    return ret;
4635fe517fc9Smrg}
4636fe517fc9Smrg
46376260e5d5Smrgstatic int
46386260e5d5Smrgprocess_device(drmDevicePtr *device, const char *d_name,
46396260e5d5Smrg               int req_subsystem_type,
46406260e5d5Smrg               bool fetch_deviceinfo, uint32_t flags)
46416260e5d5Smrg{
46426260e5d5Smrg    struct stat sbuf;
46436260e5d5Smrg    char node[PATH_MAX + 1];
464448246ce7Smrg    int node_type, subsystem_type, written;
46456260e5d5Smrg    unsigned int maj, min;
464648246ce7Smrg    const int max_node_length = ALIGN(drmGetMaxNodeName(), sizeof(void *));
46476260e5d5Smrg
46486260e5d5Smrg    node_type = drmGetNodeType(d_name);
46496260e5d5Smrg    if (node_type < 0)
46506260e5d5Smrg        return -1;
46516260e5d5Smrg
465248246ce7Smrg    written = snprintf(node, PATH_MAX, "%s/%s", DRM_DIR_NAME, d_name);
465348246ce7Smrg    if (written < 0)
465448246ce7Smrg        return -1;
465548246ce7Smrg
465648246ce7Smrg    /* anything longer than this will be truncated in drmDeviceAlloc.
465748246ce7Smrg     * Account for NULL byte
465848246ce7Smrg     */
465948246ce7Smrg    if (written + 1 > max_node_length)
466048246ce7Smrg        return -1;
466148246ce7Smrg
46626260e5d5Smrg    if (stat(node, &sbuf))
46636260e5d5Smrg        return -1;
46646260e5d5Smrg
46656260e5d5Smrg    maj = major(sbuf.st_rdev);
46666260e5d5Smrg    min = minor(sbuf.st_rdev);
46676260e5d5Smrg
46686260e5d5Smrg    if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode))
46696260e5d5Smrg        return -1;
46706260e5d5Smrg
46716260e5d5Smrg    subsystem_type = drmParseSubsystemType(maj, min);
46726260e5d5Smrg    if (req_subsystem_type != -1 && req_subsystem_type != subsystem_type)
46736260e5d5Smrg        return -1;
46746260e5d5Smrg
46756260e5d5Smrg    switch (subsystem_type) {
46766260e5d5Smrg    case DRM_BUS_PCI:
46776260e5d5Smrg    case DRM_BUS_VIRTIO:
46786260e5d5Smrg        return drmProcessPciDevice(device, node, node_type, maj, min,
46796260e5d5Smrg                                   fetch_deviceinfo, flags);
46806260e5d5Smrg    case DRM_BUS_USB:
46816260e5d5Smrg        return drmProcessUsbDevice(device, node, node_type, maj, min,
46826260e5d5Smrg                                   fetch_deviceinfo, flags);
46836260e5d5Smrg    case DRM_BUS_PLATFORM:
46846260e5d5Smrg        return drmProcessPlatformDevice(device, node, node_type, maj, min,
46856260e5d5Smrg                                        fetch_deviceinfo, flags);
46866260e5d5Smrg    case DRM_BUS_HOST1X:
46876260e5d5Smrg        return drmProcessHost1xDevice(device, node, node_type, maj, min,
46886260e5d5Smrg                                      fetch_deviceinfo, flags);
46896260e5d5Smrg    default:
46906260e5d5Smrg        return -1;
46916260e5d5Smrg   }
46926260e5d5Smrg}
46936260e5d5Smrg
4694fe517fc9Smrg/* Consider devices located on the same bus as duplicate and fold the respective
4695fe517fc9Smrg * entries into a single one.
4696fe517fc9Smrg *
4697fe517fc9Smrg * Note: this leaves "gaps" in the array, while preserving the length.
4698fe517fc9Smrg */
4699fe517fc9Smrgstatic void drmFoldDuplicatedDevices(drmDevicePtr local_devices[], int count)
4700fe517fc9Smrg{
4701fe517fc9Smrg    int node_type, i, j;
4702fe517fc9Smrg
4703fe517fc9Smrg    for (i = 0; i < count; i++) {
4704fe517fc9Smrg        for (j = i + 1; j < count; j++) {
47050655efefSmrg            if (drmDevicesEqual(local_devices[i], local_devices[j])) {
4706fe517fc9Smrg                local_devices[i]->available_nodes |= local_devices[j]->available_nodes;
47074b3d3f37Smrg                node_type = log2_int(local_devices[j]->available_nodes);
4708fe517fc9Smrg                memcpy(local_devices[i]->nodes[node_type],
4709fe517fc9Smrg                       local_devices[j]->nodes[node_type], drmGetMaxNodeName());
4710fe517fc9Smrg                drmFreeDevice(&local_devices[j]);
4711fe517fc9Smrg            }
4712fe517fc9Smrg        }
4713fe517fc9Smrg    }
4714fe517fc9Smrg}
4715fe517fc9Smrg
47162ee35494Smrg/* Check that the given flags are valid returning 0 on success */
47172ee35494Smrgstatic int
47182ee35494Smrgdrm_device_validate_flags(uint32_t flags)
47192ee35494Smrg{
47202ee35494Smrg        return (flags & ~DRM_DEVICE_GET_PCI_REVISION);
47212ee35494Smrg}
47222ee35494Smrg
47236260e5d5Smrgstatic bool
47246260e5d5Smrgdrm_device_has_rdev(drmDevicePtr device, dev_t find_rdev)
47256260e5d5Smrg{
47266260e5d5Smrg    struct stat sbuf;
47276260e5d5Smrg
47286260e5d5Smrg    for (int i = 0; i < DRM_NODE_MAX; i++) {
47296260e5d5Smrg        if (device->available_nodes & 1 << i) {
47306260e5d5Smrg            if (stat(device->nodes[i], &sbuf) == 0 &&
47316260e5d5Smrg                sbuf.st_rdev == find_rdev)
47326260e5d5Smrg                return true;
47336260e5d5Smrg        }
47346260e5d5Smrg    }
47356260e5d5Smrg    return false;
47366260e5d5Smrg}
47376260e5d5Smrg
47386260e5d5Smrg/*
47396260e5d5Smrg * The kernel drm core has a number of places that assume maximum of
47406260e5d5Smrg * 3x64 devices nodes. That's 64 for each of primary, control and
47416260e5d5Smrg * render nodes. Rounded it up to 256 for simplicity.
47426260e5d5Smrg */
47436260e5d5Smrg#define MAX_DRM_NODES 256
47446260e5d5Smrg
4745fe517fc9Smrg/**
4746adfa0b0cSmrg * Get information about a device from its dev_t identifier
4747fe517fc9Smrg *
4748adfa0b0cSmrg * \param find_rdev dev_t identifier of the device
47492ee35494Smrg * \param flags feature/behaviour bitmask
4750fe517fc9Smrg * \param device the address of a drmDevicePtr where the information
4751fe517fc9Smrg *               will be allocated in stored
4752fe517fc9Smrg *
4753fe517fc9Smrg * \return zero on success, negative error code otherwise.
4754fe517fc9Smrg */
4755adfa0b0cSmrgdrm_public int drmGetDeviceFromDevId(dev_t find_rdev, uint32_t flags, drmDevicePtr *device)
4756fe517fc9Smrg{
47572ee35494Smrg#ifdef __OpenBSD__
47582ee35494Smrg    /*
47592ee35494Smrg     * DRI device nodes on OpenBSD are not in their own directory, they reside
47602ee35494Smrg     * in /dev along with a large number of statically generated /dev nodes.
47612ee35494Smrg     * Avoid stat'ing all of /dev needlessly by implementing this custom path.
47622ee35494Smrg     */
47632ee35494Smrg    drmDevicePtr     d;
47642ee35494Smrg    char             node[PATH_MAX + 1];
47652ee35494Smrg    const char      *dev_name;
47662ee35494Smrg    int              node_type, subsystem_type;
476782025ec7Smrg    int              maj, min, n, ret;
476848246ce7Smrg    const int        max_node_length = ALIGN(drmGetMaxNodeName(), sizeof(void *));
476948246ce7Smrg    struct stat      sbuf;
47702ee35494Smrg
4771adfa0b0cSmrg    if (device == NULL)
47722ee35494Smrg        return -EINVAL;
47732ee35494Smrg
4774adfa0b0cSmrg    maj = major(find_rdev);
4775adfa0b0cSmrg    min = minor(find_rdev);
47762ee35494Smrg
4777adfa0b0cSmrg    if (!drmNodeIsDRM(maj, min))
47782ee35494Smrg        return -EINVAL;
47792ee35494Smrg
478087bf8e7cSmrg    node_type = drmGetMinorType(maj, min);
47812ee35494Smrg    if (node_type == -1)
47822ee35494Smrg        return -ENODEV;
47832ee35494Smrg
478482025ec7Smrg    dev_name = drmGetDeviceName(node_type);
478582025ec7Smrg    if (!dev_name)
47862ee35494Smrg        return -EINVAL;
47872ee35494Smrg
478848246ce7Smrg    /* anything longer than this will be truncated in drmDeviceAlloc.
478948246ce7Smrg     * Account for NULL byte
479048246ce7Smrg     */
479182025ec7Smrg    n = snprintf(node, PATH_MAX, dev_name, DRM_DIR_NAME, min);
47922ee35494Smrg    if (n == -1 || n >= PATH_MAX)
47932ee35494Smrg      return -errno;
479448246ce7Smrg    if (n + 1 > max_node_length)
479548246ce7Smrg        return -EINVAL;
47962ee35494Smrg    if (stat(node, &sbuf))
47972ee35494Smrg        return -EINVAL;
47982ee35494Smrg
47992ee35494Smrg    subsystem_type = drmParseSubsystemType(maj, min);
48002ee35494Smrg    if (subsystem_type != DRM_BUS_PCI)
48012ee35494Smrg        return -ENODEV;
48022ee35494Smrg
48032ee35494Smrg    ret = drmProcessPciDevice(&d, node, node_type, maj, min, true, flags);
48042ee35494Smrg    if (ret)
48052ee35494Smrg        return ret;
48062ee35494Smrg
48072ee35494Smrg    *device = d;
48082ee35494Smrg
48092ee35494Smrg    return 0;
48102ee35494Smrg#else
48116260e5d5Smrg    drmDevicePtr local_devices[MAX_DRM_NODES];
4812fe517fc9Smrg    drmDevicePtr d;
4813fe517fc9Smrg    DIR *sysdir;
4814fe517fc9Smrg    struct dirent *dent;
48156260e5d5Smrg    int subsystem_type;
4816fe517fc9Smrg    int maj, min;
4817fe517fc9Smrg    int ret, i, node_count;
4818fe517fc9Smrg
48192ee35494Smrg    if (drm_device_validate_flags(flags))
48202ee35494Smrg        return -EINVAL;
48212ee35494Smrg
4822adfa0b0cSmrg    if (device == NULL)
4823fe517fc9Smrg        return -EINVAL;
4824fe517fc9Smrg
4825adfa0b0cSmrg    maj = major(find_rdev);
4826adfa0b0cSmrg    min = minor(find_rdev);
4827fe517fc9Smrg
4828adfa0b0cSmrg    if (!drmNodeIsDRM(maj, min))
4829fe517fc9Smrg        return -EINVAL;
4830fe517fc9Smrg
4831fe517fc9Smrg    subsystem_type = drmParseSubsystemType(maj, min);
48326260e5d5Smrg    if (subsystem_type < 0)
48336260e5d5Smrg        return subsystem_type;
4834fe517fc9Smrg
4835fe517fc9Smrg    sysdir = opendir(DRM_DIR_NAME);
48366260e5d5Smrg    if (!sysdir)
48376260e5d5Smrg        return -errno;
4838fe517fc9Smrg
4839fe517fc9Smrg    i = 0;
4840fe517fc9Smrg    while ((dent = readdir(sysdir))) {
48416260e5d5Smrg        ret = process_device(&d, dent->d_name, subsystem_type, true, flags);
48426260e5d5Smrg        if (ret)
4843fe517fc9Smrg            continue;
4844fe517fc9Smrg
48456260e5d5Smrg        if (i >= MAX_DRM_NODES) {
48466260e5d5Smrg            fprintf(stderr, "More than %d drm nodes detected. "
48476260e5d5Smrg                    "Please report a bug - that should not happen.\n"
48486260e5d5Smrg                    "Skipping extra nodes\n", MAX_DRM_NODES);
4849fe517fc9Smrg            break;
4850fe517fc9Smrg        }
48516260e5d5Smrg        local_devices[i] = d;
4852fe517fc9Smrg        i++;
4853fe517fc9Smrg    }
4854fe517fc9Smrg    node_count = i;
4855fe517fc9Smrg
4856fe517fc9Smrg    drmFoldDuplicatedDevices(local_devices, node_count);
4857fe517fc9Smrg
48586260e5d5Smrg    *device = NULL;
48596260e5d5Smrg
48606260e5d5Smrg    for (i = 0; i < node_count; i++) {
48616260e5d5Smrg        if (!local_devices[i])
48626260e5d5Smrg            continue;
48636260e5d5Smrg
48646260e5d5Smrg        if (drm_device_has_rdev(local_devices[i], find_rdev))
48656260e5d5Smrg            *device = local_devices[i];
48666260e5d5Smrg        else
48676260e5d5Smrg            drmFreeDevice(&local_devices[i]);
48686260e5d5Smrg    }
4869fe517fc9Smrg
4870fe517fc9Smrg    closedir(sysdir);
48712ee35494Smrg    if (*device == NULL)
48722ee35494Smrg        return -ENODEV;
4873fe517fc9Smrg    return 0;
48742ee35494Smrg#endif
48752ee35494Smrg}
48762ee35494Smrg
487748246ce7Smrgdrm_public int drmGetNodeTypeFromDevId(dev_t devid)
487848246ce7Smrg{
487948246ce7Smrg    int maj, min, node_type;
488048246ce7Smrg
488148246ce7Smrg    maj = major(devid);
488248246ce7Smrg    min = minor(devid);
488348246ce7Smrg
488448246ce7Smrg    if (!drmNodeIsDRM(maj, min))
488548246ce7Smrg        return -EINVAL;
488648246ce7Smrg
488748246ce7Smrg    node_type = drmGetMinorType(maj, min);
488848246ce7Smrg    if (node_type == -1)
488948246ce7Smrg        return -ENODEV;
489048246ce7Smrg
489148246ce7Smrg    return node_type;
489248246ce7Smrg}
489348246ce7Smrg
4894adfa0b0cSmrg/**
4895adfa0b0cSmrg * Get information about the opened drm device
4896adfa0b0cSmrg *
4897adfa0b0cSmrg * \param fd file descriptor of the drm device
4898adfa0b0cSmrg * \param flags feature/behaviour bitmask
4899adfa0b0cSmrg * \param device the address of a drmDevicePtr where the information
4900adfa0b0cSmrg *               will be allocated in stored
4901adfa0b0cSmrg *
4902adfa0b0cSmrg * \return zero on success, negative error code otherwise.
4903adfa0b0cSmrg *
4904adfa0b0cSmrg * \note Unlike drmGetDevice it does not retrieve the pci device revision field
4905adfa0b0cSmrg * unless the DRM_DEVICE_GET_PCI_REVISION \p flag is set.
4906adfa0b0cSmrg */
4907adfa0b0cSmrgdrm_public int drmGetDevice2(int fd, uint32_t flags, drmDevicePtr *device)
4908adfa0b0cSmrg{
4909adfa0b0cSmrg    struct stat sbuf;
4910adfa0b0cSmrg
4911adfa0b0cSmrg    if (fd == -1)
4912adfa0b0cSmrg        return -EINVAL;
4913adfa0b0cSmrg
4914adfa0b0cSmrg    if (fstat(fd, &sbuf))
4915adfa0b0cSmrg        return -errno;
4916adfa0b0cSmrg
4917adfa0b0cSmrg    if (!S_ISCHR(sbuf.st_mode))
4918adfa0b0cSmrg        return -EINVAL;
4919adfa0b0cSmrg
4920adfa0b0cSmrg    return drmGetDeviceFromDevId(sbuf.st_rdev, flags, device);
4921adfa0b0cSmrg}
4922adfa0b0cSmrg
49232ee35494Smrg/**
49242ee35494Smrg * Get information about the opened drm device
49252ee35494Smrg *
49262ee35494Smrg * \param fd file descriptor of the drm device
49272ee35494Smrg * \param device the address of a drmDevicePtr where the information
49282ee35494Smrg *               will be allocated in stored
49292ee35494Smrg *
49302ee35494Smrg * \return zero on success, negative error code otherwise.
49312ee35494Smrg */
49326260e5d5Smrgdrm_public int drmGetDevice(int fd, drmDevicePtr *device)
49332ee35494Smrg{
49342ee35494Smrg    return drmGetDevice2(fd, DRM_DEVICE_GET_PCI_REVISION, device);
4935fe517fc9Smrg}
4936fe517fc9Smrg
4937fe517fc9Smrg/**
4938fe517fc9Smrg * Get drm devices on the system
4939fe517fc9Smrg *
49402ee35494Smrg * \param flags feature/behaviour bitmask
4941fe517fc9Smrg * \param devices the array of devices with drmDevicePtr elements
4942fe517fc9Smrg *                can be NULL to get the device number first
4943fe517fc9Smrg * \param max_devices the maximum number of devices for the array
4944fe517fc9Smrg *
4945fe517fc9Smrg * \return on error - negative error code,
4946fe517fc9Smrg *         if devices is NULL - total number of devices available on the system,
4947fe517fc9Smrg *         alternatively the number of devices stored in devices[], which is
4948fe517fc9Smrg *         capped by the max_devices.
49492ee35494Smrg *
49502ee35494Smrg * \note Unlike drmGetDevices it does not retrieve the pci device revision field
49512ee35494Smrg * unless the DRM_DEVICE_GET_PCI_REVISION \p flag is set.
4952fe517fc9Smrg */
49536260e5d5Smrgdrm_public int drmGetDevices2(uint32_t flags, drmDevicePtr devices[],
49546260e5d5Smrg                              int max_devices)
4955fe517fc9Smrg{
49566260e5d5Smrg    drmDevicePtr local_devices[MAX_DRM_NODES];
4957fe517fc9Smrg    drmDevicePtr device;
4958fe517fc9Smrg    DIR *sysdir;
4959fe517fc9Smrg    struct dirent *dent;
4960fe517fc9Smrg    int ret, i, node_count, device_count;
4961fe517fc9Smrg
49622ee35494Smrg    if (drm_device_validate_flags(flags))
49632ee35494Smrg        return -EINVAL;
49642ee35494Smrg
4965fe517fc9Smrg    sysdir = opendir(DRM_DIR_NAME);
49666260e5d5Smrg    if (!sysdir)
49676260e5d5Smrg        return -errno;
4968fe517fc9Smrg
4969fe517fc9Smrg    i = 0;
4970fe517fc9Smrg    while ((dent = readdir(sysdir))) {
49716260e5d5Smrg        ret = process_device(&device, dent->d_name, -1, devices != NULL, flags);
49726260e5d5Smrg        if (ret)
4973fe517fc9Smrg            continue;
4974fe517fc9Smrg
49756260e5d5Smrg        if (i >= MAX_DRM_NODES) {
49766260e5d5Smrg            fprintf(stderr, "More than %d drm nodes detected. "
49776260e5d5Smrg                    "Please report a bug - that should not happen.\n"
49786260e5d5Smrg                    "Skipping extra nodes\n", MAX_DRM_NODES);
49792ee35494Smrg            break;
4980fe517fc9Smrg        }
4981fe517fc9Smrg        local_devices[i] = device;
4982fe517fc9Smrg        i++;
4983fe517fc9Smrg    }
4984fe517fc9Smrg    node_count = i;
4985fe517fc9Smrg
4986fe517fc9Smrg    drmFoldDuplicatedDevices(local_devices, node_count);
4987fe517fc9Smrg
4988fe517fc9Smrg    device_count = 0;
4989fe517fc9Smrg    for (i = 0; i < node_count; i++) {
4990fe517fc9Smrg        if (!local_devices[i])
4991fe517fc9Smrg            continue;
4992fe517fc9Smrg
4993fe517fc9Smrg        if ((devices != NULL) && (device_count < max_devices))
4994fe517fc9Smrg            devices[device_count] = local_devices[i];
4995fe517fc9Smrg        else
4996fe517fc9Smrg            drmFreeDevice(&local_devices[i]);
4997fe517fc9Smrg
4998fe517fc9Smrg        device_count++;
4999fe517fc9Smrg    }
5000fe517fc9Smrg
5001fe517fc9Smrg    closedir(sysdir);
50024b3d3f37Smrg
50034b3d3f37Smrg    if (devices != NULL)
50044b3d3f37Smrg        return MIN2(device_count, max_devices);
50054b3d3f37Smrg
5006fe517fc9Smrg    return device_count;
5007424e9256Smrg}
50082ee35494Smrg
50092ee35494Smrg/**
50102ee35494Smrg * Get drm devices on the system
50112ee35494Smrg *
50122ee35494Smrg * \param devices the array of devices with drmDevicePtr elements
50132ee35494Smrg *                can be NULL to get the device number first
50142ee35494Smrg * \param max_devices the maximum number of devices for the array
50152ee35494Smrg *
50162ee35494Smrg * \return on error - negative error code,
50172ee35494Smrg *         if devices is NULL - total number of devices available on the system,
50182ee35494Smrg *         alternatively the number of devices stored in devices[], which is
50192ee35494Smrg *         capped by the max_devices.
50202ee35494Smrg */
50216260e5d5Smrgdrm_public int drmGetDevices(drmDevicePtr devices[], int max_devices)
50222ee35494Smrg{
50232ee35494Smrg    return drmGetDevices2(DRM_DEVICE_GET_PCI_REVISION, devices, max_devices);
50242ee35494Smrg}
50252ee35494Smrg
50266260e5d5Smrgdrm_public char *drmGetDeviceNameFromFd2(int fd)
50272ee35494Smrg{
50282ee35494Smrg#ifdef __linux__
50292ee35494Smrg    struct stat sbuf;
50302ee35494Smrg    char path[PATH_MAX + 1], *value;
50312ee35494Smrg    unsigned int maj, min;
50322ee35494Smrg
50332ee35494Smrg    if (fstat(fd, &sbuf))
50342ee35494Smrg        return NULL;
50352ee35494Smrg
50362ee35494Smrg    maj = major(sbuf.st_rdev);
50372ee35494Smrg    min = minor(sbuf.st_rdev);
50382ee35494Smrg
50396260e5d5Smrg    if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode))
50402ee35494Smrg        return NULL;
50412ee35494Smrg
50422ee35494Smrg    snprintf(path, sizeof(path), "/sys/dev/char/%d:%d", maj, min);
50432ee35494Smrg
50442ee35494Smrg    value = sysfs_uevent_get(path, "DEVNAME");
50452ee35494Smrg    if (!value)
50462ee35494Smrg        return NULL;
50472ee35494Smrg
50482ee35494Smrg    snprintf(path, sizeof(path), "/dev/%s", value);
50492ee35494Smrg    free(value);
50502ee35494Smrg
50512ee35494Smrg    return strdup(path);
50524b3d3f37Smrg#elif defined(__FreeBSD__)
505387bf8e7cSmrg    return drmGetDeviceNameFromFd(fd);
50542ee35494Smrg#else
50552ee35494Smrg    struct stat      sbuf;
50562ee35494Smrg    char             node[PATH_MAX + 1];
50572ee35494Smrg    const char      *dev_name;
50582ee35494Smrg    int              node_type;
505982025ec7Smrg    int              maj, min, n;
50602ee35494Smrg
50612ee35494Smrg    if (fstat(fd, &sbuf))
50622ee35494Smrg        return NULL;
50632ee35494Smrg
50642ee35494Smrg    maj = major(sbuf.st_rdev);
50652ee35494Smrg    min = minor(sbuf.st_rdev);
50662ee35494Smrg
50676260e5d5Smrg    if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode))
50682ee35494Smrg        return NULL;
50692ee35494Smrg
507087bf8e7cSmrg    node_type = drmGetMinorType(maj, min);
50712ee35494Smrg    if (node_type == -1)
50722ee35494Smrg        return NULL;
50732ee35494Smrg
507482025ec7Smrg    dev_name = drmGetDeviceName(node_type);
507582025ec7Smrg    if (!dev_name)
50762ee35494Smrg        return NULL;
50772ee35494Smrg
507882025ec7Smrg    n = snprintf(node, PATH_MAX, dev_name, DRM_DIR_NAME, min);
50792ee35494Smrg    if (n == -1 || n >= PATH_MAX)
50802ee35494Smrg      return NULL;
50812ee35494Smrg
50822ee35494Smrg    return strdup(node);
50832ee35494Smrg#endif
50842ee35494Smrg}
50850655efefSmrg
50866260e5d5Smrgdrm_public int drmSyncobjCreate(int fd, uint32_t flags, uint32_t *handle)
50870655efefSmrg{
50880655efefSmrg    struct drm_syncobj_create args;
50890655efefSmrg    int ret;
50900655efefSmrg
50910655efefSmrg    memclear(args);
50920655efefSmrg    args.flags = flags;
50930655efefSmrg    args.handle = 0;
50940655efefSmrg    ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_CREATE, &args);
50950655efefSmrg    if (ret)
50962b90624aSmrg        return ret;
50970655efefSmrg    *handle = args.handle;
50980655efefSmrg    return 0;
50990655efefSmrg}
51000655efefSmrg
51016260e5d5Smrgdrm_public int drmSyncobjDestroy(int fd, uint32_t handle)
51020655efefSmrg{
51030655efefSmrg    struct drm_syncobj_destroy args;
51040655efefSmrg
51050655efefSmrg    memclear(args);
51060655efefSmrg    args.handle = handle;
51070655efefSmrg    return drmIoctl(fd, DRM_IOCTL_SYNCOBJ_DESTROY, &args);
51080655efefSmrg}
51090655efefSmrg
51106260e5d5Smrgdrm_public int drmSyncobjHandleToFD(int fd, uint32_t handle, int *obj_fd)
51110655efefSmrg{
51120655efefSmrg    struct drm_syncobj_handle args;
51130655efefSmrg    int ret;
51140655efefSmrg
51150655efefSmrg    memclear(args);
51160655efefSmrg    args.fd = -1;
51170655efefSmrg    args.handle = handle;
51180655efefSmrg    ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD, &args);
51190655efefSmrg    if (ret)
51202b90624aSmrg        return ret;
51210655efefSmrg    *obj_fd = args.fd;
51220655efefSmrg    return 0;
51230655efefSmrg}
51240655efefSmrg
51256260e5d5Smrgdrm_public int drmSyncobjFDToHandle(int fd, int obj_fd, uint32_t *handle)
51260655efefSmrg{
51270655efefSmrg    struct drm_syncobj_handle args;
51280655efefSmrg    int ret;
51290655efefSmrg
51300655efefSmrg    memclear(args);
51310655efefSmrg    args.fd = obj_fd;
51320655efefSmrg    args.handle = 0;
51330655efefSmrg    ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE, &args);
51340655efefSmrg    if (ret)
51352b90624aSmrg        return ret;
51360655efefSmrg    *handle = args.handle;
51370655efefSmrg    return 0;
51380655efefSmrg}
51390655efefSmrg
51406260e5d5Smrgdrm_public int drmSyncobjImportSyncFile(int fd, uint32_t handle,
51416260e5d5Smrg                                        int sync_file_fd)
51420655efefSmrg{
51430655efefSmrg    struct drm_syncobj_handle args;
51440655efefSmrg
51450655efefSmrg    memclear(args);
51460655efefSmrg    args.fd = sync_file_fd;
51470655efefSmrg    args.handle = handle;
51480655efefSmrg    args.flags = DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_IMPORT_SYNC_FILE;
51490655efefSmrg    return drmIoctl(fd, DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE, &args);
51500655efefSmrg}
51510655efefSmrg
51526260e5d5Smrgdrm_public int drmSyncobjExportSyncFile(int fd, uint32_t handle,
51536260e5d5Smrg                                        int *sync_file_fd)
51540655efefSmrg{
51550655efefSmrg    struct drm_syncobj_handle args;
51560655efefSmrg    int ret;
51570655efefSmrg
51580655efefSmrg    memclear(args);
51590655efefSmrg    args.fd = -1;
51600655efefSmrg    args.handle = handle;
51610655efefSmrg    args.flags = DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_EXPORT_SYNC_FILE;
51620655efefSmrg    ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD, &args);
51630655efefSmrg    if (ret)
51642b90624aSmrg        return ret;
51650655efefSmrg    *sync_file_fd = args.fd;
51660655efefSmrg    return 0;
51670655efefSmrg}
51682b90624aSmrg
51696260e5d5Smrgdrm_public int drmSyncobjWait(int fd, uint32_t *handles, unsigned num_handles,
51706260e5d5Smrg                              int64_t timeout_nsec, unsigned flags,
51716260e5d5Smrg                              uint32_t *first_signaled)
51722b90624aSmrg{
51732b90624aSmrg    struct drm_syncobj_wait args;
51742b90624aSmrg    int ret;
51752b90624aSmrg
51762b90624aSmrg    memclear(args);
51772b90624aSmrg    args.handles = (uintptr_t)handles;
51782b90624aSmrg    args.timeout_nsec = timeout_nsec;
51792b90624aSmrg    args.count_handles = num_handles;
51802b90624aSmrg    args.flags = flags;
51812b90624aSmrg
51822b90624aSmrg    ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_WAIT, &args);
51832b90624aSmrg    if (ret < 0)
51842b90624aSmrg        return -errno;
51852b90624aSmrg
51862b90624aSmrg    if (first_signaled)
51872b90624aSmrg        *first_signaled = args.first_signaled;
51882b90624aSmrg    return ret;
51892b90624aSmrg}
51902b90624aSmrg
51916260e5d5Smrgdrm_public int drmSyncobjReset(int fd, const uint32_t *handles,
51926260e5d5Smrg                               uint32_t handle_count)
51932b90624aSmrg{
51942b90624aSmrg    struct drm_syncobj_array args;
51952b90624aSmrg    int ret;
51962b90624aSmrg
51972b90624aSmrg    memclear(args);
51982b90624aSmrg    args.handles = (uintptr_t)handles;
51992b90624aSmrg    args.count_handles = handle_count;
52002b90624aSmrg
52012b90624aSmrg    ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_RESET, &args);
52022b90624aSmrg    return ret;
52032b90624aSmrg}
52042b90624aSmrg
52056260e5d5Smrgdrm_public int drmSyncobjSignal(int fd, const uint32_t *handles,
52066260e5d5Smrg                                uint32_t handle_count)
52072b90624aSmrg{
52082b90624aSmrg    struct drm_syncobj_array args;
52092b90624aSmrg    int ret;
52102b90624aSmrg
52112b90624aSmrg    memclear(args);
52122b90624aSmrg    args.handles = (uintptr_t)handles;
52132b90624aSmrg    args.count_handles = handle_count;
52142b90624aSmrg
52152b90624aSmrg    ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_SIGNAL, &args);
52162b90624aSmrg    return ret;
52172b90624aSmrg}
5218bf6cc7dcSmrg
5219bf6cc7dcSmrgdrm_public int drmSyncobjTimelineSignal(int fd, const uint32_t *handles,
5220bf6cc7dcSmrg					uint64_t *points, uint32_t handle_count)
5221bf6cc7dcSmrg{
5222bf6cc7dcSmrg    struct drm_syncobj_timeline_array args;
5223bf6cc7dcSmrg    int ret;
5224bf6cc7dcSmrg
5225bf6cc7dcSmrg    memclear(args);
5226bf6cc7dcSmrg    args.handles = (uintptr_t)handles;
5227bf6cc7dcSmrg    args.points = (uintptr_t)points;
5228bf6cc7dcSmrg    args.count_handles = handle_count;
5229bf6cc7dcSmrg
5230bf6cc7dcSmrg    ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_TIMELINE_SIGNAL, &args);
5231bf6cc7dcSmrg    return ret;
5232bf6cc7dcSmrg}
5233bf6cc7dcSmrg
5234bf6cc7dcSmrgdrm_public int drmSyncobjTimelineWait(int fd, uint32_t *handles, uint64_t *points,
5235bf6cc7dcSmrg				      unsigned num_handles,
5236bf6cc7dcSmrg				      int64_t timeout_nsec, unsigned flags,
5237bf6cc7dcSmrg				      uint32_t *first_signaled)
5238bf6cc7dcSmrg{
5239bf6cc7dcSmrg    struct drm_syncobj_timeline_wait args;
5240bf6cc7dcSmrg    int ret;
5241bf6cc7dcSmrg
5242bf6cc7dcSmrg    memclear(args);
5243bf6cc7dcSmrg    args.handles = (uintptr_t)handles;
5244bf6cc7dcSmrg    args.points = (uintptr_t)points;
5245bf6cc7dcSmrg    args.timeout_nsec = timeout_nsec;
5246bf6cc7dcSmrg    args.count_handles = num_handles;
5247bf6cc7dcSmrg    args.flags = flags;
5248bf6cc7dcSmrg
5249bf6cc7dcSmrg    ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_TIMELINE_WAIT, &args);
5250bf6cc7dcSmrg    if (ret < 0)
5251bf6cc7dcSmrg        return -errno;
5252bf6cc7dcSmrg
5253bf6cc7dcSmrg    if (first_signaled)
5254bf6cc7dcSmrg        *first_signaled = args.first_signaled;
5255bf6cc7dcSmrg    return ret;
5256bf6cc7dcSmrg}
5257bf6cc7dcSmrg
5258bf6cc7dcSmrg
5259bf6cc7dcSmrgdrm_public int drmSyncobjQuery(int fd, uint32_t *handles, uint64_t *points,
5260bf6cc7dcSmrg			       uint32_t handle_count)
5261bf6cc7dcSmrg{
5262bf6cc7dcSmrg    struct drm_syncobj_timeline_array args;
5263bf6cc7dcSmrg    int ret;
5264bf6cc7dcSmrg
5265bf6cc7dcSmrg    memclear(args);
5266bf6cc7dcSmrg    args.handles = (uintptr_t)handles;
5267bf6cc7dcSmrg    args.points = (uintptr_t)points;
5268bf6cc7dcSmrg    args.count_handles = handle_count;
5269bf6cc7dcSmrg
5270bf6cc7dcSmrg    ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_QUERY, &args);
5271bf6cc7dcSmrg    if (ret)
5272bf6cc7dcSmrg        return ret;
5273bf6cc7dcSmrg    return 0;
5274bf6cc7dcSmrg}
5275bf6cc7dcSmrg
527687bf8e7cSmrgdrm_public int drmSyncobjQuery2(int fd, uint32_t *handles, uint64_t *points,
527787bf8e7cSmrg				uint32_t handle_count, uint32_t flags)
527887bf8e7cSmrg{
527987bf8e7cSmrg    struct drm_syncobj_timeline_array args;
528087bf8e7cSmrg
528187bf8e7cSmrg    memclear(args);
528287bf8e7cSmrg    args.handles = (uintptr_t)handles;
528387bf8e7cSmrg    args.points = (uintptr_t)points;
528487bf8e7cSmrg    args.count_handles = handle_count;
528587bf8e7cSmrg    args.flags = flags;
528687bf8e7cSmrg
528787bf8e7cSmrg    return drmIoctl(fd, DRM_IOCTL_SYNCOBJ_QUERY, &args);
528887bf8e7cSmrg}
528987bf8e7cSmrg
529087bf8e7cSmrg
5291bf6cc7dcSmrgdrm_public int drmSyncobjTransfer(int fd,
5292bf6cc7dcSmrg				  uint32_t dst_handle, uint64_t dst_point,
5293bf6cc7dcSmrg				  uint32_t src_handle, uint64_t src_point,
5294bf6cc7dcSmrg				  uint32_t flags)
5295bf6cc7dcSmrg{
5296bf6cc7dcSmrg    struct drm_syncobj_transfer args;
5297bf6cc7dcSmrg    int ret;
5298bf6cc7dcSmrg
5299bf6cc7dcSmrg    memclear(args);
5300bf6cc7dcSmrg    args.src_handle = src_handle;
5301bf6cc7dcSmrg    args.dst_handle = dst_handle;
5302bf6cc7dcSmrg    args.src_point = src_point;
5303bf6cc7dcSmrg    args.dst_point = dst_point;
5304bf6cc7dcSmrg    args.flags = flags;
5305bf6cc7dcSmrg
5306bf6cc7dcSmrg    ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_TRANSFER, &args);
5307bf6cc7dcSmrg
5308bf6cc7dcSmrg    return ret;
5309bf6cc7dcSmrg}
5310636d5e9fSmrg
531148246ce7Smrgdrm_public int drmSyncobjEventfd(int fd, uint32_t handle, uint64_t point, int ev_fd,
531248246ce7Smrg                                 uint32_t flags)
531348246ce7Smrg{
531448246ce7Smrg    struct drm_syncobj_eventfd args;
531548246ce7Smrg
531648246ce7Smrg    memclear(args);
531748246ce7Smrg    args.handle = handle;
531848246ce7Smrg    args.point = point;
531948246ce7Smrg    args.fd = ev_fd;
532048246ce7Smrg    args.flags = flags;
532148246ce7Smrg
532248246ce7Smrg    return drmIoctl(fd, DRM_IOCTL_SYNCOBJ_EVENTFD, &args);
532348246ce7Smrg}
532448246ce7Smrg
5325636d5e9fSmrgstatic char *
5326636d5e9fSmrgdrmGetFormatModifierFromSimpleTokens(uint64_t modifier)
5327636d5e9fSmrg{
5328636d5e9fSmrg    unsigned int i;
5329636d5e9fSmrg
5330636d5e9fSmrg    for (i = 0; i < ARRAY_SIZE(drm_format_modifier_table); i++) {
5331636d5e9fSmrg        if (drm_format_modifier_table[i].modifier == modifier)
5332636d5e9fSmrg            return strdup(drm_format_modifier_table[i].modifier_name);
5333636d5e9fSmrg    }
5334636d5e9fSmrg
5335636d5e9fSmrg    return NULL;
5336636d5e9fSmrg}
5337636d5e9fSmrg
5338636d5e9fSmrg/** Retrieves a human-readable representation of a vendor (as a string) from
5339636d5e9fSmrg * the format token modifier
5340636d5e9fSmrg *
5341636d5e9fSmrg * \param modifier the format modifier token
5342636d5e9fSmrg * \return a char pointer to the human-readable form of the vendor. Caller is
5343636d5e9fSmrg * responsible for freeing it.
5344636d5e9fSmrg */
5345636d5e9fSmrgdrm_public char *
5346636d5e9fSmrgdrmGetFormatModifierVendor(uint64_t modifier)
5347636d5e9fSmrg{
5348636d5e9fSmrg    unsigned int i;
5349636d5e9fSmrg    uint8_t vendor = fourcc_mod_get_vendor(modifier);
5350636d5e9fSmrg
5351636d5e9fSmrg    for (i = 0; i < ARRAY_SIZE(drm_format_modifier_vendor_table); i++) {
5352636d5e9fSmrg        if (drm_format_modifier_vendor_table[i].vendor == vendor)
5353636d5e9fSmrg            return strdup(drm_format_modifier_vendor_table[i].vendor_name);
5354636d5e9fSmrg    }
5355636d5e9fSmrg
5356636d5e9fSmrg    return NULL;
5357636d5e9fSmrg}
5358636d5e9fSmrg
5359636d5e9fSmrg/** Retrieves a human-readable representation string from a format token
5360636d5e9fSmrg * modifier
5361636d5e9fSmrg *
5362636d5e9fSmrg * If the dedicated function was not able to extract a valid name or searching
5363636d5e9fSmrg * the format modifier was not in the table, this function would return NULL.
5364636d5e9fSmrg *
5365636d5e9fSmrg * \param modifier the token format
5366636d5e9fSmrg * \return a malloc'ed string representation of the modifier. Caller is
5367636d5e9fSmrg * responsible for freeing the string returned.
5368636d5e9fSmrg *
5369636d5e9fSmrg */
5370636d5e9fSmrgdrm_public char *
5371636d5e9fSmrgdrmGetFormatModifierName(uint64_t modifier)
5372636d5e9fSmrg{
5373636d5e9fSmrg    uint8_t vendorid = fourcc_mod_get_vendor(modifier);
5374636d5e9fSmrg    char *modifier_found = NULL;
5375636d5e9fSmrg    unsigned int i;
5376636d5e9fSmrg
5377636d5e9fSmrg    for (i = 0; i < ARRAY_SIZE(modifier_format_vendor_table); i++) {
5378636d5e9fSmrg        if (modifier_format_vendor_table[i].vendor == vendorid)
5379636d5e9fSmrg            modifier_found = modifier_format_vendor_table[i].vendor_cb(modifier);
5380636d5e9fSmrg    }
5381636d5e9fSmrg
5382636d5e9fSmrg    if (!modifier_found)
5383636d5e9fSmrg        return drmGetFormatModifierFromSimpleTokens(modifier);
5384636d5e9fSmrg
5385636d5e9fSmrg    return modifier_found;
5386636d5e9fSmrg}
53873b115362Smrg
53883b115362Smrg/**
53893b115362Smrg * Get a human-readable name for a DRM FourCC format.
53903b115362Smrg *
53913b115362Smrg * \param format The format.
53923b115362Smrg * \return A malloc'ed string containing the format name. Caller is responsible
53933b115362Smrg * for freeing it.
53943b115362Smrg */
53953b115362Smrgdrm_public char *
53963b115362SmrgdrmGetFormatName(uint32_t format)
53973b115362Smrg{
53983b115362Smrg    char *str, code[5];
53993b115362Smrg    const char *be;
54003b115362Smrg    size_t str_size, i;
54013b115362Smrg
54023b115362Smrg    be = (format & DRM_FORMAT_BIG_ENDIAN) ? "_BE" : "";
54033b115362Smrg    format &= ~DRM_FORMAT_BIG_ENDIAN;
54043b115362Smrg
54053b115362Smrg    if (format == DRM_FORMAT_INVALID)
54063b115362Smrg        return strdup("INVALID");
54073b115362Smrg
54083b115362Smrg    code[0] = (char) ((format >> 0) & 0xFF);
54093b115362Smrg    code[1] = (char) ((format >> 8) & 0xFF);
54103b115362Smrg    code[2] = (char) ((format >> 16) & 0xFF);
54113b115362Smrg    code[3] = (char) ((format >> 24) & 0xFF);
54123b115362Smrg    code[4] = '\0';
54133b115362Smrg
54143b115362Smrg    /* Trim spaces at the end */
54153b115362Smrg    for (i = 3; i > 0 && code[i] == ' '; i--)
54163b115362Smrg        code[i] = '\0';
54173b115362Smrg
54183b115362Smrg    str_size = strlen(code) + strlen(be) + 1;
54193b115362Smrg    str = malloc(str_size);
54203b115362Smrg    if (!str)
54213b115362Smrg        return NULL;
54223b115362Smrg
54233b115362Smrg    snprintf(str, str_size, "%s%s", code, be);
54243b115362Smrg
54253b115362Smrg    return str;
54263b115362Smrg}
5427