xf86drm.c revision adfa0b0c
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
63fe517fc9Smrg#include <math.h>
64636d5e9fSmrg#include <inttypes.h>
6522944501Smrg
6687bf8e7cSmrg#if defined(__FreeBSD__)
6787bf8e7cSmrg#include <sys/param.h>
6887bf8e7cSmrg#include <sys/pciio.h>
6987bf8e7cSmrg#endif
7087bf8e7cSmrg
714545e80cSmrg#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
724545e80cSmrg
732ee35494Smrg/* Not all systems have MAP_FAILED defined */
742ee35494Smrg#ifndef MAP_FAILED
752ee35494Smrg#define MAP_FAILED ((void *)-1)
762ee35494Smrg#endif
7722944501Smrg
7822944501Smrg#include "xf86drm.h"
79424e9256Smrg#include "libdrm_macros.h"
80636d5e9fSmrg#include "drm_fourcc.h"
8122944501Smrg
82fe517fc9Smrg#include "util_math.h"
83fe517fc9Smrg
8487bf8e7cSmrg#ifdef __DragonFly__
8522944501Smrg#define DRM_MAJOR 145
8622944501Smrg#endif
8722944501Smrg
8822944501Smrg#ifdef __NetBSD__
892e6867f6Smrg#undef DRM_MAJOR
902e6867f6Smrg#define DRM_MAJOR 180
9106815bcbSmaya#include <sys/param.h>
92a970b457Sriastradh#include <dev/pci/pcireg.h>
93a970b457Sriastradh#include <pci.h>
9422944501Smrg#endif
9522944501Smrg
96fe517fc9Smrg#ifdef __OpenBSD__
97fe517fc9Smrg#ifdef __i386__
98fe517fc9Smrg#define DRM_MAJOR 88
99fe517fc9Smrg#else
100fe517fc9Smrg#define DRM_MAJOR 87
10122944501Smrg#endif
102fe517fc9Smrg#endif /* __OpenBSD__ */
10322944501Smrg
104fe517fc9Smrg#ifndef DRM_MAJOR
105fe517fc9Smrg#define DRM_MAJOR 226 /* Linux */
10622944501Smrg#endif
10722944501Smrg
1084545e80cSmrg#if defined(__OpenBSD__) || defined(__DragonFly__)
1092ee35494Smrgstruct drm_pciinfo {
1102ee35494Smrg	uint16_t	domain;
1112ee35494Smrg	uint8_t		bus;
1122ee35494Smrg	uint8_t		dev;
1132ee35494Smrg	uint8_t		func;
1142ee35494Smrg	uint16_t	vendor_id;
1152ee35494Smrg	uint16_t	device_id;
1162ee35494Smrg	uint16_t	subvendor_id;
1172ee35494Smrg	uint16_t	subdevice_id;
1182ee35494Smrg	uint8_t		revision_id;
1192ee35494Smrg};
1202ee35494Smrg
1212ee35494Smrg#define DRM_IOCTL_GET_PCIINFO	DRM_IOR(0x15, struct drm_pciinfo)
12211c53d23Schristos#endif
12311c53d23Schristos
12422944501Smrg#define DRM_MSG_VERBOSITY 3
12522944501Smrg
126424e9256Smrg#define memclear(s) memset(&s, 0, sizeof(s))
12722944501Smrg
12822944501Smrgstatic drmServerInfoPtr drm_server_info;
12922944501Smrg
13087bf8e7cSmrgstatic bool drmNodeIsDRM(int maj, int min);
13187bf8e7cSmrgstatic char *drmGetMinorNameForFD(int fd, int type);
13287bf8e7cSmrg
133636d5e9fSmrg#define DRM_MODIFIER(v, f, f_name) \
134636d5e9fSmrg       .modifier = DRM_FORMAT_MOD_##v ## _ ##f, \
135636d5e9fSmrg       .modifier_name = #f_name
136636d5e9fSmrg
137636d5e9fSmrg#define DRM_MODIFIER_INVALID(v, f_name) \
138636d5e9fSmrg       .modifier = DRM_FORMAT_MOD_INVALID, .modifier_name = #f_name
139636d5e9fSmrg
140636d5e9fSmrg#define DRM_MODIFIER_LINEAR(v, f_name) \
141636d5e9fSmrg       .modifier = DRM_FORMAT_MOD_LINEAR, .modifier_name = #f_name
142636d5e9fSmrg
143636d5e9fSmrg/* Intel is abit special as the format doesn't follow other vendors naming
144636d5e9fSmrg * scheme */
145636d5e9fSmrg#define DRM_MODIFIER_INTEL(f, f_name) \
146636d5e9fSmrg       .modifier = I915_FORMAT_MOD_##f, .modifier_name = #f_name
147636d5e9fSmrg
148636d5e9fSmrgstruct drmFormatModifierInfo {
149636d5e9fSmrg    uint64_t modifier;
150636d5e9fSmrg    const char *modifier_name;
151636d5e9fSmrg};
152636d5e9fSmrg
153636d5e9fSmrgstruct drmFormatModifierVendorInfo {
154636d5e9fSmrg    uint8_t vendor;
155636d5e9fSmrg    const char *vendor_name;
156636d5e9fSmrg};
157636d5e9fSmrg
158636d5e9fSmrg#include "generated_static_table_fourcc.h"
159636d5e9fSmrg
160636d5e9fSmrgstruct drmVendorInfo {
161636d5e9fSmrg    uint8_t vendor;
162636d5e9fSmrg    char *(*vendor_cb)(uint64_t modifier);
163636d5e9fSmrg};
164636d5e9fSmrg
165636d5e9fSmrgstruct drmFormatVendorModifierInfo {
166636d5e9fSmrg    uint64_t modifier;
167636d5e9fSmrg    const char *modifier_name;
168636d5e9fSmrg};
169636d5e9fSmrg
170636d5e9fSmrgstatic char *
171636d5e9fSmrgdrmGetFormatModifierNameFromArm(uint64_t modifier);
172636d5e9fSmrg
173636d5e9fSmrgstatic char *
174636d5e9fSmrgdrmGetFormatModifierNameFromNvidia(uint64_t modifier);
175636d5e9fSmrg
176636d5e9fSmrgstatic char *
177636d5e9fSmrgdrmGetFormatModifierNameFromAmd(uint64_t modifier);
178636d5e9fSmrg
179636d5e9fSmrgstatic char *
180636d5e9fSmrgdrmGetFormatModifierNameFromAmlogic(uint64_t modifier);
181636d5e9fSmrg
182636d5e9fSmrgstatic const struct drmVendorInfo modifier_format_vendor_table[] = {
183636d5e9fSmrg    { DRM_FORMAT_MOD_VENDOR_ARM, drmGetFormatModifierNameFromArm },
184636d5e9fSmrg    { DRM_FORMAT_MOD_VENDOR_NVIDIA, drmGetFormatModifierNameFromNvidia },
185636d5e9fSmrg    { DRM_FORMAT_MOD_VENDOR_AMD, drmGetFormatModifierNameFromAmd },
186636d5e9fSmrg    { DRM_FORMAT_MOD_VENDOR_AMLOGIC, drmGetFormatModifierNameFromAmlogic },
187636d5e9fSmrg};
188636d5e9fSmrg
189636d5e9fSmrg#ifndef AFBC_FORMAT_MOD_MODE_VALUE_MASK
190636d5e9fSmrg#define AFBC_FORMAT_MOD_MODE_VALUE_MASK	0x000fffffffffffffULL
191636d5e9fSmrg#endif
192636d5e9fSmrg
193636d5e9fSmrgstatic const struct drmFormatVendorModifierInfo arm_mode_value_table[] = {
194636d5e9fSmrg    { AFBC_FORMAT_MOD_YTR,          "YTR" },
195636d5e9fSmrg    { AFBC_FORMAT_MOD_SPLIT,        "SPLIT" },
196636d5e9fSmrg    { AFBC_FORMAT_MOD_SPARSE,       "SPARSE" },
197636d5e9fSmrg    { AFBC_FORMAT_MOD_CBR,          "CBR" },
198636d5e9fSmrg    { AFBC_FORMAT_MOD_TILED,        "TILED" },
199636d5e9fSmrg    { AFBC_FORMAT_MOD_SC,           "SC" },
200636d5e9fSmrg    { AFBC_FORMAT_MOD_DB,           "DB" },
201636d5e9fSmrg    { AFBC_FORMAT_MOD_BCH,          "BCH" },
202636d5e9fSmrg    { AFBC_FORMAT_MOD_USM,          "USM" },
203636d5e9fSmrg};
204636d5e9fSmrg
205636d5e9fSmrgstatic bool is_x_t_amd_gfx9_tile(uint64_t tile)
206636d5e9fSmrg{
207636d5e9fSmrg    switch (tile) {
208636d5e9fSmrg    case AMD_FMT_MOD_TILE_GFX9_64K_S_X:
209636d5e9fSmrg    case AMD_FMT_MOD_TILE_GFX9_64K_D_X:
210636d5e9fSmrg    case AMD_FMT_MOD_TILE_GFX9_64K_R_X:
211636d5e9fSmrg           return true;
212636d5e9fSmrg    }
213636d5e9fSmrg
214636d5e9fSmrg    return false;
215636d5e9fSmrg}
216636d5e9fSmrg
217adfa0b0cSmrgstatic bool
218adfa0b0cSmrgdrmGetAfbcFormatModifierNameFromArm(uint64_t modifier, FILE *fp)
219636d5e9fSmrg{
220636d5e9fSmrg    uint64_t mode_value = modifier & AFBC_FORMAT_MOD_MODE_VALUE_MASK;
221636d5e9fSmrg    uint64_t block_size = mode_value & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK;
222636d5e9fSmrg
223636d5e9fSmrg    const char *block = NULL;
224636d5e9fSmrg    const char *mode = NULL;
225636d5e9fSmrg    bool did_print_mode = false;
226636d5e9fSmrg
227636d5e9fSmrg    /* add block, can only have a (single) block */
228636d5e9fSmrg    switch (block_size) {
229636d5e9fSmrg    case AFBC_FORMAT_MOD_BLOCK_SIZE_16x16:
230636d5e9fSmrg        block = "16x16";
231636d5e9fSmrg        break;
232636d5e9fSmrg    case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8:
233636d5e9fSmrg        block = "32x8";
234636d5e9fSmrg        break;
235636d5e9fSmrg    case AFBC_FORMAT_MOD_BLOCK_SIZE_64x4:
236636d5e9fSmrg        block = "64x4";
237636d5e9fSmrg        break;
238636d5e9fSmrg    case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8_64x4:
239636d5e9fSmrg        block = "32x8_64x4";
240636d5e9fSmrg        break;
241636d5e9fSmrg    }
242636d5e9fSmrg
243636d5e9fSmrg    if (!block) {
244adfa0b0cSmrg        return false;
245636d5e9fSmrg    }
246636d5e9fSmrg
247636d5e9fSmrg    fprintf(fp, "BLOCK_SIZE=%s,", block);
248636d5e9fSmrg
249636d5e9fSmrg    /* add mode */
250adfa0b0cSmrg    for (unsigned int i = 0; i < ARRAY_SIZE(arm_mode_value_table); i++) {
251636d5e9fSmrg        if (arm_mode_value_table[i].modifier & mode_value) {
252636d5e9fSmrg            mode = arm_mode_value_table[i].modifier_name;
253636d5e9fSmrg            if (!did_print_mode) {
254636d5e9fSmrg                fprintf(fp, "MODE=%s", mode);
255636d5e9fSmrg                did_print_mode = true;
256636d5e9fSmrg            } else {
257636d5e9fSmrg                fprintf(fp, "|%s", mode);
258636d5e9fSmrg            }
259636d5e9fSmrg        }
260636d5e9fSmrg    }
261636d5e9fSmrg
262adfa0b0cSmrg    return true;
263adfa0b0cSmrg}
264adfa0b0cSmrg
265adfa0b0cSmrgstatic bool
266adfa0b0cSmrgdrmGetAfrcFormatModifierNameFromArm(uint64_t modifier, FILE *fp)
267adfa0b0cSmrg{
268adfa0b0cSmrg    for (unsigned int i = 0; i < 2; ++i) {
269adfa0b0cSmrg        uint64_t coding_unit_block =
270adfa0b0cSmrg          (modifier >> (i * 4)) & AFRC_FORMAT_MOD_CU_SIZE_MASK;
271adfa0b0cSmrg        const char *coding_unit_size = NULL;
272adfa0b0cSmrg
273adfa0b0cSmrg        switch (coding_unit_block) {
274adfa0b0cSmrg        case AFRC_FORMAT_MOD_CU_SIZE_16:
275adfa0b0cSmrg            coding_unit_size = "CU_16";
276adfa0b0cSmrg            break;
277adfa0b0cSmrg        case AFRC_FORMAT_MOD_CU_SIZE_24:
278adfa0b0cSmrg            coding_unit_size = "CU_24";
279adfa0b0cSmrg            break;
280adfa0b0cSmrg        case AFRC_FORMAT_MOD_CU_SIZE_32:
281adfa0b0cSmrg            coding_unit_size = "CU_32";
282adfa0b0cSmrg            break;
283adfa0b0cSmrg        }
284adfa0b0cSmrg
285adfa0b0cSmrg        if (!coding_unit_size) {
286adfa0b0cSmrg            if (i == 0) {
287adfa0b0cSmrg                return false;
288adfa0b0cSmrg            }
289adfa0b0cSmrg            break;
290adfa0b0cSmrg        }
291adfa0b0cSmrg
292adfa0b0cSmrg        if (i == 0) {
293adfa0b0cSmrg            fprintf(fp, "P0=%s,", coding_unit_size);
294adfa0b0cSmrg        } else {
295adfa0b0cSmrg            fprintf(fp, "P12=%s,", coding_unit_size);
296adfa0b0cSmrg        }
297adfa0b0cSmrg    }
298adfa0b0cSmrg
299adfa0b0cSmrg    bool scan_layout =
300adfa0b0cSmrg        (modifier & AFRC_FORMAT_MOD_LAYOUT_SCAN) == AFRC_FORMAT_MOD_LAYOUT_SCAN;
301adfa0b0cSmrg    if (scan_layout) {
302adfa0b0cSmrg        fprintf(fp, "SCAN");
303adfa0b0cSmrg    } else {
304adfa0b0cSmrg        fprintf(fp, "ROT");
305adfa0b0cSmrg    }
306adfa0b0cSmrg    return true;
307adfa0b0cSmrg}
308adfa0b0cSmrg
309adfa0b0cSmrgstatic char *
310adfa0b0cSmrgdrmGetFormatModifierNameFromArm(uint64_t modifier)
311adfa0b0cSmrg{
312adfa0b0cSmrg    uint64_t type = (modifier >> 52) & 0xf;
313adfa0b0cSmrg
314adfa0b0cSmrg    FILE *fp;
315adfa0b0cSmrg    size_t size = 0;
316adfa0b0cSmrg    char *modifier_name = NULL;
317adfa0b0cSmrg    bool result = false;
318adfa0b0cSmrg
319adfa0b0cSmrg    fp = open_memstream(&modifier_name, &size);
320adfa0b0cSmrg    if (!fp)
321adfa0b0cSmrg        return NULL;
322adfa0b0cSmrg
323adfa0b0cSmrg    switch (type) {
324adfa0b0cSmrg    case DRM_FORMAT_MOD_ARM_TYPE_AFBC:
325adfa0b0cSmrg        result = drmGetAfbcFormatModifierNameFromArm(modifier, fp);
326adfa0b0cSmrg        break;
327adfa0b0cSmrg    case DRM_FORMAT_MOD_ARM_TYPE_AFRC:
328adfa0b0cSmrg        result = drmGetAfrcFormatModifierNameFromArm(modifier, fp);
329adfa0b0cSmrg        break;
330adfa0b0cSmrg    /* misc type is already handled by the static table */
331adfa0b0cSmrg    case DRM_FORMAT_MOD_ARM_TYPE_MISC:
332adfa0b0cSmrg    default:
333adfa0b0cSmrg        result = false;
334adfa0b0cSmrg        break;
335adfa0b0cSmrg    }
336adfa0b0cSmrg
337636d5e9fSmrg    fclose(fp);
338adfa0b0cSmrg    if (!result) {
339adfa0b0cSmrg        free(modifier_name);
340adfa0b0cSmrg        return NULL;
341adfa0b0cSmrg    }
342adfa0b0cSmrg
343636d5e9fSmrg    return modifier_name;
344636d5e9fSmrg}
345636d5e9fSmrg
346636d5e9fSmrgstatic char *
347636d5e9fSmrgdrmGetFormatModifierNameFromNvidia(uint64_t modifier)
348636d5e9fSmrg{
349636d5e9fSmrg    uint64_t height, kind, gen, sector, compression;
350636d5e9fSmrg
351636d5e9fSmrg    height = modifier & 0xf;
352636d5e9fSmrg    kind = (modifier >> 12) & 0xff;
353636d5e9fSmrg
354636d5e9fSmrg    gen = (modifier >> 20) & 0x3;
355636d5e9fSmrg    sector = (modifier >> 22) & 0x1;
356636d5e9fSmrg    compression = (modifier >> 23) & 0x7;
357636d5e9fSmrg
358636d5e9fSmrg    /* just in case there could other simpler modifiers, not yet added, avoid
359636d5e9fSmrg     * testing against TEGRA_TILE */
360636d5e9fSmrg    if ((modifier & 0x10) == 0x10) {
361636d5e9fSmrg        char *mod_nvidia;
362636d5e9fSmrg        asprintf(&mod_nvidia, "BLOCK_LINEAR_2D,HEIGHT=%"PRIu64",KIND=%"PRIu64","
363636d5e9fSmrg                 "GEN=%"PRIu64",SECTOR=%"PRIu64",COMPRESSION=%"PRIu64"", height,
364636d5e9fSmrg                 kind, gen, sector, compression);
365636d5e9fSmrg        return mod_nvidia;
366636d5e9fSmrg    }
367636d5e9fSmrg
368636d5e9fSmrg    return  NULL;
369636d5e9fSmrg}
370636d5e9fSmrg
371636d5e9fSmrgstatic void
372636d5e9fSmrgdrmGetFormatModifierNameFromAmdDcc(uint64_t modifier, FILE *fp)
373636d5e9fSmrg{
374636d5e9fSmrg    uint64_t dcc_max_compressed_block =
375636d5e9fSmrg                AMD_FMT_MOD_GET(DCC_MAX_COMPRESSED_BLOCK, modifier);
376636d5e9fSmrg    uint64_t dcc_retile = AMD_FMT_MOD_GET(DCC_RETILE, modifier);
377636d5e9fSmrg
378636d5e9fSmrg    const char *dcc_max_compressed_block_str = NULL;
379636d5e9fSmrg
380636d5e9fSmrg    fprintf(fp, ",DCC");
381636d5e9fSmrg
382636d5e9fSmrg    if (dcc_retile)
383636d5e9fSmrg        fprintf(fp, ",DCC_RETILE");
384636d5e9fSmrg
385636d5e9fSmrg    if (!dcc_retile && AMD_FMT_MOD_GET(DCC_PIPE_ALIGN, modifier))
386636d5e9fSmrg        fprintf(fp, ",DCC_PIPE_ALIGN");
387636d5e9fSmrg
388636d5e9fSmrg    if (AMD_FMT_MOD_GET(DCC_INDEPENDENT_64B, modifier))
389636d5e9fSmrg        fprintf(fp, ",DCC_INDEPENDENT_64B");
390636d5e9fSmrg
391636d5e9fSmrg    if (AMD_FMT_MOD_GET(DCC_INDEPENDENT_128B, modifier))
392636d5e9fSmrg        fprintf(fp, ",DCC_INDEPENDENT_128B");
393636d5e9fSmrg
394636d5e9fSmrg    switch (dcc_max_compressed_block) {
395636d5e9fSmrg    case AMD_FMT_MOD_DCC_BLOCK_64B:
396636d5e9fSmrg        dcc_max_compressed_block_str = "64B";
397636d5e9fSmrg        break;
398636d5e9fSmrg    case AMD_FMT_MOD_DCC_BLOCK_128B:
399636d5e9fSmrg        dcc_max_compressed_block_str = "128B";
400636d5e9fSmrg        break;
401636d5e9fSmrg    case AMD_FMT_MOD_DCC_BLOCK_256B:
402636d5e9fSmrg        dcc_max_compressed_block_str = "256B";
403636d5e9fSmrg        break;
404636d5e9fSmrg    }
405636d5e9fSmrg
406636d5e9fSmrg    if (dcc_max_compressed_block_str)
407636d5e9fSmrg        fprintf(fp, ",DCC_MAX_COMPRESSED_BLOCK=%s",
408636d5e9fSmrg                dcc_max_compressed_block_str);
409636d5e9fSmrg
410636d5e9fSmrg    if (AMD_FMT_MOD_GET(DCC_CONSTANT_ENCODE, modifier))
411636d5e9fSmrg        fprintf(fp, ",DCC_CONSTANT_ENCODE");
412636d5e9fSmrg}
413636d5e9fSmrg
414636d5e9fSmrgstatic void
415636d5e9fSmrgdrmGetFormatModifierNameFromAmdTile(uint64_t modifier, FILE *fp)
416636d5e9fSmrg{
417636d5e9fSmrg    uint64_t pipe_xor_bits, bank_xor_bits, packers, rb;
418636d5e9fSmrg    uint64_t pipe, pipe_align, dcc, dcc_retile, tile_version;
419636d5e9fSmrg
420636d5e9fSmrg    pipe_align = AMD_FMT_MOD_GET(DCC_PIPE_ALIGN, modifier);
421636d5e9fSmrg    pipe_xor_bits = AMD_FMT_MOD_GET(PIPE_XOR_BITS, modifier);
422636d5e9fSmrg    dcc = AMD_FMT_MOD_GET(DCC, modifier);
423636d5e9fSmrg    dcc_retile = AMD_FMT_MOD_GET(DCC_RETILE, modifier);
424636d5e9fSmrg    tile_version = AMD_FMT_MOD_GET(TILE_VERSION, modifier);
425636d5e9fSmrg
426636d5e9fSmrg    fprintf(fp, ",PIPE_XOR_BITS=%"PRIu64, pipe_xor_bits);
427636d5e9fSmrg
428636d5e9fSmrg    if (tile_version == AMD_FMT_MOD_TILE_VER_GFX9) {
429636d5e9fSmrg        bank_xor_bits = AMD_FMT_MOD_GET(BANK_XOR_BITS, modifier);
430636d5e9fSmrg        fprintf(fp, ",BANK_XOR_BITS=%"PRIu64, bank_xor_bits);
431636d5e9fSmrg    }
432636d5e9fSmrg
433636d5e9fSmrg    if (tile_version == AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS) {
434636d5e9fSmrg        packers = AMD_FMT_MOD_GET(PACKERS, modifier);
435636d5e9fSmrg        fprintf(fp, ",PACKERS=%"PRIu64, packers);
436636d5e9fSmrg    }
437636d5e9fSmrg
438636d5e9fSmrg    if (dcc && tile_version == AMD_FMT_MOD_TILE_VER_GFX9) {
439636d5e9fSmrg        rb = AMD_FMT_MOD_GET(RB, modifier);
440636d5e9fSmrg        fprintf(fp, ",RB=%"PRIu64, rb);
441636d5e9fSmrg    }
442636d5e9fSmrg
443636d5e9fSmrg    if (dcc && tile_version == AMD_FMT_MOD_TILE_VER_GFX9 &&
444636d5e9fSmrg        (dcc_retile || pipe_align)) {
445636d5e9fSmrg        pipe = AMD_FMT_MOD_GET(PIPE, modifier);
446636d5e9fSmrg        fprintf(fp, ",PIPE_%"PRIu64, pipe);
447636d5e9fSmrg    }
448636d5e9fSmrg}
449636d5e9fSmrg
450636d5e9fSmrgstatic char *
451636d5e9fSmrgdrmGetFormatModifierNameFromAmd(uint64_t modifier)
452636d5e9fSmrg{
453636d5e9fSmrg    uint64_t tile, tile_version, dcc;
454636d5e9fSmrg    FILE *fp;
455636d5e9fSmrg    char *mod_amd = NULL;
456636d5e9fSmrg    size_t size = 0;
457636d5e9fSmrg
458636d5e9fSmrg    const char *str_tile = NULL;
459636d5e9fSmrg    const char *str_tile_version = NULL;
460636d5e9fSmrg
461636d5e9fSmrg    tile = AMD_FMT_MOD_GET(TILE, modifier);
462636d5e9fSmrg    tile_version = AMD_FMT_MOD_GET(TILE_VERSION, modifier);
463636d5e9fSmrg    dcc = AMD_FMT_MOD_GET(DCC, modifier);
464636d5e9fSmrg
465636d5e9fSmrg    fp = open_memstream(&mod_amd, &size);
466636d5e9fSmrg    if (!fp)
467636d5e9fSmrg        return NULL;
468636d5e9fSmrg
469636d5e9fSmrg    /* add tile  */
470636d5e9fSmrg    switch (tile_version) {
471636d5e9fSmrg    case AMD_FMT_MOD_TILE_VER_GFX9:
472636d5e9fSmrg        str_tile_version = "GFX9";
473636d5e9fSmrg        break;
474636d5e9fSmrg    case AMD_FMT_MOD_TILE_VER_GFX10:
475636d5e9fSmrg        str_tile_version = "GFX10";
476636d5e9fSmrg        break;
477636d5e9fSmrg    case AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS:
478636d5e9fSmrg        str_tile_version = "GFX10_RBPLUS";
479636d5e9fSmrg        break;
480636d5e9fSmrg    }
481636d5e9fSmrg
482636d5e9fSmrg    if (str_tile_version) {
483636d5e9fSmrg        fprintf(fp, "%s", str_tile_version);
484636d5e9fSmrg    } else {
485636d5e9fSmrg        fclose(fp);
486636d5e9fSmrg        free(mod_amd);
487636d5e9fSmrg        return NULL;
488636d5e9fSmrg    }
489636d5e9fSmrg
490636d5e9fSmrg    /* add tile str */
491636d5e9fSmrg    switch (tile) {
492636d5e9fSmrg    case AMD_FMT_MOD_TILE_GFX9_64K_S:
493636d5e9fSmrg        str_tile = "GFX9_64K_S";
494636d5e9fSmrg        break;
495636d5e9fSmrg    case AMD_FMT_MOD_TILE_GFX9_64K_D:
496636d5e9fSmrg        str_tile = "GFX9_64K_D";
497636d5e9fSmrg        break;
498636d5e9fSmrg    case AMD_FMT_MOD_TILE_GFX9_64K_S_X:
499636d5e9fSmrg        str_tile = "GFX9_64K_S_X";
500636d5e9fSmrg        break;
501636d5e9fSmrg    case AMD_FMT_MOD_TILE_GFX9_64K_D_X:
502636d5e9fSmrg        str_tile = "GFX9_64K_D_X";
503636d5e9fSmrg        break;
504636d5e9fSmrg    case AMD_FMT_MOD_TILE_GFX9_64K_R_X:
505636d5e9fSmrg        str_tile = "GFX9_64K_R_X";
506636d5e9fSmrg        break;
507636d5e9fSmrg    }
508636d5e9fSmrg
509636d5e9fSmrg    if (str_tile)
510636d5e9fSmrg        fprintf(fp, ",%s", str_tile);
511636d5e9fSmrg
512636d5e9fSmrg    if (dcc)
513636d5e9fSmrg        drmGetFormatModifierNameFromAmdDcc(modifier, fp);
514636d5e9fSmrg
515636d5e9fSmrg    if (tile_version >= AMD_FMT_MOD_TILE_VER_GFX9 && is_x_t_amd_gfx9_tile(tile))
516636d5e9fSmrg        drmGetFormatModifierNameFromAmdTile(modifier, fp);
517636d5e9fSmrg
518636d5e9fSmrg    fclose(fp);
519636d5e9fSmrg    return mod_amd;
520636d5e9fSmrg}
521636d5e9fSmrg
522636d5e9fSmrgstatic char *
523636d5e9fSmrgdrmGetFormatModifierNameFromAmlogic(uint64_t modifier)
524636d5e9fSmrg{
525636d5e9fSmrg    uint64_t layout = modifier & 0xff;
526636d5e9fSmrg    uint64_t options = (modifier >> 8) & 0xff;
527636d5e9fSmrg    char *mod_amlogic = NULL;
528636d5e9fSmrg
529636d5e9fSmrg    const char *layout_str;
530636d5e9fSmrg    const char *opts_str;
531636d5e9fSmrg
532636d5e9fSmrg    switch (layout) {
533636d5e9fSmrg    case AMLOGIC_FBC_LAYOUT_BASIC:
534636d5e9fSmrg       layout_str = "BASIC";
535636d5e9fSmrg       break;
536636d5e9fSmrg    case AMLOGIC_FBC_LAYOUT_SCATTER:
537636d5e9fSmrg       layout_str = "SCATTER";
538636d5e9fSmrg       break;
539636d5e9fSmrg    default:
540636d5e9fSmrg       layout_str = "INVALID_LAYOUT";
541636d5e9fSmrg       break;
542636d5e9fSmrg    }
543636d5e9fSmrg
544636d5e9fSmrg    if (options & AMLOGIC_FBC_OPTION_MEM_SAVING)
545636d5e9fSmrg        opts_str = "MEM_SAVING";
546636d5e9fSmrg    else
547636d5e9fSmrg        opts_str = "0";
548636d5e9fSmrg
549636d5e9fSmrg    asprintf(&mod_amlogic, "FBC,LAYOUT=%s,OPTIONS=%s", layout_str, opts_str);
550636d5e9fSmrg    return mod_amlogic;
551636d5e9fSmrg}
552636d5e9fSmrg
5534b3d3f37Smrgstatic unsigned log2_int(unsigned x)
5544b3d3f37Smrg{
5554b3d3f37Smrg    unsigned l;
5564b3d3f37Smrg
5574b3d3f37Smrg    if (x < 2) {
5584b3d3f37Smrg        return 0;
5594b3d3f37Smrg    }
5604b3d3f37Smrg    for (l = 2; ; l++) {
5614b3d3f37Smrg        if ((unsigned)(1 << l) > x) {
5624b3d3f37Smrg            return l - 1;
5634b3d3f37Smrg        }
5644b3d3f37Smrg    }
5654b3d3f37Smrg    return 0;
5664b3d3f37Smrg}
5674b3d3f37Smrg
5684b3d3f37Smrg
5696260e5d5Smrgdrm_public void drmSetServerInfo(drmServerInfoPtr info)
57022944501Smrg{
57122944501Smrg    drm_server_info = info;
57222944501Smrg}
57322944501Smrg
57422944501Smrg/**
57522944501Smrg * Output a message to stderr.
57622944501Smrg *
57722944501Smrg * \param format printf() like format string.
57822944501Smrg *
57922944501Smrg * \internal
58022944501Smrg * This function is a wrapper around vfprintf().
58122944501Smrg */
58222944501Smrg
583a7d7de1eSmrgstatic int DRM_PRINTFLIKE(1, 0)
584a7d7de1eSmrgdrmDebugPrint(const char *format, va_list ap)
58522944501Smrg{
58622944501Smrg    return vfprintf(stderr, format, ap);
58722944501Smrg}
58822944501Smrg
5896260e5d5Smrgdrm_public void
59022944501SmrgdrmMsg(const char *format, ...)
59122944501Smrg{
592fe517fc9Smrg    va_list ap;
59322944501Smrg    const char *env;
594fe517fc9Smrg    if (((env = getenv("LIBGL_DEBUG")) && strstr(env, "verbose")) ||
595fe517fc9Smrg        (drm_server_info && drm_server_info->debug_print))
59622944501Smrg    {
597fe517fc9Smrg        va_start(ap, format);
598fe517fc9Smrg        if (drm_server_info) {
599fe517fc9Smrg            drm_server_info->debug_print(format,ap);
600fe517fc9Smrg        } else {
601fe517fc9Smrg            drmDebugPrint(format, ap);
602fe517fc9Smrg        }
603fe517fc9Smrg        va_end(ap);
60422944501Smrg    }
60522944501Smrg}
60622944501Smrg
60722944501Smrgstatic void *drmHashTable = NULL; /* Context switch callbacks */
60822944501Smrg
6096260e5d5Smrgdrm_public void *drmGetHashTable(void)
61022944501Smrg{
61122944501Smrg    return drmHashTable;
61222944501Smrg}
61322944501Smrg
6146260e5d5Smrgdrm_public void *drmMalloc(int size)
61522944501Smrg{
616424e9256Smrg    return calloc(1, size);
61722944501Smrg}
61822944501Smrg
6196260e5d5Smrgdrm_public void drmFree(void *pt)
62022944501Smrg{
621424e9256Smrg    free(pt);
62222944501Smrg}
62322944501Smrg
62422944501Smrg/**
625bf6cc7dcSmrg * Call ioctl, restarting if it is interrupted
62622944501Smrg */
6276260e5d5Smrgdrm_public int
62822944501SmrgdrmIoctl(int fd, unsigned long request, void *arg)
62922944501Smrg{
630fe517fc9Smrg    int ret;
63122944501Smrg
63222944501Smrg    do {
633fe517fc9Smrg        ret = ioctl(fd, request, arg);
63422944501Smrg    } while (ret == -1 && (errno == EINTR || errno == EAGAIN));
63522944501Smrg    return ret;
63622944501Smrg}
63722944501Smrg
63822944501Smrgstatic unsigned long drmGetKeyFromFd(int fd)
63922944501Smrg{
64022944501Smrg    stat_t     st;
64122944501Smrg
64222944501Smrg    st.st_rdev = 0;
64322944501Smrg    fstat(fd, &st);
64422944501Smrg    return st.st_rdev;
64522944501Smrg}
64622944501Smrg
6476260e5d5Smrgdrm_public drmHashEntry *drmGetEntry(int fd)
64822944501Smrg{
64922944501Smrg    unsigned long key = drmGetKeyFromFd(fd);
65022944501Smrg    void          *value;
65122944501Smrg    drmHashEntry  *entry;
65222944501Smrg
65322944501Smrg    if (!drmHashTable)
654fe517fc9Smrg        drmHashTable = drmHashCreate();
65522944501Smrg
65622944501Smrg    if (drmHashLookup(drmHashTable, key, &value)) {
657fe517fc9Smrg        entry           = drmMalloc(sizeof(*entry));
658fe517fc9Smrg        entry->fd       = fd;
659fe517fc9Smrg        entry->f        = NULL;
660fe517fc9Smrg        entry->tagTable = drmHashCreate();
661fe517fc9Smrg        drmHashInsert(drmHashTable, key, entry);
66222944501Smrg    } else {
663fe517fc9Smrg        entry = value;
66422944501Smrg    }
66522944501Smrg    return entry;
66622944501Smrg}
66722944501Smrg
66822944501Smrg/**
66922944501Smrg * Compare two busid strings
67022944501Smrg *
67122944501Smrg * \param first
67222944501Smrg * \param second
67322944501Smrg *
67422944501Smrg * \return 1 if matched.
67522944501Smrg *
67622944501Smrg * \internal
67722944501Smrg * This function compares two bus ID strings.  It understands the older
67822944501Smrg * PCI:b:d:f format and the newer pci:oooo:bb:dd.f format.  In the format, o is
67922944501Smrg * domain, b is bus, d is device, f is function.
68022944501Smrg */
6816d98c517Smrgstatic int drmMatchBusID(const char *id1, const char *id2, int pci_domain_ok)
68222944501Smrg{
68322944501Smrg    /* First, check if the IDs are exactly the same */
68422944501Smrg    if (strcasecmp(id1, id2) == 0)
685fe517fc9Smrg        return 1;
68622944501Smrg
68722944501Smrg    /* Try to match old/new-style PCI bus IDs. */
68822944501Smrg    if (strncasecmp(id1, "pci", 3) == 0) {
689fe517fc9Smrg        unsigned int o1, b1, d1, f1;
690fe517fc9Smrg        unsigned int o2, b2, d2, f2;
691fe517fc9Smrg        int ret;
692fe517fc9Smrg
693fe517fc9Smrg        ret = sscanf(id1, "pci:%04x:%02x:%02x.%u", &o1, &b1, &d1, &f1);
694fe517fc9Smrg        if (ret != 4) {
695fe517fc9Smrg            o1 = 0;
696fe517fc9Smrg            ret = sscanf(id1, "PCI:%u:%u:%u", &b1, &d1, &f1);
697fe517fc9Smrg            if (ret != 3)
698fe517fc9Smrg                return 0;
699fe517fc9Smrg        }
700fe517fc9Smrg
701fe517fc9Smrg        ret = sscanf(id2, "pci:%04x:%02x:%02x.%u", &o2, &b2, &d2, &f2);
702fe517fc9Smrg        if (ret != 4) {
703fe517fc9Smrg            o2 = 0;
704fe517fc9Smrg            ret = sscanf(id2, "PCI:%u:%u:%u", &b2, &d2, &f2);
705fe517fc9Smrg            if (ret != 3)
706fe517fc9Smrg                return 0;
707fe517fc9Smrg        }
708fe517fc9Smrg
709fe517fc9Smrg        /* If domains aren't properly supported by the kernel interface,
710fe517fc9Smrg         * just ignore them, which sucks less than picking a totally random
711fe517fc9Smrg         * card with "open by name"
712fe517fc9Smrg         */
713fe517fc9Smrg        if (!pci_domain_ok)
714fe517fc9Smrg            o1 = o2 = 0;
715fe517fc9Smrg
716fe517fc9Smrg        if ((o1 != o2) || (b1 != b2) || (d1 != d2) || (f1 != f2))
717fe517fc9Smrg            return 0;
718fe517fc9Smrg        else
719fe517fc9Smrg            return 1;
72022944501Smrg    }
72122944501Smrg    return 0;
72222944501Smrg}
72322944501Smrg
72422944501Smrg/**
72522944501Smrg * Handles error checking for chown call.
72622944501Smrg *
72722944501Smrg * \param path to file.
72822944501Smrg * \param id of the new owner.
72922944501Smrg * \param id of the new group.
73022944501Smrg *
73122944501Smrg * \return zero if success or -1 if failure.
73222944501Smrg *
73322944501Smrg * \internal
73422944501Smrg * Checks for failure. If failure was caused by signal call chown again.
735bf6cc7dcSmrg * If any other failure happened then it will output error message using
73622944501Smrg * drmMsg() call.
73722944501Smrg */
7386260e5d5Smrg#if !UDEV
73922944501Smrgstatic int chown_check_return(const char *path, uid_t owner, gid_t group)
74022944501Smrg{
741fe517fc9Smrg        int rv;
74222944501Smrg
743fe517fc9Smrg        do {
744fe517fc9Smrg            rv = chown(path, owner, group);
745fe517fc9Smrg        } while (rv != 0 && errno == EINTR);
74622944501Smrg
747fe517fc9Smrg        if (rv == 0)
748fe517fc9Smrg            return 0;
74922944501Smrg
750fe517fc9Smrg        drmMsg("Failed to change owner or group for file %s! %d: %s\n",
751fe517fc9Smrg               path, errno, strerror(errno));
752fe517fc9Smrg        return -1;
75322944501Smrg}
754424e9256Smrg#endif
75522944501Smrg
75682025ec7Smrgstatic const char *drmGetDeviceName(int type)
75782025ec7Smrg{
75882025ec7Smrg    switch (type) {
75982025ec7Smrg    case DRM_NODE_PRIMARY:
76082025ec7Smrg        return DRM_DEV_NAME;
76182025ec7Smrg    case DRM_NODE_CONTROL:
76282025ec7Smrg        return DRM_CONTROL_DEV_NAME;
76382025ec7Smrg    case DRM_NODE_RENDER:
76482025ec7Smrg        return DRM_RENDER_DEV_NAME;
76582025ec7Smrg    }
76682025ec7Smrg    return NULL;
76782025ec7Smrg}
76882025ec7Smrg
76922944501Smrg/**
77022944501Smrg * Open the DRM device, creating it if necessary.
77122944501Smrg *
77222944501Smrg * \param dev major and minor numbers of the device.
77322944501Smrg * \param minor minor number of the device.
774fe517fc9Smrg *
77522944501Smrg * \return a file descriptor on success, or a negative value on error.
77622944501Smrg *
77722944501Smrg * \internal
77822944501Smrg * Assembles the device name from \p minor and opens it, creating the device
77922944501Smrg * special file node with the major and minor numbers specified by \p dev and
78022944501Smrg * parent directory if necessary and was called by root.
78122944501Smrg */
782424e9256Smrgstatic int drmOpenDevice(dev_t dev, int minor, int type)
78322944501Smrg{
78422944501Smrg    stat_t          st;
78582025ec7Smrg    const char      *dev_name = drmGetDeviceName(type);
78682025ec7Smrg    char            buf[DRM_NODE_NAME_MAX];
78722944501Smrg    int             fd;
78822944501Smrg    mode_t          devmode = DRM_DEV_MODE, serv_mode;
789424e9256Smrg    gid_t           serv_group;
7906260e5d5Smrg#if !UDEV
79122944501Smrg    int             isroot  = !geteuid();
79222944501Smrg    uid_t           user    = DRM_DEV_UID;
793424e9256Smrg    gid_t           group   = DRM_DEV_GID;
794424e9256Smrg#endif
795424e9256Smrg
79682025ec7Smrg    if (!dev_name)
797fe517fc9Smrg        return -EINVAL;
798424e9256Smrg
799424e9256Smrg    sprintf(buf, dev_name, DRM_DIR_NAME, minor);
80022944501Smrg    drmMsg("drmOpenDevice: node name is %s\n", buf);
80122944501Smrg
802fe517fc9Smrg    if (drm_server_info && drm_server_info->get_perms) {
803fe517fc9Smrg        drm_server_info->get_perms(&serv_group, &serv_mode);
804fe517fc9Smrg        devmode  = serv_mode ? serv_mode : DRM_DEV_MODE;
805fe517fc9Smrg        devmode &= ~(S_IXUSR|S_IXGRP|S_IXOTH);
80622944501Smrg    }
80722944501Smrg
8086260e5d5Smrg#if !UDEV
80922944501Smrg    if (stat(DRM_DIR_NAME, &st)) {
810fe517fc9Smrg        if (!isroot)
811fe517fc9Smrg            return DRM_ERR_NOT_ROOT;
812fe517fc9Smrg        mkdir(DRM_DIR_NAME, DRM_DEV_DIRMODE);
813fe517fc9Smrg        chown_check_return(DRM_DIR_NAME, 0, 0); /* root:root */
814fe517fc9Smrg        chmod(DRM_DIR_NAME, DRM_DEV_DIRMODE);
81522944501Smrg    }
81622944501Smrg
81722944501Smrg    /* Check if the device node exists and create it if necessary. */
81822944501Smrg    if (stat(buf, &st)) {
819fe517fc9Smrg        if (!isroot)
820fe517fc9Smrg            return DRM_ERR_NOT_ROOT;
821fe517fc9Smrg        remove(buf);
822fe517fc9Smrg        mknod(buf, S_IFCHR | devmode, dev);
82322944501Smrg    }
82422944501Smrg
825fe517fc9Smrg    if (drm_server_info && drm_server_info->get_perms) {
826fe517fc9Smrg        group = ((int)serv_group >= 0) ? serv_group : DRM_DEV_GID;
827fe517fc9Smrg        chown_check_return(buf, user, group);
828fe517fc9Smrg        chmod(buf, devmode);
82922944501Smrg    }
83022944501Smrg#else
83122944501Smrg    /* if we modprobed then wait for udev */
83222944501Smrg    {
833fe517fc9Smrg        int udev_count = 0;
83422944501Smrgwait_for_udev:
83522944501Smrg        if (stat(DRM_DIR_NAME, &st)) {
836fe517fc9Smrg            usleep(20);
837fe517fc9Smrg            udev_count++;
838fe517fc9Smrg
839fe517fc9Smrg            if (udev_count == 50)
840fe517fc9Smrg                return -1;
841fe517fc9Smrg            goto wait_for_udev;
842fe517fc9Smrg        }
843fe517fc9Smrg
844fe517fc9Smrg        if (stat(buf, &st)) {
845fe517fc9Smrg            usleep(20);
846fe517fc9Smrg            udev_count++;
847fe517fc9Smrg
848fe517fc9Smrg            if (udev_count == 50)
849fe517fc9Smrg                return -1;
850fe517fc9Smrg            goto wait_for_udev;
851fe517fc9Smrg        }
85222944501Smrg    }
85322944501Smrg#endif
85422944501Smrg
8556260e5d5Smrg    fd = open(buf, O_RDWR | O_CLOEXEC, 0);
85622944501Smrg    drmMsg("drmOpenDevice: open result is %d, (%s)\n",
857fe517fc9Smrg           fd, fd < 0 ? strerror(errno) : "OK");
85822944501Smrg    if (fd >= 0)
859fe517fc9Smrg        return fd;
86022944501Smrg
8616260e5d5Smrg#if !UDEV
86222944501Smrg    /* Check if the device node is not what we expect it to be, and recreate it
86322944501Smrg     * and try again if so.
86422944501Smrg     */
86522944501Smrg    if (st.st_rdev != dev) {
866fe517fc9Smrg        if (!isroot)
867fe517fc9Smrg            return DRM_ERR_NOT_ROOT;
868fe517fc9Smrg        remove(buf);
869fe517fc9Smrg        mknod(buf, S_IFCHR | devmode, dev);
870fe517fc9Smrg        if (drm_server_info && drm_server_info->get_perms) {
871fe517fc9Smrg            chown_check_return(buf, user, group);
872fe517fc9Smrg            chmod(buf, devmode);
873fe517fc9Smrg        }
87422944501Smrg    }
8756260e5d5Smrg    fd = open(buf, O_RDWR | O_CLOEXEC, 0);
87622944501Smrg    drmMsg("drmOpenDevice: open result is %d, (%s)\n",
877fe517fc9Smrg           fd, fd < 0 ? strerror(errno) : "OK");
87822944501Smrg    if (fd >= 0)
879fe517fc9Smrg        return fd;
88022944501Smrg
88122944501Smrg    drmMsg("drmOpenDevice: Open failed\n");
88222944501Smrg    remove(buf);
8839ce4edccSmrg#endif
88422944501Smrg    return -errno;
88522944501Smrg}
88622944501Smrg
88722944501Smrg
88822944501Smrg/**
88922944501Smrg * Open the DRM device
89022944501Smrg *
89122944501Smrg * \param minor device minor number.
89222944501Smrg * \param create allow to create the device if set.
89322944501Smrg *
89422944501Smrg * \return a file descriptor on success, or a negative value on error.
895fe517fc9Smrg *
89622944501Smrg * \internal
89722944501Smrg * Calls drmOpenDevice() if \p create is set, otherwise assembles the device
89822944501Smrg * name from \p minor and opens it.
89922944501Smrg */
90022944501Smrgstatic int drmOpenMinor(int minor, int create, int type)
90122944501Smrg{
90222944501Smrg    int  fd;
90382025ec7Smrg    char buf[DRM_NODE_NAME_MAX];
90482025ec7Smrg    const char *dev_name = drmGetDeviceName(type);
905fe517fc9Smrg
90622944501Smrg    if (create)
907fe517fc9Smrg        return drmOpenDevice(makedev(DRM_MAJOR, minor), minor, type);
908fe517fc9Smrg
90982025ec7Smrg    if (!dev_name)
910fe517fc9Smrg        return -EINVAL;
911424e9256Smrg
912424e9256Smrg    sprintf(buf, dev_name, DRM_DIR_NAME, minor);
9136260e5d5Smrg    if ((fd = open(buf, O_RDWR | O_CLOEXEC, 0)) >= 0)
914fe517fc9Smrg        return fd;
91522944501Smrg    return -errno;
91622944501Smrg}
91722944501Smrg
91822944501Smrg
91922944501Smrg/**
92022944501Smrg * Determine whether the DRM kernel driver has been loaded.
921fe517fc9Smrg *
92222944501Smrg * \return 1 if the DRM driver is loaded, 0 otherwise.
92322944501Smrg *
924fe517fc9Smrg * \internal
92522944501Smrg * Determine the presence of the kernel driver by attempting to open the 0
92622944501Smrg * minor and get version information.  For backward compatibility with older
92722944501Smrg * Linux implementations, /proc/dri is also checked.
92822944501Smrg */
9296260e5d5Smrgdrm_public int drmAvailable(void)
93022944501Smrg{
93122944501Smrg    drmVersionPtr version;
93222944501Smrg    int           retval = 0;
93322944501Smrg    int           fd;
93422944501Smrg
935424e9256Smrg    if ((fd = drmOpenMinor(0, 1, DRM_NODE_PRIMARY)) < 0) {
93622944501Smrg#ifdef __linux__
937fe517fc9Smrg        /* Try proc for backward Linux compatibility */
938fe517fc9Smrg        if (!access("/proc/dri/0", R_OK))
939fe517fc9Smrg            return 1;
94022944501Smrg#endif
941fe517fc9Smrg        return 0;
94222944501Smrg    }
943fe517fc9Smrg
94422944501Smrg    if ((version = drmGetVersion(fd))) {
945fe517fc9Smrg        retval = 1;
946fe517fc9Smrg        drmFreeVersion(version);
94722944501Smrg    }
94822944501Smrg    close(fd);
94922944501Smrg
95022944501Smrg    return retval;
95122944501Smrg}
95222944501Smrg
953424e9256Smrgstatic int drmGetMinorBase(int type)
954424e9256Smrg{
955424e9256Smrg    switch (type) {
956424e9256Smrg    case DRM_NODE_PRIMARY:
957424e9256Smrg        return 0;
958424e9256Smrg    case DRM_NODE_CONTROL:
959424e9256Smrg        return 64;
960424e9256Smrg    case DRM_NODE_RENDER:
961424e9256Smrg        return 128;
962424e9256Smrg    default:
963424e9256Smrg        return -1;
964424e9256Smrg    };
965424e9256Smrg}
966424e9256Smrg
96787bf8e7cSmrgstatic int drmGetMinorType(int major, int minor)
968424e9256Smrg{
96987bf8e7cSmrg#ifdef __FreeBSD__
97087bf8e7cSmrg    char name[SPECNAMELEN];
97187bf8e7cSmrg    int id;
97287bf8e7cSmrg
97387bf8e7cSmrg    if (!devname_r(makedev(major, minor), S_IFCHR, name, sizeof(name)))
97487bf8e7cSmrg        return -1;
97587bf8e7cSmrg
97687bf8e7cSmrg    if (sscanf(name, "drm/%d", &id) != 1) {
97787bf8e7cSmrg        // If not in /dev/drm/ we have the type in the name
97887bf8e7cSmrg        if (sscanf(name, "dri/card%d\n", &id) >= 1)
97987bf8e7cSmrg           return DRM_NODE_PRIMARY;
98087bf8e7cSmrg        else if (sscanf(name, "dri/control%d\n", &id) >= 1)
98187bf8e7cSmrg           return DRM_NODE_CONTROL;
98287bf8e7cSmrg        else if (sscanf(name, "dri/renderD%d\n", &id) >= 1)
98387bf8e7cSmrg           return DRM_NODE_RENDER;
98487bf8e7cSmrg        return -1;
98587bf8e7cSmrg    }
98687bf8e7cSmrg
98787bf8e7cSmrg    minor = id;
98887bf8e7cSmrg#endif
989424e9256Smrg    int type = minor >> 6;
990424e9256Smrg
991424e9256Smrg    if (minor < 0)
992424e9256Smrg        return -1;
993424e9256Smrg
994424e9256Smrg    switch (type) {
995424e9256Smrg    case DRM_NODE_PRIMARY:
996424e9256Smrg    case DRM_NODE_CONTROL:
997424e9256Smrg    case DRM_NODE_RENDER:
998424e9256Smrg        return type;
999424e9256Smrg    default:
1000424e9256Smrg        return -1;
1001424e9256Smrg    }
1002424e9256Smrg}
1003424e9256Smrg
1004424e9256Smrgstatic const char *drmGetMinorName(int type)
1005424e9256Smrg{
1006424e9256Smrg    switch (type) {
1007424e9256Smrg    case DRM_NODE_PRIMARY:
1008fe517fc9Smrg        return DRM_PRIMARY_MINOR_NAME;
1009424e9256Smrg    case DRM_NODE_CONTROL:
1010fe517fc9Smrg        return DRM_CONTROL_MINOR_NAME;
1011424e9256Smrg    case DRM_NODE_RENDER:
1012fe517fc9Smrg        return DRM_RENDER_MINOR_NAME;
1013424e9256Smrg    default:
1014424e9256Smrg        return NULL;
1015424e9256Smrg    }
1016424e9256Smrg}
101722944501Smrg
101822944501Smrg/**
101922944501Smrg * Open the device by bus ID.
102022944501Smrg *
102122944501Smrg * \param busid bus ID.
1022424e9256Smrg * \param type device node type.
102322944501Smrg *
102422944501Smrg * \return a file descriptor on success, or a negative value on error.
102522944501Smrg *
102622944501Smrg * \internal
102722944501Smrg * This function attempts to open every possible minor (up to DRM_MAX_MINOR),
102822944501Smrg * comparing the device bus ID with the one supplied.
102922944501Smrg *
103022944501Smrg * \sa drmOpenMinor() and drmGetBusid().
103122944501Smrg */
1032424e9256Smrgstatic int drmOpenByBusid(const char *busid, int type)
103322944501Smrg{
10346d98c517Smrg    int        i, pci_domain_ok = 1;
103522944501Smrg    int        fd;
103622944501Smrg    const char *buf;
103722944501Smrg    drmSetVersion sv;
1038424e9256Smrg    int        base = drmGetMinorBase(type);
1039424e9256Smrg
1040424e9256Smrg    if (base < 0)
1041424e9256Smrg        return -1;
104222944501Smrg
104322944501Smrg    drmMsg("drmOpenByBusid: Searching for BusID %s\n", busid);
1044424e9256Smrg    for (i = base; i < base + DRM_MAX_MINOR; i++) {
1045fe517fc9Smrg        fd = drmOpenMinor(i, 1, type);
1046fe517fc9Smrg        drmMsg("drmOpenByBusid: drmOpenMinor returns %d\n", fd);
1047fe517fc9Smrg        if (fd >= 0) {
1048fe517fc9Smrg            /* We need to try for 1.4 first for proper PCI domain support
1049fe517fc9Smrg             * and if that fails, we know the kernel is busted
1050fe517fc9Smrg             */
1051fe517fc9Smrg            sv.drm_di_major = 1;
1052fe517fc9Smrg            sv.drm_di_minor = 4;
1053fe517fc9Smrg            sv.drm_dd_major = -1;        /* Don't care */
1054fe517fc9Smrg            sv.drm_dd_minor = -1;        /* Don't care */
1055fe517fc9Smrg            if (drmSetInterfaceVersion(fd, &sv)) {
10566d98c517Smrg#ifndef __alpha__
1057fe517fc9Smrg                pci_domain_ok = 0;
10586d98c517Smrg#endif
1059fe517fc9Smrg                sv.drm_di_major = 1;
1060fe517fc9Smrg                sv.drm_di_minor = 1;
1061fe517fc9Smrg                sv.drm_dd_major = -1;       /* Don't care */
1062fe517fc9Smrg                sv.drm_dd_minor = -1;       /* Don't care */
1063fe517fc9Smrg                drmMsg("drmOpenByBusid: Interface 1.4 failed, trying 1.1\n");
1064fe517fc9Smrg                drmSetInterfaceVersion(fd, &sv);
1065fe517fc9Smrg            }
1066fe517fc9Smrg            buf = drmGetBusid(fd);
1067fe517fc9Smrg            drmMsg("drmOpenByBusid: drmGetBusid reports %s\n", buf);
1068fe517fc9Smrg            if (buf && drmMatchBusID(buf, busid, pci_domain_ok)) {
1069fe517fc9Smrg                drmFreeBusid(buf);
1070fe517fc9Smrg                return fd;
1071fe517fc9Smrg            }
1072fe517fc9Smrg            if (buf)
1073fe517fc9Smrg                drmFreeBusid(buf);
1074fe517fc9Smrg            close(fd);
1075fe517fc9Smrg        }
107622944501Smrg    }
107722944501Smrg    return -1;
107822944501Smrg}
107922944501Smrg
108022944501Smrg
108122944501Smrg/**
108222944501Smrg * Open the device by name.
108322944501Smrg *
108422944501Smrg * \param name driver name.
1085424e9256Smrg * \param type the device node type.
1086fe517fc9Smrg *
108722944501Smrg * \return a file descriptor on success, or a negative value on error.
1088fe517fc9Smrg *
108922944501Smrg * \internal
109022944501Smrg * This function opens the first minor number that matches the driver name and
109122944501Smrg * isn't already in use.  If it's in use it then it will already have a bus ID
109222944501Smrg * assigned.
1093fe517fc9Smrg *
109422944501Smrg * \sa drmOpenMinor(), drmGetVersion() and drmGetBusid().
109522944501Smrg */
1096424e9256Smrgstatic int drmOpenByName(const char *name, int type)
109722944501Smrg{
109822944501Smrg    int           i;
109922944501Smrg    int           fd;
110022944501Smrg    drmVersionPtr version;
110122944501Smrg    char *        id;
1102424e9256Smrg    int           base = drmGetMinorBase(type);
1103424e9256Smrg
1104424e9256Smrg    if (base < 0)
1105424e9256Smrg        return -1;
110622944501Smrg
110722944501Smrg    /*
110822944501Smrg     * Open the first minor number that matches the driver name and isn't
110922944501Smrg     * already in use.  If it's in use it will have a busid assigned already.
111022944501Smrg     */
1111424e9256Smrg    for (i = base; i < base + DRM_MAX_MINOR; i++) {
1112fe517fc9Smrg        if ((fd = drmOpenMinor(i, 1, type)) >= 0) {
1113fe517fc9Smrg            if ((version = drmGetVersion(fd))) {
1114fe517fc9Smrg                if (!strcmp(version->name, name)) {
1115fe517fc9Smrg                    drmFreeVersion(version);
1116fe517fc9Smrg                    id = drmGetBusid(fd);
1117fe517fc9Smrg                    drmMsg("drmGetBusid returned '%s'\n", id ? id : "NULL");
1118fe517fc9Smrg                    if (!id || !*id) {
1119fe517fc9Smrg                        if (id)
1120fe517fc9Smrg                            drmFreeBusid(id);
1121fe517fc9Smrg                        return fd;
1122fe517fc9Smrg                    } else {
1123fe517fc9Smrg                        drmFreeBusid(id);
1124fe517fc9Smrg                    }
1125fe517fc9Smrg                } else {
1126fe517fc9Smrg                    drmFreeVersion(version);
1127fe517fc9Smrg                }
1128fe517fc9Smrg            }
1129fe517fc9Smrg            close(fd);
1130fe517fc9Smrg        }
113122944501Smrg    }
113222944501Smrg
113322944501Smrg#ifdef __linux__
113422944501Smrg    /* Backward-compatibility /proc support */
113522944501Smrg    for (i = 0; i < 8; i++) {
1136fe517fc9Smrg        char proc_name[64], buf[512];
1137fe517fc9Smrg        char *driver, *pt, *devstring;
1138fe517fc9Smrg        int  retcode;
1139fe517fc9Smrg
1140fe517fc9Smrg        sprintf(proc_name, "/proc/dri/%d/name", i);
11414b3d3f37Smrg        if ((fd = open(proc_name, O_RDONLY, 0)) >= 0) {
1142fe517fc9Smrg            retcode = read(fd, buf, sizeof(buf)-1);
1143fe517fc9Smrg            close(fd);
1144fe517fc9Smrg            if (retcode) {
1145fe517fc9Smrg                buf[retcode-1] = '\0';
1146fe517fc9Smrg                for (driver = pt = buf; *pt && *pt != ' '; ++pt)
1147fe517fc9Smrg                    ;
1148fe517fc9Smrg                if (*pt) { /* Device is next */
1149fe517fc9Smrg                    *pt = '\0';
1150fe517fc9Smrg                    if (!strcmp(driver, name)) { /* Match */
1151fe517fc9Smrg                        for (devstring = ++pt; *pt && *pt != ' '; ++pt)
1152fe517fc9Smrg                            ;
1153fe517fc9Smrg                        if (*pt) { /* Found busid */
1154fe517fc9Smrg                            return drmOpenByBusid(++pt, type);
1155fe517fc9Smrg                        } else { /* No busid */
1156fe517fc9Smrg                            return drmOpenDevice(strtol(devstring, NULL, 0),i, type);
1157fe517fc9Smrg                        }
1158fe517fc9Smrg                    }
1159fe517fc9Smrg                }
1160fe517fc9Smrg            }
1161fe517fc9Smrg        }
116222944501Smrg    }
116322944501Smrg#endif
116422944501Smrg
116522944501Smrg    return -1;
116622944501Smrg}
116722944501Smrg
116822944501Smrg
116922944501Smrg/**
117022944501Smrg * Open the DRM device.
117122944501Smrg *
117222944501Smrg * Looks up the specified name and bus ID, and opens the device found.  The
117322944501Smrg * entry in /dev/dri is created if necessary and if called by root.
117422944501Smrg *
117522944501Smrg * \param name driver name. Not referenced if bus ID is supplied.
117622944501Smrg * \param busid bus ID. Zero if not known.
1177fe517fc9Smrg *
117822944501Smrg * \return a file descriptor on success, or a negative value on error.
1179fe517fc9Smrg *
118022944501Smrg * \internal
118122944501Smrg * It calls drmOpenByBusid() if \p busid is specified or drmOpenByName()
118222944501Smrg * otherwise.
118322944501Smrg */
11846260e5d5Smrgdrm_public int drmOpen(const char *name, const char *busid)
1185424e9256Smrg{
1186424e9256Smrg    return drmOpenWithType(name, busid, DRM_NODE_PRIMARY);
1187424e9256Smrg}
1188424e9256Smrg
1189424e9256Smrg/**
1190424e9256Smrg * Open the DRM device with specified type.
1191424e9256Smrg *
1192424e9256Smrg * Looks up the specified name and bus ID, and opens the device found.  The
1193424e9256Smrg * entry in /dev/dri is created if necessary and if called by root.
1194424e9256Smrg *
1195424e9256Smrg * \param name driver name. Not referenced if bus ID is supplied.
1196424e9256Smrg * \param busid bus ID. Zero if not known.
1197424e9256Smrg * \param type the device node type to open, PRIMARY, CONTROL or RENDER
1198424e9256Smrg *
1199424e9256Smrg * \return a file descriptor on success, or a negative value on error.
1200424e9256Smrg *
1201424e9256Smrg * \internal
1202424e9256Smrg * It calls drmOpenByBusid() if \p busid is specified or drmOpenByName()
1203424e9256Smrg * otherwise.
1204424e9256Smrg */
12056260e5d5Smrgdrm_public int drmOpenWithType(const char *name, const char *busid, int type)
120622944501Smrg{
1207bf6cc7dcSmrg    if (name != NULL && drm_server_info &&
1208bf6cc7dcSmrg        drm_server_info->load_module && !drmAvailable()) {
1209fe517fc9Smrg        /* try to load the kernel module */
1210fe517fc9Smrg        if (!drm_server_info->load_module(name)) {
1211fe517fc9Smrg            drmMsg("[drm] failed to load kernel module \"%s\"\n", name);
1212fe517fc9Smrg            return -1;
1213fe517fc9Smrg        }
121422944501Smrg    }
121522944501Smrg
121622944501Smrg    if (busid) {
1217fe517fc9Smrg        int fd = drmOpenByBusid(busid, type);
1218fe517fc9Smrg        if (fd >= 0)
1219fe517fc9Smrg            return fd;
122022944501Smrg    }
1221fe517fc9Smrg
122222944501Smrg    if (name)
1223fe517fc9Smrg        return drmOpenByName(name, type);
122422944501Smrg
122522944501Smrg    return -1;
122622944501Smrg}
122722944501Smrg
12286260e5d5Smrgdrm_public int drmOpenControl(int minor)
122922944501Smrg{
123022944501Smrg    return drmOpenMinor(minor, 0, DRM_NODE_CONTROL);
123122944501Smrg}
123222944501Smrg
12336260e5d5Smrgdrm_public int drmOpenRender(int minor)
1234424e9256Smrg{
1235424e9256Smrg    return drmOpenMinor(minor, 0, DRM_NODE_RENDER);
1236424e9256Smrg}
1237424e9256Smrg
123822944501Smrg/**
123922944501Smrg * Free the version information returned by drmGetVersion().
124022944501Smrg *
124122944501Smrg * \param v pointer to the version information.
124222944501Smrg *
124322944501Smrg * \internal
124422944501Smrg * It frees the memory pointed by \p %v as well as all the non-null strings
124522944501Smrg * pointers in it.
124622944501Smrg */
12476260e5d5Smrgdrm_public void drmFreeVersion(drmVersionPtr v)
124822944501Smrg{
124922944501Smrg    if (!v)
1250fe517fc9Smrg        return;
125122944501Smrg    drmFree(v->name);
125222944501Smrg    drmFree(v->date);
125322944501Smrg    drmFree(v->desc);
125422944501Smrg    drmFree(v);
125522944501Smrg}
125622944501Smrg
125722944501Smrg
125822944501Smrg/**
125922944501Smrg * Free the non-public version information returned by the kernel.
126022944501Smrg *
126122944501Smrg * \param v pointer to the version information.
126222944501Smrg *
126322944501Smrg * \internal
126422944501Smrg * Used by drmGetVersion() to free the memory pointed by \p %v as well as all
126522944501Smrg * the non-null strings pointers in it.
126622944501Smrg */
126722944501Smrgstatic void drmFreeKernelVersion(drm_version_t *v)
126822944501Smrg{
126922944501Smrg    if (!v)
1270fe517fc9Smrg        return;
127122944501Smrg    drmFree(v->name);
127222944501Smrg    drmFree(v->date);
127322944501Smrg    drmFree(v->desc);
127422944501Smrg    drmFree(v);
127522944501Smrg}
127622944501Smrg
127722944501Smrg
127822944501Smrg/**
127922944501Smrg * Copy version information.
1280fe517fc9Smrg *
128122944501Smrg * \param d destination pointer.
128222944501Smrg * \param s source pointer.
1283fe517fc9Smrg *
128422944501Smrg * \internal
128522944501Smrg * Used by drmGetVersion() to translate the information returned by the ioctl
128622944501Smrg * interface in a private structure into the public structure counterpart.
128722944501Smrg */
128822944501Smrgstatic void drmCopyVersion(drmVersionPtr d, const drm_version_t *s)
128922944501Smrg{
129022944501Smrg    d->version_major      = s->version_major;
129122944501Smrg    d->version_minor      = s->version_minor;
129222944501Smrg    d->version_patchlevel = s->version_patchlevel;
129322944501Smrg    d->name_len           = s->name_len;
12949ce4edccSmrg    d->name               = strdup(s->name);
129522944501Smrg    d->date_len           = s->date_len;
12969ce4edccSmrg    d->date               = strdup(s->date);
129722944501Smrg    d->desc_len           = s->desc_len;
12989ce4edccSmrg    d->desc               = strdup(s->desc);
129922944501Smrg}
130022944501Smrg
130122944501Smrg
130222944501Smrg/**
130322944501Smrg * Query the driver version information.
130422944501Smrg *
130522944501Smrg * \param fd file descriptor.
1306fe517fc9Smrg *
130722944501Smrg * \return pointer to a drmVersion structure which should be freed with
130822944501Smrg * drmFreeVersion().
1309fe517fc9Smrg *
131022944501Smrg * \note Similar information is available via /proc/dri.
1311fe517fc9Smrg *
131222944501Smrg * \internal
131322944501Smrg * It gets the version information via successive DRM_IOCTL_VERSION ioctls,
131422944501Smrg * first with zeros to get the string lengths, and then the actually strings.
131522944501Smrg * It also null-terminates them since they might not be already.
131622944501Smrg */
13176260e5d5Smrgdrm_public drmVersionPtr drmGetVersion(int fd)
131822944501Smrg{
131922944501Smrg    drmVersionPtr retval;
132022944501Smrg    drm_version_t *version = drmMalloc(sizeof(*version));
132122944501Smrg
132222944501Smrg    if (drmIoctl(fd, DRM_IOCTL_VERSION, version)) {
1323fe517fc9Smrg        drmFreeKernelVersion(version);
1324fe517fc9Smrg        return NULL;
132522944501Smrg    }
132622944501Smrg
132722944501Smrg    if (version->name_len)
1328fe517fc9Smrg        version->name    = drmMalloc(version->name_len + 1);
132922944501Smrg    if (version->date_len)
1330fe517fc9Smrg        version->date    = drmMalloc(version->date_len + 1);
133122944501Smrg    if (version->desc_len)
1332fe517fc9Smrg        version->desc    = drmMalloc(version->desc_len + 1);
133322944501Smrg
133422944501Smrg    if (drmIoctl(fd, DRM_IOCTL_VERSION, version)) {
1335fe517fc9Smrg        drmMsg("DRM_IOCTL_VERSION: %s\n", strerror(errno));
1336fe517fc9Smrg        drmFreeKernelVersion(version);
1337fe517fc9Smrg        return NULL;
133822944501Smrg    }
133922944501Smrg
134022944501Smrg    /* The results might not be null-terminated strings, so terminate them. */
134122944501Smrg    if (version->name_len) version->name[version->name_len] = '\0';
134222944501Smrg    if (version->date_len) version->date[version->date_len] = '\0';
134322944501Smrg    if (version->desc_len) version->desc[version->desc_len] = '\0';
134422944501Smrg
134522944501Smrg    retval = drmMalloc(sizeof(*retval));
134622944501Smrg    drmCopyVersion(retval, version);
134722944501Smrg    drmFreeKernelVersion(version);
134822944501Smrg    return retval;
134922944501Smrg}
135022944501Smrg
135122944501Smrg
135222944501Smrg/**
135322944501Smrg * Get version information for the DRM user space library.
1354fe517fc9Smrg *
135522944501Smrg * This version number is driver independent.
1356fe517fc9Smrg *
135722944501Smrg * \param fd file descriptor.
135822944501Smrg *
135922944501Smrg * \return version information.
1360fe517fc9Smrg *
136122944501Smrg * \internal
136222944501Smrg * This function allocates and fills a drm_version structure with a hard coded
136322944501Smrg * version number.
136422944501Smrg */
13656260e5d5Smrgdrm_public drmVersionPtr drmGetLibVersion(int fd)
136622944501Smrg{
136722944501Smrg    drm_version_t *version = drmMalloc(sizeof(*version));
136822944501Smrg
136922944501Smrg    /* Version history:
137022944501Smrg     *   NOTE THIS MUST NOT GO ABOVE VERSION 1.X due to drivers needing it
137122944501Smrg     *   revision 1.0.x = original DRM interface with no drmGetLibVersion
137222944501Smrg     *                    entry point and many drm<Device> extensions
137322944501Smrg     *   revision 1.1.x = added drmCommand entry points for device extensions
137422944501Smrg     *                    added drmGetLibVersion to identify libdrm.a version
137522944501Smrg     *   revision 1.2.x = added drmSetInterfaceVersion
137622944501Smrg     *                    modified drmOpen to handle both busid and name
137722944501Smrg     *   revision 1.3.x = added server + memory manager
137822944501Smrg     */
137922944501Smrg    version->version_major      = 1;
138022944501Smrg    version->version_minor      = 3;
138122944501Smrg    version->version_patchlevel = 0;
138222944501Smrg
138322944501Smrg    return (drmVersionPtr)version;
138422944501Smrg}
138522944501Smrg
13866260e5d5Smrgdrm_public int drmGetCap(int fd, uint64_t capability, uint64_t *value)
138720131375Smrg{
1388fe517fc9Smrg    struct drm_get_cap cap;
1389fe517fc9Smrg    int ret;
139020131375Smrg
1391fe517fc9Smrg    memclear(cap);
1392fe517fc9Smrg    cap.capability = capability;
1393424e9256Smrg
1394fe517fc9Smrg    ret = drmIoctl(fd, DRM_IOCTL_GET_CAP, &cap);
1395fe517fc9Smrg    if (ret)
1396fe517fc9Smrg        return ret;
139720131375Smrg
1398fe517fc9Smrg    *value = cap.value;
1399fe517fc9Smrg    return 0;
140020131375Smrg}
140120131375Smrg
14026260e5d5Smrgdrm_public int drmSetClientCap(int fd, uint64_t capability, uint64_t value)
140320131375Smrg{
1404fe517fc9Smrg    struct drm_set_client_cap cap;
1405424e9256Smrg
1406fe517fc9Smrg    memclear(cap);
1407fe517fc9Smrg    cap.capability = capability;
1408fe517fc9Smrg    cap.value = value;
140920131375Smrg
1410fe517fc9Smrg    return drmIoctl(fd, DRM_IOCTL_SET_CLIENT_CAP, &cap);
141120131375Smrg}
141222944501Smrg
141322944501Smrg/**
141422944501Smrg * Free the bus ID information.
141522944501Smrg *
141622944501Smrg * \param busid bus ID information string as given by drmGetBusid().
141722944501Smrg *
141822944501Smrg * \internal
141922944501Smrg * This function is just frees the memory pointed by \p busid.
142022944501Smrg */
14216260e5d5Smrgdrm_public void drmFreeBusid(const char *busid)
142222944501Smrg{
142322944501Smrg    drmFree((void *)busid);
142422944501Smrg}
142522944501Smrg
142622944501Smrg
142722944501Smrg/**
142822944501Smrg * Get the bus ID of the device.
142922944501Smrg *
143022944501Smrg * \param fd file descriptor.
143122944501Smrg *
143222944501Smrg * \return bus ID string.
143322944501Smrg *
143422944501Smrg * \internal
143522944501Smrg * This function gets the bus ID via successive DRM_IOCTL_GET_UNIQUE ioctls to
143622944501Smrg * get the string length and data, passing the arguments in a drm_unique
143722944501Smrg * structure.
143822944501Smrg */
14396260e5d5Smrgdrm_public char *drmGetBusid(int fd)
144022944501Smrg{
144122944501Smrg    drm_unique_t u;
144222944501Smrg
1443424e9256Smrg    memclear(u);
144422944501Smrg
144522944501Smrg    if (drmIoctl(fd, DRM_IOCTL_GET_UNIQUE, &u))
1446fe517fc9Smrg        return NULL;
144722944501Smrg    u.unique = drmMalloc(u.unique_len + 1);
14480655efefSmrg    if (drmIoctl(fd, DRM_IOCTL_GET_UNIQUE, &u)) {
14490655efefSmrg        drmFree(u.unique);
1450fe517fc9Smrg        return NULL;
14510655efefSmrg    }
145222944501Smrg    u.unique[u.unique_len] = '\0';
145322944501Smrg
145422944501Smrg    return u.unique;
145522944501Smrg}
145622944501Smrg
145722944501Smrg
145822944501Smrg/**
145922944501Smrg * Set the bus ID of the device.
146022944501Smrg *
146122944501Smrg * \param fd file descriptor.
146222944501Smrg * \param busid bus ID string.
146322944501Smrg *
146422944501Smrg * \return zero on success, negative on failure.
146522944501Smrg *
146622944501Smrg * \internal
146722944501Smrg * This function is a wrapper around the DRM_IOCTL_SET_UNIQUE ioctl, passing
146822944501Smrg * the arguments in a drm_unique structure.
146922944501Smrg */
14706260e5d5Smrgdrm_public int drmSetBusid(int fd, const char *busid)
147122944501Smrg{
147222944501Smrg    drm_unique_t u;
147322944501Smrg
1474424e9256Smrg    memclear(u);
147522944501Smrg    u.unique     = (char *)busid;
147622944501Smrg    u.unique_len = strlen(busid);
147722944501Smrg
147822944501Smrg    if (drmIoctl(fd, DRM_IOCTL_SET_UNIQUE, &u)) {
1479fe517fc9Smrg        return -errno;
148022944501Smrg    }
148122944501Smrg    return 0;
148222944501Smrg}
148322944501Smrg
14846260e5d5Smrgdrm_public int drmGetMagic(int fd, drm_magic_t * magic)
148522944501Smrg{
148622944501Smrg    drm_auth_t auth;
148722944501Smrg
1488424e9256Smrg    memclear(auth);
1489424e9256Smrg
149022944501Smrg    *magic = 0;
149122944501Smrg    if (drmIoctl(fd, DRM_IOCTL_GET_MAGIC, &auth))
1492fe517fc9Smrg        return -errno;
149322944501Smrg    *magic = auth.magic;
149422944501Smrg    return 0;
149522944501Smrg}
149622944501Smrg
14976260e5d5Smrgdrm_public int drmAuthMagic(int fd, drm_magic_t magic)
149822944501Smrg{
149922944501Smrg    drm_auth_t auth;
150022944501Smrg
1501424e9256Smrg    memclear(auth);
150222944501Smrg    auth.magic = magic;
150322944501Smrg    if (drmIoctl(fd, DRM_IOCTL_AUTH_MAGIC, &auth))
1504fe517fc9Smrg        return -errno;
150522944501Smrg    return 0;
150622944501Smrg}
150722944501Smrg
150822944501Smrg/**
150922944501Smrg * Specifies a range of memory that is available for mapping by a
151022944501Smrg * non-root process.
151122944501Smrg *
151222944501Smrg * \param fd file descriptor.
151322944501Smrg * \param offset usually the physical address. The actual meaning depends of
151422944501Smrg * the \p type parameter. See below.
151522944501Smrg * \param size of the memory in bytes.
151622944501Smrg * \param type type of the memory to be mapped.
151722944501Smrg * \param flags combination of several flags to modify the function actions.
151822944501Smrg * \param handle will be set to a value that may be used as the offset
151922944501Smrg * parameter for mmap().
1520fe517fc9Smrg *
152122944501Smrg * \return zero on success or a negative value on error.
152222944501Smrg *
152322944501Smrg * \par Mapping the frame buffer
152422944501Smrg * For the frame buffer
152522944501Smrg * - \p offset will be the physical address of the start of the frame buffer,
152622944501Smrg * - \p size will be the size of the frame buffer in bytes, and
152722944501Smrg * - \p type will be DRM_FRAME_BUFFER.
152822944501Smrg *
152922944501Smrg * \par
153022944501Smrg * The area mapped will be uncached. If MTRR support is available in the
1531fe517fc9Smrg * kernel, the frame buffer area will be set to write combining.
153222944501Smrg *
153322944501Smrg * \par Mapping the MMIO register area
153422944501Smrg * For the MMIO register area,
153522944501Smrg * - \p offset will be the physical address of the start of the register area,
153622944501Smrg * - \p size will be the size of the register area bytes, and
153722944501Smrg * - \p type will be DRM_REGISTERS.
153822944501Smrg * \par
1539fe517fc9Smrg * The area mapped will be uncached.
1540fe517fc9Smrg *
154122944501Smrg * \par Mapping the SAREA
154222944501Smrg * For the SAREA,
154322944501Smrg * - \p offset will be ignored and should be set to zero,
154422944501Smrg * - \p size will be the desired size of the SAREA in bytes,
154522944501Smrg * - \p type will be DRM_SHM.
1546fe517fc9Smrg *
154722944501Smrg * \par
154822944501Smrg * A shared memory area of the requested size will be created and locked in
154922944501Smrg * kernel memory. This area may be mapped into client-space by using the handle
1550fe517fc9Smrg * returned.
1551fe517fc9Smrg *
155222944501Smrg * \note May only be called by root.
155322944501Smrg *
155422944501Smrg * \internal
155522944501Smrg * This function is a wrapper around the DRM_IOCTL_ADD_MAP ioctl, passing
155622944501Smrg * the arguments in a drm_map structure.
155722944501Smrg */
15586260e5d5Smrgdrm_public int drmAddMap(int fd, drm_handle_t offset, drmSize size, drmMapType type,
15596260e5d5Smrg                         drmMapFlags flags, drm_handle_t *handle)
156022944501Smrg{
156122944501Smrg    drm_map_t map;
156222944501Smrg
1563424e9256Smrg    memclear(map);
156422944501Smrg    map.offset  = offset;
156522944501Smrg    map.size    = size;
1566adfa0b0cSmrg    map.type    = (enum drm_map_type)type;
1567adfa0b0cSmrg    map.flags   = (enum drm_map_flags)flags;
156822944501Smrg    if (drmIoctl(fd, DRM_IOCTL_ADD_MAP, &map))
1569fe517fc9Smrg        return -errno;
157022944501Smrg    if (handle)
1571fe517fc9Smrg        *handle = (drm_handle_t)(uintptr_t)map.handle;
157222944501Smrg    return 0;
157322944501Smrg}
157422944501Smrg
15756260e5d5Smrgdrm_public int drmRmMap(int fd, drm_handle_t handle)
157622944501Smrg{
157722944501Smrg    drm_map_t map;
157822944501Smrg
1579424e9256Smrg    memclear(map);
158020131375Smrg    map.handle = (void *)(uintptr_t)handle;
158122944501Smrg
158222944501Smrg    if(drmIoctl(fd, DRM_IOCTL_RM_MAP, &map))
1583fe517fc9Smrg        return -errno;
158422944501Smrg    return 0;
158522944501Smrg}
158622944501Smrg
158722944501Smrg/**
158822944501Smrg * Make buffers available for DMA transfers.
1589fe517fc9Smrg *
159022944501Smrg * \param fd file descriptor.
159122944501Smrg * \param count number of buffers.
159222944501Smrg * \param size size of each buffer.
159322944501Smrg * \param flags buffer allocation flags.
1594fe517fc9Smrg * \param agp_offset offset in the AGP aperture
159522944501Smrg *
159622944501Smrg * \return number of buffers allocated, negative on error.
159722944501Smrg *
159822944501Smrg * \internal
159922944501Smrg * This function is a wrapper around DRM_IOCTL_ADD_BUFS ioctl.
160022944501Smrg *
160122944501Smrg * \sa drm_buf_desc.
160222944501Smrg */
16036260e5d5Smrgdrm_public int drmAddBufs(int fd, int count, int size, drmBufDescFlags flags,
16046260e5d5Smrg                          int agp_offset)
160522944501Smrg{
160622944501Smrg    drm_buf_desc_t request;
160722944501Smrg
1608424e9256Smrg    memclear(request);
160922944501Smrg    request.count     = count;
161022944501Smrg    request.size      = size;
1611adfa0b0cSmrg    request.flags     = (int)flags;
161222944501Smrg    request.agp_start = agp_offset;
161322944501Smrg
161422944501Smrg    if (drmIoctl(fd, DRM_IOCTL_ADD_BUFS, &request))
1615fe517fc9Smrg        return -errno;
161622944501Smrg    return request.count;
161722944501Smrg}
161822944501Smrg
16196260e5d5Smrgdrm_public int drmMarkBufs(int fd, double low, double high)
162022944501Smrg{
162122944501Smrg    drm_buf_info_t info;
162222944501Smrg    int            i;
162322944501Smrg
1624424e9256Smrg    memclear(info);
162522944501Smrg
162622944501Smrg    if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info))
1627fe517fc9Smrg        return -EINVAL;
162822944501Smrg
162922944501Smrg    if (!info.count)
1630fe517fc9Smrg        return -EINVAL;
163122944501Smrg
163222944501Smrg    if (!(info.list = drmMalloc(info.count * sizeof(*info.list))))
1633fe517fc9Smrg        return -ENOMEM;
163422944501Smrg
163522944501Smrg    if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info)) {
1636fe517fc9Smrg        int retval = -errno;
1637fe517fc9Smrg        drmFree(info.list);
1638fe517fc9Smrg        return retval;
163922944501Smrg    }
164022944501Smrg
164122944501Smrg    for (i = 0; i < info.count; i++) {
1642fe517fc9Smrg        info.list[i].low_mark  = low  * info.list[i].count;
1643fe517fc9Smrg        info.list[i].high_mark = high * info.list[i].count;
1644fe517fc9Smrg        if (drmIoctl(fd, DRM_IOCTL_MARK_BUFS, &info.list[i])) {
1645fe517fc9Smrg            int retval = -errno;
1646fe517fc9Smrg            drmFree(info.list);
1647fe517fc9Smrg            return retval;
1648fe517fc9Smrg        }
164922944501Smrg    }
165022944501Smrg    drmFree(info.list);
165122944501Smrg
165222944501Smrg    return 0;
165322944501Smrg}
165422944501Smrg
165522944501Smrg/**
165622944501Smrg * Free buffers.
165722944501Smrg *
165822944501Smrg * \param fd file descriptor.
165922944501Smrg * \param count number of buffers to free.
166022944501Smrg * \param list list of buffers to be freed.
166122944501Smrg *
166222944501Smrg * \return zero on success, or a negative value on failure.
1663fe517fc9Smrg *
166422944501Smrg * \note This function is primarily used for debugging.
1665fe517fc9Smrg *
166622944501Smrg * \internal
166722944501Smrg * This function is a wrapper around the DRM_IOCTL_FREE_BUFS ioctl, passing
166822944501Smrg * the arguments in a drm_buf_free structure.
166922944501Smrg */
16706260e5d5Smrgdrm_public int drmFreeBufs(int fd, int count, int *list)
167122944501Smrg{
167222944501Smrg    drm_buf_free_t request;
167322944501Smrg
1674424e9256Smrg    memclear(request);
167522944501Smrg    request.count = count;
167622944501Smrg    request.list  = list;
167722944501Smrg    if (drmIoctl(fd, DRM_IOCTL_FREE_BUFS, &request))
1678fe517fc9Smrg        return -errno;
167922944501Smrg    return 0;
168022944501Smrg}
168122944501Smrg
168222944501Smrg
168322944501Smrg/**
168422944501Smrg * Close the device.
168522944501Smrg *
168622944501Smrg * \param fd file descriptor.
168722944501Smrg *
168822944501Smrg * \internal
168922944501Smrg * This function closes the file descriptor.
169022944501Smrg */
16916260e5d5Smrgdrm_public int drmClose(int fd)
169222944501Smrg{
169322944501Smrg    unsigned long key    = drmGetKeyFromFd(fd);
169422944501Smrg    drmHashEntry  *entry = drmGetEntry(fd);
169522944501Smrg
169622944501Smrg    drmHashDestroy(entry->tagTable);
169722944501Smrg    entry->fd       = 0;
169822944501Smrg    entry->f        = NULL;
169922944501Smrg    entry->tagTable = NULL;
170022944501Smrg
170122944501Smrg    drmHashDelete(drmHashTable, key);
170222944501Smrg    drmFree(entry);
170322944501Smrg
170422944501Smrg    return close(fd);
170522944501Smrg}
170622944501Smrg
170722944501Smrg
170822944501Smrg/**
170922944501Smrg * Map a region of memory.
171022944501Smrg *
171122944501Smrg * \param fd file descriptor.
171222944501Smrg * \param handle handle returned by drmAddMap().
171322944501Smrg * \param size size in bytes. Must match the size used by drmAddMap().
171422944501Smrg * \param address will contain the user-space virtual address where the mapping
171522944501Smrg * begins.
171622944501Smrg *
171722944501Smrg * \return zero on success, or a negative value on failure.
1718fe517fc9Smrg *
171922944501Smrg * \internal
172022944501Smrg * This function is a wrapper for mmap().
172122944501Smrg */
17226260e5d5Smrgdrm_public int drmMap(int fd, drm_handle_t handle, drmSize size,
17236260e5d5Smrg                      drmAddressPtr address)
172422944501Smrg{
172522944501Smrg    static unsigned long pagesize_mask = 0;
172622944501Smrg
172722944501Smrg    if (fd < 0)
1728fe517fc9Smrg        return -EINVAL;
172922944501Smrg
173022944501Smrg    if (!pagesize_mask)
1731fe517fc9Smrg        pagesize_mask = getpagesize() - 1;
173222944501Smrg
173322944501Smrg    size = (size + pagesize_mask) & ~pagesize_mask;
173422944501Smrg
1735a884aba1Smrg    *address = drm_mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, handle);
173622944501Smrg    if (*address == MAP_FAILED)
1737fe517fc9Smrg        return -errno;
173822944501Smrg    return 0;
173922944501Smrg}
174022944501Smrg
174122944501Smrg
174222944501Smrg/**
174322944501Smrg * Unmap mappings obtained with drmMap().
174422944501Smrg *
174522944501Smrg * \param address address as given by drmMap().
174622944501Smrg * \param size size in bytes. Must match the size used by drmMap().
1747fe517fc9Smrg *
174822944501Smrg * \return zero on success, or a negative value on failure.
174922944501Smrg *
175022944501Smrg * \internal
175122944501Smrg * This function is a wrapper for munmap().
175222944501Smrg */
17536260e5d5Smrgdrm_public int drmUnmap(drmAddress address, drmSize size)
175422944501Smrg{
1755a884aba1Smrg    return drm_munmap(address, size);
175622944501Smrg}
175722944501Smrg
17586260e5d5Smrgdrm_public drmBufInfoPtr drmGetBufInfo(int fd)
175922944501Smrg{
176022944501Smrg    drm_buf_info_t info;
176122944501Smrg    drmBufInfoPtr  retval;
176222944501Smrg    int            i;
176322944501Smrg
1764424e9256Smrg    memclear(info);
176522944501Smrg
176622944501Smrg    if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info))
1767fe517fc9Smrg        return NULL;
176822944501Smrg
176922944501Smrg    if (info.count) {
1770fe517fc9Smrg        if (!(info.list = drmMalloc(info.count * sizeof(*info.list))))
1771fe517fc9Smrg            return NULL;
1772fe517fc9Smrg
1773fe517fc9Smrg        if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info)) {
1774fe517fc9Smrg            drmFree(info.list);
1775fe517fc9Smrg            return NULL;
1776fe517fc9Smrg        }
1777fe517fc9Smrg
1778fe517fc9Smrg        retval = drmMalloc(sizeof(*retval));
1779fe517fc9Smrg        retval->count = info.count;
17804b3d3f37Smrg        if (!(retval->list = drmMalloc(info.count * sizeof(*retval->list)))) {
17814b3d3f37Smrg                drmFree(retval);
17824b3d3f37Smrg                drmFree(info.list);
17834b3d3f37Smrg                return NULL;
17844b3d3f37Smrg        }
17854b3d3f37Smrg
1786fe517fc9Smrg        for (i = 0; i < info.count; i++) {
1787fe517fc9Smrg            retval->list[i].count     = info.list[i].count;
1788fe517fc9Smrg            retval->list[i].size      = info.list[i].size;
1789fe517fc9Smrg            retval->list[i].low_mark  = info.list[i].low_mark;
1790fe517fc9Smrg            retval->list[i].high_mark = info.list[i].high_mark;
1791fe517fc9Smrg        }
1792fe517fc9Smrg        drmFree(info.list);
1793fe517fc9Smrg        return retval;
179422944501Smrg    }
179522944501Smrg    return NULL;
179622944501Smrg}
179722944501Smrg
179822944501Smrg/**
179922944501Smrg * Map all DMA buffers into client-virtual space.
180022944501Smrg *
180122944501Smrg * \param fd file descriptor.
180222944501Smrg *
180322944501Smrg * \return a pointer to a ::drmBufMap structure.
180422944501Smrg *
180522944501Smrg * \note The client may not use these buffers until obtaining buffer indices
180622944501Smrg * with drmDMA().
1807fe517fc9Smrg *
180822944501Smrg * \internal
180922944501Smrg * This function calls the DRM_IOCTL_MAP_BUFS ioctl and copies the returned
181022944501Smrg * information about the buffers in a drm_buf_map structure into the
181122944501Smrg * client-visible data structures.
1812fe517fc9Smrg */
18136260e5d5Smrgdrm_public drmBufMapPtr drmMapBufs(int fd)
181422944501Smrg{
181522944501Smrg    drm_buf_map_t bufs;
181622944501Smrg    drmBufMapPtr  retval;
181722944501Smrg    int           i;
181822944501Smrg
1819424e9256Smrg    memclear(bufs);
182022944501Smrg    if (drmIoctl(fd, DRM_IOCTL_MAP_BUFS, &bufs))
1821fe517fc9Smrg        return NULL;
182222944501Smrg
182322944501Smrg    if (!bufs.count)
1824fe517fc9Smrg        return NULL;
182522944501Smrg
1826fe517fc9Smrg    if (!(bufs.list = drmMalloc(bufs.count * sizeof(*bufs.list))))
1827fe517fc9Smrg        return NULL;
182822944501Smrg
1829fe517fc9Smrg    if (drmIoctl(fd, DRM_IOCTL_MAP_BUFS, &bufs)) {
1830fe517fc9Smrg        drmFree(bufs.list);
1831fe517fc9Smrg        return NULL;
1832fe517fc9Smrg    }
183322944501Smrg
1834fe517fc9Smrg    retval = drmMalloc(sizeof(*retval));
1835fe517fc9Smrg    retval->count = bufs.count;
1836fe517fc9Smrg    retval->list  = drmMalloc(bufs.count * sizeof(*retval->list));
1837fe517fc9Smrg    for (i = 0; i < bufs.count; i++) {
1838fe517fc9Smrg        retval->list[i].idx     = bufs.list[i].idx;
1839fe517fc9Smrg        retval->list[i].total   = bufs.list[i].total;
1840fe517fc9Smrg        retval->list[i].used    = 0;
1841fe517fc9Smrg        retval->list[i].address = bufs.list[i].address;
1842fe517fc9Smrg    }
184322944501Smrg
1844fe517fc9Smrg    drmFree(bufs.list);
1845fe517fc9Smrg    return retval;
184622944501Smrg}
184722944501Smrg
184822944501Smrg
184922944501Smrg/**
185022944501Smrg * Unmap buffers allocated with drmMapBufs().
185122944501Smrg *
185222944501Smrg * \return zero on success, or negative value on failure.
185322944501Smrg *
185422944501Smrg * \internal
185522944501Smrg * Calls munmap() for every buffer stored in \p bufs and frees the
185622944501Smrg * memory allocated by drmMapBufs().
185722944501Smrg */
18586260e5d5Smrgdrm_public int drmUnmapBufs(drmBufMapPtr bufs)
185922944501Smrg{
186022944501Smrg    int i;
186122944501Smrg
186222944501Smrg    for (i = 0; i < bufs->count; i++) {
1863fe517fc9Smrg        drm_munmap(bufs->list[i].address, bufs->list[i].total);
186422944501Smrg    }
186522944501Smrg
186622944501Smrg    drmFree(bufs->list);
186722944501Smrg    drmFree(bufs);
186822944501Smrg    return 0;
186922944501Smrg}
187022944501Smrg
187122944501Smrg
1872fe517fc9Smrg#define DRM_DMA_RETRY  16
187322944501Smrg
187422944501Smrg/**
187522944501Smrg * Reserve DMA buffers.
187622944501Smrg *
187722944501Smrg * \param fd file descriptor.
1878fe517fc9Smrg * \param request
1879fe517fc9Smrg *
188022944501Smrg * \return zero on success, or a negative value on failure.
188122944501Smrg *
188222944501Smrg * \internal
188322944501Smrg * Assemble the arguments into a drm_dma structure and keeps issuing the
188422944501Smrg * DRM_IOCTL_DMA ioctl until success or until maximum number of retries.
188522944501Smrg */
18866260e5d5Smrgdrm_public int drmDMA(int fd, drmDMAReqPtr request)
188722944501Smrg{
188822944501Smrg    drm_dma_t dma;
188922944501Smrg    int ret, i = 0;
189022944501Smrg
189122944501Smrg    dma.context         = request->context;
189222944501Smrg    dma.send_count      = request->send_count;
189322944501Smrg    dma.send_indices    = request->send_list;
189422944501Smrg    dma.send_sizes      = request->send_sizes;
1895adfa0b0cSmrg    dma.flags           = (enum drm_dma_flags)request->flags;
189622944501Smrg    dma.request_count   = request->request_count;
189722944501Smrg    dma.request_size    = request->request_size;
189822944501Smrg    dma.request_indices = request->request_list;
189922944501Smrg    dma.request_sizes   = request->request_sizes;
190022944501Smrg    dma.granted_count   = 0;
190122944501Smrg
190222944501Smrg    do {
1903fe517fc9Smrg        ret = ioctl( fd, DRM_IOCTL_DMA, &dma );
190422944501Smrg    } while ( ret && errno == EAGAIN && i++ < DRM_DMA_RETRY );
190522944501Smrg
190622944501Smrg    if ( ret == 0 ) {
1907fe517fc9Smrg        request->granted_count = dma.granted_count;
1908fe517fc9Smrg        return 0;
190922944501Smrg    } else {
1910fe517fc9Smrg        return -errno;
191122944501Smrg    }
191222944501Smrg}
191322944501Smrg
191422944501Smrg
191522944501Smrg/**
191622944501Smrg * Obtain heavyweight hardware lock.
191722944501Smrg *
191822944501Smrg * \param fd file descriptor.
191922944501Smrg * \param context context.
1920bf6cc7dcSmrg * \param flags flags that determine the state of the hardware when the function
192122944501Smrg * returns.
1922fe517fc9Smrg *
192322944501Smrg * \return always zero.
1924fe517fc9Smrg *
192522944501Smrg * \internal
192622944501Smrg * This function translates the arguments into a drm_lock structure and issue
192722944501Smrg * the DRM_IOCTL_LOCK ioctl until the lock is successfully acquired.
192822944501Smrg */
19296260e5d5Smrgdrm_public int drmGetLock(int fd, drm_context_t context, drmLockFlags flags)
193022944501Smrg{
193122944501Smrg    drm_lock_t lock;
193222944501Smrg
1933424e9256Smrg    memclear(lock);
193422944501Smrg    lock.context = context;
193522944501Smrg    lock.flags   = 0;
193622944501Smrg    if (flags & DRM_LOCK_READY)      lock.flags |= _DRM_LOCK_READY;
193722944501Smrg    if (flags & DRM_LOCK_QUIESCENT)  lock.flags |= _DRM_LOCK_QUIESCENT;
193822944501Smrg    if (flags & DRM_LOCK_FLUSH)      lock.flags |= _DRM_LOCK_FLUSH;
193922944501Smrg    if (flags & DRM_LOCK_FLUSH_ALL)  lock.flags |= _DRM_LOCK_FLUSH_ALL;
194022944501Smrg    if (flags & DRM_HALT_ALL_QUEUES) lock.flags |= _DRM_HALT_ALL_QUEUES;
194122944501Smrg    if (flags & DRM_HALT_CUR_QUEUES) lock.flags |= _DRM_HALT_CUR_QUEUES;
194222944501Smrg
194322944501Smrg    while (drmIoctl(fd, DRM_IOCTL_LOCK, &lock))
1944fe517fc9Smrg        ;
194522944501Smrg    return 0;
194622944501Smrg}
194722944501Smrg
194822944501Smrg/**
194922944501Smrg * Release the hardware lock.
195022944501Smrg *
195122944501Smrg * \param fd file descriptor.
195222944501Smrg * \param context context.
1953fe517fc9Smrg *
195422944501Smrg * \return zero on success, or a negative value on failure.
1955fe517fc9Smrg *
195622944501Smrg * \internal
195722944501Smrg * This function is a wrapper around the DRM_IOCTL_UNLOCK ioctl, passing the
195822944501Smrg * argument in a drm_lock structure.
195922944501Smrg */
19606260e5d5Smrgdrm_public int drmUnlock(int fd, drm_context_t context)
196122944501Smrg{
196222944501Smrg    drm_lock_t lock;
196322944501Smrg
1964424e9256Smrg    memclear(lock);
196522944501Smrg    lock.context = context;
196622944501Smrg    return drmIoctl(fd, DRM_IOCTL_UNLOCK, &lock);
196722944501Smrg}
196822944501Smrg
19696260e5d5Smrgdrm_public drm_context_t *drmGetReservedContextList(int fd, int *count)
197022944501Smrg{
197122944501Smrg    drm_ctx_res_t res;
197222944501Smrg    drm_ctx_t     *list;
197322944501Smrg    drm_context_t * retval;
197422944501Smrg    int           i;
197522944501Smrg
1976424e9256Smrg    memclear(res);
197722944501Smrg    if (drmIoctl(fd, DRM_IOCTL_RES_CTX, &res))
1978fe517fc9Smrg        return NULL;
197922944501Smrg
198022944501Smrg    if (!res.count)
1981fe517fc9Smrg        return NULL;
198222944501Smrg
198322944501Smrg    if (!(list   = drmMalloc(res.count * sizeof(*list))))
1984fe517fc9Smrg        return NULL;
19850655efefSmrg    if (!(retval = drmMalloc(res.count * sizeof(*retval))))
19860655efefSmrg        goto err_free_list;
198722944501Smrg
198822944501Smrg    res.contexts = list;
198922944501Smrg    if (drmIoctl(fd, DRM_IOCTL_RES_CTX, &res))
19900655efefSmrg        goto err_free_context;
199122944501Smrg
199222944501Smrg    for (i = 0; i < res.count; i++)
1993fe517fc9Smrg        retval[i] = list[i].handle;
199422944501Smrg    drmFree(list);
199522944501Smrg
199622944501Smrg    *count = res.count;
199722944501Smrg    return retval;
19980655efefSmrg
19990655efefSmrgerr_free_list:
20000655efefSmrg    drmFree(list);
20010655efefSmrgerr_free_context:
20020655efefSmrg    drmFree(retval);
20030655efefSmrg    return NULL;
200422944501Smrg}
200522944501Smrg
20066260e5d5Smrgdrm_public void drmFreeReservedContextList(drm_context_t *pt)
200722944501Smrg{
200822944501Smrg    drmFree(pt);
200922944501Smrg}
201022944501Smrg
201122944501Smrg/**
201222944501Smrg * Create context.
201322944501Smrg *
201422944501Smrg * Used by the X server during GLXContext initialization. This causes
201522944501Smrg * per-context kernel-level resources to be allocated.
201622944501Smrg *
201722944501Smrg * \param fd file descriptor.
201822944501Smrg * \param handle is set on success. To be used by the client when requesting DMA
201922944501Smrg * dispatch with drmDMA().
2020fe517fc9Smrg *
202122944501Smrg * \return zero on success, or a negative value on failure.
2022fe517fc9Smrg *
202322944501Smrg * \note May only be called by root.
2024fe517fc9Smrg *
202522944501Smrg * \internal
202622944501Smrg * This function is a wrapper around the DRM_IOCTL_ADD_CTX ioctl, passing the
202722944501Smrg * argument in a drm_ctx structure.
202822944501Smrg */
20296260e5d5Smrgdrm_public int drmCreateContext(int fd, drm_context_t *handle)
203022944501Smrg{
203122944501Smrg    drm_ctx_t ctx;
203222944501Smrg
2033424e9256Smrg    memclear(ctx);
203422944501Smrg    if (drmIoctl(fd, DRM_IOCTL_ADD_CTX, &ctx))
2035fe517fc9Smrg        return -errno;
203622944501Smrg    *handle = ctx.handle;
203722944501Smrg    return 0;
203822944501Smrg}
203922944501Smrg
20406260e5d5Smrgdrm_public int drmSwitchToContext(int fd, drm_context_t context)
204122944501Smrg{
204222944501Smrg    drm_ctx_t ctx;
204322944501Smrg
2044424e9256Smrg    memclear(ctx);
204522944501Smrg    ctx.handle = context;
204622944501Smrg    if (drmIoctl(fd, DRM_IOCTL_SWITCH_CTX, &ctx))
2047fe517fc9Smrg        return -errno;
204822944501Smrg    return 0;
204922944501Smrg}
205022944501Smrg
20516260e5d5Smrgdrm_public int drmSetContextFlags(int fd, drm_context_t context,
20526260e5d5Smrg                                  drm_context_tFlags flags)
205322944501Smrg{
205422944501Smrg    drm_ctx_t ctx;
205522944501Smrg
205622944501Smrg    /*
205722944501Smrg     * Context preserving means that no context switches are done between DMA
205822944501Smrg     * buffers from one context and the next.  This is suitable for use in the
205922944501Smrg     * X server (which promises to maintain hardware context), or in the
206022944501Smrg     * client-side library when buffers are swapped on behalf of two threads.
206122944501Smrg     */
2062424e9256Smrg    memclear(ctx);
206322944501Smrg    ctx.handle = context;
206422944501Smrg    if (flags & DRM_CONTEXT_PRESERVED)
2065fe517fc9Smrg        ctx.flags |= _DRM_CONTEXT_PRESERVED;
206622944501Smrg    if (flags & DRM_CONTEXT_2DONLY)
2067fe517fc9Smrg        ctx.flags |= _DRM_CONTEXT_2DONLY;
206822944501Smrg    if (drmIoctl(fd, DRM_IOCTL_MOD_CTX, &ctx))
2069fe517fc9Smrg        return -errno;
207022944501Smrg    return 0;
207122944501Smrg}
207222944501Smrg
20736260e5d5Smrgdrm_public int drmGetContextFlags(int fd, drm_context_t context,
20746260e5d5Smrg                                  drm_context_tFlagsPtr flags)
207522944501Smrg{
207622944501Smrg    drm_ctx_t ctx;
207722944501Smrg
2078424e9256Smrg    memclear(ctx);
207922944501Smrg    ctx.handle = context;
208022944501Smrg    if (drmIoctl(fd, DRM_IOCTL_GET_CTX, &ctx))
2081fe517fc9Smrg        return -errno;
208222944501Smrg    *flags = 0;
208322944501Smrg    if (ctx.flags & _DRM_CONTEXT_PRESERVED)
2084fe517fc9Smrg        *flags |= DRM_CONTEXT_PRESERVED;
208522944501Smrg    if (ctx.flags & _DRM_CONTEXT_2DONLY)
2086fe517fc9Smrg        *flags |= DRM_CONTEXT_2DONLY;
208722944501Smrg    return 0;
208822944501Smrg}
208922944501Smrg
209022944501Smrg/**
209122944501Smrg * Destroy context.
209222944501Smrg *
209322944501Smrg * Free any kernel-level resources allocated with drmCreateContext() associated
209422944501Smrg * with the context.
2095fe517fc9Smrg *
209622944501Smrg * \param fd file descriptor.
209722944501Smrg * \param handle handle given by drmCreateContext().
2098fe517fc9Smrg *
209922944501Smrg * \return zero on success, or a negative value on failure.
2100fe517fc9Smrg *
210122944501Smrg * \note May only be called by root.
2102fe517fc9Smrg *
210322944501Smrg * \internal
210422944501Smrg * This function is a wrapper around the DRM_IOCTL_RM_CTX ioctl, passing the
210522944501Smrg * argument in a drm_ctx structure.
210622944501Smrg */
21076260e5d5Smrgdrm_public int drmDestroyContext(int fd, drm_context_t handle)
210822944501Smrg{
210922944501Smrg    drm_ctx_t ctx;
2110424e9256Smrg
2111424e9256Smrg    memclear(ctx);
211222944501Smrg    ctx.handle = handle;
211322944501Smrg    if (drmIoctl(fd, DRM_IOCTL_RM_CTX, &ctx))
2114fe517fc9Smrg        return -errno;
211522944501Smrg    return 0;
211622944501Smrg}
211722944501Smrg
21186260e5d5Smrgdrm_public int drmCreateDrawable(int fd, drm_drawable_t *handle)
211922944501Smrg{
212022944501Smrg    drm_draw_t draw;
2121424e9256Smrg
2122424e9256Smrg    memclear(draw);
212322944501Smrg    if (drmIoctl(fd, DRM_IOCTL_ADD_DRAW, &draw))
2124fe517fc9Smrg        return -errno;
212522944501Smrg    *handle = draw.handle;
212622944501Smrg    return 0;
212722944501Smrg}
212822944501Smrg
21296260e5d5Smrgdrm_public int drmDestroyDrawable(int fd, drm_drawable_t handle)
213022944501Smrg{
213122944501Smrg    drm_draw_t draw;
2132424e9256Smrg
2133424e9256Smrg    memclear(draw);
213422944501Smrg    draw.handle = handle;
213522944501Smrg    if (drmIoctl(fd, DRM_IOCTL_RM_DRAW, &draw))
2136fe517fc9Smrg        return -errno;
213722944501Smrg    return 0;
213822944501Smrg}
213922944501Smrg
21406260e5d5Smrgdrm_public int drmUpdateDrawableInfo(int fd, drm_drawable_t handle,
21416260e5d5Smrg                                     drm_drawable_info_type_t type,
21426260e5d5Smrg                                     unsigned int num, void *data)
214322944501Smrg{
214422944501Smrg    drm_update_draw_t update;
214522944501Smrg
2146424e9256Smrg    memclear(update);
214722944501Smrg    update.handle = handle;
214822944501Smrg    update.type = type;
214922944501Smrg    update.num = num;
215022944501Smrg    update.data = (unsigned long long)(unsigned long)data;
215122944501Smrg
215222944501Smrg    if (drmIoctl(fd, DRM_IOCTL_UPDATE_DRAW, &update))
2153fe517fc9Smrg        return -errno;
215422944501Smrg
215522944501Smrg    return 0;
215622944501Smrg}
215722944501Smrg
21586260e5d5Smrgdrm_public int drmCrtcGetSequence(int fd, uint32_t crtcId, uint64_t *sequence,
21596260e5d5Smrg                                  uint64_t *ns)
21602b90624aSmrg{
21612b90624aSmrg    struct drm_crtc_get_sequence get_seq;
21622b90624aSmrg    int ret;
21632b90624aSmrg
21642b90624aSmrg    memclear(get_seq);
21652b90624aSmrg    get_seq.crtc_id = crtcId;
21662b90624aSmrg    ret = drmIoctl(fd, DRM_IOCTL_CRTC_GET_SEQUENCE, &get_seq);
21672b90624aSmrg    if (ret)
21682b90624aSmrg        return ret;
21692b90624aSmrg
21702b90624aSmrg    if (sequence)
21712b90624aSmrg        *sequence = get_seq.sequence;
21722b90624aSmrg    if (ns)
21732b90624aSmrg        *ns = get_seq.sequence_ns;
21742b90624aSmrg    return 0;
21752b90624aSmrg}
21762b90624aSmrg
21776260e5d5Smrgdrm_public int drmCrtcQueueSequence(int fd, uint32_t crtcId, uint32_t flags,
21786260e5d5Smrg                                    uint64_t sequence,
21796260e5d5Smrg                                    uint64_t *sequence_queued,
21806260e5d5Smrg                                    uint64_t user_data)
21812b90624aSmrg{
21822b90624aSmrg    struct drm_crtc_queue_sequence queue_seq;
21832b90624aSmrg    int ret;
21842b90624aSmrg
21852b90624aSmrg    memclear(queue_seq);
21862b90624aSmrg    queue_seq.crtc_id = crtcId;
21872b90624aSmrg    queue_seq.flags = flags;
21882b90624aSmrg    queue_seq.sequence = sequence;
21892b90624aSmrg    queue_seq.user_data = user_data;
21902b90624aSmrg
21912b90624aSmrg    ret = drmIoctl(fd, DRM_IOCTL_CRTC_QUEUE_SEQUENCE, &queue_seq);
21922b90624aSmrg    if (ret == 0 && sequence_queued)
21932b90624aSmrg        *sequence_queued = queue_seq.sequence;
21942b90624aSmrg
21952b90624aSmrg    return ret;
21962b90624aSmrg}
21972b90624aSmrg
219822944501Smrg/**
219922944501Smrg * Acquire the AGP device.
220022944501Smrg *
220122944501Smrg * Must be called before any of the other AGP related calls.
220222944501Smrg *
220322944501Smrg * \param fd file descriptor.
2204fe517fc9Smrg *
220522944501Smrg * \return zero on success, or a negative value on failure.
2206fe517fc9Smrg *
220722944501Smrg * \internal
220822944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_ACQUIRE ioctl.
220922944501Smrg */
22106260e5d5Smrgdrm_public int drmAgpAcquire(int fd)
221122944501Smrg{
221222944501Smrg    if (drmIoctl(fd, DRM_IOCTL_AGP_ACQUIRE, NULL))
2213fe517fc9Smrg        return -errno;
221422944501Smrg    return 0;
221522944501Smrg}
221622944501Smrg
221722944501Smrg
221822944501Smrg/**
221922944501Smrg * Release the AGP device.
222022944501Smrg *
222122944501Smrg * \param fd file descriptor.
2222fe517fc9Smrg *
222322944501Smrg * \return zero on success, or a negative value on failure.
2224fe517fc9Smrg *
222522944501Smrg * \internal
222622944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_RELEASE ioctl.
222722944501Smrg */
22286260e5d5Smrgdrm_public int drmAgpRelease(int fd)
222922944501Smrg{
223022944501Smrg    if (drmIoctl(fd, DRM_IOCTL_AGP_RELEASE, NULL))
2231fe517fc9Smrg        return -errno;
223222944501Smrg    return 0;
223322944501Smrg}
223422944501Smrg
223522944501Smrg
223622944501Smrg/**
223722944501Smrg * Set the AGP mode.
223822944501Smrg *
223922944501Smrg * \param fd file descriptor.
224022944501Smrg * \param mode AGP mode.
2241fe517fc9Smrg *
224222944501Smrg * \return zero on success, or a negative value on failure.
2243fe517fc9Smrg *
224422944501Smrg * \internal
224522944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_ENABLE ioctl, passing the
224622944501Smrg * argument in a drm_agp_mode structure.
224722944501Smrg */
22486260e5d5Smrgdrm_public int drmAgpEnable(int fd, unsigned long mode)
224922944501Smrg{
225022944501Smrg    drm_agp_mode_t m;
225122944501Smrg
2252424e9256Smrg    memclear(m);
225322944501Smrg    m.mode = mode;
225422944501Smrg    if (drmIoctl(fd, DRM_IOCTL_AGP_ENABLE, &m))
2255fe517fc9Smrg        return -errno;
225622944501Smrg    return 0;
225722944501Smrg}
225822944501Smrg
225922944501Smrg
226022944501Smrg/**
226122944501Smrg * Allocate a chunk of AGP memory.
226222944501Smrg *
226322944501Smrg * \param fd file descriptor.
226422944501Smrg * \param size requested memory size in bytes. Will be rounded to page boundary.
226522944501Smrg * \param type type of memory to allocate.
226622944501Smrg * \param address if not zero, will be set to the physical address of the
226722944501Smrg * allocated memory.
226822944501Smrg * \param handle on success will be set to a handle of the allocated memory.
2269fe517fc9Smrg *
227022944501Smrg * \return zero on success, or a negative value on failure.
2271fe517fc9Smrg *
227222944501Smrg * \internal
227322944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_ALLOC ioctl, passing the
227422944501Smrg * arguments in a drm_agp_buffer structure.
227522944501Smrg */
22766260e5d5Smrgdrm_public int drmAgpAlloc(int fd, unsigned long size, unsigned long type,
22776260e5d5Smrg                           unsigned long *address, drm_handle_t *handle)
227822944501Smrg{
227922944501Smrg    drm_agp_buffer_t b;
228022944501Smrg
2281424e9256Smrg    memclear(b);
228222944501Smrg    *handle = DRM_AGP_NO_HANDLE;
228322944501Smrg    b.size   = size;
228422944501Smrg    b.type   = type;
228522944501Smrg    if (drmIoctl(fd, DRM_IOCTL_AGP_ALLOC, &b))
2286fe517fc9Smrg        return -errno;
228722944501Smrg    if (address != 0UL)
2288fe517fc9Smrg        *address = b.physical;
228922944501Smrg    *handle = b.handle;
229022944501Smrg    return 0;
229122944501Smrg}
229222944501Smrg
229322944501Smrg
229422944501Smrg/**
229522944501Smrg * Free a chunk of AGP memory.
229622944501Smrg *
229722944501Smrg * \param fd file descriptor.
229822944501Smrg * \param handle handle to the allocated memory, as given by drmAgpAllocate().
2299fe517fc9Smrg *
230022944501Smrg * \return zero on success, or a negative value on failure.
2301fe517fc9Smrg *
230222944501Smrg * \internal
230322944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_FREE ioctl, passing the
230422944501Smrg * argument in a drm_agp_buffer structure.
230522944501Smrg */
23066260e5d5Smrgdrm_public int drmAgpFree(int fd, drm_handle_t handle)
230722944501Smrg{
230822944501Smrg    drm_agp_buffer_t b;
230922944501Smrg
2310424e9256Smrg    memclear(b);
231122944501Smrg    b.handle = handle;
231222944501Smrg    if (drmIoctl(fd, DRM_IOCTL_AGP_FREE, &b))
2313fe517fc9Smrg        return -errno;
231422944501Smrg    return 0;
231522944501Smrg}
231622944501Smrg
231722944501Smrg
231822944501Smrg/**
231922944501Smrg * Bind a chunk of AGP memory.
232022944501Smrg *
232122944501Smrg * \param fd file descriptor.
232222944501Smrg * \param handle handle to the allocated memory, as given by drmAgpAllocate().
232322944501Smrg * \param offset offset in bytes. It will round to page boundary.
2324fe517fc9Smrg *
232522944501Smrg * \return zero on success, or a negative value on failure.
2326fe517fc9Smrg *
232722944501Smrg * \internal
232822944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_BIND ioctl, passing the
232922944501Smrg * argument in a drm_agp_binding structure.
233022944501Smrg */
23316260e5d5Smrgdrm_public int drmAgpBind(int fd, drm_handle_t handle, unsigned long offset)
233222944501Smrg{
233322944501Smrg    drm_agp_binding_t b;
233422944501Smrg
2335424e9256Smrg    memclear(b);
233622944501Smrg    b.handle = handle;
233722944501Smrg    b.offset = offset;
233822944501Smrg    if (drmIoctl(fd, DRM_IOCTL_AGP_BIND, &b))
2339fe517fc9Smrg        return -errno;
234022944501Smrg    return 0;
234122944501Smrg}
234222944501Smrg
234322944501Smrg
234422944501Smrg/**
234522944501Smrg * Unbind a chunk of AGP memory.
234622944501Smrg *
234722944501Smrg * \param fd file descriptor.
234822944501Smrg * \param handle handle to the allocated memory, as given by drmAgpAllocate().
2349fe517fc9Smrg *
235022944501Smrg * \return zero on success, or a negative value on failure.
2351fe517fc9Smrg *
235222944501Smrg * \internal
235322944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_UNBIND ioctl, passing
235422944501Smrg * the argument in a drm_agp_binding structure.
235522944501Smrg */
23566260e5d5Smrgdrm_public int drmAgpUnbind(int fd, drm_handle_t handle)
235722944501Smrg{
235822944501Smrg    drm_agp_binding_t b;
235922944501Smrg
2360424e9256Smrg    memclear(b);
236122944501Smrg    b.handle = handle;
236222944501Smrg    if (drmIoctl(fd, DRM_IOCTL_AGP_UNBIND, &b))
2363fe517fc9Smrg        return -errno;
236422944501Smrg    return 0;
236522944501Smrg}
236622944501Smrg
236722944501Smrg
236822944501Smrg/**
236922944501Smrg * Get AGP driver major version number.
237022944501Smrg *
237122944501Smrg * \param fd file descriptor.
2372fe517fc9Smrg *
237322944501Smrg * \return major version number on success, or a negative value on failure..
2374fe517fc9Smrg *
237522944501Smrg * \internal
237622944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
237722944501Smrg * necessary information in a drm_agp_info structure.
237822944501Smrg */
23796260e5d5Smrgdrm_public int drmAgpVersionMajor(int fd)
238022944501Smrg{
238122944501Smrg    drm_agp_info_t i;
238222944501Smrg
2383424e9256Smrg    memclear(i);
2384424e9256Smrg
238522944501Smrg    if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
2386fe517fc9Smrg        return -errno;
238722944501Smrg    return i.agp_version_major;
238822944501Smrg}
238922944501Smrg
239022944501Smrg
239122944501Smrg/**
239222944501Smrg * Get AGP driver minor version number.
239322944501Smrg *
239422944501Smrg * \param fd file descriptor.
2395fe517fc9Smrg *
239622944501Smrg * \return minor version number on success, or a negative value on failure.
2397fe517fc9Smrg *
239822944501Smrg * \internal
239922944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
240022944501Smrg * necessary information in a drm_agp_info structure.
240122944501Smrg */
24026260e5d5Smrgdrm_public int drmAgpVersionMinor(int fd)
240322944501Smrg{
240422944501Smrg    drm_agp_info_t i;
240522944501Smrg
2406424e9256Smrg    memclear(i);
2407424e9256Smrg
240822944501Smrg    if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
2409fe517fc9Smrg        return -errno;
241022944501Smrg    return i.agp_version_minor;
241122944501Smrg}
241222944501Smrg
241322944501Smrg
241422944501Smrg/**
241522944501Smrg * Get AGP mode.
241622944501Smrg *
241722944501Smrg * \param fd file descriptor.
2418fe517fc9Smrg *
241922944501Smrg * \return mode on success, or zero on failure.
2420fe517fc9Smrg *
242122944501Smrg * \internal
242222944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
242322944501Smrg * necessary information in a drm_agp_info structure.
242422944501Smrg */
24256260e5d5Smrgdrm_public unsigned long drmAgpGetMode(int fd)
242622944501Smrg{
242722944501Smrg    drm_agp_info_t i;
242822944501Smrg
2429424e9256Smrg    memclear(i);
2430424e9256Smrg
243122944501Smrg    if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
2432fe517fc9Smrg        return 0;
243322944501Smrg    return i.mode;
243422944501Smrg}
243522944501Smrg
243622944501Smrg
243722944501Smrg/**
243822944501Smrg * Get AGP aperture base.
243922944501Smrg *
244022944501Smrg * \param fd file descriptor.
2441fe517fc9Smrg *
244222944501Smrg * \return aperture base on success, zero on failure.
2443fe517fc9Smrg *
244422944501Smrg * \internal
244522944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
244622944501Smrg * necessary information in a drm_agp_info structure.
244722944501Smrg */
24486260e5d5Smrgdrm_public unsigned long drmAgpBase(int fd)
244922944501Smrg{
245022944501Smrg    drm_agp_info_t i;
245122944501Smrg
2452424e9256Smrg    memclear(i);
2453424e9256Smrg
245422944501Smrg    if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
2455fe517fc9Smrg        return 0;
245622944501Smrg    return i.aperture_base;
245722944501Smrg}
245822944501Smrg
245922944501Smrg
246022944501Smrg/**
246122944501Smrg * Get AGP aperture size.
246222944501Smrg *
246322944501Smrg * \param fd file descriptor.
2464fe517fc9Smrg *
246522944501Smrg * \return aperture size on success, zero on failure.
2466fe517fc9Smrg *
246722944501Smrg * \internal
246822944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
246922944501Smrg * necessary information in a drm_agp_info structure.
247022944501Smrg */
24716260e5d5Smrgdrm_public unsigned long drmAgpSize(int fd)
247222944501Smrg{
247322944501Smrg    drm_agp_info_t i;
247422944501Smrg
2475424e9256Smrg    memclear(i);
2476424e9256Smrg
247722944501Smrg    if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
2478fe517fc9Smrg        return 0;
247922944501Smrg    return i.aperture_size;
248022944501Smrg}
248122944501Smrg
248222944501Smrg
248322944501Smrg/**
248422944501Smrg * Get used AGP memory.
248522944501Smrg *
248622944501Smrg * \param fd file descriptor.
2487fe517fc9Smrg *
248822944501Smrg * \return memory used on success, or zero on failure.
2489fe517fc9Smrg *
249022944501Smrg * \internal
249122944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
249222944501Smrg * necessary information in a drm_agp_info structure.
249322944501Smrg */
24946260e5d5Smrgdrm_public unsigned long drmAgpMemoryUsed(int fd)
249522944501Smrg{
249622944501Smrg    drm_agp_info_t i;
249722944501Smrg
2498424e9256Smrg    memclear(i);
2499424e9256Smrg
250022944501Smrg    if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
2501fe517fc9Smrg        return 0;
250222944501Smrg    return i.memory_used;
250322944501Smrg}
250422944501Smrg
250522944501Smrg
250622944501Smrg/**
250722944501Smrg * Get available AGP memory.
250822944501Smrg *
250922944501Smrg * \param fd file descriptor.
2510fe517fc9Smrg *
251122944501Smrg * \return memory available on success, or zero on failure.
2512fe517fc9Smrg *
251322944501Smrg * \internal
251422944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
251522944501Smrg * necessary information in a drm_agp_info structure.
251622944501Smrg */
25176260e5d5Smrgdrm_public unsigned long drmAgpMemoryAvail(int fd)
251822944501Smrg{
251922944501Smrg    drm_agp_info_t i;
252022944501Smrg
2521424e9256Smrg    memclear(i);
2522424e9256Smrg
252322944501Smrg    if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
2524fe517fc9Smrg        return 0;
252522944501Smrg    return i.memory_allowed;
252622944501Smrg}
252722944501Smrg
252822944501Smrg
252922944501Smrg/**
253022944501Smrg * Get hardware vendor ID.
253122944501Smrg *
253222944501Smrg * \param fd file descriptor.
2533fe517fc9Smrg *
253422944501Smrg * \return vendor ID on success, or zero on failure.
2535fe517fc9Smrg *
253622944501Smrg * \internal
253722944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
253822944501Smrg * necessary information in a drm_agp_info structure.
253922944501Smrg */
25406260e5d5Smrgdrm_public unsigned int drmAgpVendorId(int fd)
254122944501Smrg{
254222944501Smrg    drm_agp_info_t i;
254322944501Smrg
2544424e9256Smrg    memclear(i);
2545424e9256Smrg
254622944501Smrg    if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
2547fe517fc9Smrg        return 0;
254822944501Smrg    return i.id_vendor;
254922944501Smrg}
255022944501Smrg
255122944501Smrg
255222944501Smrg/**
255322944501Smrg * Get hardware device ID.
255422944501Smrg *
255522944501Smrg * \param fd file descriptor.
2556fe517fc9Smrg *
255722944501Smrg * \return zero on success, or zero on failure.
2558fe517fc9Smrg *
255922944501Smrg * \internal
256022944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
256122944501Smrg * necessary information in a drm_agp_info structure.
256222944501Smrg */
25636260e5d5Smrgdrm_public unsigned int drmAgpDeviceId(int fd)
256422944501Smrg{
256522944501Smrg    drm_agp_info_t i;
256622944501Smrg
2567424e9256Smrg    memclear(i);
2568424e9256Smrg
256922944501Smrg    if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
2570fe517fc9Smrg        return 0;
257122944501Smrg    return i.id_device;
257222944501Smrg}
257322944501Smrg
25746260e5d5Smrgdrm_public int drmScatterGatherAlloc(int fd, unsigned long size,
25756260e5d5Smrg                                     drm_handle_t *handle)
257622944501Smrg{
257722944501Smrg    drm_scatter_gather_t sg;
257822944501Smrg
2579424e9256Smrg    memclear(sg);
2580424e9256Smrg
258122944501Smrg    *handle = 0;
258222944501Smrg    sg.size   = size;
258322944501Smrg    if (drmIoctl(fd, DRM_IOCTL_SG_ALLOC, &sg))
2584fe517fc9Smrg        return -errno;
258522944501Smrg    *handle = sg.handle;
258622944501Smrg    return 0;
258722944501Smrg}
258822944501Smrg
25896260e5d5Smrgdrm_public int drmScatterGatherFree(int fd, drm_handle_t handle)
259022944501Smrg{
259122944501Smrg    drm_scatter_gather_t sg;
259222944501Smrg
2593424e9256Smrg    memclear(sg);
259422944501Smrg    sg.handle = handle;
259522944501Smrg    if (drmIoctl(fd, DRM_IOCTL_SG_FREE, &sg))
2596fe517fc9Smrg        return -errno;
259722944501Smrg    return 0;
259822944501Smrg}
259922944501Smrg
260022944501Smrg/**
260122944501Smrg * Wait for VBLANK.
260222944501Smrg *
260322944501Smrg * \param fd file descriptor.
260422944501Smrg * \param vbl pointer to a drmVBlank structure.
2605fe517fc9Smrg *
260622944501Smrg * \return zero on success, or a negative value on failure.
2607fe517fc9Smrg *
260822944501Smrg * \internal
260922944501Smrg * This function is a wrapper around the DRM_IOCTL_WAIT_VBLANK ioctl.
261022944501Smrg */
26116260e5d5Smrgdrm_public int drmWaitVBlank(int fd, drmVBlankPtr vbl)
261222944501Smrg{
261322944501Smrg    struct timespec timeout, cur;
261422944501Smrg    int ret;
261522944501Smrg
261622944501Smrg    ret = clock_gettime(CLOCK_MONOTONIC, &timeout);
261722944501Smrg    if (ret < 0) {
2618fe517fc9Smrg        fprintf(stderr, "clock_gettime failed: %s\n", strerror(errno));
2619fe517fc9Smrg        goto out;
262022944501Smrg    }
262122944501Smrg    timeout.tv_sec++;
262222944501Smrg
262322944501Smrg    do {
262422944501Smrg       ret = ioctl(fd, DRM_IOCTL_WAIT_VBLANK, vbl);
262522944501Smrg       vbl->request.type &= ~DRM_VBLANK_RELATIVE;
262622944501Smrg       if (ret && errno == EINTR) {
2627fe517fc9Smrg           clock_gettime(CLOCK_MONOTONIC, &cur);
2628fe517fc9Smrg           /* Timeout after 1s */
2629fe517fc9Smrg           if (cur.tv_sec > timeout.tv_sec + 1 ||
2630fe517fc9Smrg               (cur.tv_sec == timeout.tv_sec && cur.tv_nsec >=
2631fe517fc9Smrg                timeout.tv_nsec)) {
2632fe517fc9Smrg                   errno = EBUSY;
2633fe517fc9Smrg                   ret = -1;
2634fe517fc9Smrg                   break;
2635fe517fc9Smrg           }
263622944501Smrg       }
263722944501Smrg    } while (ret && errno == EINTR);
263822944501Smrg
263922944501Smrgout:
264022944501Smrg    return ret;
264122944501Smrg}
264222944501Smrg
26436260e5d5Smrgdrm_public int drmError(int err, const char *label)
264422944501Smrg{
264522944501Smrg    switch (err) {
264622944501Smrg    case DRM_ERR_NO_DEVICE:
2647fe517fc9Smrg        fprintf(stderr, "%s: no device\n", label);
2648fe517fc9Smrg        break;
264922944501Smrg    case DRM_ERR_NO_ACCESS:
2650fe517fc9Smrg        fprintf(stderr, "%s: no access\n", label);
2651fe517fc9Smrg        break;
265222944501Smrg    case DRM_ERR_NOT_ROOT:
2653fe517fc9Smrg        fprintf(stderr, "%s: not root\n", label);
2654fe517fc9Smrg        break;
265522944501Smrg    case DRM_ERR_INVALID:
2656fe517fc9Smrg        fprintf(stderr, "%s: invalid args\n", label);
2657fe517fc9Smrg        break;
265822944501Smrg    default:
2659fe517fc9Smrg        if (err < 0)
2660fe517fc9Smrg            err = -err;
2661fe517fc9Smrg        fprintf( stderr, "%s: error %d (%s)\n", label, err, strerror(err) );
2662fe517fc9Smrg        break;
266322944501Smrg    }
266422944501Smrg
266522944501Smrg    return 1;
266622944501Smrg}
266722944501Smrg
266822944501Smrg/**
266922944501Smrg * Install IRQ handler.
267022944501Smrg *
267122944501Smrg * \param fd file descriptor.
267222944501Smrg * \param irq IRQ number.
2673fe517fc9Smrg *
267422944501Smrg * \return zero on success, or a negative value on failure.
2675fe517fc9Smrg *
267622944501Smrg * \internal
267722944501Smrg * This function is a wrapper around the DRM_IOCTL_CONTROL ioctl, passing the
267822944501Smrg * argument in a drm_control structure.
267922944501Smrg */
26806260e5d5Smrgdrm_public int drmCtlInstHandler(int fd, int irq)
268122944501Smrg{
268222944501Smrg    drm_control_t ctl;
268322944501Smrg
2684424e9256Smrg    memclear(ctl);
268522944501Smrg    ctl.func  = DRM_INST_HANDLER;
268622944501Smrg    ctl.irq   = irq;
268722944501Smrg    if (drmIoctl(fd, DRM_IOCTL_CONTROL, &ctl))
2688fe517fc9Smrg        return -errno;
268922944501Smrg    return 0;
269022944501Smrg}
269122944501Smrg
269222944501Smrg
269322944501Smrg/**
269422944501Smrg * Uninstall IRQ handler.
269522944501Smrg *
269622944501Smrg * \param fd file descriptor.
2697fe517fc9Smrg *
269822944501Smrg * \return zero on success, or a negative value on failure.
2699fe517fc9Smrg *
270022944501Smrg * \internal
270122944501Smrg * This function is a wrapper around the DRM_IOCTL_CONTROL ioctl, passing the
270222944501Smrg * argument in a drm_control structure.
270322944501Smrg */
27046260e5d5Smrgdrm_public int drmCtlUninstHandler(int fd)
270522944501Smrg{
270622944501Smrg    drm_control_t ctl;
270722944501Smrg
2708424e9256Smrg    memclear(ctl);
270922944501Smrg    ctl.func  = DRM_UNINST_HANDLER;
271022944501Smrg    ctl.irq   = 0;
271122944501Smrg    if (drmIoctl(fd, DRM_IOCTL_CONTROL, &ctl))
2712fe517fc9Smrg        return -errno;
271322944501Smrg    return 0;
271422944501Smrg}
271522944501Smrg
27166260e5d5Smrgdrm_public int drmFinish(int fd, int context, drmLockFlags flags)
271722944501Smrg{
271822944501Smrg    drm_lock_t lock;
271922944501Smrg
2720424e9256Smrg    memclear(lock);
272122944501Smrg    lock.context = context;
272222944501Smrg    if (flags & DRM_LOCK_READY)      lock.flags |= _DRM_LOCK_READY;
272322944501Smrg    if (flags & DRM_LOCK_QUIESCENT)  lock.flags |= _DRM_LOCK_QUIESCENT;
272422944501Smrg    if (flags & DRM_LOCK_FLUSH)      lock.flags |= _DRM_LOCK_FLUSH;
272522944501Smrg    if (flags & DRM_LOCK_FLUSH_ALL)  lock.flags |= _DRM_LOCK_FLUSH_ALL;
272622944501Smrg    if (flags & DRM_HALT_ALL_QUEUES) lock.flags |= _DRM_HALT_ALL_QUEUES;
272722944501Smrg    if (flags & DRM_HALT_CUR_QUEUES) lock.flags |= _DRM_HALT_CUR_QUEUES;
272822944501Smrg    if (drmIoctl(fd, DRM_IOCTL_FINISH, &lock))
2729fe517fc9Smrg        return -errno;
273022944501Smrg    return 0;
273122944501Smrg}
273222944501Smrg
273322944501Smrg/**
273422944501Smrg * Get IRQ from bus ID.
273522944501Smrg *
273622944501Smrg * \param fd file descriptor.
273722944501Smrg * \param busnum bus number.
273822944501Smrg * \param devnum device number.
273922944501Smrg * \param funcnum function number.
2740fe517fc9Smrg *
274122944501Smrg * \return IRQ number on success, or a negative value on failure.
2742fe517fc9Smrg *
274322944501Smrg * \internal
274422944501Smrg * This function is a wrapper around the DRM_IOCTL_IRQ_BUSID ioctl, passing the
274522944501Smrg * arguments in a drm_irq_busid structure.
274622944501Smrg */
27476260e5d5Smrgdrm_public int drmGetInterruptFromBusID(int fd, int busnum, int devnum,
27486260e5d5Smrg                                        int funcnum)
274922944501Smrg{
275022944501Smrg    drm_irq_busid_t p;
275122944501Smrg
2752424e9256Smrg    memclear(p);
275322944501Smrg    p.busnum  = busnum;
275422944501Smrg    p.devnum  = devnum;
275522944501Smrg    p.funcnum = funcnum;
275622944501Smrg    if (drmIoctl(fd, DRM_IOCTL_IRQ_BUSID, &p))
2757fe517fc9Smrg        return -errno;
275822944501Smrg    return p.irq;
275922944501Smrg}
276022944501Smrg
27616260e5d5Smrgdrm_public int drmAddContextTag(int fd, drm_context_t context, void *tag)
276222944501Smrg{
276322944501Smrg    drmHashEntry  *entry = drmGetEntry(fd);
276422944501Smrg
276522944501Smrg    if (drmHashInsert(entry->tagTable, context, tag)) {
2766fe517fc9Smrg        drmHashDelete(entry->tagTable, context);
2767fe517fc9Smrg        drmHashInsert(entry->tagTable, context, tag);
276822944501Smrg    }
276922944501Smrg    return 0;
277022944501Smrg}
277122944501Smrg
27726260e5d5Smrgdrm_public int drmDelContextTag(int fd, drm_context_t context)
277322944501Smrg{
277422944501Smrg    drmHashEntry  *entry = drmGetEntry(fd);
277522944501Smrg
277622944501Smrg    return drmHashDelete(entry->tagTable, context);
277722944501Smrg}
277822944501Smrg
27796260e5d5Smrgdrm_public void *drmGetContextTag(int fd, drm_context_t context)
278022944501Smrg{
278122944501Smrg    drmHashEntry  *entry = drmGetEntry(fd);
278222944501Smrg    void          *value;
278322944501Smrg
278422944501Smrg    if (drmHashLookup(entry->tagTable, context, &value))
2785fe517fc9Smrg        return NULL;
278622944501Smrg
278722944501Smrg    return value;
278822944501Smrg}
278922944501Smrg
27906260e5d5Smrgdrm_public int drmAddContextPrivateMapping(int fd, drm_context_t ctx_id,
27916260e5d5Smrg                                           drm_handle_t handle)
279222944501Smrg{
279322944501Smrg    drm_ctx_priv_map_t map;
279422944501Smrg
2795424e9256Smrg    memclear(map);
279622944501Smrg    map.ctx_id = ctx_id;
279720131375Smrg    map.handle = (void *)(uintptr_t)handle;
279822944501Smrg
279922944501Smrg    if (drmIoctl(fd, DRM_IOCTL_SET_SAREA_CTX, &map))
2800fe517fc9Smrg        return -errno;
280122944501Smrg    return 0;
280222944501Smrg}
280322944501Smrg
28046260e5d5Smrgdrm_public int drmGetContextPrivateMapping(int fd, drm_context_t ctx_id,
28056260e5d5Smrg                                           drm_handle_t *handle)
280622944501Smrg{
280722944501Smrg    drm_ctx_priv_map_t map;
280822944501Smrg
2809424e9256Smrg    memclear(map);
281022944501Smrg    map.ctx_id = ctx_id;
281122944501Smrg
281222944501Smrg    if (drmIoctl(fd, DRM_IOCTL_GET_SAREA_CTX, &map))
2813fe517fc9Smrg        return -errno;
281422944501Smrg    if (handle)
2815fe517fc9Smrg        *handle = (drm_handle_t)(uintptr_t)map.handle;
281622944501Smrg
281722944501Smrg    return 0;
281822944501Smrg}
281922944501Smrg
28206260e5d5Smrgdrm_public int drmGetMap(int fd, int idx, drm_handle_t *offset, drmSize *size,
28216260e5d5Smrg                         drmMapType *type, drmMapFlags *flags,
28226260e5d5Smrg                         drm_handle_t *handle, int *mtrr)
282322944501Smrg{
282422944501Smrg    drm_map_t map;
282522944501Smrg
2826424e9256Smrg    memclear(map);
282722944501Smrg    map.offset = idx;
282822944501Smrg    if (drmIoctl(fd, DRM_IOCTL_GET_MAP, &map))
2829fe517fc9Smrg        return -errno;
283022944501Smrg    *offset = map.offset;
283122944501Smrg    *size   = map.size;
2832adfa0b0cSmrg    *type   = (drmMapType)map.type;
2833adfa0b0cSmrg    *flags  = (drmMapFlags)map.flags;
283422944501Smrg    *handle = (unsigned long)map.handle;
283522944501Smrg    *mtrr   = map.mtrr;
283622944501Smrg    return 0;
283722944501Smrg}
283822944501Smrg
28396260e5d5Smrgdrm_public int drmGetClient(int fd, int idx, int *auth, int *pid, int *uid,
28406260e5d5Smrg                            unsigned long *magic, unsigned long *iocs)
284122944501Smrg{
284222944501Smrg    drm_client_t client;
284322944501Smrg
2844424e9256Smrg    memclear(client);
284522944501Smrg    client.idx = idx;
284622944501Smrg    if (drmIoctl(fd, DRM_IOCTL_GET_CLIENT, &client))
2847fe517fc9Smrg        return -errno;
284822944501Smrg    *auth      = client.auth;
284922944501Smrg    *pid       = client.pid;
285022944501Smrg    *uid       = client.uid;
285122944501Smrg    *magic     = client.magic;
285222944501Smrg    *iocs      = client.iocs;
285322944501Smrg    return 0;
285422944501Smrg}
285522944501Smrg
28566260e5d5Smrgdrm_public int drmGetStats(int fd, drmStatsT *stats)
285722944501Smrg{
285822944501Smrg    drm_stats_t s;
2859424e9256Smrg    unsigned    i;
286022944501Smrg
2861424e9256Smrg    memclear(s);
286222944501Smrg    if (drmIoctl(fd, DRM_IOCTL_GET_STATS, &s))
2863fe517fc9Smrg        return -errno;
286422944501Smrg
286522944501Smrg    stats->count = 0;
286622944501Smrg    memset(stats, 0, sizeof(*stats));
286722944501Smrg    if (s.count > sizeof(stats->data)/sizeof(stats->data[0]))
2868fe517fc9Smrg        return -1;
286922944501Smrg
287022944501Smrg#define SET_VALUE                              \
287122944501Smrg    stats->data[i].long_format = "%-20.20s";   \
287222944501Smrg    stats->data[i].rate_format = "%8.8s";      \
287322944501Smrg    stats->data[i].isvalue     = 1;            \
287422944501Smrg    stats->data[i].verbose     = 0
287522944501Smrg
287622944501Smrg#define SET_COUNT                              \
287722944501Smrg    stats->data[i].long_format = "%-20.20s";   \
287822944501Smrg    stats->data[i].rate_format = "%5.5s";      \
287922944501Smrg    stats->data[i].isvalue     = 0;            \
288022944501Smrg    stats->data[i].mult_names  = "kgm";        \
288122944501Smrg    stats->data[i].mult        = 1000;         \
288222944501Smrg    stats->data[i].verbose     = 0
288322944501Smrg
288422944501Smrg#define SET_BYTE                               \
288522944501Smrg    stats->data[i].long_format = "%-20.20s";   \
288622944501Smrg    stats->data[i].rate_format = "%5.5s";      \
288722944501Smrg    stats->data[i].isvalue     = 0;            \
288822944501Smrg    stats->data[i].mult_names  = "KGM";        \
288922944501Smrg    stats->data[i].mult        = 1024;         \
289022944501Smrg    stats->data[i].verbose     = 0
289122944501Smrg
289222944501Smrg
289322944501Smrg    stats->count = s.count;
289422944501Smrg    for (i = 0; i < s.count; i++) {
2895fe517fc9Smrg        stats->data[i].value = s.data[i].value;
2896fe517fc9Smrg        switch (s.data[i].type) {
2897fe517fc9Smrg        case _DRM_STAT_LOCK:
2898fe517fc9Smrg            stats->data[i].long_name = "Lock";
2899fe517fc9Smrg            stats->data[i].rate_name = "Lock";
2900fe517fc9Smrg            SET_VALUE;
2901fe517fc9Smrg            break;
2902fe517fc9Smrg        case _DRM_STAT_OPENS:
2903fe517fc9Smrg            stats->data[i].long_name = "Opens";
2904fe517fc9Smrg            stats->data[i].rate_name = "O";
2905fe517fc9Smrg            SET_COUNT;
2906fe517fc9Smrg            stats->data[i].verbose   = 1;
2907fe517fc9Smrg            break;
2908fe517fc9Smrg        case _DRM_STAT_CLOSES:
2909fe517fc9Smrg            stats->data[i].long_name = "Closes";
2910fe517fc9Smrg            stats->data[i].rate_name = "Lock";
2911fe517fc9Smrg            SET_COUNT;
2912fe517fc9Smrg            stats->data[i].verbose   = 1;
2913fe517fc9Smrg            break;
2914fe517fc9Smrg        case _DRM_STAT_IOCTLS:
2915fe517fc9Smrg            stats->data[i].long_name = "Ioctls";
2916fe517fc9Smrg            stats->data[i].rate_name = "Ioc/s";
2917fe517fc9Smrg            SET_COUNT;
2918fe517fc9Smrg            break;
2919fe517fc9Smrg        case _DRM_STAT_LOCKS:
2920fe517fc9Smrg            stats->data[i].long_name = "Locks";
2921fe517fc9Smrg            stats->data[i].rate_name = "Lck/s";
2922fe517fc9Smrg            SET_COUNT;
2923fe517fc9Smrg            break;
2924fe517fc9Smrg        case _DRM_STAT_UNLOCKS:
2925fe517fc9Smrg            stats->data[i].long_name = "Unlocks";
2926fe517fc9Smrg            stats->data[i].rate_name = "Unl/s";
2927fe517fc9Smrg            SET_COUNT;
2928fe517fc9Smrg            break;
2929fe517fc9Smrg        case _DRM_STAT_IRQ:
2930fe517fc9Smrg            stats->data[i].long_name = "IRQs";
2931fe517fc9Smrg            stats->data[i].rate_name = "IRQ/s";
2932fe517fc9Smrg            SET_COUNT;
2933fe517fc9Smrg            break;
2934fe517fc9Smrg        case _DRM_STAT_PRIMARY:
2935fe517fc9Smrg            stats->data[i].long_name = "Primary Bytes";
2936fe517fc9Smrg            stats->data[i].rate_name = "PB/s";
2937fe517fc9Smrg            SET_BYTE;
2938fe517fc9Smrg            break;
2939fe517fc9Smrg        case _DRM_STAT_SECONDARY:
2940fe517fc9Smrg            stats->data[i].long_name = "Secondary Bytes";
2941fe517fc9Smrg            stats->data[i].rate_name = "SB/s";
2942fe517fc9Smrg            SET_BYTE;
2943fe517fc9Smrg            break;
2944fe517fc9Smrg        case _DRM_STAT_DMA:
2945fe517fc9Smrg            stats->data[i].long_name = "DMA";
2946fe517fc9Smrg            stats->data[i].rate_name = "DMA/s";
2947fe517fc9Smrg            SET_COUNT;
2948fe517fc9Smrg            break;
2949fe517fc9Smrg        case _DRM_STAT_SPECIAL:
2950fe517fc9Smrg            stats->data[i].long_name = "Special DMA";
2951fe517fc9Smrg            stats->data[i].rate_name = "dma/s";
2952fe517fc9Smrg            SET_COUNT;
2953fe517fc9Smrg            break;
2954fe517fc9Smrg        case _DRM_STAT_MISSED:
2955fe517fc9Smrg            stats->data[i].long_name = "Miss";
2956fe517fc9Smrg            stats->data[i].rate_name = "Ms/s";
2957fe517fc9Smrg            SET_COUNT;
2958fe517fc9Smrg            break;
2959fe517fc9Smrg        case _DRM_STAT_VALUE:
2960fe517fc9Smrg            stats->data[i].long_name = "Value";
2961fe517fc9Smrg            stats->data[i].rate_name = "Value";
2962fe517fc9Smrg            SET_VALUE;
2963fe517fc9Smrg            break;
2964fe517fc9Smrg        case _DRM_STAT_BYTE:
2965fe517fc9Smrg            stats->data[i].long_name = "Bytes";
2966fe517fc9Smrg            stats->data[i].rate_name = "B/s";
2967fe517fc9Smrg            SET_BYTE;
2968fe517fc9Smrg            break;
2969fe517fc9Smrg        case _DRM_STAT_COUNT:
2970fe517fc9Smrg        default:
2971fe517fc9Smrg            stats->data[i].long_name = "Count";
2972fe517fc9Smrg            stats->data[i].rate_name = "Cnt/s";
2973fe517fc9Smrg            SET_COUNT;
2974fe517fc9Smrg            break;
2975fe517fc9Smrg        }
297622944501Smrg    }
297722944501Smrg    return 0;
297822944501Smrg}
297922944501Smrg
298022944501Smrg/**
298122944501Smrg * Issue a set-version ioctl.
298222944501Smrg *
298322944501Smrg * \param fd file descriptor.
2984fe517fc9Smrg * \param drmCommandIndex command index
298522944501Smrg * \param data source pointer of the data to be read and written.
298622944501Smrg * \param size size of the data to be read and written.
2987fe517fc9Smrg *
298822944501Smrg * \return zero on success, or a negative value on failure.
2989fe517fc9Smrg *
299022944501Smrg * \internal
2991fe517fc9Smrg * It issues a read-write ioctl given by
299222944501Smrg * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
299322944501Smrg */
29946260e5d5Smrgdrm_public int drmSetInterfaceVersion(int fd, drmSetVersion *version)
299522944501Smrg{
299622944501Smrg    int retcode = 0;
299722944501Smrg    drm_set_version_t sv;
299822944501Smrg
2999424e9256Smrg    memclear(sv);
300022944501Smrg    sv.drm_di_major = version->drm_di_major;
300122944501Smrg    sv.drm_di_minor = version->drm_di_minor;
300222944501Smrg    sv.drm_dd_major = version->drm_dd_major;
300322944501Smrg    sv.drm_dd_minor = version->drm_dd_minor;
300422944501Smrg
300522944501Smrg    if (drmIoctl(fd, DRM_IOCTL_SET_VERSION, &sv)) {
3006fe517fc9Smrg        retcode = -errno;
300722944501Smrg    }
300822944501Smrg
300922944501Smrg    version->drm_di_major = sv.drm_di_major;
301022944501Smrg    version->drm_di_minor = sv.drm_di_minor;
301122944501Smrg    version->drm_dd_major = sv.drm_dd_major;
301222944501Smrg    version->drm_dd_minor = sv.drm_dd_minor;
301322944501Smrg
301422944501Smrg    return retcode;
301522944501Smrg}
301622944501Smrg
301722944501Smrg/**
301822944501Smrg * Send a device-specific command.
301922944501Smrg *
302022944501Smrg * \param fd file descriptor.
3021fe517fc9Smrg * \param drmCommandIndex command index
3022fe517fc9Smrg *
302322944501Smrg * \return zero on success, or a negative value on failure.
3024fe517fc9Smrg *
302522944501Smrg * \internal
3026fe517fc9Smrg * It issues a ioctl given by
302722944501Smrg * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
302822944501Smrg */
30296260e5d5Smrgdrm_public int drmCommandNone(int fd, unsigned long drmCommandIndex)
303022944501Smrg{
303122944501Smrg    unsigned long request;
303222944501Smrg
303322944501Smrg    request = DRM_IO( DRM_COMMAND_BASE + drmCommandIndex);
303422944501Smrg
3035424e9256Smrg    if (drmIoctl(fd, request, NULL)) {
3036fe517fc9Smrg        return -errno;
303722944501Smrg    }
303822944501Smrg    return 0;
303922944501Smrg}
304022944501Smrg
304122944501Smrg
304222944501Smrg/**
304322944501Smrg * Send a device-specific read command.
304422944501Smrg *
304522944501Smrg * \param fd file descriptor.
3046fe517fc9Smrg * \param drmCommandIndex command index
304722944501Smrg * \param data destination pointer of the data to be read.
304822944501Smrg * \param size size of the data to be read.
3049fe517fc9Smrg *
305022944501Smrg * \return zero on success, or a negative value on failure.
305122944501Smrg *
305222944501Smrg * \internal
3053fe517fc9Smrg * It issues a read ioctl given by
305422944501Smrg * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
305522944501Smrg */
30566260e5d5Smrgdrm_public int drmCommandRead(int fd, unsigned long drmCommandIndex,
30576260e5d5Smrg                              void *data, unsigned long size)
305822944501Smrg{
305922944501Smrg    unsigned long request;
306022944501Smrg
3061fe517fc9Smrg    request = DRM_IOC( DRM_IOC_READ, DRM_IOCTL_BASE,
3062fe517fc9Smrg        DRM_COMMAND_BASE + drmCommandIndex, size);
306322944501Smrg
306422944501Smrg    if (drmIoctl(fd, request, data)) {
3065fe517fc9Smrg        return -errno;
306622944501Smrg    }
306722944501Smrg    return 0;
306822944501Smrg}
306922944501Smrg
307022944501Smrg
307122944501Smrg/**
307222944501Smrg * Send a device-specific write command.
307322944501Smrg *
307422944501Smrg * \param fd file descriptor.
3075fe517fc9Smrg * \param drmCommandIndex command index
307622944501Smrg * \param data source pointer of the data to be written.
307722944501Smrg * \param size size of the data to be written.
3078fe517fc9Smrg *
307922944501Smrg * \return zero on success, or a negative value on failure.
3080fe517fc9Smrg *
308122944501Smrg * \internal
3082fe517fc9Smrg * It issues a write ioctl given by
308322944501Smrg * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
308422944501Smrg */
30856260e5d5Smrgdrm_public int drmCommandWrite(int fd, unsigned long drmCommandIndex,
30866260e5d5Smrg                               void *data, unsigned long size)
308722944501Smrg{
308822944501Smrg    unsigned long request;
308922944501Smrg
3090fe517fc9Smrg    request = DRM_IOC( DRM_IOC_WRITE, DRM_IOCTL_BASE,
3091fe517fc9Smrg        DRM_COMMAND_BASE + drmCommandIndex, size);
309222944501Smrg
309322944501Smrg    if (drmIoctl(fd, request, data)) {
3094fe517fc9Smrg        return -errno;
309522944501Smrg    }
309622944501Smrg    return 0;
309722944501Smrg}
309822944501Smrg
309922944501Smrg
310022944501Smrg/**
310122944501Smrg * Send a device-specific read-write command.
310222944501Smrg *
310322944501Smrg * \param fd file descriptor.
3104fe517fc9Smrg * \param drmCommandIndex command index
310522944501Smrg * \param data source pointer of the data to be read and written.
310622944501Smrg * \param size size of the data to be read and written.
3107fe517fc9Smrg *
310822944501Smrg * \return zero on success, or a negative value on failure.
3109fe517fc9Smrg *
311022944501Smrg * \internal
3111fe517fc9Smrg * It issues a read-write ioctl given by
311222944501Smrg * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
311322944501Smrg */
31146260e5d5Smrgdrm_public int drmCommandWriteRead(int fd, unsigned long drmCommandIndex,
31156260e5d5Smrg                                   void *data, unsigned long size)
311622944501Smrg{
311722944501Smrg    unsigned long request;
311822944501Smrg
3119fe517fc9Smrg    request = DRM_IOC( DRM_IOC_READ|DRM_IOC_WRITE, DRM_IOCTL_BASE,
3120fe517fc9Smrg        DRM_COMMAND_BASE + drmCommandIndex, size);
312122944501Smrg
312222944501Smrg    if (drmIoctl(fd, request, data))
3123fe517fc9Smrg        return -errno;
312422944501Smrg    return 0;
312522944501Smrg}
312622944501Smrg
312722944501Smrg#define DRM_MAX_FDS 16
312822944501Smrgstatic struct {
312922944501Smrg    char *BusID;
313022944501Smrg    int fd;
313122944501Smrg    int refcount;
3132424e9256Smrg    int type;
313322944501Smrg} connection[DRM_MAX_FDS];
313422944501Smrg
313522944501Smrgstatic int nr_fds = 0;
313622944501Smrg
31376260e5d5Smrgdrm_public int drmOpenOnce(void *unused, const char *BusID, int *newlyopened)
3138424e9256Smrg{
3139424e9256Smrg    return drmOpenOnceWithType(BusID, newlyopened, DRM_NODE_PRIMARY);
3140424e9256Smrg}
3141424e9256Smrg
31426260e5d5Smrgdrm_public int drmOpenOnceWithType(const char *BusID, int *newlyopened,
31436260e5d5Smrg                                   int type)
314422944501Smrg{
314522944501Smrg    int i;
314622944501Smrg    int fd;
3147fe517fc9Smrg
314822944501Smrg    for (i = 0; i < nr_fds; i++)
3149fe517fc9Smrg        if ((strcmp(BusID, connection[i].BusID) == 0) &&
3150fe517fc9Smrg            (connection[i].type == type)) {
3151fe517fc9Smrg            connection[i].refcount++;
3152fe517fc9Smrg            *newlyopened = 0;
3153fe517fc9Smrg            return connection[i].fd;
3154fe517fc9Smrg        }
315522944501Smrg
3156424e9256Smrg    fd = drmOpenWithType(NULL, BusID, type);
3157fe517fc9Smrg    if (fd < 0 || nr_fds == DRM_MAX_FDS)
3158fe517fc9Smrg        return fd;
3159fe517fc9Smrg
316022944501Smrg    connection[nr_fds].BusID = strdup(BusID);
316122944501Smrg    connection[nr_fds].fd = fd;
316222944501Smrg    connection[nr_fds].refcount = 1;
3163424e9256Smrg    connection[nr_fds].type = type;
316422944501Smrg    *newlyopened = 1;
316522944501Smrg
316622944501Smrg    if (0)
3167fe517fc9Smrg        fprintf(stderr, "saved connection %d for %s %d\n",
3168fe517fc9Smrg                nr_fds, connection[nr_fds].BusID,
3169fe517fc9Smrg                strcmp(BusID, connection[nr_fds].BusID));
317022944501Smrg
317122944501Smrg    nr_fds++;
317222944501Smrg
317322944501Smrg    return fd;
317422944501Smrg}
317522944501Smrg
31766260e5d5Smrgdrm_public void drmCloseOnce(int fd)
317722944501Smrg{
317822944501Smrg    int i;
317922944501Smrg
318022944501Smrg    for (i = 0; i < nr_fds; i++) {
3181fe517fc9Smrg        if (fd == connection[i].fd) {
3182fe517fc9Smrg            if (--connection[i].refcount == 0) {
3183fe517fc9Smrg                drmClose(connection[i].fd);
3184fe517fc9Smrg                free(connection[i].BusID);
3185fe517fc9Smrg
3186fe517fc9Smrg                if (i < --nr_fds)
3187fe517fc9Smrg                    connection[i] = connection[nr_fds];
3188fe517fc9Smrg
3189fe517fc9Smrg                return;
3190fe517fc9Smrg            }
3191fe517fc9Smrg        }
319222944501Smrg    }
319322944501Smrg}
319422944501Smrg
31956260e5d5Smrgdrm_public int drmSetMaster(int fd)
319622944501Smrg{
3197fe517fc9Smrg        return drmIoctl(fd, DRM_IOCTL_SET_MASTER, NULL);
319822944501Smrg}
319922944501Smrg
32006260e5d5Smrgdrm_public int drmDropMaster(int fd)
320122944501Smrg{
3202fe517fc9Smrg        return drmIoctl(fd, DRM_IOCTL_DROP_MASTER, NULL);
320322944501Smrg}
320422944501Smrg
3205bf6cc7dcSmrgdrm_public int drmIsMaster(int fd)
3206bf6cc7dcSmrg{
3207bf6cc7dcSmrg        /* Detect master by attempting something that requires master.
3208bf6cc7dcSmrg         *
3209bf6cc7dcSmrg         * Authenticating magic tokens requires master and 0 is an
3210bf6cc7dcSmrg         * internal kernel detail which we could use. Attempting this on
3211bf6cc7dcSmrg         * a master fd would fail therefore fail with EINVAL because 0
3212bf6cc7dcSmrg         * is invalid.
3213bf6cc7dcSmrg         *
3214bf6cc7dcSmrg         * A non-master fd will fail with EACCES, as the kernel checks
3215bf6cc7dcSmrg         * for master before attempting to do anything else.
3216bf6cc7dcSmrg         *
3217bf6cc7dcSmrg         * Since we don't want to leak implementation details, use
3218bf6cc7dcSmrg         * EACCES.
3219bf6cc7dcSmrg         */
3220bf6cc7dcSmrg        return drmAuthMagic(fd, 0) != -EACCES;
3221bf6cc7dcSmrg}
3222bf6cc7dcSmrg
32236260e5d5Smrgdrm_public char *drmGetDeviceNameFromFd(int fd)
322422944501Smrg{
322587bf8e7cSmrg#ifdef __FreeBSD__
322687bf8e7cSmrg    struct stat sbuf;
322787bf8e7cSmrg    int maj, min;
322887bf8e7cSmrg    int nodetype;
322987bf8e7cSmrg
323087bf8e7cSmrg    if (fstat(fd, &sbuf))
323187bf8e7cSmrg        return NULL;
323287bf8e7cSmrg
323387bf8e7cSmrg    maj = major(sbuf.st_rdev);
323487bf8e7cSmrg    min = minor(sbuf.st_rdev);
323587bf8e7cSmrg    nodetype = drmGetMinorType(maj, min);
323687bf8e7cSmrg    return drmGetMinorNameForFD(fd, nodetype);
323787bf8e7cSmrg#else
3238fe517fc9Smrg    char name[128];
3239fe517fc9Smrg    struct stat sbuf;
3240fe517fc9Smrg    dev_t d;
3241fe517fc9Smrg    int i;
324222944501Smrg
3243fe517fc9Smrg    /* The whole drmOpen thing is a fiasco and we need to find a way
3244fe517fc9Smrg     * back to just using open(2).  For now, however, lets just make
3245fe517fc9Smrg     * things worse with even more ad hoc directory walking code to
3246fe517fc9Smrg     * discover the device file name. */
324722944501Smrg
3248fe517fc9Smrg    fstat(fd, &sbuf);
3249fe517fc9Smrg    d = sbuf.st_rdev;
325022944501Smrg
3251fe517fc9Smrg    for (i = 0; i < DRM_MAX_MINOR; i++) {
3252fe517fc9Smrg        snprintf(name, sizeof name, DRM_DEV_NAME, DRM_DIR_NAME, i);
3253fe517fc9Smrg        if (stat(name, &sbuf) == 0 && sbuf.st_rdev == d)
3254fe517fc9Smrg            break;
3255fe517fc9Smrg    }
3256fe517fc9Smrg    if (i == DRM_MAX_MINOR)
3257fe517fc9Smrg        return NULL;
325822944501Smrg
3259fe517fc9Smrg    return strdup(name);
326087bf8e7cSmrg#endif
326122944501Smrg}
326220131375Smrg
32636260e5d5Smrgstatic bool drmNodeIsDRM(int maj, int min)
32646260e5d5Smrg{
32656260e5d5Smrg#ifdef __linux__
32666260e5d5Smrg    char path[64];
32676260e5d5Smrg    struct stat sbuf;
32686260e5d5Smrg
32696260e5d5Smrg    snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device/drm",
32706260e5d5Smrg             maj, min);
32716260e5d5Smrg    return stat(path, &sbuf) == 0;
32724b3d3f37Smrg#elif defined(__FreeBSD__)
327387bf8e7cSmrg    char name[SPECNAMELEN];
327487bf8e7cSmrg
327587bf8e7cSmrg    if (!devname_r(makedev(maj, min), S_IFCHR, name, sizeof(name)))
327687bf8e7cSmrg      return 0;
327787bf8e7cSmrg    /* Handle drm/ and dri/ as both are present in different FreeBSD version
327887bf8e7cSmrg     * FreeBSD on amd64/i386/powerpc external kernel modules create node in
327987bf8e7cSmrg     * in /dev/drm/ and links in /dev/dri while a WIP in kernel driver creates
328087bf8e7cSmrg     * only device nodes in /dev/dri/ */
328187bf8e7cSmrg    return (!strncmp(name, "drm/", 4) || !strncmp(name, "dri/", 4));
32826260e5d5Smrg#else
32836260e5d5Smrg    return maj == DRM_MAJOR;
32846260e5d5Smrg#endif
32856260e5d5Smrg}
32866260e5d5Smrg
32876260e5d5Smrgdrm_public int drmGetNodeTypeFromFd(int fd)
3288424e9256Smrg{
3289fe517fc9Smrg    struct stat sbuf;
3290fe517fc9Smrg    int maj, min, type;
3291424e9256Smrg
3292fe517fc9Smrg    if (fstat(fd, &sbuf))
3293fe517fc9Smrg        return -1;
3294424e9256Smrg
3295fe517fc9Smrg    maj = major(sbuf.st_rdev);
3296fe517fc9Smrg    min = minor(sbuf.st_rdev);
3297424e9256Smrg
32986260e5d5Smrg    if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode)) {
3299fe517fc9Smrg        errno = EINVAL;
3300fe517fc9Smrg        return -1;
3301fe517fc9Smrg    }
3302424e9256Smrg
330387bf8e7cSmrg    type = drmGetMinorType(maj, min);
3304fe517fc9Smrg    if (type == -1)
3305fe517fc9Smrg        errno = ENODEV;
3306fe517fc9Smrg    return type;
3307424e9256Smrg}
3308424e9256Smrg
33096260e5d5Smrgdrm_public int drmPrimeHandleToFD(int fd, uint32_t handle, uint32_t flags,
33106260e5d5Smrg                                  int *prime_fd)
331120131375Smrg{
3312fe517fc9Smrg    struct drm_prime_handle args;
3313fe517fc9Smrg    int ret;
331420131375Smrg
3315fe517fc9Smrg    memclear(args);
3316fe517fc9Smrg    args.fd = -1;
3317fe517fc9Smrg    args.handle = handle;
3318fe517fc9Smrg    args.flags = flags;
3319fe517fc9Smrg    ret = drmIoctl(fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &args);
3320fe517fc9Smrg    if (ret)
3321fe517fc9Smrg        return ret;
332220131375Smrg
3323fe517fc9Smrg    *prime_fd = args.fd;
3324fe517fc9Smrg    return 0;
332520131375Smrg}
332620131375Smrg
33276260e5d5Smrgdrm_public int drmPrimeFDToHandle(int fd, int prime_fd, uint32_t *handle)
332820131375Smrg{
3329fe517fc9Smrg    struct drm_prime_handle args;
3330fe517fc9Smrg    int ret;
333120131375Smrg
3332fe517fc9Smrg    memclear(args);
3333fe517fc9Smrg    args.fd = prime_fd;
3334fe517fc9Smrg    ret = drmIoctl(fd, DRM_IOCTL_PRIME_FD_TO_HANDLE, &args);
3335fe517fc9Smrg    if (ret)
3336fe517fc9Smrg        return ret;
333720131375Smrg
3338fe517fc9Smrg    *handle = args.handle;
3339fe517fc9Smrg    return 0;
334020131375Smrg}
3341424e9256Smrg
3342adfa0b0cSmrgdrm_public int drmCloseBufferHandle(int fd, uint32_t handle)
3343adfa0b0cSmrg{
3344adfa0b0cSmrg    struct drm_gem_close args;
3345adfa0b0cSmrg
3346adfa0b0cSmrg    memclear(args);
3347adfa0b0cSmrg    args.handle = handle;
3348adfa0b0cSmrg    return drmIoctl(fd, DRM_IOCTL_GEM_CLOSE, &args);
3349adfa0b0cSmrg}
3350adfa0b0cSmrg
3351424e9256Smrgstatic char *drmGetMinorNameForFD(int fd, int type)
3352424e9256Smrg{
3353424e9256Smrg#ifdef __linux__
3354fe517fc9Smrg    DIR *sysdir;
33556260e5d5Smrg    struct dirent *ent;
3356fe517fc9Smrg    struct stat sbuf;
3357fe517fc9Smrg    const char *name = drmGetMinorName(type);
3358fe517fc9Smrg    int len;
3359fe517fc9Smrg    char dev_name[64], buf[64];
3360fe517fc9Smrg    int maj, min;
3361fe517fc9Smrg
3362fe517fc9Smrg    if (!name)
3363fe517fc9Smrg        return NULL;
3364424e9256Smrg
3365fe517fc9Smrg    len = strlen(name);
3366424e9256Smrg
3367fe517fc9Smrg    if (fstat(fd, &sbuf))
3368fe517fc9Smrg        return NULL;
3369424e9256Smrg
3370fe517fc9Smrg    maj = major(sbuf.st_rdev);
3371fe517fc9Smrg    min = minor(sbuf.st_rdev);
3372424e9256Smrg
33736260e5d5Smrg    if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode))
3374fe517fc9Smrg        return NULL;
3375424e9256Smrg
3376fe517fc9Smrg    snprintf(buf, sizeof(buf), "/sys/dev/char/%d:%d/device/drm", maj, min);
3377424e9256Smrg
3378fe517fc9Smrg    sysdir = opendir(buf);
3379fe517fc9Smrg    if (!sysdir)
3380fe517fc9Smrg        return NULL;
3381424e9256Smrg
33826260e5d5Smrg    while ((ent = readdir(sysdir))) {
3383fe517fc9Smrg        if (strncmp(ent->d_name, name, len) == 0) {
3384adfa0b0cSmrg            if (snprintf(dev_name, sizeof(dev_name), DRM_DIR_NAME "/%s",
3385adfa0b0cSmrg                        ent->d_name) < 0)
3386adfa0b0cSmrg                return NULL;
3387424e9256Smrg
3388fe517fc9Smrg            closedir(sysdir);
3389fe517fc9Smrg            return strdup(dev_name);
3390fe517fc9Smrg        }
3391fe517fc9Smrg    }
3392424e9256Smrg
3393fe517fc9Smrg    closedir(sysdir);
33946260e5d5Smrg    return NULL;
33954b3d3f37Smrg#elif defined(__FreeBSD__)
339687bf8e7cSmrg    struct stat sbuf;
339787bf8e7cSmrg    char dname[SPECNAMELEN];
339887bf8e7cSmrg    const char *mname;
339987bf8e7cSmrg    char name[SPECNAMELEN];
340087bf8e7cSmrg    int id, maj, min, nodetype, i;
340187bf8e7cSmrg
340287bf8e7cSmrg    if (fstat(fd, &sbuf))
340387bf8e7cSmrg        return NULL;
340487bf8e7cSmrg
340587bf8e7cSmrg    maj = major(sbuf.st_rdev);
340687bf8e7cSmrg    min = minor(sbuf.st_rdev);
340787bf8e7cSmrg
340887bf8e7cSmrg    if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode))
340987bf8e7cSmrg        return NULL;
341087bf8e7cSmrg
341187bf8e7cSmrg    if (!devname_r(sbuf.st_rdev, S_IFCHR, dname, sizeof(dname)))
341287bf8e7cSmrg        return NULL;
341387bf8e7cSmrg
341487bf8e7cSmrg    /* Handle both /dev/drm and /dev/dri
341587bf8e7cSmrg     * FreeBSD on amd64/i386/powerpc external kernel modules create node in
341687bf8e7cSmrg     * in /dev/drm/ and links in /dev/dri while a WIP in kernel driver creates
341787bf8e7cSmrg     * only device nodes in /dev/dri/ */
341887bf8e7cSmrg
341987bf8e7cSmrg    /* Get the node type represented by fd so we can deduce the target name */
342087bf8e7cSmrg    nodetype = drmGetMinorType(maj, min);
342187bf8e7cSmrg    if (nodetype == -1)
342287bf8e7cSmrg        return (NULL);
342387bf8e7cSmrg    mname = drmGetMinorName(type);
342487bf8e7cSmrg
342587bf8e7cSmrg    for (i = 0; i < SPECNAMELEN; i++) {
342687bf8e7cSmrg        if (isalpha(dname[i]) == 0 && dname[i] != '/')
342787bf8e7cSmrg           break;
342887bf8e7cSmrg    }
342987bf8e7cSmrg    if (dname[i] == '\0')
343087bf8e7cSmrg        return (NULL);
343187bf8e7cSmrg
343287bf8e7cSmrg    id = (int)strtol(&dname[i], NULL, 10);
343387bf8e7cSmrg    id -= drmGetMinorBase(nodetype);
343487bf8e7cSmrg    snprintf(name, sizeof(name), DRM_DIR_NAME "/%s%d", mname,
343587bf8e7cSmrg         id + drmGetMinorBase(type));
343687bf8e7cSmrg
343787bf8e7cSmrg    return strdup(name);
3438fe517fc9Smrg#else
34392ee35494Smrg    struct stat sbuf;
34402ee35494Smrg    char buf[PATH_MAX + 1];
344182025ec7Smrg    const char *dev_name = drmGetDeviceName(type);
34422ee35494Smrg    unsigned int maj, min;
344382025ec7Smrg    int n;
34442ee35494Smrg
34452ee35494Smrg    if (fstat(fd, &sbuf))
34462ee35494Smrg        return NULL;
34472ee35494Smrg
34482ee35494Smrg    maj = major(sbuf.st_rdev);
34492ee35494Smrg    min = minor(sbuf.st_rdev);
34502ee35494Smrg
34516260e5d5Smrg    if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode))
34522ee35494Smrg        return NULL;
34532ee35494Smrg
345482025ec7Smrg    if (!dev_name)
34552ee35494Smrg        return NULL;
34562ee35494Smrg
345782025ec7Smrg    n = snprintf(buf, sizeof(buf), dev_name, DRM_DIR_NAME, min);
34582ee35494Smrg    if (n == -1 || n >= sizeof(buf))
34592ee35494Smrg        return NULL;
34602ee35494Smrg
34612ee35494Smrg    return strdup(buf);
3462424e9256Smrg#endif
3463424e9256Smrg}
3464424e9256Smrg
34656260e5d5Smrgdrm_public char *drmGetPrimaryDeviceNameFromFd(int fd)
3466424e9256Smrg{
3467fe517fc9Smrg    return drmGetMinorNameForFD(fd, DRM_NODE_PRIMARY);
3468424e9256Smrg}
3469424e9256Smrg
34706260e5d5Smrgdrm_public char *drmGetRenderDeviceNameFromFd(int fd)
3471424e9256Smrg{
3472fe517fc9Smrg    return drmGetMinorNameForFD(fd, DRM_NODE_RENDER);
3473fe517fc9Smrg}
3474fe517fc9Smrg
34752ee35494Smrg#ifdef __linux__
34762ee35494Smrgstatic char * DRM_PRINTFLIKE(2, 3)
34772ee35494Smrgsysfs_uevent_get(const char *path, const char *fmt, ...)
34782ee35494Smrg{
34792ee35494Smrg    char filename[PATH_MAX + 1], *key, *line = NULL, *value = NULL;
34802ee35494Smrg    size_t size = 0, len;
34812ee35494Smrg    ssize_t num;
34822ee35494Smrg    va_list ap;
34832ee35494Smrg    FILE *fp;
34842ee35494Smrg
34852ee35494Smrg    va_start(ap, fmt);
34862ee35494Smrg    num = vasprintf(&key, fmt, ap);
34872ee35494Smrg    va_end(ap);
34882ee35494Smrg    len = num;
34892ee35494Smrg
34902ee35494Smrg    snprintf(filename, sizeof(filename), "%s/uevent", path);
34912ee35494Smrg
34922ee35494Smrg    fp = fopen(filename, "r");
34932ee35494Smrg    if (!fp) {
34942ee35494Smrg        free(key);
34952ee35494Smrg        return NULL;
34962ee35494Smrg    }
34972ee35494Smrg
34982ee35494Smrg    while ((num = getline(&line, &size, fp)) >= 0) {
34992ee35494Smrg        if ((strncmp(line, key, len) == 0) && (line[len] == '=')) {
35002ee35494Smrg            char *start = line + len + 1, *end = line + num - 1;
35012ee35494Smrg
35022ee35494Smrg            if (*end != '\n')
35032ee35494Smrg                end++;
35042ee35494Smrg
35052ee35494Smrg            value = strndup(start, end - start);
35062ee35494Smrg            break;
35072ee35494Smrg        }
35082ee35494Smrg    }
35092ee35494Smrg
35102ee35494Smrg    free(line);
35112ee35494Smrg    fclose(fp);
35122ee35494Smrg
35132ee35494Smrg    free(key);
35142ee35494Smrg
35152ee35494Smrg    return value;
35162ee35494Smrg}
35172ee35494Smrg#endif
35182ee35494Smrg
35196260e5d5Smrg/* Little white lie to avoid major rework of the existing code */
35206260e5d5Smrg#define DRM_BUS_VIRTIO 0x10
35216260e5d5Smrg
3522fe517fc9Smrg#ifdef __linux__
352387bf8e7cSmrgstatic int get_subsystem_type(const char *device_path)
352487bf8e7cSmrg{
352587bf8e7cSmrg    char path[PATH_MAX + 1] = "";
3526fe517fc9Smrg    char link[PATH_MAX + 1] = "";
3527fe517fc9Smrg    char *name;
35284545e80cSmrg    struct {
35294545e80cSmrg        const char *name;
35304545e80cSmrg        int bus_type;
35314545e80cSmrg    } bus_types[] = {
35324545e80cSmrg        { "/pci", DRM_BUS_PCI },
35334545e80cSmrg        { "/usb", DRM_BUS_USB },
35344545e80cSmrg        { "/platform", DRM_BUS_PLATFORM },
35354545e80cSmrg        { "/spi", DRM_BUS_PLATFORM },
35364545e80cSmrg        { "/host1x", DRM_BUS_HOST1X },
35374545e80cSmrg        { "/virtio", DRM_BUS_VIRTIO },
35384545e80cSmrg    };
3539fe517fc9Smrg
354087bf8e7cSmrg    strncpy(path, device_path, PATH_MAX);
354187bf8e7cSmrg    strncat(path, "/subsystem", PATH_MAX);
3542fe517fc9Smrg
3543fe517fc9Smrg    if (readlink(path, link, PATH_MAX) < 0)
3544fe517fc9Smrg        return -errno;
3545fe517fc9Smrg
3546fe517fc9Smrg    name = strrchr(link, '/');
3547fe517fc9Smrg    if (!name)
3548fe517fc9Smrg        return -EINVAL;
3549fe517fc9Smrg
35504545e80cSmrg    for (unsigned i = 0; i < ARRAY_SIZE(bus_types); i++) {
35514545e80cSmrg        if (strncmp(name, bus_types[i].name, strlen(bus_types[i].name)) == 0)
35524545e80cSmrg            return bus_types[i].bus_type;
35534545e80cSmrg    }
35546260e5d5Smrg
3555fe517fc9Smrg    return -EINVAL;
355687bf8e7cSmrg}
355787bf8e7cSmrg#endif
355887bf8e7cSmrg
355987bf8e7cSmrgstatic int drmParseSubsystemType(int maj, int min)
356087bf8e7cSmrg{
356187bf8e7cSmrg#ifdef __linux__
356287bf8e7cSmrg    char path[PATH_MAX + 1] = "";
356387bf8e7cSmrg    char real_path[PATH_MAX + 1] = "";
356487bf8e7cSmrg    int subsystem_type;
356587bf8e7cSmrg
356687bf8e7cSmrg    snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min);
356787bf8e7cSmrg
356887bf8e7cSmrg    subsystem_type = get_subsystem_type(path);
356987bf8e7cSmrg    /* Try to get the parent (underlying) device type */
357087bf8e7cSmrg    if (subsystem_type == DRM_BUS_VIRTIO) {
357187bf8e7cSmrg        /* Assume virtio-pci on error */
357287bf8e7cSmrg        if (!realpath(path, real_path))
357387bf8e7cSmrg            return DRM_BUS_VIRTIO;
357487bf8e7cSmrg        strncat(path, "/..", PATH_MAX);
357587bf8e7cSmrg        subsystem_type = get_subsystem_type(path);
357687bf8e7cSmrg        if (subsystem_type < 0)
357787bf8e7cSmrg            return DRM_BUS_VIRTIO;
357887bf8e7cSmrg     }
3579a970b457Sriastradh#elif defined(__NetBSD__)
3580a970b457Sriastradh    int type, fd;
3581a970b457Sriastradh    drmSetVersion sv;
3582a970b457Sriastradh    char *buf;
3583a970b457Sriastradh    unsigned domain, bus, dev;
3584a970b457Sriastradh    int func;
3585a970b457Sriastradh    int ret;
3586a970b457Sriastradh
3587a970b457Sriastradh    /* Get the type of device we're looking for to pick the right pathname.  */
358877e87e13Smrg    type = drmGetMinorType(maj, min);
3589a970b457Sriastradh    if (type == -1)
3590a970b457Sriastradh	return -ENODEV;
3591a970b457Sriastradh
3592a970b457Sriastradh    /* Open the device.  Don't try to create it if it's not there.  */
3593a970b457Sriastradh    fd = drmOpenMinor(min, 0, type);
3594a970b457Sriastradh    if (fd < 0)
3595a970b457Sriastradh	return -errno;
3596a970b457Sriastradh
3597a970b457Sriastradh    /*
3598a970b457Sriastradh     * Set the interface version to 1.4 or 1.1, which has the effect of
3599a970b457Sriastradh     * populating the bus id for us.
3600a970b457Sriastradh     */
3601a970b457Sriastradh    sv.drm_di_major = 1;
3602a970b457Sriastradh    sv.drm_di_minor = 4;
3603a970b457Sriastradh    sv.drm_dd_major = -1;
3604a970b457Sriastradh    sv.drm_dd_minor = -1;
3605a970b457Sriastradh    if (drmSetInterfaceVersion(fd, &sv)) {
3606a970b457Sriastradh	sv.drm_di_major = 1;
3607a970b457Sriastradh	sv.drm_di_minor = 1;
3608a970b457Sriastradh	sv.drm_dd_major = -1;
3609a970b457Sriastradh	sv.drm_dd_minor = -1;
3610a970b457Sriastradh	if (drmSetInterfaceVersion(fd, &sv)) {
36115046d36bSriastradh	    /*
36125046d36bSriastradh	     * We're probably not the master.  Hope the master already
36135046d36bSriastradh	     * set the version to >=1.1 so that we can get the busid.
36145046d36bSriastradh	     */
3615a970b457Sriastradh	}
3616a970b457Sriastradh    }
3617a970b457Sriastradh
3618a970b457Sriastradh    /* Get the bus id.  */
3619a970b457Sriastradh    buf = drmGetBusid(fd);
3620a970b457Sriastradh
3621a970b457Sriastradh    /* We're done with the device now.  */
3622a970b457Sriastradh    (void)close(fd);
3623a970b457Sriastradh
3624a970b457Sriastradh    /* If there is no bus id, fail.  */
3625a970b457Sriastradh    if (buf == NULL)
3626a970b457Sriastradh	return -ENODEV;
3627a970b457Sriastradh
3628a970b457Sriastradh    /* Find a string we know about; otherwise -EINVAL.  */
3629a970b457Sriastradh    ret = -EINVAL;
363048994cb0Sriastradh    if (strncmp(buf, "pci:", 4) == 0)
3631a970b457Sriastradh	ret = DRM_BUS_PCI;
3632a970b457Sriastradh
3633a970b457Sriastradh    /* We're done with the bus id.  */
3634a970b457Sriastradh    free(buf);
3635a970b457Sriastradh
3636a970b457Sriastradh    /* Success or not, we're done.  */
3637a970b457Sriastradh    return ret;
36384545e80cSmrg#elif defined(__OpenBSD__) || defined(__DragonFly__)
36392ee35494Smrg    return DRM_BUS_PCI;
3640fe517fc9Smrg#else
3641fe517fc9Smrg#warning "Missing implementation of drmParseSubsystemType"
3642fe517fc9Smrg    return -EINVAL;
3643fe517fc9Smrg#endif
3644fe517fc9Smrg}
3645fe517fc9Smrg
364687bf8e7cSmrg#ifdef __linux__
36476260e5d5Smrgstatic void
36486260e5d5Smrgget_pci_path(int maj, int min, char *pci_path)
36496260e5d5Smrg{
36506260e5d5Smrg    char path[PATH_MAX + 1], *term;
36516260e5d5Smrg
36526260e5d5Smrg    snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min);
36536260e5d5Smrg    if (!realpath(path, pci_path)) {
36546260e5d5Smrg        strcpy(pci_path, path);
36556260e5d5Smrg        return;
36566260e5d5Smrg    }
36576260e5d5Smrg
36586260e5d5Smrg    term = strrchr(pci_path, '/');
36596260e5d5Smrg    if (term && strncmp(term, "/virtio", 7) == 0)
36606260e5d5Smrg        *term = 0;
36616260e5d5Smrg}
366287bf8e7cSmrg#endif
366387bf8e7cSmrg
366487bf8e7cSmrg#ifdef __FreeBSD__
366587bf8e7cSmrgstatic int get_sysctl_pci_bus_info(int maj, int min, drmPciBusInfoPtr info)
366687bf8e7cSmrg{
366787bf8e7cSmrg    char dname[SPECNAMELEN];
366887bf8e7cSmrg    char sysctl_name[16];
366987bf8e7cSmrg    char sysctl_val[256];
367087bf8e7cSmrg    size_t sysctl_len;
367187bf8e7cSmrg    int id, type, nelem;
367287bf8e7cSmrg    unsigned int rdev, majmin, domain, bus, dev, func;
367387bf8e7cSmrg
367487bf8e7cSmrg    rdev = makedev(maj, min);
367587bf8e7cSmrg    if (!devname_r(rdev, S_IFCHR, dname, sizeof(dname)))
367687bf8e7cSmrg      return -EINVAL;
367787bf8e7cSmrg
367887bf8e7cSmrg    if (sscanf(dname, "drm/%d\n", &id) != 1)
367987bf8e7cSmrg        return -EINVAL;
368087bf8e7cSmrg    type = drmGetMinorType(maj, min);
368187bf8e7cSmrg    if (type == -1)
368287bf8e7cSmrg        return -EINVAL;
368387bf8e7cSmrg
368487bf8e7cSmrg    /* BUG: This above section is iffy, since it mandates that a driver will
368587bf8e7cSmrg     * create both card and render node.
368687bf8e7cSmrg     * If it does not, the next DRM device will create card#X and
368787bf8e7cSmrg     * renderD#(128+X)-1.
368887bf8e7cSmrg     * This is a possibility in FreeBSD but for now there is no good way for
368987bf8e7cSmrg     * obtaining the info.
369087bf8e7cSmrg     */
369187bf8e7cSmrg    switch (type) {
369287bf8e7cSmrg    case DRM_NODE_PRIMARY:
369387bf8e7cSmrg         break;
369487bf8e7cSmrg    case DRM_NODE_CONTROL:
369587bf8e7cSmrg         id -= 64;
369687bf8e7cSmrg         break;
369787bf8e7cSmrg    case DRM_NODE_RENDER:
369887bf8e7cSmrg         id -= 128;
369987bf8e7cSmrg          break;
370087bf8e7cSmrg    }
370187bf8e7cSmrg    if (id < 0)
370287bf8e7cSmrg        return -EINVAL;
370387bf8e7cSmrg
370487bf8e7cSmrg    if (snprintf(sysctl_name, sizeof(sysctl_name), "hw.dri.%d.busid", id) <= 0)
370587bf8e7cSmrg      return -EINVAL;
370687bf8e7cSmrg    sysctl_len = sizeof(sysctl_val);
370787bf8e7cSmrg    if (sysctlbyname(sysctl_name, sysctl_val, &sysctl_len, NULL, 0))
370887bf8e7cSmrg      return -EINVAL;
370987bf8e7cSmrg
371087bf8e7cSmrg    #define bus_fmt "pci:%04x:%02x:%02x.%u"
371187bf8e7cSmrg
371287bf8e7cSmrg    nelem = sscanf(sysctl_val, bus_fmt, &domain, &bus, &dev, &func);
371387bf8e7cSmrg    if (nelem != 4)
371487bf8e7cSmrg      return -EINVAL;
371587bf8e7cSmrg    info->domain = domain;
371687bf8e7cSmrg    info->bus = bus;
371787bf8e7cSmrg    info->dev = dev;
371887bf8e7cSmrg    info->func = func;
371987bf8e7cSmrg
372087bf8e7cSmrg    return 0;
372187bf8e7cSmrg}
372287bf8e7cSmrg#endif
37236260e5d5Smrg
3724fe517fc9Smrgstatic int drmParsePciBusInfo(int maj, int min, drmPciBusInfoPtr info)
3725fe517fc9Smrg{
3726fe517fc9Smrg#ifdef __linux__
37272ee35494Smrg    unsigned int domain, bus, dev, func;
37286260e5d5Smrg    char pci_path[PATH_MAX + 1], *value;
37292ee35494Smrg    int num;
3730fe517fc9Smrg
37316260e5d5Smrg    get_pci_path(maj, min, pci_path);
3732fe517fc9Smrg
37336260e5d5Smrg    value = sysfs_uevent_get(pci_path, "PCI_SLOT_NAME");
37342ee35494Smrg    if (!value)
37352ee35494Smrg        return -ENOENT;
3736fe517fc9Smrg
37372ee35494Smrg    num = sscanf(value, "%04x:%02x:%02x.%1u", &domain, &bus, &dev, &func);
37382ee35494Smrg    free(value);
3739fe517fc9Smrg
37402ee35494Smrg    if (num != 4)
3741fe517fc9Smrg        return -EINVAL;
3742fe517fc9Smrg
3743fe517fc9Smrg    info->domain = domain;
3744fe517fc9Smrg    info->bus = bus;
3745fe517fc9Smrg    info->dev = dev;
3746fe517fc9Smrg    info->func = func;
3747fe517fc9Smrg
3748a970b457Sriastradh    return 0;
3749a970b457Sriastradh#elif defined(__NetBSD__)
3750a970b457Sriastradh    int type, fd;
3751a970b457Sriastradh    drmSetVersion sv;
3752a970b457Sriastradh    char *buf;
3753a970b457Sriastradh    unsigned domain, bus, dev;
3754a970b457Sriastradh    int func;
3755a970b457Sriastradh    int ret;
3756a970b457Sriastradh
3757a970b457Sriastradh    /* Get the type of device we're looking for to pick the right pathname.  */
375877e87e13Smrg    type = drmGetMinorType(maj, min);
3759a970b457Sriastradh    if (type == -1)
3760a970b457Sriastradh	return -ENODEV;
3761a970b457Sriastradh
3762a970b457Sriastradh    /* Open the device.  Don't try to create it if it's not there.  */
3763a970b457Sriastradh    fd = drmOpenMinor(min, 0, type);
3764a970b457Sriastradh    if (fd < 0)
3765a970b457Sriastradh	return -errno;
3766a970b457Sriastradh
3767a970b457Sriastradh    /*
3768a970b457Sriastradh     * Set the interface version to 1.4 or 1.1, which has the effect of
3769a970b457Sriastradh     * populating the bus id for us.
3770a970b457Sriastradh     */
3771a970b457Sriastradh    sv.drm_di_major = 1;
3772a970b457Sriastradh    sv.drm_di_minor = 4;
3773a970b457Sriastradh    sv.drm_dd_major = -1;
3774a970b457Sriastradh    sv.drm_dd_minor = -1;
3775a970b457Sriastradh    if (drmSetInterfaceVersion(fd, &sv)) {
3776a970b457Sriastradh	sv.drm_di_major = 1;
3777a970b457Sriastradh	sv.drm_di_minor = 1;
3778a970b457Sriastradh	sv.drm_dd_major = -1;
3779a970b457Sriastradh	sv.drm_dd_minor = -1;
3780a970b457Sriastradh	if (drmSetInterfaceVersion(fd, &sv)) {
378106815bcbSmaya            /*
378206815bcbSmaya	     * We're probably not the master.  Hope the master already
378306815bcbSmaya	     * set the version to >=1.1 so that we can get the busid.
378406815bcbSmaya	     */
3785a970b457Sriastradh	}
3786a970b457Sriastradh    }
3787a970b457Sriastradh
3788a970b457Sriastradh    /* Get the bus id.  */
3789a970b457Sriastradh    buf = drmGetBusid(fd);
3790a970b457Sriastradh
3791a970b457Sriastradh    /* We're done with the device now.  */
3792a970b457Sriastradh    (void)close(fd);
3793a970b457Sriastradh
3794a970b457Sriastradh    /* If there is no bus id, fail.  */
3795a970b457Sriastradh    if (buf == NULL)
3796a970b457Sriastradh	return -ENODEV;
3797a970b457Sriastradh
3798a970b457Sriastradh    /* Parse the bus id.  */
3799a970b457Sriastradh    ret = sscanf(buf, "pci:%04x:%02x:%02x.%d", &domain, &bus, &dev, &func);
3800a970b457Sriastradh
3801a970b457Sriastradh    /* We're done with the bus id.  */
3802a970b457Sriastradh    free(buf);
3803a970b457Sriastradh
3804a970b457Sriastradh    /* If scanf didn't return 4 -- domain, bus, dev, func -- then fail.  */
3805a970b457Sriastradh    if (ret != 4)
3806a970b457Sriastradh	return -ENODEV;
3807a970b457Sriastradh
3808a970b457Sriastradh    /* Populate the results.  */
3809a970b457Sriastradh    info->domain = domain;
3810a970b457Sriastradh    info->bus = bus;
3811a970b457Sriastradh    info->dev = dev;
3812a970b457Sriastradh    info->func = func;
3813a970b457Sriastradh
3814a970b457Sriastradh    /* Success!  */
38152ee35494Smrg    return 0;
38164545e80cSmrg#elif defined(__OpenBSD__) || defined(__DragonFly__)
38172ee35494Smrg    struct drm_pciinfo pinfo;
38182ee35494Smrg    int fd, type;
38192ee35494Smrg
382087bf8e7cSmrg    type = drmGetMinorType(maj, min);
38212ee35494Smrg    if (type == -1)
38222ee35494Smrg        return -ENODEV;
38232ee35494Smrg
38242ee35494Smrg    fd = drmOpenMinor(min, 0, type);
38252ee35494Smrg    if (fd < 0)
38262ee35494Smrg        return -errno;
38272ee35494Smrg
38282ee35494Smrg    if (drmIoctl(fd, DRM_IOCTL_GET_PCIINFO, &pinfo)) {
38292ee35494Smrg        close(fd);
38302ee35494Smrg        return -errno;
38312ee35494Smrg    }
38322ee35494Smrg    close(fd);
38332ee35494Smrg
38342ee35494Smrg    info->domain = pinfo.domain;
38352ee35494Smrg    info->bus = pinfo.bus;
38362ee35494Smrg    info->dev = pinfo.dev;
38372ee35494Smrg    info->func = pinfo.func;
38382ee35494Smrg
3839fe517fc9Smrg    return 0;
38404b3d3f37Smrg#elif defined(__FreeBSD__)
384187bf8e7cSmrg    return get_sysctl_pci_bus_info(maj, min, info);
3842fe517fc9Smrg#else
3843fe517fc9Smrg#warning "Missing implementation of drmParsePciBusInfo"
3844fe517fc9Smrg    return -EINVAL;
3845fe517fc9Smrg#endif
3846fe517fc9Smrg}
3847fe517fc9Smrg
38486260e5d5Smrgdrm_public int drmDevicesEqual(drmDevicePtr a, drmDevicePtr b)
3849fe517fc9Smrg{
3850fe517fc9Smrg    if (a == NULL || b == NULL)
38510655efefSmrg        return 0;
3852fe517fc9Smrg
3853fe517fc9Smrg    if (a->bustype != b->bustype)
38540655efefSmrg        return 0;
3855fe517fc9Smrg
3856fe517fc9Smrg    switch (a->bustype) {
3857fe517fc9Smrg    case DRM_BUS_PCI:
38580655efefSmrg        return memcmp(a->businfo.pci, b->businfo.pci, sizeof(drmPciBusInfo)) == 0;
38592ee35494Smrg
38602ee35494Smrg    case DRM_BUS_USB:
38610655efefSmrg        return memcmp(a->businfo.usb, b->businfo.usb, sizeof(drmUsbBusInfo)) == 0;
38622ee35494Smrg
38632ee35494Smrg    case DRM_BUS_PLATFORM:
38640655efefSmrg        return memcmp(a->businfo.platform, b->businfo.platform, sizeof(drmPlatformBusInfo)) == 0;
38652ee35494Smrg
38662ee35494Smrg    case DRM_BUS_HOST1X:
38670655efefSmrg        return memcmp(a->businfo.host1x, b->businfo.host1x, sizeof(drmHost1xBusInfo)) == 0;
38682ee35494Smrg
3869fe517fc9Smrg    default:
3870fe517fc9Smrg        break;
3871fe517fc9Smrg    }
3872fe517fc9Smrg
38730655efefSmrg    return 0;
3874fe517fc9Smrg}
3875fe517fc9Smrg
3876fe517fc9Smrgstatic int drmGetNodeType(const char *name)
3877fe517fc9Smrg{
3878fe517fc9Smrg    if (strncmp(name, DRM_CONTROL_MINOR_NAME,
3879fe517fc9Smrg        sizeof(DRM_CONTROL_MINOR_NAME ) - 1) == 0)
3880fe517fc9Smrg        return DRM_NODE_CONTROL;
3881fe517fc9Smrg
3882fe517fc9Smrg    if (strncmp(name, DRM_RENDER_MINOR_NAME,
3883fe517fc9Smrg        sizeof(DRM_RENDER_MINOR_NAME) - 1) == 0)
3884fe517fc9Smrg        return DRM_NODE_RENDER;
3885fe517fc9Smrg
388682025ec7Smrg    if (strncmp(name, DRM_PRIMARY_MINOR_NAME,
388782025ec7Smrg        sizeof(DRM_PRIMARY_MINOR_NAME) - 1) == 0)
388882025ec7Smrg        return DRM_NODE_PRIMARY;
388982025ec7Smrg
3890fe517fc9Smrg    return -EINVAL;
3891fe517fc9Smrg}
3892fe517fc9Smrg
3893fe517fc9Smrgstatic int drmGetMaxNodeName(void)
3894fe517fc9Smrg{
3895fe517fc9Smrg    return sizeof(DRM_DIR_NAME) +
3896fe517fc9Smrg           MAX3(sizeof(DRM_PRIMARY_MINOR_NAME),
3897fe517fc9Smrg                sizeof(DRM_CONTROL_MINOR_NAME),
3898fe517fc9Smrg                sizeof(DRM_RENDER_MINOR_NAME)) +
3899fe517fc9Smrg           3 /* length of the node number */;
3900fe517fc9Smrg}
3901fe517fc9Smrg
3902fe517fc9Smrg#ifdef __linux__
39032ee35494Smrgstatic int parse_separate_sysfs_files(int maj, int min,
39042ee35494Smrg                                      drmPciDeviceInfoPtr device,
39052ee35494Smrg                                      bool ignore_revision)
39062ee35494Smrg{
39072ee35494Smrg    static const char *attrs[] = {
39082ee35494Smrg      "revision", /* Older kernels are missing the file, so check for it first */
39092ee35494Smrg      "vendor",
39102ee35494Smrg      "device",
39112ee35494Smrg      "subsystem_vendor",
39122ee35494Smrg      "subsystem_device",
39132ee35494Smrg    };
39146260e5d5Smrg    char path[PATH_MAX + 1], pci_path[PATH_MAX + 1];
39152ee35494Smrg    unsigned int data[ARRAY_SIZE(attrs)];
39162ee35494Smrg    FILE *fp;
39172ee35494Smrg    int ret;
39182ee35494Smrg
39196260e5d5Smrg    get_pci_path(maj, min, pci_path);
39206260e5d5Smrg
39212ee35494Smrg    for (unsigned i = ignore_revision ? 1 : 0; i < ARRAY_SIZE(attrs); i++) {
3922adfa0b0cSmrg        if (snprintf(path, PATH_MAX, "%s/%s", pci_path, attrs[i]) < 0)
3923adfa0b0cSmrg            return -errno;
3924adfa0b0cSmrg
39252ee35494Smrg        fp = fopen(path, "r");
39262ee35494Smrg        if (!fp)
39272ee35494Smrg            return -errno;
39282ee35494Smrg
39292ee35494Smrg        ret = fscanf(fp, "%x", &data[i]);
39302ee35494Smrg        fclose(fp);
39312ee35494Smrg        if (ret != 1)
39322ee35494Smrg            return -errno;
39332ee35494Smrg
39342ee35494Smrg    }
39352ee35494Smrg
39362ee35494Smrg    device->revision_id = ignore_revision ? 0xff : data[0] & 0xff;
39372ee35494Smrg    device->vendor_id = data[1] & 0xffff;
39382ee35494Smrg    device->device_id = data[2] & 0xffff;
39392ee35494Smrg    device->subvendor_id = data[3] & 0xffff;
39402ee35494Smrg    device->subdevice_id = data[4] & 0xffff;
39412ee35494Smrg
39422ee35494Smrg    return 0;
39432ee35494Smrg}
39442ee35494Smrg
39452ee35494Smrgstatic int parse_config_sysfs_file(int maj, int min,
39462ee35494Smrg                                   drmPciDeviceInfoPtr device)
39472ee35494Smrg{
39486260e5d5Smrg    char path[PATH_MAX + 1], pci_path[PATH_MAX + 1];
3949fe517fc9Smrg    unsigned char config[64];
3950fe517fc9Smrg    int fd, ret;
3951fe517fc9Smrg
39526260e5d5Smrg    get_pci_path(maj, min, pci_path);
39536260e5d5Smrg
3954adfa0b0cSmrg    if (snprintf(path, PATH_MAX, "%s/config", pci_path) < 0)
3955adfa0b0cSmrg        return -errno;
3956adfa0b0cSmrg
3957fe517fc9Smrg    fd = open(path, O_RDONLY);
3958fe517fc9Smrg    if (fd < 0)
3959fe517fc9Smrg        return -errno;
3960fe517fc9Smrg
3961fe517fc9Smrg    ret = read(fd, config, sizeof(config));
3962fe517fc9Smrg    close(fd);
3963fe517fc9Smrg    if (ret < 0)
3964fe517fc9Smrg        return -errno;
3965fe517fc9Smrg
3966fe517fc9Smrg    device->vendor_id = config[0] | (config[1] << 8);
3967fe517fc9Smrg    device->device_id = config[2] | (config[3] << 8);
3968fe517fc9Smrg    device->revision_id = config[8];
3969fe517fc9Smrg    device->subvendor_id = config[44] | (config[45] << 8);
3970fe517fc9Smrg    device->subdevice_id = config[46] | (config[47] << 8);
3971fe517fc9Smrg
39722ee35494Smrg    return 0;
39732ee35494Smrg}
39742ee35494Smrg#endif
39752ee35494Smrg
39762ee35494Smrgstatic int drmParsePciDeviceInfo(int maj, int min,
39772ee35494Smrg                                 drmPciDeviceInfoPtr device,
39782ee35494Smrg                                 uint32_t flags)
39792ee35494Smrg{
39802ee35494Smrg#ifdef __linux__
39812ee35494Smrg    if (!(flags & DRM_DEVICE_GET_PCI_REVISION))
39822ee35494Smrg        return parse_separate_sysfs_files(maj, min, device, true);
39832ee35494Smrg
39842ee35494Smrg    if (parse_separate_sysfs_files(maj, min, device, false))
39852ee35494Smrg        return parse_config_sysfs_file(maj, min, device);
39862ee35494Smrg
39872ee35494Smrg    return 0;
3988a970b457Sriastradh#elif defined(__NetBSD__)
3989a970b457Sriastradh    drmPciBusInfo businfo;
3990a970b457Sriastradh    char fname[PATH_MAX];
3991a970b457Sriastradh    int pcifd;
3992a970b457Sriastradh    pcireg_t id, class, subsys;
3993a970b457Sriastradh    int ret;
3994a970b457Sriastradh
3995a970b457Sriastradh    /* Find where on the bus the device lives.  */
3996a970b457Sriastradh    ret = drmParsePciBusInfo(maj, min, &businfo);
3997a970b457Sriastradh    if (ret)
3998a970b457Sriastradh	return ret;
3999a970b457Sriastradh
4000a970b457Sriastradh    /* Open the pciN device node to get at its config registers.  */
4001a970b457Sriastradh    if (snprintf(fname, sizeof fname, "/dev/pci%u", businfo.domain)
4002a970b457Sriastradh	>= sizeof fname)
4003a970b457Sriastradh	return -ENODEV;
4004a970b457Sriastradh    if ((pcifd = open(fname, O_RDONLY)) == -1)
4005a970b457Sriastradh	return -errno;
4006a970b457Sriastradh
4007f8b67707Schristos    ret = -1;
4008a970b457Sriastradh    /* Read the id and class pci config registers.  */
4009a970b457Sriastradh    if (pcibus_conf_read(pcifd, businfo.bus, businfo.dev, businfo.func,
4010a970b457Sriastradh	    PCI_ID_REG, &id) == -1)
4011f8b67707Schristos	goto out;
4012a970b457Sriastradh    if (pcibus_conf_read(pcifd, businfo.bus, businfo.dev, businfo.func,
4013a970b457Sriastradh	    PCI_CLASS_REG, &class) == -1)
4014f8b67707Schristos	goto out;
4015a970b457Sriastradh    if (pcibus_conf_read(pcifd, businfo.bus, businfo.dev, businfo.func,
4016a970b457Sriastradh	    PCI_SUBSYS_ID_REG, &subsys) == -1)
4017f8b67707Schristos	goto out;
4018a970b457Sriastradh
4019f8b67707Schristos    ret = 0;
4020a970b457Sriastradh    device->vendor_id = PCI_VENDOR(id);
4021a970b457Sriastradh    device->device_id = PCI_PRODUCT(id);
4022a970b457Sriastradh    device->subvendor_id = PCI_SUBSYS_VENDOR(subsys);
4023a970b457Sriastradh    device->subdevice_id = PCI_SUBSYS_ID(subsys);
4024a970b457Sriastradh    device->revision_id = PCI_REVISION(class);
4025f8b67707Schristosout:
4026f8b67707Schristos    if (ret == -1)
4027f8b67707Schristos	ret = -errno;
4028f8b67707Schristos    close(pcifd);
4029f8b67707Schristos    return ret;
40304545e80cSmrg#elif defined(__OpenBSD__) || defined(__DragonFly__)
40312ee35494Smrg    struct drm_pciinfo pinfo;
40322ee35494Smrg    int fd, type;
40332ee35494Smrg
403487bf8e7cSmrg    type = drmGetMinorType(maj, min);
40352ee35494Smrg    if (type == -1)
40362ee35494Smrg        return -ENODEV;
40372ee35494Smrg
40382ee35494Smrg    fd = drmOpenMinor(min, 0, type);
40392ee35494Smrg    if (fd < 0)
40402ee35494Smrg        return -errno;
40412ee35494Smrg
40422ee35494Smrg    if (drmIoctl(fd, DRM_IOCTL_GET_PCIINFO, &pinfo)) {
40432ee35494Smrg        close(fd);
40442ee35494Smrg        return -errno;
40452ee35494Smrg    }
40462ee35494Smrg    close(fd);
40472ee35494Smrg
40482ee35494Smrg    device->vendor_id = pinfo.vendor_id;
40492ee35494Smrg    device->device_id = pinfo.device_id;
40502ee35494Smrg    device->revision_id = pinfo.revision_id;
40512ee35494Smrg    device->subvendor_id = pinfo.subvendor_id;
40522ee35494Smrg    device->subdevice_id = pinfo.subdevice_id;
40532ee35494Smrg
405487bf8e7cSmrg    return 0;
40554b3d3f37Smrg#elif defined(__FreeBSD__)
405687bf8e7cSmrg    drmPciBusInfo info;
405787bf8e7cSmrg    struct pci_conf_io pc;
405887bf8e7cSmrg    struct pci_match_conf patterns[1];
405987bf8e7cSmrg    struct pci_conf results[1];
406087bf8e7cSmrg    int fd, error;
406187bf8e7cSmrg
406287bf8e7cSmrg    if (get_sysctl_pci_bus_info(maj, min, &info) != 0)
406387bf8e7cSmrg        return -EINVAL;
406487bf8e7cSmrg
406587bf8e7cSmrg    fd = open("/dev/pci", O_RDONLY, 0);
406687bf8e7cSmrg    if (fd < 0)
406787bf8e7cSmrg        return -errno;
406887bf8e7cSmrg
406987bf8e7cSmrg    bzero(&patterns, sizeof(patterns));
407087bf8e7cSmrg    patterns[0].pc_sel.pc_domain = info.domain;
407187bf8e7cSmrg    patterns[0].pc_sel.pc_bus = info.bus;
407287bf8e7cSmrg    patterns[0].pc_sel.pc_dev = info.dev;
407387bf8e7cSmrg    patterns[0].pc_sel.pc_func = info.func;
407487bf8e7cSmrg    patterns[0].flags = PCI_GETCONF_MATCH_DOMAIN | PCI_GETCONF_MATCH_BUS
407587bf8e7cSmrg                      | PCI_GETCONF_MATCH_DEV | PCI_GETCONF_MATCH_FUNC;
407687bf8e7cSmrg    bzero(&pc, sizeof(struct pci_conf_io));
407787bf8e7cSmrg    pc.num_patterns = 1;
407887bf8e7cSmrg    pc.pat_buf_len = sizeof(patterns);
407987bf8e7cSmrg    pc.patterns = patterns;
408087bf8e7cSmrg    pc.match_buf_len = sizeof(results);
408187bf8e7cSmrg    pc.matches = results;
408287bf8e7cSmrg
408387bf8e7cSmrg    if (ioctl(fd, PCIOCGETCONF, &pc) || pc.status == PCI_GETCONF_ERROR) {
408487bf8e7cSmrg        error = errno;
408587bf8e7cSmrg        close(fd);
408687bf8e7cSmrg        return -error;
408787bf8e7cSmrg    }
408887bf8e7cSmrg    close(fd);
408987bf8e7cSmrg
409087bf8e7cSmrg    device->vendor_id = results[0].pc_vendor;
409187bf8e7cSmrg    device->device_id = results[0].pc_device;
409287bf8e7cSmrg    device->subvendor_id = results[0].pc_subvendor;
409387bf8e7cSmrg    device->subdevice_id = results[0].pc_subdevice;
409487bf8e7cSmrg    device->revision_id = results[0].pc_revid;
409587bf8e7cSmrg
4096fe517fc9Smrg    return 0;
4097fe517fc9Smrg#else
4098fe517fc9Smrg#warning "Missing implementation of drmParsePciDeviceInfo"
4099fe517fc9Smrg    return -EINVAL;
4100fe517fc9Smrg#endif
4101fe517fc9Smrg}
4102fe517fc9Smrg
41032ee35494Smrgstatic void drmFreePlatformDevice(drmDevicePtr device)
41042ee35494Smrg{
41052ee35494Smrg    if (device->deviceinfo.platform) {
41062ee35494Smrg        if (device->deviceinfo.platform->compatible) {
41072ee35494Smrg            char **compatible = device->deviceinfo.platform->compatible;
41082ee35494Smrg
41092ee35494Smrg            while (*compatible) {
41102ee35494Smrg                free(*compatible);
41112ee35494Smrg                compatible++;
41122ee35494Smrg            }
41132ee35494Smrg
41142ee35494Smrg            free(device->deviceinfo.platform->compatible);
41152ee35494Smrg        }
41162ee35494Smrg    }
41172ee35494Smrg}
41182ee35494Smrg
41192ee35494Smrgstatic void drmFreeHost1xDevice(drmDevicePtr device)
41202ee35494Smrg{
41212ee35494Smrg    if (device->deviceinfo.host1x) {
41222ee35494Smrg        if (device->deviceinfo.host1x->compatible) {
41232ee35494Smrg            char **compatible = device->deviceinfo.host1x->compatible;
41242ee35494Smrg
41252ee35494Smrg            while (*compatible) {
41262ee35494Smrg                free(*compatible);
41272ee35494Smrg                compatible++;
41282ee35494Smrg            }
41292ee35494Smrg
41302ee35494Smrg            free(device->deviceinfo.host1x->compatible);
41312ee35494Smrg        }
41322ee35494Smrg    }
41332ee35494Smrg}
41342ee35494Smrg
41356260e5d5Smrgdrm_public void drmFreeDevice(drmDevicePtr *device)
4136fe517fc9Smrg{
4137fe517fc9Smrg    if (device == NULL)
4138fe517fc9Smrg        return;
4139fe517fc9Smrg
41402ee35494Smrg    if (*device) {
41412ee35494Smrg        switch ((*device)->bustype) {
41422ee35494Smrg        case DRM_BUS_PLATFORM:
41432ee35494Smrg            drmFreePlatformDevice(*device);
41442ee35494Smrg            break;
41452ee35494Smrg
41462ee35494Smrg        case DRM_BUS_HOST1X:
41472ee35494Smrg            drmFreeHost1xDevice(*device);
41482ee35494Smrg            break;
41492ee35494Smrg        }
41502ee35494Smrg    }
41512ee35494Smrg
4152fe517fc9Smrg    free(*device);
4153fe517fc9Smrg    *device = NULL;
4154fe517fc9Smrg}
4155fe517fc9Smrg
41566260e5d5Smrgdrm_public void drmFreeDevices(drmDevicePtr devices[], int count)
4157fe517fc9Smrg{
4158fe517fc9Smrg    int i;
4159fe517fc9Smrg
4160fe517fc9Smrg    if (devices == NULL)
4161fe517fc9Smrg        return;
4162fe517fc9Smrg
4163fe517fc9Smrg    for (i = 0; i < count; i++)
4164fe517fc9Smrg        if (devices[i])
4165fe517fc9Smrg            drmFreeDevice(&devices[i]);
4166fe517fc9Smrg}
4167fe517fc9Smrg
41682ee35494Smrgstatic drmDevicePtr drmDeviceAlloc(unsigned int type, const char *node,
41692ee35494Smrg                                   size_t bus_size, size_t device_size,
41702ee35494Smrg                                   char **ptrp)
4171fe517fc9Smrg{
41722ee35494Smrg    size_t max_node_length, extra, size;
41732ee35494Smrg    drmDevicePtr device;
41742ee35494Smrg    unsigned int i;
41752ee35494Smrg    char *ptr;
4176fe517fc9Smrg
41772ee35494Smrg    max_node_length = ALIGN(drmGetMaxNodeName(), sizeof(void *));
41782ee35494Smrg    extra = DRM_NODE_MAX * (sizeof(void *) + max_node_length);
4179fe517fc9Smrg
41802ee35494Smrg    size = sizeof(*device) + extra + bus_size + device_size;
4181fe517fc9Smrg
41822ee35494Smrg    device = calloc(1, size);
41832ee35494Smrg    if (!device)
41842ee35494Smrg        return NULL;
41852ee35494Smrg
41862ee35494Smrg    device->available_nodes = 1 << type;
4187fe517fc9Smrg
41882ee35494Smrg    ptr = (char *)device + sizeof(*device);
41892ee35494Smrg    device->nodes = (char **)ptr;
41902ee35494Smrg
41912ee35494Smrg    ptr += DRM_NODE_MAX * sizeof(void *);
4192fe517fc9Smrg
4193fe517fc9Smrg    for (i = 0; i < DRM_NODE_MAX; i++) {
41942ee35494Smrg        device->nodes[i] = ptr;
41952ee35494Smrg        ptr += max_node_length;
4196fe517fc9Smrg    }
4197fe517fc9Smrg
41982ee35494Smrg    memcpy(device->nodes[type], node, max_node_length);
41992ee35494Smrg
42002ee35494Smrg    *ptrp = ptr;
42012ee35494Smrg
42022ee35494Smrg    return device;
42032ee35494Smrg}
42042ee35494Smrg
42052ee35494Smrgstatic int drmProcessPciDevice(drmDevicePtr *device,
42062ee35494Smrg                               const char *node, int node_type,
42072ee35494Smrg                               int maj, int min, bool fetch_deviceinfo,
42082ee35494Smrg                               uint32_t flags)
42092ee35494Smrg{
42102ee35494Smrg    drmDevicePtr dev;
42112ee35494Smrg    char *addr;
42122ee35494Smrg    int ret;
42132ee35494Smrg
42142ee35494Smrg    dev = drmDeviceAlloc(node_type, node, sizeof(drmPciBusInfo),
42152ee35494Smrg                         sizeof(drmPciDeviceInfo), &addr);
42162ee35494Smrg    if (!dev)
42172ee35494Smrg        return -ENOMEM;
42182ee35494Smrg
42192ee35494Smrg    dev->bustype = DRM_BUS_PCI;
4220fe517fc9Smrg
42212ee35494Smrg    dev->businfo.pci = (drmPciBusInfoPtr)addr;
42222ee35494Smrg
42232ee35494Smrg    ret = drmParsePciBusInfo(maj, min, dev->businfo.pci);
4224fe517fc9Smrg    if (ret)
4225fe517fc9Smrg        goto free_device;
4226fe517fc9Smrg
4227fe517fc9Smrg    // Fetch the device info if the user has requested it
4228fe517fc9Smrg    if (fetch_deviceinfo) {
4229fe517fc9Smrg        addr += sizeof(drmPciBusInfo);
42302ee35494Smrg        dev->deviceinfo.pci = (drmPciDeviceInfoPtr)addr;
4231fe517fc9Smrg
42322ee35494Smrg        ret = drmParsePciDeviceInfo(maj, min, dev->deviceinfo.pci, flags);
4233fe517fc9Smrg        if (ret)
4234fe517fc9Smrg            goto free_device;
4235fe517fc9Smrg    }
42362ee35494Smrg
42372ee35494Smrg    *device = dev;
42382ee35494Smrg
4239fe517fc9Smrg    return 0;
4240fe517fc9Smrg
4241fe517fc9Smrgfree_device:
42422ee35494Smrg    free(dev);
42432ee35494Smrg    return ret;
42442ee35494Smrg}
42452ee35494Smrg
424687bf8e7cSmrg#ifdef __linux__
424787bf8e7cSmrgstatic int drm_usb_dev_path(int maj, int min, char *path, size_t len)
424887bf8e7cSmrg{
424987bf8e7cSmrg    char *value, *tmp_path, *slash;
4250adfa0b0cSmrg    bool usb_device, usb_interface;
425187bf8e7cSmrg
425287bf8e7cSmrg    snprintf(path, len, "/sys/dev/char/%d:%d/device", maj, min);
425387bf8e7cSmrg
425487bf8e7cSmrg    value = sysfs_uevent_get(path, "DEVTYPE");
425587bf8e7cSmrg    if (!value)
425687bf8e7cSmrg        return -ENOENT;
425787bf8e7cSmrg
4258adfa0b0cSmrg    usb_device = strcmp(value, "usb_device") == 0;
4259adfa0b0cSmrg    usb_interface = strcmp(value, "usb_interface") == 0;
4260adfa0b0cSmrg    free(value);
4261adfa0b0cSmrg
4262adfa0b0cSmrg    if (usb_device)
426387bf8e7cSmrg        return 0;
4264adfa0b0cSmrg    if (!usb_interface)
426587bf8e7cSmrg        return -ENOTSUP;
426687bf8e7cSmrg
426787bf8e7cSmrg    /* The parent of a usb_interface is a usb_device */
426887bf8e7cSmrg
426987bf8e7cSmrg    tmp_path = realpath(path, NULL);
427087bf8e7cSmrg    if (!tmp_path)
427187bf8e7cSmrg        return -errno;
427287bf8e7cSmrg
427387bf8e7cSmrg    slash = strrchr(tmp_path, '/');
427487bf8e7cSmrg    if (!slash) {
427587bf8e7cSmrg        free(tmp_path);
427687bf8e7cSmrg        return -EINVAL;
427787bf8e7cSmrg    }
427887bf8e7cSmrg
427987bf8e7cSmrg    *slash = '\0';
428087bf8e7cSmrg
428187bf8e7cSmrg    if (snprintf(path, len, "%s", tmp_path) >= (int)len) {
428287bf8e7cSmrg        free(tmp_path);
428387bf8e7cSmrg        return -EINVAL;
428487bf8e7cSmrg    }
428587bf8e7cSmrg
428687bf8e7cSmrg    free(tmp_path);
428787bf8e7cSmrg    return 0;
428887bf8e7cSmrg}
428987bf8e7cSmrg#endif
429087bf8e7cSmrg
42912ee35494Smrgstatic int drmParseUsbBusInfo(int maj, int min, drmUsbBusInfoPtr info)
42922ee35494Smrg{
42932ee35494Smrg#ifdef __linux__
42942ee35494Smrg    char path[PATH_MAX + 1], *value;
42952ee35494Smrg    unsigned int bus, dev;
42962ee35494Smrg    int ret;
42972ee35494Smrg
429887bf8e7cSmrg    ret = drm_usb_dev_path(maj, min, path, sizeof(path));
429987bf8e7cSmrg    if (ret < 0)
430087bf8e7cSmrg        return ret;
43012ee35494Smrg
43022ee35494Smrg    value = sysfs_uevent_get(path, "BUSNUM");
43032ee35494Smrg    if (!value)
43042ee35494Smrg        return -ENOENT;
43052ee35494Smrg
43062ee35494Smrg    ret = sscanf(value, "%03u", &bus);
43072ee35494Smrg    free(value);
43082ee35494Smrg
43092ee35494Smrg    if (ret <= 0)
43102ee35494Smrg        return -errno;
43112ee35494Smrg
43122ee35494Smrg    value = sysfs_uevent_get(path, "DEVNUM");
43132ee35494Smrg    if (!value)
43142ee35494Smrg        return -ENOENT;
43152ee35494Smrg
43162ee35494Smrg    ret = sscanf(value, "%03u", &dev);
43172ee35494Smrg    free(value);
43182ee35494Smrg
43192ee35494Smrg    if (ret <= 0)
43202ee35494Smrg        return -errno;
43212ee35494Smrg
43222ee35494Smrg    info->bus = bus;
43232ee35494Smrg    info->dev = dev;
43242ee35494Smrg
43252ee35494Smrg    return 0;
43262ee35494Smrg#else
43272ee35494Smrg#warning "Missing implementation of drmParseUsbBusInfo"
43282ee35494Smrg    return -EINVAL;
43292ee35494Smrg#endif
43302ee35494Smrg}
43312ee35494Smrg
43322ee35494Smrgstatic int drmParseUsbDeviceInfo(int maj, int min, drmUsbDeviceInfoPtr info)
43332ee35494Smrg{
43342ee35494Smrg#ifdef __linux__
43352ee35494Smrg    char path[PATH_MAX + 1], *value;
43362ee35494Smrg    unsigned int vendor, product;
43372ee35494Smrg    int ret;
43382ee35494Smrg
433987bf8e7cSmrg    ret = drm_usb_dev_path(maj, min, path, sizeof(path));
434087bf8e7cSmrg    if (ret < 0)
434187bf8e7cSmrg        return ret;
43422ee35494Smrg
43432ee35494Smrg    value = sysfs_uevent_get(path, "PRODUCT");
43442ee35494Smrg    if (!value)
43452ee35494Smrg        return -ENOENT;
43462ee35494Smrg
43472ee35494Smrg    ret = sscanf(value, "%x/%x", &vendor, &product);
43482ee35494Smrg    free(value);
43492ee35494Smrg
43502ee35494Smrg    if (ret <= 0)
43512ee35494Smrg        return -errno;
43522ee35494Smrg
43532ee35494Smrg    info->vendor = vendor;
43542ee35494Smrg    info->product = product;
43552ee35494Smrg
43562ee35494Smrg    return 0;
43572ee35494Smrg#else
43582ee35494Smrg#warning "Missing implementation of drmParseUsbDeviceInfo"
43592ee35494Smrg    return -EINVAL;
43602ee35494Smrg#endif
43612ee35494Smrg}
43622ee35494Smrg
43632ee35494Smrgstatic int drmProcessUsbDevice(drmDevicePtr *device, const char *node,
43642ee35494Smrg                               int node_type, int maj, int min,
43652ee35494Smrg                               bool fetch_deviceinfo, uint32_t flags)
43662ee35494Smrg{
43672ee35494Smrg    drmDevicePtr dev;
43682ee35494Smrg    char *ptr;
43692ee35494Smrg    int ret;
43702ee35494Smrg
43712ee35494Smrg    dev = drmDeviceAlloc(node_type, node, sizeof(drmUsbBusInfo),
43722ee35494Smrg                         sizeof(drmUsbDeviceInfo), &ptr);
43732ee35494Smrg    if (!dev)
43742ee35494Smrg        return -ENOMEM;
43752ee35494Smrg
43762ee35494Smrg    dev->bustype = DRM_BUS_USB;
43772ee35494Smrg
43782ee35494Smrg    dev->businfo.usb = (drmUsbBusInfoPtr)ptr;
43792ee35494Smrg
43802ee35494Smrg    ret = drmParseUsbBusInfo(maj, min, dev->businfo.usb);
43812ee35494Smrg    if (ret < 0)
43822ee35494Smrg        goto free_device;
43832ee35494Smrg
43842ee35494Smrg    if (fetch_deviceinfo) {
43852ee35494Smrg        ptr += sizeof(drmUsbBusInfo);
43862ee35494Smrg        dev->deviceinfo.usb = (drmUsbDeviceInfoPtr)ptr;
43872ee35494Smrg
43882ee35494Smrg        ret = drmParseUsbDeviceInfo(maj, min, dev->deviceinfo.usb);
43892ee35494Smrg        if (ret < 0)
43902ee35494Smrg            goto free_device;
43912ee35494Smrg    }
43922ee35494Smrg
43932ee35494Smrg    *device = dev;
43942ee35494Smrg
43952ee35494Smrg    return 0;
43962ee35494Smrg
43972ee35494Smrgfree_device:
43982ee35494Smrg    free(dev);
43992ee35494Smrg    return ret;
44002ee35494Smrg}
44012ee35494Smrg
4402bf6cc7dcSmrgstatic int drmParseOFBusInfo(int maj, int min, char *fullname)
44032ee35494Smrg{
44042ee35494Smrg#ifdef __linux__
4405bf6cc7dcSmrg    char path[PATH_MAX + 1], *name, *tmp_name;
44062ee35494Smrg
44072ee35494Smrg    snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min);
44082ee35494Smrg
44092ee35494Smrg    name = sysfs_uevent_get(path, "OF_FULLNAME");
4410bf6cc7dcSmrg    tmp_name = name;
4411bf6cc7dcSmrg    if (!name) {
4412bf6cc7dcSmrg        /* If the device lacks OF data, pick the MODALIAS info */
4413bf6cc7dcSmrg        name = sysfs_uevent_get(path, "MODALIAS");
4414bf6cc7dcSmrg        if (!name)
4415bf6cc7dcSmrg            return -ENOENT;
4416bf6cc7dcSmrg
4417bf6cc7dcSmrg        /* .. and strip the MODALIAS=[platform,usb...]: part. */
4418bf6cc7dcSmrg        tmp_name = strrchr(name, ':');
4419bf6cc7dcSmrg        if (!tmp_name) {
4420bf6cc7dcSmrg            free(name);
4421bf6cc7dcSmrg            return -ENOENT;
4422bf6cc7dcSmrg        }
4423bf6cc7dcSmrg        tmp_name++;
4424bf6cc7dcSmrg    }
44252ee35494Smrg
4426bf6cc7dcSmrg    strncpy(fullname, tmp_name, DRM_PLATFORM_DEVICE_NAME_LEN);
4427bf6cc7dcSmrg    fullname[DRM_PLATFORM_DEVICE_NAME_LEN - 1] = '\0';
44282ee35494Smrg    free(name);
44292ee35494Smrg
44302ee35494Smrg    return 0;
44312ee35494Smrg#else
4432bf6cc7dcSmrg#warning "Missing implementation of drmParseOFBusInfo"
44332ee35494Smrg    return -EINVAL;
44342ee35494Smrg#endif
44352ee35494Smrg}
44362ee35494Smrg
4437bf6cc7dcSmrgstatic int drmParseOFDeviceInfo(int maj, int min, char ***compatible)
44382ee35494Smrg{
44392ee35494Smrg#ifdef __linux__
4440bf6cc7dcSmrg    char path[PATH_MAX + 1], *value, *tmp_name;
44412ee35494Smrg    unsigned int count, i;
44422ee35494Smrg    int err;
44432ee35494Smrg
44442ee35494Smrg    snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min);
44452ee35494Smrg
44462ee35494Smrg    value = sysfs_uevent_get(path, "OF_COMPATIBLE_N");
4447bf6cc7dcSmrg    if (value) {
4448bf6cc7dcSmrg        sscanf(value, "%u", &count);
4449bf6cc7dcSmrg        free(value);
4450bf6cc7dcSmrg    } else {
4451bf6cc7dcSmrg        /* Assume one entry if the device lack OF data */
4452bf6cc7dcSmrg        count = 1;
4453bf6cc7dcSmrg    }
44542ee35494Smrg
4455bf6cc7dcSmrg    *compatible = calloc(count + 1, sizeof(char *));
4456bf6cc7dcSmrg    if (!*compatible)
44572ee35494Smrg        return -ENOMEM;
44582ee35494Smrg
44592ee35494Smrg    for (i = 0; i < count; i++) {
44602ee35494Smrg        value = sysfs_uevent_get(path, "OF_COMPATIBLE_%u", i);
4461bf6cc7dcSmrg        tmp_name = value;
44622ee35494Smrg        if (!value) {
4463bf6cc7dcSmrg            /* If the device lacks OF data, pick the MODALIAS info */
4464bf6cc7dcSmrg            value = sysfs_uevent_get(path, "MODALIAS");
4465bf6cc7dcSmrg            if (!value) {
4466bf6cc7dcSmrg                err = -ENOENT;
4467bf6cc7dcSmrg                goto free;
4468bf6cc7dcSmrg            }
4469bf6cc7dcSmrg
4470bf6cc7dcSmrg            /* .. and strip the MODALIAS=[platform,usb...]: part. */
4471bf6cc7dcSmrg            tmp_name = strrchr(value, ':');
4472bf6cc7dcSmrg            if (!tmp_name) {
4473bf6cc7dcSmrg                free(value);
4474bf6cc7dcSmrg                return -ENOENT;
4475bf6cc7dcSmrg            }
4476bf6cc7dcSmrg            tmp_name = strdup(tmp_name + 1);
4477bf6cc7dcSmrg            free(value);
44782ee35494Smrg        }
44792ee35494Smrg
4480bf6cc7dcSmrg        (*compatible)[i] = tmp_name;
44812ee35494Smrg    }
44822ee35494Smrg
44832ee35494Smrg    return 0;
44842ee35494Smrg
44852ee35494Smrgfree:
44862ee35494Smrg    while (i--)
4487bf6cc7dcSmrg        free((*compatible)[i]);
44882ee35494Smrg
4489bf6cc7dcSmrg    free(*compatible);
44902ee35494Smrg    return err;
44912ee35494Smrg#else
4492bf6cc7dcSmrg#warning "Missing implementation of drmParseOFDeviceInfo"
44932ee35494Smrg    return -EINVAL;
44942ee35494Smrg#endif
44952ee35494Smrg}
44962ee35494Smrg
44972ee35494Smrgstatic int drmProcessPlatformDevice(drmDevicePtr *device,
44982ee35494Smrg                                    const char *node, int node_type,
44992ee35494Smrg                                    int maj, int min, bool fetch_deviceinfo,
45002ee35494Smrg                                    uint32_t flags)
45012ee35494Smrg{
45022ee35494Smrg    drmDevicePtr dev;
45032ee35494Smrg    char *ptr;
45042ee35494Smrg    int ret;
45052ee35494Smrg
45062ee35494Smrg    dev = drmDeviceAlloc(node_type, node, sizeof(drmPlatformBusInfo),
45072ee35494Smrg                         sizeof(drmPlatformDeviceInfo), &ptr);
45082ee35494Smrg    if (!dev)
45092ee35494Smrg        return -ENOMEM;
45102ee35494Smrg
45112ee35494Smrg    dev->bustype = DRM_BUS_PLATFORM;
45122ee35494Smrg
45132ee35494Smrg    dev->businfo.platform = (drmPlatformBusInfoPtr)ptr;
45142ee35494Smrg
4515bf6cc7dcSmrg    ret = drmParseOFBusInfo(maj, min, dev->businfo.platform->fullname);
45162ee35494Smrg    if (ret < 0)
45172ee35494Smrg        goto free_device;
45182ee35494Smrg
45192ee35494Smrg    if (fetch_deviceinfo) {
45202ee35494Smrg        ptr += sizeof(drmPlatformBusInfo);
45212ee35494Smrg        dev->deviceinfo.platform = (drmPlatformDeviceInfoPtr)ptr;
45222ee35494Smrg
4523bf6cc7dcSmrg        ret = drmParseOFDeviceInfo(maj, min, &dev->deviceinfo.platform->compatible);
45242ee35494Smrg        if (ret < 0)
45252ee35494Smrg            goto free_device;
45262ee35494Smrg    }
45272ee35494Smrg
45282ee35494Smrg    *device = dev;
45292ee35494Smrg
45302ee35494Smrg    return 0;
45312ee35494Smrg
45322ee35494Smrgfree_device:
45332ee35494Smrg    free(dev);
45342ee35494Smrg    return ret;
45352ee35494Smrg}
45362ee35494Smrg
45372ee35494Smrgstatic int drmProcessHost1xDevice(drmDevicePtr *device,
45382ee35494Smrg                                  const char *node, int node_type,
45392ee35494Smrg                                  int maj, int min, bool fetch_deviceinfo,
45402ee35494Smrg                                  uint32_t flags)
45412ee35494Smrg{
45422ee35494Smrg    drmDevicePtr dev;
45432ee35494Smrg    char *ptr;
45442ee35494Smrg    int ret;
45452ee35494Smrg
45462ee35494Smrg    dev = drmDeviceAlloc(node_type, node, sizeof(drmHost1xBusInfo),
45472ee35494Smrg                         sizeof(drmHost1xDeviceInfo), &ptr);
45482ee35494Smrg    if (!dev)
45492ee35494Smrg        return -ENOMEM;
45502ee35494Smrg
45512ee35494Smrg    dev->bustype = DRM_BUS_HOST1X;
45522ee35494Smrg
45532ee35494Smrg    dev->businfo.host1x = (drmHost1xBusInfoPtr)ptr;
45542ee35494Smrg
4555bf6cc7dcSmrg    ret = drmParseOFBusInfo(maj, min, dev->businfo.host1x->fullname);
45562ee35494Smrg    if (ret < 0)
45572ee35494Smrg        goto free_device;
45582ee35494Smrg
45592ee35494Smrg    if (fetch_deviceinfo) {
45602ee35494Smrg        ptr += sizeof(drmHost1xBusInfo);
45612ee35494Smrg        dev->deviceinfo.host1x = (drmHost1xDeviceInfoPtr)ptr;
45622ee35494Smrg
4563bf6cc7dcSmrg        ret = drmParseOFDeviceInfo(maj, min, &dev->deviceinfo.host1x->compatible);
45642ee35494Smrg        if (ret < 0)
45652ee35494Smrg            goto free_device;
45662ee35494Smrg    }
45672ee35494Smrg
45682ee35494Smrg    *device = dev;
45692ee35494Smrg
45702ee35494Smrg    return 0;
45712ee35494Smrg
45722ee35494Smrgfree_device:
45732ee35494Smrg    free(dev);
4574fe517fc9Smrg    return ret;
4575fe517fc9Smrg}
4576fe517fc9Smrg
45776260e5d5Smrgstatic int
45786260e5d5Smrgprocess_device(drmDevicePtr *device, const char *d_name,
45796260e5d5Smrg               int req_subsystem_type,
45806260e5d5Smrg               bool fetch_deviceinfo, uint32_t flags)
45816260e5d5Smrg{
45826260e5d5Smrg    struct stat sbuf;
45836260e5d5Smrg    char node[PATH_MAX + 1];
45846260e5d5Smrg    int node_type, subsystem_type;
45856260e5d5Smrg    unsigned int maj, min;
45866260e5d5Smrg
45876260e5d5Smrg    node_type = drmGetNodeType(d_name);
45886260e5d5Smrg    if (node_type < 0)
45896260e5d5Smrg        return -1;
45906260e5d5Smrg
45916260e5d5Smrg    snprintf(node, PATH_MAX, "%s/%s", DRM_DIR_NAME, d_name);
45926260e5d5Smrg    if (stat(node, &sbuf))
45936260e5d5Smrg        return -1;
45946260e5d5Smrg
45956260e5d5Smrg    maj = major(sbuf.st_rdev);
45966260e5d5Smrg    min = minor(sbuf.st_rdev);
45976260e5d5Smrg
45986260e5d5Smrg    if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode))
45996260e5d5Smrg        return -1;
46006260e5d5Smrg
46016260e5d5Smrg    subsystem_type = drmParseSubsystemType(maj, min);
46026260e5d5Smrg    if (req_subsystem_type != -1 && req_subsystem_type != subsystem_type)
46036260e5d5Smrg        return -1;
46046260e5d5Smrg
46056260e5d5Smrg    switch (subsystem_type) {
46066260e5d5Smrg    case DRM_BUS_PCI:
46076260e5d5Smrg    case DRM_BUS_VIRTIO:
46086260e5d5Smrg        return drmProcessPciDevice(device, node, node_type, maj, min,
46096260e5d5Smrg                                   fetch_deviceinfo, flags);
46106260e5d5Smrg    case DRM_BUS_USB:
46116260e5d5Smrg        return drmProcessUsbDevice(device, node, node_type, maj, min,
46126260e5d5Smrg                                   fetch_deviceinfo, flags);
46136260e5d5Smrg    case DRM_BUS_PLATFORM:
46146260e5d5Smrg        return drmProcessPlatformDevice(device, node, node_type, maj, min,
46156260e5d5Smrg                                        fetch_deviceinfo, flags);
46166260e5d5Smrg    case DRM_BUS_HOST1X:
46176260e5d5Smrg        return drmProcessHost1xDevice(device, node, node_type, maj, min,
46186260e5d5Smrg                                      fetch_deviceinfo, flags);
46196260e5d5Smrg    default:
46206260e5d5Smrg        return -1;
46216260e5d5Smrg   }
46226260e5d5Smrg}
46236260e5d5Smrg
4624fe517fc9Smrg/* Consider devices located on the same bus as duplicate and fold the respective
4625fe517fc9Smrg * entries into a single one.
4626fe517fc9Smrg *
4627fe517fc9Smrg * Note: this leaves "gaps" in the array, while preserving the length.
4628fe517fc9Smrg */
4629fe517fc9Smrgstatic void drmFoldDuplicatedDevices(drmDevicePtr local_devices[], int count)
4630fe517fc9Smrg{
4631fe517fc9Smrg    int node_type, i, j;
4632fe517fc9Smrg
4633fe517fc9Smrg    for (i = 0; i < count; i++) {
4634fe517fc9Smrg        for (j = i + 1; j < count; j++) {
46350655efefSmrg            if (drmDevicesEqual(local_devices[i], local_devices[j])) {
4636fe517fc9Smrg                local_devices[i]->available_nodes |= local_devices[j]->available_nodes;
46374b3d3f37Smrg                node_type = log2_int(local_devices[j]->available_nodes);
4638fe517fc9Smrg                memcpy(local_devices[i]->nodes[node_type],
4639fe517fc9Smrg                       local_devices[j]->nodes[node_type], drmGetMaxNodeName());
4640fe517fc9Smrg                drmFreeDevice(&local_devices[j]);
4641fe517fc9Smrg            }
4642fe517fc9Smrg        }
4643fe517fc9Smrg    }
4644fe517fc9Smrg}
4645fe517fc9Smrg
46462ee35494Smrg/* Check that the given flags are valid returning 0 on success */
46472ee35494Smrgstatic int
46482ee35494Smrgdrm_device_validate_flags(uint32_t flags)
46492ee35494Smrg{
46502ee35494Smrg        return (flags & ~DRM_DEVICE_GET_PCI_REVISION);
46512ee35494Smrg}
46522ee35494Smrg
46536260e5d5Smrgstatic bool
46546260e5d5Smrgdrm_device_has_rdev(drmDevicePtr device, dev_t find_rdev)
46556260e5d5Smrg{
46566260e5d5Smrg    struct stat sbuf;
46576260e5d5Smrg
46586260e5d5Smrg    for (int i = 0; i < DRM_NODE_MAX; i++) {
46596260e5d5Smrg        if (device->available_nodes & 1 << i) {
46606260e5d5Smrg            if (stat(device->nodes[i], &sbuf) == 0 &&
46616260e5d5Smrg                sbuf.st_rdev == find_rdev)
46626260e5d5Smrg                return true;
46636260e5d5Smrg        }
46646260e5d5Smrg    }
46656260e5d5Smrg    return false;
46666260e5d5Smrg}
46676260e5d5Smrg
46686260e5d5Smrg/*
46696260e5d5Smrg * The kernel drm core has a number of places that assume maximum of
46706260e5d5Smrg * 3x64 devices nodes. That's 64 for each of primary, control and
46716260e5d5Smrg * render nodes. Rounded it up to 256 for simplicity.
46726260e5d5Smrg */
46736260e5d5Smrg#define MAX_DRM_NODES 256
46746260e5d5Smrg
4675fe517fc9Smrg/**
4676adfa0b0cSmrg * Get information about a device from its dev_t identifier
4677fe517fc9Smrg *
4678adfa0b0cSmrg * \param find_rdev dev_t identifier of the device
46792ee35494Smrg * \param flags feature/behaviour bitmask
4680fe517fc9Smrg * \param device the address of a drmDevicePtr where the information
4681fe517fc9Smrg *               will be allocated in stored
4682fe517fc9Smrg *
4683fe517fc9Smrg * \return zero on success, negative error code otherwise.
4684fe517fc9Smrg */
4685adfa0b0cSmrgdrm_public int drmGetDeviceFromDevId(dev_t find_rdev, uint32_t flags, drmDevicePtr *device)
4686fe517fc9Smrg{
46872ee35494Smrg#ifdef __OpenBSD__
46882ee35494Smrg    /*
46892ee35494Smrg     * DRI device nodes on OpenBSD are not in their own directory, they reside
46902ee35494Smrg     * in /dev along with a large number of statically generated /dev nodes.
46912ee35494Smrg     * Avoid stat'ing all of /dev needlessly by implementing this custom path.
46922ee35494Smrg     */
46932ee35494Smrg    drmDevicePtr     d;
46942ee35494Smrg    char             node[PATH_MAX + 1];
46952ee35494Smrg    const char      *dev_name;
46962ee35494Smrg    int              node_type, subsystem_type;
469782025ec7Smrg    int              maj, min, n, ret;
46982ee35494Smrg
4699adfa0b0cSmrg    if (device == NULL)
47002ee35494Smrg        return -EINVAL;
47012ee35494Smrg
4702adfa0b0cSmrg    maj = major(find_rdev);
4703adfa0b0cSmrg    min = minor(find_rdev);
47042ee35494Smrg
4705adfa0b0cSmrg    if (!drmNodeIsDRM(maj, min))
47062ee35494Smrg        return -EINVAL;
47072ee35494Smrg
470887bf8e7cSmrg    node_type = drmGetMinorType(maj, min);
47092ee35494Smrg    if (node_type == -1)
47102ee35494Smrg        return -ENODEV;
47112ee35494Smrg
471282025ec7Smrg    dev_name = drmGetDeviceName(node_type);
471382025ec7Smrg    if (!dev_name)
47142ee35494Smrg        return -EINVAL;
47152ee35494Smrg
471682025ec7Smrg    n = snprintf(node, PATH_MAX, dev_name, DRM_DIR_NAME, min);
47172ee35494Smrg    if (n == -1 || n >= PATH_MAX)
47182ee35494Smrg      return -errno;
47192ee35494Smrg    if (stat(node, &sbuf))
47202ee35494Smrg        return -EINVAL;
47212ee35494Smrg
47222ee35494Smrg    subsystem_type = drmParseSubsystemType(maj, min);
47232ee35494Smrg    if (subsystem_type != DRM_BUS_PCI)
47242ee35494Smrg        return -ENODEV;
47252ee35494Smrg
47262ee35494Smrg    ret = drmProcessPciDevice(&d, node, node_type, maj, min, true, flags);
47272ee35494Smrg    if (ret)
47282ee35494Smrg        return ret;
47292ee35494Smrg
47302ee35494Smrg    *device = d;
47312ee35494Smrg
47322ee35494Smrg    return 0;
47332ee35494Smrg#else
47346260e5d5Smrg    drmDevicePtr local_devices[MAX_DRM_NODES];
4735fe517fc9Smrg    drmDevicePtr d;
4736fe517fc9Smrg    DIR *sysdir;
4737fe517fc9Smrg    struct dirent *dent;
47386260e5d5Smrg    int subsystem_type;
4739fe517fc9Smrg    int maj, min;
4740fe517fc9Smrg    int ret, i, node_count;
4741fe517fc9Smrg
47422ee35494Smrg    if (drm_device_validate_flags(flags))
47432ee35494Smrg        return -EINVAL;
47442ee35494Smrg
4745adfa0b0cSmrg    if (device == NULL)
4746fe517fc9Smrg        return -EINVAL;
4747fe517fc9Smrg
4748adfa0b0cSmrg    maj = major(find_rdev);
4749adfa0b0cSmrg    min = minor(find_rdev);
4750fe517fc9Smrg
4751adfa0b0cSmrg    if (!drmNodeIsDRM(maj, min))
4752fe517fc9Smrg        return -EINVAL;
4753fe517fc9Smrg
4754fe517fc9Smrg    subsystem_type = drmParseSubsystemType(maj, min);
47556260e5d5Smrg    if (subsystem_type < 0)
47566260e5d5Smrg        return subsystem_type;
4757fe517fc9Smrg
4758fe517fc9Smrg    sysdir = opendir(DRM_DIR_NAME);
47596260e5d5Smrg    if (!sysdir)
47606260e5d5Smrg        return -errno;
4761fe517fc9Smrg
4762fe517fc9Smrg    i = 0;
4763fe517fc9Smrg    while ((dent = readdir(sysdir))) {
47646260e5d5Smrg        ret = process_device(&d, dent->d_name, subsystem_type, true, flags);
47656260e5d5Smrg        if (ret)
4766fe517fc9Smrg            continue;
4767fe517fc9Smrg
47686260e5d5Smrg        if (i >= MAX_DRM_NODES) {
47696260e5d5Smrg            fprintf(stderr, "More than %d drm nodes detected. "
47706260e5d5Smrg                    "Please report a bug - that should not happen.\n"
47716260e5d5Smrg                    "Skipping extra nodes\n", MAX_DRM_NODES);
4772fe517fc9Smrg            break;
4773fe517fc9Smrg        }
47746260e5d5Smrg        local_devices[i] = d;
4775fe517fc9Smrg        i++;
4776fe517fc9Smrg    }
4777fe517fc9Smrg    node_count = i;
4778fe517fc9Smrg
4779fe517fc9Smrg    drmFoldDuplicatedDevices(local_devices, node_count);
4780fe517fc9Smrg
47816260e5d5Smrg    *device = NULL;
47826260e5d5Smrg
47836260e5d5Smrg    for (i = 0; i < node_count; i++) {
47846260e5d5Smrg        if (!local_devices[i])
47856260e5d5Smrg            continue;
47866260e5d5Smrg
47876260e5d5Smrg        if (drm_device_has_rdev(local_devices[i], find_rdev))
47886260e5d5Smrg            *device = local_devices[i];
47896260e5d5Smrg        else
47906260e5d5Smrg            drmFreeDevice(&local_devices[i]);
47916260e5d5Smrg    }
4792fe517fc9Smrg
4793fe517fc9Smrg    closedir(sysdir);
47942ee35494Smrg    if (*device == NULL)
47952ee35494Smrg        return -ENODEV;
4796fe517fc9Smrg    return 0;
47972ee35494Smrg#endif
47982ee35494Smrg}
47992ee35494Smrg
4800adfa0b0cSmrg/**
4801adfa0b0cSmrg * Get information about the opened drm device
4802adfa0b0cSmrg *
4803adfa0b0cSmrg * \param fd file descriptor of the drm device
4804adfa0b0cSmrg * \param flags feature/behaviour bitmask
4805adfa0b0cSmrg * \param device the address of a drmDevicePtr where the information
4806adfa0b0cSmrg *               will be allocated in stored
4807adfa0b0cSmrg *
4808adfa0b0cSmrg * \return zero on success, negative error code otherwise.
4809adfa0b0cSmrg *
4810adfa0b0cSmrg * \note Unlike drmGetDevice it does not retrieve the pci device revision field
4811adfa0b0cSmrg * unless the DRM_DEVICE_GET_PCI_REVISION \p flag is set.
4812adfa0b0cSmrg */
4813adfa0b0cSmrgdrm_public int drmGetDevice2(int fd, uint32_t flags, drmDevicePtr *device)
4814adfa0b0cSmrg{
4815adfa0b0cSmrg    struct stat sbuf;
4816adfa0b0cSmrg
4817adfa0b0cSmrg    if (fd == -1)
4818adfa0b0cSmrg        return -EINVAL;
4819adfa0b0cSmrg
4820adfa0b0cSmrg    if (fstat(fd, &sbuf))
4821adfa0b0cSmrg        return -errno;
4822adfa0b0cSmrg
4823adfa0b0cSmrg    if (!S_ISCHR(sbuf.st_mode))
4824adfa0b0cSmrg        return -EINVAL;
4825adfa0b0cSmrg
4826adfa0b0cSmrg    return drmGetDeviceFromDevId(sbuf.st_rdev, flags, device);
4827adfa0b0cSmrg}
4828adfa0b0cSmrg
48292ee35494Smrg/**
48302ee35494Smrg * Get information about the opened drm device
48312ee35494Smrg *
48322ee35494Smrg * \param fd file descriptor of the drm device
48332ee35494Smrg * \param device the address of a drmDevicePtr where the information
48342ee35494Smrg *               will be allocated in stored
48352ee35494Smrg *
48362ee35494Smrg * \return zero on success, negative error code otherwise.
48372ee35494Smrg */
48386260e5d5Smrgdrm_public int drmGetDevice(int fd, drmDevicePtr *device)
48392ee35494Smrg{
48402ee35494Smrg    return drmGetDevice2(fd, DRM_DEVICE_GET_PCI_REVISION, device);
4841fe517fc9Smrg}
4842fe517fc9Smrg
4843fe517fc9Smrg/**
4844fe517fc9Smrg * Get drm devices on the system
4845fe517fc9Smrg *
48462ee35494Smrg * \param flags feature/behaviour bitmask
4847fe517fc9Smrg * \param devices the array of devices with drmDevicePtr elements
4848fe517fc9Smrg *                can be NULL to get the device number first
4849fe517fc9Smrg * \param max_devices the maximum number of devices for the array
4850fe517fc9Smrg *
4851fe517fc9Smrg * \return on error - negative error code,
4852fe517fc9Smrg *         if devices is NULL - total number of devices available on the system,
4853fe517fc9Smrg *         alternatively the number of devices stored in devices[], which is
4854fe517fc9Smrg *         capped by the max_devices.
48552ee35494Smrg *
48562ee35494Smrg * \note Unlike drmGetDevices it does not retrieve the pci device revision field
48572ee35494Smrg * unless the DRM_DEVICE_GET_PCI_REVISION \p flag is set.
4858fe517fc9Smrg */
48596260e5d5Smrgdrm_public int drmGetDevices2(uint32_t flags, drmDevicePtr devices[],
48606260e5d5Smrg                              int max_devices)
4861fe517fc9Smrg{
48626260e5d5Smrg    drmDevicePtr local_devices[MAX_DRM_NODES];
4863fe517fc9Smrg    drmDevicePtr device;
4864fe517fc9Smrg    DIR *sysdir;
4865fe517fc9Smrg    struct dirent *dent;
4866fe517fc9Smrg    int ret, i, node_count, device_count;
4867fe517fc9Smrg
48682ee35494Smrg    if (drm_device_validate_flags(flags))
48692ee35494Smrg        return -EINVAL;
48702ee35494Smrg
4871fe517fc9Smrg    sysdir = opendir(DRM_DIR_NAME);
48726260e5d5Smrg    if (!sysdir)
48736260e5d5Smrg        return -errno;
4874fe517fc9Smrg
4875fe517fc9Smrg    i = 0;
4876fe517fc9Smrg    while ((dent = readdir(sysdir))) {
48776260e5d5Smrg        ret = process_device(&device, dent->d_name, -1, devices != NULL, flags);
48786260e5d5Smrg        if (ret)
4879fe517fc9Smrg            continue;
4880fe517fc9Smrg
48816260e5d5Smrg        if (i >= MAX_DRM_NODES) {
48826260e5d5Smrg            fprintf(stderr, "More than %d drm nodes detected. "
48836260e5d5Smrg                    "Please report a bug - that should not happen.\n"
48846260e5d5Smrg                    "Skipping extra nodes\n", MAX_DRM_NODES);
48852ee35494Smrg            break;
4886fe517fc9Smrg        }
4887fe517fc9Smrg        local_devices[i] = device;
4888fe517fc9Smrg        i++;
4889fe517fc9Smrg    }
4890fe517fc9Smrg    node_count = i;
4891fe517fc9Smrg
4892fe517fc9Smrg    drmFoldDuplicatedDevices(local_devices, node_count);
4893fe517fc9Smrg
4894fe517fc9Smrg    device_count = 0;
4895fe517fc9Smrg    for (i = 0; i < node_count; i++) {
4896fe517fc9Smrg        if (!local_devices[i])
4897fe517fc9Smrg            continue;
4898fe517fc9Smrg
4899fe517fc9Smrg        if ((devices != NULL) && (device_count < max_devices))
4900fe517fc9Smrg            devices[device_count] = local_devices[i];
4901fe517fc9Smrg        else
4902fe517fc9Smrg            drmFreeDevice(&local_devices[i]);
4903fe517fc9Smrg
4904fe517fc9Smrg        device_count++;
4905fe517fc9Smrg    }
4906fe517fc9Smrg
4907fe517fc9Smrg    closedir(sysdir);
49084b3d3f37Smrg
49094b3d3f37Smrg    if (devices != NULL)
49104b3d3f37Smrg        return MIN2(device_count, max_devices);
49114b3d3f37Smrg
4912fe517fc9Smrg    return device_count;
4913424e9256Smrg}
49142ee35494Smrg
49152ee35494Smrg/**
49162ee35494Smrg * Get drm devices on the system
49172ee35494Smrg *
49182ee35494Smrg * \param devices the array of devices with drmDevicePtr elements
49192ee35494Smrg *                can be NULL to get the device number first
49202ee35494Smrg * \param max_devices the maximum number of devices for the array
49212ee35494Smrg *
49222ee35494Smrg * \return on error - negative error code,
49232ee35494Smrg *         if devices is NULL - total number of devices available on the system,
49242ee35494Smrg *         alternatively the number of devices stored in devices[], which is
49252ee35494Smrg *         capped by the max_devices.
49262ee35494Smrg */
49276260e5d5Smrgdrm_public int drmGetDevices(drmDevicePtr devices[], int max_devices)
49282ee35494Smrg{
49292ee35494Smrg    return drmGetDevices2(DRM_DEVICE_GET_PCI_REVISION, devices, max_devices);
49302ee35494Smrg}
49312ee35494Smrg
49326260e5d5Smrgdrm_public char *drmGetDeviceNameFromFd2(int fd)
49332ee35494Smrg{
49342ee35494Smrg#ifdef __linux__
49352ee35494Smrg    struct stat sbuf;
49362ee35494Smrg    char path[PATH_MAX + 1], *value;
49372ee35494Smrg    unsigned int maj, min;
49382ee35494Smrg
49392ee35494Smrg    if (fstat(fd, &sbuf))
49402ee35494Smrg        return NULL;
49412ee35494Smrg
49422ee35494Smrg    maj = major(sbuf.st_rdev);
49432ee35494Smrg    min = minor(sbuf.st_rdev);
49442ee35494Smrg
49456260e5d5Smrg    if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode))
49462ee35494Smrg        return NULL;
49472ee35494Smrg
49482ee35494Smrg    snprintf(path, sizeof(path), "/sys/dev/char/%d:%d", maj, min);
49492ee35494Smrg
49502ee35494Smrg    value = sysfs_uevent_get(path, "DEVNAME");
49512ee35494Smrg    if (!value)
49522ee35494Smrg        return NULL;
49532ee35494Smrg
49542ee35494Smrg    snprintf(path, sizeof(path), "/dev/%s", value);
49552ee35494Smrg    free(value);
49562ee35494Smrg
49572ee35494Smrg    return strdup(path);
49584b3d3f37Smrg#elif defined(__FreeBSD__)
495987bf8e7cSmrg    return drmGetDeviceNameFromFd(fd);
49602ee35494Smrg#else
49612ee35494Smrg    struct stat      sbuf;
49622ee35494Smrg    char             node[PATH_MAX + 1];
49632ee35494Smrg    const char      *dev_name;
49642ee35494Smrg    int              node_type;
496582025ec7Smrg    int              maj, min, n;
49662ee35494Smrg
49672ee35494Smrg    if (fstat(fd, &sbuf))
49682ee35494Smrg        return NULL;
49692ee35494Smrg
49702ee35494Smrg    maj = major(sbuf.st_rdev);
49712ee35494Smrg    min = minor(sbuf.st_rdev);
49722ee35494Smrg
49736260e5d5Smrg    if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode))
49742ee35494Smrg        return NULL;
49752ee35494Smrg
497687bf8e7cSmrg    node_type = drmGetMinorType(maj, min);
49772ee35494Smrg    if (node_type == -1)
49782ee35494Smrg        return NULL;
49792ee35494Smrg
498082025ec7Smrg    dev_name = drmGetDeviceName(node_type);
498182025ec7Smrg    if (!dev_name)
49822ee35494Smrg        return NULL;
49832ee35494Smrg
498482025ec7Smrg    n = snprintf(node, PATH_MAX, dev_name, DRM_DIR_NAME, min);
49852ee35494Smrg    if (n == -1 || n >= PATH_MAX)
49862ee35494Smrg      return NULL;
49872ee35494Smrg
49882ee35494Smrg    return strdup(node);
49892ee35494Smrg#endif
49902ee35494Smrg}
49910655efefSmrg
49926260e5d5Smrgdrm_public int drmSyncobjCreate(int fd, uint32_t flags, uint32_t *handle)
49930655efefSmrg{
49940655efefSmrg    struct drm_syncobj_create args;
49950655efefSmrg    int ret;
49960655efefSmrg
49970655efefSmrg    memclear(args);
49980655efefSmrg    args.flags = flags;
49990655efefSmrg    args.handle = 0;
50000655efefSmrg    ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_CREATE, &args);
50010655efefSmrg    if (ret)
50022b90624aSmrg        return ret;
50030655efefSmrg    *handle = args.handle;
50040655efefSmrg    return 0;
50050655efefSmrg}
50060655efefSmrg
50076260e5d5Smrgdrm_public int drmSyncobjDestroy(int fd, uint32_t handle)
50080655efefSmrg{
50090655efefSmrg    struct drm_syncobj_destroy args;
50100655efefSmrg
50110655efefSmrg    memclear(args);
50120655efefSmrg    args.handle = handle;
50130655efefSmrg    return drmIoctl(fd, DRM_IOCTL_SYNCOBJ_DESTROY, &args);
50140655efefSmrg}
50150655efefSmrg
50166260e5d5Smrgdrm_public int drmSyncobjHandleToFD(int fd, uint32_t handle, int *obj_fd)
50170655efefSmrg{
50180655efefSmrg    struct drm_syncobj_handle args;
50190655efefSmrg    int ret;
50200655efefSmrg
50210655efefSmrg    memclear(args);
50220655efefSmrg    args.fd = -1;
50230655efefSmrg    args.handle = handle;
50240655efefSmrg    ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD, &args);
50250655efefSmrg    if (ret)
50262b90624aSmrg        return ret;
50270655efefSmrg    *obj_fd = args.fd;
50280655efefSmrg    return 0;
50290655efefSmrg}
50300655efefSmrg
50316260e5d5Smrgdrm_public int drmSyncobjFDToHandle(int fd, int obj_fd, uint32_t *handle)
50320655efefSmrg{
50330655efefSmrg    struct drm_syncobj_handle args;
50340655efefSmrg    int ret;
50350655efefSmrg
50360655efefSmrg    memclear(args);
50370655efefSmrg    args.fd = obj_fd;
50380655efefSmrg    args.handle = 0;
50390655efefSmrg    ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE, &args);
50400655efefSmrg    if (ret)
50412b90624aSmrg        return ret;
50420655efefSmrg    *handle = args.handle;
50430655efefSmrg    return 0;
50440655efefSmrg}
50450655efefSmrg
50466260e5d5Smrgdrm_public int drmSyncobjImportSyncFile(int fd, uint32_t handle,
50476260e5d5Smrg                                        int sync_file_fd)
50480655efefSmrg{
50490655efefSmrg    struct drm_syncobj_handle args;
50500655efefSmrg
50510655efefSmrg    memclear(args);
50520655efefSmrg    args.fd = sync_file_fd;
50530655efefSmrg    args.handle = handle;
50540655efefSmrg    args.flags = DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_IMPORT_SYNC_FILE;
50550655efefSmrg    return drmIoctl(fd, DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE, &args);
50560655efefSmrg}
50570655efefSmrg
50586260e5d5Smrgdrm_public int drmSyncobjExportSyncFile(int fd, uint32_t handle,
50596260e5d5Smrg                                        int *sync_file_fd)
50600655efefSmrg{
50610655efefSmrg    struct drm_syncobj_handle args;
50620655efefSmrg    int ret;
50630655efefSmrg
50640655efefSmrg    memclear(args);
50650655efefSmrg    args.fd = -1;
50660655efefSmrg    args.handle = handle;
50670655efefSmrg    args.flags = DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_EXPORT_SYNC_FILE;
50680655efefSmrg    ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD, &args);
50690655efefSmrg    if (ret)
50702b90624aSmrg        return ret;
50710655efefSmrg    *sync_file_fd = args.fd;
50720655efefSmrg    return 0;
50730655efefSmrg}
50742b90624aSmrg
50756260e5d5Smrgdrm_public int drmSyncobjWait(int fd, uint32_t *handles, unsigned num_handles,
50766260e5d5Smrg                              int64_t timeout_nsec, unsigned flags,
50776260e5d5Smrg                              uint32_t *first_signaled)
50782b90624aSmrg{
50792b90624aSmrg    struct drm_syncobj_wait args;
50802b90624aSmrg    int ret;
50812b90624aSmrg
50822b90624aSmrg    memclear(args);
50832b90624aSmrg    args.handles = (uintptr_t)handles;
50842b90624aSmrg    args.timeout_nsec = timeout_nsec;
50852b90624aSmrg    args.count_handles = num_handles;
50862b90624aSmrg    args.flags = flags;
50872b90624aSmrg
50882b90624aSmrg    ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_WAIT, &args);
50892b90624aSmrg    if (ret < 0)
50902b90624aSmrg        return -errno;
50912b90624aSmrg
50922b90624aSmrg    if (first_signaled)
50932b90624aSmrg        *first_signaled = args.first_signaled;
50942b90624aSmrg    return ret;
50952b90624aSmrg}
50962b90624aSmrg
50976260e5d5Smrgdrm_public int drmSyncobjReset(int fd, const uint32_t *handles,
50986260e5d5Smrg                               uint32_t handle_count)
50992b90624aSmrg{
51002b90624aSmrg    struct drm_syncobj_array args;
51012b90624aSmrg    int ret;
51022b90624aSmrg
51032b90624aSmrg    memclear(args);
51042b90624aSmrg    args.handles = (uintptr_t)handles;
51052b90624aSmrg    args.count_handles = handle_count;
51062b90624aSmrg
51072b90624aSmrg    ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_RESET, &args);
51082b90624aSmrg    return ret;
51092b90624aSmrg}
51102b90624aSmrg
51116260e5d5Smrgdrm_public int drmSyncobjSignal(int fd, const uint32_t *handles,
51126260e5d5Smrg                                uint32_t handle_count)
51132b90624aSmrg{
51142b90624aSmrg    struct drm_syncobj_array args;
51152b90624aSmrg    int ret;
51162b90624aSmrg
51172b90624aSmrg    memclear(args);
51182b90624aSmrg    args.handles = (uintptr_t)handles;
51192b90624aSmrg    args.count_handles = handle_count;
51202b90624aSmrg
51212b90624aSmrg    ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_SIGNAL, &args);
51222b90624aSmrg    return ret;
51232b90624aSmrg}
5124bf6cc7dcSmrg
5125bf6cc7dcSmrgdrm_public int drmSyncobjTimelineSignal(int fd, const uint32_t *handles,
5126bf6cc7dcSmrg					uint64_t *points, uint32_t handle_count)
5127bf6cc7dcSmrg{
5128bf6cc7dcSmrg    struct drm_syncobj_timeline_array args;
5129bf6cc7dcSmrg    int ret;
5130bf6cc7dcSmrg
5131bf6cc7dcSmrg    memclear(args);
5132bf6cc7dcSmrg    args.handles = (uintptr_t)handles;
5133bf6cc7dcSmrg    args.points = (uintptr_t)points;
5134bf6cc7dcSmrg    args.count_handles = handle_count;
5135bf6cc7dcSmrg
5136bf6cc7dcSmrg    ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_TIMELINE_SIGNAL, &args);
5137bf6cc7dcSmrg    return ret;
5138bf6cc7dcSmrg}
5139bf6cc7dcSmrg
5140bf6cc7dcSmrgdrm_public int drmSyncobjTimelineWait(int fd, uint32_t *handles, uint64_t *points,
5141bf6cc7dcSmrg				      unsigned num_handles,
5142bf6cc7dcSmrg				      int64_t timeout_nsec, unsigned flags,
5143bf6cc7dcSmrg				      uint32_t *first_signaled)
5144bf6cc7dcSmrg{
5145bf6cc7dcSmrg    struct drm_syncobj_timeline_wait args;
5146bf6cc7dcSmrg    int ret;
5147bf6cc7dcSmrg
5148bf6cc7dcSmrg    memclear(args);
5149bf6cc7dcSmrg    args.handles = (uintptr_t)handles;
5150bf6cc7dcSmrg    args.points = (uintptr_t)points;
5151bf6cc7dcSmrg    args.timeout_nsec = timeout_nsec;
5152bf6cc7dcSmrg    args.count_handles = num_handles;
5153bf6cc7dcSmrg    args.flags = flags;
5154bf6cc7dcSmrg
5155bf6cc7dcSmrg    ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_TIMELINE_WAIT, &args);
5156bf6cc7dcSmrg    if (ret < 0)
5157bf6cc7dcSmrg        return -errno;
5158bf6cc7dcSmrg
5159bf6cc7dcSmrg    if (first_signaled)
5160bf6cc7dcSmrg        *first_signaled = args.first_signaled;
5161bf6cc7dcSmrg    return ret;
5162bf6cc7dcSmrg}
5163bf6cc7dcSmrg
5164bf6cc7dcSmrg
5165bf6cc7dcSmrgdrm_public int drmSyncobjQuery(int fd, uint32_t *handles, uint64_t *points,
5166bf6cc7dcSmrg			       uint32_t handle_count)
5167bf6cc7dcSmrg{
5168bf6cc7dcSmrg    struct drm_syncobj_timeline_array args;
5169bf6cc7dcSmrg    int ret;
5170bf6cc7dcSmrg
5171bf6cc7dcSmrg    memclear(args);
5172bf6cc7dcSmrg    args.handles = (uintptr_t)handles;
5173bf6cc7dcSmrg    args.points = (uintptr_t)points;
5174bf6cc7dcSmrg    args.count_handles = handle_count;
5175bf6cc7dcSmrg
5176bf6cc7dcSmrg    ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_QUERY, &args);
5177bf6cc7dcSmrg    if (ret)
5178bf6cc7dcSmrg        return ret;
5179bf6cc7dcSmrg    return 0;
5180bf6cc7dcSmrg}
5181bf6cc7dcSmrg
518287bf8e7cSmrgdrm_public int drmSyncobjQuery2(int fd, uint32_t *handles, uint64_t *points,
518387bf8e7cSmrg				uint32_t handle_count, uint32_t flags)
518487bf8e7cSmrg{
518587bf8e7cSmrg    struct drm_syncobj_timeline_array args;
518687bf8e7cSmrg
518787bf8e7cSmrg    memclear(args);
518887bf8e7cSmrg    args.handles = (uintptr_t)handles;
518987bf8e7cSmrg    args.points = (uintptr_t)points;
519087bf8e7cSmrg    args.count_handles = handle_count;
519187bf8e7cSmrg    args.flags = flags;
519287bf8e7cSmrg
519387bf8e7cSmrg    return drmIoctl(fd, DRM_IOCTL_SYNCOBJ_QUERY, &args);
519487bf8e7cSmrg}
519587bf8e7cSmrg
519687bf8e7cSmrg
5197bf6cc7dcSmrgdrm_public int drmSyncobjTransfer(int fd,
5198bf6cc7dcSmrg				  uint32_t dst_handle, uint64_t dst_point,
5199bf6cc7dcSmrg				  uint32_t src_handle, uint64_t src_point,
5200bf6cc7dcSmrg				  uint32_t flags)
5201bf6cc7dcSmrg{
5202bf6cc7dcSmrg    struct drm_syncobj_transfer args;
5203bf6cc7dcSmrg    int ret;
5204bf6cc7dcSmrg
5205bf6cc7dcSmrg    memclear(args);
5206bf6cc7dcSmrg    args.src_handle = src_handle;
5207bf6cc7dcSmrg    args.dst_handle = dst_handle;
5208bf6cc7dcSmrg    args.src_point = src_point;
5209bf6cc7dcSmrg    args.dst_point = dst_point;
5210bf6cc7dcSmrg    args.flags = flags;
5211bf6cc7dcSmrg
5212bf6cc7dcSmrg    ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_TRANSFER, &args);
5213bf6cc7dcSmrg
5214bf6cc7dcSmrg    return ret;
5215bf6cc7dcSmrg}
5216636d5e9fSmrg
5217636d5e9fSmrgstatic char *
5218636d5e9fSmrgdrmGetFormatModifierFromSimpleTokens(uint64_t modifier)
5219636d5e9fSmrg{
5220636d5e9fSmrg    unsigned int i;
5221636d5e9fSmrg
5222636d5e9fSmrg    for (i = 0; i < ARRAY_SIZE(drm_format_modifier_table); i++) {
5223636d5e9fSmrg        if (drm_format_modifier_table[i].modifier == modifier)
5224636d5e9fSmrg            return strdup(drm_format_modifier_table[i].modifier_name);
5225636d5e9fSmrg    }
5226636d5e9fSmrg
5227636d5e9fSmrg    return NULL;
5228636d5e9fSmrg}
5229636d5e9fSmrg
5230636d5e9fSmrg/** Retrieves a human-readable representation of a vendor (as a string) from
5231636d5e9fSmrg * the format token modifier
5232636d5e9fSmrg *
5233636d5e9fSmrg * \param modifier the format modifier token
5234636d5e9fSmrg * \return a char pointer to the human-readable form of the vendor. Caller is
5235636d5e9fSmrg * responsible for freeing it.
5236636d5e9fSmrg */
5237636d5e9fSmrgdrm_public char *
5238636d5e9fSmrgdrmGetFormatModifierVendor(uint64_t modifier)
5239636d5e9fSmrg{
5240636d5e9fSmrg    unsigned int i;
5241636d5e9fSmrg    uint8_t vendor = fourcc_mod_get_vendor(modifier);
5242636d5e9fSmrg
5243636d5e9fSmrg    for (i = 0; i < ARRAY_SIZE(drm_format_modifier_vendor_table); i++) {
5244636d5e9fSmrg        if (drm_format_modifier_vendor_table[i].vendor == vendor)
5245636d5e9fSmrg            return strdup(drm_format_modifier_vendor_table[i].vendor_name);
5246636d5e9fSmrg    }
5247636d5e9fSmrg
5248636d5e9fSmrg    return NULL;
5249636d5e9fSmrg}
5250636d5e9fSmrg
5251636d5e9fSmrg/** Retrieves a human-readable representation string from a format token
5252636d5e9fSmrg * modifier
5253636d5e9fSmrg *
5254636d5e9fSmrg * If the dedicated function was not able to extract a valid name or searching
5255636d5e9fSmrg * the format modifier was not in the table, this function would return NULL.
5256636d5e9fSmrg *
5257636d5e9fSmrg * \param modifier the token format
5258636d5e9fSmrg * \return a malloc'ed string representation of the modifier. Caller is
5259636d5e9fSmrg * responsible for freeing the string returned.
5260636d5e9fSmrg *
5261636d5e9fSmrg */
5262636d5e9fSmrgdrm_public char *
5263636d5e9fSmrgdrmGetFormatModifierName(uint64_t modifier)
5264636d5e9fSmrg{
5265636d5e9fSmrg    uint8_t vendorid = fourcc_mod_get_vendor(modifier);
5266636d5e9fSmrg    char *modifier_found = NULL;
5267636d5e9fSmrg    unsigned int i;
5268636d5e9fSmrg
5269636d5e9fSmrg    for (i = 0; i < ARRAY_SIZE(modifier_format_vendor_table); i++) {
5270636d5e9fSmrg        if (modifier_format_vendor_table[i].vendor == vendorid)
5271636d5e9fSmrg            modifier_found = modifier_format_vendor_table[i].vendor_cb(modifier);
5272636d5e9fSmrg    }
5273636d5e9fSmrg
5274636d5e9fSmrg    if (!modifier_found)
5275636d5e9fSmrg        return drmGetFormatModifierFromSimpleTokens(modifier);
5276636d5e9fSmrg
5277636d5e9fSmrg    return modifier_found;
5278636d5e9fSmrg}
5279