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