xf86drm.c revision 2ee35494
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#ifdef HAVE_CONFIG_H
3522944501Smrg# include <config.h>
3622944501Smrg#endif
3722944501Smrg#include <stdio.h>
3822944501Smrg#include <stdlib.h>
39fe517fc9Smrg#include <stdbool.h>
4022944501Smrg#include <unistd.h>
4122944501Smrg#include <string.h>
4222944501Smrg#include <strings.h>
4322944501Smrg#include <ctype.h>
44424e9256Smrg#include <dirent.h>
45424e9256Smrg#include <stddef.h>
4622944501Smrg#include <fcntl.h>
4722944501Smrg#include <errno.h>
48fe517fc9Smrg#include <limits.h>
4922944501Smrg#include <signal.h>
5022944501Smrg#include <time.h>
5122944501Smrg#include <sys/types.h>
5222944501Smrg#include <sys/stat.h>
5322944501Smrg#define stat_t struct stat
5422944501Smrg#include <sys/ioctl.h>
5522944501Smrg#include <sys/time.h>
5622944501Smrg#include <stdarg.h>
57fe517fc9Smrg#ifdef MAJOR_IN_MKDEV
58fe517fc9Smrg#include <sys/mkdev.h>
59424e9256Smrg#endif
60fe517fc9Smrg#ifdef MAJOR_IN_SYSMACROS
61fe517fc9Smrg#include <sys/sysmacros.h>
62fe517fc9Smrg#endif
63fe517fc9Smrg#include <math.h>
6422944501Smrg
652ee35494Smrg/* Not all systems have MAP_FAILED defined */
662ee35494Smrg#ifndef MAP_FAILED
672ee35494Smrg#define MAP_FAILED ((void *)-1)
682ee35494Smrg#endif
6922944501Smrg
7022944501Smrg#include "xf86drm.h"
71424e9256Smrg#include "libdrm_macros.h"
7222944501Smrg
73fe517fc9Smrg#include "util_math.h"
74fe517fc9Smrg
75fe517fc9Smrg#ifdef __OpenBSD__
76fe517fc9Smrg#define DRM_PRIMARY_MINOR_NAME  "drm"
77fe517fc9Smrg#define DRM_CONTROL_MINOR_NAME  "drmC"
78fe517fc9Smrg#define DRM_RENDER_MINOR_NAME   "drmR"
79fe517fc9Smrg#else
80fe517fc9Smrg#define DRM_PRIMARY_MINOR_NAME  "card"
81fe517fc9Smrg#define DRM_CONTROL_MINOR_NAME  "controlD"
82fe517fc9Smrg#define DRM_RENDER_MINOR_NAME   "renderD"
83fe517fc9Smrg#endif
84fe517fc9Smrg
8522944501Smrg#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
8622944501Smrg#define DRM_MAJOR 145
8722944501Smrg#endif
8822944501Smrg
8922944501Smrg#ifdef __NetBSD__
902e6867f6Smrg#undef DRM_MAJOR
912e6867f6Smrg#define DRM_MAJOR 180
9222944501Smrg#endif
9322944501Smrg
94fe517fc9Smrg#ifdef __OpenBSD__
95fe517fc9Smrg#ifdef __i386__
96fe517fc9Smrg#define DRM_MAJOR 88
97fe517fc9Smrg#else
98fe517fc9Smrg#define DRM_MAJOR 87
9922944501Smrg#endif
100fe517fc9Smrg#endif /* __OpenBSD__ */
10122944501Smrg
102fe517fc9Smrg#ifndef DRM_MAJOR
103fe517fc9Smrg#define DRM_MAJOR 226 /* Linux */
10422944501Smrg#endif
10522944501Smrg
1062ee35494Smrg#ifdef __OpenBSD__
1072ee35494Smrgstruct drm_pciinfo {
1082ee35494Smrg	uint16_t	domain;
1092ee35494Smrg	uint8_t		bus;
1102ee35494Smrg	uint8_t		dev;
1112ee35494Smrg	uint8_t		func;
1122ee35494Smrg	uint16_t	vendor_id;
1132ee35494Smrg	uint16_t	device_id;
1142ee35494Smrg	uint16_t	subvendor_id;
1152ee35494Smrg	uint16_t	subdevice_id;
1162ee35494Smrg	uint8_t		revision_id;
1172ee35494Smrg};
1182ee35494Smrg
1192ee35494Smrg#define DRM_IOCTL_GET_PCIINFO	DRM_IOR(0x15, struct drm_pciinfo)
12011c53d23Schristos#endif
12111c53d23Schristos
12222944501Smrg#define DRM_MSG_VERBOSITY 3
12322944501Smrg
124424e9256Smrg#define memclear(s) memset(&s, 0, sizeof(s))
12522944501Smrg
12622944501Smrgstatic drmServerInfoPtr drm_server_info;
12722944501Smrg
12822944501Smrgvoid drmSetServerInfo(drmServerInfoPtr info)
12922944501Smrg{
13022944501Smrg    drm_server_info = info;
13122944501Smrg}
13222944501Smrg
13322944501Smrg/**
13422944501Smrg * Output a message to stderr.
13522944501Smrg *
13622944501Smrg * \param format printf() like format string.
13722944501Smrg *
13822944501Smrg * \internal
13922944501Smrg * This function is a wrapper around vfprintf().
14022944501Smrg */
14122944501Smrg
142a7d7de1eSmrgstatic int DRM_PRINTFLIKE(1, 0)
143a7d7de1eSmrgdrmDebugPrint(const char *format, va_list ap)
14422944501Smrg{
14522944501Smrg    return vfprintf(stderr, format, ap);
14622944501Smrg}
14722944501Smrg
14822944501Smrgvoid
14922944501SmrgdrmMsg(const char *format, ...)
15022944501Smrg{
151fe517fc9Smrg    va_list ap;
15222944501Smrg    const char *env;
153fe517fc9Smrg    if (((env = getenv("LIBGL_DEBUG")) && strstr(env, "verbose")) ||
154fe517fc9Smrg        (drm_server_info && drm_server_info->debug_print))
15522944501Smrg    {
156fe517fc9Smrg        va_start(ap, format);
157fe517fc9Smrg        if (drm_server_info) {
158fe517fc9Smrg            drm_server_info->debug_print(format,ap);
159fe517fc9Smrg        } else {
160fe517fc9Smrg            drmDebugPrint(format, ap);
161fe517fc9Smrg        }
162fe517fc9Smrg        va_end(ap);
16322944501Smrg    }
16422944501Smrg}
16522944501Smrg
16622944501Smrgstatic void *drmHashTable = NULL; /* Context switch callbacks */
16722944501Smrg
16822944501Smrgvoid *drmGetHashTable(void)
16922944501Smrg{
17022944501Smrg    return drmHashTable;
17122944501Smrg}
17222944501Smrg
17322944501Smrgvoid *drmMalloc(int size)
17422944501Smrg{
175424e9256Smrg    return calloc(1, size);
17622944501Smrg}
17722944501Smrg
17822944501Smrgvoid drmFree(void *pt)
17922944501Smrg{
180424e9256Smrg    free(pt);
18122944501Smrg}
18222944501Smrg
18322944501Smrg/**
18422944501Smrg * Call ioctl, restarting if it is interupted
18522944501Smrg */
18622944501Smrgint
18722944501SmrgdrmIoctl(int fd, unsigned long request, void *arg)
18822944501Smrg{
189fe517fc9Smrg    int ret;
19022944501Smrg
19122944501Smrg    do {
192fe517fc9Smrg        ret = ioctl(fd, request, arg);
19322944501Smrg    } while (ret == -1 && (errno == EINTR || errno == EAGAIN));
19422944501Smrg    return ret;
19522944501Smrg}
19622944501Smrg
19722944501Smrgstatic unsigned long drmGetKeyFromFd(int fd)
19822944501Smrg{
19922944501Smrg    stat_t     st;
20022944501Smrg
20122944501Smrg    st.st_rdev = 0;
20222944501Smrg    fstat(fd, &st);
20322944501Smrg    return st.st_rdev;
20422944501Smrg}
20522944501Smrg
20622944501SmrgdrmHashEntry *drmGetEntry(int fd)
20722944501Smrg{
20822944501Smrg    unsigned long key = drmGetKeyFromFd(fd);
20922944501Smrg    void          *value;
21022944501Smrg    drmHashEntry  *entry;
21122944501Smrg
21222944501Smrg    if (!drmHashTable)
213fe517fc9Smrg        drmHashTable = drmHashCreate();
21422944501Smrg
21522944501Smrg    if (drmHashLookup(drmHashTable, key, &value)) {
216fe517fc9Smrg        entry           = drmMalloc(sizeof(*entry));
217fe517fc9Smrg        entry->fd       = fd;
218fe517fc9Smrg        entry->f        = NULL;
219fe517fc9Smrg        entry->tagTable = drmHashCreate();
220fe517fc9Smrg        drmHashInsert(drmHashTable, key, entry);
22122944501Smrg    } else {
222fe517fc9Smrg        entry = value;
22322944501Smrg    }
22422944501Smrg    return entry;
22522944501Smrg}
22622944501Smrg
22722944501Smrg/**
22822944501Smrg * Compare two busid strings
22922944501Smrg *
23022944501Smrg * \param first
23122944501Smrg * \param second
23222944501Smrg *
23322944501Smrg * \return 1 if matched.
23422944501Smrg *
23522944501Smrg * \internal
23622944501Smrg * This function compares two bus ID strings.  It understands the older
23722944501Smrg * PCI:b:d:f format and the newer pci:oooo:bb:dd.f format.  In the format, o is
23822944501Smrg * domain, b is bus, d is device, f is function.
23922944501Smrg */
2406d98c517Smrgstatic int drmMatchBusID(const char *id1, const char *id2, int pci_domain_ok)
24122944501Smrg{
24222944501Smrg    /* First, check if the IDs are exactly the same */
24322944501Smrg    if (strcasecmp(id1, id2) == 0)
244fe517fc9Smrg        return 1;
24522944501Smrg
24622944501Smrg    /* Try to match old/new-style PCI bus IDs. */
24722944501Smrg    if (strncasecmp(id1, "pci", 3) == 0) {
248fe517fc9Smrg        unsigned int o1, b1, d1, f1;
249fe517fc9Smrg        unsigned int o2, b2, d2, f2;
250fe517fc9Smrg        int ret;
251fe517fc9Smrg
252fe517fc9Smrg        ret = sscanf(id1, "pci:%04x:%02x:%02x.%u", &o1, &b1, &d1, &f1);
253fe517fc9Smrg        if (ret != 4) {
254fe517fc9Smrg            o1 = 0;
255fe517fc9Smrg            ret = sscanf(id1, "PCI:%u:%u:%u", &b1, &d1, &f1);
256fe517fc9Smrg            if (ret != 3)
257fe517fc9Smrg                return 0;
258fe517fc9Smrg        }
259fe517fc9Smrg
260fe517fc9Smrg        ret = sscanf(id2, "pci:%04x:%02x:%02x.%u", &o2, &b2, &d2, &f2);
261fe517fc9Smrg        if (ret != 4) {
262fe517fc9Smrg            o2 = 0;
263fe517fc9Smrg            ret = sscanf(id2, "PCI:%u:%u:%u", &b2, &d2, &f2);
264fe517fc9Smrg            if (ret != 3)
265fe517fc9Smrg                return 0;
266fe517fc9Smrg        }
267fe517fc9Smrg
268fe517fc9Smrg        /* If domains aren't properly supported by the kernel interface,
269fe517fc9Smrg         * just ignore them, which sucks less than picking a totally random
270fe517fc9Smrg         * card with "open by name"
271fe517fc9Smrg         */
272fe517fc9Smrg        if (!pci_domain_ok)
273fe517fc9Smrg            o1 = o2 = 0;
274fe517fc9Smrg
275fe517fc9Smrg        if ((o1 != o2) || (b1 != b2) || (d1 != d2) || (f1 != f2))
276fe517fc9Smrg            return 0;
277fe517fc9Smrg        else
278fe517fc9Smrg            return 1;
27922944501Smrg    }
28022944501Smrg    return 0;
28122944501Smrg}
28222944501Smrg
28322944501Smrg/**
28422944501Smrg * Handles error checking for chown call.
28522944501Smrg *
28622944501Smrg * \param path to file.
28722944501Smrg * \param id of the new owner.
28822944501Smrg * \param id of the new group.
28922944501Smrg *
29022944501Smrg * \return zero if success or -1 if failure.
29122944501Smrg *
29222944501Smrg * \internal
29322944501Smrg * Checks for failure. If failure was caused by signal call chown again.
29422944501Smrg * If any other failure happened then it will output error mesage using
29522944501Smrg * drmMsg() call.
29622944501Smrg */
297424e9256Smrg#if !defined(UDEV)
29822944501Smrgstatic int chown_check_return(const char *path, uid_t owner, gid_t group)
29922944501Smrg{
300fe517fc9Smrg        int rv;
30122944501Smrg
302fe517fc9Smrg        do {
303fe517fc9Smrg            rv = chown(path, owner, group);
304fe517fc9Smrg        } while (rv != 0 && errno == EINTR);
30522944501Smrg
306fe517fc9Smrg        if (rv == 0)
307fe517fc9Smrg            return 0;
30822944501Smrg
309fe517fc9Smrg        drmMsg("Failed to change owner or group for file %s! %d: %s\n",
310fe517fc9Smrg               path, errno, strerror(errno));
311fe517fc9Smrg        return -1;
31222944501Smrg}
313424e9256Smrg#endif
31422944501Smrg
31522944501Smrg/**
31622944501Smrg * Open the DRM device, creating it if necessary.
31722944501Smrg *
31822944501Smrg * \param dev major and minor numbers of the device.
31922944501Smrg * \param minor minor number of the device.
320fe517fc9Smrg *
32122944501Smrg * \return a file descriptor on success, or a negative value on error.
32222944501Smrg *
32322944501Smrg * \internal
32422944501Smrg * Assembles the device name from \p minor and opens it, creating the device
32522944501Smrg * special file node with the major and minor numbers specified by \p dev and
32622944501Smrg * parent directory if necessary and was called by root.
32722944501Smrg */
328424e9256Smrgstatic int drmOpenDevice(dev_t dev, int minor, int type)
32922944501Smrg{
33022944501Smrg    stat_t          st;
331424e9256Smrg    const char      *dev_name;
33222944501Smrg    char            buf[64];
33322944501Smrg    int             fd;
33422944501Smrg    mode_t          devmode = DRM_DEV_MODE, serv_mode;
335424e9256Smrg    gid_t           serv_group;
336424e9256Smrg#if !defined(UDEV)
33722944501Smrg    int             isroot  = !geteuid();
33822944501Smrg    uid_t           user    = DRM_DEV_UID;
339424e9256Smrg    gid_t           group   = DRM_DEV_GID;
340424e9256Smrg#endif
341424e9256Smrg
342424e9256Smrg    switch (type) {
343424e9256Smrg    case DRM_NODE_PRIMARY:
344fe517fc9Smrg        dev_name = DRM_DEV_NAME;
345fe517fc9Smrg        break;
346424e9256Smrg    case DRM_NODE_CONTROL:
347fe517fc9Smrg        dev_name = DRM_CONTROL_DEV_NAME;
348fe517fc9Smrg        break;
349424e9256Smrg    case DRM_NODE_RENDER:
350fe517fc9Smrg        dev_name = DRM_RENDER_DEV_NAME;
351fe517fc9Smrg        break;
352424e9256Smrg    default:
353fe517fc9Smrg        return -EINVAL;
354424e9256Smrg    };
355424e9256Smrg
356424e9256Smrg    sprintf(buf, dev_name, DRM_DIR_NAME, minor);
35722944501Smrg    drmMsg("drmOpenDevice: node name is %s\n", buf);
35822944501Smrg
359fe517fc9Smrg    if (drm_server_info && drm_server_info->get_perms) {
360fe517fc9Smrg        drm_server_info->get_perms(&serv_group, &serv_mode);
361fe517fc9Smrg        devmode  = serv_mode ? serv_mode : DRM_DEV_MODE;
362fe517fc9Smrg        devmode &= ~(S_IXUSR|S_IXGRP|S_IXOTH);
36322944501Smrg    }
36422944501Smrg
36522944501Smrg#if !defined(UDEV)
36622944501Smrg    if (stat(DRM_DIR_NAME, &st)) {
367fe517fc9Smrg        if (!isroot)
368fe517fc9Smrg            return DRM_ERR_NOT_ROOT;
369fe517fc9Smrg        mkdir(DRM_DIR_NAME, DRM_DEV_DIRMODE);
370fe517fc9Smrg        chown_check_return(DRM_DIR_NAME, 0, 0); /* root:root */
371fe517fc9Smrg        chmod(DRM_DIR_NAME, DRM_DEV_DIRMODE);
37222944501Smrg    }
37322944501Smrg
37422944501Smrg    /* Check if the device node exists and create it if necessary. */
37522944501Smrg    if (stat(buf, &st)) {
376fe517fc9Smrg        if (!isroot)
377fe517fc9Smrg            return DRM_ERR_NOT_ROOT;
378fe517fc9Smrg        remove(buf);
379fe517fc9Smrg        mknod(buf, S_IFCHR | devmode, dev);
38022944501Smrg    }
38122944501Smrg
382fe517fc9Smrg    if (drm_server_info && drm_server_info->get_perms) {
383fe517fc9Smrg        group = ((int)serv_group >= 0) ? serv_group : DRM_DEV_GID;
384fe517fc9Smrg        chown_check_return(buf, user, group);
385fe517fc9Smrg        chmod(buf, devmode);
38622944501Smrg    }
38722944501Smrg#else
38822944501Smrg    /* if we modprobed then wait for udev */
38922944501Smrg    {
390fe517fc9Smrg        int udev_count = 0;
39122944501Smrgwait_for_udev:
39222944501Smrg        if (stat(DRM_DIR_NAME, &st)) {
393fe517fc9Smrg            usleep(20);
394fe517fc9Smrg            udev_count++;
395fe517fc9Smrg
396fe517fc9Smrg            if (udev_count == 50)
397fe517fc9Smrg                return -1;
398fe517fc9Smrg            goto wait_for_udev;
399fe517fc9Smrg        }
400fe517fc9Smrg
401fe517fc9Smrg        if (stat(buf, &st)) {
402fe517fc9Smrg            usleep(20);
403fe517fc9Smrg            udev_count++;
404fe517fc9Smrg
405fe517fc9Smrg            if (udev_count == 50)
406fe517fc9Smrg                return -1;
407fe517fc9Smrg            goto wait_for_udev;
408fe517fc9Smrg        }
40922944501Smrg    }
41022944501Smrg#endif
41122944501Smrg
41222944501Smrg    fd = open(buf, O_RDWR, 0);
41322944501Smrg    drmMsg("drmOpenDevice: open result is %d, (%s)\n",
414fe517fc9Smrg           fd, fd < 0 ? strerror(errno) : "OK");
41522944501Smrg    if (fd >= 0)
416fe517fc9Smrg        return fd;
41722944501Smrg
4189ce4edccSmrg#if !defined(UDEV)
41922944501Smrg    /* Check if the device node is not what we expect it to be, and recreate it
42022944501Smrg     * and try again if so.
42122944501Smrg     */
42222944501Smrg    if (st.st_rdev != dev) {
423fe517fc9Smrg        if (!isroot)
424fe517fc9Smrg            return DRM_ERR_NOT_ROOT;
425fe517fc9Smrg        remove(buf);
426fe517fc9Smrg        mknod(buf, S_IFCHR | devmode, dev);
427fe517fc9Smrg        if (drm_server_info && drm_server_info->get_perms) {
428fe517fc9Smrg            chown_check_return(buf, user, group);
429fe517fc9Smrg            chmod(buf, devmode);
430fe517fc9Smrg        }
43122944501Smrg    }
43222944501Smrg    fd = open(buf, O_RDWR, 0);
43322944501Smrg    drmMsg("drmOpenDevice: open result is %d, (%s)\n",
434fe517fc9Smrg           fd, fd < 0 ? strerror(errno) : "OK");
43522944501Smrg    if (fd >= 0)
436fe517fc9Smrg        return fd;
43722944501Smrg
43822944501Smrg    drmMsg("drmOpenDevice: Open failed\n");
43922944501Smrg    remove(buf);
4409ce4edccSmrg#endif
44122944501Smrg    return -errno;
44222944501Smrg}
44322944501Smrg
44422944501Smrg
44522944501Smrg/**
44622944501Smrg * Open the DRM device
44722944501Smrg *
44822944501Smrg * \param minor device minor number.
44922944501Smrg * \param create allow to create the device if set.
45022944501Smrg *
45122944501Smrg * \return a file descriptor on success, or a negative value on error.
452fe517fc9Smrg *
45322944501Smrg * \internal
45422944501Smrg * Calls drmOpenDevice() if \p create is set, otherwise assembles the device
45522944501Smrg * name from \p minor and opens it.
45622944501Smrg */
45722944501Smrgstatic int drmOpenMinor(int minor, int create, int type)
45822944501Smrg{
45922944501Smrg    int  fd;
46022944501Smrg    char buf[64];
461424e9256Smrg    const char *dev_name;
462fe517fc9Smrg
46322944501Smrg    if (create)
464fe517fc9Smrg        return drmOpenDevice(makedev(DRM_MAJOR, minor), minor, type);
465fe517fc9Smrg
466424e9256Smrg    switch (type) {
467424e9256Smrg    case DRM_NODE_PRIMARY:
468fe517fc9Smrg        dev_name = DRM_DEV_NAME;
469fe517fc9Smrg        break;
470424e9256Smrg    case DRM_NODE_CONTROL:
471fe517fc9Smrg        dev_name = DRM_CONTROL_DEV_NAME;
472fe517fc9Smrg        break;
473424e9256Smrg    case DRM_NODE_RENDER:
474fe517fc9Smrg        dev_name = DRM_RENDER_DEV_NAME;
475fe517fc9Smrg        break;
476424e9256Smrg    default:
477fe517fc9Smrg        return -EINVAL;
478424e9256Smrg    };
479424e9256Smrg
480424e9256Smrg    sprintf(buf, dev_name, DRM_DIR_NAME, minor);
48122944501Smrg    if ((fd = open(buf, O_RDWR, 0)) >= 0)
482fe517fc9Smrg        return fd;
48322944501Smrg    return -errno;
48422944501Smrg}
48522944501Smrg
48622944501Smrg
48722944501Smrg/**
48822944501Smrg * Determine whether the DRM kernel driver has been loaded.
489fe517fc9Smrg *
49022944501Smrg * \return 1 if the DRM driver is loaded, 0 otherwise.
49122944501Smrg *
492fe517fc9Smrg * \internal
49322944501Smrg * Determine the presence of the kernel driver by attempting to open the 0
49422944501Smrg * minor and get version information.  For backward compatibility with older
49522944501Smrg * Linux implementations, /proc/dri is also checked.
49622944501Smrg */
49722944501Smrgint drmAvailable(void)
49822944501Smrg{
49922944501Smrg    drmVersionPtr version;
50022944501Smrg    int           retval = 0;
50122944501Smrg    int           fd;
50222944501Smrg
503424e9256Smrg    if ((fd = drmOpenMinor(0, 1, DRM_NODE_PRIMARY)) < 0) {
50422944501Smrg#ifdef __linux__
505fe517fc9Smrg        /* Try proc for backward Linux compatibility */
506fe517fc9Smrg        if (!access("/proc/dri/0", R_OK))
507fe517fc9Smrg            return 1;
50822944501Smrg#endif
509fe517fc9Smrg        return 0;
51022944501Smrg    }
511fe517fc9Smrg
51222944501Smrg    if ((version = drmGetVersion(fd))) {
513fe517fc9Smrg        retval = 1;
514fe517fc9Smrg        drmFreeVersion(version);
51522944501Smrg    }
51622944501Smrg    close(fd);
51722944501Smrg
51822944501Smrg    return retval;
51922944501Smrg}
52022944501Smrg
521424e9256Smrgstatic int drmGetMinorBase(int type)
522424e9256Smrg{
523424e9256Smrg    switch (type) {
524424e9256Smrg    case DRM_NODE_PRIMARY:
525424e9256Smrg        return 0;
526424e9256Smrg    case DRM_NODE_CONTROL:
527424e9256Smrg        return 64;
528424e9256Smrg    case DRM_NODE_RENDER:
529424e9256Smrg        return 128;
530424e9256Smrg    default:
531424e9256Smrg        return -1;
532424e9256Smrg    };
533424e9256Smrg}
534424e9256Smrg
535424e9256Smrgstatic int drmGetMinorType(int minor)
536424e9256Smrg{
537424e9256Smrg    int type = minor >> 6;
538424e9256Smrg
539424e9256Smrg    if (minor < 0)
540424e9256Smrg        return -1;
541424e9256Smrg
542424e9256Smrg    switch (type) {
543424e9256Smrg    case DRM_NODE_PRIMARY:
544424e9256Smrg    case DRM_NODE_CONTROL:
545424e9256Smrg    case DRM_NODE_RENDER:
546424e9256Smrg        return type;
547424e9256Smrg    default:
548424e9256Smrg        return -1;
549424e9256Smrg    }
550424e9256Smrg}
551424e9256Smrg
552424e9256Smrgstatic const char *drmGetMinorName(int type)
553424e9256Smrg{
554424e9256Smrg    switch (type) {
555424e9256Smrg    case DRM_NODE_PRIMARY:
556fe517fc9Smrg        return DRM_PRIMARY_MINOR_NAME;
557424e9256Smrg    case DRM_NODE_CONTROL:
558fe517fc9Smrg        return DRM_CONTROL_MINOR_NAME;
559424e9256Smrg    case DRM_NODE_RENDER:
560fe517fc9Smrg        return DRM_RENDER_MINOR_NAME;
561424e9256Smrg    default:
562424e9256Smrg        return NULL;
563424e9256Smrg    }
564424e9256Smrg}
56522944501Smrg
56622944501Smrg/**
56722944501Smrg * Open the device by bus ID.
56822944501Smrg *
56922944501Smrg * \param busid bus ID.
570424e9256Smrg * \param type device node type.
57122944501Smrg *
57222944501Smrg * \return a file descriptor on success, or a negative value on error.
57322944501Smrg *
57422944501Smrg * \internal
57522944501Smrg * This function attempts to open every possible minor (up to DRM_MAX_MINOR),
57622944501Smrg * comparing the device bus ID with the one supplied.
57722944501Smrg *
57822944501Smrg * \sa drmOpenMinor() and drmGetBusid().
57922944501Smrg */
580424e9256Smrgstatic int drmOpenByBusid(const char *busid, int type)
58122944501Smrg{
5826d98c517Smrg    int        i, pci_domain_ok = 1;
58322944501Smrg    int        fd;
58422944501Smrg    const char *buf;
58522944501Smrg    drmSetVersion sv;
586424e9256Smrg    int        base = drmGetMinorBase(type);
587424e9256Smrg
588424e9256Smrg    if (base < 0)
589424e9256Smrg        return -1;
59022944501Smrg
59122944501Smrg    drmMsg("drmOpenByBusid: Searching for BusID %s\n", busid);
592424e9256Smrg    for (i = base; i < base + DRM_MAX_MINOR; i++) {
593fe517fc9Smrg        fd = drmOpenMinor(i, 1, type);
594fe517fc9Smrg        drmMsg("drmOpenByBusid: drmOpenMinor returns %d\n", fd);
595fe517fc9Smrg        if (fd >= 0) {
596fe517fc9Smrg            /* We need to try for 1.4 first for proper PCI domain support
597fe517fc9Smrg             * and if that fails, we know the kernel is busted
598fe517fc9Smrg             */
599fe517fc9Smrg            sv.drm_di_major = 1;
600fe517fc9Smrg            sv.drm_di_minor = 4;
601fe517fc9Smrg            sv.drm_dd_major = -1;        /* Don't care */
602fe517fc9Smrg            sv.drm_dd_minor = -1;        /* Don't care */
603fe517fc9Smrg            if (drmSetInterfaceVersion(fd, &sv)) {
6046d98c517Smrg#ifndef __alpha__
605fe517fc9Smrg                pci_domain_ok = 0;
6066d98c517Smrg#endif
607fe517fc9Smrg                sv.drm_di_major = 1;
608fe517fc9Smrg                sv.drm_di_minor = 1;
609fe517fc9Smrg                sv.drm_dd_major = -1;       /* Don't care */
610fe517fc9Smrg                sv.drm_dd_minor = -1;       /* Don't care */
611fe517fc9Smrg                drmMsg("drmOpenByBusid: Interface 1.4 failed, trying 1.1\n");
612fe517fc9Smrg                drmSetInterfaceVersion(fd, &sv);
613fe517fc9Smrg            }
614fe517fc9Smrg            buf = drmGetBusid(fd);
615fe517fc9Smrg            drmMsg("drmOpenByBusid: drmGetBusid reports %s\n", buf);
616fe517fc9Smrg            if (buf && drmMatchBusID(buf, busid, pci_domain_ok)) {
617fe517fc9Smrg                drmFreeBusid(buf);
618fe517fc9Smrg                return fd;
619fe517fc9Smrg            }
620fe517fc9Smrg            if (buf)
621fe517fc9Smrg                drmFreeBusid(buf);
622fe517fc9Smrg            close(fd);
623fe517fc9Smrg        }
62422944501Smrg    }
62522944501Smrg    return -1;
62622944501Smrg}
62722944501Smrg
62822944501Smrg
62922944501Smrg/**
63022944501Smrg * Open the device by name.
63122944501Smrg *
63222944501Smrg * \param name driver name.
633424e9256Smrg * \param type the device node type.
634fe517fc9Smrg *
63522944501Smrg * \return a file descriptor on success, or a negative value on error.
636fe517fc9Smrg *
63722944501Smrg * \internal
63822944501Smrg * This function opens the first minor number that matches the driver name and
63922944501Smrg * isn't already in use.  If it's in use it then it will already have a bus ID
64022944501Smrg * assigned.
641fe517fc9Smrg *
64222944501Smrg * \sa drmOpenMinor(), drmGetVersion() and drmGetBusid().
64322944501Smrg */
644424e9256Smrgstatic int drmOpenByName(const char *name, int type)
64522944501Smrg{
64622944501Smrg    int           i;
64722944501Smrg    int           fd;
64822944501Smrg    drmVersionPtr version;
64922944501Smrg    char *        id;
650424e9256Smrg    int           base = drmGetMinorBase(type);
651424e9256Smrg
652424e9256Smrg    if (base < 0)
653424e9256Smrg        return -1;
65422944501Smrg
65522944501Smrg    /*
65622944501Smrg     * Open the first minor number that matches the driver name and isn't
65722944501Smrg     * already in use.  If it's in use it will have a busid assigned already.
65822944501Smrg     */
659424e9256Smrg    for (i = base; i < base + DRM_MAX_MINOR; i++) {
660fe517fc9Smrg        if ((fd = drmOpenMinor(i, 1, type)) >= 0) {
661fe517fc9Smrg            if ((version = drmGetVersion(fd))) {
662fe517fc9Smrg                if (!strcmp(version->name, name)) {
663fe517fc9Smrg                    drmFreeVersion(version);
664fe517fc9Smrg                    id = drmGetBusid(fd);
665fe517fc9Smrg                    drmMsg("drmGetBusid returned '%s'\n", id ? id : "NULL");
666fe517fc9Smrg                    if (!id || !*id) {
667fe517fc9Smrg                        if (id)
668fe517fc9Smrg                            drmFreeBusid(id);
669fe517fc9Smrg                        return fd;
670fe517fc9Smrg                    } else {
671fe517fc9Smrg                        drmFreeBusid(id);
672fe517fc9Smrg                    }
673fe517fc9Smrg                } else {
674fe517fc9Smrg                    drmFreeVersion(version);
675fe517fc9Smrg                }
676fe517fc9Smrg            }
677fe517fc9Smrg            close(fd);
678fe517fc9Smrg        }
67922944501Smrg    }
68022944501Smrg
68122944501Smrg#ifdef __linux__
68222944501Smrg    /* Backward-compatibility /proc support */
68322944501Smrg    for (i = 0; i < 8; i++) {
684fe517fc9Smrg        char proc_name[64], buf[512];
685fe517fc9Smrg        char *driver, *pt, *devstring;
686fe517fc9Smrg        int  retcode;
687fe517fc9Smrg
688fe517fc9Smrg        sprintf(proc_name, "/proc/dri/%d/name", i);
689fe517fc9Smrg        if ((fd = open(proc_name, 0, 0)) >= 0) {
690fe517fc9Smrg            retcode = read(fd, buf, sizeof(buf)-1);
691fe517fc9Smrg            close(fd);
692fe517fc9Smrg            if (retcode) {
693fe517fc9Smrg                buf[retcode-1] = '\0';
694fe517fc9Smrg                for (driver = pt = buf; *pt && *pt != ' '; ++pt)
695fe517fc9Smrg                    ;
696fe517fc9Smrg                if (*pt) { /* Device is next */
697fe517fc9Smrg                    *pt = '\0';
698fe517fc9Smrg                    if (!strcmp(driver, name)) { /* Match */
699fe517fc9Smrg                        for (devstring = ++pt; *pt && *pt != ' '; ++pt)
700fe517fc9Smrg                            ;
701fe517fc9Smrg                        if (*pt) { /* Found busid */
702fe517fc9Smrg                            return drmOpenByBusid(++pt, type);
703fe517fc9Smrg                        } else { /* No busid */
704fe517fc9Smrg                            return drmOpenDevice(strtol(devstring, NULL, 0),i, type);
705fe517fc9Smrg                        }
706fe517fc9Smrg                    }
707fe517fc9Smrg                }
708fe517fc9Smrg            }
709fe517fc9Smrg        }
71022944501Smrg    }
71122944501Smrg#endif
71222944501Smrg
71322944501Smrg    return -1;
71422944501Smrg}
71522944501Smrg
71622944501Smrg
71722944501Smrg/**
71822944501Smrg * Open the DRM device.
71922944501Smrg *
72022944501Smrg * Looks up the specified name and bus ID, and opens the device found.  The
72122944501Smrg * entry in /dev/dri is created if necessary and if called by root.
72222944501Smrg *
72322944501Smrg * \param name driver name. Not referenced if bus ID is supplied.
72422944501Smrg * \param busid bus ID. Zero if not known.
725fe517fc9Smrg *
72622944501Smrg * \return a file descriptor on success, or a negative value on error.
727fe517fc9Smrg *
72822944501Smrg * \internal
72922944501Smrg * It calls drmOpenByBusid() if \p busid is specified or drmOpenByName()
73022944501Smrg * otherwise.
73122944501Smrg */
73222944501Smrgint drmOpen(const char *name, const char *busid)
733424e9256Smrg{
734424e9256Smrg    return drmOpenWithType(name, busid, DRM_NODE_PRIMARY);
735424e9256Smrg}
736424e9256Smrg
737424e9256Smrg/**
738424e9256Smrg * Open the DRM device with specified type.
739424e9256Smrg *
740424e9256Smrg * Looks up the specified name and bus ID, and opens the device found.  The
741424e9256Smrg * entry in /dev/dri is created if necessary and if called by root.
742424e9256Smrg *
743424e9256Smrg * \param name driver name. Not referenced if bus ID is supplied.
744424e9256Smrg * \param busid bus ID. Zero if not known.
745424e9256Smrg * \param type the device node type to open, PRIMARY, CONTROL or RENDER
746424e9256Smrg *
747424e9256Smrg * \return a file descriptor on success, or a negative value on error.
748424e9256Smrg *
749424e9256Smrg * \internal
750424e9256Smrg * It calls drmOpenByBusid() if \p busid is specified or drmOpenByName()
751424e9256Smrg * otherwise.
752424e9256Smrg */
753424e9256Smrgint drmOpenWithType(const char *name, const char *busid, int type)
75422944501Smrg{
755fe517fc9Smrg    if (!drmAvailable() && name != NULL && drm_server_info &&
756fe517fc9Smrg        drm_server_info->load_module) {
757fe517fc9Smrg        /* try to load the kernel module */
758fe517fc9Smrg        if (!drm_server_info->load_module(name)) {
759fe517fc9Smrg            drmMsg("[drm] failed to load kernel module \"%s\"\n", name);
760fe517fc9Smrg            return -1;
761fe517fc9Smrg        }
76222944501Smrg    }
76322944501Smrg
76422944501Smrg    if (busid) {
765fe517fc9Smrg        int fd = drmOpenByBusid(busid, type);
766fe517fc9Smrg        if (fd >= 0)
767fe517fc9Smrg            return fd;
76822944501Smrg    }
769fe517fc9Smrg
77022944501Smrg    if (name)
771fe517fc9Smrg        return drmOpenByName(name, type);
77222944501Smrg
77322944501Smrg    return -1;
77422944501Smrg}
77522944501Smrg
77622944501Smrgint drmOpenControl(int minor)
77722944501Smrg{
77822944501Smrg    return drmOpenMinor(minor, 0, DRM_NODE_CONTROL);
77922944501Smrg}
78022944501Smrg
781424e9256Smrgint drmOpenRender(int minor)
782424e9256Smrg{
783424e9256Smrg    return drmOpenMinor(minor, 0, DRM_NODE_RENDER);
784424e9256Smrg}
785424e9256Smrg
78622944501Smrg/**
78722944501Smrg * Free the version information returned by drmGetVersion().
78822944501Smrg *
78922944501Smrg * \param v pointer to the version information.
79022944501Smrg *
79122944501Smrg * \internal
79222944501Smrg * It frees the memory pointed by \p %v as well as all the non-null strings
79322944501Smrg * pointers in it.
79422944501Smrg */
79522944501Smrgvoid drmFreeVersion(drmVersionPtr v)
79622944501Smrg{
79722944501Smrg    if (!v)
798fe517fc9Smrg        return;
79922944501Smrg    drmFree(v->name);
80022944501Smrg    drmFree(v->date);
80122944501Smrg    drmFree(v->desc);
80222944501Smrg    drmFree(v);
80322944501Smrg}
80422944501Smrg
80522944501Smrg
80622944501Smrg/**
80722944501Smrg * Free the non-public version information returned by the kernel.
80822944501Smrg *
80922944501Smrg * \param v pointer to the version information.
81022944501Smrg *
81122944501Smrg * \internal
81222944501Smrg * Used by drmGetVersion() to free the memory pointed by \p %v as well as all
81322944501Smrg * the non-null strings pointers in it.
81422944501Smrg */
81522944501Smrgstatic void drmFreeKernelVersion(drm_version_t *v)
81622944501Smrg{
81722944501Smrg    if (!v)
818fe517fc9Smrg        return;
81922944501Smrg    drmFree(v->name);
82022944501Smrg    drmFree(v->date);
82122944501Smrg    drmFree(v->desc);
82222944501Smrg    drmFree(v);
82322944501Smrg}
82422944501Smrg
82522944501Smrg
82622944501Smrg/**
82722944501Smrg * Copy version information.
828fe517fc9Smrg *
82922944501Smrg * \param d destination pointer.
83022944501Smrg * \param s source pointer.
831fe517fc9Smrg *
83222944501Smrg * \internal
83322944501Smrg * Used by drmGetVersion() to translate the information returned by the ioctl
83422944501Smrg * interface in a private structure into the public structure counterpart.
83522944501Smrg */
83622944501Smrgstatic void drmCopyVersion(drmVersionPtr d, const drm_version_t *s)
83722944501Smrg{
83822944501Smrg    d->version_major      = s->version_major;
83922944501Smrg    d->version_minor      = s->version_minor;
84022944501Smrg    d->version_patchlevel = s->version_patchlevel;
84122944501Smrg    d->name_len           = s->name_len;
8429ce4edccSmrg    d->name               = strdup(s->name);
84322944501Smrg    d->date_len           = s->date_len;
8449ce4edccSmrg    d->date               = strdup(s->date);
84522944501Smrg    d->desc_len           = s->desc_len;
8469ce4edccSmrg    d->desc               = strdup(s->desc);
84722944501Smrg}
84822944501Smrg
84922944501Smrg
85022944501Smrg/**
85122944501Smrg * Query the driver version information.
85222944501Smrg *
85322944501Smrg * \param fd file descriptor.
854fe517fc9Smrg *
85522944501Smrg * \return pointer to a drmVersion structure which should be freed with
85622944501Smrg * drmFreeVersion().
857fe517fc9Smrg *
85822944501Smrg * \note Similar information is available via /proc/dri.
859fe517fc9Smrg *
86022944501Smrg * \internal
86122944501Smrg * It gets the version information via successive DRM_IOCTL_VERSION ioctls,
86222944501Smrg * first with zeros to get the string lengths, and then the actually strings.
86322944501Smrg * It also null-terminates them since they might not be already.
86422944501Smrg */
86522944501SmrgdrmVersionPtr drmGetVersion(int fd)
86622944501Smrg{
86722944501Smrg    drmVersionPtr retval;
86822944501Smrg    drm_version_t *version = drmMalloc(sizeof(*version));
86922944501Smrg
870424e9256Smrg    memclear(*version);
87122944501Smrg
87222944501Smrg    if (drmIoctl(fd, DRM_IOCTL_VERSION, version)) {
873fe517fc9Smrg        drmFreeKernelVersion(version);
874fe517fc9Smrg        return NULL;
87522944501Smrg    }
87622944501Smrg
87722944501Smrg    if (version->name_len)
878fe517fc9Smrg        version->name    = drmMalloc(version->name_len + 1);
87922944501Smrg    if (version->date_len)
880fe517fc9Smrg        version->date    = drmMalloc(version->date_len + 1);
88122944501Smrg    if (version->desc_len)
882fe517fc9Smrg        version->desc    = drmMalloc(version->desc_len + 1);
88322944501Smrg
88422944501Smrg    if (drmIoctl(fd, DRM_IOCTL_VERSION, version)) {
885fe517fc9Smrg        drmMsg("DRM_IOCTL_VERSION: %s\n", strerror(errno));
886fe517fc9Smrg        drmFreeKernelVersion(version);
887fe517fc9Smrg        return NULL;
88822944501Smrg    }
88922944501Smrg
89022944501Smrg    /* The results might not be null-terminated strings, so terminate them. */
89122944501Smrg    if (version->name_len) version->name[version->name_len] = '\0';
89222944501Smrg    if (version->date_len) version->date[version->date_len] = '\0';
89322944501Smrg    if (version->desc_len) version->desc[version->desc_len] = '\0';
89422944501Smrg
89522944501Smrg    retval = drmMalloc(sizeof(*retval));
89622944501Smrg    drmCopyVersion(retval, version);
89722944501Smrg    drmFreeKernelVersion(version);
89822944501Smrg    return retval;
89922944501Smrg}
90022944501Smrg
90122944501Smrg
90222944501Smrg/**
90322944501Smrg * Get version information for the DRM user space library.
904fe517fc9Smrg *
90522944501Smrg * This version number is driver independent.
906fe517fc9Smrg *
90722944501Smrg * \param fd file descriptor.
90822944501Smrg *
90922944501Smrg * \return version information.
910fe517fc9Smrg *
91122944501Smrg * \internal
91222944501Smrg * This function allocates and fills a drm_version structure with a hard coded
91322944501Smrg * version number.
91422944501Smrg */
91522944501SmrgdrmVersionPtr drmGetLibVersion(int fd)
91622944501Smrg{
91722944501Smrg    drm_version_t *version = drmMalloc(sizeof(*version));
91822944501Smrg
91922944501Smrg    /* Version history:
92022944501Smrg     *   NOTE THIS MUST NOT GO ABOVE VERSION 1.X due to drivers needing it
92122944501Smrg     *   revision 1.0.x = original DRM interface with no drmGetLibVersion
92222944501Smrg     *                    entry point and many drm<Device> extensions
92322944501Smrg     *   revision 1.1.x = added drmCommand entry points for device extensions
92422944501Smrg     *                    added drmGetLibVersion to identify libdrm.a version
92522944501Smrg     *   revision 1.2.x = added drmSetInterfaceVersion
92622944501Smrg     *                    modified drmOpen to handle both busid and name
92722944501Smrg     *   revision 1.3.x = added server + memory manager
92822944501Smrg     */
92922944501Smrg    version->version_major      = 1;
93022944501Smrg    version->version_minor      = 3;
93122944501Smrg    version->version_patchlevel = 0;
93222944501Smrg
93322944501Smrg    return (drmVersionPtr)version;
93422944501Smrg}
93522944501Smrg
93620131375Smrgint drmGetCap(int fd, uint64_t capability, uint64_t *value)
93720131375Smrg{
938fe517fc9Smrg    struct drm_get_cap cap;
939fe517fc9Smrg    int ret;
94020131375Smrg
941fe517fc9Smrg    memclear(cap);
942fe517fc9Smrg    cap.capability = capability;
943424e9256Smrg
944fe517fc9Smrg    ret = drmIoctl(fd, DRM_IOCTL_GET_CAP, &cap);
945fe517fc9Smrg    if (ret)
946fe517fc9Smrg        return ret;
94720131375Smrg
948fe517fc9Smrg    *value = cap.value;
949fe517fc9Smrg    return 0;
95020131375Smrg}
95120131375Smrg
95220131375Smrgint drmSetClientCap(int fd, uint64_t capability, uint64_t value)
95320131375Smrg{
954fe517fc9Smrg    struct drm_set_client_cap cap;
955424e9256Smrg
956fe517fc9Smrg    memclear(cap);
957fe517fc9Smrg    cap.capability = capability;
958fe517fc9Smrg    cap.value = value;
95920131375Smrg
960fe517fc9Smrg    return drmIoctl(fd, DRM_IOCTL_SET_CLIENT_CAP, &cap);
96120131375Smrg}
96222944501Smrg
96322944501Smrg/**
96422944501Smrg * Free the bus ID information.
96522944501Smrg *
96622944501Smrg * \param busid bus ID information string as given by drmGetBusid().
96722944501Smrg *
96822944501Smrg * \internal
96922944501Smrg * This function is just frees the memory pointed by \p busid.
97022944501Smrg */
97122944501Smrgvoid drmFreeBusid(const char *busid)
97222944501Smrg{
97322944501Smrg    drmFree((void *)busid);
97422944501Smrg}
97522944501Smrg
97622944501Smrg
97722944501Smrg/**
97822944501Smrg * Get the bus ID of the device.
97922944501Smrg *
98022944501Smrg * \param fd file descriptor.
98122944501Smrg *
98222944501Smrg * \return bus ID string.
98322944501Smrg *
98422944501Smrg * \internal
98522944501Smrg * This function gets the bus ID via successive DRM_IOCTL_GET_UNIQUE ioctls to
98622944501Smrg * get the string length and data, passing the arguments in a drm_unique
98722944501Smrg * structure.
98822944501Smrg */
98922944501Smrgchar *drmGetBusid(int fd)
99022944501Smrg{
99122944501Smrg    drm_unique_t u;
99222944501Smrg
993424e9256Smrg    memclear(u);
99422944501Smrg
99522944501Smrg    if (drmIoctl(fd, DRM_IOCTL_GET_UNIQUE, &u))
996fe517fc9Smrg        return NULL;
99722944501Smrg    u.unique = drmMalloc(u.unique_len + 1);
99822944501Smrg    if (drmIoctl(fd, DRM_IOCTL_GET_UNIQUE, &u))
999fe517fc9Smrg        return NULL;
100022944501Smrg    u.unique[u.unique_len] = '\0';
100122944501Smrg
100222944501Smrg    return u.unique;
100322944501Smrg}
100422944501Smrg
100522944501Smrg
100622944501Smrg/**
100722944501Smrg * Set the bus ID of the device.
100822944501Smrg *
100922944501Smrg * \param fd file descriptor.
101022944501Smrg * \param busid bus ID string.
101122944501Smrg *
101222944501Smrg * \return zero on success, negative on failure.
101322944501Smrg *
101422944501Smrg * \internal
101522944501Smrg * This function is a wrapper around the DRM_IOCTL_SET_UNIQUE ioctl, passing
101622944501Smrg * the arguments in a drm_unique structure.
101722944501Smrg */
101822944501Smrgint drmSetBusid(int fd, const char *busid)
101922944501Smrg{
102022944501Smrg    drm_unique_t u;
102122944501Smrg
1022424e9256Smrg    memclear(u);
102322944501Smrg    u.unique     = (char *)busid;
102422944501Smrg    u.unique_len = strlen(busid);
102522944501Smrg
102622944501Smrg    if (drmIoctl(fd, DRM_IOCTL_SET_UNIQUE, &u)) {
1027fe517fc9Smrg        return -errno;
102822944501Smrg    }
102922944501Smrg    return 0;
103022944501Smrg}
103122944501Smrg
103222944501Smrgint drmGetMagic(int fd, drm_magic_t * magic)
103322944501Smrg{
103422944501Smrg    drm_auth_t auth;
103522944501Smrg
1036424e9256Smrg    memclear(auth);
1037424e9256Smrg
103822944501Smrg    *magic = 0;
103922944501Smrg    if (drmIoctl(fd, DRM_IOCTL_GET_MAGIC, &auth))
1040fe517fc9Smrg        return -errno;
104122944501Smrg    *magic = auth.magic;
104222944501Smrg    return 0;
104322944501Smrg}
104422944501Smrg
104522944501Smrgint drmAuthMagic(int fd, drm_magic_t magic)
104622944501Smrg{
104722944501Smrg    drm_auth_t auth;
104822944501Smrg
1049424e9256Smrg    memclear(auth);
105022944501Smrg    auth.magic = magic;
105122944501Smrg    if (drmIoctl(fd, DRM_IOCTL_AUTH_MAGIC, &auth))
1052fe517fc9Smrg        return -errno;
105322944501Smrg    return 0;
105422944501Smrg}
105522944501Smrg
105622944501Smrg/**
105722944501Smrg * Specifies a range of memory that is available for mapping by a
105822944501Smrg * non-root process.
105922944501Smrg *
106022944501Smrg * \param fd file descriptor.
106122944501Smrg * \param offset usually the physical address. The actual meaning depends of
106222944501Smrg * the \p type parameter. See below.
106322944501Smrg * \param size of the memory in bytes.
106422944501Smrg * \param type type of the memory to be mapped.
106522944501Smrg * \param flags combination of several flags to modify the function actions.
106622944501Smrg * \param handle will be set to a value that may be used as the offset
106722944501Smrg * parameter for mmap().
1068fe517fc9Smrg *
106922944501Smrg * \return zero on success or a negative value on error.
107022944501Smrg *
107122944501Smrg * \par Mapping the frame buffer
107222944501Smrg * For the frame buffer
107322944501Smrg * - \p offset will be the physical address of the start of the frame buffer,
107422944501Smrg * - \p size will be the size of the frame buffer in bytes, and
107522944501Smrg * - \p type will be DRM_FRAME_BUFFER.
107622944501Smrg *
107722944501Smrg * \par
107822944501Smrg * The area mapped will be uncached. If MTRR support is available in the
1079fe517fc9Smrg * kernel, the frame buffer area will be set to write combining.
108022944501Smrg *
108122944501Smrg * \par Mapping the MMIO register area
108222944501Smrg * For the MMIO register area,
108322944501Smrg * - \p offset will be the physical address of the start of the register area,
108422944501Smrg * - \p size will be the size of the register area bytes, and
108522944501Smrg * - \p type will be DRM_REGISTERS.
108622944501Smrg * \par
1087fe517fc9Smrg * The area mapped will be uncached.
1088fe517fc9Smrg *
108922944501Smrg * \par Mapping the SAREA
109022944501Smrg * For the SAREA,
109122944501Smrg * - \p offset will be ignored and should be set to zero,
109222944501Smrg * - \p size will be the desired size of the SAREA in bytes,
109322944501Smrg * - \p type will be DRM_SHM.
1094fe517fc9Smrg *
109522944501Smrg * \par
109622944501Smrg * A shared memory area of the requested size will be created and locked in
109722944501Smrg * kernel memory. This area may be mapped into client-space by using the handle
1098fe517fc9Smrg * returned.
1099fe517fc9Smrg *
110022944501Smrg * \note May only be called by root.
110122944501Smrg *
110222944501Smrg * \internal
110322944501Smrg * This function is a wrapper around the DRM_IOCTL_ADD_MAP ioctl, passing
110422944501Smrg * the arguments in a drm_map structure.
110522944501Smrg */
110622944501Smrgint drmAddMap(int fd, drm_handle_t offset, drmSize size, drmMapType type,
1107fe517fc9Smrg              drmMapFlags flags, drm_handle_t *handle)
110822944501Smrg{
110922944501Smrg    drm_map_t map;
111022944501Smrg
1111424e9256Smrg    memclear(map);
111222944501Smrg    map.offset  = offset;
111322944501Smrg    map.size    = size;
111422944501Smrg    map.type    = type;
111522944501Smrg    map.flags   = flags;
111622944501Smrg    if (drmIoctl(fd, DRM_IOCTL_ADD_MAP, &map))
1117fe517fc9Smrg        return -errno;
111822944501Smrg    if (handle)
1119fe517fc9Smrg        *handle = (drm_handle_t)(uintptr_t)map.handle;
112022944501Smrg    return 0;
112122944501Smrg}
112222944501Smrg
112322944501Smrgint drmRmMap(int fd, drm_handle_t handle)
112422944501Smrg{
112522944501Smrg    drm_map_t map;
112622944501Smrg
1127424e9256Smrg    memclear(map);
112820131375Smrg    map.handle = (void *)(uintptr_t)handle;
112922944501Smrg
113022944501Smrg    if(drmIoctl(fd, DRM_IOCTL_RM_MAP, &map))
1131fe517fc9Smrg        return -errno;
113222944501Smrg    return 0;
113322944501Smrg}
113422944501Smrg
113522944501Smrg/**
113622944501Smrg * Make buffers available for DMA transfers.
1137fe517fc9Smrg *
113822944501Smrg * \param fd file descriptor.
113922944501Smrg * \param count number of buffers.
114022944501Smrg * \param size size of each buffer.
114122944501Smrg * \param flags buffer allocation flags.
1142fe517fc9Smrg * \param agp_offset offset in the AGP aperture
114322944501Smrg *
114422944501Smrg * \return number of buffers allocated, negative on error.
114522944501Smrg *
114622944501Smrg * \internal
114722944501Smrg * This function is a wrapper around DRM_IOCTL_ADD_BUFS ioctl.
114822944501Smrg *
114922944501Smrg * \sa drm_buf_desc.
115022944501Smrg */
115122944501Smrgint drmAddBufs(int fd, int count, int size, drmBufDescFlags flags,
1152fe517fc9Smrg               int agp_offset)
115322944501Smrg{
115422944501Smrg    drm_buf_desc_t request;
115522944501Smrg
1156424e9256Smrg    memclear(request);
115722944501Smrg    request.count     = count;
115822944501Smrg    request.size      = size;
115922944501Smrg    request.flags     = flags;
116022944501Smrg    request.agp_start = agp_offset;
116122944501Smrg
116222944501Smrg    if (drmIoctl(fd, DRM_IOCTL_ADD_BUFS, &request))
1163fe517fc9Smrg        return -errno;
116422944501Smrg    return request.count;
116522944501Smrg}
116622944501Smrg
116722944501Smrgint drmMarkBufs(int fd, double low, double high)
116822944501Smrg{
116922944501Smrg    drm_buf_info_t info;
117022944501Smrg    int            i;
117122944501Smrg
1172424e9256Smrg    memclear(info);
117322944501Smrg
117422944501Smrg    if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info))
1175fe517fc9Smrg        return -EINVAL;
117622944501Smrg
117722944501Smrg    if (!info.count)
1178fe517fc9Smrg        return -EINVAL;
117922944501Smrg
118022944501Smrg    if (!(info.list = drmMalloc(info.count * sizeof(*info.list))))
1181fe517fc9Smrg        return -ENOMEM;
118222944501Smrg
118322944501Smrg    if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info)) {
1184fe517fc9Smrg        int retval = -errno;
1185fe517fc9Smrg        drmFree(info.list);
1186fe517fc9Smrg        return retval;
118722944501Smrg    }
118822944501Smrg
118922944501Smrg    for (i = 0; i < info.count; i++) {
1190fe517fc9Smrg        info.list[i].low_mark  = low  * info.list[i].count;
1191fe517fc9Smrg        info.list[i].high_mark = high * info.list[i].count;
1192fe517fc9Smrg        if (drmIoctl(fd, DRM_IOCTL_MARK_BUFS, &info.list[i])) {
1193fe517fc9Smrg            int retval = -errno;
1194fe517fc9Smrg            drmFree(info.list);
1195fe517fc9Smrg            return retval;
1196fe517fc9Smrg        }
119722944501Smrg    }
119822944501Smrg    drmFree(info.list);
119922944501Smrg
120022944501Smrg    return 0;
120122944501Smrg}
120222944501Smrg
120322944501Smrg/**
120422944501Smrg * Free buffers.
120522944501Smrg *
120622944501Smrg * \param fd file descriptor.
120722944501Smrg * \param count number of buffers to free.
120822944501Smrg * \param list list of buffers to be freed.
120922944501Smrg *
121022944501Smrg * \return zero on success, or a negative value on failure.
1211fe517fc9Smrg *
121222944501Smrg * \note This function is primarily used for debugging.
1213fe517fc9Smrg *
121422944501Smrg * \internal
121522944501Smrg * This function is a wrapper around the DRM_IOCTL_FREE_BUFS ioctl, passing
121622944501Smrg * the arguments in a drm_buf_free structure.
121722944501Smrg */
121822944501Smrgint drmFreeBufs(int fd, int count, int *list)
121922944501Smrg{
122022944501Smrg    drm_buf_free_t request;
122122944501Smrg
1222424e9256Smrg    memclear(request);
122322944501Smrg    request.count = count;
122422944501Smrg    request.list  = list;
122522944501Smrg    if (drmIoctl(fd, DRM_IOCTL_FREE_BUFS, &request))
1226fe517fc9Smrg        return -errno;
122722944501Smrg    return 0;
122822944501Smrg}
122922944501Smrg
123022944501Smrg
123122944501Smrg/**
123222944501Smrg * Close the device.
123322944501Smrg *
123422944501Smrg * \param fd file descriptor.
123522944501Smrg *
123622944501Smrg * \internal
123722944501Smrg * This function closes the file descriptor.
123822944501Smrg */
123922944501Smrgint drmClose(int fd)
124022944501Smrg{
124122944501Smrg    unsigned long key    = drmGetKeyFromFd(fd);
124222944501Smrg    drmHashEntry  *entry = drmGetEntry(fd);
124322944501Smrg
124422944501Smrg    drmHashDestroy(entry->tagTable);
124522944501Smrg    entry->fd       = 0;
124622944501Smrg    entry->f        = NULL;
124722944501Smrg    entry->tagTable = NULL;
124822944501Smrg
124922944501Smrg    drmHashDelete(drmHashTable, key);
125022944501Smrg    drmFree(entry);
125122944501Smrg
125222944501Smrg    return close(fd);
125322944501Smrg}
125422944501Smrg
125522944501Smrg
125622944501Smrg/**
125722944501Smrg * Map a region of memory.
125822944501Smrg *
125922944501Smrg * \param fd file descriptor.
126022944501Smrg * \param handle handle returned by drmAddMap().
126122944501Smrg * \param size size in bytes. Must match the size used by drmAddMap().
126222944501Smrg * \param address will contain the user-space virtual address where the mapping
126322944501Smrg * begins.
126422944501Smrg *
126522944501Smrg * \return zero on success, or a negative value on failure.
1266fe517fc9Smrg *
126722944501Smrg * \internal
126822944501Smrg * This function is a wrapper for mmap().
126922944501Smrg */
127022944501Smrgint drmMap(int fd, drm_handle_t handle, drmSize size, drmAddressPtr address)
127122944501Smrg{
127222944501Smrg    static unsigned long pagesize_mask = 0;
127322944501Smrg
127422944501Smrg    if (fd < 0)
1275fe517fc9Smrg        return -EINVAL;
127622944501Smrg
127722944501Smrg    if (!pagesize_mask)
1278fe517fc9Smrg        pagesize_mask = getpagesize() - 1;
127922944501Smrg
128022944501Smrg    size = (size + pagesize_mask) & ~pagesize_mask;
128122944501Smrg
1282a884aba1Smrg    *address = drm_mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, handle);
128322944501Smrg    if (*address == MAP_FAILED)
1284fe517fc9Smrg        return -errno;
128522944501Smrg    return 0;
128622944501Smrg}
128722944501Smrg
128822944501Smrg
128922944501Smrg/**
129022944501Smrg * Unmap mappings obtained with drmMap().
129122944501Smrg *
129222944501Smrg * \param address address as given by drmMap().
129322944501Smrg * \param size size in bytes. Must match the size used by drmMap().
1294fe517fc9Smrg *
129522944501Smrg * \return zero on success, or a negative value on failure.
129622944501Smrg *
129722944501Smrg * \internal
129822944501Smrg * This function is a wrapper for munmap().
129922944501Smrg */
130022944501Smrgint drmUnmap(drmAddress address, drmSize size)
130122944501Smrg{
1302a884aba1Smrg    return drm_munmap(address, size);
130322944501Smrg}
130422944501Smrg
130522944501SmrgdrmBufInfoPtr drmGetBufInfo(int fd)
130622944501Smrg{
130722944501Smrg    drm_buf_info_t info;
130822944501Smrg    drmBufInfoPtr  retval;
130922944501Smrg    int            i;
131022944501Smrg
1311424e9256Smrg    memclear(info);
131222944501Smrg
131322944501Smrg    if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info))
1314fe517fc9Smrg        return NULL;
131522944501Smrg
131622944501Smrg    if (info.count) {
1317fe517fc9Smrg        if (!(info.list = drmMalloc(info.count * sizeof(*info.list))))
1318fe517fc9Smrg            return NULL;
1319fe517fc9Smrg
1320fe517fc9Smrg        if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info)) {
1321fe517fc9Smrg            drmFree(info.list);
1322fe517fc9Smrg            return NULL;
1323fe517fc9Smrg        }
1324fe517fc9Smrg
1325fe517fc9Smrg        retval = drmMalloc(sizeof(*retval));
1326fe517fc9Smrg        retval->count = info.count;
1327fe517fc9Smrg        retval->list  = drmMalloc(info.count * sizeof(*retval->list));
1328fe517fc9Smrg        for (i = 0; i < info.count; i++) {
1329fe517fc9Smrg            retval->list[i].count     = info.list[i].count;
1330fe517fc9Smrg            retval->list[i].size      = info.list[i].size;
1331fe517fc9Smrg            retval->list[i].low_mark  = info.list[i].low_mark;
1332fe517fc9Smrg            retval->list[i].high_mark = info.list[i].high_mark;
1333fe517fc9Smrg        }
1334fe517fc9Smrg        drmFree(info.list);
1335fe517fc9Smrg        return retval;
133622944501Smrg    }
133722944501Smrg    return NULL;
133822944501Smrg}
133922944501Smrg
134022944501Smrg/**
134122944501Smrg * Map all DMA buffers into client-virtual space.
134222944501Smrg *
134322944501Smrg * \param fd file descriptor.
134422944501Smrg *
134522944501Smrg * \return a pointer to a ::drmBufMap structure.
134622944501Smrg *
134722944501Smrg * \note The client may not use these buffers until obtaining buffer indices
134822944501Smrg * with drmDMA().
1349fe517fc9Smrg *
135022944501Smrg * \internal
135122944501Smrg * This function calls the DRM_IOCTL_MAP_BUFS ioctl and copies the returned
135222944501Smrg * information about the buffers in a drm_buf_map structure into the
135322944501Smrg * client-visible data structures.
1354fe517fc9Smrg */
135522944501SmrgdrmBufMapPtr drmMapBufs(int fd)
135622944501Smrg{
135722944501Smrg    drm_buf_map_t bufs;
135822944501Smrg    drmBufMapPtr  retval;
135922944501Smrg    int           i;
136022944501Smrg
1361424e9256Smrg    memclear(bufs);
136222944501Smrg    if (drmIoctl(fd, DRM_IOCTL_MAP_BUFS, &bufs))
1363fe517fc9Smrg        return NULL;
136422944501Smrg
136522944501Smrg    if (!bufs.count)
1366fe517fc9Smrg        return NULL;
136722944501Smrg
1368fe517fc9Smrg    if (!(bufs.list = drmMalloc(bufs.count * sizeof(*bufs.list))))
1369fe517fc9Smrg        return NULL;
137022944501Smrg
1371fe517fc9Smrg    if (drmIoctl(fd, DRM_IOCTL_MAP_BUFS, &bufs)) {
1372fe517fc9Smrg        drmFree(bufs.list);
1373fe517fc9Smrg        return NULL;
1374fe517fc9Smrg    }
137522944501Smrg
1376fe517fc9Smrg    retval = drmMalloc(sizeof(*retval));
1377fe517fc9Smrg    retval->count = bufs.count;
1378fe517fc9Smrg    retval->list  = drmMalloc(bufs.count * sizeof(*retval->list));
1379fe517fc9Smrg    for (i = 0; i < bufs.count; i++) {
1380fe517fc9Smrg        retval->list[i].idx     = bufs.list[i].idx;
1381fe517fc9Smrg        retval->list[i].total   = bufs.list[i].total;
1382fe517fc9Smrg        retval->list[i].used    = 0;
1383fe517fc9Smrg        retval->list[i].address = bufs.list[i].address;
1384fe517fc9Smrg    }
138522944501Smrg
1386fe517fc9Smrg    drmFree(bufs.list);
1387fe517fc9Smrg    return retval;
138822944501Smrg}
138922944501Smrg
139022944501Smrg
139122944501Smrg/**
139222944501Smrg * Unmap buffers allocated with drmMapBufs().
139322944501Smrg *
139422944501Smrg * \return zero on success, or negative value on failure.
139522944501Smrg *
139622944501Smrg * \internal
139722944501Smrg * Calls munmap() for every buffer stored in \p bufs and frees the
139822944501Smrg * memory allocated by drmMapBufs().
139922944501Smrg */
140022944501Smrgint drmUnmapBufs(drmBufMapPtr bufs)
140122944501Smrg{
140222944501Smrg    int i;
140322944501Smrg
140422944501Smrg    for (i = 0; i < bufs->count; i++) {
1405fe517fc9Smrg        drm_munmap(bufs->list[i].address, bufs->list[i].total);
140622944501Smrg    }
140722944501Smrg
140822944501Smrg    drmFree(bufs->list);
140922944501Smrg    drmFree(bufs);
141022944501Smrg    return 0;
141122944501Smrg}
141222944501Smrg
141322944501Smrg
1414fe517fc9Smrg#define DRM_DMA_RETRY  16
141522944501Smrg
141622944501Smrg/**
141722944501Smrg * Reserve DMA buffers.
141822944501Smrg *
141922944501Smrg * \param fd file descriptor.
1420fe517fc9Smrg * \param request
1421fe517fc9Smrg *
142222944501Smrg * \return zero on success, or a negative value on failure.
142322944501Smrg *
142422944501Smrg * \internal
142522944501Smrg * Assemble the arguments into a drm_dma structure and keeps issuing the
142622944501Smrg * DRM_IOCTL_DMA ioctl until success or until maximum number of retries.
142722944501Smrg */
142822944501Smrgint drmDMA(int fd, drmDMAReqPtr request)
142922944501Smrg{
143022944501Smrg    drm_dma_t dma;
143122944501Smrg    int ret, i = 0;
143222944501Smrg
143322944501Smrg    dma.context         = request->context;
143422944501Smrg    dma.send_count      = request->send_count;
143522944501Smrg    dma.send_indices    = request->send_list;
143622944501Smrg    dma.send_sizes      = request->send_sizes;
143722944501Smrg    dma.flags           = request->flags;
143822944501Smrg    dma.request_count   = request->request_count;
143922944501Smrg    dma.request_size    = request->request_size;
144022944501Smrg    dma.request_indices = request->request_list;
144122944501Smrg    dma.request_sizes   = request->request_sizes;
144222944501Smrg    dma.granted_count   = 0;
144322944501Smrg
144422944501Smrg    do {
1445fe517fc9Smrg        ret = ioctl( fd, DRM_IOCTL_DMA, &dma );
144622944501Smrg    } while ( ret && errno == EAGAIN && i++ < DRM_DMA_RETRY );
144722944501Smrg
144822944501Smrg    if ( ret == 0 ) {
1449fe517fc9Smrg        request->granted_count = dma.granted_count;
1450fe517fc9Smrg        return 0;
145122944501Smrg    } else {
1452fe517fc9Smrg        return -errno;
145322944501Smrg    }
145422944501Smrg}
145522944501Smrg
145622944501Smrg
145722944501Smrg/**
145822944501Smrg * Obtain heavyweight hardware lock.
145922944501Smrg *
146022944501Smrg * \param fd file descriptor.
146122944501Smrg * \param context context.
146222944501Smrg * \param flags flags that determine the sate of the hardware when the function
146322944501Smrg * returns.
1464fe517fc9Smrg *
146522944501Smrg * \return always zero.
1466fe517fc9Smrg *
146722944501Smrg * \internal
146822944501Smrg * This function translates the arguments into a drm_lock structure and issue
146922944501Smrg * the DRM_IOCTL_LOCK ioctl until the lock is successfully acquired.
147022944501Smrg */
147122944501Smrgint drmGetLock(int fd, drm_context_t context, drmLockFlags flags)
147222944501Smrg{
147322944501Smrg    drm_lock_t lock;
147422944501Smrg
1475424e9256Smrg    memclear(lock);
147622944501Smrg    lock.context = context;
147722944501Smrg    lock.flags   = 0;
147822944501Smrg    if (flags & DRM_LOCK_READY)      lock.flags |= _DRM_LOCK_READY;
147922944501Smrg    if (flags & DRM_LOCK_QUIESCENT)  lock.flags |= _DRM_LOCK_QUIESCENT;
148022944501Smrg    if (flags & DRM_LOCK_FLUSH)      lock.flags |= _DRM_LOCK_FLUSH;
148122944501Smrg    if (flags & DRM_LOCK_FLUSH_ALL)  lock.flags |= _DRM_LOCK_FLUSH_ALL;
148222944501Smrg    if (flags & DRM_HALT_ALL_QUEUES) lock.flags |= _DRM_HALT_ALL_QUEUES;
148322944501Smrg    if (flags & DRM_HALT_CUR_QUEUES) lock.flags |= _DRM_HALT_CUR_QUEUES;
148422944501Smrg
148522944501Smrg    while (drmIoctl(fd, DRM_IOCTL_LOCK, &lock))
1486fe517fc9Smrg        ;
148722944501Smrg    return 0;
148822944501Smrg}
148922944501Smrg
149022944501Smrg/**
149122944501Smrg * Release the hardware lock.
149222944501Smrg *
149322944501Smrg * \param fd file descriptor.
149422944501Smrg * \param context context.
1495fe517fc9Smrg *
149622944501Smrg * \return zero on success, or a negative value on failure.
1497fe517fc9Smrg *
149822944501Smrg * \internal
149922944501Smrg * This function is a wrapper around the DRM_IOCTL_UNLOCK ioctl, passing the
150022944501Smrg * argument in a drm_lock structure.
150122944501Smrg */
150222944501Smrgint drmUnlock(int fd, drm_context_t context)
150322944501Smrg{
150422944501Smrg    drm_lock_t lock;
150522944501Smrg
1506424e9256Smrg    memclear(lock);
150722944501Smrg    lock.context = context;
150822944501Smrg    return drmIoctl(fd, DRM_IOCTL_UNLOCK, &lock);
150922944501Smrg}
151022944501Smrg
151122944501Smrgdrm_context_t *drmGetReservedContextList(int fd, int *count)
151222944501Smrg{
151322944501Smrg    drm_ctx_res_t res;
151422944501Smrg    drm_ctx_t     *list;
151522944501Smrg    drm_context_t * retval;
151622944501Smrg    int           i;
151722944501Smrg
1518424e9256Smrg    memclear(res);
151922944501Smrg    if (drmIoctl(fd, DRM_IOCTL_RES_CTX, &res))
1520fe517fc9Smrg        return NULL;
152122944501Smrg
152222944501Smrg    if (!res.count)
1523fe517fc9Smrg        return NULL;
152422944501Smrg
152522944501Smrg    if (!(list   = drmMalloc(res.count * sizeof(*list))))
1526fe517fc9Smrg        return NULL;
152722944501Smrg    if (!(retval = drmMalloc(res.count * sizeof(*retval)))) {
1528fe517fc9Smrg        drmFree(list);
1529fe517fc9Smrg        return NULL;
153022944501Smrg    }
153122944501Smrg
153222944501Smrg    res.contexts = list;
153322944501Smrg    if (drmIoctl(fd, DRM_IOCTL_RES_CTX, &res))
1534fe517fc9Smrg        return NULL;
153522944501Smrg
153622944501Smrg    for (i = 0; i < res.count; i++)
1537fe517fc9Smrg        retval[i] = list[i].handle;
153822944501Smrg    drmFree(list);
153922944501Smrg
154022944501Smrg    *count = res.count;
154122944501Smrg    return retval;
154222944501Smrg}
154322944501Smrg
154422944501Smrgvoid drmFreeReservedContextList(drm_context_t *pt)
154522944501Smrg{
154622944501Smrg    drmFree(pt);
154722944501Smrg}
154822944501Smrg
154922944501Smrg/**
155022944501Smrg * Create context.
155122944501Smrg *
155222944501Smrg * Used by the X server during GLXContext initialization. This causes
155322944501Smrg * per-context kernel-level resources to be allocated.
155422944501Smrg *
155522944501Smrg * \param fd file descriptor.
155622944501Smrg * \param handle is set on success. To be used by the client when requesting DMA
155722944501Smrg * dispatch with drmDMA().
1558fe517fc9Smrg *
155922944501Smrg * \return zero on success, or a negative value on failure.
1560fe517fc9Smrg *
156122944501Smrg * \note May only be called by root.
1562fe517fc9Smrg *
156322944501Smrg * \internal
156422944501Smrg * This function is a wrapper around the DRM_IOCTL_ADD_CTX ioctl, passing the
156522944501Smrg * argument in a drm_ctx structure.
156622944501Smrg */
156722944501Smrgint drmCreateContext(int fd, drm_context_t *handle)
156822944501Smrg{
156922944501Smrg    drm_ctx_t ctx;
157022944501Smrg
1571424e9256Smrg    memclear(ctx);
157222944501Smrg    if (drmIoctl(fd, DRM_IOCTL_ADD_CTX, &ctx))
1573fe517fc9Smrg        return -errno;
157422944501Smrg    *handle = ctx.handle;
157522944501Smrg    return 0;
157622944501Smrg}
157722944501Smrg
157822944501Smrgint drmSwitchToContext(int fd, drm_context_t context)
157922944501Smrg{
158022944501Smrg    drm_ctx_t ctx;
158122944501Smrg
1582424e9256Smrg    memclear(ctx);
158322944501Smrg    ctx.handle = context;
158422944501Smrg    if (drmIoctl(fd, DRM_IOCTL_SWITCH_CTX, &ctx))
1585fe517fc9Smrg        return -errno;
158622944501Smrg    return 0;
158722944501Smrg}
158822944501Smrg
158922944501Smrgint drmSetContextFlags(int fd, drm_context_t context, drm_context_tFlags flags)
159022944501Smrg{
159122944501Smrg    drm_ctx_t ctx;
159222944501Smrg
159322944501Smrg    /*
159422944501Smrg     * Context preserving means that no context switches are done between DMA
159522944501Smrg     * buffers from one context and the next.  This is suitable for use in the
159622944501Smrg     * X server (which promises to maintain hardware context), or in the
159722944501Smrg     * client-side library when buffers are swapped on behalf of two threads.
159822944501Smrg     */
1599424e9256Smrg    memclear(ctx);
160022944501Smrg    ctx.handle = context;
160122944501Smrg    if (flags & DRM_CONTEXT_PRESERVED)
1602fe517fc9Smrg        ctx.flags |= _DRM_CONTEXT_PRESERVED;
160322944501Smrg    if (flags & DRM_CONTEXT_2DONLY)
1604fe517fc9Smrg        ctx.flags |= _DRM_CONTEXT_2DONLY;
160522944501Smrg    if (drmIoctl(fd, DRM_IOCTL_MOD_CTX, &ctx))
1606fe517fc9Smrg        return -errno;
160722944501Smrg    return 0;
160822944501Smrg}
160922944501Smrg
161022944501Smrgint drmGetContextFlags(int fd, drm_context_t context,
161122944501Smrg                       drm_context_tFlagsPtr flags)
161222944501Smrg{
161322944501Smrg    drm_ctx_t ctx;
161422944501Smrg
1615424e9256Smrg    memclear(ctx);
161622944501Smrg    ctx.handle = context;
161722944501Smrg    if (drmIoctl(fd, DRM_IOCTL_GET_CTX, &ctx))
1618fe517fc9Smrg        return -errno;
161922944501Smrg    *flags = 0;
162022944501Smrg    if (ctx.flags & _DRM_CONTEXT_PRESERVED)
1621fe517fc9Smrg        *flags |= DRM_CONTEXT_PRESERVED;
162222944501Smrg    if (ctx.flags & _DRM_CONTEXT_2DONLY)
1623fe517fc9Smrg        *flags |= DRM_CONTEXT_2DONLY;
162422944501Smrg    return 0;
162522944501Smrg}
162622944501Smrg
162722944501Smrg/**
162822944501Smrg * Destroy context.
162922944501Smrg *
163022944501Smrg * Free any kernel-level resources allocated with drmCreateContext() associated
163122944501Smrg * with the context.
1632fe517fc9Smrg *
163322944501Smrg * \param fd file descriptor.
163422944501Smrg * \param handle handle given by drmCreateContext().
1635fe517fc9Smrg *
163622944501Smrg * \return zero on success, or a negative value on failure.
1637fe517fc9Smrg *
163822944501Smrg * \note May only be called by root.
1639fe517fc9Smrg *
164022944501Smrg * \internal
164122944501Smrg * This function is a wrapper around the DRM_IOCTL_RM_CTX ioctl, passing the
164222944501Smrg * argument in a drm_ctx structure.
164322944501Smrg */
164422944501Smrgint drmDestroyContext(int fd, drm_context_t handle)
164522944501Smrg{
164622944501Smrg    drm_ctx_t ctx;
1647424e9256Smrg
1648424e9256Smrg    memclear(ctx);
164922944501Smrg    ctx.handle = handle;
165022944501Smrg    if (drmIoctl(fd, DRM_IOCTL_RM_CTX, &ctx))
1651fe517fc9Smrg        return -errno;
165222944501Smrg    return 0;
165322944501Smrg}
165422944501Smrg
165522944501Smrgint drmCreateDrawable(int fd, drm_drawable_t *handle)
165622944501Smrg{
165722944501Smrg    drm_draw_t draw;
1658424e9256Smrg
1659424e9256Smrg    memclear(draw);
166022944501Smrg    if (drmIoctl(fd, DRM_IOCTL_ADD_DRAW, &draw))
1661fe517fc9Smrg        return -errno;
166222944501Smrg    *handle = draw.handle;
166322944501Smrg    return 0;
166422944501Smrg}
166522944501Smrg
166622944501Smrgint drmDestroyDrawable(int fd, drm_drawable_t handle)
166722944501Smrg{
166822944501Smrg    drm_draw_t draw;
1669424e9256Smrg
1670424e9256Smrg    memclear(draw);
167122944501Smrg    draw.handle = handle;
167222944501Smrg    if (drmIoctl(fd, DRM_IOCTL_RM_DRAW, &draw))
1673fe517fc9Smrg        return -errno;
167422944501Smrg    return 0;
167522944501Smrg}
167622944501Smrg
167722944501Smrgint drmUpdateDrawableInfo(int fd, drm_drawable_t handle,
1678fe517fc9Smrg                          drm_drawable_info_type_t type, unsigned int num,
1679fe517fc9Smrg                          void *data)
168022944501Smrg{
168122944501Smrg    drm_update_draw_t update;
168222944501Smrg
1683424e9256Smrg    memclear(update);
168422944501Smrg    update.handle = handle;
168522944501Smrg    update.type = type;
168622944501Smrg    update.num = num;
168722944501Smrg    update.data = (unsigned long long)(unsigned long)data;
168822944501Smrg
168922944501Smrg    if (drmIoctl(fd, DRM_IOCTL_UPDATE_DRAW, &update))
1690fe517fc9Smrg        return -errno;
169122944501Smrg
169222944501Smrg    return 0;
169322944501Smrg}
169422944501Smrg
169522944501Smrg/**
169622944501Smrg * Acquire the AGP device.
169722944501Smrg *
169822944501Smrg * Must be called before any of the other AGP related calls.
169922944501Smrg *
170022944501Smrg * \param fd file descriptor.
1701fe517fc9Smrg *
170222944501Smrg * \return zero on success, or a negative value on failure.
1703fe517fc9Smrg *
170422944501Smrg * \internal
170522944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_ACQUIRE ioctl.
170622944501Smrg */
170722944501Smrgint drmAgpAcquire(int fd)
170822944501Smrg{
170922944501Smrg    if (drmIoctl(fd, DRM_IOCTL_AGP_ACQUIRE, NULL))
1710fe517fc9Smrg        return -errno;
171122944501Smrg    return 0;
171222944501Smrg}
171322944501Smrg
171422944501Smrg
171522944501Smrg/**
171622944501Smrg * Release the AGP device.
171722944501Smrg *
171822944501Smrg * \param fd file descriptor.
1719fe517fc9Smrg *
172022944501Smrg * \return zero on success, or a negative value on failure.
1721fe517fc9Smrg *
172222944501Smrg * \internal
172322944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_RELEASE ioctl.
172422944501Smrg */
172522944501Smrgint drmAgpRelease(int fd)
172622944501Smrg{
172722944501Smrg    if (drmIoctl(fd, DRM_IOCTL_AGP_RELEASE, NULL))
1728fe517fc9Smrg        return -errno;
172922944501Smrg    return 0;
173022944501Smrg}
173122944501Smrg
173222944501Smrg
173322944501Smrg/**
173422944501Smrg * Set the AGP mode.
173522944501Smrg *
173622944501Smrg * \param fd file descriptor.
173722944501Smrg * \param mode AGP mode.
1738fe517fc9Smrg *
173922944501Smrg * \return zero on success, or a negative value on failure.
1740fe517fc9Smrg *
174122944501Smrg * \internal
174222944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_ENABLE ioctl, passing the
174322944501Smrg * argument in a drm_agp_mode structure.
174422944501Smrg */
174522944501Smrgint drmAgpEnable(int fd, unsigned long mode)
174622944501Smrg{
174722944501Smrg    drm_agp_mode_t m;
174822944501Smrg
1749424e9256Smrg    memclear(m);
175022944501Smrg    m.mode = mode;
175122944501Smrg    if (drmIoctl(fd, DRM_IOCTL_AGP_ENABLE, &m))
1752fe517fc9Smrg        return -errno;
175322944501Smrg    return 0;
175422944501Smrg}
175522944501Smrg
175622944501Smrg
175722944501Smrg/**
175822944501Smrg * Allocate a chunk of AGP memory.
175922944501Smrg *
176022944501Smrg * \param fd file descriptor.
176122944501Smrg * \param size requested memory size in bytes. Will be rounded to page boundary.
176222944501Smrg * \param type type of memory to allocate.
176322944501Smrg * \param address if not zero, will be set to the physical address of the
176422944501Smrg * allocated memory.
176522944501Smrg * \param handle on success will be set to a handle of the allocated memory.
1766fe517fc9Smrg *
176722944501Smrg * \return zero on success, or a negative value on failure.
1768fe517fc9Smrg *
176922944501Smrg * \internal
177022944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_ALLOC ioctl, passing the
177122944501Smrg * arguments in a drm_agp_buffer structure.
177222944501Smrg */
177322944501Smrgint drmAgpAlloc(int fd, unsigned long size, unsigned long type,
1774fe517fc9Smrg                unsigned long *address, drm_handle_t *handle)
177522944501Smrg{
177622944501Smrg    drm_agp_buffer_t b;
177722944501Smrg
1778424e9256Smrg    memclear(b);
177922944501Smrg    *handle = DRM_AGP_NO_HANDLE;
178022944501Smrg    b.size   = size;
178122944501Smrg    b.type   = type;
178222944501Smrg    if (drmIoctl(fd, DRM_IOCTL_AGP_ALLOC, &b))
1783fe517fc9Smrg        return -errno;
178422944501Smrg    if (address != 0UL)
1785fe517fc9Smrg        *address = b.physical;
178622944501Smrg    *handle = b.handle;
178722944501Smrg    return 0;
178822944501Smrg}
178922944501Smrg
179022944501Smrg
179122944501Smrg/**
179222944501Smrg * Free a chunk of AGP memory.
179322944501Smrg *
179422944501Smrg * \param fd file descriptor.
179522944501Smrg * \param handle handle to the allocated memory, as given by drmAgpAllocate().
1796fe517fc9Smrg *
179722944501Smrg * \return zero on success, or a negative value on failure.
1798fe517fc9Smrg *
179922944501Smrg * \internal
180022944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_FREE ioctl, passing the
180122944501Smrg * argument in a drm_agp_buffer structure.
180222944501Smrg */
180322944501Smrgint drmAgpFree(int fd, drm_handle_t handle)
180422944501Smrg{
180522944501Smrg    drm_agp_buffer_t b;
180622944501Smrg
1807424e9256Smrg    memclear(b);
180822944501Smrg    b.handle = handle;
180922944501Smrg    if (drmIoctl(fd, DRM_IOCTL_AGP_FREE, &b))
1810fe517fc9Smrg        return -errno;
181122944501Smrg    return 0;
181222944501Smrg}
181322944501Smrg
181422944501Smrg
181522944501Smrg/**
181622944501Smrg * Bind a chunk of AGP memory.
181722944501Smrg *
181822944501Smrg * \param fd file descriptor.
181922944501Smrg * \param handle handle to the allocated memory, as given by drmAgpAllocate().
182022944501Smrg * \param offset offset in bytes. It will round to page boundary.
1821fe517fc9Smrg *
182222944501Smrg * \return zero on success, or a negative value on failure.
1823fe517fc9Smrg *
182422944501Smrg * \internal
182522944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_BIND ioctl, passing the
182622944501Smrg * argument in a drm_agp_binding structure.
182722944501Smrg */
182822944501Smrgint drmAgpBind(int fd, drm_handle_t handle, unsigned long offset)
182922944501Smrg{
183022944501Smrg    drm_agp_binding_t b;
183122944501Smrg
1832424e9256Smrg    memclear(b);
183322944501Smrg    b.handle = handle;
183422944501Smrg    b.offset = offset;
183522944501Smrg    if (drmIoctl(fd, DRM_IOCTL_AGP_BIND, &b))
1836fe517fc9Smrg        return -errno;
183722944501Smrg    return 0;
183822944501Smrg}
183922944501Smrg
184022944501Smrg
184122944501Smrg/**
184222944501Smrg * Unbind a chunk of AGP memory.
184322944501Smrg *
184422944501Smrg * \param fd file descriptor.
184522944501Smrg * \param handle handle to the allocated memory, as given by drmAgpAllocate().
1846fe517fc9Smrg *
184722944501Smrg * \return zero on success, or a negative value on failure.
1848fe517fc9Smrg *
184922944501Smrg * \internal
185022944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_UNBIND ioctl, passing
185122944501Smrg * the argument in a drm_agp_binding structure.
185222944501Smrg */
185322944501Smrgint drmAgpUnbind(int fd, drm_handle_t handle)
185422944501Smrg{
185522944501Smrg    drm_agp_binding_t b;
185622944501Smrg
1857424e9256Smrg    memclear(b);
185822944501Smrg    b.handle = handle;
185922944501Smrg    if (drmIoctl(fd, DRM_IOCTL_AGP_UNBIND, &b))
1860fe517fc9Smrg        return -errno;
186122944501Smrg    return 0;
186222944501Smrg}
186322944501Smrg
186422944501Smrg
186522944501Smrg/**
186622944501Smrg * Get AGP driver major version number.
186722944501Smrg *
186822944501Smrg * \param fd file descriptor.
1869fe517fc9Smrg *
187022944501Smrg * \return major version number on success, or a negative value on failure..
1871fe517fc9Smrg *
187222944501Smrg * \internal
187322944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
187422944501Smrg * necessary information in a drm_agp_info structure.
187522944501Smrg */
187622944501Smrgint drmAgpVersionMajor(int fd)
187722944501Smrg{
187822944501Smrg    drm_agp_info_t i;
187922944501Smrg
1880424e9256Smrg    memclear(i);
1881424e9256Smrg
188222944501Smrg    if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
1883fe517fc9Smrg        return -errno;
188422944501Smrg    return i.agp_version_major;
188522944501Smrg}
188622944501Smrg
188722944501Smrg
188822944501Smrg/**
188922944501Smrg * Get AGP driver minor version number.
189022944501Smrg *
189122944501Smrg * \param fd file descriptor.
1892fe517fc9Smrg *
189322944501Smrg * \return minor version number on success, or a negative value on failure.
1894fe517fc9Smrg *
189522944501Smrg * \internal
189622944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
189722944501Smrg * necessary information in a drm_agp_info structure.
189822944501Smrg */
189922944501Smrgint drmAgpVersionMinor(int fd)
190022944501Smrg{
190122944501Smrg    drm_agp_info_t i;
190222944501Smrg
1903424e9256Smrg    memclear(i);
1904424e9256Smrg
190522944501Smrg    if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
1906fe517fc9Smrg        return -errno;
190722944501Smrg    return i.agp_version_minor;
190822944501Smrg}
190922944501Smrg
191022944501Smrg
191122944501Smrg/**
191222944501Smrg * Get AGP mode.
191322944501Smrg *
191422944501Smrg * \param fd file descriptor.
1915fe517fc9Smrg *
191622944501Smrg * \return mode on success, or zero on failure.
1917fe517fc9Smrg *
191822944501Smrg * \internal
191922944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
192022944501Smrg * necessary information in a drm_agp_info structure.
192122944501Smrg */
192222944501Smrgunsigned long drmAgpGetMode(int fd)
192322944501Smrg{
192422944501Smrg    drm_agp_info_t i;
192522944501Smrg
1926424e9256Smrg    memclear(i);
1927424e9256Smrg
192822944501Smrg    if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
1929fe517fc9Smrg        return 0;
193022944501Smrg    return i.mode;
193122944501Smrg}
193222944501Smrg
193322944501Smrg
193422944501Smrg/**
193522944501Smrg * Get AGP aperture base.
193622944501Smrg *
193722944501Smrg * \param fd file descriptor.
1938fe517fc9Smrg *
193922944501Smrg * \return aperture base on success, zero on failure.
1940fe517fc9Smrg *
194122944501Smrg * \internal
194222944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
194322944501Smrg * necessary information in a drm_agp_info structure.
194422944501Smrg */
194522944501Smrgunsigned long drmAgpBase(int fd)
194622944501Smrg{
194722944501Smrg    drm_agp_info_t i;
194822944501Smrg
1949424e9256Smrg    memclear(i);
1950424e9256Smrg
195122944501Smrg    if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
1952fe517fc9Smrg        return 0;
195322944501Smrg    return i.aperture_base;
195422944501Smrg}
195522944501Smrg
195622944501Smrg
195722944501Smrg/**
195822944501Smrg * Get AGP aperture size.
195922944501Smrg *
196022944501Smrg * \param fd file descriptor.
1961fe517fc9Smrg *
196222944501Smrg * \return aperture size on success, zero on failure.
1963fe517fc9Smrg *
196422944501Smrg * \internal
196522944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
196622944501Smrg * necessary information in a drm_agp_info structure.
196722944501Smrg */
196822944501Smrgunsigned long drmAgpSize(int fd)
196922944501Smrg{
197022944501Smrg    drm_agp_info_t i;
197122944501Smrg
1972424e9256Smrg    memclear(i);
1973424e9256Smrg
197422944501Smrg    if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
1975fe517fc9Smrg        return 0;
197622944501Smrg    return i.aperture_size;
197722944501Smrg}
197822944501Smrg
197922944501Smrg
198022944501Smrg/**
198122944501Smrg * Get used AGP memory.
198222944501Smrg *
198322944501Smrg * \param fd file descriptor.
1984fe517fc9Smrg *
198522944501Smrg * \return memory used on success, or zero on failure.
1986fe517fc9Smrg *
198722944501Smrg * \internal
198822944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
198922944501Smrg * necessary information in a drm_agp_info structure.
199022944501Smrg */
199122944501Smrgunsigned long drmAgpMemoryUsed(int fd)
199222944501Smrg{
199322944501Smrg    drm_agp_info_t i;
199422944501Smrg
1995424e9256Smrg    memclear(i);
1996424e9256Smrg
199722944501Smrg    if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
1998fe517fc9Smrg        return 0;
199922944501Smrg    return i.memory_used;
200022944501Smrg}
200122944501Smrg
200222944501Smrg
200322944501Smrg/**
200422944501Smrg * Get available AGP memory.
200522944501Smrg *
200622944501Smrg * \param fd file descriptor.
2007fe517fc9Smrg *
200822944501Smrg * \return memory available on success, or zero on failure.
2009fe517fc9Smrg *
201022944501Smrg * \internal
201122944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
201222944501Smrg * necessary information in a drm_agp_info structure.
201322944501Smrg */
201422944501Smrgunsigned long drmAgpMemoryAvail(int fd)
201522944501Smrg{
201622944501Smrg    drm_agp_info_t i;
201722944501Smrg
2018424e9256Smrg    memclear(i);
2019424e9256Smrg
202022944501Smrg    if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
2021fe517fc9Smrg        return 0;
202222944501Smrg    return i.memory_allowed;
202322944501Smrg}
202422944501Smrg
202522944501Smrg
202622944501Smrg/**
202722944501Smrg * Get hardware vendor ID.
202822944501Smrg *
202922944501Smrg * \param fd file descriptor.
2030fe517fc9Smrg *
203122944501Smrg * \return vendor ID on success, or zero on failure.
2032fe517fc9Smrg *
203322944501Smrg * \internal
203422944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
203522944501Smrg * necessary information in a drm_agp_info structure.
203622944501Smrg */
203722944501Smrgunsigned int drmAgpVendorId(int fd)
203822944501Smrg{
203922944501Smrg    drm_agp_info_t i;
204022944501Smrg
2041424e9256Smrg    memclear(i);
2042424e9256Smrg
204322944501Smrg    if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
2044fe517fc9Smrg        return 0;
204522944501Smrg    return i.id_vendor;
204622944501Smrg}
204722944501Smrg
204822944501Smrg
204922944501Smrg/**
205022944501Smrg * Get hardware device ID.
205122944501Smrg *
205222944501Smrg * \param fd file descriptor.
2053fe517fc9Smrg *
205422944501Smrg * \return zero on success, or zero on failure.
2055fe517fc9Smrg *
205622944501Smrg * \internal
205722944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
205822944501Smrg * necessary information in a drm_agp_info structure.
205922944501Smrg */
206022944501Smrgunsigned int drmAgpDeviceId(int fd)
206122944501Smrg{
206222944501Smrg    drm_agp_info_t i;
206322944501Smrg
2064424e9256Smrg    memclear(i);
2065424e9256Smrg
206622944501Smrg    if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
2067fe517fc9Smrg        return 0;
206822944501Smrg    return i.id_device;
206922944501Smrg}
207022944501Smrg
207122944501Smrgint drmScatterGatherAlloc(int fd, unsigned long size, drm_handle_t *handle)
207222944501Smrg{
207322944501Smrg    drm_scatter_gather_t sg;
207422944501Smrg
2075424e9256Smrg    memclear(sg);
2076424e9256Smrg
207722944501Smrg    *handle = 0;
207822944501Smrg    sg.size   = size;
207922944501Smrg    if (drmIoctl(fd, DRM_IOCTL_SG_ALLOC, &sg))
2080fe517fc9Smrg        return -errno;
208122944501Smrg    *handle = sg.handle;
208222944501Smrg    return 0;
208322944501Smrg}
208422944501Smrg
208522944501Smrgint drmScatterGatherFree(int fd, drm_handle_t handle)
208622944501Smrg{
208722944501Smrg    drm_scatter_gather_t sg;
208822944501Smrg
2089424e9256Smrg    memclear(sg);
209022944501Smrg    sg.handle = handle;
209122944501Smrg    if (drmIoctl(fd, DRM_IOCTL_SG_FREE, &sg))
2092fe517fc9Smrg        return -errno;
209322944501Smrg    return 0;
209422944501Smrg}
209522944501Smrg
209622944501Smrg/**
209722944501Smrg * Wait for VBLANK.
209822944501Smrg *
209922944501Smrg * \param fd file descriptor.
210022944501Smrg * \param vbl pointer to a drmVBlank structure.
2101fe517fc9Smrg *
210222944501Smrg * \return zero on success, or a negative value on failure.
2103fe517fc9Smrg *
210422944501Smrg * \internal
210522944501Smrg * This function is a wrapper around the DRM_IOCTL_WAIT_VBLANK ioctl.
210622944501Smrg */
210722944501Smrgint drmWaitVBlank(int fd, drmVBlankPtr vbl)
210822944501Smrg{
210922944501Smrg    struct timespec timeout, cur;
211022944501Smrg    int ret;
211122944501Smrg
211222944501Smrg    ret = clock_gettime(CLOCK_MONOTONIC, &timeout);
211322944501Smrg    if (ret < 0) {
2114fe517fc9Smrg        fprintf(stderr, "clock_gettime failed: %s\n", strerror(errno));
2115fe517fc9Smrg        goto out;
211622944501Smrg    }
211722944501Smrg    timeout.tv_sec++;
211822944501Smrg
211922944501Smrg    do {
212022944501Smrg       ret = ioctl(fd, DRM_IOCTL_WAIT_VBLANK, vbl);
212122944501Smrg       vbl->request.type &= ~DRM_VBLANK_RELATIVE;
212222944501Smrg       if (ret && errno == EINTR) {
2123fe517fc9Smrg           clock_gettime(CLOCK_MONOTONIC, &cur);
2124fe517fc9Smrg           /* Timeout after 1s */
2125fe517fc9Smrg           if (cur.tv_sec > timeout.tv_sec + 1 ||
2126fe517fc9Smrg               (cur.tv_sec == timeout.tv_sec && cur.tv_nsec >=
2127fe517fc9Smrg                timeout.tv_nsec)) {
2128fe517fc9Smrg                   errno = EBUSY;
2129fe517fc9Smrg                   ret = -1;
2130fe517fc9Smrg                   break;
2131fe517fc9Smrg           }
213222944501Smrg       }
213322944501Smrg    } while (ret && errno == EINTR);
213422944501Smrg
213522944501Smrgout:
213622944501Smrg    return ret;
213722944501Smrg}
213822944501Smrg
213922944501Smrgint drmError(int err, const char *label)
214022944501Smrg{
214122944501Smrg    switch (err) {
214222944501Smrg    case DRM_ERR_NO_DEVICE:
2143fe517fc9Smrg        fprintf(stderr, "%s: no device\n", label);
2144fe517fc9Smrg        break;
214522944501Smrg    case DRM_ERR_NO_ACCESS:
2146fe517fc9Smrg        fprintf(stderr, "%s: no access\n", label);
2147fe517fc9Smrg        break;
214822944501Smrg    case DRM_ERR_NOT_ROOT:
2149fe517fc9Smrg        fprintf(stderr, "%s: not root\n", label);
2150fe517fc9Smrg        break;
215122944501Smrg    case DRM_ERR_INVALID:
2152fe517fc9Smrg        fprintf(stderr, "%s: invalid args\n", label);
2153fe517fc9Smrg        break;
215422944501Smrg    default:
2155fe517fc9Smrg        if (err < 0)
2156fe517fc9Smrg            err = -err;
2157fe517fc9Smrg        fprintf( stderr, "%s: error %d (%s)\n", label, err, strerror(err) );
2158fe517fc9Smrg        break;
215922944501Smrg    }
216022944501Smrg
216122944501Smrg    return 1;
216222944501Smrg}
216322944501Smrg
216422944501Smrg/**
216522944501Smrg * Install IRQ handler.
216622944501Smrg *
216722944501Smrg * \param fd file descriptor.
216822944501Smrg * \param irq IRQ number.
2169fe517fc9Smrg *
217022944501Smrg * \return zero on success, or a negative value on failure.
2171fe517fc9Smrg *
217222944501Smrg * \internal
217322944501Smrg * This function is a wrapper around the DRM_IOCTL_CONTROL ioctl, passing the
217422944501Smrg * argument in a drm_control structure.
217522944501Smrg */
217622944501Smrgint drmCtlInstHandler(int fd, int irq)
217722944501Smrg{
217822944501Smrg    drm_control_t ctl;
217922944501Smrg
2180424e9256Smrg    memclear(ctl);
218122944501Smrg    ctl.func  = DRM_INST_HANDLER;
218222944501Smrg    ctl.irq   = irq;
218322944501Smrg    if (drmIoctl(fd, DRM_IOCTL_CONTROL, &ctl))
2184fe517fc9Smrg        return -errno;
218522944501Smrg    return 0;
218622944501Smrg}
218722944501Smrg
218822944501Smrg
218922944501Smrg/**
219022944501Smrg * Uninstall IRQ handler.
219122944501Smrg *
219222944501Smrg * \param fd file descriptor.
2193fe517fc9Smrg *
219422944501Smrg * \return zero on success, or a negative value on failure.
2195fe517fc9Smrg *
219622944501Smrg * \internal
219722944501Smrg * This function is a wrapper around the DRM_IOCTL_CONTROL ioctl, passing the
219822944501Smrg * argument in a drm_control structure.
219922944501Smrg */
220022944501Smrgint drmCtlUninstHandler(int fd)
220122944501Smrg{
220222944501Smrg    drm_control_t ctl;
220322944501Smrg
2204424e9256Smrg    memclear(ctl);
220522944501Smrg    ctl.func  = DRM_UNINST_HANDLER;
220622944501Smrg    ctl.irq   = 0;
220722944501Smrg    if (drmIoctl(fd, DRM_IOCTL_CONTROL, &ctl))
2208fe517fc9Smrg        return -errno;
220922944501Smrg    return 0;
221022944501Smrg}
221122944501Smrg
221222944501Smrgint drmFinish(int fd, int context, drmLockFlags flags)
221322944501Smrg{
221422944501Smrg    drm_lock_t lock;
221522944501Smrg
2216424e9256Smrg    memclear(lock);
221722944501Smrg    lock.context = context;
221822944501Smrg    if (flags & DRM_LOCK_READY)      lock.flags |= _DRM_LOCK_READY;
221922944501Smrg    if (flags & DRM_LOCK_QUIESCENT)  lock.flags |= _DRM_LOCK_QUIESCENT;
222022944501Smrg    if (flags & DRM_LOCK_FLUSH)      lock.flags |= _DRM_LOCK_FLUSH;
222122944501Smrg    if (flags & DRM_LOCK_FLUSH_ALL)  lock.flags |= _DRM_LOCK_FLUSH_ALL;
222222944501Smrg    if (flags & DRM_HALT_ALL_QUEUES) lock.flags |= _DRM_HALT_ALL_QUEUES;
222322944501Smrg    if (flags & DRM_HALT_CUR_QUEUES) lock.flags |= _DRM_HALT_CUR_QUEUES;
222422944501Smrg    if (drmIoctl(fd, DRM_IOCTL_FINISH, &lock))
2225fe517fc9Smrg        return -errno;
222622944501Smrg    return 0;
222722944501Smrg}
222822944501Smrg
222922944501Smrg/**
223022944501Smrg * Get IRQ from bus ID.
223122944501Smrg *
223222944501Smrg * \param fd file descriptor.
223322944501Smrg * \param busnum bus number.
223422944501Smrg * \param devnum device number.
223522944501Smrg * \param funcnum function number.
2236fe517fc9Smrg *
223722944501Smrg * \return IRQ number on success, or a negative value on failure.
2238fe517fc9Smrg *
223922944501Smrg * \internal
224022944501Smrg * This function is a wrapper around the DRM_IOCTL_IRQ_BUSID ioctl, passing the
224122944501Smrg * arguments in a drm_irq_busid structure.
224222944501Smrg */
224322944501Smrgint drmGetInterruptFromBusID(int fd, int busnum, int devnum, int funcnum)
224422944501Smrg{
224522944501Smrg    drm_irq_busid_t p;
224622944501Smrg
2247424e9256Smrg    memclear(p);
224822944501Smrg    p.busnum  = busnum;
224922944501Smrg    p.devnum  = devnum;
225022944501Smrg    p.funcnum = funcnum;
225122944501Smrg    if (drmIoctl(fd, DRM_IOCTL_IRQ_BUSID, &p))
2252fe517fc9Smrg        return -errno;
225322944501Smrg    return p.irq;
225422944501Smrg}
225522944501Smrg
225622944501Smrgint drmAddContextTag(int fd, drm_context_t context, void *tag)
225722944501Smrg{
225822944501Smrg    drmHashEntry  *entry = drmGetEntry(fd);
225922944501Smrg
226022944501Smrg    if (drmHashInsert(entry->tagTable, context, tag)) {
2261fe517fc9Smrg        drmHashDelete(entry->tagTable, context);
2262fe517fc9Smrg        drmHashInsert(entry->tagTable, context, tag);
226322944501Smrg    }
226422944501Smrg    return 0;
226522944501Smrg}
226622944501Smrg
226722944501Smrgint drmDelContextTag(int fd, drm_context_t context)
226822944501Smrg{
226922944501Smrg    drmHashEntry  *entry = drmGetEntry(fd);
227022944501Smrg
227122944501Smrg    return drmHashDelete(entry->tagTable, context);
227222944501Smrg}
227322944501Smrg
227422944501Smrgvoid *drmGetContextTag(int fd, drm_context_t context)
227522944501Smrg{
227622944501Smrg    drmHashEntry  *entry = drmGetEntry(fd);
227722944501Smrg    void          *value;
227822944501Smrg
227922944501Smrg    if (drmHashLookup(entry->tagTable, context, &value))
2280fe517fc9Smrg        return NULL;
228122944501Smrg
228222944501Smrg    return value;
228322944501Smrg}
228422944501Smrg
228522944501Smrgint drmAddContextPrivateMapping(int fd, drm_context_t ctx_id,
228622944501Smrg                                drm_handle_t handle)
228722944501Smrg{
228822944501Smrg    drm_ctx_priv_map_t map;
228922944501Smrg
2290424e9256Smrg    memclear(map);
229122944501Smrg    map.ctx_id = ctx_id;
229220131375Smrg    map.handle = (void *)(uintptr_t)handle;
229322944501Smrg
229422944501Smrg    if (drmIoctl(fd, DRM_IOCTL_SET_SAREA_CTX, &map))
2295fe517fc9Smrg        return -errno;
229622944501Smrg    return 0;
229722944501Smrg}
229822944501Smrg
229922944501Smrgint drmGetContextPrivateMapping(int fd, drm_context_t ctx_id,
230022944501Smrg                                drm_handle_t *handle)
230122944501Smrg{
230222944501Smrg    drm_ctx_priv_map_t map;
230322944501Smrg
2304424e9256Smrg    memclear(map);
230522944501Smrg    map.ctx_id = ctx_id;
230622944501Smrg
230722944501Smrg    if (drmIoctl(fd, DRM_IOCTL_GET_SAREA_CTX, &map))
2308fe517fc9Smrg        return -errno;
230922944501Smrg    if (handle)
2310fe517fc9Smrg        *handle = (drm_handle_t)(uintptr_t)map.handle;
231122944501Smrg
231222944501Smrg    return 0;
231322944501Smrg}
231422944501Smrg
231522944501Smrgint drmGetMap(int fd, int idx, drm_handle_t *offset, drmSize *size,
2316fe517fc9Smrg              drmMapType *type, drmMapFlags *flags, drm_handle_t *handle,
2317fe517fc9Smrg              int *mtrr)
231822944501Smrg{
231922944501Smrg    drm_map_t map;
232022944501Smrg
2321424e9256Smrg    memclear(map);
232222944501Smrg    map.offset = idx;
232322944501Smrg    if (drmIoctl(fd, DRM_IOCTL_GET_MAP, &map))
2324fe517fc9Smrg        return -errno;
232522944501Smrg    *offset = map.offset;
232622944501Smrg    *size   = map.size;
232722944501Smrg    *type   = map.type;
232822944501Smrg    *flags  = map.flags;
232922944501Smrg    *handle = (unsigned long)map.handle;
233022944501Smrg    *mtrr   = map.mtrr;
233122944501Smrg    return 0;
233222944501Smrg}
233322944501Smrg
233422944501Smrgint drmGetClient(int fd, int idx, int *auth, int *pid, int *uid,
2335fe517fc9Smrg                 unsigned long *magic, unsigned long *iocs)
233622944501Smrg{
233722944501Smrg    drm_client_t client;
233822944501Smrg
2339424e9256Smrg    memclear(client);
234022944501Smrg    client.idx = idx;
234122944501Smrg    if (drmIoctl(fd, DRM_IOCTL_GET_CLIENT, &client))
2342fe517fc9Smrg        return -errno;
234322944501Smrg    *auth      = client.auth;
234422944501Smrg    *pid       = client.pid;
234522944501Smrg    *uid       = client.uid;
234622944501Smrg    *magic     = client.magic;
234722944501Smrg    *iocs      = client.iocs;
234822944501Smrg    return 0;
234922944501Smrg}
235022944501Smrg
235122944501Smrgint drmGetStats(int fd, drmStatsT *stats)
235222944501Smrg{
235322944501Smrg    drm_stats_t s;
2354424e9256Smrg    unsigned    i;
235522944501Smrg
2356424e9256Smrg    memclear(s);
235722944501Smrg    if (drmIoctl(fd, DRM_IOCTL_GET_STATS, &s))
2358fe517fc9Smrg        return -errno;
235922944501Smrg
236022944501Smrg    stats->count = 0;
236122944501Smrg    memset(stats, 0, sizeof(*stats));
236222944501Smrg    if (s.count > sizeof(stats->data)/sizeof(stats->data[0]))
2363fe517fc9Smrg        return -1;
236422944501Smrg
236522944501Smrg#define SET_VALUE                              \
236622944501Smrg    stats->data[i].long_format = "%-20.20s";   \
236722944501Smrg    stats->data[i].rate_format = "%8.8s";      \
236822944501Smrg    stats->data[i].isvalue     = 1;            \
236922944501Smrg    stats->data[i].verbose     = 0
237022944501Smrg
237122944501Smrg#define SET_COUNT                              \
237222944501Smrg    stats->data[i].long_format = "%-20.20s";   \
237322944501Smrg    stats->data[i].rate_format = "%5.5s";      \
237422944501Smrg    stats->data[i].isvalue     = 0;            \
237522944501Smrg    stats->data[i].mult_names  = "kgm";        \
237622944501Smrg    stats->data[i].mult        = 1000;         \
237722944501Smrg    stats->data[i].verbose     = 0
237822944501Smrg
237922944501Smrg#define SET_BYTE                               \
238022944501Smrg    stats->data[i].long_format = "%-20.20s";   \
238122944501Smrg    stats->data[i].rate_format = "%5.5s";      \
238222944501Smrg    stats->data[i].isvalue     = 0;            \
238322944501Smrg    stats->data[i].mult_names  = "KGM";        \
238422944501Smrg    stats->data[i].mult        = 1024;         \
238522944501Smrg    stats->data[i].verbose     = 0
238622944501Smrg
238722944501Smrg
238822944501Smrg    stats->count = s.count;
238922944501Smrg    for (i = 0; i < s.count; i++) {
2390fe517fc9Smrg        stats->data[i].value = s.data[i].value;
2391fe517fc9Smrg        switch (s.data[i].type) {
2392fe517fc9Smrg        case _DRM_STAT_LOCK:
2393fe517fc9Smrg            stats->data[i].long_name = "Lock";
2394fe517fc9Smrg            stats->data[i].rate_name = "Lock";
2395fe517fc9Smrg            SET_VALUE;
2396fe517fc9Smrg            break;
2397fe517fc9Smrg        case _DRM_STAT_OPENS:
2398fe517fc9Smrg            stats->data[i].long_name = "Opens";
2399fe517fc9Smrg            stats->data[i].rate_name = "O";
2400fe517fc9Smrg            SET_COUNT;
2401fe517fc9Smrg            stats->data[i].verbose   = 1;
2402fe517fc9Smrg            break;
2403fe517fc9Smrg        case _DRM_STAT_CLOSES:
2404fe517fc9Smrg            stats->data[i].long_name = "Closes";
2405fe517fc9Smrg            stats->data[i].rate_name = "Lock";
2406fe517fc9Smrg            SET_COUNT;
2407fe517fc9Smrg            stats->data[i].verbose   = 1;
2408fe517fc9Smrg            break;
2409fe517fc9Smrg        case _DRM_STAT_IOCTLS:
2410fe517fc9Smrg            stats->data[i].long_name = "Ioctls";
2411fe517fc9Smrg            stats->data[i].rate_name = "Ioc/s";
2412fe517fc9Smrg            SET_COUNT;
2413fe517fc9Smrg            break;
2414fe517fc9Smrg        case _DRM_STAT_LOCKS:
2415fe517fc9Smrg            stats->data[i].long_name = "Locks";
2416fe517fc9Smrg            stats->data[i].rate_name = "Lck/s";
2417fe517fc9Smrg            SET_COUNT;
2418fe517fc9Smrg            break;
2419fe517fc9Smrg        case _DRM_STAT_UNLOCKS:
2420fe517fc9Smrg            stats->data[i].long_name = "Unlocks";
2421fe517fc9Smrg            stats->data[i].rate_name = "Unl/s";
2422fe517fc9Smrg            SET_COUNT;
2423fe517fc9Smrg            break;
2424fe517fc9Smrg        case _DRM_STAT_IRQ:
2425fe517fc9Smrg            stats->data[i].long_name = "IRQs";
2426fe517fc9Smrg            stats->data[i].rate_name = "IRQ/s";
2427fe517fc9Smrg            SET_COUNT;
2428fe517fc9Smrg            break;
2429fe517fc9Smrg        case _DRM_STAT_PRIMARY:
2430fe517fc9Smrg            stats->data[i].long_name = "Primary Bytes";
2431fe517fc9Smrg            stats->data[i].rate_name = "PB/s";
2432fe517fc9Smrg            SET_BYTE;
2433fe517fc9Smrg            break;
2434fe517fc9Smrg        case _DRM_STAT_SECONDARY:
2435fe517fc9Smrg            stats->data[i].long_name = "Secondary Bytes";
2436fe517fc9Smrg            stats->data[i].rate_name = "SB/s";
2437fe517fc9Smrg            SET_BYTE;
2438fe517fc9Smrg            break;
2439fe517fc9Smrg        case _DRM_STAT_DMA:
2440fe517fc9Smrg            stats->data[i].long_name = "DMA";
2441fe517fc9Smrg            stats->data[i].rate_name = "DMA/s";
2442fe517fc9Smrg            SET_COUNT;
2443fe517fc9Smrg            break;
2444fe517fc9Smrg        case _DRM_STAT_SPECIAL:
2445fe517fc9Smrg            stats->data[i].long_name = "Special DMA";
2446fe517fc9Smrg            stats->data[i].rate_name = "dma/s";
2447fe517fc9Smrg            SET_COUNT;
2448fe517fc9Smrg            break;
2449fe517fc9Smrg        case _DRM_STAT_MISSED:
2450fe517fc9Smrg            stats->data[i].long_name = "Miss";
2451fe517fc9Smrg            stats->data[i].rate_name = "Ms/s";
2452fe517fc9Smrg            SET_COUNT;
2453fe517fc9Smrg            break;
2454fe517fc9Smrg        case _DRM_STAT_VALUE:
2455fe517fc9Smrg            stats->data[i].long_name = "Value";
2456fe517fc9Smrg            stats->data[i].rate_name = "Value";
2457fe517fc9Smrg            SET_VALUE;
2458fe517fc9Smrg            break;
2459fe517fc9Smrg        case _DRM_STAT_BYTE:
2460fe517fc9Smrg            stats->data[i].long_name = "Bytes";
2461fe517fc9Smrg            stats->data[i].rate_name = "B/s";
2462fe517fc9Smrg            SET_BYTE;
2463fe517fc9Smrg            break;
2464fe517fc9Smrg        case _DRM_STAT_COUNT:
2465fe517fc9Smrg        default:
2466fe517fc9Smrg            stats->data[i].long_name = "Count";
2467fe517fc9Smrg            stats->data[i].rate_name = "Cnt/s";
2468fe517fc9Smrg            SET_COUNT;
2469fe517fc9Smrg            break;
2470fe517fc9Smrg        }
247122944501Smrg    }
247222944501Smrg    return 0;
247322944501Smrg}
247422944501Smrg
247522944501Smrg/**
247622944501Smrg * Issue a set-version ioctl.
247722944501Smrg *
247822944501Smrg * \param fd file descriptor.
2479fe517fc9Smrg * \param drmCommandIndex command index
248022944501Smrg * \param data source pointer of the data to be read and written.
248122944501Smrg * \param size size of the data to be read and written.
2482fe517fc9Smrg *
248322944501Smrg * \return zero on success, or a negative value on failure.
2484fe517fc9Smrg *
248522944501Smrg * \internal
2486fe517fc9Smrg * It issues a read-write ioctl given by
248722944501Smrg * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
248822944501Smrg */
248922944501Smrgint drmSetInterfaceVersion(int fd, drmSetVersion *version)
249022944501Smrg{
249122944501Smrg    int retcode = 0;
249222944501Smrg    drm_set_version_t sv;
249322944501Smrg
2494424e9256Smrg    memclear(sv);
249522944501Smrg    sv.drm_di_major = version->drm_di_major;
249622944501Smrg    sv.drm_di_minor = version->drm_di_minor;
249722944501Smrg    sv.drm_dd_major = version->drm_dd_major;
249822944501Smrg    sv.drm_dd_minor = version->drm_dd_minor;
249922944501Smrg
250022944501Smrg    if (drmIoctl(fd, DRM_IOCTL_SET_VERSION, &sv)) {
2501fe517fc9Smrg        retcode = -errno;
250222944501Smrg    }
250322944501Smrg
250422944501Smrg    version->drm_di_major = sv.drm_di_major;
250522944501Smrg    version->drm_di_minor = sv.drm_di_minor;
250622944501Smrg    version->drm_dd_major = sv.drm_dd_major;
250722944501Smrg    version->drm_dd_minor = sv.drm_dd_minor;
250822944501Smrg
250922944501Smrg    return retcode;
251022944501Smrg}
251122944501Smrg
251222944501Smrg/**
251322944501Smrg * Send a device-specific command.
251422944501Smrg *
251522944501Smrg * \param fd file descriptor.
2516fe517fc9Smrg * \param drmCommandIndex command index
2517fe517fc9Smrg *
251822944501Smrg * \return zero on success, or a negative value on failure.
2519fe517fc9Smrg *
252022944501Smrg * \internal
2521fe517fc9Smrg * It issues a ioctl given by
252222944501Smrg * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
252322944501Smrg */
252422944501Smrgint drmCommandNone(int fd, unsigned long drmCommandIndex)
252522944501Smrg{
252622944501Smrg    unsigned long request;
252722944501Smrg
252822944501Smrg    request = DRM_IO( DRM_COMMAND_BASE + drmCommandIndex);
252922944501Smrg
2530424e9256Smrg    if (drmIoctl(fd, request, NULL)) {
2531fe517fc9Smrg        return -errno;
253222944501Smrg    }
253322944501Smrg    return 0;
253422944501Smrg}
253522944501Smrg
253622944501Smrg
253722944501Smrg/**
253822944501Smrg * Send a device-specific read command.
253922944501Smrg *
254022944501Smrg * \param fd file descriptor.
2541fe517fc9Smrg * \param drmCommandIndex command index
254222944501Smrg * \param data destination pointer of the data to be read.
254322944501Smrg * \param size size of the data to be read.
2544fe517fc9Smrg *
254522944501Smrg * \return zero on success, or a negative value on failure.
254622944501Smrg *
254722944501Smrg * \internal
2548fe517fc9Smrg * It issues a read ioctl given by
254922944501Smrg * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
255022944501Smrg */
255122944501Smrgint drmCommandRead(int fd, unsigned long drmCommandIndex, void *data,
255222944501Smrg                   unsigned long size)
255322944501Smrg{
255422944501Smrg    unsigned long request;
255522944501Smrg
2556fe517fc9Smrg    request = DRM_IOC( DRM_IOC_READ, DRM_IOCTL_BASE,
2557fe517fc9Smrg        DRM_COMMAND_BASE + drmCommandIndex, size);
255822944501Smrg
255922944501Smrg    if (drmIoctl(fd, request, data)) {
2560fe517fc9Smrg        return -errno;
256122944501Smrg    }
256222944501Smrg    return 0;
256322944501Smrg}
256422944501Smrg
256522944501Smrg
256622944501Smrg/**
256722944501Smrg * Send a device-specific write command.
256822944501Smrg *
256922944501Smrg * \param fd file descriptor.
2570fe517fc9Smrg * \param drmCommandIndex command index
257122944501Smrg * \param data source pointer of the data to be written.
257222944501Smrg * \param size size of the data to be written.
2573fe517fc9Smrg *
257422944501Smrg * \return zero on success, or a negative value on failure.
2575fe517fc9Smrg *
257622944501Smrg * \internal
2577fe517fc9Smrg * It issues a write ioctl given by
257822944501Smrg * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
257922944501Smrg */
258022944501Smrgint drmCommandWrite(int fd, unsigned long drmCommandIndex, void *data,
258122944501Smrg                    unsigned long size)
258222944501Smrg{
258322944501Smrg    unsigned long request;
258422944501Smrg
2585fe517fc9Smrg    request = DRM_IOC( DRM_IOC_WRITE, DRM_IOCTL_BASE,
2586fe517fc9Smrg        DRM_COMMAND_BASE + drmCommandIndex, size);
258722944501Smrg
258822944501Smrg    if (drmIoctl(fd, request, data)) {
2589fe517fc9Smrg        return -errno;
259022944501Smrg    }
259122944501Smrg    return 0;
259222944501Smrg}
259322944501Smrg
259422944501Smrg
259522944501Smrg/**
259622944501Smrg * Send a device-specific read-write command.
259722944501Smrg *
259822944501Smrg * \param fd file descriptor.
2599fe517fc9Smrg * \param drmCommandIndex command index
260022944501Smrg * \param data source pointer of the data to be read and written.
260122944501Smrg * \param size size of the data to be read and written.
2602fe517fc9Smrg *
260322944501Smrg * \return zero on success, or a negative value on failure.
2604fe517fc9Smrg *
260522944501Smrg * \internal
2606fe517fc9Smrg * It issues a read-write ioctl given by
260722944501Smrg * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
260822944501Smrg */
260922944501Smrgint drmCommandWriteRead(int fd, unsigned long drmCommandIndex, void *data,
261022944501Smrg                        unsigned long size)
261122944501Smrg{
261222944501Smrg    unsigned long request;
261322944501Smrg
2614fe517fc9Smrg    request = DRM_IOC( DRM_IOC_READ|DRM_IOC_WRITE, DRM_IOCTL_BASE,
2615fe517fc9Smrg        DRM_COMMAND_BASE + drmCommandIndex, size);
261622944501Smrg
261722944501Smrg    if (drmIoctl(fd, request, data))
2618fe517fc9Smrg        return -errno;
261922944501Smrg    return 0;
262022944501Smrg}
262122944501Smrg
262222944501Smrg#define DRM_MAX_FDS 16
262322944501Smrgstatic struct {
262422944501Smrg    char *BusID;
262522944501Smrg    int fd;
262622944501Smrg    int refcount;
2627424e9256Smrg    int type;
262822944501Smrg} connection[DRM_MAX_FDS];
262922944501Smrg
263022944501Smrgstatic int nr_fds = 0;
263122944501Smrg
2632fe517fc9Smrgint drmOpenOnce(void *unused,
2633fe517fc9Smrg                const char *BusID,
2634fe517fc9Smrg                int *newlyopened)
2635424e9256Smrg{
2636424e9256Smrg    return drmOpenOnceWithType(BusID, newlyopened, DRM_NODE_PRIMARY);
2637424e9256Smrg}
2638424e9256Smrg
2639424e9256Smrgint drmOpenOnceWithType(const char *BusID, int *newlyopened, int type)
264022944501Smrg{
264122944501Smrg    int i;
264222944501Smrg    int fd;
2643fe517fc9Smrg
264422944501Smrg    for (i = 0; i < nr_fds; i++)
2645fe517fc9Smrg        if ((strcmp(BusID, connection[i].BusID) == 0) &&
2646fe517fc9Smrg            (connection[i].type == type)) {
2647fe517fc9Smrg            connection[i].refcount++;
2648fe517fc9Smrg            *newlyopened = 0;
2649fe517fc9Smrg            return connection[i].fd;
2650fe517fc9Smrg        }
265122944501Smrg
2652424e9256Smrg    fd = drmOpenWithType(NULL, BusID, type);
2653fe517fc9Smrg    if (fd < 0 || nr_fds == DRM_MAX_FDS)
2654fe517fc9Smrg        return fd;
2655fe517fc9Smrg
265622944501Smrg    connection[nr_fds].BusID = strdup(BusID);
265722944501Smrg    connection[nr_fds].fd = fd;
265822944501Smrg    connection[nr_fds].refcount = 1;
2659424e9256Smrg    connection[nr_fds].type = type;
266022944501Smrg    *newlyopened = 1;
266122944501Smrg
266222944501Smrg    if (0)
2663fe517fc9Smrg        fprintf(stderr, "saved connection %d for %s %d\n",
2664fe517fc9Smrg                nr_fds, connection[nr_fds].BusID,
2665fe517fc9Smrg                strcmp(BusID, connection[nr_fds].BusID));
266622944501Smrg
266722944501Smrg    nr_fds++;
266822944501Smrg
266922944501Smrg    return fd;
267022944501Smrg}
267122944501Smrg
267222944501Smrgvoid drmCloseOnce(int fd)
267322944501Smrg{
267422944501Smrg    int i;
267522944501Smrg
267622944501Smrg    for (i = 0; i < nr_fds; i++) {
2677fe517fc9Smrg        if (fd == connection[i].fd) {
2678fe517fc9Smrg            if (--connection[i].refcount == 0) {
2679fe517fc9Smrg                drmClose(connection[i].fd);
2680fe517fc9Smrg                free(connection[i].BusID);
2681fe517fc9Smrg
2682fe517fc9Smrg                if (i < --nr_fds)
2683fe517fc9Smrg                    connection[i] = connection[nr_fds];
2684fe517fc9Smrg
2685fe517fc9Smrg                return;
2686fe517fc9Smrg            }
2687fe517fc9Smrg        }
268822944501Smrg    }
268922944501Smrg}
269022944501Smrg
269122944501Smrgint drmSetMaster(int fd)
269222944501Smrg{
2693fe517fc9Smrg        return drmIoctl(fd, DRM_IOCTL_SET_MASTER, NULL);
269422944501Smrg}
269522944501Smrg
269622944501Smrgint drmDropMaster(int fd)
269722944501Smrg{
2698fe517fc9Smrg        return drmIoctl(fd, DRM_IOCTL_DROP_MASTER, NULL);
269922944501Smrg}
270022944501Smrg
270122944501Smrgchar *drmGetDeviceNameFromFd(int fd)
270222944501Smrg{
2703fe517fc9Smrg    char name[128];
2704fe517fc9Smrg    struct stat sbuf;
2705fe517fc9Smrg    dev_t d;
2706fe517fc9Smrg    int i;
270722944501Smrg
2708fe517fc9Smrg    /* The whole drmOpen thing is a fiasco and we need to find a way
2709fe517fc9Smrg     * back to just using open(2).  For now, however, lets just make
2710fe517fc9Smrg     * things worse with even more ad hoc directory walking code to
2711fe517fc9Smrg     * discover the device file name. */
271222944501Smrg
2713fe517fc9Smrg    fstat(fd, &sbuf);
2714fe517fc9Smrg    d = sbuf.st_rdev;
271522944501Smrg
2716fe517fc9Smrg    for (i = 0; i < DRM_MAX_MINOR; i++) {
2717fe517fc9Smrg        snprintf(name, sizeof name, DRM_DEV_NAME, DRM_DIR_NAME, i);
2718fe517fc9Smrg        if (stat(name, &sbuf) == 0 && sbuf.st_rdev == d)
2719fe517fc9Smrg            break;
2720fe517fc9Smrg    }
2721fe517fc9Smrg    if (i == DRM_MAX_MINOR)
2722fe517fc9Smrg        return NULL;
272322944501Smrg
2724fe517fc9Smrg    return strdup(name);
272522944501Smrg}
272620131375Smrg
2727424e9256Smrgint drmGetNodeTypeFromFd(int fd)
2728424e9256Smrg{
2729fe517fc9Smrg    struct stat sbuf;
2730fe517fc9Smrg    int maj, min, type;
2731424e9256Smrg
2732fe517fc9Smrg    if (fstat(fd, &sbuf))
2733fe517fc9Smrg        return -1;
2734424e9256Smrg
2735fe517fc9Smrg    maj = major(sbuf.st_rdev);
2736fe517fc9Smrg    min = minor(sbuf.st_rdev);
2737424e9256Smrg
2738fe517fc9Smrg    if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode)) {
2739fe517fc9Smrg        errno = EINVAL;
2740fe517fc9Smrg        return -1;
2741fe517fc9Smrg    }
2742424e9256Smrg
2743fe517fc9Smrg    type = drmGetMinorType(min);
2744fe517fc9Smrg    if (type == -1)
2745fe517fc9Smrg        errno = ENODEV;
2746fe517fc9Smrg    return type;
2747424e9256Smrg}
2748424e9256Smrg
274920131375Smrgint drmPrimeHandleToFD(int fd, uint32_t handle, uint32_t flags, int *prime_fd)
275020131375Smrg{
2751fe517fc9Smrg    struct drm_prime_handle args;
2752fe517fc9Smrg    int ret;
275320131375Smrg
2754fe517fc9Smrg    memclear(args);
2755fe517fc9Smrg    args.fd = -1;
2756fe517fc9Smrg    args.handle = handle;
2757fe517fc9Smrg    args.flags = flags;
2758fe517fc9Smrg    ret = drmIoctl(fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &args);
2759fe517fc9Smrg    if (ret)
2760fe517fc9Smrg        return ret;
276120131375Smrg
2762fe517fc9Smrg    *prime_fd = args.fd;
2763fe517fc9Smrg    return 0;
276420131375Smrg}
276520131375Smrg
276620131375Smrgint drmPrimeFDToHandle(int fd, int prime_fd, uint32_t *handle)
276720131375Smrg{
2768fe517fc9Smrg    struct drm_prime_handle args;
2769fe517fc9Smrg    int ret;
277020131375Smrg
2771fe517fc9Smrg    memclear(args);
2772fe517fc9Smrg    args.fd = prime_fd;
2773fe517fc9Smrg    ret = drmIoctl(fd, DRM_IOCTL_PRIME_FD_TO_HANDLE, &args);
2774fe517fc9Smrg    if (ret)
2775fe517fc9Smrg        return ret;
277620131375Smrg
2777fe517fc9Smrg    *handle = args.handle;
2778fe517fc9Smrg    return 0;
277920131375Smrg}
2780424e9256Smrg
2781424e9256Smrgstatic char *drmGetMinorNameForFD(int fd, int type)
2782424e9256Smrg{
2783424e9256Smrg#ifdef __linux__
2784fe517fc9Smrg    DIR *sysdir;
2785fe517fc9Smrg    struct dirent *pent, *ent;
2786fe517fc9Smrg    struct stat sbuf;
2787fe517fc9Smrg    const char *name = drmGetMinorName(type);
2788fe517fc9Smrg    int len;
2789fe517fc9Smrg    char dev_name[64], buf[64];
2790fe517fc9Smrg    long name_max;
2791fe517fc9Smrg    int maj, min;
2792fe517fc9Smrg
2793fe517fc9Smrg    if (!name)
2794fe517fc9Smrg        return NULL;
2795424e9256Smrg
2796fe517fc9Smrg    len = strlen(name);
2797424e9256Smrg
2798fe517fc9Smrg    if (fstat(fd, &sbuf))
2799fe517fc9Smrg        return NULL;
2800424e9256Smrg
2801fe517fc9Smrg    maj = major(sbuf.st_rdev);
2802fe517fc9Smrg    min = minor(sbuf.st_rdev);
2803424e9256Smrg
2804fe517fc9Smrg    if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode))
2805fe517fc9Smrg        return NULL;
2806424e9256Smrg
2807fe517fc9Smrg    snprintf(buf, sizeof(buf), "/sys/dev/char/%d:%d/device/drm", maj, min);
2808424e9256Smrg
2809fe517fc9Smrg    sysdir = opendir(buf);
2810fe517fc9Smrg    if (!sysdir)
2811fe517fc9Smrg        return NULL;
2812424e9256Smrg
2813fe517fc9Smrg    name_max = fpathconf(dirfd(sysdir), _PC_NAME_MAX);
2814fe517fc9Smrg    if (name_max == -1)
2815fe517fc9Smrg        goto out_close_dir;
2816424e9256Smrg
2817fe517fc9Smrg    pent = malloc(offsetof(struct dirent, d_name) + name_max + 1);
2818fe517fc9Smrg    if (pent == NULL)
2819fe517fc9Smrg         goto out_close_dir;
2820424e9256Smrg
2821fe517fc9Smrg    while (readdir_r(sysdir, pent, &ent) == 0 && ent != NULL) {
2822fe517fc9Smrg        if (strncmp(ent->d_name, name, len) == 0) {
2823fe517fc9Smrg            snprintf(dev_name, sizeof(dev_name), DRM_DIR_NAME "/%s",
2824fe517fc9Smrg                 ent->d_name);
2825424e9256Smrg
2826fe517fc9Smrg            free(pent);
2827fe517fc9Smrg            closedir(sysdir);
2828424e9256Smrg
2829fe517fc9Smrg            return strdup(dev_name);
2830fe517fc9Smrg        }
2831fe517fc9Smrg    }
2832424e9256Smrg
2833fe517fc9Smrg    free(pent);
2834424e9256Smrg
2835424e9256Smrgout_close_dir:
2836fe517fc9Smrg    closedir(sysdir);
2837fe517fc9Smrg#else
28382ee35494Smrg    struct stat sbuf;
28392ee35494Smrg    char buf[PATH_MAX + 1];
28402ee35494Smrg    const char *dev_name;
28412ee35494Smrg    unsigned int maj, min;
28422ee35494Smrg    int n, base;
28432ee35494Smrg
28442ee35494Smrg    if (fstat(fd, &sbuf))
28452ee35494Smrg        return NULL;
28462ee35494Smrg
28472ee35494Smrg    maj = major(sbuf.st_rdev);
28482ee35494Smrg    min = minor(sbuf.st_rdev);
28492ee35494Smrg
28502ee35494Smrg    if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode))
28512ee35494Smrg        return NULL;
28522ee35494Smrg
28532ee35494Smrg    switch (type) {
28542ee35494Smrg    case DRM_NODE_PRIMARY:
28552ee35494Smrg        dev_name = DRM_DEV_NAME;
28562ee35494Smrg        break;
28572ee35494Smrg    case DRM_NODE_CONTROL:
28582ee35494Smrg        dev_name = DRM_CONTROL_DEV_NAME;
28592ee35494Smrg        break;
28602ee35494Smrg    case DRM_NODE_RENDER:
28612ee35494Smrg        dev_name = DRM_RENDER_DEV_NAME;
28622ee35494Smrg        break;
28632ee35494Smrg    default:
28642ee35494Smrg        return NULL;
28652ee35494Smrg    };
28662ee35494Smrg
28672ee35494Smrg    base = drmGetMinorBase(type);
28682ee35494Smrg    if (base < 0)
28692ee35494Smrg        return NULL;
28702ee35494Smrg
28712ee35494Smrg    n = snprintf(buf, sizeof(buf), dev_name, DRM_DIR_NAME, min - base);
28722ee35494Smrg    if (n == -1 || n >= sizeof(buf))
28732ee35494Smrg        return NULL;
28742ee35494Smrg
28752ee35494Smrg    return strdup(buf);
2876424e9256Smrg#endif
2877fe517fc9Smrg    return NULL;
2878424e9256Smrg}
2879424e9256Smrg
2880424e9256Smrgchar *drmGetPrimaryDeviceNameFromFd(int fd)
2881424e9256Smrg{
2882fe517fc9Smrg    return drmGetMinorNameForFD(fd, DRM_NODE_PRIMARY);
2883424e9256Smrg}
2884424e9256Smrg
2885424e9256Smrgchar *drmGetRenderDeviceNameFromFd(int fd)
2886424e9256Smrg{
2887fe517fc9Smrg    return drmGetMinorNameForFD(fd, DRM_NODE_RENDER);
2888fe517fc9Smrg}
2889fe517fc9Smrg
28902ee35494Smrg#ifdef __linux__
28912ee35494Smrgstatic char * DRM_PRINTFLIKE(2, 3)
28922ee35494Smrgsysfs_uevent_get(const char *path, const char *fmt, ...)
28932ee35494Smrg{
28942ee35494Smrg    char filename[PATH_MAX + 1], *key, *line = NULL, *value = NULL;
28952ee35494Smrg    size_t size = 0, len;
28962ee35494Smrg    ssize_t num;
28972ee35494Smrg    va_list ap;
28982ee35494Smrg    FILE *fp;
28992ee35494Smrg
29002ee35494Smrg    va_start(ap, fmt);
29012ee35494Smrg    num = vasprintf(&key, fmt, ap);
29022ee35494Smrg    va_end(ap);
29032ee35494Smrg    len = num;
29042ee35494Smrg
29052ee35494Smrg    snprintf(filename, sizeof(filename), "%s/uevent", path);
29062ee35494Smrg
29072ee35494Smrg    fp = fopen(filename, "r");
29082ee35494Smrg    if (!fp) {
29092ee35494Smrg        free(key);
29102ee35494Smrg        return NULL;
29112ee35494Smrg    }
29122ee35494Smrg
29132ee35494Smrg    while ((num = getline(&line, &size, fp)) >= 0) {
29142ee35494Smrg        if ((strncmp(line, key, len) == 0) && (line[len] == '=')) {
29152ee35494Smrg            char *start = line + len + 1, *end = line + num - 1;
29162ee35494Smrg
29172ee35494Smrg            if (*end != '\n')
29182ee35494Smrg                end++;
29192ee35494Smrg
29202ee35494Smrg            value = strndup(start, end - start);
29212ee35494Smrg            break;
29222ee35494Smrg        }
29232ee35494Smrg    }
29242ee35494Smrg
29252ee35494Smrg    free(line);
29262ee35494Smrg    fclose(fp);
29272ee35494Smrg
29282ee35494Smrg    free(key);
29292ee35494Smrg
29302ee35494Smrg    return value;
29312ee35494Smrg}
29322ee35494Smrg#endif
29332ee35494Smrg
2934fe517fc9Smrgstatic int drmParseSubsystemType(int maj, int min)
2935fe517fc9Smrg{
2936fe517fc9Smrg#ifdef __linux__
2937fe517fc9Smrg    char path[PATH_MAX + 1];
2938fe517fc9Smrg    char link[PATH_MAX + 1] = "";
2939fe517fc9Smrg    char *name;
2940fe517fc9Smrg
2941fe517fc9Smrg    snprintf(path, PATH_MAX, "/sys/dev/char/%d:%d/device/subsystem",
2942fe517fc9Smrg             maj, min);
2943fe517fc9Smrg
2944fe517fc9Smrg    if (readlink(path, link, PATH_MAX) < 0)
2945fe517fc9Smrg        return -errno;
2946fe517fc9Smrg
2947fe517fc9Smrg    name = strrchr(link, '/');
2948fe517fc9Smrg    if (!name)
2949fe517fc9Smrg        return -EINVAL;
2950fe517fc9Smrg
2951fe517fc9Smrg    if (strncmp(name, "/pci", 4) == 0)
2952fe517fc9Smrg        return DRM_BUS_PCI;
2953fe517fc9Smrg
29542ee35494Smrg    if (strncmp(name, "/usb", 4) == 0)
29552ee35494Smrg        return DRM_BUS_USB;
29562ee35494Smrg
29572ee35494Smrg    if (strncmp(name, "/platform", 9) == 0)
29582ee35494Smrg        return DRM_BUS_PLATFORM;
29592ee35494Smrg
29602ee35494Smrg    if (strncmp(name, "/host1x", 7) == 0)
29612ee35494Smrg        return DRM_BUS_HOST1X;
29622ee35494Smrg
2963fe517fc9Smrg    return -EINVAL;
29642ee35494Smrg#elif defined(__OpenBSD__)
29652ee35494Smrg    return DRM_BUS_PCI;
2966fe517fc9Smrg#else
2967fe517fc9Smrg#warning "Missing implementation of drmParseSubsystemType"
2968fe517fc9Smrg    return -EINVAL;
2969fe517fc9Smrg#endif
2970fe517fc9Smrg}
2971fe517fc9Smrg
2972fe517fc9Smrgstatic int drmParsePciBusInfo(int maj, int min, drmPciBusInfoPtr info)
2973fe517fc9Smrg{
2974fe517fc9Smrg#ifdef __linux__
29752ee35494Smrg    unsigned int domain, bus, dev, func;
29762ee35494Smrg    char path[PATH_MAX + 1], *value;
29772ee35494Smrg    int num;
2978fe517fc9Smrg
29792ee35494Smrg    snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min);
2980fe517fc9Smrg
29812ee35494Smrg    value = sysfs_uevent_get(path, "PCI_SLOT_NAME");
29822ee35494Smrg    if (!value)
29832ee35494Smrg        return -ENOENT;
2984fe517fc9Smrg
29852ee35494Smrg    num = sscanf(value, "%04x:%02x:%02x.%1u", &domain, &bus, &dev, &func);
29862ee35494Smrg    free(value);
2987fe517fc9Smrg
29882ee35494Smrg    if (num != 4)
2989fe517fc9Smrg        return -EINVAL;
2990fe517fc9Smrg
2991fe517fc9Smrg    info->domain = domain;
2992fe517fc9Smrg    info->bus = bus;
2993fe517fc9Smrg    info->dev = dev;
2994fe517fc9Smrg    info->func = func;
2995fe517fc9Smrg
29962ee35494Smrg    return 0;
29972ee35494Smrg#elif defined(__OpenBSD__)
29982ee35494Smrg    struct drm_pciinfo pinfo;
29992ee35494Smrg    int fd, type;
30002ee35494Smrg
30012ee35494Smrg    type = drmGetMinorType(min);
30022ee35494Smrg    if (type == -1)
30032ee35494Smrg        return -ENODEV;
30042ee35494Smrg
30052ee35494Smrg    fd = drmOpenMinor(min, 0, type);
30062ee35494Smrg    if (fd < 0)
30072ee35494Smrg        return -errno;
30082ee35494Smrg
30092ee35494Smrg    if (drmIoctl(fd, DRM_IOCTL_GET_PCIINFO, &pinfo)) {
30102ee35494Smrg        close(fd);
30112ee35494Smrg        return -errno;
30122ee35494Smrg    }
30132ee35494Smrg    close(fd);
30142ee35494Smrg
30152ee35494Smrg    info->domain = pinfo.domain;
30162ee35494Smrg    info->bus = pinfo.bus;
30172ee35494Smrg    info->dev = pinfo.dev;
30182ee35494Smrg    info->func = pinfo.func;
30192ee35494Smrg
3020fe517fc9Smrg    return 0;
3021fe517fc9Smrg#else
3022fe517fc9Smrg#warning "Missing implementation of drmParsePciBusInfo"
3023fe517fc9Smrg    return -EINVAL;
3024fe517fc9Smrg#endif
3025fe517fc9Smrg}
3026fe517fc9Smrg
3027fe517fc9Smrgstatic int drmCompareBusInfo(drmDevicePtr a, drmDevicePtr b)
3028fe517fc9Smrg{
3029fe517fc9Smrg    if (a == NULL || b == NULL)
3030fe517fc9Smrg        return -1;
3031fe517fc9Smrg
3032fe517fc9Smrg    if (a->bustype != b->bustype)
3033fe517fc9Smrg        return -1;
3034fe517fc9Smrg
3035fe517fc9Smrg    switch (a->bustype) {
3036fe517fc9Smrg    case DRM_BUS_PCI:
3037fe517fc9Smrg        return memcmp(a->businfo.pci, b->businfo.pci, sizeof(drmPciBusInfo));
30382ee35494Smrg
30392ee35494Smrg    case DRM_BUS_USB:
30402ee35494Smrg        return memcmp(a->businfo.usb, b->businfo.usb, sizeof(drmUsbBusInfo));
30412ee35494Smrg
30422ee35494Smrg    case DRM_BUS_PLATFORM:
30432ee35494Smrg        return memcmp(a->businfo.platform, b->businfo.platform, sizeof(drmPlatformBusInfo));
30442ee35494Smrg
30452ee35494Smrg    case DRM_BUS_HOST1X:
30462ee35494Smrg        return memcmp(a->businfo.host1x, b->businfo.host1x, sizeof(drmHost1xBusInfo));
30472ee35494Smrg
3048fe517fc9Smrg    default:
3049fe517fc9Smrg        break;
3050fe517fc9Smrg    }
3051fe517fc9Smrg
3052fe517fc9Smrg    return -1;
3053fe517fc9Smrg}
3054fe517fc9Smrg
3055fe517fc9Smrgstatic int drmGetNodeType(const char *name)
3056fe517fc9Smrg{
3057fe517fc9Smrg    if (strncmp(name, DRM_PRIMARY_MINOR_NAME,
3058fe517fc9Smrg        sizeof(DRM_PRIMARY_MINOR_NAME) - 1) == 0)
3059fe517fc9Smrg        return DRM_NODE_PRIMARY;
3060fe517fc9Smrg
3061fe517fc9Smrg    if (strncmp(name, DRM_CONTROL_MINOR_NAME,
3062fe517fc9Smrg        sizeof(DRM_CONTROL_MINOR_NAME ) - 1) == 0)
3063fe517fc9Smrg        return DRM_NODE_CONTROL;
3064fe517fc9Smrg
3065fe517fc9Smrg    if (strncmp(name, DRM_RENDER_MINOR_NAME,
3066fe517fc9Smrg        sizeof(DRM_RENDER_MINOR_NAME) - 1) == 0)
3067fe517fc9Smrg        return DRM_NODE_RENDER;
3068fe517fc9Smrg
3069fe517fc9Smrg    return -EINVAL;
3070fe517fc9Smrg}
3071fe517fc9Smrg
3072fe517fc9Smrgstatic int drmGetMaxNodeName(void)
3073fe517fc9Smrg{
3074fe517fc9Smrg    return sizeof(DRM_DIR_NAME) +
3075fe517fc9Smrg           MAX3(sizeof(DRM_PRIMARY_MINOR_NAME),
3076fe517fc9Smrg                sizeof(DRM_CONTROL_MINOR_NAME),
3077fe517fc9Smrg                sizeof(DRM_RENDER_MINOR_NAME)) +
3078fe517fc9Smrg           3 /* length of the node number */;
3079fe517fc9Smrg}
3080fe517fc9Smrg
3081fe517fc9Smrg#ifdef __linux__
30822ee35494Smrgstatic int parse_separate_sysfs_files(int maj, int min,
30832ee35494Smrg                                      drmPciDeviceInfoPtr device,
30842ee35494Smrg                                      bool ignore_revision)
30852ee35494Smrg{
30862ee35494Smrg#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
30872ee35494Smrg    static const char *attrs[] = {
30882ee35494Smrg      "revision", /* Older kernels are missing the file, so check for it first */
30892ee35494Smrg      "vendor",
30902ee35494Smrg      "device",
30912ee35494Smrg      "subsystem_vendor",
30922ee35494Smrg      "subsystem_device",
30932ee35494Smrg    };
30942ee35494Smrg    char path[PATH_MAX + 1];
30952ee35494Smrg    unsigned int data[ARRAY_SIZE(attrs)];
30962ee35494Smrg    FILE *fp;
30972ee35494Smrg    int ret;
30982ee35494Smrg
30992ee35494Smrg    for (unsigned i = ignore_revision ? 1 : 0; i < ARRAY_SIZE(attrs); i++) {
31002ee35494Smrg        snprintf(path, PATH_MAX, "/sys/dev/char/%d:%d/device/%s", maj, min,
31012ee35494Smrg                 attrs[i]);
31022ee35494Smrg        fp = fopen(path, "r");
31032ee35494Smrg        if (!fp)
31042ee35494Smrg            return -errno;
31052ee35494Smrg
31062ee35494Smrg        ret = fscanf(fp, "%x", &data[i]);
31072ee35494Smrg        fclose(fp);
31082ee35494Smrg        if (ret != 1)
31092ee35494Smrg            return -errno;
31102ee35494Smrg
31112ee35494Smrg    }
31122ee35494Smrg
31132ee35494Smrg    device->revision_id = ignore_revision ? 0xff : data[0] & 0xff;
31142ee35494Smrg    device->vendor_id = data[1] & 0xffff;
31152ee35494Smrg    device->device_id = data[2] & 0xffff;
31162ee35494Smrg    device->subvendor_id = data[3] & 0xffff;
31172ee35494Smrg    device->subdevice_id = data[4] & 0xffff;
31182ee35494Smrg
31192ee35494Smrg    return 0;
31202ee35494Smrg}
31212ee35494Smrg
31222ee35494Smrgstatic int parse_config_sysfs_file(int maj, int min,
31232ee35494Smrg                                   drmPciDeviceInfoPtr device)
31242ee35494Smrg{
3125fe517fc9Smrg    char path[PATH_MAX + 1];
3126fe517fc9Smrg    unsigned char config[64];
3127fe517fc9Smrg    int fd, ret;
3128fe517fc9Smrg
31292ee35494Smrg    snprintf(path, PATH_MAX, "/sys/dev/char/%d:%d/device/config", maj, min);
3130fe517fc9Smrg    fd = open(path, O_RDONLY);
3131fe517fc9Smrg    if (fd < 0)
3132fe517fc9Smrg        return -errno;
3133fe517fc9Smrg
3134fe517fc9Smrg    ret = read(fd, config, sizeof(config));
3135fe517fc9Smrg    close(fd);
3136fe517fc9Smrg    if (ret < 0)
3137fe517fc9Smrg        return -errno;
3138fe517fc9Smrg
3139fe517fc9Smrg    device->vendor_id = config[0] | (config[1] << 8);
3140fe517fc9Smrg    device->device_id = config[2] | (config[3] << 8);
3141fe517fc9Smrg    device->revision_id = config[8];
3142fe517fc9Smrg    device->subvendor_id = config[44] | (config[45] << 8);
3143fe517fc9Smrg    device->subdevice_id = config[46] | (config[47] << 8);
3144fe517fc9Smrg
31452ee35494Smrg    return 0;
31462ee35494Smrg}
31472ee35494Smrg#endif
31482ee35494Smrg
31492ee35494Smrgstatic int drmParsePciDeviceInfo(int maj, int min,
31502ee35494Smrg                                 drmPciDeviceInfoPtr device,
31512ee35494Smrg                                 uint32_t flags)
31522ee35494Smrg{
31532ee35494Smrg#ifdef __linux__
31542ee35494Smrg    if (!(flags & DRM_DEVICE_GET_PCI_REVISION))
31552ee35494Smrg        return parse_separate_sysfs_files(maj, min, device, true);
31562ee35494Smrg
31572ee35494Smrg    if (parse_separate_sysfs_files(maj, min, device, false))
31582ee35494Smrg        return parse_config_sysfs_file(maj, min, device);
31592ee35494Smrg
31602ee35494Smrg    return 0;
31612ee35494Smrg#elif defined(__OpenBSD__)
31622ee35494Smrg    struct drm_pciinfo pinfo;
31632ee35494Smrg    int fd, type;
31642ee35494Smrg
31652ee35494Smrg    type = drmGetMinorType(min);
31662ee35494Smrg    if (type == -1)
31672ee35494Smrg        return -ENODEV;
31682ee35494Smrg
31692ee35494Smrg    fd = drmOpenMinor(min, 0, type);
31702ee35494Smrg    if (fd < 0)
31712ee35494Smrg        return -errno;
31722ee35494Smrg
31732ee35494Smrg    if (drmIoctl(fd, DRM_IOCTL_GET_PCIINFO, &pinfo)) {
31742ee35494Smrg        close(fd);
31752ee35494Smrg        return -errno;
31762ee35494Smrg    }
31772ee35494Smrg    close(fd);
31782ee35494Smrg
31792ee35494Smrg    device->vendor_id = pinfo.vendor_id;
31802ee35494Smrg    device->device_id = pinfo.device_id;
31812ee35494Smrg    device->revision_id = pinfo.revision_id;
31822ee35494Smrg    device->subvendor_id = pinfo.subvendor_id;
31832ee35494Smrg    device->subdevice_id = pinfo.subdevice_id;
31842ee35494Smrg
3185fe517fc9Smrg    return 0;
3186fe517fc9Smrg#else
3187fe517fc9Smrg#warning "Missing implementation of drmParsePciDeviceInfo"
3188fe517fc9Smrg    return -EINVAL;
3189fe517fc9Smrg#endif
3190fe517fc9Smrg}
3191fe517fc9Smrg
31922ee35494Smrgstatic void drmFreePlatformDevice(drmDevicePtr device)
31932ee35494Smrg{
31942ee35494Smrg    if (device->deviceinfo.platform) {
31952ee35494Smrg        if (device->deviceinfo.platform->compatible) {
31962ee35494Smrg            char **compatible = device->deviceinfo.platform->compatible;
31972ee35494Smrg
31982ee35494Smrg            while (*compatible) {
31992ee35494Smrg                free(*compatible);
32002ee35494Smrg                compatible++;
32012ee35494Smrg            }
32022ee35494Smrg
32032ee35494Smrg            free(device->deviceinfo.platform->compatible);
32042ee35494Smrg        }
32052ee35494Smrg    }
32062ee35494Smrg}
32072ee35494Smrg
32082ee35494Smrgstatic void drmFreeHost1xDevice(drmDevicePtr device)
32092ee35494Smrg{
32102ee35494Smrg    if (device->deviceinfo.host1x) {
32112ee35494Smrg        if (device->deviceinfo.host1x->compatible) {
32122ee35494Smrg            char **compatible = device->deviceinfo.host1x->compatible;
32132ee35494Smrg
32142ee35494Smrg            while (*compatible) {
32152ee35494Smrg                free(*compatible);
32162ee35494Smrg                compatible++;
32172ee35494Smrg            }
32182ee35494Smrg
32192ee35494Smrg            free(device->deviceinfo.host1x->compatible);
32202ee35494Smrg        }
32212ee35494Smrg    }
32222ee35494Smrg}
32232ee35494Smrg
3224fe517fc9Smrgvoid drmFreeDevice(drmDevicePtr *device)
3225fe517fc9Smrg{
3226fe517fc9Smrg    if (device == NULL)
3227fe517fc9Smrg        return;
3228fe517fc9Smrg
32292ee35494Smrg    if (*device) {
32302ee35494Smrg        switch ((*device)->bustype) {
32312ee35494Smrg        case DRM_BUS_PLATFORM:
32322ee35494Smrg            drmFreePlatformDevice(*device);
32332ee35494Smrg            break;
32342ee35494Smrg
32352ee35494Smrg        case DRM_BUS_HOST1X:
32362ee35494Smrg            drmFreeHost1xDevice(*device);
32372ee35494Smrg            break;
32382ee35494Smrg        }
32392ee35494Smrg    }
32402ee35494Smrg
3241fe517fc9Smrg    free(*device);
3242fe517fc9Smrg    *device = NULL;
3243fe517fc9Smrg}
3244fe517fc9Smrg
3245fe517fc9Smrgvoid drmFreeDevices(drmDevicePtr devices[], int count)
3246fe517fc9Smrg{
3247fe517fc9Smrg    int i;
3248fe517fc9Smrg
3249fe517fc9Smrg    if (devices == NULL)
3250fe517fc9Smrg        return;
3251fe517fc9Smrg
3252fe517fc9Smrg    for (i = 0; i < count; i++)
3253fe517fc9Smrg        if (devices[i])
3254fe517fc9Smrg            drmFreeDevice(&devices[i]);
3255fe517fc9Smrg}
3256fe517fc9Smrg
32572ee35494Smrgstatic drmDevicePtr drmDeviceAlloc(unsigned int type, const char *node,
32582ee35494Smrg                                   size_t bus_size, size_t device_size,
32592ee35494Smrg                                   char **ptrp)
3260fe517fc9Smrg{
32612ee35494Smrg    size_t max_node_length, extra, size;
32622ee35494Smrg    drmDevicePtr device;
32632ee35494Smrg    unsigned int i;
32642ee35494Smrg    char *ptr;
3265fe517fc9Smrg
32662ee35494Smrg    max_node_length = ALIGN(drmGetMaxNodeName(), sizeof(void *));
32672ee35494Smrg    extra = DRM_NODE_MAX * (sizeof(void *) + max_node_length);
3268fe517fc9Smrg
32692ee35494Smrg    size = sizeof(*device) + extra + bus_size + device_size;
3270fe517fc9Smrg
32712ee35494Smrg    device = calloc(1, size);
32722ee35494Smrg    if (!device)
32732ee35494Smrg        return NULL;
32742ee35494Smrg
32752ee35494Smrg    device->available_nodes = 1 << type;
3276fe517fc9Smrg
32772ee35494Smrg    ptr = (char *)device + sizeof(*device);
32782ee35494Smrg    device->nodes = (char **)ptr;
32792ee35494Smrg
32802ee35494Smrg    ptr += DRM_NODE_MAX * sizeof(void *);
3281fe517fc9Smrg
3282fe517fc9Smrg    for (i = 0; i < DRM_NODE_MAX; i++) {
32832ee35494Smrg        device->nodes[i] = ptr;
32842ee35494Smrg        ptr += max_node_length;
3285fe517fc9Smrg    }
3286fe517fc9Smrg
32872ee35494Smrg    memcpy(device->nodes[type], node, max_node_length);
32882ee35494Smrg
32892ee35494Smrg    *ptrp = ptr;
32902ee35494Smrg
32912ee35494Smrg    return device;
32922ee35494Smrg}
32932ee35494Smrg
32942ee35494Smrgstatic int drmProcessPciDevice(drmDevicePtr *device,
32952ee35494Smrg                               const char *node, int node_type,
32962ee35494Smrg                               int maj, int min, bool fetch_deviceinfo,
32972ee35494Smrg                               uint32_t flags)
32982ee35494Smrg{
32992ee35494Smrg    drmDevicePtr dev;
33002ee35494Smrg    char *addr;
33012ee35494Smrg    int ret;
33022ee35494Smrg
33032ee35494Smrg    dev = drmDeviceAlloc(node_type, node, sizeof(drmPciBusInfo),
33042ee35494Smrg                         sizeof(drmPciDeviceInfo), &addr);
33052ee35494Smrg    if (!dev)
33062ee35494Smrg        return -ENOMEM;
33072ee35494Smrg
33082ee35494Smrg    dev->bustype = DRM_BUS_PCI;
3309fe517fc9Smrg
33102ee35494Smrg    dev->businfo.pci = (drmPciBusInfoPtr)addr;
33112ee35494Smrg
33122ee35494Smrg    ret = drmParsePciBusInfo(maj, min, dev->businfo.pci);
3313fe517fc9Smrg    if (ret)
3314fe517fc9Smrg        goto free_device;
3315fe517fc9Smrg
3316fe517fc9Smrg    // Fetch the device info if the user has requested it
3317fe517fc9Smrg    if (fetch_deviceinfo) {
3318fe517fc9Smrg        addr += sizeof(drmPciBusInfo);
33192ee35494Smrg        dev->deviceinfo.pci = (drmPciDeviceInfoPtr)addr;
3320fe517fc9Smrg
33212ee35494Smrg        ret = drmParsePciDeviceInfo(maj, min, dev->deviceinfo.pci, flags);
3322fe517fc9Smrg        if (ret)
3323fe517fc9Smrg            goto free_device;
3324fe517fc9Smrg    }
33252ee35494Smrg
33262ee35494Smrg    *device = dev;
33272ee35494Smrg
3328fe517fc9Smrg    return 0;
3329fe517fc9Smrg
3330fe517fc9Smrgfree_device:
33312ee35494Smrg    free(dev);
33322ee35494Smrg    return ret;
33332ee35494Smrg}
33342ee35494Smrg
33352ee35494Smrgstatic int drmParseUsbBusInfo(int maj, int min, drmUsbBusInfoPtr info)
33362ee35494Smrg{
33372ee35494Smrg#ifdef __linux__
33382ee35494Smrg    char path[PATH_MAX + 1], *value;
33392ee35494Smrg    unsigned int bus, dev;
33402ee35494Smrg    int ret;
33412ee35494Smrg
33422ee35494Smrg    snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min);
33432ee35494Smrg
33442ee35494Smrg    value = sysfs_uevent_get(path, "BUSNUM");
33452ee35494Smrg    if (!value)
33462ee35494Smrg        return -ENOENT;
33472ee35494Smrg
33482ee35494Smrg    ret = sscanf(value, "%03u", &bus);
33492ee35494Smrg    free(value);
33502ee35494Smrg
33512ee35494Smrg    if (ret <= 0)
33522ee35494Smrg        return -errno;
33532ee35494Smrg
33542ee35494Smrg    value = sysfs_uevent_get(path, "DEVNUM");
33552ee35494Smrg    if (!value)
33562ee35494Smrg        return -ENOENT;
33572ee35494Smrg
33582ee35494Smrg    ret = sscanf(value, "%03u", &dev);
33592ee35494Smrg    free(value);
33602ee35494Smrg
33612ee35494Smrg    if (ret <= 0)
33622ee35494Smrg        return -errno;
33632ee35494Smrg
33642ee35494Smrg    info->bus = bus;
33652ee35494Smrg    info->dev = dev;
33662ee35494Smrg
33672ee35494Smrg    return 0;
33682ee35494Smrg#else
33692ee35494Smrg#warning "Missing implementation of drmParseUsbBusInfo"
33702ee35494Smrg    return -EINVAL;
33712ee35494Smrg#endif
33722ee35494Smrg}
33732ee35494Smrg
33742ee35494Smrgstatic int drmParseUsbDeviceInfo(int maj, int min, drmUsbDeviceInfoPtr info)
33752ee35494Smrg{
33762ee35494Smrg#ifdef __linux__
33772ee35494Smrg    char path[PATH_MAX + 1], *value;
33782ee35494Smrg    unsigned int vendor, product;
33792ee35494Smrg    int ret;
33802ee35494Smrg
33812ee35494Smrg    snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min);
33822ee35494Smrg
33832ee35494Smrg    value = sysfs_uevent_get(path, "PRODUCT");
33842ee35494Smrg    if (!value)
33852ee35494Smrg        return -ENOENT;
33862ee35494Smrg
33872ee35494Smrg    ret = sscanf(value, "%x/%x", &vendor, &product);
33882ee35494Smrg    free(value);
33892ee35494Smrg
33902ee35494Smrg    if (ret <= 0)
33912ee35494Smrg        return -errno;
33922ee35494Smrg
33932ee35494Smrg    info->vendor = vendor;
33942ee35494Smrg    info->product = product;
33952ee35494Smrg
33962ee35494Smrg    return 0;
33972ee35494Smrg#else
33982ee35494Smrg#warning "Missing implementation of drmParseUsbDeviceInfo"
33992ee35494Smrg    return -EINVAL;
34002ee35494Smrg#endif
34012ee35494Smrg}
34022ee35494Smrg
34032ee35494Smrgstatic int drmProcessUsbDevice(drmDevicePtr *device, const char *node,
34042ee35494Smrg                               int node_type, int maj, int min,
34052ee35494Smrg                               bool fetch_deviceinfo, uint32_t flags)
34062ee35494Smrg{
34072ee35494Smrg    drmDevicePtr dev;
34082ee35494Smrg    char *ptr;
34092ee35494Smrg    int ret;
34102ee35494Smrg
34112ee35494Smrg    dev = drmDeviceAlloc(node_type, node, sizeof(drmUsbBusInfo),
34122ee35494Smrg                         sizeof(drmUsbDeviceInfo), &ptr);
34132ee35494Smrg    if (!dev)
34142ee35494Smrg        return -ENOMEM;
34152ee35494Smrg
34162ee35494Smrg    dev->bustype = DRM_BUS_USB;
34172ee35494Smrg
34182ee35494Smrg    dev->businfo.usb = (drmUsbBusInfoPtr)ptr;
34192ee35494Smrg
34202ee35494Smrg    ret = drmParseUsbBusInfo(maj, min, dev->businfo.usb);
34212ee35494Smrg    if (ret < 0)
34222ee35494Smrg        goto free_device;
34232ee35494Smrg
34242ee35494Smrg    if (fetch_deviceinfo) {
34252ee35494Smrg        ptr += sizeof(drmUsbBusInfo);
34262ee35494Smrg        dev->deviceinfo.usb = (drmUsbDeviceInfoPtr)ptr;
34272ee35494Smrg
34282ee35494Smrg        ret = drmParseUsbDeviceInfo(maj, min, dev->deviceinfo.usb);
34292ee35494Smrg        if (ret < 0)
34302ee35494Smrg            goto free_device;
34312ee35494Smrg    }
34322ee35494Smrg
34332ee35494Smrg    *device = dev;
34342ee35494Smrg
34352ee35494Smrg    return 0;
34362ee35494Smrg
34372ee35494Smrgfree_device:
34382ee35494Smrg    free(dev);
34392ee35494Smrg    return ret;
34402ee35494Smrg}
34412ee35494Smrg
34422ee35494Smrgstatic int drmParsePlatformBusInfo(int maj, int min, drmPlatformBusInfoPtr info)
34432ee35494Smrg{
34442ee35494Smrg#ifdef __linux__
34452ee35494Smrg    char path[PATH_MAX + 1], *name;
34462ee35494Smrg
34472ee35494Smrg    snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min);
34482ee35494Smrg
34492ee35494Smrg    name = sysfs_uevent_get(path, "OF_FULLNAME");
34502ee35494Smrg    if (!name)
34512ee35494Smrg        return -ENOENT;
34522ee35494Smrg
34532ee35494Smrg    strncpy(info->fullname, name, DRM_PLATFORM_DEVICE_NAME_LEN);
34542ee35494Smrg    info->fullname[DRM_PLATFORM_DEVICE_NAME_LEN - 1] = '\0';
34552ee35494Smrg    free(name);
34562ee35494Smrg
34572ee35494Smrg    return 0;
34582ee35494Smrg#else
34592ee35494Smrg#warning "Missing implementation of drmParsePlatformBusInfo"
34602ee35494Smrg    return -EINVAL;
34612ee35494Smrg#endif
34622ee35494Smrg}
34632ee35494Smrg
34642ee35494Smrgstatic int drmParsePlatformDeviceInfo(int maj, int min,
34652ee35494Smrg                                      drmPlatformDeviceInfoPtr info)
34662ee35494Smrg{
34672ee35494Smrg#ifdef __linux__
34682ee35494Smrg    char path[PATH_MAX + 1], *value;
34692ee35494Smrg    unsigned int count, i;
34702ee35494Smrg    int err;
34712ee35494Smrg
34722ee35494Smrg    snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min);
34732ee35494Smrg
34742ee35494Smrg    value = sysfs_uevent_get(path, "OF_COMPATIBLE_N");
34752ee35494Smrg    if (!value)
34762ee35494Smrg        return -ENOENT;
34772ee35494Smrg
34782ee35494Smrg    sscanf(value, "%u", &count);
34792ee35494Smrg    free(value);
34802ee35494Smrg
34812ee35494Smrg    info->compatible = calloc(count + 1, sizeof(*info->compatible));
34822ee35494Smrg    if (!info->compatible)
34832ee35494Smrg        return -ENOMEM;
34842ee35494Smrg
34852ee35494Smrg    for (i = 0; i < count; i++) {
34862ee35494Smrg        value = sysfs_uevent_get(path, "OF_COMPATIBLE_%u", i);
34872ee35494Smrg        if (!value) {
34882ee35494Smrg            err = -ENOENT;
34892ee35494Smrg            goto free;
34902ee35494Smrg        }
34912ee35494Smrg
34922ee35494Smrg        info->compatible[i] = value;
34932ee35494Smrg    }
34942ee35494Smrg
34952ee35494Smrg    return 0;
34962ee35494Smrg
34972ee35494Smrgfree:
34982ee35494Smrg    while (i--)
34992ee35494Smrg        free(info->compatible[i]);
35002ee35494Smrg
35012ee35494Smrg    free(info->compatible);
35022ee35494Smrg    return err;
35032ee35494Smrg#else
35042ee35494Smrg#warning "Missing implementation of drmParsePlatformDeviceInfo"
35052ee35494Smrg    return -EINVAL;
35062ee35494Smrg#endif
35072ee35494Smrg}
35082ee35494Smrg
35092ee35494Smrgstatic int drmProcessPlatformDevice(drmDevicePtr *device,
35102ee35494Smrg                                    const char *node, int node_type,
35112ee35494Smrg                                    int maj, int min, bool fetch_deviceinfo,
35122ee35494Smrg                                    uint32_t flags)
35132ee35494Smrg{
35142ee35494Smrg    drmDevicePtr dev;
35152ee35494Smrg    char *ptr;
35162ee35494Smrg    int ret;
35172ee35494Smrg
35182ee35494Smrg    dev = drmDeviceAlloc(node_type, node, sizeof(drmPlatformBusInfo),
35192ee35494Smrg                         sizeof(drmPlatformDeviceInfo), &ptr);
35202ee35494Smrg    if (!dev)
35212ee35494Smrg        return -ENOMEM;
35222ee35494Smrg
35232ee35494Smrg    dev->bustype = DRM_BUS_PLATFORM;
35242ee35494Smrg
35252ee35494Smrg    dev->businfo.platform = (drmPlatformBusInfoPtr)ptr;
35262ee35494Smrg
35272ee35494Smrg    ret = drmParsePlatformBusInfo(maj, min, dev->businfo.platform);
35282ee35494Smrg    if (ret < 0)
35292ee35494Smrg        goto free_device;
35302ee35494Smrg
35312ee35494Smrg    if (fetch_deviceinfo) {
35322ee35494Smrg        ptr += sizeof(drmPlatformBusInfo);
35332ee35494Smrg        dev->deviceinfo.platform = (drmPlatformDeviceInfoPtr)ptr;
35342ee35494Smrg
35352ee35494Smrg        ret = drmParsePlatformDeviceInfo(maj, min, dev->deviceinfo.platform);
35362ee35494Smrg        if (ret < 0)
35372ee35494Smrg            goto free_device;
35382ee35494Smrg    }
35392ee35494Smrg
35402ee35494Smrg    *device = dev;
35412ee35494Smrg
35422ee35494Smrg    return 0;
35432ee35494Smrg
35442ee35494Smrgfree_device:
35452ee35494Smrg    free(dev);
35462ee35494Smrg    return ret;
35472ee35494Smrg}
35482ee35494Smrg
35492ee35494Smrgstatic int drmParseHost1xBusInfo(int maj, int min, drmHost1xBusInfoPtr info)
35502ee35494Smrg{
35512ee35494Smrg#ifdef __linux__
35522ee35494Smrg    char path[PATH_MAX + 1], *name;
35532ee35494Smrg
35542ee35494Smrg    snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min);
35552ee35494Smrg
35562ee35494Smrg    name = sysfs_uevent_get(path, "OF_FULLNAME");
35572ee35494Smrg    if (!name)
35582ee35494Smrg        return -ENOENT;
35592ee35494Smrg
35602ee35494Smrg    strncpy(info->fullname, name, DRM_HOST1X_DEVICE_NAME_LEN);
35612ee35494Smrg    info->fullname[DRM_HOST1X_DEVICE_NAME_LEN - 1] = '\0';
35622ee35494Smrg    free(name);
35632ee35494Smrg
35642ee35494Smrg    return 0;
35652ee35494Smrg#else
35662ee35494Smrg#warning "Missing implementation of drmParseHost1xBusInfo"
35672ee35494Smrg    return -EINVAL;
35682ee35494Smrg#endif
35692ee35494Smrg}
35702ee35494Smrg
35712ee35494Smrgstatic int drmParseHost1xDeviceInfo(int maj, int min,
35722ee35494Smrg                                    drmHost1xDeviceInfoPtr info)
35732ee35494Smrg{
35742ee35494Smrg#ifdef __linux__
35752ee35494Smrg    char path[PATH_MAX + 1], *value;
35762ee35494Smrg    unsigned int count, i;
35772ee35494Smrg    int err;
35782ee35494Smrg
35792ee35494Smrg    snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min);
35802ee35494Smrg
35812ee35494Smrg    value = sysfs_uevent_get(path, "OF_COMPATIBLE_N");
35822ee35494Smrg    if (!value)
35832ee35494Smrg        return -ENOENT;
35842ee35494Smrg
35852ee35494Smrg    sscanf(value, "%u", &count);
35862ee35494Smrg    free(value);
35872ee35494Smrg
35882ee35494Smrg    info->compatible = calloc(count + 1, sizeof(*info->compatible));
35892ee35494Smrg    if (!info->compatible)
35902ee35494Smrg        return -ENOMEM;
35912ee35494Smrg
35922ee35494Smrg    for (i = 0; i < count; i++) {
35932ee35494Smrg        value = sysfs_uevent_get(path, "OF_COMPATIBLE_%u", i);
35942ee35494Smrg        if (!value) {
35952ee35494Smrg            err = -ENOENT;
35962ee35494Smrg            goto free;
35972ee35494Smrg        }
35982ee35494Smrg
35992ee35494Smrg        info->compatible[i] = value;
36002ee35494Smrg    }
36012ee35494Smrg
36022ee35494Smrg    return 0;
36032ee35494Smrg
36042ee35494Smrgfree:
36052ee35494Smrg    while (i--)
36062ee35494Smrg        free(info->compatible[i]);
36072ee35494Smrg
36082ee35494Smrg    free(info->compatible);
36092ee35494Smrg    return err;
36102ee35494Smrg#else
36112ee35494Smrg#warning "Missing implementation of drmParseHost1xDeviceInfo"
36122ee35494Smrg    return -EINVAL;
36132ee35494Smrg#endif
36142ee35494Smrg}
36152ee35494Smrg
36162ee35494Smrgstatic int drmProcessHost1xDevice(drmDevicePtr *device,
36172ee35494Smrg                                  const char *node, int node_type,
36182ee35494Smrg                                  int maj, int min, bool fetch_deviceinfo,
36192ee35494Smrg                                  uint32_t flags)
36202ee35494Smrg{
36212ee35494Smrg    drmDevicePtr dev;
36222ee35494Smrg    char *ptr;
36232ee35494Smrg    int ret;
36242ee35494Smrg
36252ee35494Smrg    dev = drmDeviceAlloc(node_type, node, sizeof(drmHost1xBusInfo),
36262ee35494Smrg                         sizeof(drmHost1xDeviceInfo), &ptr);
36272ee35494Smrg    if (!dev)
36282ee35494Smrg        return -ENOMEM;
36292ee35494Smrg
36302ee35494Smrg    dev->bustype = DRM_BUS_HOST1X;
36312ee35494Smrg
36322ee35494Smrg    dev->businfo.host1x = (drmHost1xBusInfoPtr)ptr;
36332ee35494Smrg
36342ee35494Smrg    ret = drmParseHost1xBusInfo(maj, min, dev->businfo.host1x);
36352ee35494Smrg    if (ret < 0)
36362ee35494Smrg        goto free_device;
36372ee35494Smrg
36382ee35494Smrg    if (fetch_deviceinfo) {
36392ee35494Smrg        ptr += sizeof(drmHost1xBusInfo);
36402ee35494Smrg        dev->deviceinfo.host1x = (drmHost1xDeviceInfoPtr)ptr;
36412ee35494Smrg
36422ee35494Smrg        ret = drmParseHost1xDeviceInfo(maj, min, dev->deviceinfo.host1x);
36432ee35494Smrg        if (ret < 0)
36442ee35494Smrg            goto free_device;
36452ee35494Smrg    }
36462ee35494Smrg
36472ee35494Smrg    *device = dev;
36482ee35494Smrg
36492ee35494Smrg    return 0;
36502ee35494Smrg
36512ee35494Smrgfree_device:
36522ee35494Smrg    free(dev);
3653fe517fc9Smrg    return ret;
3654fe517fc9Smrg}
3655fe517fc9Smrg
3656fe517fc9Smrg/* Consider devices located on the same bus as duplicate and fold the respective
3657fe517fc9Smrg * entries into a single one.
3658fe517fc9Smrg *
3659fe517fc9Smrg * Note: this leaves "gaps" in the array, while preserving the length.
3660fe517fc9Smrg */
3661fe517fc9Smrgstatic void drmFoldDuplicatedDevices(drmDevicePtr local_devices[], int count)
3662fe517fc9Smrg{
3663fe517fc9Smrg    int node_type, i, j;
3664fe517fc9Smrg
3665fe517fc9Smrg    for (i = 0; i < count; i++) {
3666fe517fc9Smrg        for (j = i + 1; j < count; j++) {
3667fe517fc9Smrg            if (drmCompareBusInfo(local_devices[i], local_devices[j]) == 0) {
3668fe517fc9Smrg                local_devices[i]->available_nodes |= local_devices[j]->available_nodes;
3669fe517fc9Smrg                node_type = log2(local_devices[j]->available_nodes);
3670fe517fc9Smrg                memcpy(local_devices[i]->nodes[node_type],
3671fe517fc9Smrg                       local_devices[j]->nodes[node_type], drmGetMaxNodeName());
3672fe517fc9Smrg                drmFreeDevice(&local_devices[j]);
3673fe517fc9Smrg            }
3674fe517fc9Smrg        }
3675fe517fc9Smrg    }
3676fe517fc9Smrg}
3677fe517fc9Smrg
36782ee35494Smrg/* Check that the given flags are valid returning 0 on success */
36792ee35494Smrgstatic int
36802ee35494Smrgdrm_device_validate_flags(uint32_t flags)
36812ee35494Smrg{
36822ee35494Smrg        return (flags & ~DRM_DEVICE_GET_PCI_REVISION);
36832ee35494Smrg}
36842ee35494Smrg
3685fe517fc9Smrg/**
3686fe517fc9Smrg * Get information about the opened drm device
3687fe517fc9Smrg *
3688fe517fc9Smrg * \param fd file descriptor of the drm device
36892ee35494Smrg * \param flags feature/behaviour bitmask
3690fe517fc9Smrg * \param device the address of a drmDevicePtr where the information
3691fe517fc9Smrg *               will be allocated in stored
3692fe517fc9Smrg *
3693fe517fc9Smrg * \return zero on success, negative error code otherwise.
36942ee35494Smrg *
36952ee35494Smrg * \note Unlike drmGetDevice it does not retrieve the pci device revision field
36962ee35494Smrg * unless the DRM_DEVICE_GET_PCI_REVISION \p flag is set.
3697fe517fc9Smrg */
36982ee35494Smrgint drmGetDevice2(int fd, uint32_t flags, drmDevicePtr *device)
3699fe517fc9Smrg{
37002ee35494Smrg#ifdef __OpenBSD__
37012ee35494Smrg    /*
37022ee35494Smrg     * DRI device nodes on OpenBSD are not in their own directory, they reside
37032ee35494Smrg     * in /dev along with a large number of statically generated /dev nodes.
37042ee35494Smrg     * Avoid stat'ing all of /dev needlessly by implementing this custom path.
37052ee35494Smrg     */
37062ee35494Smrg    drmDevicePtr     d;
37072ee35494Smrg    struct stat      sbuf;
37082ee35494Smrg    char             node[PATH_MAX + 1];
37092ee35494Smrg    const char      *dev_name;
37102ee35494Smrg    int              node_type, subsystem_type;
37112ee35494Smrg    int              maj, min, n, ret, base;
37122ee35494Smrg
37132ee35494Smrg    if (fd == -1 || device == NULL)
37142ee35494Smrg        return -EINVAL;
37152ee35494Smrg
37162ee35494Smrg    if (fstat(fd, &sbuf))
37172ee35494Smrg        return -errno;
37182ee35494Smrg
37192ee35494Smrg    maj = major(sbuf.st_rdev);
37202ee35494Smrg    min = minor(sbuf.st_rdev);
37212ee35494Smrg
37222ee35494Smrg    if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode))
37232ee35494Smrg        return -EINVAL;
37242ee35494Smrg
37252ee35494Smrg    node_type = drmGetMinorType(min);
37262ee35494Smrg    if (node_type == -1)
37272ee35494Smrg        return -ENODEV;
37282ee35494Smrg
37292ee35494Smrg    switch (node_type) {
37302ee35494Smrg    case DRM_NODE_PRIMARY:
37312ee35494Smrg        dev_name = DRM_DEV_NAME;
37322ee35494Smrg        break;
37332ee35494Smrg    case DRM_NODE_CONTROL:
37342ee35494Smrg        dev_name = DRM_CONTROL_DEV_NAME;
37352ee35494Smrg        break;
37362ee35494Smrg    case DRM_NODE_RENDER:
37372ee35494Smrg        dev_name = DRM_RENDER_DEV_NAME;
37382ee35494Smrg        break;
37392ee35494Smrg    default:
37402ee35494Smrg        return -EINVAL;
37412ee35494Smrg    };
37422ee35494Smrg
37432ee35494Smrg    base = drmGetMinorBase(node_type);
37442ee35494Smrg    if (base < 0)
37452ee35494Smrg        return -EINVAL;
37462ee35494Smrg
37472ee35494Smrg    n = snprintf(node, PATH_MAX, dev_name, DRM_DIR_NAME, min - base);
37482ee35494Smrg    if (n == -1 || n >= PATH_MAX)
37492ee35494Smrg      return -errno;
37502ee35494Smrg    if (stat(node, &sbuf))
37512ee35494Smrg        return -EINVAL;
37522ee35494Smrg
37532ee35494Smrg    subsystem_type = drmParseSubsystemType(maj, min);
37542ee35494Smrg    if (subsystem_type != DRM_BUS_PCI)
37552ee35494Smrg        return -ENODEV;
37562ee35494Smrg
37572ee35494Smrg    ret = drmProcessPciDevice(&d, node, node_type, maj, min, true, flags);
37582ee35494Smrg    if (ret)
37592ee35494Smrg        return ret;
37602ee35494Smrg
37612ee35494Smrg    *device = d;
37622ee35494Smrg
37632ee35494Smrg    return 0;
37642ee35494Smrg#else
3765fe517fc9Smrg    drmDevicePtr *local_devices;
3766fe517fc9Smrg    drmDevicePtr d;
3767fe517fc9Smrg    DIR *sysdir;
3768fe517fc9Smrg    struct dirent *dent;
3769fe517fc9Smrg    struct stat sbuf;
3770fe517fc9Smrg    char node[PATH_MAX + 1];
3771fe517fc9Smrg    int node_type, subsystem_type;
3772fe517fc9Smrg    int maj, min;
3773fe517fc9Smrg    int ret, i, node_count;
3774fe517fc9Smrg    int max_count = 16;
3775fe517fc9Smrg    dev_t find_rdev;
3776fe517fc9Smrg
37772ee35494Smrg    if (drm_device_validate_flags(flags))
37782ee35494Smrg        return -EINVAL;
37792ee35494Smrg
3780fe517fc9Smrg    if (fd == -1 || device == NULL)
3781fe517fc9Smrg        return -EINVAL;
3782fe517fc9Smrg
3783fe517fc9Smrg    if (fstat(fd, &sbuf))
3784fe517fc9Smrg        return -errno;
3785fe517fc9Smrg
3786fe517fc9Smrg    find_rdev = sbuf.st_rdev;
3787fe517fc9Smrg    maj = major(sbuf.st_rdev);
3788fe517fc9Smrg    min = minor(sbuf.st_rdev);
3789fe517fc9Smrg
3790fe517fc9Smrg    if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode))
3791fe517fc9Smrg        return -EINVAL;
3792fe517fc9Smrg
3793fe517fc9Smrg    subsystem_type = drmParseSubsystemType(maj, min);
3794fe517fc9Smrg
3795fe517fc9Smrg    local_devices = calloc(max_count, sizeof(drmDevicePtr));
3796fe517fc9Smrg    if (local_devices == NULL)
3797fe517fc9Smrg        return -ENOMEM;
3798fe517fc9Smrg
3799fe517fc9Smrg    sysdir = opendir(DRM_DIR_NAME);
3800fe517fc9Smrg    if (!sysdir) {
3801fe517fc9Smrg        ret = -errno;
3802fe517fc9Smrg        goto free_locals;
3803fe517fc9Smrg    }
3804fe517fc9Smrg
3805fe517fc9Smrg    i = 0;
3806fe517fc9Smrg    while ((dent = readdir(sysdir))) {
3807fe517fc9Smrg        node_type = drmGetNodeType(dent->d_name);
3808fe517fc9Smrg        if (node_type < 0)
3809fe517fc9Smrg            continue;
3810fe517fc9Smrg
3811fe517fc9Smrg        snprintf(node, PATH_MAX, "%s/%s", DRM_DIR_NAME, dent->d_name);
3812fe517fc9Smrg        if (stat(node, &sbuf))
3813fe517fc9Smrg            continue;
3814fe517fc9Smrg
3815fe517fc9Smrg        maj = major(sbuf.st_rdev);
3816fe517fc9Smrg        min = minor(sbuf.st_rdev);
3817fe517fc9Smrg
3818fe517fc9Smrg        if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode))
3819fe517fc9Smrg            continue;
3820fe517fc9Smrg
3821fe517fc9Smrg        if (drmParseSubsystemType(maj, min) != subsystem_type)
3822fe517fc9Smrg            continue;
3823fe517fc9Smrg
3824fe517fc9Smrg        switch (subsystem_type) {
3825fe517fc9Smrg        case DRM_BUS_PCI:
38262ee35494Smrg            ret = drmProcessPciDevice(&d, node, node_type, maj, min, true, flags);
3827fe517fc9Smrg            if (ret)
38282ee35494Smrg                continue;
38292ee35494Smrg
38302ee35494Smrg            break;
38312ee35494Smrg
38322ee35494Smrg        case DRM_BUS_USB:
38332ee35494Smrg            ret = drmProcessUsbDevice(&d, node, node_type, maj, min, true, flags);
38342ee35494Smrg            if (ret)
38352ee35494Smrg                continue;
38362ee35494Smrg
38372ee35494Smrg            break;
38382ee35494Smrg
38392ee35494Smrg        case DRM_BUS_PLATFORM:
38402ee35494Smrg            ret = drmProcessPlatformDevice(&d, node, node_type, maj, min, true, flags);
38412ee35494Smrg            if (ret)
38422ee35494Smrg                continue;
38432ee35494Smrg
38442ee35494Smrg            break;
38452ee35494Smrg
38462ee35494Smrg        case DRM_BUS_HOST1X:
38472ee35494Smrg            ret = drmProcessHost1xDevice(&d, node, node_type, maj, min, true, flags);
38482ee35494Smrg            if (ret)
38492ee35494Smrg                continue;
3850fe517fc9Smrg
3851fe517fc9Smrg            break;
38522ee35494Smrg
3853fe517fc9Smrg        default:
3854fe517fc9Smrg            continue;
3855fe517fc9Smrg        }
3856fe517fc9Smrg
3857fe517fc9Smrg        if (i >= max_count) {
3858fe517fc9Smrg            drmDevicePtr *temp;
3859fe517fc9Smrg
3860fe517fc9Smrg            max_count += 16;
3861fe517fc9Smrg            temp = realloc(local_devices, max_count * sizeof(drmDevicePtr));
3862fe517fc9Smrg            if (!temp)
3863fe517fc9Smrg                goto free_devices;
3864fe517fc9Smrg            local_devices = temp;
3865fe517fc9Smrg        }
3866fe517fc9Smrg
3867fe517fc9Smrg        /* store target at local_devices[0] for ease to use below */
3868fe517fc9Smrg        if (find_rdev == sbuf.st_rdev && i) {
3869fe517fc9Smrg            local_devices[i] = local_devices[0];
3870fe517fc9Smrg            local_devices[0] = d;
3871fe517fc9Smrg        }
3872fe517fc9Smrg        else
3873fe517fc9Smrg            local_devices[i] = d;
3874fe517fc9Smrg        i++;
3875fe517fc9Smrg    }
3876fe517fc9Smrg    node_count = i;
3877fe517fc9Smrg
3878fe517fc9Smrg    drmFoldDuplicatedDevices(local_devices, node_count);
3879fe517fc9Smrg
3880fe517fc9Smrg    *device = local_devices[0];
3881fe517fc9Smrg    drmFreeDevices(&local_devices[1], node_count - 1);
3882fe517fc9Smrg
3883fe517fc9Smrg    closedir(sysdir);
3884fe517fc9Smrg    free(local_devices);
38852ee35494Smrg    if (*device == NULL)
38862ee35494Smrg        return -ENODEV;
3887fe517fc9Smrg    return 0;
3888fe517fc9Smrg
3889fe517fc9Smrgfree_devices:
3890fe517fc9Smrg    drmFreeDevices(local_devices, i);
3891fe517fc9Smrg    closedir(sysdir);
3892fe517fc9Smrg
3893fe517fc9Smrgfree_locals:
3894fe517fc9Smrg    free(local_devices);
3895fe517fc9Smrg    return ret;
38962ee35494Smrg#endif
38972ee35494Smrg}
38982ee35494Smrg
38992ee35494Smrg/**
39002ee35494Smrg * Get information about the opened drm device
39012ee35494Smrg *
39022ee35494Smrg * \param fd file descriptor of the drm device
39032ee35494Smrg * \param device the address of a drmDevicePtr where the information
39042ee35494Smrg *               will be allocated in stored
39052ee35494Smrg *
39062ee35494Smrg * \return zero on success, negative error code otherwise.
39072ee35494Smrg */
39082ee35494Smrgint drmGetDevice(int fd, drmDevicePtr *device)
39092ee35494Smrg{
39102ee35494Smrg    return drmGetDevice2(fd, DRM_DEVICE_GET_PCI_REVISION, device);
3911fe517fc9Smrg}
3912fe517fc9Smrg
3913fe517fc9Smrg/**
3914fe517fc9Smrg * Get drm devices on the system
3915fe517fc9Smrg *
39162ee35494Smrg * \param flags feature/behaviour bitmask
3917fe517fc9Smrg * \param devices the array of devices with drmDevicePtr elements
3918fe517fc9Smrg *                can be NULL to get the device number first
3919fe517fc9Smrg * \param max_devices the maximum number of devices for the array
3920fe517fc9Smrg *
3921fe517fc9Smrg * \return on error - negative error code,
3922fe517fc9Smrg *         if devices is NULL - total number of devices available on the system,
3923fe517fc9Smrg *         alternatively the number of devices stored in devices[], which is
3924fe517fc9Smrg *         capped by the max_devices.
39252ee35494Smrg *
39262ee35494Smrg * \note Unlike drmGetDevices it does not retrieve the pci device revision field
39272ee35494Smrg * unless the DRM_DEVICE_GET_PCI_REVISION \p flag is set.
3928fe517fc9Smrg */
39292ee35494Smrgint drmGetDevices2(uint32_t flags, drmDevicePtr devices[], int max_devices)
3930fe517fc9Smrg{
3931fe517fc9Smrg    drmDevicePtr *local_devices;
3932fe517fc9Smrg    drmDevicePtr device;
3933fe517fc9Smrg    DIR *sysdir;
3934fe517fc9Smrg    struct dirent *dent;
3935fe517fc9Smrg    struct stat sbuf;
3936fe517fc9Smrg    char node[PATH_MAX + 1];
3937fe517fc9Smrg    int node_type, subsystem_type;
3938fe517fc9Smrg    int maj, min;
3939fe517fc9Smrg    int ret, i, node_count, device_count;
3940fe517fc9Smrg    int max_count = 16;
3941fe517fc9Smrg
39422ee35494Smrg    if (drm_device_validate_flags(flags))
39432ee35494Smrg        return -EINVAL;
39442ee35494Smrg
3945fe517fc9Smrg    local_devices = calloc(max_count, sizeof(drmDevicePtr));
3946fe517fc9Smrg    if (local_devices == NULL)
3947fe517fc9Smrg        return -ENOMEM;
3948fe517fc9Smrg
3949fe517fc9Smrg    sysdir = opendir(DRM_DIR_NAME);
3950fe517fc9Smrg    if (!sysdir) {
3951fe517fc9Smrg        ret = -errno;
3952fe517fc9Smrg        goto free_locals;
3953fe517fc9Smrg    }
3954fe517fc9Smrg
3955fe517fc9Smrg    i = 0;
3956fe517fc9Smrg    while ((dent = readdir(sysdir))) {
3957fe517fc9Smrg        node_type = drmGetNodeType(dent->d_name);
3958fe517fc9Smrg        if (node_type < 0)
3959fe517fc9Smrg            continue;
3960fe517fc9Smrg
3961fe517fc9Smrg        snprintf(node, PATH_MAX, "%s/%s", DRM_DIR_NAME, dent->d_name);
3962fe517fc9Smrg        if (stat(node, &sbuf))
3963fe517fc9Smrg            continue;
3964fe517fc9Smrg
3965fe517fc9Smrg        maj = major(sbuf.st_rdev);
3966fe517fc9Smrg        min = minor(sbuf.st_rdev);
3967fe517fc9Smrg
3968fe517fc9Smrg        if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode))
3969fe517fc9Smrg            continue;
3970fe517fc9Smrg
3971fe517fc9Smrg        subsystem_type = drmParseSubsystemType(maj, min);
3972fe517fc9Smrg
3973fe517fc9Smrg        if (subsystem_type < 0)
3974fe517fc9Smrg            continue;
3975fe517fc9Smrg
3976fe517fc9Smrg        switch (subsystem_type) {
3977fe517fc9Smrg        case DRM_BUS_PCI:
39782ee35494Smrg            ret = drmProcessPciDevice(&device, node, node_type,
39792ee35494Smrg                                      maj, min, devices != NULL, flags);
39802ee35494Smrg            if (ret)
39812ee35494Smrg                continue;
39822ee35494Smrg
39832ee35494Smrg            break;
39842ee35494Smrg
39852ee35494Smrg        case DRM_BUS_USB:
39862ee35494Smrg            ret = drmProcessUsbDevice(&device, node, node_type, maj, min,
39872ee35494Smrg                                      devices != NULL, flags);
3988fe517fc9Smrg            if (ret)
3989fe517fc9Smrg                goto free_devices;
3990fe517fc9Smrg
3991fe517fc9Smrg            break;
39922ee35494Smrg
39932ee35494Smrg        case DRM_BUS_PLATFORM:
39942ee35494Smrg            ret = drmProcessPlatformDevice(&device, node, node_type, maj, min,
39952ee35494Smrg                                           devices != NULL, flags);
39962ee35494Smrg            if (ret)
39972ee35494Smrg                goto free_devices;
39982ee35494Smrg
39992ee35494Smrg            break;
40002ee35494Smrg
40012ee35494Smrg        case DRM_BUS_HOST1X:
40022ee35494Smrg            ret = drmProcessHost1xDevice(&device, node, node_type, maj, min,
40032ee35494Smrg                                         devices != NULL, flags);
40042ee35494Smrg            if (ret)
40052ee35494Smrg                goto free_devices;
40062ee35494Smrg
40072ee35494Smrg            break;
40082ee35494Smrg
4009fe517fc9Smrg        default:
4010fe517fc9Smrg            continue;
4011fe517fc9Smrg        }
4012fe517fc9Smrg
4013fe517fc9Smrg        if (i >= max_count) {
4014fe517fc9Smrg            drmDevicePtr *temp;
4015fe517fc9Smrg
4016fe517fc9Smrg            max_count += 16;
4017fe517fc9Smrg            temp = realloc(local_devices, max_count * sizeof(drmDevicePtr));
4018fe517fc9Smrg            if (!temp)
4019fe517fc9Smrg                goto free_devices;
4020fe517fc9Smrg            local_devices = temp;
4021fe517fc9Smrg        }
4022fe517fc9Smrg
4023fe517fc9Smrg        local_devices[i] = device;
4024fe517fc9Smrg        i++;
4025fe517fc9Smrg    }
4026fe517fc9Smrg    node_count = i;
4027fe517fc9Smrg
4028fe517fc9Smrg    drmFoldDuplicatedDevices(local_devices, node_count);
4029fe517fc9Smrg
4030fe517fc9Smrg    device_count = 0;
4031fe517fc9Smrg    for (i = 0; i < node_count; i++) {
4032fe517fc9Smrg        if (!local_devices[i])
4033fe517fc9Smrg            continue;
4034fe517fc9Smrg
4035fe517fc9Smrg        if ((devices != NULL) && (device_count < max_devices))
4036fe517fc9Smrg            devices[device_count] = local_devices[i];
4037fe517fc9Smrg        else
4038fe517fc9Smrg            drmFreeDevice(&local_devices[i]);
4039fe517fc9Smrg
4040fe517fc9Smrg        device_count++;
4041fe517fc9Smrg    }
4042fe517fc9Smrg
4043fe517fc9Smrg    closedir(sysdir);
4044fe517fc9Smrg    free(local_devices);
4045fe517fc9Smrg    return device_count;
4046fe517fc9Smrg
4047fe517fc9Smrgfree_devices:
4048fe517fc9Smrg    drmFreeDevices(local_devices, i);
4049fe517fc9Smrg    closedir(sysdir);
4050fe517fc9Smrg
4051fe517fc9Smrgfree_locals:
4052fe517fc9Smrg    free(local_devices);
4053fe517fc9Smrg    return ret;
4054424e9256Smrg}
40552ee35494Smrg
40562ee35494Smrg/**
40572ee35494Smrg * Get drm devices on the system
40582ee35494Smrg *
40592ee35494Smrg * \param devices the array of devices with drmDevicePtr elements
40602ee35494Smrg *                can be NULL to get the device number first
40612ee35494Smrg * \param max_devices the maximum number of devices for the array
40622ee35494Smrg *
40632ee35494Smrg * \return on error - negative error code,
40642ee35494Smrg *         if devices is NULL - total number of devices available on the system,
40652ee35494Smrg *         alternatively the number of devices stored in devices[], which is
40662ee35494Smrg *         capped by the max_devices.
40672ee35494Smrg */
40682ee35494Smrgint drmGetDevices(drmDevicePtr devices[], int max_devices)
40692ee35494Smrg{
40702ee35494Smrg    return drmGetDevices2(DRM_DEVICE_GET_PCI_REVISION, devices, max_devices);
40712ee35494Smrg}
40722ee35494Smrg
40732ee35494Smrgchar *drmGetDeviceNameFromFd2(int fd)
40742ee35494Smrg{
40752ee35494Smrg#ifdef __linux__
40762ee35494Smrg    struct stat sbuf;
40772ee35494Smrg    char path[PATH_MAX + 1], *value;
40782ee35494Smrg    unsigned int maj, min;
40792ee35494Smrg
40802ee35494Smrg    if (fstat(fd, &sbuf))
40812ee35494Smrg        return NULL;
40822ee35494Smrg
40832ee35494Smrg    maj = major(sbuf.st_rdev);
40842ee35494Smrg    min = minor(sbuf.st_rdev);
40852ee35494Smrg
40862ee35494Smrg    if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode))
40872ee35494Smrg        return NULL;
40882ee35494Smrg
40892ee35494Smrg    snprintf(path, sizeof(path), "/sys/dev/char/%d:%d", maj, min);
40902ee35494Smrg
40912ee35494Smrg    value = sysfs_uevent_get(path, "DEVNAME");
40922ee35494Smrg    if (!value)
40932ee35494Smrg        return NULL;
40942ee35494Smrg
40952ee35494Smrg    snprintf(path, sizeof(path), "/dev/%s", value);
40962ee35494Smrg    free(value);
40972ee35494Smrg
40982ee35494Smrg    return strdup(path);
40992ee35494Smrg#else
41002ee35494Smrg    struct stat      sbuf;
41012ee35494Smrg    char             node[PATH_MAX + 1];
41022ee35494Smrg    const char      *dev_name;
41032ee35494Smrg    int              node_type;
41042ee35494Smrg    int              maj, min, n, base;
41052ee35494Smrg
41062ee35494Smrg    if (fstat(fd, &sbuf))
41072ee35494Smrg        return NULL;
41082ee35494Smrg
41092ee35494Smrg    maj = major(sbuf.st_rdev);
41102ee35494Smrg    min = minor(sbuf.st_rdev);
41112ee35494Smrg
41122ee35494Smrg    if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode))
41132ee35494Smrg        return NULL;
41142ee35494Smrg
41152ee35494Smrg    node_type = drmGetMinorType(min);
41162ee35494Smrg    if (node_type == -1)
41172ee35494Smrg        return NULL;
41182ee35494Smrg
41192ee35494Smrg    switch (node_type) {
41202ee35494Smrg    case DRM_NODE_PRIMARY:
41212ee35494Smrg        dev_name = DRM_DEV_NAME;
41222ee35494Smrg        break;
41232ee35494Smrg    case DRM_NODE_CONTROL:
41242ee35494Smrg        dev_name = DRM_CONTROL_DEV_NAME;
41252ee35494Smrg        break;
41262ee35494Smrg    case DRM_NODE_RENDER:
41272ee35494Smrg        dev_name = DRM_RENDER_DEV_NAME;
41282ee35494Smrg        break;
41292ee35494Smrg    default:
41302ee35494Smrg        return NULL;
41312ee35494Smrg    };
41322ee35494Smrg
41332ee35494Smrg    base = drmGetMinorBase(node_type);
41342ee35494Smrg    if (base < 0)
41352ee35494Smrg        return NULL;
41362ee35494Smrg
41372ee35494Smrg    n = snprintf(node, PATH_MAX, dev_name, DRM_DIR_NAME, min - base);
41382ee35494Smrg    if (n == -1 || n >= PATH_MAX)
41392ee35494Smrg      return NULL;
41402ee35494Smrg
41412ee35494Smrg    return strdup(node);
41422ee35494Smrg#endif
41432ee35494Smrg}
4144