xf86drm.c revision 82025ec7
122944501Smrg/**
2fe517fc9Smrg * \file xf86drm.c
322944501Smrg * User-level interface to DRM device
422944501Smrg *
522944501Smrg * \author Rickard E. (Rik) Faith <faith@valinux.com>
622944501Smrg * \author Kevin E. Martin <martin@valinux.com>
722944501Smrg */
822944501Smrg
922944501Smrg/*
1022944501Smrg * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
1122944501Smrg * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
1222944501Smrg * All Rights Reserved.
1322944501Smrg *
1422944501Smrg * Permission is hereby granted, free of charge, to any person obtaining a
1522944501Smrg * copy of this software and associated documentation files (the "Software"),
1622944501Smrg * to deal in the Software without restriction, including without limitation
1722944501Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
1822944501Smrg * and/or sell copies of the Software, and to permit persons to whom the
1922944501Smrg * Software is furnished to do so, subject to the following conditions:
2022944501Smrg *
2122944501Smrg * The above copyright notice and this permission notice (including the next
2222944501Smrg * paragraph) shall be included in all copies or substantial portions of the
2322944501Smrg * Software.
2422944501Smrg *
2522944501Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2622944501Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2722944501Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
2822944501Smrg * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
2922944501Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
3022944501Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
3122944501Smrg * DEALINGS IN THE SOFTWARE.
3222944501Smrg */
3322944501Smrg
3422944501Smrg#include <stdio.h>
3522944501Smrg#include <stdlib.h>
36fe517fc9Smrg#include <stdbool.h>
3722944501Smrg#include <unistd.h>
3822944501Smrg#include <string.h>
3922944501Smrg#include <strings.h>
4022944501Smrg#include <ctype.h>
41424e9256Smrg#include <dirent.h>
42424e9256Smrg#include <stddef.h>
4322944501Smrg#include <fcntl.h>
4422944501Smrg#include <errno.h>
45fe517fc9Smrg#include <limits.h>
4622944501Smrg#include <signal.h>
4722944501Smrg#include <time.h>
4822944501Smrg#include <sys/types.h>
4922944501Smrg#include <sys/stat.h>
5022944501Smrg#define stat_t struct stat
5122944501Smrg#include <sys/ioctl.h>
5222944501Smrg#include <sys/time.h>
5322944501Smrg#include <stdarg.h>
54fe517fc9Smrg#ifdef MAJOR_IN_MKDEV
55fe517fc9Smrg#include <sys/mkdev.h>
56424e9256Smrg#endif
57fe517fc9Smrg#ifdef MAJOR_IN_SYSMACROS
58fe517fc9Smrg#include <sys/sysmacros.h>
59fe517fc9Smrg#endif
60fe517fc9Smrg#include <math.h>
6122944501Smrg
624545e80cSmrg#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
634545e80cSmrg
642ee35494Smrg/* Not all systems have MAP_FAILED defined */
652ee35494Smrg#ifndef MAP_FAILED
662ee35494Smrg#define MAP_FAILED ((void *)-1)
672ee35494Smrg#endif
6822944501Smrg
6922944501Smrg#include "xf86drm.h"
70424e9256Smrg#include "libdrm_macros.h"
7122944501Smrg
72fe517fc9Smrg#include "util_math.h"
73fe517fc9Smrg
7422944501Smrg#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
7522944501Smrg#define DRM_MAJOR 145
7622944501Smrg#endif
7722944501Smrg
7822944501Smrg#ifdef __NetBSD__
792e6867f6Smrg#undef DRM_MAJOR
802e6867f6Smrg#define DRM_MAJOR 180
8106815bcbSmaya#include <sys/param.h>
82a970b457Sriastradh#include <dev/pci/pcireg.h>
83a970b457Sriastradh#include <pci.h>
8422944501Smrg#endif
8522944501Smrg
86fe517fc9Smrg#ifdef __OpenBSD__
87fe517fc9Smrg#ifdef __i386__
88fe517fc9Smrg#define DRM_MAJOR 88
89fe517fc9Smrg#else
90fe517fc9Smrg#define DRM_MAJOR 87
9122944501Smrg#endif
92fe517fc9Smrg#endif /* __OpenBSD__ */
9322944501Smrg
94fe517fc9Smrg#ifndef DRM_MAJOR
95fe517fc9Smrg#define DRM_MAJOR 226 /* Linux */
9622944501Smrg#endif
9722944501Smrg
984545e80cSmrg#if defined(__OpenBSD__) || defined(__DragonFly__)
992ee35494Smrgstruct drm_pciinfo {
1002ee35494Smrg	uint16_t	domain;
1012ee35494Smrg	uint8_t		bus;
1022ee35494Smrg	uint8_t		dev;
1032ee35494Smrg	uint8_t		func;
1042ee35494Smrg	uint16_t	vendor_id;
1052ee35494Smrg	uint16_t	device_id;
1062ee35494Smrg	uint16_t	subvendor_id;
1072ee35494Smrg	uint16_t	subdevice_id;
1082ee35494Smrg	uint8_t		revision_id;
1092ee35494Smrg};
1102ee35494Smrg
1112ee35494Smrg#define DRM_IOCTL_GET_PCIINFO	DRM_IOR(0x15, struct drm_pciinfo)
11211c53d23Schristos#endif
11311c53d23Schristos
11422944501Smrg#define DRM_MSG_VERBOSITY 3
11522944501Smrg
116424e9256Smrg#define memclear(s) memset(&s, 0, sizeof(s))
11722944501Smrg
11822944501Smrgstatic drmServerInfoPtr drm_server_info;
11922944501Smrg
1206260e5d5Smrgdrm_public void drmSetServerInfo(drmServerInfoPtr info)
12122944501Smrg{
12222944501Smrg    drm_server_info = info;
12322944501Smrg}
12422944501Smrg
12522944501Smrg/**
12622944501Smrg * Output a message to stderr.
12722944501Smrg *
12822944501Smrg * \param format printf() like format string.
12922944501Smrg *
13022944501Smrg * \internal
13122944501Smrg * This function is a wrapper around vfprintf().
13222944501Smrg */
13322944501Smrg
134a7d7de1eSmrgstatic int DRM_PRINTFLIKE(1, 0)
135a7d7de1eSmrgdrmDebugPrint(const char *format, va_list ap)
13622944501Smrg{
13722944501Smrg    return vfprintf(stderr, format, ap);
13822944501Smrg}
13922944501Smrg
1406260e5d5Smrgdrm_public void
14122944501SmrgdrmMsg(const char *format, ...)
14222944501Smrg{
143fe517fc9Smrg    va_list ap;
14422944501Smrg    const char *env;
145fe517fc9Smrg    if (((env = getenv("LIBGL_DEBUG")) && strstr(env, "verbose")) ||
146fe517fc9Smrg        (drm_server_info && drm_server_info->debug_print))
14722944501Smrg    {
148fe517fc9Smrg        va_start(ap, format);
149fe517fc9Smrg        if (drm_server_info) {
150fe517fc9Smrg            drm_server_info->debug_print(format,ap);
151fe517fc9Smrg        } else {
152fe517fc9Smrg            drmDebugPrint(format, ap);
153fe517fc9Smrg        }
154fe517fc9Smrg        va_end(ap);
15522944501Smrg    }
15622944501Smrg}
15722944501Smrg
15822944501Smrgstatic void *drmHashTable = NULL; /* Context switch callbacks */
15922944501Smrg
1606260e5d5Smrgdrm_public void *drmGetHashTable(void)
16122944501Smrg{
16222944501Smrg    return drmHashTable;
16322944501Smrg}
16422944501Smrg
1656260e5d5Smrgdrm_public void *drmMalloc(int size)
16622944501Smrg{
167424e9256Smrg    return calloc(1, size);
16822944501Smrg}
16922944501Smrg
1706260e5d5Smrgdrm_public void drmFree(void *pt)
17122944501Smrg{
172424e9256Smrg    free(pt);
17322944501Smrg}
17422944501Smrg
17522944501Smrg/**
176bf6cc7dcSmrg * Call ioctl, restarting if it is interrupted
17722944501Smrg */
1786260e5d5Smrgdrm_public int
17922944501SmrgdrmIoctl(int fd, unsigned long request, void *arg)
18022944501Smrg{
181fe517fc9Smrg    int ret;
18222944501Smrg
18322944501Smrg    do {
184fe517fc9Smrg        ret = ioctl(fd, request, arg);
18522944501Smrg    } while (ret == -1 && (errno == EINTR || errno == EAGAIN));
18622944501Smrg    return ret;
18722944501Smrg}
18822944501Smrg
18922944501Smrgstatic unsigned long drmGetKeyFromFd(int fd)
19022944501Smrg{
19122944501Smrg    stat_t     st;
19222944501Smrg
19322944501Smrg    st.st_rdev = 0;
19422944501Smrg    fstat(fd, &st);
19522944501Smrg    return st.st_rdev;
19622944501Smrg}
19722944501Smrg
1986260e5d5Smrgdrm_public drmHashEntry *drmGetEntry(int fd)
19922944501Smrg{
20022944501Smrg    unsigned long key = drmGetKeyFromFd(fd);
20122944501Smrg    void          *value;
20222944501Smrg    drmHashEntry  *entry;
20322944501Smrg
20422944501Smrg    if (!drmHashTable)
205fe517fc9Smrg        drmHashTable = drmHashCreate();
20622944501Smrg
20722944501Smrg    if (drmHashLookup(drmHashTable, key, &value)) {
208fe517fc9Smrg        entry           = drmMalloc(sizeof(*entry));
209fe517fc9Smrg        entry->fd       = fd;
210fe517fc9Smrg        entry->f        = NULL;
211fe517fc9Smrg        entry->tagTable = drmHashCreate();
212fe517fc9Smrg        drmHashInsert(drmHashTable, key, entry);
21322944501Smrg    } else {
214fe517fc9Smrg        entry = value;
21522944501Smrg    }
21622944501Smrg    return entry;
21722944501Smrg}
21822944501Smrg
21922944501Smrg/**
22022944501Smrg * Compare two busid strings
22122944501Smrg *
22222944501Smrg * \param first
22322944501Smrg * \param second
22422944501Smrg *
22522944501Smrg * \return 1 if matched.
22622944501Smrg *
22722944501Smrg * \internal
22822944501Smrg * This function compares two bus ID strings.  It understands the older
22922944501Smrg * PCI:b:d:f format and the newer pci:oooo:bb:dd.f format.  In the format, o is
23022944501Smrg * domain, b is bus, d is device, f is function.
23122944501Smrg */
2326d98c517Smrgstatic int drmMatchBusID(const char *id1, const char *id2, int pci_domain_ok)
23322944501Smrg{
23422944501Smrg    /* First, check if the IDs are exactly the same */
23522944501Smrg    if (strcasecmp(id1, id2) == 0)
236fe517fc9Smrg        return 1;
23722944501Smrg
23822944501Smrg    /* Try to match old/new-style PCI bus IDs. */
23922944501Smrg    if (strncasecmp(id1, "pci", 3) == 0) {
240fe517fc9Smrg        unsigned int o1, b1, d1, f1;
241fe517fc9Smrg        unsigned int o2, b2, d2, f2;
242fe517fc9Smrg        int ret;
243fe517fc9Smrg
244fe517fc9Smrg        ret = sscanf(id1, "pci:%04x:%02x:%02x.%u", &o1, &b1, &d1, &f1);
245fe517fc9Smrg        if (ret != 4) {
246fe517fc9Smrg            o1 = 0;
247fe517fc9Smrg            ret = sscanf(id1, "PCI:%u:%u:%u", &b1, &d1, &f1);
248fe517fc9Smrg            if (ret != 3)
249fe517fc9Smrg                return 0;
250fe517fc9Smrg        }
251fe517fc9Smrg
252fe517fc9Smrg        ret = sscanf(id2, "pci:%04x:%02x:%02x.%u", &o2, &b2, &d2, &f2);
253fe517fc9Smrg        if (ret != 4) {
254fe517fc9Smrg            o2 = 0;
255fe517fc9Smrg            ret = sscanf(id2, "PCI:%u:%u:%u", &b2, &d2, &f2);
256fe517fc9Smrg            if (ret != 3)
257fe517fc9Smrg                return 0;
258fe517fc9Smrg        }
259fe517fc9Smrg
260fe517fc9Smrg        /* If domains aren't properly supported by the kernel interface,
261fe517fc9Smrg         * just ignore them, which sucks less than picking a totally random
262fe517fc9Smrg         * card with "open by name"
263fe517fc9Smrg         */
264fe517fc9Smrg        if (!pci_domain_ok)
265fe517fc9Smrg            o1 = o2 = 0;
266fe517fc9Smrg
267fe517fc9Smrg        if ((o1 != o2) || (b1 != b2) || (d1 != d2) || (f1 != f2))
268fe517fc9Smrg            return 0;
269fe517fc9Smrg        else
270fe517fc9Smrg            return 1;
27122944501Smrg    }
27222944501Smrg    return 0;
27322944501Smrg}
27422944501Smrg
27522944501Smrg/**
27622944501Smrg * Handles error checking for chown call.
27722944501Smrg *
27822944501Smrg * \param path to file.
27922944501Smrg * \param id of the new owner.
28022944501Smrg * \param id of the new group.
28122944501Smrg *
28222944501Smrg * \return zero if success or -1 if failure.
28322944501Smrg *
28422944501Smrg * \internal
28522944501Smrg * Checks for failure. If failure was caused by signal call chown again.
286bf6cc7dcSmrg * If any other failure happened then it will output error message using
28722944501Smrg * drmMsg() call.
28822944501Smrg */
2896260e5d5Smrg#if !UDEV
29022944501Smrgstatic int chown_check_return(const char *path, uid_t owner, gid_t group)
29122944501Smrg{
292fe517fc9Smrg        int rv;
29322944501Smrg
294fe517fc9Smrg        do {
295fe517fc9Smrg            rv = chown(path, owner, group);
296fe517fc9Smrg        } while (rv != 0 && errno == EINTR);
29722944501Smrg
298fe517fc9Smrg        if (rv == 0)
299fe517fc9Smrg            return 0;
30022944501Smrg
301fe517fc9Smrg        drmMsg("Failed to change owner or group for file %s! %d: %s\n",
302fe517fc9Smrg               path, errno, strerror(errno));
303fe517fc9Smrg        return -1;
30422944501Smrg}
305424e9256Smrg#endif
30622944501Smrg
30782025ec7Smrgstatic const char *drmGetDeviceName(int type)
30882025ec7Smrg{
30982025ec7Smrg    switch (type) {
31082025ec7Smrg    case DRM_NODE_PRIMARY:
31182025ec7Smrg        return DRM_DEV_NAME;
31282025ec7Smrg    case DRM_NODE_CONTROL:
31382025ec7Smrg        return DRM_CONTROL_DEV_NAME;
31482025ec7Smrg    case DRM_NODE_RENDER:
31582025ec7Smrg        return DRM_RENDER_DEV_NAME;
31682025ec7Smrg    }
31782025ec7Smrg    return NULL;
31882025ec7Smrg}
31982025ec7Smrg
32022944501Smrg/**
32122944501Smrg * Open the DRM device, creating it if necessary.
32222944501Smrg *
32322944501Smrg * \param dev major and minor numbers of the device.
32422944501Smrg * \param minor minor number of the device.
325fe517fc9Smrg *
32622944501Smrg * \return a file descriptor on success, or a negative value on error.
32722944501Smrg *
32822944501Smrg * \internal
32922944501Smrg * Assembles the device name from \p minor and opens it, creating the device
33022944501Smrg * special file node with the major and minor numbers specified by \p dev and
33122944501Smrg * parent directory if necessary and was called by root.
33222944501Smrg */
333424e9256Smrgstatic int drmOpenDevice(dev_t dev, int minor, int type)
33422944501Smrg{
33522944501Smrg    stat_t          st;
33682025ec7Smrg    const char      *dev_name = drmGetDeviceName(type);
33782025ec7Smrg    char            buf[DRM_NODE_NAME_MAX];
33822944501Smrg    int             fd;
33922944501Smrg    mode_t          devmode = DRM_DEV_MODE, serv_mode;
340424e9256Smrg    gid_t           serv_group;
3416260e5d5Smrg#if !UDEV
34222944501Smrg    int             isroot  = !geteuid();
34322944501Smrg    uid_t           user    = DRM_DEV_UID;
344424e9256Smrg    gid_t           group   = DRM_DEV_GID;
345424e9256Smrg#endif
346424e9256Smrg
34782025ec7Smrg    if (!dev_name)
348fe517fc9Smrg        return -EINVAL;
349424e9256Smrg
350424e9256Smrg    sprintf(buf, dev_name, DRM_DIR_NAME, minor);
35122944501Smrg    drmMsg("drmOpenDevice: node name is %s\n", buf);
35222944501Smrg
353fe517fc9Smrg    if (drm_server_info && drm_server_info->get_perms) {
354fe517fc9Smrg        drm_server_info->get_perms(&serv_group, &serv_mode);
355fe517fc9Smrg        devmode  = serv_mode ? serv_mode : DRM_DEV_MODE;
356fe517fc9Smrg        devmode &= ~(S_IXUSR|S_IXGRP|S_IXOTH);
35722944501Smrg    }
35822944501Smrg
3596260e5d5Smrg#if !UDEV
36022944501Smrg    if (stat(DRM_DIR_NAME, &st)) {
361fe517fc9Smrg        if (!isroot)
362fe517fc9Smrg            return DRM_ERR_NOT_ROOT;
363fe517fc9Smrg        mkdir(DRM_DIR_NAME, DRM_DEV_DIRMODE);
364fe517fc9Smrg        chown_check_return(DRM_DIR_NAME, 0, 0); /* root:root */
365fe517fc9Smrg        chmod(DRM_DIR_NAME, DRM_DEV_DIRMODE);
36622944501Smrg    }
36722944501Smrg
36822944501Smrg    /* Check if the device node exists and create it if necessary. */
36922944501Smrg    if (stat(buf, &st)) {
370fe517fc9Smrg        if (!isroot)
371fe517fc9Smrg            return DRM_ERR_NOT_ROOT;
372fe517fc9Smrg        remove(buf);
373fe517fc9Smrg        mknod(buf, S_IFCHR | devmode, dev);
37422944501Smrg    }
37522944501Smrg
376fe517fc9Smrg    if (drm_server_info && drm_server_info->get_perms) {
377fe517fc9Smrg        group = ((int)serv_group >= 0) ? serv_group : DRM_DEV_GID;
378fe517fc9Smrg        chown_check_return(buf, user, group);
379fe517fc9Smrg        chmod(buf, devmode);
38022944501Smrg    }
38122944501Smrg#else
38222944501Smrg    /* if we modprobed then wait for udev */
38322944501Smrg    {
384fe517fc9Smrg        int udev_count = 0;
38522944501Smrgwait_for_udev:
38622944501Smrg        if (stat(DRM_DIR_NAME, &st)) {
387fe517fc9Smrg            usleep(20);
388fe517fc9Smrg            udev_count++;
389fe517fc9Smrg
390fe517fc9Smrg            if (udev_count == 50)
391fe517fc9Smrg                return -1;
392fe517fc9Smrg            goto wait_for_udev;
393fe517fc9Smrg        }
394fe517fc9Smrg
395fe517fc9Smrg        if (stat(buf, &st)) {
396fe517fc9Smrg            usleep(20);
397fe517fc9Smrg            udev_count++;
398fe517fc9Smrg
399fe517fc9Smrg            if (udev_count == 50)
400fe517fc9Smrg                return -1;
401fe517fc9Smrg            goto wait_for_udev;
402fe517fc9Smrg        }
40322944501Smrg    }
40422944501Smrg#endif
40522944501Smrg
4066260e5d5Smrg    fd = open(buf, O_RDWR | O_CLOEXEC, 0);
40722944501Smrg    drmMsg("drmOpenDevice: open result is %d, (%s)\n",
408fe517fc9Smrg           fd, fd < 0 ? strerror(errno) : "OK");
40922944501Smrg    if (fd >= 0)
410fe517fc9Smrg        return fd;
41122944501Smrg
4126260e5d5Smrg#if !UDEV
41322944501Smrg    /* Check if the device node is not what we expect it to be, and recreate it
41422944501Smrg     * and try again if so.
41522944501Smrg     */
41622944501Smrg    if (st.st_rdev != dev) {
417fe517fc9Smrg        if (!isroot)
418fe517fc9Smrg            return DRM_ERR_NOT_ROOT;
419fe517fc9Smrg        remove(buf);
420fe517fc9Smrg        mknod(buf, S_IFCHR | devmode, dev);
421fe517fc9Smrg        if (drm_server_info && drm_server_info->get_perms) {
422fe517fc9Smrg            chown_check_return(buf, user, group);
423fe517fc9Smrg            chmod(buf, devmode);
424fe517fc9Smrg        }
42522944501Smrg    }
4266260e5d5Smrg    fd = open(buf, O_RDWR | O_CLOEXEC, 0);
42722944501Smrg    drmMsg("drmOpenDevice: open result is %d, (%s)\n",
428fe517fc9Smrg           fd, fd < 0 ? strerror(errno) : "OK");
42922944501Smrg    if (fd >= 0)
430fe517fc9Smrg        return fd;
43122944501Smrg
43222944501Smrg    drmMsg("drmOpenDevice: Open failed\n");
43322944501Smrg    remove(buf);
4349ce4edccSmrg#endif
43522944501Smrg    return -errno;
43622944501Smrg}
43722944501Smrg
43822944501Smrg
43922944501Smrg/**
44022944501Smrg * Open the DRM device
44122944501Smrg *
44222944501Smrg * \param minor device minor number.
44322944501Smrg * \param create allow to create the device if set.
44422944501Smrg *
44522944501Smrg * \return a file descriptor on success, or a negative value on error.
446fe517fc9Smrg *
44722944501Smrg * \internal
44822944501Smrg * Calls drmOpenDevice() if \p create is set, otherwise assembles the device
44922944501Smrg * name from \p minor and opens it.
45022944501Smrg */
45122944501Smrgstatic int drmOpenMinor(int minor, int create, int type)
45222944501Smrg{
45322944501Smrg    int  fd;
45482025ec7Smrg    char buf[DRM_NODE_NAME_MAX];
45582025ec7Smrg    const char *dev_name = drmGetDeviceName(type);
456fe517fc9Smrg
45722944501Smrg    if (create)
458fe517fc9Smrg        return drmOpenDevice(makedev(DRM_MAJOR, minor), minor, type);
459fe517fc9Smrg
46082025ec7Smrg    if (!dev_name)
461fe517fc9Smrg        return -EINVAL;
462424e9256Smrg
463424e9256Smrg    sprintf(buf, dev_name, DRM_DIR_NAME, minor);
4646260e5d5Smrg    if ((fd = open(buf, O_RDWR | O_CLOEXEC, 0)) >= 0)
465fe517fc9Smrg        return fd;
46622944501Smrg    return -errno;
46722944501Smrg}
46822944501Smrg
46922944501Smrg
47022944501Smrg/**
47122944501Smrg * Determine whether the DRM kernel driver has been loaded.
472fe517fc9Smrg *
47322944501Smrg * \return 1 if the DRM driver is loaded, 0 otherwise.
47422944501Smrg *
475fe517fc9Smrg * \internal
47622944501Smrg * Determine the presence of the kernel driver by attempting to open the 0
47722944501Smrg * minor and get version information.  For backward compatibility with older
47822944501Smrg * Linux implementations, /proc/dri is also checked.
47922944501Smrg */
4806260e5d5Smrgdrm_public int drmAvailable(void)
48122944501Smrg{
48222944501Smrg    drmVersionPtr version;
48322944501Smrg    int           retval = 0;
48422944501Smrg    int           fd;
48522944501Smrg
486424e9256Smrg    if ((fd = drmOpenMinor(0, 1, DRM_NODE_PRIMARY)) < 0) {
48722944501Smrg#ifdef __linux__
488fe517fc9Smrg        /* Try proc for backward Linux compatibility */
489fe517fc9Smrg        if (!access("/proc/dri/0", R_OK))
490fe517fc9Smrg            return 1;
49122944501Smrg#endif
492fe517fc9Smrg        return 0;
49322944501Smrg    }
494fe517fc9Smrg
49522944501Smrg    if ((version = drmGetVersion(fd))) {
496fe517fc9Smrg        retval = 1;
497fe517fc9Smrg        drmFreeVersion(version);
49822944501Smrg    }
49922944501Smrg    close(fd);
50022944501Smrg
50122944501Smrg    return retval;
50222944501Smrg}
50322944501Smrg
504424e9256Smrgstatic int drmGetMinorBase(int type)
505424e9256Smrg{
506424e9256Smrg    switch (type) {
507424e9256Smrg    case DRM_NODE_PRIMARY:
508424e9256Smrg        return 0;
509424e9256Smrg    case DRM_NODE_CONTROL:
510424e9256Smrg        return 64;
511424e9256Smrg    case DRM_NODE_RENDER:
512424e9256Smrg        return 128;
513424e9256Smrg    default:
514424e9256Smrg        return -1;
515424e9256Smrg    };
516424e9256Smrg}
517424e9256Smrg
518424e9256Smrgstatic int drmGetMinorType(int minor)
519424e9256Smrg{
520424e9256Smrg    int type = minor >> 6;
521424e9256Smrg
522424e9256Smrg    if (minor < 0)
523424e9256Smrg        return -1;
524424e9256Smrg
525424e9256Smrg    switch (type) {
526424e9256Smrg    case DRM_NODE_PRIMARY:
527424e9256Smrg    case DRM_NODE_CONTROL:
528424e9256Smrg    case DRM_NODE_RENDER:
529424e9256Smrg        return type;
530424e9256Smrg    default:
531424e9256Smrg        return -1;
532424e9256Smrg    }
533424e9256Smrg}
534424e9256Smrg
535424e9256Smrgstatic const char *drmGetMinorName(int type)
536424e9256Smrg{
537424e9256Smrg    switch (type) {
538424e9256Smrg    case DRM_NODE_PRIMARY:
539fe517fc9Smrg        return DRM_PRIMARY_MINOR_NAME;
540424e9256Smrg    case DRM_NODE_CONTROL:
541fe517fc9Smrg        return DRM_CONTROL_MINOR_NAME;
542424e9256Smrg    case DRM_NODE_RENDER:
543fe517fc9Smrg        return DRM_RENDER_MINOR_NAME;
544424e9256Smrg    default:
545424e9256Smrg        return NULL;
546424e9256Smrg    }
547424e9256Smrg}
54822944501Smrg
54922944501Smrg/**
55022944501Smrg * Open the device by bus ID.
55122944501Smrg *
55222944501Smrg * \param busid bus ID.
553424e9256Smrg * \param type device node type.
55422944501Smrg *
55522944501Smrg * \return a file descriptor on success, or a negative value on error.
55622944501Smrg *
55722944501Smrg * \internal
55822944501Smrg * This function attempts to open every possible minor (up to DRM_MAX_MINOR),
55922944501Smrg * comparing the device bus ID with the one supplied.
56022944501Smrg *
56122944501Smrg * \sa drmOpenMinor() and drmGetBusid().
56222944501Smrg */
563424e9256Smrgstatic int drmOpenByBusid(const char *busid, int type)
56422944501Smrg{
5656d98c517Smrg    int        i, pci_domain_ok = 1;
56622944501Smrg    int        fd;
56722944501Smrg    const char *buf;
56822944501Smrg    drmSetVersion sv;
569424e9256Smrg    int        base = drmGetMinorBase(type);
570424e9256Smrg
571424e9256Smrg    if (base < 0)
572424e9256Smrg        return -1;
57322944501Smrg
57422944501Smrg    drmMsg("drmOpenByBusid: Searching for BusID %s\n", busid);
575424e9256Smrg    for (i = base; i < base + DRM_MAX_MINOR; i++) {
576fe517fc9Smrg        fd = drmOpenMinor(i, 1, type);
577fe517fc9Smrg        drmMsg("drmOpenByBusid: drmOpenMinor returns %d\n", fd);
578fe517fc9Smrg        if (fd >= 0) {
579fe517fc9Smrg            /* We need to try for 1.4 first for proper PCI domain support
580fe517fc9Smrg             * and if that fails, we know the kernel is busted
581fe517fc9Smrg             */
582fe517fc9Smrg            sv.drm_di_major = 1;
583fe517fc9Smrg            sv.drm_di_minor = 4;
584fe517fc9Smrg            sv.drm_dd_major = -1;        /* Don't care */
585fe517fc9Smrg            sv.drm_dd_minor = -1;        /* Don't care */
586fe517fc9Smrg            if (drmSetInterfaceVersion(fd, &sv)) {
5876d98c517Smrg#ifndef __alpha__
588fe517fc9Smrg                pci_domain_ok = 0;
5896d98c517Smrg#endif
590fe517fc9Smrg                sv.drm_di_major = 1;
591fe517fc9Smrg                sv.drm_di_minor = 1;
592fe517fc9Smrg                sv.drm_dd_major = -1;       /* Don't care */
593fe517fc9Smrg                sv.drm_dd_minor = -1;       /* Don't care */
594fe517fc9Smrg                drmMsg("drmOpenByBusid: Interface 1.4 failed, trying 1.1\n");
595fe517fc9Smrg                drmSetInterfaceVersion(fd, &sv);
596fe517fc9Smrg            }
597fe517fc9Smrg            buf = drmGetBusid(fd);
598fe517fc9Smrg            drmMsg("drmOpenByBusid: drmGetBusid reports %s\n", buf);
599fe517fc9Smrg            if (buf && drmMatchBusID(buf, busid, pci_domain_ok)) {
600fe517fc9Smrg                drmFreeBusid(buf);
601fe517fc9Smrg                return fd;
602fe517fc9Smrg            }
603fe517fc9Smrg            if (buf)
604fe517fc9Smrg                drmFreeBusid(buf);
605fe517fc9Smrg            close(fd);
606fe517fc9Smrg        }
60722944501Smrg    }
60822944501Smrg    return -1;
60922944501Smrg}
61022944501Smrg
61122944501Smrg
61222944501Smrg/**
61322944501Smrg * Open the device by name.
61422944501Smrg *
61522944501Smrg * \param name driver name.
616424e9256Smrg * \param type the device node type.
617fe517fc9Smrg *
61822944501Smrg * \return a file descriptor on success, or a negative value on error.
619fe517fc9Smrg *
62022944501Smrg * \internal
62122944501Smrg * This function opens the first minor number that matches the driver name and
62222944501Smrg * isn't already in use.  If it's in use it then it will already have a bus ID
62322944501Smrg * assigned.
624fe517fc9Smrg *
62522944501Smrg * \sa drmOpenMinor(), drmGetVersion() and drmGetBusid().
62622944501Smrg */
627424e9256Smrgstatic int drmOpenByName(const char *name, int type)
62822944501Smrg{
62922944501Smrg    int           i;
63022944501Smrg    int           fd;
63122944501Smrg    drmVersionPtr version;
63222944501Smrg    char *        id;
633424e9256Smrg    int           base = drmGetMinorBase(type);
634424e9256Smrg
635424e9256Smrg    if (base < 0)
636424e9256Smrg        return -1;
63722944501Smrg
63822944501Smrg    /*
63922944501Smrg     * Open the first minor number that matches the driver name and isn't
64022944501Smrg     * already in use.  If it's in use it will have a busid assigned already.
64122944501Smrg     */
642424e9256Smrg    for (i = base; i < base + DRM_MAX_MINOR; i++) {
643fe517fc9Smrg        if ((fd = drmOpenMinor(i, 1, type)) >= 0) {
644fe517fc9Smrg            if ((version = drmGetVersion(fd))) {
645fe517fc9Smrg                if (!strcmp(version->name, name)) {
646fe517fc9Smrg                    drmFreeVersion(version);
647fe517fc9Smrg                    id = drmGetBusid(fd);
648fe517fc9Smrg                    drmMsg("drmGetBusid returned '%s'\n", id ? id : "NULL");
649fe517fc9Smrg                    if (!id || !*id) {
650fe517fc9Smrg                        if (id)
651fe517fc9Smrg                            drmFreeBusid(id);
652fe517fc9Smrg                        return fd;
653fe517fc9Smrg                    } else {
654fe517fc9Smrg                        drmFreeBusid(id);
655fe517fc9Smrg                    }
656fe517fc9Smrg                } else {
657fe517fc9Smrg                    drmFreeVersion(version);
658fe517fc9Smrg                }
659fe517fc9Smrg            }
660fe517fc9Smrg            close(fd);
661fe517fc9Smrg        }
66222944501Smrg    }
66322944501Smrg
66422944501Smrg#ifdef __linux__
66522944501Smrg    /* Backward-compatibility /proc support */
66622944501Smrg    for (i = 0; i < 8; i++) {
667fe517fc9Smrg        char proc_name[64], buf[512];
668fe517fc9Smrg        char *driver, *pt, *devstring;
669fe517fc9Smrg        int  retcode;
670fe517fc9Smrg
671fe517fc9Smrg        sprintf(proc_name, "/proc/dri/%d/name", i);
672fe517fc9Smrg        if ((fd = open(proc_name, 0, 0)) >= 0) {
673fe517fc9Smrg            retcode = read(fd, buf, sizeof(buf)-1);
674fe517fc9Smrg            close(fd);
675fe517fc9Smrg            if (retcode) {
676fe517fc9Smrg                buf[retcode-1] = '\0';
677fe517fc9Smrg                for (driver = pt = buf; *pt && *pt != ' '; ++pt)
678fe517fc9Smrg                    ;
679fe517fc9Smrg                if (*pt) { /* Device is next */
680fe517fc9Smrg                    *pt = '\0';
681fe517fc9Smrg                    if (!strcmp(driver, name)) { /* Match */
682fe517fc9Smrg                        for (devstring = ++pt; *pt && *pt != ' '; ++pt)
683fe517fc9Smrg                            ;
684fe517fc9Smrg                        if (*pt) { /* Found busid */
685fe517fc9Smrg                            return drmOpenByBusid(++pt, type);
686fe517fc9Smrg                        } else { /* No busid */
687fe517fc9Smrg                            return drmOpenDevice(strtol(devstring, NULL, 0),i, type);
688fe517fc9Smrg                        }
689fe517fc9Smrg                    }
690fe517fc9Smrg                }
691fe517fc9Smrg            }
692fe517fc9Smrg        }
69322944501Smrg    }
69422944501Smrg#endif
69522944501Smrg
69622944501Smrg    return -1;
69722944501Smrg}
69822944501Smrg
69922944501Smrg
70022944501Smrg/**
70122944501Smrg * Open the DRM device.
70222944501Smrg *
70322944501Smrg * Looks up the specified name and bus ID, and opens the device found.  The
70422944501Smrg * entry in /dev/dri is created if necessary and if called by root.
70522944501Smrg *
70622944501Smrg * \param name driver name. Not referenced if bus ID is supplied.
70722944501Smrg * \param busid bus ID. Zero if not known.
708fe517fc9Smrg *
70922944501Smrg * \return a file descriptor on success, or a negative value on error.
710fe517fc9Smrg *
71122944501Smrg * \internal
71222944501Smrg * It calls drmOpenByBusid() if \p busid is specified or drmOpenByName()
71322944501Smrg * otherwise.
71422944501Smrg */
7156260e5d5Smrgdrm_public int drmOpen(const char *name, const char *busid)
716424e9256Smrg{
717424e9256Smrg    return drmOpenWithType(name, busid, DRM_NODE_PRIMARY);
718424e9256Smrg}
719424e9256Smrg
720424e9256Smrg/**
721424e9256Smrg * Open the DRM device with specified type.
722424e9256Smrg *
723424e9256Smrg * Looks up the specified name and bus ID, and opens the device found.  The
724424e9256Smrg * entry in /dev/dri is created if necessary and if called by root.
725424e9256Smrg *
726424e9256Smrg * \param name driver name. Not referenced if bus ID is supplied.
727424e9256Smrg * \param busid bus ID. Zero if not known.
728424e9256Smrg * \param type the device node type to open, PRIMARY, CONTROL or RENDER
729424e9256Smrg *
730424e9256Smrg * \return a file descriptor on success, or a negative value on error.
731424e9256Smrg *
732424e9256Smrg * \internal
733424e9256Smrg * It calls drmOpenByBusid() if \p busid is specified or drmOpenByName()
734424e9256Smrg * otherwise.
735424e9256Smrg */
7366260e5d5Smrgdrm_public int drmOpenWithType(const char *name, const char *busid, int type)
73722944501Smrg{
738bf6cc7dcSmrg    if (name != NULL && drm_server_info &&
739bf6cc7dcSmrg        drm_server_info->load_module && !drmAvailable()) {
740fe517fc9Smrg        /* try to load the kernel module */
741fe517fc9Smrg        if (!drm_server_info->load_module(name)) {
742fe517fc9Smrg            drmMsg("[drm] failed to load kernel module \"%s\"\n", name);
743fe517fc9Smrg            return -1;
744fe517fc9Smrg        }
74522944501Smrg    }
74622944501Smrg
74722944501Smrg    if (busid) {
748fe517fc9Smrg        int fd = drmOpenByBusid(busid, type);
749fe517fc9Smrg        if (fd >= 0)
750fe517fc9Smrg            return fd;
75122944501Smrg    }
752fe517fc9Smrg
75322944501Smrg    if (name)
754fe517fc9Smrg        return drmOpenByName(name, type);
75522944501Smrg
75622944501Smrg    return -1;
75722944501Smrg}
75822944501Smrg
7596260e5d5Smrgdrm_public int drmOpenControl(int minor)
76022944501Smrg{
76122944501Smrg    return drmOpenMinor(minor, 0, DRM_NODE_CONTROL);
76222944501Smrg}
76322944501Smrg
7646260e5d5Smrgdrm_public int drmOpenRender(int minor)
765424e9256Smrg{
766424e9256Smrg    return drmOpenMinor(minor, 0, DRM_NODE_RENDER);
767424e9256Smrg}
768424e9256Smrg
76922944501Smrg/**
77022944501Smrg * Free the version information returned by drmGetVersion().
77122944501Smrg *
77222944501Smrg * \param v pointer to the version information.
77322944501Smrg *
77422944501Smrg * \internal
77522944501Smrg * It frees the memory pointed by \p %v as well as all the non-null strings
77622944501Smrg * pointers in it.
77722944501Smrg */
7786260e5d5Smrgdrm_public void drmFreeVersion(drmVersionPtr v)
77922944501Smrg{
78022944501Smrg    if (!v)
781fe517fc9Smrg        return;
78222944501Smrg    drmFree(v->name);
78322944501Smrg    drmFree(v->date);
78422944501Smrg    drmFree(v->desc);
78522944501Smrg    drmFree(v);
78622944501Smrg}
78722944501Smrg
78822944501Smrg
78922944501Smrg/**
79022944501Smrg * Free the non-public version information returned by the kernel.
79122944501Smrg *
79222944501Smrg * \param v pointer to the version information.
79322944501Smrg *
79422944501Smrg * \internal
79522944501Smrg * Used by drmGetVersion() to free the memory pointed by \p %v as well as all
79622944501Smrg * the non-null strings pointers in it.
79722944501Smrg */
79822944501Smrgstatic void drmFreeKernelVersion(drm_version_t *v)
79922944501Smrg{
80022944501Smrg    if (!v)
801fe517fc9Smrg        return;
80222944501Smrg    drmFree(v->name);
80322944501Smrg    drmFree(v->date);
80422944501Smrg    drmFree(v->desc);
80522944501Smrg    drmFree(v);
80622944501Smrg}
80722944501Smrg
80822944501Smrg
80922944501Smrg/**
81022944501Smrg * Copy version information.
811fe517fc9Smrg *
81222944501Smrg * \param d destination pointer.
81322944501Smrg * \param s source pointer.
814fe517fc9Smrg *
81522944501Smrg * \internal
81622944501Smrg * Used by drmGetVersion() to translate the information returned by the ioctl
81722944501Smrg * interface in a private structure into the public structure counterpart.
81822944501Smrg */
81922944501Smrgstatic void drmCopyVersion(drmVersionPtr d, const drm_version_t *s)
82022944501Smrg{
82122944501Smrg    d->version_major      = s->version_major;
82222944501Smrg    d->version_minor      = s->version_minor;
82322944501Smrg    d->version_patchlevel = s->version_patchlevel;
82422944501Smrg    d->name_len           = s->name_len;
8259ce4edccSmrg    d->name               = strdup(s->name);
82622944501Smrg    d->date_len           = s->date_len;
8279ce4edccSmrg    d->date               = strdup(s->date);
82822944501Smrg    d->desc_len           = s->desc_len;
8299ce4edccSmrg    d->desc               = strdup(s->desc);
83022944501Smrg}
83122944501Smrg
83222944501Smrg
83322944501Smrg/**
83422944501Smrg * Query the driver version information.
83522944501Smrg *
83622944501Smrg * \param fd file descriptor.
837fe517fc9Smrg *
83822944501Smrg * \return pointer to a drmVersion structure which should be freed with
83922944501Smrg * drmFreeVersion().
840fe517fc9Smrg *
84122944501Smrg * \note Similar information is available via /proc/dri.
842fe517fc9Smrg *
84322944501Smrg * \internal
84422944501Smrg * It gets the version information via successive DRM_IOCTL_VERSION ioctls,
84522944501Smrg * first with zeros to get the string lengths, and then the actually strings.
84622944501Smrg * It also null-terminates them since they might not be already.
84722944501Smrg */
8486260e5d5Smrgdrm_public drmVersionPtr drmGetVersion(int fd)
84922944501Smrg{
85022944501Smrg    drmVersionPtr retval;
85122944501Smrg    drm_version_t *version = drmMalloc(sizeof(*version));
85222944501Smrg
85322944501Smrg    if (drmIoctl(fd, DRM_IOCTL_VERSION, version)) {
854fe517fc9Smrg        drmFreeKernelVersion(version);
855fe517fc9Smrg        return NULL;
85622944501Smrg    }
85722944501Smrg
85822944501Smrg    if (version->name_len)
859fe517fc9Smrg        version->name    = drmMalloc(version->name_len + 1);
86022944501Smrg    if (version->date_len)
861fe517fc9Smrg        version->date    = drmMalloc(version->date_len + 1);
86222944501Smrg    if (version->desc_len)
863fe517fc9Smrg        version->desc    = drmMalloc(version->desc_len + 1);
86422944501Smrg
86522944501Smrg    if (drmIoctl(fd, DRM_IOCTL_VERSION, version)) {
866fe517fc9Smrg        drmMsg("DRM_IOCTL_VERSION: %s\n", strerror(errno));
867fe517fc9Smrg        drmFreeKernelVersion(version);
868fe517fc9Smrg        return NULL;
86922944501Smrg    }
87022944501Smrg
87122944501Smrg    /* The results might not be null-terminated strings, so terminate them. */
87222944501Smrg    if (version->name_len) version->name[version->name_len] = '\0';
87322944501Smrg    if (version->date_len) version->date[version->date_len] = '\0';
87422944501Smrg    if (version->desc_len) version->desc[version->desc_len] = '\0';
87522944501Smrg
87622944501Smrg    retval = drmMalloc(sizeof(*retval));
87722944501Smrg    drmCopyVersion(retval, version);
87822944501Smrg    drmFreeKernelVersion(version);
87922944501Smrg    return retval;
88022944501Smrg}
88122944501Smrg
88222944501Smrg
88322944501Smrg/**
88422944501Smrg * Get version information for the DRM user space library.
885fe517fc9Smrg *
88622944501Smrg * This version number is driver independent.
887fe517fc9Smrg *
88822944501Smrg * \param fd file descriptor.
88922944501Smrg *
89022944501Smrg * \return version information.
891fe517fc9Smrg *
89222944501Smrg * \internal
89322944501Smrg * This function allocates and fills a drm_version structure with a hard coded
89422944501Smrg * version number.
89522944501Smrg */
8966260e5d5Smrgdrm_public drmVersionPtr drmGetLibVersion(int fd)
89722944501Smrg{
89822944501Smrg    drm_version_t *version = drmMalloc(sizeof(*version));
89922944501Smrg
90022944501Smrg    /* Version history:
90122944501Smrg     *   NOTE THIS MUST NOT GO ABOVE VERSION 1.X due to drivers needing it
90222944501Smrg     *   revision 1.0.x = original DRM interface with no drmGetLibVersion
90322944501Smrg     *                    entry point and many drm<Device> extensions
90422944501Smrg     *   revision 1.1.x = added drmCommand entry points for device extensions
90522944501Smrg     *                    added drmGetLibVersion to identify libdrm.a version
90622944501Smrg     *   revision 1.2.x = added drmSetInterfaceVersion
90722944501Smrg     *                    modified drmOpen to handle both busid and name
90822944501Smrg     *   revision 1.3.x = added server + memory manager
90922944501Smrg     */
91022944501Smrg    version->version_major      = 1;
91122944501Smrg    version->version_minor      = 3;
91222944501Smrg    version->version_patchlevel = 0;
91322944501Smrg
91422944501Smrg    return (drmVersionPtr)version;
91522944501Smrg}
91622944501Smrg
9176260e5d5Smrgdrm_public int drmGetCap(int fd, uint64_t capability, uint64_t *value)
91820131375Smrg{
919fe517fc9Smrg    struct drm_get_cap cap;
920fe517fc9Smrg    int ret;
92120131375Smrg
922fe517fc9Smrg    memclear(cap);
923fe517fc9Smrg    cap.capability = capability;
924424e9256Smrg
925fe517fc9Smrg    ret = drmIoctl(fd, DRM_IOCTL_GET_CAP, &cap);
926fe517fc9Smrg    if (ret)
927fe517fc9Smrg        return ret;
92820131375Smrg
929fe517fc9Smrg    *value = cap.value;
930fe517fc9Smrg    return 0;
93120131375Smrg}
93220131375Smrg
9336260e5d5Smrgdrm_public int drmSetClientCap(int fd, uint64_t capability, uint64_t value)
93420131375Smrg{
935fe517fc9Smrg    struct drm_set_client_cap cap;
936424e9256Smrg
937fe517fc9Smrg    memclear(cap);
938fe517fc9Smrg    cap.capability = capability;
939fe517fc9Smrg    cap.value = value;
94020131375Smrg
941fe517fc9Smrg    return drmIoctl(fd, DRM_IOCTL_SET_CLIENT_CAP, &cap);
94220131375Smrg}
94322944501Smrg
94422944501Smrg/**
94522944501Smrg * Free the bus ID information.
94622944501Smrg *
94722944501Smrg * \param busid bus ID information string as given by drmGetBusid().
94822944501Smrg *
94922944501Smrg * \internal
95022944501Smrg * This function is just frees the memory pointed by \p busid.
95122944501Smrg */
9526260e5d5Smrgdrm_public void drmFreeBusid(const char *busid)
95322944501Smrg{
95422944501Smrg    drmFree((void *)busid);
95522944501Smrg}
95622944501Smrg
95722944501Smrg
95822944501Smrg/**
95922944501Smrg * Get the bus ID of the device.
96022944501Smrg *
96122944501Smrg * \param fd file descriptor.
96222944501Smrg *
96322944501Smrg * \return bus ID string.
96422944501Smrg *
96522944501Smrg * \internal
96622944501Smrg * This function gets the bus ID via successive DRM_IOCTL_GET_UNIQUE ioctls to
96722944501Smrg * get the string length and data, passing the arguments in a drm_unique
96822944501Smrg * structure.
96922944501Smrg */
9706260e5d5Smrgdrm_public char *drmGetBusid(int fd)
97122944501Smrg{
97222944501Smrg    drm_unique_t u;
97322944501Smrg
974424e9256Smrg    memclear(u);
97522944501Smrg
97622944501Smrg    if (drmIoctl(fd, DRM_IOCTL_GET_UNIQUE, &u))
977fe517fc9Smrg        return NULL;
97822944501Smrg    u.unique = drmMalloc(u.unique_len + 1);
9790655efefSmrg    if (drmIoctl(fd, DRM_IOCTL_GET_UNIQUE, &u)) {
9800655efefSmrg        drmFree(u.unique);
981fe517fc9Smrg        return NULL;
9820655efefSmrg    }
98322944501Smrg    u.unique[u.unique_len] = '\0';
98422944501Smrg
98522944501Smrg    return u.unique;
98622944501Smrg}
98722944501Smrg
98822944501Smrg
98922944501Smrg/**
99022944501Smrg * Set the bus ID of the device.
99122944501Smrg *
99222944501Smrg * \param fd file descriptor.
99322944501Smrg * \param busid bus ID string.
99422944501Smrg *
99522944501Smrg * \return zero on success, negative on failure.
99622944501Smrg *
99722944501Smrg * \internal
99822944501Smrg * This function is a wrapper around the DRM_IOCTL_SET_UNIQUE ioctl, passing
99922944501Smrg * the arguments in a drm_unique structure.
100022944501Smrg */
10016260e5d5Smrgdrm_public int drmSetBusid(int fd, const char *busid)
100222944501Smrg{
100322944501Smrg    drm_unique_t u;
100422944501Smrg
1005424e9256Smrg    memclear(u);
100622944501Smrg    u.unique     = (char *)busid;
100722944501Smrg    u.unique_len = strlen(busid);
100822944501Smrg
100922944501Smrg    if (drmIoctl(fd, DRM_IOCTL_SET_UNIQUE, &u)) {
1010fe517fc9Smrg        return -errno;
101122944501Smrg    }
101222944501Smrg    return 0;
101322944501Smrg}
101422944501Smrg
10156260e5d5Smrgdrm_public int drmGetMagic(int fd, drm_magic_t * magic)
101622944501Smrg{
101722944501Smrg    drm_auth_t auth;
101822944501Smrg
1019424e9256Smrg    memclear(auth);
1020424e9256Smrg
102122944501Smrg    *magic = 0;
102222944501Smrg    if (drmIoctl(fd, DRM_IOCTL_GET_MAGIC, &auth))
1023fe517fc9Smrg        return -errno;
102422944501Smrg    *magic = auth.magic;
102522944501Smrg    return 0;
102622944501Smrg}
102722944501Smrg
10286260e5d5Smrgdrm_public int drmAuthMagic(int fd, drm_magic_t magic)
102922944501Smrg{
103022944501Smrg    drm_auth_t auth;
103122944501Smrg
1032424e9256Smrg    memclear(auth);
103322944501Smrg    auth.magic = magic;
103422944501Smrg    if (drmIoctl(fd, DRM_IOCTL_AUTH_MAGIC, &auth))
1035fe517fc9Smrg        return -errno;
103622944501Smrg    return 0;
103722944501Smrg}
103822944501Smrg
103922944501Smrg/**
104022944501Smrg * Specifies a range of memory that is available for mapping by a
104122944501Smrg * non-root process.
104222944501Smrg *
104322944501Smrg * \param fd file descriptor.
104422944501Smrg * \param offset usually the physical address. The actual meaning depends of
104522944501Smrg * the \p type parameter. See below.
104622944501Smrg * \param size of the memory in bytes.
104722944501Smrg * \param type type of the memory to be mapped.
104822944501Smrg * \param flags combination of several flags to modify the function actions.
104922944501Smrg * \param handle will be set to a value that may be used as the offset
105022944501Smrg * parameter for mmap().
1051fe517fc9Smrg *
105222944501Smrg * \return zero on success or a negative value on error.
105322944501Smrg *
105422944501Smrg * \par Mapping the frame buffer
105522944501Smrg * For the frame buffer
105622944501Smrg * - \p offset will be the physical address of the start of the frame buffer,
105722944501Smrg * - \p size will be the size of the frame buffer in bytes, and
105822944501Smrg * - \p type will be DRM_FRAME_BUFFER.
105922944501Smrg *
106022944501Smrg * \par
106122944501Smrg * The area mapped will be uncached. If MTRR support is available in the
1062fe517fc9Smrg * kernel, the frame buffer area will be set to write combining.
106322944501Smrg *
106422944501Smrg * \par Mapping the MMIO register area
106522944501Smrg * For the MMIO register area,
106622944501Smrg * - \p offset will be the physical address of the start of the register area,
106722944501Smrg * - \p size will be the size of the register area bytes, and
106822944501Smrg * - \p type will be DRM_REGISTERS.
106922944501Smrg * \par
1070fe517fc9Smrg * The area mapped will be uncached.
1071fe517fc9Smrg *
107222944501Smrg * \par Mapping the SAREA
107322944501Smrg * For the SAREA,
107422944501Smrg * - \p offset will be ignored and should be set to zero,
107522944501Smrg * - \p size will be the desired size of the SAREA in bytes,
107622944501Smrg * - \p type will be DRM_SHM.
1077fe517fc9Smrg *
107822944501Smrg * \par
107922944501Smrg * A shared memory area of the requested size will be created and locked in
108022944501Smrg * kernel memory. This area may be mapped into client-space by using the handle
1081fe517fc9Smrg * returned.
1082fe517fc9Smrg *
108322944501Smrg * \note May only be called by root.
108422944501Smrg *
108522944501Smrg * \internal
108622944501Smrg * This function is a wrapper around the DRM_IOCTL_ADD_MAP ioctl, passing
108722944501Smrg * the arguments in a drm_map structure.
108822944501Smrg */
10896260e5d5Smrgdrm_public int drmAddMap(int fd, drm_handle_t offset, drmSize size, drmMapType type,
10906260e5d5Smrg                         drmMapFlags flags, drm_handle_t *handle)
109122944501Smrg{
109222944501Smrg    drm_map_t map;
109322944501Smrg
1094424e9256Smrg    memclear(map);
109522944501Smrg    map.offset  = offset;
109622944501Smrg    map.size    = size;
109722944501Smrg    map.type    = type;
109822944501Smrg    map.flags   = flags;
109922944501Smrg    if (drmIoctl(fd, DRM_IOCTL_ADD_MAP, &map))
1100fe517fc9Smrg        return -errno;
110122944501Smrg    if (handle)
1102fe517fc9Smrg        *handle = (drm_handle_t)(uintptr_t)map.handle;
110322944501Smrg    return 0;
110422944501Smrg}
110522944501Smrg
11066260e5d5Smrgdrm_public int drmRmMap(int fd, drm_handle_t handle)
110722944501Smrg{
110822944501Smrg    drm_map_t map;
110922944501Smrg
1110424e9256Smrg    memclear(map);
111120131375Smrg    map.handle = (void *)(uintptr_t)handle;
111222944501Smrg
111322944501Smrg    if(drmIoctl(fd, DRM_IOCTL_RM_MAP, &map))
1114fe517fc9Smrg        return -errno;
111522944501Smrg    return 0;
111622944501Smrg}
111722944501Smrg
111822944501Smrg/**
111922944501Smrg * Make buffers available for DMA transfers.
1120fe517fc9Smrg *
112122944501Smrg * \param fd file descriptor.
112222944501Smrg * \param count number of buffers.
112322944501Smrg * \param size size of each buffer.
112422944501Smrg * \param flags buffer allocation flags.
1125fe517fc9Smrg * \param agp_offset offset in the AGP aperture
112622944501Smrg *
112722944501Smrg * \return number of buffers allocated, negative on error.
112822944501Smrg *
112922944501Smrg * \internal
113022944501Smrg * This function is a wrapper around DRM_IOCTL_ADD_BUFS ioctl.
113122944501Smrg *
113222944501Smrg * \sa drm_buf_desc.
113322944501Smrg */
11346260e5d5Smrgdrm_public int drmAddBufs(int fd, int count, int size, drmBufDescFlags flags,
11356260e5d5Smrg                          int agp_offset)
113622944501Smrg{
113722944501Smrg    drm_buf_desc_t request;
113822944501Smrg
1139424e9256Smrg    memclear(request);
114022944501Smrg    request.count     = count;
114122944501Smrg    request.size      = size;
114222944501Smrg    request.flags     = flags;
114322944501Smrg    request.agp_start = agp_offset;
114422944501Smrg
114522944501Smrg    if (drmIoctl(fd, DRM_IOCTL_ADD_BUFS, &request))
1146fe517fc9Smrg        return -errno;
114722944501Smrg    return request.count;
114822944501Smrg}
114922944501Smrg
11506260e5d5Smrgdrm_public int drmMarkBufs(int fd, double low, double high)
115122944501Smrg{
115222944501Smrg    drm_buf_info_t info;
115322944501Smrg    int            i;
115422944501Smrg
1155424e9256Smrg    memclear(info);
115622944501Smrg
115722944501Smrg    if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info))
1158fe517fc9Smrg        return -EINVAL;
115922944501Smrg
116022944501Smrg    if (!info.count)
1161fe517fc9Smrg        return -EINVAL;
116222944501Smrg
116322944501Smrg    if (!(info.list = drmMalloc(info.count * sizeof(*info.list))))
1164fe517fc9Smrg        return -ENOMEM;
116522944501Smrg
116622944501Smrg    if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info)) {
1167fe517fc9Smrg        int retval = -errno;
1168fe517fc9Smrg        drmFree(info.list);
1169fe517fc9Smrg        return retval;
117022944501Smrg    }
117122944501Smrg
117222944501Smrg    for (i = 0; i < info.count; i++) {
1173fe517fc9Smrg        info.list[i].low_mark  = low  * info.list[i].count;
1174fe517fc9Smrg        info.list[i].high_mark = high * info.list[i].count;
1175fe517fc9Smrg        if (drmIoctl(fd, DRM_IOCTL_MARK_BUFS, &info.list[i])) {
1176fe517fc9Smrg            int retval = -errno;
1177fe517fc9Smrg            drmFree(info.list);
1178fe517fc9Smrg            return retval;
1179fe517fc9Smrg        }
118022944501Smrg    }
118122944501Smrg    drmFree(info.list);
118222944501Smrg
118322944501Smrg    return 0;
118422944501Smrg}
118522944501Smrg
118622944501Smrg/**
118722944501Smrg * Free buffers.
118822944501Smrg *
118922944501Smrg * \param fd file descriptor.
119022944501Smrg * \param count number of buffers to free.
119122944501Smrg * \param list list of buffers to be freed.
119222944501Smrg *
119322944501Smrg * \return zero on success, or a negative value on failure.
1194fe517fc9Smrg *
119522944501Smrg * \note This function is primarily used for debugging.
1196fe517fc9Smrg *
119722944501Smrg * \internal
119822944501Smrg * This function is a wrapper around the DRM_IOCTL_FREE_BUFS ioctl, passing
119922944501Smrg * the arguments in a drm_buf_free structure.
120022944501Smrg */
12016260e5d5Smrgdrm_public int drmFreeBufs(int fd, int count, int *list)
120222944501Smrg{
120322944501Smrg    drm_buf_free_t request;
120422944501Smrg
1205424e9256Smrg    memclear(request);
120622944501Smrg    request.count = count;
120722944501Smrg    request.list  = list;
120822944501Smrg    if (drmIoctl(fd, DRM_IOCTL_FREE_BUFS, &request))
1209fe517fc9Smrg        return -errno;
121022944501Smrg    return 0;
121122944501Smrg}
121222944501Smrg
121322944501Smrg
121422944501Smrg/**
121522944501Smrg * Close the device.
121622944501Smrg *
121722944501Smrg * \param fd file descriptor.
121822944501Smrg *
121922944501Smrg * \internal
122022944501Smrg * This function closes the file descriptor.
122122944501Smrg */
12226260e5d5Smrgdrm_public int drmClose(int fd)
122322944501Smrg{
122422944501Smrg    unsigned long key    = drmGetKeyFromFd(fd);
122522944501Smrg    drmHashEntry  *entry = drmGetEntry(fd);
122622944501Smrg
122722944501Smrg    drmHashDestroy(entry->tagTable);
122822944501Smrg    entry->fd       = 0;
122922944501Smrg    entry->f        = NULL;
123022944501Smrg    entry->tagTable = NULL;
123122944501Smrg
123222944501Smrg    drmHashDelete(drmHashTable, key);
123322944501Smrg    drmFree(entry);
123422944501Smrg
123522944501Smrg    return close(fd);
123622944501Smrg}
123722944501Smrg
123822944501Smrg
123922944501Smrg/**
124022944501Smrg * Map a region of memory.
124122944501Smrg *
124222944501Smrg * \param fd file descriptor.
124322944501Smrg * \param handle handle returned by drmAddMap().
124422944501Smrg * \param size size in bytes. Must match the size used by drmAddMap().
124522944501Smrg * \param address will contain the user-space virtual address where the mapping
124622944501Smrg * begins.
124722944501Smrg *
124822944501Smrg * \return zero on success, or a negative value on failure.
1249fe517fc9Smrg *
125022944501Smrg * \internal
125122944501Smrg * This function is a wrapper for mmap().
125222944501Smrg */
12536260e5d5Smrgdrm_public int drmMap(int fd, drm_handle_t handle, drmSize size,
12546260e5d5Smrg                      drmAddressPtr address)
125522944501Smrg{
125622944501Smrg    static unsigned long pagesize_mask = 0;
125722944501Smrg
125822944501Smrg    if (fd < 0)
1259fe517fc9Smrg        return -EINVAL;
126022944501Smrg
126122944501Smrg    if (!pagesize_mask)
1262fe517fc9Smrg        pagesize_mask = getpagesize() - 1;
126322944501Smrg
126422944501Smrg    size = (size + pagesize_mask) & ~pagesize_mask;
126522944501Smrg
1266a884aba1Smrg    *address = drm_mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, handle);
126722944501Smrg    if (*address == MAP_FAILED)
1268fe517fc9Smrg        return -errno;
126922944501Smrg    return 0;
127022944501Smrg}
127122944501Smrg
127222944501Smrg
127322944501Smrg/**
127422944501Smrg * Unmap mappings obtained with drmMap().
127522944501Smrg *
127622944501Smrg * \param address address as given by drmMap().
127722944501Smrg * \param size size in bytes. Must match the size used by drmMap().
1278fe517fc9Smrg *
127922944501Smrg * \return zero on success, or a negative value on failure.
128022944501Smrg *
128122944501Smrg * \internal
128222944501Smrg * This function is a wrapper for munmap().
128322944501Smrg */
12846260e5d5Smrgdrm_public int drmUnmap(drmAddress address, drmSize size)
128522944501Smrg{
1286a884aba1Smrg    return drm_munmap(address, size);
128722944501Smrg}
128822944501Smrg
12896260e5d5Smrgdrm_public drmBufInfoPtr drmGetBufInfo(int fd)
129022944501Smrg{
129122944501Smrg    drm_buf_info_t info;
129222944501Smrg    drmBufInfoPtr  retval;
129322944501Smrg    int            i;
129422944501Smrg
1295424e9256Smrg    memclear(info);
129622944501Smrg
129722944501Smrg    if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info))
1298fe517fc9Smrg        return NULL;
129922944501Smrg
130022944501Smrg    if (info.count) {
1301fe517fc9Smrg        if (!(info.list = drmMalloc(info.count * sizeof(*info.list))))
1302fe517fc9Smrg            return NULL;
1303fe517fc9Smrg
1304fe517fc9Smrg        if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info)) {
1305fe517fc9Smrg            drmFree(info.list);
1306fe517fc9Smrg            return NULL;
1307fe517fc9Smrg        }
1308fe517fc9Smrg
1309fe517fc9Smrg        retval = drmMalloc(sizeof(*retval));
1310fe517fc9Smrg        retval->count = info.count;
1311fe517fc9Smrg        retval->list  = drmMalloc(info.count * sizeof(*retval->list));
1312fe517fc9Smrg        for (i = 0; i < info.count; i++) {
1313fe517fc9Smrg            retval->list[i].count     = info.list[i].count;
1314fe517fc9Smrg            retval->list[i].size      = info.list[i].size;
1315fe517fc9Smrg            retval->list[i].low_mark  = info.list[i].low_mark;
1316fe517fc9Smrg            retval->list[i].high_mark = info.list[i].high_mark;
1317fe517fc9Smrg        }
1318fe517fc9Smrg        drmFree(info.list);
1319fe517fc9Smrg        return retval;
132022944501Smrg    }
132122944501Smrg    return NULL;
132222944501Smrg}
132322944501Smrg
132422944501Smrg/**
132522944501Smrg * Map all DMA buffers into client-virtual space.
132622944501Smrg *
132722944501Smrg * \param fd file descriptor.
132822944501Smrg *
132922944501Smrg * \return a pointer to a ::drmBufMap structure.
133022944501Smrg *
133122944501Smrg * \note The client may not use these buffers until obtaining buffer indices
133222944501Smrg * with drmDMA().
1333fe517fc9Smrg *
133422944501Smrg * \internal
133522944501Smrg * This function calls the DRM_IOCTL_MAP_BUFS ioctl and copies the returned
133622944501Smrg * information about the buffers in a drm_buf_map structure into the
133722944501Smrg * client-visible data structures.
1338fe517fc9Smrg */
13396260e5d5Smrgdrm_public drmBufMapPtr drmMapBufs(int fd)
134022944501Smrg{
134122944501Smrg    drm_buf_map_t bufs;
134222944501Smrg    drmBufMapPtr  retval;
134322944501Smrg    int           i;
134422944501Smrg
1345424e9256Smrg    memclear(bufs);
134622944501Smrg    if (drmIoctl(fd, DRM_IOCTL_MAP_BUFS, &bufs))
1347fe517fc9Smrg        return NULL;
134822944501Smrg
134922944501Smrg    if (!bufs.count)
1350fe517fc9Smrg        return NULL;
135122944501Smrg
1352fe517fc9Smrg    if (!(bufs.list = drmMalloc(bufs.count * sizeof(*bufs.list))))
1353fe517fc9Smrg        return NULL;
135422944501Smrg
1355fe517fc9Smrg    if (drmIoctl(fd, DRM_IOCTL_MAP_BUFS, &bufs)) {
1356fe517fc9Smrg        drmFree(bufs.list);
1357fe517fc9Smrg        return NULL;
1358fe517fc9Smrg    }
135922944501Smrg
1360fe517fc9Smrg    retval = drmMalloc(sizeof(*retval));
1361fe517fc9Smrg    retval->count = bufs.count;
1362fe517fc9Smrg    retval->list  = drmMalloc(bufs.count * sizeof(*retval->list));
1363fe517fc9Smrg    for (i = 0; i < bufs.count; i++) {
1364fe517fc9Smrg        retval->list[i].idx     = bufs.list[i].idx;
1365fe517fc9Smrg        retval->list[i].total   = bufs.list[i].total;
1366fe517fc9Smrg        retval->list[i].used    = 0;
1367fe517fc9Smrg        retval->list[i].address = bufs.list[i].address;
1368fe517fc9Smrg    }
136922944501Smrg
1370fe517fc9Smrg    drmFree(bufs.list);
1371fe517fc9Smrg    return retval;
137222944501Smrg}
137322944501Smrg
137422944501Smrg
137522944501Smrg/**
137622944501Smrg * Unmap buffers allocated with drmMapBufs().
137722944501Smrg *
137822944501Smrg * \return zero on success, or negative value on failure.
137922944501Smrg *
138022944501Smrg * \internal
138122944501Smrg * Calls munmap() for every buffer stored in \p bufs and frees the
138222944501Smrg * memory allocated by drmMapBufs().
138322944501Smrg */
13846260e5d5Smrgdrm_public int drmUnmapBufs(drmBufMapPtr bufs)
138522944501Smrg{
138622944501Smrg    int i;
138722944501Smrg
138822944501Smrg    for (i = 0; i < bufs->count; i++) {
1389fe517fc9Smrg        drm_munmap(bufs->list[i].address, bufs->list[i].total);
139022944501Smrg    }
139122944501Smrg
139222944501Smrg    drmFree(bufs->list);
139322944501Smrg    drmFree(bufs);
139422944501Smrg    return 0;
139522944501Smrg}
139622944501Smrg
139722944501Smrg
1398fe517fc9Smrg#define DRM_DMA_RETRY  16
139922944501Smrg
140022944501Smrg/**
140122944501Smrg * Reserve DMA buffers.
140222944501Smrg *
140322944501Smrg * \param fd file descriptor.
1404fe517fc9Smrg * \param request
1405fe517fc9Smrg *
140622944501Smrg * \return zero on success, or a negative value on failure.
140722944501Smrg *
140822944501Smrg * \internal
140922944501Smrg * Assemble the arguments into a drm_dma structure and keeps issuing the
141022944501Smrg * DRM_IOCTL_DMA ioctl until success or until maximum number of retries.
141122944501Smrg */
14126260e5d5Smrgdrm_public int drmDMA(int fd, drmDMAReqPtr request)
141322944501Smrg{
141422944501Smrg    drm_dma_t dma;
141522944501Smrg    int ret, i = 0;
141622944501Smrg
141722944501Smrg    dma.context         = request->context;
141822944501Smrg    dma.send_count      = request->send_count;
141922944501Smrg    dma.send_indices    = request->send_list;
142022944501Smrg    dma.send_sizes      = request->send_sizes;
142122944501Smrg    dma.flags           = request->flags;
142222944501Smrg    dma.request_count   = request->request_count;
142322944501Smrg    dma.request_size    = request->request_size;
142422944501Smrg    dma.request_indices = request->request_list;
142522944501Smrg    dma.request_sizes   = request->request_sizes;
142622944501Smrg    dma.granted_count   = 0;
142722944501Smrg
142822944501Smrg    do {
1429fe517fc9Smrg        ret = ioctl( fd, DRM_IOCTL_DMA, &dma );
143022944501Smrg    } while ( ret && errno == EAGAIN && i++ < DRM_DMA_RETRY );
143122944501Smrg
143222944501Smrg    if ( ret == 0 ) {
1433fe517fc9Smrg        request->granted_count = dma.granted_count;
1434fe517fc9Smrg        return 0;
143522944501Smrg    } else {
1436fe517fc9Smrg        return -errno;
143722944501Smrg    }
143822944501Smrg}
143922944501Smrg
144022944501Smrg
144122944501Smrg/**
144222944501Smrg * Obtain heavyweight hardware lock.
144322944501Smrg *
144422944501Smrg * \param fd file descriptor.
144522944501Smrg * \param context context.
1446bf6cc7dcSmrg * \param flags flags that determine the state of the hardware when the function
144722944501Smrg * returns.
1448fe517fc9Smrg *
144922944501Smrg * \return always zero.
1450fe517fc9Smrg *
145122944501Smrg * \internal
145222944501Smrg * This function translates the arguments into a drm_lock structure and issue
145322944501Smrg * the DRM_IOCTL_LOCK ioctl until the lock is successfully acquired.
145422944501Smrg */
14556260e5d5Smrgdrm_public int drmGetLock(int fd, drm_context_t context, drmLockFlags flags)
145622944501Smrg{
145722944501Smrg    drm_lock_t lock;
145822944501Smrg
1459424e9256Smrg    memclear(lock);
146022944501Smrg    lock.context = context;
146122944501Smrg    lock.flags   = 0;
146222944501Smrg    if (flags & DRM_LOCK_READY)      lock.flags |= _DRM_LOCK_READY;
146322944501Smrg    if (flags & DRM_LOCK_QUIESCENT)  lock.flags |= _DRM_LOCK_QUIESCENT;
146422944501Smrg    if (flags & DRM_LOCK_FLUSH)      lock.flags |= _DRM_LOCK_FLUSH;
146522944501Smrg    if (flags & DRM_LOCK_FLUSH_ALL)  lock.flags |= _DRM_LOCK_FLUSH_ALL;
146622944501Smrg    if (flags & DRM_HALT_ALL_QUEUES) lock.flags |= _DRM_HALT_ALL_QUEUES;
146722944501Smrg    if (flags & DRM_HALT_CUR_QUEUES) lock.flags |= _DRM_HALT_CUR_QUEUES;
146822944501Smrg
146922944501Smrg    while (drmIoctl(fd, DRM_IOCTL_LOCK, &lock))
1470fe517fc9Smrg        ;
147122944501Smrg    return 0;
147222944501Smrg}
147322944501Smrg
147422944501Smrg/**
147522944501Smrg * Release the hardware lock.
147622944501Smrg *
147722944501Smrg * \param fd file descriptor.
147822944501Smrg * \param context context.
1479fe517fc9Smrg *
148022944501Smrg * \return zero on success, or a negative value on failure.
1481fe517fc9Smrg *
148222944501Smrg * \internal
148322944501Smrg * This function is a wrapper around the DRM_IOCTL_UNLOCK ioctl, passing the
148422944501Smrg * argument in a drm_lock structure.
148522944501Smrg */
14866260e5d5Smrgdrm_public int drmUnlock(int fd, drm_context_t context)
148722944501Smrg{
148822944501Smrg    drm_lock_t lock;
148922944501Smrg
1490424e9256Smrg    memclear(lock);
149122944501Smrg    lock.context = context;
149222944501Smrg    return drmIoctl(fd, DRM_IOCTL_UNLOCK, &lock);
149322944501Smrg}
149422944501Smrg
14956260e5d5Smrgdrm_public drm_context_t *drmGetReservedContextList(int fd, int *count)
149622944501Smrg{
149722944501Smrg    drm_ctx_res_t res;
149822944501Smrg    drm_ctx_t     *list;
149922944501Smrg    drm_context_t * retval;
150022944501Smrg    int           i;
150122944501Smrg
1502424e9256Smrg    memclear(res);
150322944501Smrg    if (drmIoctl(fd, DRM_IOCTL_RES_CTX, &res))
1504fe517fc9Smrg        return NULL;
150522944501Smrg
150622944501Smrg    if (!res.count)
1507fe517fc9Smrg        return NULL;
150822944501Smrg
150922944501Smrg    if (!(list   = drmMalloc(res.count * sizeof(*list))))
1510fe517fc9Smrg        return NULL;
15110655efefSmrg    if (!(retval = drmMalloc(res.count * sizeof(*retval))))
15120655efefSmrg        goto err_free_list;
151322944501Smrg
151422944501Smrg    res.contexts = list;
151522944501Smrg    if (drmIoctl(fd, DRM_IOCTL_RES_CTX, &res))
15160655efefSmrg        goto err_free_context;
151722944501Smrg
151822944501Smrg    for (i = 0; i < res.count; i++)
1519fe517fc9Smrg        retval[i] = list[i].handle;
152022944501Smrg    drmFree(list);
152122944501Smrg
152222944501Smrg    *count = res.count;
152322944501Smrg    return retval;
15240655efefSmrg
15250655efefSmrgerr_free_list:
15260655efefSmrg    drmFree(list);
15270655efefSmrgerr_free_context:
15280655efefSmrg    drmFree(retval);
15290655efefSmrg    return NULL;
153022944501Smrg}
153122944501Smrg
15326260e5d5Smrgdrm_public void drmFreeReservedContextList(drm_context_t *pt)
153322944501Smrg{
153422944501Smrg    drmFree(pt);
153522944501Smrg}
153622944501Smrg
153722944501Smrg/**
153822944501Smrg * Create context.
153922944501Smrg *
154022944501Smrg * Used by the X server during GLXContext initialization. This causes
154122944501Smrg * per-context kernel-level resources to be allocated.
154222944501Smrg *
154322944501Smrg * \param fd file descriptor.
154422944501Smrg * \param handle is set on success. To be used by the client when requesting DMA
154522944501Smrg * dispatch with drmDMA().
1546fe517fc9Smrg *
154722944501Smrg * \return zero on success, or a negative value on failure.
1548fe517fc9Smrg *
154922944501Smrg * \note May only be called by root.
1550fe517fc9Smrg *
155122944501Smrg * \internal
155222944501Smrg * This function is a wrapper around the DRM_IOCTL_ADD_CTX ioctl, passing the
155322944501Smrg * argument in a drm_ctx structure.
155422944501Smrg */
15556260e5d5Smrgdrm_public int drmCreateContext(int fd, drm_context_t *handle)
155622944501Smrg{
155722944501Smrg    drm_ctx_t ctx;
155822944501Smrg
1559424e9256Smrg    memclear(ctx);
156022944501Smrg    if (drmIoctl(fd, DRM_IOCTL_ADD_CTX, &ctx))
1561fe517fc9Smrg        return -errno;
156222944501Smrg    *handle = ctx.handle;
156322944501Smrg    return 0;
156422944501Smrg}
156522944501Smrg
15666260e5d5Smrgdrm_public int drmSwitchToContext(int fd, drm_context_t context)
156722944501Smrg{
156822944501Smrg    drm_ctx_t ctx;
156922944501Smrg
1570424e9256Smrg    memclear(ctx);
157122944501Smrg    ctx.handle = context;
157222944501Smrg    if (drmIoctl(fd, DRM_IOCTL_SWITCH_CTX, &ctx))
1573fe517fc9Smrg        return -errno;
157422944501Smrg    return 0;
157522944501Smrg}
157622944501Smrg
15776260e5d5Smrgdrm_public int drmSetContextFlags(int fd, drm_context_t context,
15786260e5d5Smrg                                  drm_context_tFlags flags)
157922944501Smrg{
158022944501Smrg    drm_ctx_t ctx;
158122944501Smrg
158222944501Smrg    /*
158322944501Smrg     * Context preserving means that no context switches are done between DMA
158422944501Smrg     * buffers from one context and the next.  This is suitable for use in the
158522944501Smrg     * X server (which promises to maintain hardware context), or in the
158622944501Smrg     * client-side library when buffers are swapped on behalf of two threads.
158722944501Smrg     */
1588424e9256Smrg    memclear(ctx);
158922944501Smrg    ctx.handle = context;
159022944501Smrg    if (flags & DRM_CONTEXT_PRESERVED)
1591fe517fc9Smrg        ctx.flags |= _DRM_CONTEXT_PRESERVED;
159222944501Smrg    if (flags & DRM_CONTEXT_2DONLY)
1593fe517fc9Smrg        ctx.flags |= _DRM_CONTEXT_2DONLY;
159422944501Smrg    if (drmIoctl(fd, DRM_IOCTL_MOD_CTX, &ctx))
1595fe517fc9Smrg        return -errno;
159622944501Smrg    return 0;
159722944501Smrg}
159822944501Smrg
15996260e5d5Smrgdrm_public int drmGetContextFlags(int fd, drm_context_t context,
16006260e5d5Smrg                                  drm_context_tFlagsPtr flags)
160122944501Smrg{
160222944501Smrg    drm_ctx_t ctx;
160322944501Smrg
1604424e9256Smrg    memclear(ctx);
160522944501Smrg    ctx.handle = context;
160622944501Smrg    if (drmIoctl(fd, DRM_IOCTL_GET_CTX, &ctx))
1607fe517fc9Smrg        return -errno;
160822944501Smrg    *flags = 0;
160922944501Smrg    if (ctx.flags & _DRM_CONTEXT_PRESERVED)
1610fe517fc9Smrg        *flags |= DRM_CONTEXT_PRESERVED;
161122944501Smrg    if (ctx.flags & _DRM_CONTEXT_2DONLY)
1612fe517fc9Smrg        *flags |= DRM_CONTEXT_2DONLY;
161322944501Smrg    return 0;
161422944501Smrg}
161522944501Smrg
161622944501Smrg/**
161722944501Smrg * Destroy context.
161822944501Smrg *
161922944501Smrg * Free any kernel-level resources allocated with drmCreateContext() associated
162022944501Smrg * with the context.
1621fe517fc9Smrg *
162222944501Smrg * \param fd file descriptor.
162322944501Smrg * \param handle handle given by drmCreateContext().
1624fe517fc9Smrg *
162522944501Smrg * \return zero on success, or a negative value on failure.
1626fe517fc9Smrg *
162722944501Smrg * \note May only be called by root.
1628fe517fc9Smrg *
162922944501Smrg * \internal
163022944501Smrg * This function is a wrapper around the DRM_IOCTL_RM_CTX ioctl, passing the
163122944501Smrg * argument in a drm_ctx structure.
163222944501Smrg */
16336260e5d5Smrgdrm_public int drmDestroyContext(int fd, drm_context_t handle)
163422944501Smrg{
163522944501Smrg    drm_ctx_t ctx;
1636424e9256Smrg
1637424e9256Smrg    memclear(ctx);
163822944501Smrg    ctx.handle = handle;
163922944501Smrg    if (drmIoctl(fd, DRM_IOCTL_RM_CTX, &ctx))
1640fe517fc9Smrg        return -errno;
164122944501Smrg    return 0;
164222944501Smrg}
164322944501Smrg
16446260e5d5Smrgdrm_public int drmCreateDrawable(int fd, drm_drawable_t *handle)
164522944501Smrg{
164622944501Smrg    drm_draw_t draw;
1647424e9256Smrg
1648424e9256Smrg    memclear(draw);
164922944501Smrg    if (drmIoctl(fd, DRM_IOCTL_ADD_DRAW, &draw))
1650fe517fc9Smrg        return -errno;
165122944501Smrg    *handle = draw.handle;
165222944501Smrg    return 0;
165322944501Smrg}
165422944501Smrg
16556260e5d5Smrgdrm_public int drmDestroyDrawable(int fd, drm_drawable_t handle)
165622944501Smrg{
165722944501Smrg    drm_draw_t draw;
1658424e9256Smrg
1659424e9256Smrg    memclear(draw);
166022944501Smrg    draw.handle = handle;
166122944501Smrg    if (drmIoctl(fd, DRM_IOCTL_RM_DRAW, &draw))
1662fe517fc9Smrg        return -errno;
166322944501Smrg    return 0;
166422944501Smrg}
166522944501Smrg
16666260e5d5Smrgdrm_public int drmUpdateDrawableInfo(int fd, drm_drawable_t handle,
16676260e5d5Smrg                                     drm_drawable_info_type_t type,
16686260e5d5Smrg                                     unsigned int num, void *data)
166922944501Smrg{
167022944501Smrg    drm_update_draw_t update;
167122944501Smrg
1672424e9256Smrg    memclear(update);
167322944501Smrg    update.handle = handle;
167422944501Smrg    update.type = type;
167522944501Smrg    update.num = num;
167622944501Smrg    update.data = (unsigned long long)(unsigned long)data;
167722944501Smrg
167822944501Smrg    if (drmIoctl(fd, DRM_IOCTL_UPDATE_DRAW, &update))
1679fe517fc9Smrg        return -errno;
168022944501Smrg
168122944501Smrg    return 0;
168222944501Smrg}
168322944501Smrg
16846260e5d5Smrgdrm_public int drmCrtcGetSequence(int fd, uint32_t crtcId, uint64_t *sequence,
16856260e5d5Smrg                                  uint64_t *ns)
16862b90624aSmrg{
16872b90624aSmrg    struct drm_crtc_get_sequence get_seq;
16882b90624aSmrg    int ret;
16892b90624aSmrg
16902b90624aSmrg    memclear(get_seq);
16912b90624aSmrg    get_seq.crtc_id = crtcId;
16922b90624aSmrg    ret = drmIoctl(fd, DRM_IOCTL_CRTC_GET_SEQUENCE, &get_seq);
16932b90624aSmrg    if (ret)
16942b90624aSmrg        return ret;
16952b90624aSmrg
16962b90624aSmrg    if (sequence)
16972b90624aSmrg        *sequence = get_seq.sequence;
16982b90624aSmrg    if (ns)
16992b90624aSmrg        *ns = get_seq.sequence_ns;
17002b90624aSmrg    return 0;
17012b90624aSmrg}
17022b90624aSmrg
17036260e5d5Smrgdrm_public int drmCrtcQueueSequence(int fd, uint32_t crtcId, uint32_t flags,
17046260e5d5Smrg                                    uint64_t sequence,
17056260e5d5Smrg                                    uint64_t *sequence_queued,
17066260e5d5Smrg                                    uint64_t user_data)
17072b90624aSmrg{
17082b90624aSmrg    struct drm_crtc_queue_sequence queue_seq;
17092b90624aSmrg    int ret;
17102b90624aSmrg
17112b90624aSmrg    memclear(queue_seq);
17122b90624aSmrg    queue_seq.crtc_id = crtcId;
17132b90624aSmrg    queue_seq.flags = flags;
17142b90624aSmrg    queue_seq.sequence = sequence;
17152b90624aSmrg    queue_seq.user_data = user_data;
17162b90624aSmrg
17172b90624aSmrg    ret = drmIoctl(fd, DRM_IOCTL_CRTC_QUEUE_SEQUENCE, &queue_seq);
17182b90624aSmrg    if (ret == 0 && sequence_queued)
17192b90624aSmrg        *sequence_queued = queue_seq.sequence;
17202b90624aSmrg
17212b90624aSmrg    return ret;
17222b90624aSmrg}
17232b90624aSmrg
172422944501Smrg/**
172522944501Smrg * Acquire the AGP device.
172622944501Smrg *
172722944501Smrg * Must be called before any of the other AGP related calls.
172822944501Smrg *
172922944501Smrg * \param fd file descriptor.
1730fe517fc9Smrg *
173122944501Smrg * \return zero on success, or a negative value on failure.
1732fe517fc9Smrg *
173322944501Smrg * \internal
173422944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_ACQUIRE ioctl.
173522944501Smrg */
17366260e5d5Smrgdrm_public int drmAgpAcquire(int fd)
173722944501Smrg{
173822944501Smrg    if (drmIoctl(fd, DRM_IOCTL_AGP_ACQUIRE, NULL))
1739fe517fc9Smrg        return -errno;
174022944501Smrg    return 0;
174122944501Smrg}
174222944501Smrg
174322944501Smrg
174422944501Smrg/**
174522944501Smrg * Release the AGP device.
174622944501Smrg *
174722944501Smrg * \param fd file descriptor.
1748fe517fc9Smrg *
174922944501Smrg * \return zero on success, or a negative value on failure.
1750fe517fc9Smrg *
175122944501Smrg * \internal
175222944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_RELEASE ioctl.
175322944501Smrg */
17546260e5d5Smrgdrm_public int drmAgpRelease(int fd)
175522944501Smrg{
175622944501Smrg    if (drmIoctl(fd, DRM_IOCTL_AGP_RELEASE, NULL))
1757fe517fc9Smrg        return -errno;
175822944501Smrg    return 0;
175922944501Smrg}
176022944501Smrg
176122944501Smrg
176222944501Smrg/**
176322944501Smrg * Set the AGP mode.
176422944501Smrg *
176522944501Smrg * \param fd file descriptor.
176622944501Smrg * \param mode AGP mode.
1767fe517fc9Smrg *
176822944501Smrg * \return zero on success, or a negative value on failure.
1769fe517fc9Smrg *
177022944501Smrg * \internal
177122944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_ENABLE ioctl, passing the
177222944501Smrg * argument in a drm_agp_mode structure.
177322944501Smrg */
17746260e5d5Smrgdrm_public int drmAgpEnable(int fd, unsigned long mode)
177522944501Smrg{
177622944501Smrg    drm_agp_mode_t m;
177722944501Smrg
1778424e9256Smrg    memclear(m);
177922944501Smrg    m.mode = mode;
178022944501Smrg    if (drmIoctl(fd, DRM_IOCTL_AGP_ENABLE, &m))
1781fe517fc9Smrg        return -errno;
178222944501Smrg    return 0;
178322944501Smrg}
178422944501Smrg
178522944501Smrg
178622944501Smrg/**
178722944501Smrg * Allocate a chunk of AGP memory.
178822944501Smrg *
178922944501Smrg * \param fd file descriptor.
179022944501Smrg * \param size requested memory size in bytes. Will be rounded to page boundary.
179122944501Smrg * \param type type of memory to allocate.
179222944501Smrg * \param address if not zero, will be set to the physical address of the
179322944501Smrg * allocated memory.
179422944501Smrg * \param handle on success will be set to a handle of the allocated memory.
1795fe517fc9Smrg *
179622944501Smrg * \return zero on success, or a negative value on failure.
1797fe517fc9Smrg *
179822944501Smrg * \internal
179922944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_ALLOC ioctl, passing the
180022944501Smrg * arguments in a drm_agp_buffer structure.
180122944501Smrg */
18026260e5d5Smrgdrm_public int drmAgpAlloc(int fd, unsigned long size, unsigned long type,
18036260e5d5Smrg                           unsigned long *address, drm_handle_t *handle)
180422944501Smrg{
180522944501Smrg    drm_agp_buffer_t b;
180622944501Smrg
1807424e9256Smrg    memclear(b);
180822944501Smrg    *handle = DRM_AGP_NO_HANDLE;
180922944501Smrg    b.size   = size;
181022944501Smrg    b.type   = type;
181122944501Smrg    if (drmIoctl(fd, DRM_IOCTL_AGP_ALLOC, &b))
1812fe517fc9Smrg        return -errno;
181322944501Smrg    if (address != 0UL)
1814fe517fc9Smrg        *address = b.physical;
181522944501Smrg    *handle = b.handle;
181622944501Smrg    return 0;
181722944501Smrg}
181822944501Smrg
181922944501Smrg
182022944501Smrg/**
182122944501Smrg * Free a chunk of AGP memory.
182222944501Smrg *
182322944501Smrg * \param fd file descriptor.
182422944501Smrg * \param handle handle to the allocated memory, as given by drmAgpAllocate().
1825fe517fc9Smrg *
182622944501Smrg * \return zero on success, or a negative value on failure.
1827fe517fc9Smrg *
182822944501Smrg * \internal
182922944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_FREE ioctl, passing the
183022944501Smrg * argument in a drm_agp_buffer structure.
183122944501Smrg */
18326260e5d5Smrgdrm_public int drmAgpFree(int fd, drm_handle_t handle)
183322944501Smrg{
183422944501Smrg    drm_agp_buffer_t b;
183522944501Smrg
1836424e9256Smrg    memclear(b);
183722944501Smrg    b.handle = handle;
183822944501Smrg    if (drmIoctl(fd, DRM_IOCTL_AGP_FREE, &b))
1839fe517fc9Smrg        return -errno;
184022944501Smrg    return 0;
184122944501Smrg}
184222944501Smrg
184322944501Smrg
184422944501Smrg/**
184522944501Smrg * Bind a chunk of AGP memory.
184622944501Smrg *
184722944501Smrg * \param fd file descriptor.
184822944501Smrg * \param handle handle to the allocated memory, as given by drmAgpAllocate().
184922944501Smrg * \param offset offset in bytes. It will round to page boundary.
1850fe517fc9Smrg *
185122944501Smrg * \return zero on success, or a negative value on failure.
1852fe517fc9Smrg *
185322944501Smrg * \internal
185422944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_BIND ioctl, passing the
185522944501Smrg * argument in a drm_agp_binding structure.
185622944501Smrg */
18576260e5d5Smrgdrm_public int drmAgpBind(int fd, drm_handle_t handle, unsigned long offset)
185822944501Smrg{
185922944501Smrg    drm_agp_binding_t b;
186022944501Smrg
1861424e9256Smrg    memclear(b);
186222944501Smrg    b.handle = handle;
186322944501Smrg    b.offset = offset;
186422944501Smrg    if (drmIoctl(fd, DRM_IOCTL_AGP_BIND, &b))
1865fe517fc9Smrg        return -errno;
186622944501Smrg    return 0;
186722944501Smrg}
186822944501Smrg
186922944501Smrg
187022944501Smrg/**
187122944501Smrg * Unbind a chunk of AGP memory.
187222944501Smrg *
187322944501Smrg * \param fd file descriptor.
187422944501Smrg * \param handle handle to the allocated memory, as given by drmAgpAllocate().
1875fe517fc9Smrg *
187622944501Smrg * \return zero on success, or a negative value on failure.
1877fe517fc9Smrg *
187822944501Smrg * \internal
187922944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_UNBIND ioctl, passing
188022944501Smrg * the argument in a drm_agp_binding structure.
188122944501Smrg */
18826260e5d5Smrgdrm_public int drmAgpUnbind(int fd, drm_handle_t handle)
188322944501Smrg{
188422944501Smrg    drm_agp_binding_t b;
188522944501Smrg
1886424e9256Smrg    memclear(b);
188722944501Smrg    b.handle = handle;
188822944501Smrg    if (drmIoctl(fd, DRM_IOCTL_AGP_UNBIND, &b))
1889fe517fc9Smrg        return -errno;
189022944501Smrg    return 0;
189122944501Smrg}
189222944501Smrg
189322944501Smrg
189422944501Smrg/**
189522944501Smrg * Get AGP driver major version number.
189622944501Smrg *
189722944501Smrg * \param fd file descriptor.
1898fe517fc9Smrg *
189922944501Smrg * \return major version number on success, or a negative value on failure..
1900fe517fc9Smrg *
190122944501Smrg * \internal
190222944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
190322944501Smrg * necessary information in a drm_agp_info structure.
190422944501Smrg */
19056260e5d5Smrgdrm_public int drmAgpVersionMajor(int fd)
190622944501Smrg{
190722944501Smrg    drm_agp_info_t i;
190822944501Smrg
1909424e9256Smrg    memclear(i);
1910424e9256Smrg
191122944501Smrg    if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
1912fe517fc9Smrg        return -errno;
191322944501Smrg    return i.agp_version_major;
191422944501Smrg}
191522944501Smrg
191622944501Smrg
191722944501Smrg/**
191822944501Smrg * Get AGP driver minor version number.
191922944501Smrg *
192022944501Smrg * \param fd file descriptor.
1921fe517fc9Smrg *
192222944501Smrg * \return minor version number on success, or a negative value on failure.
1923fe517fc9Smrg *
192422944501Smrg * \internal
192522944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
192622944501Smrg * necessary information in a drm_agp_info structure.
192722944501Smrg */
19286260e5d5Smrgdrm_public int drmAgpVersionMinor(int fd)
192922944501Smrg{
193022944501Smrg    drm_agp_info_t i;
193122944501Smrg
1932424e9256Smrg    memclear(i);
1933424e9256Smrg
193422944501Smrg    if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
1935fe517fc9Smrg        return -errno;
193622944501Smrg    return i.agp_version_minor;
193722944501Smrg}
193822944501Smrg
193922944501Smrg
194022944501Smrg/**
194122944501Smrg * Get AGP mode.
194222944501Smrg *
194322944501Smrg * \param fd file descriptor.
1944fe517fc9Smrg *
194522944501Smrg * \return mode on success, or zero on failure.
1946fe517fc9Smrg *
194722944501Smrg * \internal
194822944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
194922944501Smrg * necessary information in a drm_agp_info structure.
195022944501Smrg */
19516260e5d5Smrgdrm_public unsigned long drmAgpGetMode(int fd)
195222944501Smrg{
195322944501Smrg    drm_agp_info_t i;
195422944501Smrg
1955424e9256Smrg    memclear(i);
1956424e9256Smrg
195722944501Smrg    if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
1958fe517fc9Smrg        return 0;
195922944501Smrg    return i.mode;
196022944501Smrg}
196122944501Smrg
196222944501Smrg
196322944501Smrg/**
196422944501Smrg * Get AGP aperture base.
196522944501Smrg *
196622944501Smrg * \param fd file descriptor.
1967fe517fc9Smrg *
196822944501Smrg * \return aperture base on success, zero on failure.
1969fe517fc9Smrg *
197022944501Smrg * \internal
197122944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
197222944501Smrg * necessary information in a drm_agp_info structure.
197322944501Smrg */
19746260e5d5Smrgdrm_public unsigned long drmAgpBase(int fd)
197522944501Smrg{
197622944501Smrg    drm_agp_info_t i;
197722944501Smrg
1978424e9256Smrg    memclear(i);
1979424e9256Smrg
198022944501Smrg    if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
1981fe517fc9Smrg        return 0;
198222944501Smrg    return i.aperture_base;
198322944501Smrg}
198422944501Smrg
198522944501Smrg
198622944501Smrg/**
198722944501Smrg * Get AGP aperture size.
198822944501Smrg *
198922944501Smrg * \param fd file descriptor.
1990fe517fc9Smrg *
199122944501Smrg * \return aperture size on success, zero on failure.
1992fe517fc9Smrg *
199322944501Smrg * \internal
199422944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
199522944501Smrg * necessary information in a drm_agp_info structure.
199622944501Smrg */
19976260e5d5Smrgdrm_public unsigned long drmAgpSize(int fd)
199822944501Smrg{
199922944501Smrg    drm_agp_info_t i;
200022944501Smrg
2001424e9256Smrg    memclear(i);
2002424e9256Smrg
200322944501Smrg    if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
2004fe517fc9Smrg        return 0;
200522944501Smrg    return i.aperture_size;
200622944501Smrg}
200722944501Smrg
200822944501Smrg
200922944501Smrg/**
201022944501Smrg * Get used AGP memory.
201122944501Smrg *
201222944501Smrg * \param fd file descriptor.
2013fe517fc9Smrg *
201422944501Smrg * \return memory used on success, or zero on failure.
2015fe517fc9Smrg *
201622944501Smrg * \internal
201722944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
201822944501Smrg * necessary information in a drm_agp_info structure.
201922944501Smrg */
20206260e5d5Smrgdrm_public unsigned long drmAgpMemoryUsed(int fd)
202122944501Smrg{
202222944501Smrg    drm_agp_info_t i;
202322944501Smrg
2024424e9256Smrg    memclear(i);
2025424e9256Smrg
202622944501Smrg    if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
2027fe517fc9Smrg        return 0;
202822944501Smrg    return i.memory_used;
202922944501Smrg}
203022944501Smrg
203122944501Smrg
203222944501Smrg/**
203322944501Smrg * Get available AGP memory.
203422944501Smrg *
203522944501Smrg * \param fd file descriptor.
2036fe517fc9Smrg *
203722944501Smrg * \return memory available on success, or zero on failure.
2038fe517fc9Smrg *
203922944501Smrg * \internal
204022944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
204122944501Smrg * necessary information in a drm_agp_info structure.
204222944501Smrg */
20436260e5d5Smrgdrm_public unsigned long drmAgpMemoryAvail(int fd)
204422944501Smrg{
204522944501Smrg    drm_agp_info_t i;
204622944501Smrg
2047424e9256Smrg    memclear(i);
2048424e9256Smrg
204922944501Smrg    if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
2050fe517fc9Smrg        return 0;
205122944501Smrg    return i.memory_allowed;
205222944501Smrg}
205322944501Smrg
205422944501Smrg
205522944501Smrg/**
205622944501Smrg * Get hardware vendor ID.
205722944501Smrg *
205822944501Smrg * \param fd file descriptor.
2059fe517fc9Smrg *
206022944501Smrg * \return vendor ID on success, or zero on failure.
2061fe517fc9Smrg *
206222944501Smrg * \internal
206322944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
206422944501Smrg * necessary information in a drm_agp_info structure.
206522944501Smrg */
20666260e5d5Smrgdrm_public unsigned int drmAgpVendorId(int fd)
206722944501Smrg{
206822944501Smrg    drm_agp_info_t i;
206922944501Smrg
2070424e9256Smrg    memclear(i);
2071424e9256Smrg
207222944501Smrg    if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
2073fe517fc9Smrg        return 0;
207422944501Smrg    return i.id_vendor;
207522944501Smrg}
207622944501Smrg
207722944501Smrg
207822944501Smrg/**
207922944501Smrg * Get hardware device ID.
208022944501Smrg *
208122944501Smrg * \param fd file descriptor.
2082fe517fc9Smrg *
208322944501Smrg * \return zero on success, or zero on failure.
2084fe517fc9Smrg *
208522944501Smrg * \internal
208622944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
208722944501Smrg * necessary information in a drm_agp_info structure.
208822944501Smrg */
20896260e5d5Smrgdrm_public unsigned int drmAgpDeviceId(int fd)
209022944501Smrg{
209122944501Smrg    drm_agp_info_t i;
209222944501Smrg
2093424e9256Smrg    memclear(i);
2094424e9256Smrg
209522944501Smrg    if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
2096fe517fc9Smrg        return 0;
209722944501Smrg    return i.id_device;
209822944501Smrg}
209922944501Smrg
21006260e5d5Smrgdrm_public int drmScatterGatherAlloc(int fd, unsigned long size,
21016260e5d5Smrg                                     drm_handle_t *handle)
210222944501Smrg{
210322944501Smrg    drm_scatter_gather_t sg;
210422944501Smrg
2105424e9256Smrg    memclear(sg);
2106424e9256Smrg
210722944501Smrg    *handle = 0;
210822944501Smrg    sg.size   = size;
210922944501Smrg    if (drmIoctl(fd, DRM_IOCTL_SG_ALLOC, &sg))
2110fe517fc9Smrg        return -errno;
211122944501Smrg    *handle = sg.handle;
211222944501Smrg    return 0;
211322944501Smrg}
211422944501Smrg
21156260e5d5Smrgdrm_public int drmScatterGatherFree(int fd, drm_handle_t handle)
211622944501Smrg{
211722944501Smrg    drm_scatter_gather_t sg;
211822944501Smrg
2119424e9256Smrg    memclear(sg);
212022944501Smrg    sg.handle = handle;
212122944501Smrg    if (drmIoctl(fd, DRM_IOCTL_SG_FREE, &sg))
2122fe517fc9Smrg        return -errno;
212322944501Smrg    return 0;
212422944501Smrg}
212522944501Smrg
212622944501Smrg/**
212722944501Smrg * Wait for VBLANK.
212822944501Smrg *
212922944501Smrg * \param fd file descriptor.
213022944501Smrg * \param vbl pointer to a drmVBlank structure.
2131fe517fc9Smrg *
213222944501Smrg * \return zero on success, or a negative value on failure.
2133fe517fc9Smrg *
213422944501Smrg * \internal
213522944501Smrg * This function is a wrapper around the DRM_IOCTL_WAIT_VBLANK ioctl.
213622944501Smrg */
21376260e5d5Smrgdrm_public int drmWaitVBlank(int fd, drmVBlankPtr vbl)
213822944501Smrg{
213922944501Smrg    struct timespec timeout, cur;
214022944501Smrg    int ret;
214122944501Smrg
214222944501Smrg    ret = clock_gettime(CLOCK_MONOTONIC, &timeout);
214322944501Smrg    if (ret < 0) {
2144fe517fc9Smrg        fprintf(stderr, "clock_gettime failed: %s\n", strerror(errno));
2145fe517fc9Smrg        goto out;
214622944501Smrg    }
214722944501Smrg    timeout.tv_sec++;
214822944501Smrg
214922944501Smrg    do {
215022944501Smrg       ret = ioctl(fd, DRM_IOCTL_WAIT_VBLANK, vbl);
215122944501Smrg       vbl->request.type &= ~DRM_VBLANK_RELATIVE;
215222944501Smrg       if (ret && errno == EINTR) {
2153fe517fc9Smrg           clock_gettime(CLOCK_MONOTONIC, &cur);
2154fe517fc9Smrg           /* Timeout after 1s */
2155fe517fc9Smrg           if (cur.tv_sec > timeout.tv_sec + 1 ||
2156fe517fc9Smrg               (cur.tv_sec == timeout.tv_sec && cur.tv_nsec >=
2157fe517fc9Smrg                timeout.tv_nsec)) {
2158fe517fc9Smrg                   errno = EBUSY;
2159fe517fc9Smrg                   ret = -1;
2160fe517fc9Smrg                   break;
2161fe517fc9Smrg           }
216222944501Smrg       }
216322944501Smrg    } while (ret && errno == EINTR);
216422944501Smrg
216522944501Smrgout:
216622944501Smrg    return ret;
216722944501Smrg}
216822944501Smrg
21696260e5d5Smrgdrm_public int drmError(int err, const char *label)
217022944501Smrg{
217122944501Smrg    switch (err) {
217222944501Smrg    case DRM_ERR_NO_DEVICE:
2173fe517fc9Smrg        fprintf(stderr, "%s: no device\n", label);
2174fe517fc9Smrg        break;
217522944501Smrg    case DRM_ERR_NO_ACCESS:
2176fe517fc9Smrg        fprintf(stderr, "%s: no access\n", label);
2177fe517fc9Smrg        break;
217822944501Smrg    case DRM_ERR_NOT_ROOT:
2179fe517fc9Smrg        fprintf(stderr, "%s: not root\n", label);
2180fe517fc9Smrg        break;
218122944501Smrg    case DRM_ERR_INVALID:
2182fe517fc9Smrg        fprintf(stderr, "%s: invalid args\n", label);
2183fe517fc9Smrg        break;
218422944501Smrg    default:
2185fe517fc9Smrg        if (err < 0)
2186fe517fc9Smrg            err = -err;
2187fe517fc9Smrg        fprintf( stderr, "%s: error %d (%s)\n", label, err, strerror(err) );
2188fe517fc9Smrg        break;
218922944501Smrg    }
219022944501Smrg
219122944501Smrg    return 1;
219222944501Smrg}
219322944501Smrg
219422944501Smrg/**
219522944501Smrg * Install IRQ handler.
219622944501Smrg *
219722944501Smrg * \param fd file descriptor.
219822944501Smrg * \param irq IRQ number.
2199fe517fc9Smrg *
220022944501Smrg * \return zero on success, or a negative value on failure.
2201fe517fc9Smrg *
220222944501Smrg * \internal
220322944501Smrg * This function is a wrapper around the DRM_IOCTL_CONTROL ioctl, passing the
220422944501Smrg * argument in a drm_control structure.
220522944501Smrg */
22066260e5d5Smrgdrm_public int drmCtlInstHandler(int fd, int irq)
220722944501Smrg{
220822944501Smrg    drm_control_t ctl;
220922944501Smrg
2210424e9256Smrg    memclear(ctl);
221122944501Smrg    ctl.func  = DRM_INST_HANDLER;
221222944501Smrg    ctl.irq   = irq;
221322944501Smrg    if (drmIoctl(fd, DRM_IOCTL_CONTROL, &ctl))
2214fe517fc9Smrg        return -errno;
221522944501Smrg    return 0;
221622944501Smrg}
221722944501Smrg
221822944501Smrg
221922944501Smrg/**
222022944501Smrg * Uninstall IRQ handler.
222122944501Smrg *
222222944501Smrg * \param fd file descriptor.
2223fe517fc9Smrg *
222422944501Smrg * \return zero on success, or a negative value on failure.
2225fe517fc9Smrg *
222622944501Smrg * \internal
222722944501Smrg * This function is a wrapper around the DRM_IOCTL_CONTROL ioctl, passing the
222822944501Smrg * argument in a drm_control structure.
222922944501Smrg */
22306260e5d5Smrgdrm_public int drmCtlUninstHandler(int fd)
223122944501Smrg{
223222944501Smrg    drm_control_t ctl;
223322944501Smrg
2234424e9256Smrg    memclear(ctl);
223522944501Smrg    ctl.func  = DRM_UNINST_HANDLER;
223622944501Smrg    ctl.irq   = 0;
223722944501Smrg    if (drmIoctl(fd, DRM_IOCTL_CONTROL, &ctl))
2238fe517fc9Smrg        return -errno;
223922944501Smrg    return 0;
224022944501Smrg}
224122944501Smrg
22426260e5d5Smrgdrm_public int drmFinish(int fd, int context, drmLockFlags flags)
224322944501Smrg{
224422944501Smrg    drm_lock_t lock;
224522944501Smrg
2246424e9256Smrg    memclear(lock);
224722944501Smrg    lock.context = context;
224822944501Smrg    if (flags & DRM_LOCK_READY)      lock.flags |= _DRM_LOCK_READY;
224922944501Smrg    if (flags & DRM_LOCK_QUIESCENT)  lock.flags |= _DRM_LOCK_QUIESCENT;
225022944501Smrg    if (flags & DRM_LOCK_FLUSH)      lock.flags |= _DRM_LOCK_FLUSH;
225122944501Smrg    if (flags & DRM_LOCK_FLUSH_ALL)  lock.flags |= _DRM_LOCK_FLUSH_ALL;
225222944501Smrg    if (flags & DRM_HALT_ALL_QUEUES) lock.flags |= _DRM_HALT_ALL_QUEUES;
225322944501Smrg    if (flags & DRM_HALT_CUR_QUEUES) lock.flags |= _DRM_HALT_CUR_QUEUES;
225422944501Smrg    if (drmIoctl(fd, DRM_IOCTL_FINISH, &lock))
2255fe517fc9Smrg        return -errno;
225622944501Smrg    return 0;
225722944501Smrg}
225822944501Smrg
225922944501Smrg/**
226022944501Smrg * Get IRQ from bus ID.
226122944501Smrg *
226222944501Smrg * \param fd file descriptor.
226322944501Smrg * \param busnum bus number.
226422944501Smrg * \param devnum device number.
226522944501Smrg * \param funcnum function number.
2266fe517fc9Smrg *
226722944501Smrg * \return IRQ number on success, or a negative value on failure.
2268fe517fc9Smrg *
226922944501Smrg * \internal
227022944501Smrg * This function is a wrapper around the DRM_IOCTL_IRQ_BUSID ioctl, passing the
227122944501Smrg * arguments in a drm_irq_busid structure.
227222944501Smrg */
22736260e5d5Smrgdrm_public int drmGetInterruptFromBusID(int fd, int busnum, int devnum,
22746260e5d5Smrg                                        int funcnum)
227522944501Smrg{
227622944501Smrg    drm_irq_busid_t p;
227722944501Smrg
2278424e9256Smrg    memclear(p);
227922944501Smrg    p.busnum  = busnum;
228022944501Smrg    p.devnum  = devnum;
228122944501Smrg    p.funcnum = funcnum;
228222944501Smrg    if (drmIoctl(fd, DRM_IOCTL_IRQ_BUSID, &p))
2283fe517fc9Smrg        return -errno;
228422944501Smrg    return p.irq;
228522944501Smrg}
228622944501Smrg
22876260e5d5Smrgdrm_public int drmAddContextTag(int fd, drm_context_t context, void *tag)
228822944501Smrg{
228922944501Smrg    drmHashEntry  *entry = drmGetEntry(fd);
229022944501Smrg
229122944501Smrg    if (drmHashInsert(entry->tagTable, context, tag)) {
2292fe517fc9Smrg        drmHashDelete(entry->tagTable, context);
2293fe517fc9Smrg        drmHashInsert(entry->tagTable, context, tag);
229422944501Smrg    }
229522944501Smrg    return 0;
229622944501Smrg}
229722944501Smrg
22986260e5d5Smrgdrm_public int drmDelContextTag(int fd, drm_context_t context)
229922944501Smrg{
230022944501Smrg    drmHashEntry  *entry = drmGetEntry(fd);
230122944501Smrg
230222944501Smrg    return drmHashDelete(entry->tagTable, context);
230322944501Smrg}
230422944501Smrg
23056260e5d5Smrgdrm_public void *drmGetContextTag(int fd, drm_context_t context)
230622944501Smrg{
230722944501Smrg    drmHashEntry  *entry = drmGetEntry(fd);
230822944501Smrg    void          *value;
230922944501Smrg
231022944501Smrg    if (drmHashLookup(entry->tagTable, context, &value))
2311fe517fc9Smrg        return NULL;
231222944501Smrg
231322944501Smrg    return value;
231422944501Smrg}
231522944501Smrg
23166260e5d5Smrgdrm_public int drmAddContextPrivateMapping(int fd, drm_context_t ctx_id,
23176260e5d5Smrg                                           drm_handle_t handle)
231822944501Smrg{
231922944501Smrg    drm_ctx_priv_map_t map;
232022944501Smrg
2321424e9256Smrg    memclear(map);
232222944501Smrg    map.ctx_id = ctx_id;
232320131375Smrg    map.handle = (void *)(uintptr_t)handle;
232422944501Smrg
232522944501Smrg    if (drmIoctl(fd, DRM_IOCTL_SET_SAREA_CTX, &map))
2326fe517fc9Smrg        return -errno;
232722944501Smrg    return 0;
232822944501Smrg}
232922944501Smrg
23306260e5d5Smrgdrm_public int drmGetContextPrivateMapping(int fd, drm_context_t ctx_id,
23316260e5d5Smrg                                           drm_handle_t *handle)
233222944501Smrg{
233322944501Smrg    drm_ctx_priv_map_t map;
233422944501Smrg
2335424e9256Smrg    memclear(map);
233622944501Smrg    map.ctx_id = ctx_id;
233722944501Smrg
233822944501Smrg    if (drmIoctl(fd, DRM_IOCTL_GET_SAREA_CTX, &map))
2339fe517fc9Smrg        return -errno;
234022944501Smrg    if (handle)
2341fe517fc9Smrg        *handle = (drm_handle_t)(uintptr_t)map.handle;
234222944501Smrg
234322944501Smrg    return 0;
234422944501Smrg}
234522944501Smrg
23466260e5d5Smrgdrm_public int drmGetMap(int fd, int idx, drm_handle_t *offset, drmSize *size,
23476260e5d5Smrg                         drmMapType *type, drmMapFlags *flags,
23486260e5d5Smrg                         drm_handle_t *handle, int *mtrr)
234922944501Smrg{
235022944501Smrg    drm_map_t map;
235122944501Smrg
2352424e9256Smrg    memclear(map);
235322944501Smrg    map.offset = idx;
235422944501Smrg    if (drmIoctl(fd, DRM_IOCTL_GET_MAP, &map))
2355fe517fc9Smrg        return -errno;
235622944501Smrg    *offset = map.offset;
235722944501Smrg    *size   = map.size;
235822944501Smrg    *type   = map.type;
235922944501Smrg    *flags  = map.flags;
236022944501Smrg    *handle = (unsigned long)map.handle;
236122944501Smrg    *mtrr   = map.mtrr;
236222944501Smrg    return 0;
236322944501Smrg}
236422944501Smrg
23656260e5d5Smrgdrm_public int drmGetClient(int fd, int idx, int *auth, int *pid, int *uid,
23666260e5d5Smrg                            unsigned long *magic, unsigned long *iocs)
236722944501Smrg{
236822944501Smrg    drm_client_t client;
236922944501Smrg
2370424e9256Smrg    memclear(client);
237122944501Smrg    client.idx = idx;
237222944501Smrg    if (drmIoctl(fd, DRM_IOCTL_GET_CLIENT, &client))
2373fe517fc9Smrg        return -errno;
237422944501Smrg    *auth      = client.auth;
237522944501Smrg    *pid       = client.pid;
237622944501Smrg    *uid       = client.uid;
237722944501Smrg    *magic     = client.magic;
237822944501Smrg    *iocs      = client.iocs;
237922944501Smrg    return 0;
238022944501Smrg}
238122944501Smrg
23826260e5d5Smrgdrm_public int drmGetStats(int fd, drmStatsT *stats)
238322944501Smrg{
238422944501Smrg    drm_stats_t s;
2385424e9256Smrg    unsigned    i;
238622944501Smrg
2387424e9256Smrg    memclear(s);
238822944501Smrg    if (drmIoctl(fd, DRM_IOCTL_GET_STATS, &s))
2389fe517fc9Smrg        return -errno;
239022944501Smrg
239122944501Smrg    stats->count = 0;
239222944501Smrg    memset(stats, 0, sizeof(*stats));
239322944501Smrg    if (s.count > sizeof(stats->data)/sizeof(stats->data[0]))
2394fe517fc9Smrg        return -1;
239522944501Smrg
239622944501Smrg#define SET_VALUE                              \
239722944501Smrg    stats->data[i].long_format = "%-20.20s";   \
239822944501Smrg    stats->data[i].rate_format = "%8.8s";      \
239922944501Smrg    stats->data[i].isvalue     = 1;            \
240022944501Smrg    stats->data[i].verbose     = 0
240122944501Smrg
240222944501Smrg#define SET_COUNT                              \
240322944501Smrg    stats->data[i].long_format = "%-20.20s";   \
240422944501Smrg    stats->data[i].rate_format = "%5.5s";      \
240522944501Smrg    stats->data[i].isvalue     = 0;            \
240622944501Smrg    stats->data[i].mult_names  = "kgm";        \
240722944501Smrg    stats->data[i].mult        = 1000;         \
240822944501Smrg    stats->data[i].verbose     = 0
240922944501Smrg
241022944501Smrg#define SET_BYTE                               \
241122944501Smrg    stats->data[i].long_format = "%-20.20s";   \
241222944501Smrg    stats->data[i].rate_format = "%5.5s";      \
241322944501Smrg    stats->data[i].isvalue     = 0;            \
241422944501Smrg    stats->data[i].mult_names  = "KGM";        \
241522944501Smrg    stats->data[i].mult        = 1024;         \
241622944501Smrg    stats->data[i].verbose     = 0
241722944501Smrg
241822944501Smrg
241922944501Smrg    stats->count = s.count;
242022944501Smrg    for (i = 0; i < s.count; i++) {
2421fe517fc9Smrg        stats->data[i].value = s.data[i].value;
2422fe517fc9Smrg        switch (s.data[i].type) {
2423fe517fc9Smrg        case _DRM_STAT_LOCK:
2424fe517fc9Smrg            stats->data[i].long_name = "Lock";
2425fe517fc9Smrg            stats->data[i].rate_name = "Lock";
2426fe517fc9Smrg            SET_VALUE;
2427fe517fc9Smrg            break;
2428fe517fc9Smrg        case _DRM_STAT_OPENS:
2429fe517fc9Smrg            stats->data[i].long_name = "Opens";
2430fe517fc9Smrg            stats->data[i].rate_name = "O";
2431fe517fc9Smrg            SET_COUNT;
2432fe517fc9Smrg            stats->data[i].verbose   = 1;
2433fe517fc9Smrg            break;
2434fe517fc9Smrg        case _DRM_STAT_CLOSES:
2435fe517fc9Smrg            stats->data[i].long_name = "Closes";
2436fe517fc9Smrg            stats->data[i].rate_name = "Lock";
2437fe517fc9Smrg            SET_COUNT;
2438fe517fc9Smrg            stats->data[i].verbose   = 1;
2439fe517fc9Smrg            break;
2440fe517fc9Smrg        case _DRM_STAT_IOCTLS:
2441fe517fc9Smrg            stats->data[i].long_name = "Ioctls";
2442fe517fc9Smrg            stats->data[i].rate_name = "Ioc/s";
2443fe517fc9Smrg            SET_COUNT;
2444fe517fc9Smrg            break;
2445fe517fc9Smrg        case _DRM_STAT_LOCKS:
2446fe517fc9Smrg            stats->data[i].long_name = "Locks";
2447fe517fc9Smrg            stats->data[i].rate_name = "Lck/s";
2448fe517fc9Smrg            SET_COUNT;
2449fe517fc9Smrg            break;
2450fe517fc9Smrg        case _DRM_STAT_UNLOCKS:
2451fe517fc9Smrg            stats->data[i].long_name = "Unlocks";
2452fe517fc9Smrg            stats->data[i].rate_name = "Unl/s";
2453fe517fc9Smrg            SET_COUNT;
2454fe517fc9Smrg            break;
2455fe517fc9Smrg        case _DRM_STAT_IRQ:
2456fe517fc9Smrg            stats->data[i].long_name = "IRQs";
2457fe517fc9Smrg            stats->data[i].rate_name = "IRQ/s";
2458fe517fc9Smrg            SET_COUNT;
2459fe517fc9Smrg            break;
2460fe517fc9Smrg        case _DRM_STAT_PRIMARY:
2461fe517fc9Smrg            stats->data[i].long_name = "Primary Bytes";
2462fe517fc9Smrg            stats->data[i].rate_name = "PB/s";
2463fe517fc9Smrg            SET_BYTE;
2464fe517fc9Smrg            break;
2465fe517fc9Smrg        case _DRM_STAT_SECONDARY:
2466fe517fc9Smrg            stats->data[i].long_name = "Secondary Bytes";
2467fe517fc9Smrg            stats->data[i].rate_name = "SB/s";
2468fe517fc9Smrg            SET_BYTE;
2469fe517fc9Smrg            break;
2470fe517fc9Smrg        case _DRM_STAT_DMA:
2471fe517fc9Smrg            stats->data[i].long_name = "DMA";
2472fe517fc9Smrg            stats->data[i].rate_name = "DMA/s";
2473fe517fc9Smrg            SET_COUNT;
2474fe517fc9Smrg            break;
2475fe517fc9Smrg        case _DRM_STAT_SPECIAL:
2476fe517fc9Smrg            stats->data[i].long_name = "Special DMA";
2477fe517fc9Smrg            stats->data[i].rate_name = "dma/s";
2478fe517fc9Smrg            SET_COUNT;
2479fe517fc9Smrg            break;
2480fe517fc9Smrg        case _DRM_STAT_MISSED:
2481fe517fc9Smrg            stats->data[i].long_name = "Miss";
2482fe517fc9Smrg            stats->data[i].rate_name = "Ms/s";
2483fe517fc9Smrg            SET_COUNT;
2484fe517fc9Smrg            break;
2485fe517fc9Smrg        case _DRM_STAT_VALUE:
2486fe517fc9Smrg            stats->data[i].long_name = "Value";
2487fe517fc9Smrg            stats->data[i].rate_name = "Value";
2488fe517fc9Smrg            SET_VALUE;
2489fe517fc9Smrg            break;
2490fe517fc9Smrg        case _DRM_STAT_BYTE:
2491fe517fc9Smrg            stats->data[i].long_name = "Bytes";
2492fe517fc9Smrg            stats->data[i].rate_name = "B/s";
2493fe517fc9Smrg            SET_BYTE;
2494fe517fc9Smrg            break;
2495fe517fc9Smrg        case _DRM_STAT_COUNT:
2496fe517fc9Smrg        default:
2497fe517fc9Smrg            stats->data[i].long_name = "Count";
2498fe517fc9Smrg            stats->data[i].rate_name = "Cnt/s";
2499fe517fc9Smrg            SET_COUNT;
2500fe517fc9Smrg            break;
2501fe517fc9Smrg        }
250222944501Smrg    }
250322944501Smrg    return 0;
250422944501Smrg}
250522944501Smrg
250622944501Smrg/**
250722944501Smrg * Issue a set-version ioctl.
250822944501Smrg *
250922944501Smrg * \param fd file descriptor.
2510fe517fc9Smrg * \param drmCommandIndex command index
251122944501Smrg * \param data source pointer of the data to be read and written.
251222944501Smrg * \param size size of the data to be read and written.
2513fe517fc9Smrg *
251422944501Smrg * \return zero on success, or a negative value on failure.
2515fe517fc9Smrg *
251622944501Smrg * \internal
2517fe517fc9Smrg * It issues a read-write ioctl given by
251822944501Smrg * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
251922944501Smrg */
25206260e5d5Smrgdrm_public int drmSetInterfaceVersion(int fd, drmSetVersion *version)
252122944501Smrg{
252222944501Smrg    int retcode = 0;
252322944501Smrg    drm_set_version_t sv;
252422944501Smrg
2525424e9256Smrg    memclear(sv);
252622944501Smrg    sv.drm_di_major = version->drm_di_major;
252722944501Smrg    sv.drm_di_minor = version->drm_di_minor;
252822944501Smrg    sv.drm_dd_major = version->drm_dd_major;
252922944501Smrg    sv.drm_dd_minor = version->drm_dd_minor;
253022944501Smrg
253122944501Smrg    if (drmIoctl(fd, DRM_IOCTL_SET_VERSION, &sv)) {
2532fe517fc9Smrg        retcode = -errno;
253322944501Smrg    }
253422944501Smrg
253522944501Smrg    version->drm_di_major = sv.drm_di_major;
253622944501Smrg    version->drm_di_minor = sv.drm_di_minor;
253722944501Smrg    version->drm_dd_major = sv.drm_dd_major;
253822944501Smrg    version->drm_dd_minor = sv.drm_dd_minor;
253922944501Smrg
254022944501Smrg    return retcode;
254122944501Smrg}
254222944501Smrg
254322944501Smrg/**
254422944501Smrg * Send a device-specific command.
254522944501Smrg *
254622944501Smrg * \param fd file descriptor.
2547fe517fc9Smrg * \param drmCommandIndex command index
2548fe517fc9Smrg *
254922944501Smrg * \return zero on success, or a negative value on failure.
2550fe517fc9Smrg *
255122944501Smrg * \internal
2552fe517fc9Smrg * It issues a ioctl given by
255322944501Smrg * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
255422944501Smrg */
25556260e5d5Smrgdrm_public int drmCommandNone(int fd, unsigned long drmCommandIndex)
255622944501Smrg{
255722944501Smrg    unsigned long request;
255822944501Smrg
255922944501Smrg    request = DRM_IO( DRM_COMMAND_BASE + drmCommandIndex);
256022944501Smrg
2561424e9256Smrg    if (drmIoctl(fd, request, NULL)) {
2562fe517fc9Smrg        return -errno;
256322944501Smrg    }
256422944501Smrg    return 0;
256522944501Smrg}
256622944501Smrg
256722944501Smrg
256822944501Smrg/**
256922944501Smrg * Send a device-specific read command.
257022944501Smrg *
257122944501Smrg * \param fd file descriptor.
2572fe517fc9Smrg * \param drmCommandIndex command index
257322944501Smrg * \param data destination pointer of the data to be read.
257422944501Smrg * \param size size of the data to be read.
2575fe517fc9Smrg *
257622944501Smrg * \return zero on success, or a negative value on failure.
257722944501Smrg *
257822944501Smrg * \internal
2579fe517fc9Smrg * It issues a read ioctl given by
258022944501Smrg * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
258122944501Smrg */
25826260e5d5Smrgdrm_public int drmCommandRead(int fd, unsigned long drmCommandIndex,
25836260e5d5Smrg                              void *data, unsigned long size)
258422944501Smrg{
258522944501Smrg    unsigned long request;
258622944501Smrg
2587fe517fc9Smrg    request = DRM_IOC( DRM_IOC_READ, DRM_IOCTL_BASE,
2588fe517fc9Smrg        DRM_COMMAND_BASE + drmCommandIndex, size);
258922944501Smrg
259022944501Smrg    if (drmIoctl(fd, request, data)) {
2591fe517fc9Smrg        return -errno;
259222944501Smrg    }
259322944501Smrg    return 0;
259422944501Smrg}
259522944501Smrg
259622944501Smrg
259722944501Smrg/**
259822944501Smrg * Send a device-specific write command.
259922944501Smrg *
260022944501Smrg * \param fd file descriptor.
2601fe517fc9Smrg * \param drmCommandIndex command index
260222944501Smrg * \param data source pointer of the data to be written.
260322944501Smrg * \param size size of the data to be written.
2604fe517fc9Smrg *
260522944501Smrg * \return zero on success, or a negative value on failure.
2606fe517fc9Smrg *
260722944501Smrg * \internal
2608fe517fc9Smrg * It issues a write ioctl given by
260922944501Smrg * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
261022944501Smrg */
26116260e5d5Smrgdrm_public int drmCommandWrite(int fd, unsigned long drmCommandIndex,
26126260e5d5Smrg                               void *data, unsigned long size)
261322944501Smrg{
261422944501Smrg    unsigned long request;
261522944501Smrg
2616fe517fc9Smrg    request = DRM_IOC( DRM_IOC_WRITE, DRM_IOCTL_BASE,
2617fe517fc9Smrg        DRM_COMMAND_BASE + drmCommandIndex, size);
261822944501Smrg
261922944501Smrg    if (drmIoctl(fd, request, data)) {
2620fe517fc9Smrg        return -errno;
262122944501Smrg    }
262222944501Smrg    return 0;
262322944501Smrg}
262422944501Smrg
262522944501Smrg
262622944501Smrg/**
262722944501Smrg * Send a device-specific read-write command.
262822944501Smrg *
262922944501Smrg * \param fd file descriptor.
2630fe517fc9Smrg * \param drmCommandIndex command index
263122944501Smrg * \param data source pointer of the data to be read and written.
263222944501Smrg * \param size size of the data to be read and written.
2633fe517fc9Smrg *
263422944501Smrg * \return zero on success, or a negative value on failure.
2635fe517fc9Smrg *
263622944501Smrg * \internal
2637fe517fc9Smrg * It issues a read-write ioctl given by
263822944501Smrg * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
263922944501Smrg */
26406260e5d5Smrgdrm_public int drmCommandWriteRead(int fd, unsigned long drmCommandIndex,
26416260e5d5Smrg                                   void *data, unsigned long size)
264222944501Smrg{
264322944501Smrg    unsigned long request;
264422944501Smrg
2645fe517fc9Smrg    request = DRM_IOC( DRM_IOC_READ|DRM_IOC_WRITE, DRM_IOCTL_BASE,
2646fe517fc9Smrg        DRM_COMMAND_BASE + drmCommandIndex, size);
264722944501Smrg
264822944501Smrg    if (drmIoctl(fd, request, data))
2649fe517fc9Smrg        return -errno;
265022944501Smrg    return 0;
265122944501Smrg}
265222944501Smrg
265322944501Smrg#define DRM_MAX_FDS 16
265422944501Smrgstatic struct {
265522944501Smrg    char *BusID;
265622944501Smrg    int fd;
265722944501Smrg    int refcount;
2658424e9256Smrg    int type;
265922944501Smrg} connection[DRM_MAX_FDS];
266022944501Smrg
266122944501Smrgstatic int nr_fds = 0;
266222944501Smrg
26636260e5d5Smrgdrm_public int drmOpenOnce(void *unused, const char *BusID, int *newlyopened)
2664424e9256Smrg{
2665424e9256Smrg    return drmOpenOnceWithType(BusID, newlyopened, DRM_NODE_PRIMARY);
2666424e9256Smrg}
2667424e9256Smrg
26686260e5d5Smrgdrm_public int drmOpenOnceWithType(const char *BusID, int *newlyopened,
26696260e5d5Smrg                                   int type)
267022944501Smrg{
267122944501Smrg    int i;
267222944501Smrg    int fd;
2673fe517fc9Smrg
267422944501Smrg    for (i = 0; i < nr_fds; i++)
2675fe517fc9Smrg        if ((strcmp(BusID, connection[i].BusID) == 0) &&
2676fe517fc9Smrg            (connection[i].type == type)) {
2677fe517fc9Smrg            connection[i].refcount++;
2678fe517fc9Smrg            *newlyopened = 0;
2679fe517fc9Smrg            return connection[i].fd;
2680fe517fc9Smrg        }
268122944501Smrg
2682424e9256Smrg    fd = drmOpenWithType(NULL, BusID, type);
2683fe517fc9Smrg    if (fd < 0 || nr_fds == DRM_MAX_FDS)
2684fe517fc9Smrg        return fd;
2685fe517fc9Smrg
268622944501Smrg    connection[nr_fds].BusID = strdup(BusID);
268722944501Smrg    connection[nr_fds].fd = fd;
268822944501Smrg    connection[nr_fds].refcount = 1;
2689424e9256Smrg    connection[nr_fds].type = type;
269022944501Smrg    *newlyopened = 1;
269122944501Smrg
269222944501Smrg    if (0)
2693fe517fc9Smrg        fprintf(stderr, "saved connection %d for %s %d\n",
2694fe517fc9Smrg                nr_fds, connection[nr_fds].BusID,
2695fe517fc9Smrg                strcmp(BusID, connection[nr_fds].BusID));
269622944501Smrg
269722944501Smrg    nr_fds++;
269822944501Smrg
269922944501Smrg    return fd;
270022944501Smrg}
270122944501Smrg
27026260e5d5Smrgdrm_public void drmCloseOnce(int fd)
270322944501Smrg{
270422944501Smrg    int i;
270522944501Smrg
270622944501Smrg    for (i = 0; i < nr_fds; i++) {
2707fe517fc9Smrg        if (fd == connection[i].fd) {
2708fe517fc9Smrg            if (--connection[i].refcount == 0) {
2709fe517fc9Smrg                drmClose(connection[i].fd);
2710fe517fc9Smrg                free(connection[i].BusID);
2711fe517fc9Smrg
2712fe517fc9Smrg                if (i < --nr_fds)
2713fe517fc9Smrg                    connection[i] = connection[nr_fds];
2714fe517fc9Smrg
2715fe517fc9Smrg                return;
2716fe517fc9Smrg            }
2717fe517fc9Smrg        }
271822944501Smrg    }
271922944501Smrg}
272022944501Smrg
27216260e5d5Smrgdrm_public int drmSetMaster(int fd)
272222944501Smrg{
2723fe517fc9Smrg        return drmIoctl(fd, DRM_IOCTL_SET_MASTER, NULL);
272422944501Smrg}
272522944501Smrg
27266260e5d5Smrgdrm_public int drmDropMaster(int fd)
272722944501Smrg{
2728fe517fc9Smrg        return drmIoctl(fd, DRM_IOCTL_DROP_MASTER, NULL);
272922944501Smrg}
273022944501Smrg
2731bf6cc7dcSmrgdrm_public int drmIsMaster(int fd)
2732bf6cc7dcSmrg{
2733bf6cc7dcSmrg        /* Detect master by attempting something that requires master.
2734bf6cc7dcSmrg         *
2735bf6cc7dcSmrg         * Authenticating magic tokens requires master and 0 is an
2736bf6cc7dcSmrg         * internal kernel detail which we could use. Attempting this on
2737bf6cc7dcSmrg         * a master fd would fail therefore fail with EINVAL because 0
2738bf6cc7dcSmrg         * is invalid.
2739bf6cc7dcSmrg         *
2740bf6cc7dcSmrg         * A non-master fd will fail with EACCES, as the kernel checks
2741bf6cc7dcSmrg         * for master before attempting to do anything else.
2742bf6cc7dcSmrg         *
2743bf6cc7dcSmrg         * Since we don't want to leak implementation details, use
2744bf6cc7dcSmrg         * EACCES.
2745bf6cc7dcSmrg         */
2746bf6cc7dcSmrg        return drmAuthMagic(fd, 0) != -EACCES;
2747bf6cc7dcSmrg}
2748bf6cc7dcSmrg
27496260e5d5Smrgdrm_public char *drmGetDeviceNameFromFd(int fd)
275022944501Smrg{
2751fe517fc9Smrg    char name[128];
2752fe517fc9Smrg    struct stat sbuf;
2753fe517fc9Smrg    dev_t d;
2754fe517fc9Smrg    int i;
275522944501Smrg
2756fe517fc9Smrg    /* The whole drmOpen thing is a fiasco and we need to find a way
2757fe517fc9Smrg     * back to just using open(2).  For now, however, lets just make
2758fe517fc9Smrg     * things worse with even more ad hoc directory walking code to
2759fe517fc9Smrg     * discover the device file name. */
276022944501Smrg
2761fe517fc9Smrg    fstat(fd, &sbuf);
2762fe517fc9Smrg    d = sbuf.st_rdev;
276322944501Smrg
2764fe517fc9Smrg    for (i = 0; i < DRM_MAX_MINOR; i++) {
2765fe517fc9Smrg        snprintf(name, sizeof name, DRM_DEV_NAME, DRM_DIR_NAME, i);
2766fe517fc9Smrg        if (stat(name, &sbuf) == 0 && sbuf.st_rdev == d)
2767fe517fc9Smrg            break;
2768fe517fc9Smrg    }
2769fe517fc9Smrg    if (i == DRM_MAX_MINOR)
2770fe517fc9Smrg        return NULL;
277122944501Smrg
2772fe517fc9Smrg    return strdup(name);
277322944501Smrg}
277420131375Smrg
27756260e5d5Smrgstatic bool drmNodeIsDRM(int maj, int min)
27766260e5d5Smrg{
27776260e5d5Smrg#ifdef __linux__
27786260e5d5Smrg    char path[64];
27796260e5d5Smrg    struct stat sbuf;
27806260e5d5Smrg
27816260e5d5Smrg    snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device/drm",
27826260e5d5Smrg             maj, min);
27836260e5d5Smrg    return stat(path, &sbuf) == 0;
27846260e5d5Smrg#else
27856260e5d5Smrg    return maj == DRM_MAJOR;
27866260e5d5Smrg#endif
27876260e5d5Smrg}
27886260e5d5Smrg
27896260e5d5Smrgdrm_public int drmGetNodeTypeFromFd(int fd)
2790424e9256Smrg{
2791fe517fc9Smrg    struct stat sbuf;
2792fe517fc9Smrg    int maj, min, type;
2793424e9256Smrg
2794fe517fc9Smrg    if (fstat(fd, &sbuf))
2795fe517fc9Smrg        return -1;
2796424e9256Smrg
2797fe517fc9Smrg    maj = major(sbuf.st_rdev);
2798fe517fc9Smrg    min = minor(sbuf.st_rdev);
2799424e9256Smrg
28006260e5d5Smrg    if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode)) {
2801fe517fc9Smrg        errno = EINVAL;
2802fe517fc9Smrg        return -1;
2803fe517fc9Smrg    }
2804424e9256Smrg
2805fe517fc9Smrg    type = drmGetMinorType(min);
2806fe517fc9Smrg    if (type == -1)
2807fe517fc9Smrg        errno = ENODEV;
2808fe517fc9Smrg    return type;
2809424e9256Smrg}
2810424e9256Smrg
28116260e5d5Smrgdrm_public int drmPrimeHandleToFD(int fd, uint32_t handle, uint32_t flags,
28126260e5d5Smrg                                  int *prime_fd)
281320131375Smrg{
2814fe517fc9Smrg    struct drm_prime_handle args;
2815fe517fc9Smrg    int ret;
281620131375Smrg
2817fe517fc9Smrg    memclear(args);
2818fe517fc9Smrg    args.fd = -1;
2819fe517fc9Smrg    args.handle = handle;
2820fe517fc9Smrg    args.flags = flags;
2821fe517fc9Smrg    ret = drmIoctl(fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &args);
2822fe517fc9Smrg    if (ret)
2823fe517fc9Smrg        return ret;
282420131375Smrg
2825fe517fc9Smrg    *prime_fd = args.fd;
2826fe517fc9Smrg    return 0;
282720131375Smrg}
282820131375Smrg
28296260e5d5Smrgdrm_public int drmPrimeFDToHandle(int fd, int prime_fd, uint32_t *handle)
283020131375Smrg{
2831fe517fc9Smrg    struct drm_prime_handle args;
2832fe517fc9Smrg    int ret;
283320131375Smrg
2834fe517fc9Smrg    memclear(args);
2835fe517fc9Smrg    args.fd = prime_fd;
2836fe517fc9Smrg    ret = drmIoctl(fd, DRM_IOCTL_PRIME_FD_TO_HANDLE, &args);
2837fe517fc9Smrg    if (ret)
2838fe517fc9Smrg        return ret;
283920131375Smrg
2840fe517fc9Smrg    *handle = args.handle;
2841fe517fc9Smrg    return 0;
284220131375Smrg}
2843424e9256Smrg
2844424e9256Smrgstatic char *drmGetMinorNameForFD(int fd, int type)
2845424e9256Smrg{
2846424e9256Smrg#ifdef __linux__
2847fe517fc9Smrg    DIR *sysdir;
28486260e5d5Smrg    struct dirent *ent;
2849fe517fc9Smrg    struct stat sbuf;
2850fe517fc9Smrg    const char *name = drmGetMinorName(type);
2851fe517fc9Smrg    int len;
2852fe517fc9Smrg    char dev_name[64], buf[64];
2853fe517fc9Smrg    int maj, min;
2854fe517fc9Smrg
2855fe517fc9Smrg    if (!name)
2856fe517fc9Smrg        return NULL;
2857424e9256Smrg
2858fe517fc9Smrg    len = strlen(name);
2859424e9256Smrg
2860fe517fc9Smrg    if (fstat(fd, &sbuf))
2861fe517fc9Smrg        return NULL;
2862424e9256Smrg
2863fe517fc9Smrg    maj = major(sbuf.st_rdev);
2864fe517fc9Smrg    min = minor(sbuf.st_rdev);
2865424e9256Smrg
28666260e5d5Smrg    if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode))
2867fe517fc9Smrg        return NULL;
2868424e9256Smrg
2869fe517fc9Smrg    snprintf(buf, sizeof(buf), "/sys/dev/char/%d:%d/device/drm", maj, min);
2870424e9256Smrg
2871fe517fc9Smrg    sysdir = opendir(buf);
2872fe517fc9Smrg    if (!sysdir)
2873fe517fc9Smrg        return NULL;
2874424e9256Smrg
28756260e5d5Smrg    while ((ent = readdir(sysdir))) {
2876fe517fc9Smrg        if (strncmp(ent->d_name, name, len) == 0) {
2877fe517fc9Smrg            snprintf(dev_name, sizeof(dev_name), DRM_DIR_NAME "/%s",
2878fe517fc9Smrg                 ent->d_name);
2879424e9256Smrg
2880fe517fc9Smrg            closedir(sysdir);
2881fe517fc9Smrg            return strdup(dev_name);
2882fe517fc9Smrg        }
2883fe517fc9Smrg    }
2884424e9256Smrg
2885fe517fc9Smrg    closedir(sysdir);
28866260e5d5Smrg    return NULL;
2887fe517fc9Smrg#else
28882ee35494Smrg    struct stat sbuf;
28892ee35494Smrg    char buf[PATH_MAX + 1];
289082025ec7Smrg    const char *dev_name = drmGetDeviceName(type);
28912ee35494Smrg    unsigned int maj, min;
289282025ec7Smrg    int n;
28932ee35494Smrg
28942ee35494Smrg    if (fstat(fd, &sbuf))
28952ee35494Smrg        return NULL;
28962ee35494Smrg
28972ee35494Smrg    maj = major(sbuf.st_rdev);
28982ee35494Smrg    min = minor(sbuf.st_rdev);
28992ee35494Smrg
29006260e5d5Smrg    if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode))
29012ee35494Smrg        return NULL;
29022ee35494Smrg
290382025ec7Smrg    if (!dev_name)
29042ee35494Smrg        return NULL;
29052ee35494Smrg
290682025ec7Smrg    n = snprintf(buf, sizeof(buf), dev_name, DRM_DIR_NAME, min);
29072ee35494Smrg    if (n == -1 || n >= sizeof(buf))
29082ee35494Smrg        return NULL;
29092ee35494Smrg
29102ee35494Smrg    return strdup(buf);
2911424e9256Smrg#endif
2912424e9256Smrg}
2913424e9256Smrg
29146260e5d5Smrgdrm_public char *drmGetPrimaryDeviceNameFromFd(int fd)
2915424e9256Smrg{
2916fe517fc9Smrg    return drmGetMinorNameForFD(fd, DRM_NODE_PRIMARY);
2917424e9256Smrg}
2918424e9256Smrg
29196260e5d5Smrgdrm_public char *drmGetRenderDeviceNameFromFd(int fd)
2920424e9256Smrg{
2921fe517fc9Smrg    return drmGetMinorNameForFD(fd, DRM_NODE_RENDER);
2922fe517fc9Smrg}
2923fe517fc9Smrg
29242ee35494Smrg#ifdef __linux__
29252ee35494Smrgstatic char * DRM_PRINTFLIKE(2, 3)
29262ee35494Smrgsysfs_uevent_get(const char *path, const char *fmt, ...)
29272ee35494Smrg{
29282ee35494Smrg    char filename[PATH_MAX + 1], *key, *line = NULL, *value = NULL;
29292ee35494Smrg    size_t size = 0, len;
29302ee35494Smrg    ssize_t num;
29312ee35494Smrg    va_list ap;
29322ee35494Smrg    FILE *fp;
29332ee35494Smrg
29342ee35494Smrg    va_start(ap, fmt);
29352ee35494Smrg    num = vasprintf(&key, fmt, ap);
29362ee35494Smrg    va_end(ap);
29372ee35494Smrg    len = num;
29382ee35494Smrg
29392ee35494Smrg    snprintf(filename, sizeof(filename), "%s/uevent", path);
29402ee35494Smrg
29412ee35494Smrg    fp = fopen(filename, "r");
29422ee35494Smrg    if (!fp) {
29432ee35494Smrg        free(key);
29442ee35494Smrg        return NULL;
29452ee35494Smrg    }
29462ee35494Smrg
29472ee35494Smrg    while ((num = getline(&line, &size, fp)) >= 0) {
29482ee35494Smrg        if ((strncmp(line, key, len) == 0) && (line[len] == '=')) {
29492ee35494Smrg            char *start = line + len + 1, *end = line + num - 1;
29502ee35494Smrg
29512ee35494Smrg            if (*end != '\n')
29522ee35494Smrg                end++;
29532ee35494Smrg
29542ee35494Smrg            value = strndup(start, end - start);
29552ee35494Smrg            break;
29562ee35494Smrg        }
29572ee35494Smrg    }
29582ee35494Smrg
29592ee35494Smrg    free(line);
29602ee35494Smrg    fclose(fp);
29612ee35494Smrg
29622ee35494Smrg    free(key);
29632ee35494Smrg
29642ee35494Smrg    return value;
29652ee35494Smrg}
29662ee35494Smrg#endif
29672ee35494Smrg
29686260e5d5Smrg/* Little white lie to avoid major rework of the existing code */
29696260e5d5Smrg#define DRM_BUS_VIRTIO 0x10
29706260e5d5Smrg
2971fe517fc9Smrgstatic int drmParseSubsystemType(int maj, int min)
2972fe517fc9Smrg{
2973fe517fc9Smrg#ifdef __linux__
2974fe517fc9Smrg    char path[PATH_MAX + 1];
2975fe517fc9Smrg    char link[PATH_MAX + 1] = "";
2976fe517fc9Smrg    char *name;
29774545e80cSmrg    struct {
29784545e80cSmrg        const char *name;
29794545e80cSmrg        int bus_type;
29804545e80cSmrg    } bus_types[] = {
29814545e80cSmrg        { "/pci", DRM_BUS_PCI },
29824545e80cSmrg        { "/usb", DRM_BUS_USB },
29834545e80cSmrg        { "/platform", DRM_BUS_PLATFORM },
29844545e80cSmrg        { "/spi", DRM_BUS_PLATFORM },
29854545e80cSmrg        { "/host1x", DRM_BUS_HOST1X },
29864545e80cSmrg        { "/virtio", DRM_BUS_VIRTIO },
29874545e80cSmrg    };
2988fe517fc9Smrg
2989fe517fc9Smrg    snprintf(path, PATH_MAX, "/sys/dev/char/%d:%d/device/subsystem",
2990fe517fc9Smrg             maj, min);
2991fe517fc9Smrg
2992fe517fc9Smrg    if (readlink(path, link, PATH_MAX) < 0)
2993fe517fc9Smrg        return -errno;
2994fe517fc9Smrg
2995fe517fc9Smrg    name = strrchr(link, '/');
2996fe517fc9Smrg    if (!name)
2997fe517fc9Smrg        return -EINVAL;
2998fe517fc9Smrg
29994545e80cSmrg    for (unsigned i = 0; i < ARRAY_SIZE(bus_types); i++) {
30004545e80cSmrg        if (strncmp(name, bus_types[i].name, strlen(bus_types[i].name)) == 0)
30014545e80cSmrg            return bus_types[i].bus_type;
30024545e80cSmrg    }
30036260e5d5Smrg
3004fe517fc9Smrg    return -EINVAL;
3005a970b457Sriastradh#elif defined(__NetBSD__)
3006a970b457Sriastradh    int type, fd;
3007a970b457Sriastradh    drmSetVersion sv;
3008a970b457Sriastradh    char *buf;
3009a970b457Sriastradh    unsigned domain, bus, dev;
3010a970b457Sriastradh    int func;
3011a970b457Sriastradh    int ret;
3012a970b457Sriastradh
3013a970b457Sriastradh    /* Get the type of device we're looking for to pick the right pathname.  */
3014a970b457Sriastradh    type = drmGetMinorType(min);
3015a970b457Sriastradh    if (type == -1)
3016a970b457Sriastradh	return -ENODEV;
3017a970b457Sriastradh
3018a970b457Sriastradh    /* Open the device.  Don't try to create it if it's not there.  */
3019a970b457Sriastradh    fd = drmOpenMinor(min, 0, type);
3020a970b457Sriastradh    if (fd < 0)
3021a970b457Sriastradh	return -errno;
3022a970b457Sriastradh
3023a970b457Sriastradh    /*
3024a970b457Sriastradh     * Set the interface version to 1.4 or 1.1, which has the effect of
3025a970b457Sriastradh     * populating the bus id for us.
3026a970b457Sriastradh     */
3027a970b457Sriastradh    sv.drm_di_major = 1;
3028a970b457Sriastradh    sv.drm_di_minor = 4;
3029a970b457Sriastradh    sv.drm_dd_major = -1;
3030a970b457Sriastradh    sv.drm_dd_minor = -1;
3031a970b457Sriastradh    if (drmSetInterfaceVersion(fd, &sv)) {
3032a970b457Sriastradh	sv.drm_di_major = 1;
3033a970b457Sriastradh	sv.drm_di_minor = 1;
3034a970b457Sriastradh	sv.drm_dd_major = -1;
3035a970b457Sriastradh	sv.drm_dd_minor = -1;
3036a970b457Sriastradh	if (drmSetInterfaceVersion(fd, &sv)) {
30375046d36bSriastradh	    /*
30385046d36bSriastradh	     * We're probably not the master.  Hope the master already
30395046d36bSriastradh	     * set the version to >=1.1 so that we can get the busid.
30405046d36bSriastradh	     */
3041a970b457Sriastradh	}
3042a970b457Sriastradh    }
3043a970b457Sriastradh
3044a970b457Sriastradh    /* Get the bus id.  */
3045a970b457Sriastradh    buf = drmGetBusid(fd);
3046a970b457Sriastradh
3047a970b457Sriastradh    /* We're done with the device now.  */
3048a970b457Sriastradh    (void)close(fd);
3049a970b457Sriastradh
3050a970b457Sriastradh    /* If there is no bus id, fail.  */
3051a970b457Sriastradh    if (buf == NULL)
3052a970b457Sriastradh	return -ENODEV;
3053a970b457Sriastradh
3054a970b457Sriastradh    /* Find a string we know about; otherwise -EINVAL.  */
3055a970b457Sriastradh    ret = -EINVAL;
305648994cb0Sriastradh    if (strncmp(buf, "pci:", 4) == 0)
3057a970b457Sriastradh	ret = DRM_BUS_PCI;
3058a970b457Sriastradh
3059a970b457Sriastradh    /* We're done with the bus id.  */
3060a970b457Sriastradh    free(buf);
3061a970b457Sriastradh
3062a970b457Sriastradh    /* Success or not, we're done.  */
3063a970b457Sriastradh    return ret;
30644545e80cSmrg#elif defined(__OpenBSD__) || defined(__DragonFly__)
30652ee35494Smrg    return DRM_BUS_PCI;
3066fe517fc9Smrg#else
3067fe517fc9Smrg#warning "Missing implementation of drmParseSubsystemType"
3068fe517fc9Smrg    return -EINVAL;
3069fe517fc9Smrg#endif
3070fe517fc9Smrg}
3071fe517fc9Smrg
30726260e5d5Smrgstatic void
30736260e5d5Smrgget_pci_path(int maj, int min, char *pci_path)
30746260e5d5Smrg{
30756260e5d5Smrg    char path[PATH_MAX + 1], *term;
30766260e5d5Smrg
30776260e5d5Smrg    snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min);
30786260e5d5Smrg    if (!realpath(path, pci_path)) {
30796260e5d5Smrg        strcpy(pci_path, path);
30806260e5d5Smrg        return;
30816260e5d5Smrg    }
30826260e5d5Smrg
30836260e5d5Smrg    term = strrchr(pci_path, '/');
30846260e5d5Smrg    if (term && strncmp(term, "/virtio", 7) == 0)
30856260e5d5Smrg        *term = 0;
30866260e5d5Smrg}
30876260e5d5Smrg
3088fe517fc9Smrgstatic int drmParsePciBusInfo(int maj, int min, drmPciBusInfoPtr info)
3089fe517fc9Smrg{
3090fe517fc9Smrg#ifdef __linux__
30912ee35494Smrg    unsigned int domain, bus, dev, func;
30926260e5d5Smrg    char pci_path[PATH_MAX + 1], *value;
30932ee35494Smrg    int num;
3094fe517fc9Smrg
30956260e5d5Smrg    get_pci_path(maj, min, pci_path);
3096fe517fc9Smrg
30976260e5d5Smrg    value = sysfs_uevent_get(pci_path, "PCI_SLOT_NAME");
30982ee35494Smrg    if (!value)
30992ee35494Smrg        return -ENOENT;
3100fe517fc9Smrg
31012ee35494Smrg    num = sscanf(value, "%04x:%02x:%02x.%1u", &domain, &bus, &dev, &func);
31022ee35494Smrg    free(value);
3103fe517fc9Smrg
31042ee35494Smrg    if (num != 4)
3105fe517fc9Smrg        return -EINVAL;
3106fe517fc9Smrg
3107fe517fc9Smrg    info->domain = domain;
3108fe517fc9Smrg    info->bus = bus;
3109fe517fc9Smrg    info->dev = dev;
3110fe517fc9Smrg    info->func = func;
3111fe517fc9Smrg
3112a970b457Sriastradh    return 0;
3113a970b457Sriastradh#elif defined(__NetBSD__)
3114a970b457Sriastradh    int type, fd;
3115a970b457Sriastradh    drmSetVersion sv;
3116a970b457Sriastradh    char *buf;
3117a970b457Sriastradh    unsigned domain, bus, dev;
3118a970b457Sriastradh    int func;
3119a970b457Sriastradh    int ret;
3120a970b457Sriastradh
3121a970b457Sriastradh    /* Get the type of device we're looking for to pick the right pathname.  */
3122a970b457Sriastradh    type = drmGetMinorType(min);
3123a970b457Sriastradh    if (type == -1)
3124a970b457Sriastradh	return -ENODEV;
3125a970b457Sriastradh
3126a970b457Sriastradh    /* Open the device.  Don't try to create it if it's not there.  */
3127a970b457Sriastradh    fd = drmOpenMinor(min, 0, type);
3128a970b457Sriastradh    if (fd < 0)
3129a970b457Sriastradh	return -errno;
3130a970b457Sriastradh
3131a970b457Sriastradh    /*
3132a970b457Sriastradh     * Set the interface version to 1.4 or 1.1, which has the effect of
3133a970b457Sriastradh     * populating the bus id for us.
3134a970b457Sriastradh     */
3135a970b457Sriastradh    sv.drm_di_major = 1;
3136a970b457Sriastradh    sv.drm_di_minor = 4;
3137a970b457Sriastradh    sv.drm_dd_major = -1;
3138a970b457Sriastradh    sv.drm_dd_minor = -1;
3139a970b457Sriastradh    if (drmSetInterfaceVersion(fd, &sv)) {
3140a970b457Sriastradh	sv.drm_di_major = 1;
3141a970b457Sriastradh	sv.drm_di_minor = 1;
3142a970b457Sriastradh	sv.drm_dd_major = -1;
3143a970b457Sriastradh	sv.drm_dd_minor = -1;
3144a970b457Sriastradh	if (drmSetInterfaceVersion(fd, &sv)) {
314506815bcbSmaya            /*
314606815bcbSmaya	     * We're probably not the master.  Hope the master already
314706815bcbSmaya	     * set the version to >=1.1 so that we can get the busid.
314806815bcbSmaya	     */
3149a970b457Sriastradh	}
3150a970b457Sriastradh    }
3151a970b457Sriastradh
3152a970b457Sriastradh    /* Get the bus id.  */
3153a970b457Sriastradh    buf = drmGetBusid(fd);
3154a970b457Sriastradh
3155a970b457Sriastradh    /* We're done with the device now.  */
3156a970b457Sriastradh    (void)close(fd);
3157a970b457Sriastradh
3158a970b457Sriastradh    /* If there is no bus id, fail.  */
3159a970b457Sriastradh    if (buf == NULL)
3160a970b457Sriastradh	return -ENODEV;
3161a970b457Sriastradh
3162a970b457Sriastradh    /* Parse the bus id.  */
3163a970b457Sriastradh    ret = sscanf(buf, "pci:%04x:%02x:%02x.%d", &domain, &bus, &dev, &func);
3164a970b457Sriastradh
3165a970b457Sriastradh    /* We're done with the bus id.  */
3166a970b457Sriastradh    free(buf);
3167a970b457Sriastradh
3168a970b457Sriastradh    /* If scanf didn't return 4 -- domain, bus, dev, func -- then fail.  */
3169a970b457Sriastradh    if (ret != 4)
3170a970b457Sriastradh	return -ENODEV;
3171a970b457Sriastradh
3172a970b457Sriastradh    /* Populate the results.  */
3173a970b457Sriastradh    info->domain = domain;
3174a970b457Sriastradh    info->bus = bus;
3175a970b457Sriastradh    info->dev = dev;
3176a970b457Sriastradh    info->func = func;
3177a970b457Sriastradh
3178a970b457Sriastradh    /* Success!  */
31792ee35494Smrg    return 0;
31804545e80cSmrg#elif defined(__OpenBSD__) || defined(__DragonFly__)
31812ee35494Smrg    struct drm_pciinfo pinfo;
31822ee35494Smrg    int fd, type;
31832ee35494Smrg
31842ee35494Smrg    type = drmGetMinorType(min);
31852ee35494Smrg    if (type == -1)
31862ee35494Smrg        return -ENODEV;
31872ee35494Smrg
31882ee35494Smrg    fd = drmOpenMinor(min, 0, type);
31892ee35494Smrg    if (fd < 0)
31902ee35494Smrg        return -errno;
31912ee35494Smrg
31922ee35494Smrg    if (drmIoctl(fd, DRM_IOCTL_GET_PCIINFO, &pinfo)) {
31932ee35494Smrg        close(fd);
31942ee35494Smrg        return -errno;
31952ee35494Smrg    }
31962ee35494Smrg    close(fd);
31972ee35494Smrg
31982ee35494Smrg    info->domain = pinfo.domain;
31992ee35494Smrg    info->bus = pinfo.bus;
32002ee35494Smrg    info->dev = pinfo.dev;
32012ee35494Smrg    info->func = pinfo.func;
32022ee35494Smrg
3203fe517fc9Smrg    return 0;
3204fe517fc9Smrg#else
3205fe517fc9Smrg#warning "Missing implementation of drmParsePciBusInfo"
3206fe517fc9Smrg    return -EINVAL;
3207fe517fc9Smrg#endif
3208fe517fc9Smrg}
3209fe517fc9Smrg
32106260e5d5Smrgdrm_public int drmDevicesEqual(drmDevicePtr a, drmDevicePtr b)
3211fe517fc9Smrg{
3212fe517fc9Smrg    if (a == NULL || b == NULL)
32130655efefSmrg        return 0;
3214fe517fc9Smrg
3215fe517fc9Smrg    if (a->bustype != b->bustype)
32160655efefSmrg        return 0;
3217fe517fc9Smrg
3218fe517fc9Smrg    switch (a->bustype) {
3219fe517fc9Smrg    case DRM_BUS_PCI:
32200655efefSmrg        return memcmp(a->businfo.pci, b->businfo.pci, sizeof(drmPciBusInfo)) == 0;
32212ee35494Smrg
32222ee35494Smrg    case DRM_BUS_USB:
32230655efefSmrg        return memcmp(a->businfo.usb, b->businfo.usb, sizeof(drmUsbBusInfo)) == 0;
32242ee35494Smrg
32252ee35494Smrg    case DRM_BUS_PLATFORM:
32260655efefSmrg        return memcmp(a->businfo.platform, b->businfo.platform, sizeof(drmPlatformBusInfo)) == 0;
32272ee35494Smrg
32282ee35494Smrg    case DRM_BUS_HOST1X:
32290655efefSmrg        return memcmp(a->businfo.host1x, b->businfo.host1x, sizeof(drmHost1xBusInfo)) == 0;
32302ee35494Smrg
3231fe517fc9Smrg    default:
3232fe517fc9Smrg        break;
3233fe517fc9Smrg    }
3234fe517fc9Smrg
32350655efefSmrg    return 0;
3236fe517fc9Smrg}
3237fe517fc9Smrg
3238fe517fc9Smrgstatic int drmGetNodeType(const char *name)
3239fe517fc9Smrg{
3240fe517fc9Smrg    if (strncmp(name, DRM_CONTROL_MINOR_NAME,
3241fe517fc9Smrg        sizeof(DRM_CONTROL_MINOR_NAME ) - 1) == 0)
3242fe517fc9Smrg        return DRM_NODE_CONTROL;
3243fe517fc9Smrg
3244fe517fc9Smrg    if (strncmp(name, DRM_RENDER_MINOR_NAME,
3245fe517fc9Smrg        sizeof(DRM_RENDER_MINOR_NAME) - 1) == 0)
3246fe517fc9Smrg        return DRM_NODE_RENDER;
3247fe517fc9Smrg
324882025ec7Smrg    if (strncmp(name, DRM_PRIMARY_MINOR_NAME,
324982025ec7Smrg        sizeof(DRM_PRIMARY_MINOR_NAME) - 1) == 0)
325082025ec7Smrg        return DRM_NODE_PRIMARY;
325182025ec7Smrg
3252fe517fc9Smrg    return -EINVAL;
3253fe517fc9Smrg}
3254fe517fc9Smrg
3255fe517fc9Smrgstatic int drmGetMaxNodeName(void)
3256fe517fc9Smrg{
3257fe517fc9Smrg    return sizeof(DRM_DIR_NAME) +
3258fe517fc9Smrg           MAX3(sizeof(DRM_PRIMARY_MINOR_NAME),
3259fe517fc9Smrg                sizeof(DRM_CONTROL_MINOR_NAME),
3260fe517fc9Smrg                sizeof(DRM_RENDER_MINOR_NAME)) +
3261fe517fc9Smrg           3 /* length of the node number */;
3262fe517fc9Smrg}
3263fe517fc9Smrg
3264fe517fc9Smrg#ifdef __linux__
32652ee35494Smrgstatic int parse_separate_sysfs_files(int maj, int min,
32662ee35494Smrg                                      drmPciDeviceInfoPtr device,
32672ee35494Smrg                                      bool ignore_revision)
32682ee35494Smrg{
32692ee35494Smrg    static const char *attrs[] = {
32702ee35494Smrg      "revision", /* Older kernels are missing the file, so check for it first */
32712ee35494Smrg      "vendor",
32722ee35494Smrg      "device",
32732ee35494Smrg      "subsystem_vendor",
32742ee35494Smrg      "subsystem_device",
32752ee35494Smrg    };
32766260e5d5Smrg    char path[PATH_MAX + 1], pci_path[PATH_MAX + 1];
32772ee35494Smrg    unsigned int data[ARRAY_SIZE(attrs)];
32782ee35494Smrg    FILE *fp;
32792ee35494Smrg    int ret;
32802ee35494Smrg
32816260e5d5Smrg    get_pci_path(maj, min, pci_path);
32826260e5d5Smrg
32832ee35494Smrg    for (unsigned i = ignore_revision ? 1 : 0; i < ARRAY_SIZE(attrs); i++) {
32846260e5d5Smrg        snprintf(path, PATH_MAX, "%s/%s", pci_path, attrs[i]);
32852ee35494Smrg        fp = fopen(path, "r");
32862ee35494Smrg        if (!fp)
32872ee35494Smrg            return -errno;
32882ee35494Smrg
32892ee35494Smrg        ret = fscanf(fp, "%x", &data[i]);
32902ee35494Smrg        fclose(fp);
32912ee35494Smrg        if (ret != 1)
32922ee35494Smrg            return -errno;
32932ee35494Smrg
32942ee35494Smrg    }
32952ee35494Smrg
32962ee35494Smrg    device->revision_id = ignore_revision ? 0xff : data[0] & 0xff;
32972ee35494Smrg    device->vendor_id = data[1] & 0xffff;
32982ee35494Smrg    device->device_id = data[2] & 0xffff;
32992ee35494Smrg    device->subvendor_id = data[3] & 0xffff;
33002ee35494Smrg    device->subdevice_id = data[4] & 0xffff;
33012ee35494Smrg
33022ee35494Smrg    return 0;
33032ee35494Smrg}
33042ee35494Smrg
33052ee35494Smrgstatic int parse_config_sysfs_file(int maj, int min,
33062ee35494Smrg                                   drmPciDeviceInfoPtr device)
33072ee35494Smrg{
33086260e5d5Smrg    char path[PATH_MAX + 1], pci_path[PATH_MAX + 1];
3309fe517fc9Smrg    unsigned char config[64];
3310fe517fc9Smrg    int fd, ret;
3311fe517fc9Smrg
33126260e5d5Smrg    get_pci_path(maj, min, pci_path);
33136260e5d5Smrg
33146260e5d5Smrg    snprintf(path, PATH_MAX, "%s/config", pci_path);
3315fe517fc9Smrg    fd = open(path, O_RDONLY);
3316fe517fc9Smrg    if (fd < 0)
3317fe517fc9Smrg        return -errno;
3318fe517fc9Smrg
3319fe517fc9Smrg    ret = read(fd, config, sizeof(config));
3320fe517fc9Smrg    close(fd);
3321fe517fc9Smrg    if (ret < 0)
3322fe517fc9Smrg        return -errno;
3323fe517fc9Smrg
3324fe517fc9Smrg    device->vendor_id = config[0] | (config[1] << 8);
3325fe517fc9Smrg    device->device_id = config[2] | (config[3] << 8);
3326fe517fc9Smrg    device->revision_id = config[8];
3327fe517fc9Smrg    device->subvendor_id = config[44] | (config[45] << 8);
3328fe517fc9Smrg    device->subdevice_id = config[46] | (config[47] << 8);
3329fe517fc9Smrg
33302ee35494Smrg    return 0;
33312ee35494Smrg}
33322ee35494Smrg#endif
33332ee35494Smrg
33342ee35494Smrgstatic int drmParsePciDeviceInfo(int maj, int min,
33352ee35494Smrg                                 drmPciDeviceInfoPtr device,
33362ee35494Smrg                                 uint32_t flags)
33372ee35494Smrg{
33382ee35494Smrg#ifdef __linux__
33392ee35494Smrg    if (!(flags & DRM_DEVICE_GET_PCI_REVISION))
33402ee35494Smrg        return parse_separate_sysfs_files(maj, min, device, true);
33412ee35494Smrg
33422ee35494Smrg    if (parse_separate_sysfs_files(maj, min, device, false))
33432ee35494Smrg        return parse_config_sysfs_file(maj, min, device);
33442ee35494Smrg
33452ee35494Smrg    return 0;
3346a970b457Sriastradh#elif defined(__NetBSD__)
3347a970b457Sriastradh    drmPciBusInfo businfo;
3348a970b457Sriastradh    char fname[PATH_MAX];
3349a970b457Sriastradh    int pcifd;
3350a970b457Sriastradh    pcireg_t id, class, subsys;
3351a970b457Sriastradh    int ret;
3352a970b457Sriastradh
3353a970b457Sriastradh    /* Find where on the bus the device lives.  */
3354a970b457Sriastradh    ret = drmParsePciBusInfo(maj, min, &businfo);
3355a970b457Sriastradh    if (ret)
3356a970b457Sriastradh	return ret;
3357a970b457Sriastradh
3358a970b457Sriastradh    /* Open the pciN device node to get at its config registers.  */
3359a970b457Sriastradh    if (snprintf(fname, sizeof fname, "/dev/pci%u", businfo.domain)
3360a970b457Sriastradh	>= sizeof fname)
3361a970b457Sriastradh	return -ENODEV;
3362a970b457Sriastradh    if ((pcifd = open(fname, O_RDONLY)) == -1)
3363a970b457Sriastradh	return -errno;
3364a970b457Sriastradh
3365f8b67707Schristos    ret = -1;
3366a970b457Sriastradh    /* Read the id and class pci config registers.  */
3367a970b457Sriastradh    if (pcibus_conf_read(pcifd, businfo.bus, businfo.dev, businfo.func,
3368a970b457Sriastradh	    PCI_ID_REG, &id) == -1)
3369f8b67707Schristos	goto out;
3370a970b457Sriastradh    if (pcibus_conf_read(pcifd, businfo.bus, businfo.dev, businfo.func,
3371a970b457Sriastradh	    PCI_CLASS_REG, &class) == -1)
3372f8b67707Schristos	goto out;
3373a970b457Sriastradh    if (pcibus_conf_read(pcifd, businfo.bus, businfo.dev, businfo.func,
3374a970b457Sriastradh	    PCI_SUBSYS_ID_REG, &subsys) == -1)
3375f8b67707Schristos	goto out;
3376a970b457Sriastradh
3377f8b67707Schristos    ret = 0;
3378a970b457Sriastradh    device->vendor_id = PCI_VENDOR(id);
3379a970b457Sriastradh    device->device_id = PCI_PRODUCT(id);
3380a970b457Sriastradh    device->subvendor_id = PCI_SUBSYS_VENDOR(subsys);
3381a970b457Sriastradh    device->subdevice_id = PCI_SUBSYS_ID(subsys);
3382a970b457Sriastradh    device->revision_id = PCI_REVISION(class);
3383f8b67707Schristosout:
3384f8b67707Schristos    if (ret == -1)
3385f8b67707Schristos	ret = -errno;
3386f8b67707Schristos    close(pcifd);
3387f8b67707Schristos    return ret;
33884545e80cSmrg#elif defined(__OpenBSD__) || defined(__DragonFly__)
33892ee35494Smrg    struct drm_pciinfo pinfo;
33902ee35494Smrg    int fd, type;
33912ee35494Smrg
33922ee35494Smrg    type = drmGetMinorType(min);
33932ee35494Smrg    if (type == -1)
33942ee35494Smrg        return -ENODEV;
33952ee35494Smrg
33962ee35494Smrg    fd = drmOpenMinor(min, 0, type);
33972ee35494Smrg    if (fd < 0)
33982ee35494Smrg        return -errno;
33992ee35494Smrg
34002ee35494Smrg    if (drmIoctl(fd, DRM_IOCTL_GET_PCIINFO, &pinfo)) {
34012ee35494Smrg        close(fd);
34022ee35494Smrg        return -errno;
34032ee35494Smrg    }
34042ee35494Smrg    close(fd);
34052ee35494Smrg
34062ee35494Smrg    device->vendor_id = pinfo.vendor_id;
34072ee35494Smrg    device->device_id = pinfo.device_id;
34082ee35494Smrg    device->revision_id = pinfo.revision_id;
34092ee35494Smrg    device->subvendor_id = pinfo.subvendor_id;
34102ee35494Smrg    device->subdevice_id = pinfo.subdevice_id;
34112ee35494Smrg
3412fe517fc9Smrg    return 0;
3413fe517fc9Smrg#else
3414fe517fc9Smrg#warning "Missing implementation of drmParsePciDeviceInfo"
3415fe517fc9Smrg    return -EINVAL;
3416fe517fc9Smrg#endif
3417fe517fc9Smrg}
3418fe517fc9Smrg
34192ee35494Smrgstatic void drmFreePlatformDevice(drmDevicePtr device)
34202ee35494Smrg{
34212ee35494Smrg    if (device->deviceinfo.platform) {
34222ee35494Smrg        if (device->deviceinfo.platform->compatible) {
34232ee35494Smrg            char **compatible = device->deviceinfo.platform->compatible;
34242ee35494Smrg
34252ee35494Smrg            while (*compatible) {
34262ee35494Smrg                free(*compatible);
34272ee35494Smrg                compatible++;
34282ee35494Smrg            }
34292ee35494Smrg
34302ee35494Smrg            free(device->deviceinfo.platform->compatible);
34312ee35494Smrg        }
34322ee35494Smrg    }
34332ee35494Smrg}
34342ee35494Smrg
34352ee35494Smrgstatic void drmFreeHost1xDevice(drmDevicePtr device)
34362ee35494Smrg{
34372ee35494Smrg    if (device->deviceinfo.host1x) {
34382ee35494Smrg        if (device->deviceinfo.host1x->compatible) {
34392ee35494Smrg            char **compatible = device->deviceinfo.host1x->compatible;
34402ee35494Smrg
34412ee35494Smrg            while (*compatible) {
34422ee35494Smrg                free(*compatible);
34432ee35494Smrg                compatible++;
34442ee35494Smrg            }
34452ee35494Smrg
34462ee35494Smrg            free(device->deviceinfo.host1x->compatible);
34472ee35494Smrg        }
34482ee35494Smrg    }
34492ee35494Smrg}
34502ee35494Smrg
34516260e5d5Smrgdrm_public void drmFreeDevice(drmDevicePtr *device)
3452fe517fc9Smrg{
3453fe517fc9Smrg    if (device == NULL)
3454fe517fc9Smrg        return;
3455fe517fc9Smrg
34562ee35494Smrg    if (*device) {
34572ee35494Smrg        switch ((*device)->bustype) {
34582ee35494Smrg        case DRM_BUS_PLATFORM:
34592ee35494Smrg            drmFreePlatformDevice(*device);
34602ee35494Smrg            break;
34612ee35494Smrg
34622ee35494Smrg        case DRM_BUS_HOST1X:
34632ee35494Smrg            drmFreeHost1xDevice(*device);
34642ee35494Smrg            break;
34652ee35494Smrg        }
34662ee35494Smrg    }
34672ee35494Smrg
3468fe517fc9Smrg    free(*device);
3469fe517fc9Smrg    *device = NULL;
3470fe517fc9Smrg}
3471fe517fc9Smrg
34726260e5d5Smrgdrm_public void drmFreeDevices(drmDevicePtr devices[], int count)
3473fe517fc9Smrg{
3474fe517fc9Smrg    int i;
3475fe517fc9Smrg
3476fe517fc9Smrg    if (devices == NULL)
3477fe517fc9Smrg        return;
3478fe517fc9Smrg
3479fe517fc9Smrg    for (i = 0; i < count; i++)
3480fe517fc9Smrg        if (devices[i])
3481fe517fc9Smrg            drmFreeDevice(&devices[i]);
3482fe517fc9Smrg}
3483fe517fc9Smrg
34842ee35494Smrgstatic drmDevicePtr drmDeviceAlloc(unsigned int type, const char *node,
34852ee35494Smrg                                   size_t bus_size, size_t device_size,
34862ee35494Smrg                                   char **ptrp)
3487fe517fc9Smrg{
34882ee35494Smrg    size_t max_node_length, extra, size;
34892ee35494Smrg    drmDevicePtr device;
34902ee35494Smrg    unsigned int i;
34912ee35494Smrg    char *ptr;
3492fe517fc9Smrg
34932ee35494Smrg    max_node_length = ALIGN(drmGetMaxNodeName(), sizeof(void *));
34942ee35494Smrg    extra = DRM_NODE_MAX * (sizeof(void *) + max_node_length);
3495fe517fc9Smrg
34962ee35494Smrg    size = sizeof(*device) + extra + bus_size + device_size;
3497fe517fc9Smrg
34982ee35494Smrg    device = calloc(1, size);
34992ee35494Smrg    if (!device)
35002ee35494Smrg        return NULL;
35012ee35494Smrg
35022ee35494Smrg    device->available_nodes = 1 << type;
3503fe517fc9Smrg
35042ee35494Smrg    ptr = (char *)device + sizeof(*device);
35052ee35494Smrg    device->nodes = (char **)ptr;
35062ee35494Smrg
35072ee35494Smrg    ptr += DRM_NODE_MAX * sizeof(void *);
3508fe517fc9Smrg
3509fe517fc9Smrg    for (i = 0; i < DRM_NODE_MAX; i++) {
35102ee35494Smrg        device->nodes[i] = ptr;
35112ee35494Smrg        ptr += max_node_length;
3512fe517fc9Smrg    }
3513fe517fc9Smrg
35142ee35494Smrg    memcpy(device->nodes[type], node, max_node_length);
35152ee35494Smrg
35162ee35494Smrg    *ptrp = ptr;
35172ee35494Smrg
35182ee35494Smrg    return device;
35192ee35494Smrg}
35202ee35494Smrg
35212ee35494Smrgstatic int drmProcessPciDevice(drmDevicePtr *device,
35222ee35494Smrg                               const char *node, int node_type,
35232ee35494Smrg                               int maj, int min, bool fetch_deviceinfo,
35242ee35494Smrg                               uint32_t flags)
35252ee35494Smrg{
35262ee35494Smrg    drmDevicePtr dev;
35272ee35494Smrg    char *addr;
35282ee35494Smrg    int ret;
35292ee35494Smrg
35302ee35494Smrg    dev = drmDeviceAlloc(node_type, node, sizeof(drmPciBusInfo),
35312ee35494Smrg                         sizeof(drmPciDeviceInfo), &addr);
35322ee35494Smrg    if (!dev)
35332ee35494Smrg        return -ENOMEM;
35342ee35494Smrg
35352ee35494Smrg    dev->bustype = DRM_BUS_PCI;
3536fe517fc9Smrg
35372ee35494Smrg    dev->businfo.pci = (drmPciBusInfoPtr)addr;
35382ee35494Smrg
35392ee35494Smrg    ret = drmParsePciBusInfo(maj, min, dev->businfo.pci);
3540fe517fc9Smrg    if (ret)
3541fe517fc9Smrg        goto free_device;
3542fe517fc9Smrg
3543fe517fc9Smrg    // Fetch the device info if the user has requested it
3544fe517fc9Smrg    if (fetch_deviceinfo) {
3545fe517fc9Smrg        addr += sizeof(drmPciBusInfo);
35462ee35494Smrg        dev->deviceinfo.pci = (drmPciDeviceInfoPtr)addr;
3547fe517fc9Smrg
35482ee35494Smrg        ret = drmParsePciDeviceInfo(maj, min, dev->deviceinfo.pci, flags);
3549fe517fc9Smrg        if (ret)
3550fe517fc9Smrg            goto free_device;
3551fe517fc9Smrg    }
35522ee35494Smrg
35532ee35494Smrg    *device = dev;
35542ee35494Smrg
3555fe517fc9Smrg    return 0;
3556fe517fc9Smrg
3557fe517fc9Smrgfree_device:
35582ee35494Smrg    free(dev);
35592ee35494Smrg    return ret;
35602ee35494Smrg}
35612ee35494Smrg
35622ee35494Smrgstatic int drmParseUsbBusInfo(int maj, int min, drmUsbBusInfoPtr info)
35632ee35494Smrg{
35642ee35494Smrg#ifdef __linux__
35652ee35494Smrg    char path[PATH_MAX + 1], *value;
35662ee35494Smrg    unsigned int bus, dev;
35672ee35494Smrg    int ret;
35682ee35494Smrg
35692ee35494Smrg    snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min);
35702ee35494Smrg
35712ee35494Smrg    value = sysfs_uevent_get(path, "BUSNUM");
35722ee35494Smrg    if (!value)
35732ee35494Smrg        return -ENOENT;
35742ee35494Smrg
35752ee35494Smrg    ret = sscanf(value, "%03u", &bus);
35762ee35494Smrg    free(value);
35772ee35494Smrg
35782ee35494Smrg    if (ret <= 0)
35792ee35494Smrg        return -errno;
35802ee35494Smrg
35812ee35494Smrg    value = sysfs_uevent_get(path, "DEVNUM");
35822ee35494Smrg    if (!value)
35832ee35494Smrg        return -ENOENT;
35842ee35494Smrg
35852ee35494Smrg    ret = sscanf(value, "%03u", &dev);
35862ee35494Smrg    free(value);
35872ee35494Smrg
35882ee35494Smrg    if (ret <= 0)
35892ee35494Smrg        return -errno;
35902ee35494Smrg
35912ee35494Smrg    info->bus = bus;
35922ee35494Smrg    info->dev = dev;
35932ee35494Smrg
35942ee35494Smrg    return 0;
35952ee35494Smrg#else
35962ee35494Smrg#warning "Missing implementation of drmParseUsbBusInfo"
35972ee35494Smrg    return -EINVAL;
35982ee35494Smrg#endif
35992ee35494Smrg}
36002ee35494Smrg
36012ee35494Smrgstatic int drmParseUsbDeviceInfo(int maj, int min, drmUsbDeviceInfoPtr info)
36022ee35494Smrg{
36032ee35494Smrg#ifdef __linux__
36042ee35494Smrg    char path[PATH_MAX + 1], *value;
36052ee35494Smrg    unsigned int vendor, product;
36062ee35494Smrg    int ret;
36072ee35494Smrg
36082ee35494Smrg    snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min);
36092ee35494Smrg
36102ee35494Smrg    value = sysfs_uevent_get(path, "PRODUCT");
36112ee35494Smrg    if (!value)
36122ee35494Smrg        return -ENOENT;
36132ee35494Smrg
36142ee35494Smrg    ret = sscanf(value, "%x/%x", &vendor, &product);
36152ee35494Smrg    free(value);
36162ee35494Smrg
36172ee35494Smrg    if (ret <= 0)
36182ee35494Smrg        return -errno;
36192ee35494Smrg
36202ee35494Smrg    info->vendor = vendor;
36212ee35494Smrg    info->product = product;
36222ee35494Smrg
36232ee35494Smrg    return 0;
36242ee35494Smrg#else
36252ee35494Smrg#warning "Missing implementation of drmParseUsbDeviceInfo"
36262ee35494Smrg    return -EINVAL;
36272ee35494Smrg#endif
36282ee35494Smrg}
36292ee35494Smrg
36302ee35494Smrgstatic int drmProcessUsbDevice(drmDevicePtr *device, const char *node,
36312ee35494Smrg                               int node_type, int maj, int min,
36322ee35494Smrg                               bool fetch_deviceinfo, uint32_t flags)
36332ee35494Smrg{
36342ee35494Smrg    drmDevicePtr dev;
36352ee35494Smrg    char *ptr;
36362ee35494Smrg    int ret;
36372ee35494Smrg
36382ee35494Smrg    dev = drmDeviceAlloc(node_type, node, sizeof(drmUsbBusInfo),
36392ee35494Smrg                         sizeof(drmUsbDeviceInfo), &ptr);
36402ee35494Smrg    if (!dev)
36412ee35494Smrg        return -ENOMEM;
36422ee35494Smrg
36432ee35494Smrg    dev->bustype = DRM_BUS_USB;
36442ee35494Smrg
36452ee35494Smrg    dev->businfo.usb = (drmUsbBusInfoPtr)ptr;
36462ee35494Smrg
36472ee35494Smrg    ret = drmParseUsbBusInfo(maj, min, dev->businfo.usb);
36482ee35494Smrg    if (ret < 0)
36492ee35494Smrg        goto free_device;
36502ee35494Smrg
36512ee35494Smrg    if (fetch_deviceinfo) {
36522ee35494Smrg        ptr += sizeof(drmUsbBusInfo);
36532ee35494Smrg        dev->deviceinfo.usb = (drmUsbDeviceInfoPtr)ptr;
36542ee35494Smrg
36552ee35494Smrg        ret = drmParseUsbDeviceInfo(maj, min, dev->deviceinfo.usb);
36562ee35494Smrg        if (ret < 0)
36572ee35494Smrg            goto free_device;
36582ee35494Smrg    }
36592ee35494Smrg
36602ee35494Smrg    *device = dev;
36612ee35494Smrg
36622ee35494Smrg    return 0;
36632ee35494Smrg
36642ee35494Smrgfree_device:
36652ee35494Smrg    free(dev);
36662ee35494Smrg    return ret;
36672ee35494Smrg}
36682ee35494Smrg
3669bf6cc7dcSmrgstatic int drmParseOFBusInfo(int maj, int min, char *fullname)
36702ee35494Smrg{
36712ee35494Smrg#ifdef __linux__
3672bf6cc7dcSmrg    char path[PATH_MAX + 1], *name, *tmp_name;
36732ee35494Smrg
36742ee35494Smrg    snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min);
36752ee35494Smrg
36762ee35494Smrg    name = sysfs_uevent_get(path, "OF_FULLNAME");
3677bf6cc7dcSmrg    tmp_name = name;
3678bf6cc7dcSmrg    if (!name) {
3679bf6cc7dcSmrg        /* If the device lacks OF data, pick the MODALIAS info */
3680bf6cc7dcSmrg        name = sysfs_uevent_get(path, "MODALIAS");
3681bf6cc7dcSmrg        if (!name)
3682bf6cc7dcSmrg            return -ENOENT;
3683bf6cc7dcSmrg
3684bf6cc7dcSmrg        /* .. and strip the MODALIAS=[platform,usb...]: part. */
3685bf6cc7dcSmrg        tmp_name = strrchr(name, ':');
3686bf6cc7dcSmrg        if (!tmp_name) {
3687bf6cc7dcSmrg            free(name);
3688bf6cc7dcSmrg            return -ENOENT;
3689bf6cc7dcSmrg        }
3690bf6cc7dcSmrg        tmp_name++;
3691bf6cc7dcSmrg    }
36922ee35494Smrg
3693bf6cc7dcSmrg    strncpy(fullname, tmp_name, DRM_PLATFORM_DEVICE_NAME_LEN);
3694bf6cc7dcSmrg    fullname[DRM_PLATFORM_DEVICE_NAME_LEN - 1] = '\0';
36952ee35494Smrg    free(name);
36962ee35494Smrg
36972ee35494Smrg    return 0;
36982ee35494Smrg#else
3699bf6cc7dcSmrg#warning "Missing implementation of drmParseOFBusInfo"
37002ee35494Smrg    return -EINVAL;
37012ee35494Smrg#endif
37022ee35494Smrg}
37032ee35494Smrg
3704bf6cc7dcSmrgstatic int drmParseOFDeviceInfo(int maj, int min, char ***compatible)
37052ee35494Smrg{
37062ee35494Smrg#ifdef __linux__
3707bf6cc7dcSmrg    char path[PATH_MAX + 1], *value, *tmp_name;
37082ee35494Smrg    unsigned int count, i;
37092ee35494Smrg    int err;
37102ee35494Smrg
37112ee35494Smrg    snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min);
37122ee35494Smrg
37132ee35494Smrg    value = sysfs_uevent_get(path, "OF_COMPATIBLE_N");
3714bf6cc7dcSmrg    if (value) {
3715bf6cc7dcSmrg        sscanf(value, "%u", &count);
3716bf6cc7dcSmrg        free(value);
3717bf6cc7dcSmrg    } else {
3718bf6cc7dcSmrg        /* Assume one entry if the device lack OF data */
3719bf6cc7dcSmrg        count = 1;
3720bf6cc7dcSmrg    }
37212ee35494Smrg
3722bf6cc7dcSmrg    *compatible = calloc(count + 1, sizeof(char *));
3723bf6cc7dcSmrg    if (!*compatible)
37242ee35494Smrg        return -ENOMEM;
37252ee35494Smrg
37262ee35494Smrg    for (i = 0; i < count; i++) {
37272ee35494Smrg        value = sysfs_uevent_get(path, "OF_COMPATIBLE_%u", i);
3728bf6cc7dcSmrg        tmp_name = value;
37292ee35494Smrg        if (!value) {
3730bf6cc7dcSmrg            /* If the device lacks OF data, pick the MODALIAS info */
3731bf6cc7dcSmrg            value = sysfs_uevent_get(path, "MODALIAS");
3732bf6cc7dcSmrg            if (!value) {
3733bf6cc7dcSmrg                err = -ENOENT;
3734bf6cc7dcSmrg                goto free;
3735bf6cc7dcSmrg            }
3736bf6cc7dcSmrg
3737bf6cc7dcSmrg            /* .. and strip the MODALIAS=[platform,usb...]: part. */
3738bf6cc7dcSmrg            tmp_name = strrchr(value, ':');
3739bf6cc7dcSmrg            if (!tmp_name) {
3740bf6cc7dcSmrg                free(value);
3741bf6cc7dcSmrg                return -ENOENT;
3742bf6cc7dcSmrg            }
3743bf6cc7dcSmrg            tmp_name = strdup(tmp_name + 1);
3744bf6cc7dcSmrg            free(value);
37452ee35494Smrg        }
37462ee35494Smrg
3747bf6cc7dcSmrg        (*compatible)[i] = tmp_name;
37482ee35494Smrg    }
37492ee35494Smrg
37502ee35494Smrg    return 0;
37512ee35494Smrg
37522ee35494Smrgfree:
37532ee35494Smrg    while (i--)
3754bf6cc7dcSmrg        free((*compatible)[i]);
37552ee35494Smrg
3756bf6cc7dcSmrg    free(*compatible);
37572ee35494Smrg    return err;
37582ee35494Smrg#else
3759bf6cc7dcSmrg#warning "Missing implementation of drmParseOFDeviceInfo"
37602ee35494Smrg    return -EINVAL;
37612ee35494Smrg#endif
37622ee35494Smrg}
37632ee35494Smrg
37642ee35494Smrgstatic int drmProcessPlatformDevice(drmDevicePtr *device,
37652ee35494Smrg                                    const char *node, int node_type,
37662ee35494Smrg                                    int maj, int min, bool fetch_deviceinfo,
37672ee35494Smrg                                    uint32_t flags)
37682ee35494Smrg{
37692ee35494Smrg    drmDevicePtr dev;
37702ee35494Smrg    char *ptr;
37712ee35494Smrg    int ret;
37722ee35494Smrg
37732ee35494Smrg    dev = drmDeviceAlloc(node_type, node, sizeof(drmPlatformBusInfo),
37742ee35494Smrg                         sizeof(drmPlatformDeviceInfo), &ptr);
37752ee35494Smrg    if (!dev)
37762ee35494Smrg        return -ENOMEM;
37772ee35494Smrg
37782ee35494Smrg    dev->bustype = DRM_BUS_PLATFORM;
37792ee35494Smrg
37802ee35494Smrg    dev->businfo.platform = (drmPlatformBusInfoPtr)ptr;
37812ee35494Smrg
3782bf6cc7dcSmrg    ret = drmParseOFBusInfo(maj, min, dev->businfo.platform->fullname);
37832ee35494Smrg    if (ret < 0)
37842ee35494Smrg        goto free_device;
37852ee35494Smrg
37862ee35494Smrg    if (fetch_deviceinfo) {
37872ee35494Smrg        ptr += sizeof(drmPlatformBusInfo);
37882ee35494Smrg        dev->deviceinfo.platform = (drmPlatformDeviceInfoPtr)ptr;
37892ee35494Smrg
3790bf6cc7dcSmrg        ret = drmParseOFDeviceInfo(maj, min, &dev->deviceinfo.platform->compatible);
37912ee35494Smrg        if (ret < 0)
37922ee35494Smrg            goto free_device;
37932ee35494Smrg    }
37942ee35494Smrg
37952ee35494Smrg    *device = dev;
37962ee35494Smrg
37972ee35494Smrg    return 0;
37982ee35494Smrg
37992ee35494Smrgfree_device:
38002ee35494Smrg    free(dev);
38012ee35494Smrg    return ret;
38022ee35494Smrg}
38032ee35494Smrg
38042ee35494Smrgstatic int drmProcessHost1xDevice(drmDevicePtr *device,
38052ee35494Smrg                                  const char *node, int node_type,
38062ee35494Smrg                                  int maj, int min, bool fetch_deviceinfo,
38072ee35494Smrg                                  uint32_t flags)
38082ee35494Smrg{
38092ee35494Smrg    drmDevicePtr dev;
38102ee35494Smrg    char *ptr;
38112ee35494Smrg    int ret;
38122ee35494Smrg
38132ee35494Smrg    dev = drmDeviceAlloc(node_type, node, sizeof(drmHost1xBusInfo),
38142ee35494Smrg                         sizeof(drmHost1xDeviceInfo), &ptr);
38152ee35494Smrg    if (!dev)
38162ee35494Smrg        return -ENOMEM;
38172ee35494Smrg
38182ee35494Smrg    dev->bustype = DRM_BUS_HOST1X;
38192ee35494Smrg
38202ee35494Smrg    dev->businfo.host1x = (drmHost1xBusInfoPtr)ptr;
38212ee35494Smrg
3822bf6cc7dcSmrg    ret = drmParseOFBusInfo(maj, min, dev->businfo.host1x->fullname);
38232ee35494Smrg    if (ret < 0)
38242ee35494Smrg        goto free_device;
38252ee35494Smrg
38262ee35494Smrg    if (fetch_deviceinfo) {
38272ee35494Smrg        ptr += sizeof(drmHost1xBusInfo);
38282ee35494Smrg        dev->deviceinfo.host1x = (drmHost1xDeviceInfoPtr)ptr;
38292ee35494Smrg
3830bf6cc7dcSmrg        ret = drmParseOFDeviceInfo(maj, min, &dev->deviceinfo.host1x->compatible);
38312ee35494Smrg        if (ret < 0)
38322ee35494Smrg            goto free_device;
38332ee35494Smrg    }
38342ee35494Smrg
38352ee35494Smrg    *device = dev;
38362ee35494Smrg
38372ee35494Smrg    return 0;
38382ee35494Smrg
38392ee35494Smrgfree_device:
38402ee35494Smrg    free(dev);
3841fe517fc9Smrg    return ret;
3842fe517fc9Smrg}
3843fe517fc9Smrg
38446260e5d5Smrgstatic int
38456260e5d5Smrgprocess_device(drmDevicePtr *device, const char *d_name,
38466260e5d5Smrg               int req_subsystem_type,
38476260e5d5Smrg               bool fetch_deviceinfo, uint32_t flags)
38486260e5d5Smrg{
38496260e5d5Smrg    struct stat sbuf;
38506260e5d5Smrg    char node[PATH_MAX + 1];
38516260e5d5Smrg    int node_type, subsystem_type;
38526260e5d5Smrg    unsigned int maj, min;
38536260e5d5Smrg
38546260e5d5Smrg    node_type = drmGetNodeType(d_name);
38556260e5d5Smrg    if (node_type < 0)
38566260e5d5Smrg        return -1;
38576260e5d5Smrg
38586260e5d5Smrg    snprintf(node, PATH_MAX, "%s/%s", DRM_DIR_NAME, d_name);
38596260e5d5Smrg    if (stat(node, &sbuf))
38606260e5d5Smrg        return -1;
38616260e5d5Smrg
38626260e5d5Smrg    maj = major(sbuf.st_rdev);
38636260e5d5Smrg    min = minor(sbuf.st_rdev);
38646260e5d5Smrg
38656260e5d5Smrg    if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode))
38666260e5d5Smrg        return -1;
38676260e5d5Smrg
38686260e5d5Smrg    subsystem_type = drmParseSubsystemType(maj, min);
38696260e5d5Smrg    if (req_subsystem_type != -1 && req_subsystem_type != subsystem_type)
38706260e5d5Smrg        return -1;
38716260e5d5Smrg
38726260e5d5Smrg    switch (subsystem_type) {
38736260e5d5Smrg    case DRM_BUS_PCI:
38746260e5d5Smrg    case DRM_BUS_VIRTIO:
38756260e5d5Smrg        return drmProcessPciDevice(device, node, node_type, maj, min,
38766260e5d5Smrg                                   fetch_deviceinfo, flags);
38776260e5d5Smrg    case DRM_BUS_USB:
38786260e5d5Smrg        return drmProcessUsbDevice(device, node, node_type, maj, min,
38796260e5d5Smrg                                   fetch_deviceinfo, flags);
38806260e5d5Smrg    case DRM_BUS_PLATFORM:
38816260e5d5Smrg        return drmProcessPlatformDevice(device, node, node_type, maj, min,
38826260e5d5Smrg                                        fetch_deviceinfo, flags);
38836260e5d5Smrg    case DRM_BUS_HOST1X:
38846260e5d5Smrg        return drmProcessHost1xDevice(device, node, node_type, maj, min,
38856260e5d5Smrg                                      fetch_deviceinfo, flags);
38866260e5d5Smrg    default:
38876260e5d5Smrg        return -1;
38886260e5d5Smrg   }
38896260e5d5Smrg}
38906260e5d5Smrg
3891fe517fc9Smrg/* Consider devices located on the same bus as duplicate and fold the respective
3892fe517fc9Smrg * entries into a single one.
3893fe517fc9Smrg *
3894fe517fc9Smrg * Note: this leaves "gaps" in the array, while preserving the length.
3895fe517fc9Smrg */
3896fe517fc9Smrgstatic void drmFoldDuplicatedDevices(drmDevicePtr local_devices[], int count)
3897fe517fc9Smrg{
3898fe517fc9Smrg    int node_type, i, j;
3899fe517fc9Smrg
3900fe517fc9Smrg    for (i = 0; i < count; i++) {
3901fe517fc9Smrg        for (j = i + 1; j < count; j++) {
39020655efefSmrg            if (drmDevicesEqual(local_devices[i], local_devices[j])) {
3903fe517fc9Smrg                local_devices[i]->available_nodes |= local_devices[j]->available_nodes;
3904fe517fc9Smrg                node_type = log2(local_devices[j]->available_nodes);
3905fe517fc9Smrg                memcpy(local_devices[i]->nodes[node_type],
3906fe517fc9Smrg                       local_devices[j]->nodes[node_type], drmGetMaxNodeName());
3907fe517fc9Smrg                drmFreeDevice(&local_devices[j]);
3908fe517fc9Smrg            }
3909fe517fc9Smrg        }
3910fe517fc9Smrg    }
3911fe517fc9Smrg}
3912fe517fc9Smrg
39132ee35494Smrg/* Check that the given flags are valid returning 0 on success */
39142ee35494Smrgstatic int
39152ee35494Smrgdrm_device_validate_flags(uint32_t flags)
39162ee35494Smrg{
39172ee35494Smrg        return (flags & ~DRM_DEVICE_GET_PCI_REVISION);
39182ee35494Smrg}
39192ee35494Smrg
39206260e5d5Smrgstatic bool
39216260e5d5Smrgdrm_device_has_rdev(drmDevicePtr device, dev_t find_rdev)
39226260e5d5Smrg{
39236260e5d5Smrg    struct stat sbuf;
39246260e5d5Smrg
39256260e5d5Smrg    for (int i = 0; i < DRM_NODE_MAX; i++) {
39266260e5d5Smrg        if (device->available_nodes & 1 << i) {
39276260e5d5Smrg            if (stat(device->nodes[i], &sbuf) == 0 &&
39286260e5d5Smrg                sbuf.st_rdev == find_rdev)
39296260e5d5Smrg                return true;
39306260e5d5Smrg        }
39316260e5d5Smrg    }
39326260e5d5Smrg    return false;
39336260e5d5Smrg}
39346260e5d5Smrg
39356260e5d5Smrg/*
39366260e5d5Smrg * The kernel drm core has a number of places that assume maximum of
39376260e5d5Smrg * 3x64 devices nodes. That's 64 for each of primary, control and
39386260e5d5Smrg * render nodes. Rounded it up to 256 for simplicity.
39396260e5d5Smrg */
39406260e5d5Smrg#define MAX_DRM_NODES 256
39416260e5d5Smrg
3942fe517fc9Smrg/**
3943fe517fc9Smrg * Get information about the opened drm device
3944fe517fc9Smrg *
3945fe517fc9Smrg * \param fd file descriptor of the drm device
39462ee35494Smrg * \param flags feature/behaviour bitmask
3947fe517fc9Smrg * \param device the address of a drmDevicePtr where the information
3948fe517fc9Smrg *               will be allocated in stored
3949fe517fc9Smrg *
3950fe517fc9Smrg * \return zero on success, negative error code otherwise.
39512ee35494Smrg *
39522ee35494Smrg * \note Unlike drmGetDevice it does not retrieve the pci device revision field
39532ee35494Smrg * unless the DRM_DEVICE_GET_PCI_REVISION \p flag is set.
3954fe517fc9Smrg */
39556260e5d5Smrgdrm_public int drmGetDevice2(int fd, uint32_t flags, drmDevicePtr *device)
3956fe517fc9Smrg{
39572ee35494Smrg#ifdef __OpenBSD__
39582ee35494Smrg    /*
39592ee35494Smrg     * DRI device nodes on OpenBSD are not in their own directory, they reside
39602ee35494Smrg     * in /dev along with a large number of statically generated /dev nodes.
39612ee35494Smrg     * Avoid stat'ing all of /dev needlessly by implementing this custom path.
39622ee35494Smrg     */
39632ee35494Smrg    drmDevicePtr     d;
39642ee35494Smrg    struct stat      sbuf;
39652ee35494Smrg    char             node[PATH_MAX + 1];
39662ee35494Smrg    const char      *dev_name;
39672ee35494Smrg    int              node_type, subsystem_type;
396882025ec7Smrg    int              maj, min, n, ret;
39692ee35494Smrg
39702ee35494Smrg    if (fd == -1 || device == NULL)
39712ee35494Smrg        return -EINVAL;
39722ee35494Smrg
39732ee35494Smrg    if (fstat(fd, &sbuf))
39742ee35494Smrg        return -errno;
39752ee35494Smrg
39762ee35494Smrg    maj = major(sbuf.st_rdev);
39772ee35494Smrg    min = minor(sbuf.st_rdev);
39782ee35494Smrg
39796260e5d5Smrg    if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode))
39802ee35494Smrg        return -EINVAL;
39812ee35494Smrg
39822ee35494Smrg    node_type = drmGetMinorType(min);
39832ee35494Smrg    if (node_type == -1)
39842ee35494Smrg        return -ENODEV;
39852ee35494Smrg
398682025ec7Smrg    dev_name = drmGetDeviceName(node_type);
398782025ec7Smrg    if (!dev_name)
39882ee35494Smrg        return -EINVAL;
39892ee35494Smrg
399082025ec7Smrg    n = snprintf(node, PATH_MAX, dev_name, DRM_DIR_NAME, min);
39912ee35494Smrg    if (n == -1 || n >= PATH_MAX)
39922ee35494Smrg      return -errno;
39932ee35494Smrg    if (stat(node, &sbuf))
39942ee35494Smrg        return -EINVAL;
39952ee35494Smrg
39962ee35494Smrg    subsystem_type = drmParseSubsystemType(maj, min);
39972ee35494Smrg    if (subsystem_type != DRM_BUS_PCI)
39982ee35494Smrg        return -ENODEV;
39992ee35494Smrg
40002ee35494Smrg    ret = drmProcessPciDevice(&d, node, node_type, maj, min, true, flags);
40012ee35494Smrg    if (ret)
40022ee35494Smrg        return ret;
40032ee35494Smrg
40042ee35494Smrg    *device = d;
40052ee35494Smrg
40062ee35494Smrg    return 0;
40072ee35494Smrg#else
40086260e5d5Smrg    drmDevicePtr local_devices[MAX_DRM_NODES];
4009fe517fc9Smrg    drmDevicePtr d;
4010fe517fc9Smrg    DIR *sysdir;
4011fe517fc9Smrg    struct dirent *dent;
4012fe517fc9Smrg    struct stat sbuf;
40136260e5d5Smrg    int subsystem_type;
4014fe517fc9Smrg    int maj, min;
4015fe517fc9Smrg    int ret, i, node_count;
4016fe517fc9Smrg    dev_t find_rdev;
4017fe517fc9Smrg
40182ee35494Smrg    if (drm_device_validate_flags(flags))
40192ee35494Smrg        return -EINVAL;
40202ee35494Smrg
4021fe517fc9Smrg    if (fd == -1 || device == NULL)
4022fe517fc9Smrg        return -EINVAL;
4023fe517fc9Smrg
4024fe517fc9Smrg    if (fstat(fd, &sbuf))
4025fe517fc9Smrg        return -errno;
4026fe517fc9Smrg
4027fe517fc9Smrg    find_rdev = sbuf.st_rdev;
4028fe517fc9Smrg    maj = major(sbuf.st_rdev);
4029fe517fc9Smrg    min = minor(sbuf.st_rdev);
4030fe517fc9Smrg
40316260e5d5Smrg    if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode))
4032fe517fc9Smrg        return -EINVAL;
4033fe517fc9Smrg
4034fe517fc9Smrg    subsystem_type = drmParseSubsystemType(maj, min);
40356260e5d5Smrg    if (subsystem_type < 0)
40366260e5d5Smrg        return subsystem_type;
4037fe517fc9Smrg
4038fe517fc9Smrg    sysdir = opendir(DRM_DIR_NAME);
40396260e5d5Smrg    if (!sysdir)
40406260e5d5Smrg        return -errno;
4041fe517fc9Smrg
4042fe517fc9Smrg    i = 0;
4043fe517fc9Smrg    while ((dent = readdir(sysdir))) {
40446260e5d5Smrg        ret = process_device(&d, dent->d_name, subsystem_type, true, flags);
40456260e5d5Smrg        if (ret)
4046fe517fc9Smrg            continue;
4047fe517fc9Smrg
40486260e5d5Smrg        if (i >= MAX_DRM_NODES) {
40496260e5d5Smrg            fprintf(stderr, "More than %d drm nodes detected. "
40506260e5d5Smrg                    "Please report a bug - that should not happen.\n"
40516260e5d5Smrg                    "Skipping extra nodes\n", MAX_DRM_NODES);
4052fe517fc9Smrg            break;
4053fe517fc9Smrg        }
40546260e5d5Smrg        local_devices[i] = d;
4055fe517fc9Smrg        i++;
4056fe517fc9Smrg    }
4057fe517fc9Smrg    node_count = i;
4058fe517fc9Smrg
4059fe517fc9Smrg    drmFoldDuplicatedDevices(local_devices, node_count);
4060fe517fc9Smrg
40616260e5d5Smrg    *device = NULL;
40626260e5d5Smrg
40636260e5d5Smrg    for (i = 0; i < node_count; i++) {
40646260e5d5Smrg        if (!local_devices[i])
40656260e5d5Smrg            continue;
40666260e5d5Smrg
40676260e5d5Smrg        if (drm_device_has_rdev(local_devices[i], find_rdev))
40686260e5d5Smrg            *device = local_devices[i];
40696260e5d5Smrg        else
40706260e5d5Smrg            drmFreeDevice(&local_devices[i]);
40716260e5d5Smrg    }
4072fe517fc9Smrg
4073fe517fc9Smrg    closedir(sysdir);
40742ee35494Smrg    if (*device == NULL)
40752ee35494Smrg        return -ENODEV;
4076fe517fc9Smrg    return 0;
40772ee35494Smrg#endif
40782ee35494Smrg}
40792ee35494Smrg
40802ee35494Smrg/**
40812ee35494Smrg * Get information about the opened drm device
40822ee35494Smrg *
40832ee35494Smrg * \param fd file descriptor of the drm device
40842ee35494Smrg * \param device the address of a drmDevicePtr where the information
40852ee35494Smrg *               will be allocated in stored
40862ee35494Smrg *
40872ee35494Smrg * \return zero on success, negative error code otherwise.
40882ee35494Smrg */
40896260e5d5Smrgdrm_public int drmGetDevice(int fd, drmDevicePtr *device)
40902ee35494Smrg{
40912ee35494Smrg    return drmGetDevice2(fd, DRM_DEVICE_GET_PCI_REVISION, device);
4092fe517fc9Smrg}
4093fe517fc9Smrg
4094fe517fc9Smrg/**
4095fe517fc9Smrg * Get drm devices on the system
4096fe517fc9Smrg *
40972ee35494Smrg * \param flags feature/behaviour bitmask
4098fe517fc9Smrg * \param devices the array of devices with drmDevicePtr elements
4099fe517fc9Smrg *                can be NULL to get the device number first
4100fe517fc9Smrg * \param max_devices the maximum number of devices for the array
4101fe517fc9Smrg *
4102fe517fc9Smrg * \return on error - negative error code,
4103fe517fc9Smrg *         if devices is NULL - total number of devices available on the system,
4104fe517fc9Smrg *         alternatively the number of devices stored in devices[], which is
4105fe517fc9Smrg *         capped by the max_devices.
41062ee35494Smrg *
41072ee35494Smrg * \note Unlike drmGetDevices it does not retrieve the pci device revision field
41082ee35494Smrg * unless the DRM_DEVICE_GET_PCI_REVISION \p flag is set.
4109fe517fc9Smrg */
41106260e5d5Smrgdrm_public int drmGetDevices2(uint32_t flags, drmDevicePtr devices[],
41116260e5d5Smrg                              int max_devices)
4112fe517fc9Smrg{
41136260e5d5Smrg    drmDevicePtr local_devices[MAX_DRM_NODES];
4114fe517fc9Smrg    drmDevicePtr device;
4115fe517fc9Smrg    DIR *sysdir;
4116fe517fc9Smrg    struct dirent *dent;
4117fe517fc9Smrg    int ret, i, node_count, device_count;
4118fe517fc9Smrg
41192ee35494Smrg    if (drm_device_validate_flags(flags))
41202ee35494Smrg        return -EINVAL;
41212ee35494Smrg
4122fe517fc9Smrg    sysdir = opendir(DRM_DIR_NAME);
41236260e5d5Smrg    if (!sysdir)
41246260e5d5Smrg        return -errno;
4125fe517fc9Smrg
4126fe517fc9Smrg    i = 0;
4127fe517fc9Smrg    while ((dent = readdir(sysdir))) {
41286260e5d5Smrg        ret = process_device(&device, dent->d_name, -1, devices != NULL, flags);
41296260e5d5Smrg        if (ret)
4130fe517fc9Smrg            continue;
4131fe517fc9Smrg
41326260e5d5Smrg        if (i >= MAX_DRM_NODES) {
41336260e5d5Smrg            fprintf(stderr, "More than %d drm nodes detected. "
41346260e5d5Smrg                    "Please report a bug - that should not happen.\n"
41356260e5d5Smrg                    "Skipping extra nodes\n", MAX_DRM_NODES);
41362ee35494Smrg            break;
4137fe517fc9Smrg        }
4138fe517fc9Smrg        local_devices[i] = device;
4139fe517fc9Smrg        i++;
4140fe517fc9Smrg    }
4141fe517fc9Smrg    node_count = i;
4142fe517fc9Smrg
4143fe517fc9Smrg    drmFoldDuplicatedDevices(local_devices, node_count);
4144fe517fc9Smrg
4145fe517fc9Smrg    device_count = 0;
4146fe517fc9Smrg    for (i = 0; i < node_count; i++) {
4147fe517fc9Smrg        if (!local_devices[i])
4148fe517fc9Smrg            continue;
4149fe517fc9Smrg
4150fe517fc9Smrg        if ((devices != NULL) && (device_count < max_devices))
4151fe517fc9Smrg            devices[device_count] = local_devices[i];
4152fe517fc9Smrg        else
4153fe517fc9Smrg            drmFreeDevice(&local_devices[i]);
4154fe517fc9Smrg
4155fe517fc9Smrg        device_count++;
4156fe517fc9Smrg    }
4157fe517fc9Smrg
4158fe517fc9Smrg    closedir(sysdir);
4159fe517fc9Smrg    return device_count;
4160424e9256Smrg}
41612ee35494Smrg
41622ee35494Smrg/**
41632ee35494Smrg * Get drm devices on the system
41642ee35494Smrg *
41652ee35494Smrg * \param devices the array of devices with drmDevicePtr elements
41662ee35494Smrg *                can be NULL to get the device number first
41672ee35494Smrg * \param max_devices the maximum number of devices for the array
41682ee35494Smrg *
41692ee35494Smrg * \return on error - negative error code,
41702ee35494Smrg *         if devices is NULL - total number of devices available on the system,
41712ee35494Smrg *         alternatively the number of devices stored in devices[], which is
41722ee35494Smrg *         capped by the max_devices.
41732ee35494Smrg */
41746260e5d5Smrgdrm_public int drmGetDevices(drmDevicePtr devices[], int max_devices)
41752ee35494Smrg{
41762ee35494Smrg    return drmGetDevices2(DRM_DEVICE_GET_PCI_REVISION, devices, max_devices);
41772ee35494Smrg}
41782ee35494Smrg
41796260e5d5Smrgdrm_public char *drmGetDeviceNameFromFd2(int fd)
41802ee35494Smrg{
41812ee35494Smrg#ifdef __linux__
41822ee35494Smrg    struct stat sbuf;
41832ee35494Smrg    char path[PATH_MAX + 1], *value;
41842ee35494Smrg    unsigned int maj, min;
41852ee35494Smrg
41862ee35494Smrg    if (fstat(fd, &sbuf))
41872ee35494Smrg        return NULL;
41882ee35494Smrg
41892ee35494Smrg    maj = major(sbuf.st_rdev);
41902ee35494Smrg    min = minor(sbuf.st_rdev);
41912ee35494Smrg
41926260e5d5Smrg    if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode))
41932ee35494Smrg        return NULL;
41942ee35494Smrg
41952ee35494Smrg    snprintf(path, sizeof(path), "/sys/dev/char/%d:%d", maj, min);
41962ee35494Smrg
41972ee35494Smrg    value = sysfs_uevent_get(path, "DEVNAME");
41982ee35494Smrg    if (!value)
41992ee35494Smrg        return NULL;
42002ee35494Smrg
42012ee35494Smrg    snprintf(path, sizeof(path), "/dev/%s", value);
42022ee35494Smrg    free(value);
42032ee35494Smrg
42042ee35494Smrg    return strdup(path);
42052ee35494Smrg#else
42062ee35494Smrg    struct stat      sbuf;
42072ee35494Smrg    char             node[PATH_MAX + 1];
42082ee35494Smrg    const char      *dev_name;
42092ee35494Smrg    int              node_type;
421082025ec7Smrg    int              maj, min, n;
42112ee35494Smrg
42122ee35494Smrg    if (fstat(fd, &sbuf))
42132ee35494Smrg        return NULL;
42142ee35494Smrg
42152ee35494Smrg    maj = major(sbuf.st_rdev);
42162ee35494Smrg    min = minor(sbuf.st_rdev);
42172ee35494Smrg
42186260e5d5Smrg    if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode))
42192ee35494Smrg        return NULL;
42202ee35494Smrg
42212ee35494Smrg    node_type = drmGetMinorType(min);
42222ee35494Smrg    if (node_type == -1)
42232ee35494Smrg        return NULL;
42242ee35494Smrg
422582025ec7Smrg    dev_name = drmGetDeviceName(node_type);
422682025ec7Smrg    if (!dev_name)
42272ee35494Smrg        return NULL;
42282ee35494Smrg
422982025ec7Smrg    n = snprintf(node, PATH_MAX, dev_name, DRM_DIR_NAME, min);
42302ee35494Smrg    if (n == -1 || n >= PATH_MAX)
42312ee35494Smrg      return NULL;
42322ee35494Smrg
42332ee35494Smrg    return strdup(node);
42342ee35494Smrg#endif
42352ee35494Smrg}
42360655efefSmrg
42376260e5d5Smrgdrm_public int drmSyncobjCreate(int fd, uint32_t flags, uint32_t *handle)
42380655efefSmrg{
42390655efefSmrg    struct drm_syncobj_create args;
42400655efefSmrg    int ret;
42410655efefSmrg
42420655efefSmrg    memclear(args);
42430655efefSmrg    args.flags = flags;
42440655efefSmrg    args.handle = 0;
42450655efefSmrg    ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_CREATE, &args);
42460655efefSmrg    if (ret)
42472b90624aSmrg        return ret;
42480655efefSmrg    *handle = args.handle;
42490655efefSmrg    return 0;
42500655efefSmrg}
42510655efefSmrg
42526260e5d5Smrgdrm_public int drmSyncobjDestroy(int fd, uint32_t handle)
42530655efefSmrg{
42540655efefSmrg    struct drm_syncobj_destroy args;
42550655efefSmrg
42560655efefSmrg    memclear(args);
42570655efefSmrg    args.handle = handle;
42580655efefSmrg    return drmIoctl(fd, DRM_IOCTL_SYNCOBJ_DESTROY, &args);
42590655efefSmrg}
42600655efefSmrg
42616260e5d5Smrgdrm_public int drmSyncobjHandleToFD(int fd, uint32_t handle, int *obj_fd)
42620655efefSmrg{
42630655efefSmrg    struct drm_syncobj_handle args;
42640655efefSmrg    int ret;
42650655efefSmrg
42660655efefSmrg    memclear(args);
42670655efefSmrg    args.fd = -1;
42680655efefSmrg    args.handle = handle;
42690655efefSmrg    ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD, &args);
42700655efefSmrg    if (ret)
42712b90624aSmrg        return ret;
42720655efefSmrg    *obj_fd = args.fd;
42730655efefSmrg    return 0;
42740655efefSmrg}
42750655efefSmrg
42766260e5d5Smrgdrm_public int drmSyncobjFDToHandle(int fd, int obj_fd, uint32_t *handle)
42770655efefSmrg{
42780655efefSmrg    struct drm_syncobj_handle args;
42790655efefSmrg    int ret;
42800655efefSmrg
42810655efefSmrg    memclear(args);
42820655efefSmrg    args.fd = obj_fd;
42830655efefSmrg    args.handle = 0;
42840655efefSmrg    ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE, &args);
42850655efefSmrg    if (ret)
42862b90624aSmrg        return ret;
42870655efefSmrg    *handle = args.handle;
42880655efefSmrg    return 0;
42890655efefSmrg}
42900655efefSmrg
42916260e5d5Smrgdrm_public int drmSyncobjImportSyncFile(int fd, uint32_t handle,
42926260e5d5Smrg                                        int sync_file_fd)
42930655efefSmrg{
42940655efefSmrg    struct drm_syncobj_handle args;
42950655efefSmrg
42960655efefSmrg    memclear(args);
42970655efefSmrg    args.fd = sync_file_fd;
42980655efefSmrg    args.handle = handle;
42990655efefSmrg    args.flags = DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_IMPORT_SYNC_FILE;
43000655efefSmrg    return drmIoctl(fd, DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE, &args);
43010655efefSmrg}
43020655efefSmrg
43036260e5d5Smrgdrm_public int drmSyncobjExportSyncFile(int fd, uint32_t handle,
43046260e5d5Smrg                                        int *sync_file_fd)
43050655efefSmrg{
43060655efefSmrg    struct drm_syncobj_handle args;
43070655efefSmrg    int ret;
43080655efefSmrg
43090655efefSmrg    memclear(args);
43100655efefSmrg    args.fd = -1;
43110655efefSmrg    args.handle = handle;
43120655efefSmrg    args.flags = DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_EXPORT_SYNC_FILE;
43130655efefSmrg    ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD, &args);
43140655efefSmrg    if (ret)
43152b90624aSmrg        return ret;
43160655efefSmrg    *sync_file_fd = args.fd;
43170655efefSmrg    return 0;
43180655efefSmrg}
43192b90624aSmrg
43206260e5d5Smrgdrm_public int drmSyncobjWait(int fd, uint32_t *handles, unsigned num_handles,
43216260e5d5Smrg                              int64_t timeout_nsec, unsigned flags,
43226260e5d5Smrg                              uint32_t *first_signaled)
43232b90624aSmrg{
43242b90624aSmrg    struct drm_syncobj_wait args;
43252b90624aSmrg    int ret;
43262b90624aSmrg
43272b90624aSmrg    memclear(args);
43282b90624aSmrg    args.handles = (uintptr_t)handles;
43292b90624aSmrg    args.timeout_nsec = timeout_nsec;
43302b90624aSmrg    args.count_handles = num_handles;
43312b90624aSmrg    args.flags = flags;
43322b90624aSmrg
43332b90624aSmrg    ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_WAIT, &args);
43342b90624aSmrg    if (ret < 0)
43352b90624aSmrg        return -errno;
43362b90624aSmrg
43372b90624aSmrg    if (first_signaled)
43382b90624aSmrg        *first_signaled = args.first_signaled;
43392b90624aSmrg    return ret;
43402b90624aSmrg}
43412b90624aSmrg
43426260e5d5Smrgdrm_public int drmSyncobjReset(int fd, const uint32_t *handles,
43436260e5d5Smrg                               uint32_t handle_count)
43442b90624aSmrg{
43452b90624aSmrg    struct drm_syncobj_array args;
43462b90624aSmrg    int ret;
43472b90624aSmrg
43482b90624aSmrg    memclear(args);
43492b90624aSmrg    args.handles = (uintptr_t)handles;
43502b90624aSmrg    args.count_handles = handle_count;
43512b90624aSmrg
43522b90624aSmrg    ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_RESET, &args);
43532b90624aSmrg    return ret;
43542b90624aSmrg}
43552b90624aSmrg
43566260e5d5Smrgdrm_public int drmSyncobjSignal(int fd, const uint32_t *handles,
43576260e5d5Smrg                                uint32_t handle_count)
43582b90624aSmrg{
43592b90624aSmrg    struct drm_syncobj_array args;
43602b90624aSmrg    int ret;
43612b90624aSmrg
43622b90624aSmrg    memclear(args);
43632b90624aSmrg    args.handles = (uintptr_t)handles;
43642b90624aSmrg    args.count_handles = handle_count;
43652b90624aSmrg
43662b90624aSmrg    ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_SIGNAL, &args);
43672b90624aSmrg    return ret;
43682b90624aSmrg}
4369bf6cc7dcSmrg
4370bf6cc7dcSmrgdrm_public int drmSyncobjTimelineSignal(int fd, const uint32_t *handles,
4371bf6cc7dcSmrg					uint64_t *points, uint32_t handle_count)
4372bf6cc7dcSmrg{
4373bf6cc7dcSmrg    struct drm_syncobj_timeline_array args;
4374bf6cc7dcSmrg    int ret;
4375bf6cc7dcSmrg
4376bf6cc7dcSmrg    memclear(args);
4377bf6cc7dcSmrg    args.handles = (uintptr_t)handles;
4378bf6cc7dcSmrg    args.points = (uintptr_t)points;
4379bf6cc7dcSmrg    args.count_handles = handle_count;
4380bf6cc7dcSmrg
4381bf6cc7dcSmrg    ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_TIMELINE_SIGNAL, &args);
4382bf6cc7dcSmrg    return ret;
4383bf6cc7dcSmrg}
4384bf6cc7dcSmrg
4385bf6cc7dcSmrgdrm_public int drmSyncobjTimelineWait(int fd, uint32_t *handles, uint64_t *points,
4386bf6cc7dcSmrg				      unsigned num_handles,
4387bf6cc7dcSmrg				      int64_t timeout_nsec, unsigned flags,
4388bf6cc7dcSmrg				      uint32_t *first_signaled)
4389bf6cc7dcSmrg{
4390bf6cc7dcSmrg    struct drm_syncobj_timeline_wait args;
4391bf6cc7dcSmrg    int ret;
4392bf6cc7dcSmrg
4393bf6cc7dcSmrg    memclear(args);
4394bf6cc7dcSmrg    args.handles = (uintptr_t)handles;
4395bf6cc7dcSmrg    args.points = (uintptr_t)points;
4396bf6cc7dcSmrg    args.timeout_nsec = timeout_nsec;
4397bf6cc7dcSmrg    args.count_handles = num_handles;
4398bf6cc7dcSmrg    args.flags = flags;
4399bf6cc7dcSmrg
4400bf6cc7dcSmrg    ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_TIMELINE_WAIT, &args);
4401bf6cc7dcSmrg    if (ret < 0)
4402bf6cc7dcSmrg        return -errno;
4403bf6cc7dcSmrg
4404bf6cc7dcSmrg    if (first_signaled)
4405bf6cc7dcSmrg        *first_signaled = args.first_signaled;
4406bf6cc7dcSmrg    return ret;
4407bf6cc7dcSmrg}
4408bf6cc7dcSmrg
4409bf6cc7dcSmrg
4410bf6cc7dcSmrgdrm_public int drmSyncobjQuery(int fd, uint32_t *handles, uint64_t *points,
4411bf6cc7dcSmrg			       uint32_t handle_count)
4412bf6cc7dcSmrg{
4413bf6cc7dcSmrg    struct drm_syncobj_timeline_array args;
4414bf6cc7dcSmrg    int ret;
4415bf6cc7dcSmrg
4416bf6cc7dcSmrg    memclear(args);
4417bf6cc7dcSmrg    args.handles = (uintptr_t)handles;
4418bf6cc7dcSmrg    args.points = (uintptr_t)points;
4419bf6cc7dcSmrg    args.count_handles = handle_count;
4420bf6cc7dcSmrg
4421bf6cc7dcSmrg    ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_QUERY, &args);
4422bf6cc7dcSmrg    if (ret)
4423bf6cc7dcSmrg        return ret;
4424bf6cc7dcSmrg    return 0;
4425bf6cc7dcSmrg}
4426bf6cc7dcSmrg
4427bf6cc7dcSmrgdrm_public int drmSyncobjTransfer(int fd,
4428bf6cc7dcSmrg				  uint32_t dst_handle, uint64_t dst_point,
4429bf6cc7dcSmrg				  uint32_t src_handle, uint64_t src_point,
4430bf6cc7dcSmrg				  uint32_t flags)
4431bf6cc7dcSmrg{
4432bf6cc7dcSmrg    struct drm_syncobj_transfer args;
4433bf6cc7dcSmrg    int ret;
4434bf6cc7dcSmrg
4435bf6cc7dcSmrg    memclear(args);
4436bf6cc7dcSmrg    args.src_handle = src_handle;
4437bf6cc7dcSmrg    args.dst_handle = dst_handle;
4438bf6cc7dcSmrg    args.src_point = src_point;
4439bf6cc7dcSmrg    args.dst_point = dst_point;
4440bf6cc7dcSmrg    args.flags = flags;
4441bf6cc7dcSmrg
4442bf6cc7dcSmrg    ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_TRANSFER, &args);
4443bf6cc7dcSmrg
4444bf6cc7dcSmrg    return ret;
4445bf6cc7dcSmrg}
4446