xf86drm.c revision 11c53d23
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
6522944501Smrg
6622944501Smrg#include "xf86drm.h"
67424e9256Smrg#include "libdrm_macros.h"
6822944501Smrg
69fe517fc9Smrg#include "util_math.h"
70fe517fc9Smrg
71fe517fc9Smrg#ifdef __OpenBSD__
72fe517fc9Smrg#define DRM_PRIMARY_MINOR_NAME  "drm"
73fe517fc9Smrg#define DRM_CONTROL_MINOR_NAME  "drmC"
74fe517fc9Smrg#define DRM_RENDER_MINOR_NAME   "drmR"
75fe517fc9Smrg#else
76fe517fc9Smrg#define DRM_PRIMARY_MINOR_NAME  "card"
77fe517fc9Smrg#define DRM_CONTROL_MINOR_NAME  "controlD"
78fe517fc9Smrg#define DRM_RENDER_MINOR_NAME   "renderD"
79fe517fc9Smrg#endif
80fe517fc9Smrg
8122944501Smrg#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
8222944501Smrg#define DRM_MAJOR 145
8322944501Smrg#endif
8422944501Smrg
8522944501Smrg#ifdef __NetBSD__
862e6867f6Smrg#undef DRM_MAJOR
872e6867f6Smrg#define DRM_MAJOR 180
8822944501Smrg#endif
8922944501Smrg
90fe517fc9Smrg#ifdef __OpenBSD__
91fe517fc9Smrg#ifdef __i386__
92fe517fc9Smrg#define DRM_MAJOR 88
93fe517fc9Smrg#else
94fe517fc9Smrg#define DRM_MAJOR 87
9522944501Smrg#endif
96fe517fc9Smrg#endif /* __OpenBSD__ */
9722944501Smrg
98fe517fc9Smrg#ifndef DRM_MAJOR
99fe517fc9Smrg#define DRM_MAJOR 226 /* Linux */
10022944501Smrg#endif
10122944501Smrg
10211c53d23Schristos/* Not all systems have MAP_FAILED defined */
10311c53d23Schristos#ifndef MAP_FAILED
10411c53d23Schristos#define MAP_FAILED ((void *)-1)
10511c53d23Schristos#endif
10611c53d23Schristos
10722944501Smrg#define DRM_MSG_VERBOSITY 3
10822944501Smrg
109424e9256Smrg#define memclear(s) memset(&s, 0, sizeof(s))
11022944501Smrg
11122944501Smrgstatic drmServerInfoPtr drm_server_info;
11222944501Smrg
11322944501Smrgvoid drmSetServerInfo(drmServerInfoPtr info)
11422944501Smrg{
11522944501Smrg    drm_server_info = info;
11622944501Smrg}
11722944501Smrg
11822944501Smrg/**
11922944501Smrg * Output a message to stderr.
12022944501Smrg *
12122944501Smrg * \param format printf() like format string.
12222944501Smrg *
12322944501Smrg * \internal
12422944501Smrg * This function is a wrapper around vfprintf().
12522944501Smrg */
12622944501Smrg
127a7d7de1eSmrgstatic int DRM_PRINTFLIKE(1, 0)
128a7d7de1eSmrgdrmDebugPrint(const char *format, va_list ap)
12922944501Smrg{
13022944501Smrg    return vfprintf(stderr, format, ap);
13122944501Smrg}
13222944501Smrg
13322944501Smrgvoid
13422944501SmrgdrmMsg(const char *format, ...)
13522944501Smrg{
136fe517fc9Smrg    va_list ap;
13722944501Smrg    const char *env;
138fe517fc9Smrg    if (((env = getenv("LIBGL_DEBUG")) && strstr(env, "verbose")) ||
139fe517fc9Smrg        (drm_server_info && drm_server_info->debug_print))
14022944501Smrg    {
141fe517fc9Smrg        va_start(ap, format);
142fe517fc9Smrg        if (drm_server_info) {
143fe517fc9Smrg            drm_server_info->debug_print(format,ap);
144fe517fc9Smrg        } else {
145fe517fc9Smrg            drmDebugPrint(format, ap);
146fe517fc9Smrg        }
147fe517fc9Smrg        va_end(ap);
14822944501Smrg    }
14922944501Smrg}
15022944501Smrg
15122944501Smrgstatic void *drmHashTable = NULL; /* Context switch callbacks */
15222944501Smrg
15322944501Smrgvoid *drmGetHashTable(void)
15422944501Smrg{
15522944501Smrg    return drmHashTable;
15622944501Smrg}
15722944501Smrg
15822944501Smrgvoid *drmMalloc(int size)
15922944501Smrg{
160424e9256Smrg    return calloc(1, size);
16122944501Smrg}
16222944501Smrg
16322944501Smrgvoid drmFree(void *pt)
16422944501Smrg{
165424e9256Smrg    free(pt);
16622944501Smrg}
16722944501Smrg
16822944501Smrg/**
16922944501Smrg * Call ioctl, restarting if it is interupted
17022944501Smrg */
17122944501Smrgint
17222944501SmrgdrmIoctl(int fd, unsigned long request, void *arg)
17322944501Smrg{
174fe517fc9Smrg    int ret;
17522944501Smrg
17622944501Smrg    do {
177fe517fc9Smrg        ret = ioctl(fd, request, arg);
17822944501Smrg    } while (ret == -1 && (errno == EINTR || errno == EAGAIN));
17922944501Smrg    return ret;
18022944501Smrg}
18122944501Smrg
18222944501Smrgstatic unsigned long drmGetKeyFromFd(int fd)
18322944501Smrg{
18422944501Smrg    stat_t     st;
18522944501Smrg
18622944501Smrg    st.st_rdev = 0;
18722944501Smrg    fstat(fd, &st);
18822944501Smrg    return st.st_rdev;
18922944501Smrg}
19022944501Smrg
19122944501SmrgdrmHashEntry *drmGetEntry(int fd)
19222944501Smrg{
19322944501Smrg    unsigned long key = drmGetKeyFromFd(fd);
19422944501Smrg    void          *value;
19522944501Smrg    drmHashEntry  *entry;
19622944501Smrg
19722944501Smrg    if (!drmHashTable)
198fe517fc9Smrg        drmHashTable = drmHashCreate();
19922944501Smrg
20022944501Smrg    if (drmHashLookup(drmHashTable, key, &value)) {
201fe517fc9Smrg        entry           = drmMalloc(sizeof(*entry));
202fe517fc9Smrg        entry->fd       = fd;
203fe517fc9Smrg        entry->f        = NULL;
204fe517fc9Smrg        entry->tagTable = drmHashCreate();
205fe517fc9Smrg        drmHashInsert(drmHashTable, key, entry);
20622944501Smrg    } else {
207fe517fc9Smrg        entry = value;
20822944501Smrg    }
20922944501Smrg    return entry;
21022944501Smrg}
21122944501Smrg
21222944501Smrg/**
21322944501Smrg * Compare two busid strings
21422944501Smrg *
21522944501Smrg * \param first
21622944501Smrg * \param second
21722944501Smrg *
21822944501Smrg * \return 1 if matched.
21922944501Smrg *
22022944501Smrg * \internal
22122944501Smrg * This function compares two bus ID strings.  It understands the older
22222944501Smrg * PCI:b:d:f format and the newer pci:oooo:bb:dd.f format.  In the format, o is
22322944501Smrg * domain, b is bus, d is device, f is function.
22422944501Smrg */
2256d98c517Smrgstatic int drmMatchBusID(const char *id1, const char *id2, int pci_domain_ok)
22622944501Smrg{
22722944501Smrg    /* First, check if the IDs are exactly the same */
22822944501Smrg    if (strcasecmp(id1, id2) == 0)
229fe517fc9Smrg        return 1;
23022944501Smrg
23122944501Smrg    /* Try to match old/new-style PCI bus IDs. */
23222944501Smrg    if (strncasecmp(id1, "pci", 3) == 0) {
233fe517fc9Smrg        unsigned int o1, b1, d1, f1;
234fe517fc9Smrg        unsigned int o2, b2, d2, f2;
235fe517fc9Smrg        int ret;
236fe517fc9Smrg
237fe517fc9Smrg        ret = sscanf(id1, "pci:%04x:%02x:%02x.%u", &o1, &b1, &d1, &f1);
238fe517fc9Smrg        if (ret != 4) {
239fe517fc9Smrg            o1 = 0;
240fe517fc9Smrg            ret = sscanf(id1, "PCI:%u:%u:%u", &b1, &d1, &f1);
241fe517fc9Smrg            if (ret != 3)
242fe517fc9Smrg                return 0;
243fe517fc9Smrg        }
244fe517fc9Smrg
245fe517fc9Smrg        ret = sscanf(id2, "pci:%04x:%02x:%02x.%u", &o2, &b2, &d2, &f2);
246fe517fc9Smrg        if (ret != 4) {
247fe517fc9Smrg            o2 = 0;
248fe517fc9Smrg            ret = sscanf(id2, "PCI:%u:%u:%u", &b2, &d2, &f2);
249fe517fc9Smrg            if (ret != 3)
250fe517fc9Smrg                return 0;
251fe517fc9Smrg        }
252fe517fc9Smrg
253fe517fc9Smrg        /* If domains aren't properly supported by the kernel interface,
254fe517fc9Smrg         * just ignore them, which sucks less than picking a totally random
255fe517fc9Smrg         * card with "open by name"
256fe517fc9Smrg         */
257fe517fc9Smrg        if (!pci_domain_ok)
258fe517fc9Smrg            o1 = o2 = 0;
259fe517fc9Smrg
260fe517fc9Smrg        if ((o1 != o2) || (b1 != b2) || (d1 != d2) || (f1 != f2))
261fe517fc9Smrg            return 0;
262fe517fc9Smrg        else
263fe517fc9Smrg            return 1;
26422944501Smrg    }
26522944501Smrg    return 0;
26622944501Smrg}
26722944501Smrg
26822944501Smrg/**
26922944501Smrg * Handles error checking for chown call.
27022944501Smrg *
27122944501Smrg * \param path to file.
27222944501Smrg * \param id of the new owner.
27322944501Smrg * \param id of the new group.
27422944501Smrg *
27522944501Smrg * \return zero if success or -1 if failure.
27622944501Smrg *
27722944501Smrg * \internal
27822944501Smrg * Checks for failure. If failure was caused by signal call chown again.
27922944501Smrg * If any other failure happened then it will output error mesage using
28022944501Smrg * drmMsg() call.
28122944501Smrg */
282424e9256Smrg#if !defined(UDEV)
28322944501Smrgstatic int chown_check_return(const char *path, uid_t owner, gid_t group)
28422944501Smrg{
285fe517fc9Smrg        int rv;
28622944501Smrg
287fe517fc9Smrg        do {
288fe517fc9Smrg            rv = chown(path, owner, group);
289fe517fc9Smrg        } while (rv != 0 && errno == EINTR);
29022944501Smrg
291fe517fc9Smrg        if (rv == 0)
292fe517fc9Smrg            return 0;
29322944501Smrg
294fe517fc9Smrg        drmMsg("Failed to change owner or group for file %s! %d: %s\n",
295fe517fc9Smrg               path, errno, strerror(errno));
296fe517fc9Smrg        return -1;
29722944501Smrg}
298424e9256Smrg#endif
29922944501Smrg
30022944501Smrg/**
30122944501Smrg * Open the DRM device, creating it if necessary.
30222944501Smrg *
30322944501Smrg * \param dev major and minor numbers of the device.
30422944501Smrg * \param minor minor number of the device.
305fe517fc9Smrg *
30622944501Smrg * \return a file descriptor on success, or a negative value on error.
30722944501Smrg *
30822944501Smrg * \internal
30922944501Smrg * Assembles the device name from \p minor and opens it, creating the device
31022944501Smrg * special file node with the major and minor numbers specified by \p dev and
31122944501Smrg * parent directory if necessary and was called by root.
31222944501Smrg */
313424e9256Smrgstatic int drmOpenDevice(dev_t dev, int minor, int type)
31422944501Smrg{
31522944501Smrg    stat_t          st;
316424e9256Smrg    const char      *dev_name;
31722944501Smrg    char            buf[64];
31822944501Smrg    int             fd;
31922944501Smrg    mode_t          devmode = DRM_DEV_MODE, serv_mode;
320424e9256Smrg    gid_t           serv_group;
321424e9256Smrg#if !defined(UDEV)
32222944501Smrg    int             isroot  = !geteuid();
32322944501Smrg    uid_t           user    = DRM_DEV_UID;
324424e9256Smrg    gid_t           group   = DRM_DEV_GID;
325424e9256Smrg#endif
326424e9256Smrg
327424e9256Smrg    switch (type) {
328424e9256Smrg    case DRM_NODE_PRIMARY:
329fe517fc9Smrg        dev_name = DRM_DEV_NAME;
330fe517fc9Smrg        break;
331424e9256Smrg    case DRM_NODE_CONTROL:
332fe517fc9Smrg        dev_name = DRM_CONTROL_DEV_NAME;
333fe517fc9Smrg        break;
334424e9256Smrg    case DRM_NODE_RENDER:
335fe517fc9Smrg        dev_name = DRM_RENDER_DEV_NAME;
336fe517fc9Smrg        break;
337424e9256Smrg    default:
338fe517fc9Smrg        return -EINVAL;
339424e9256Smrg    };
340424e9256Smrg
341424e9256Smrg    sprintf(buf, dev_name, DRM_DIR_NAME, minor);
34222944501Smrg    drmMsg("drmOpenDevice: node name is %s\n", buf);
34322944501Smrg
344fe517fc9Smrg    if (drm_server_info && drm_server_info->get_perms) {
345fe517fc9Smrg        drm_server_info->get_perms(&serv_group, &serv_mode);
346fe517fc9Smrg        devmode  = serv_mode ? serv_mode : DRM_DEV_MODE;
347fe517fc9Smrg        devmode &= ~(S_IXUSR|S_IXGRP|S_IXOTH);
34822944501Smrg    }
34922944501Smrg
35022944501Smrg#if !defined(UDEV)
35122944501Smrg    if (stat(DRM_DIR_NAME, &st)) {
352fe517fc9Smrg        if (!isroot)
353fe517fc9Smrg            return DRM_ERR_NOT_ROOT;
354fe517fc9Smrg        mkdir(DRM_DIR_NAME, DRM_DEV_DIRMODE);
355fe517fc9Smrg        chown_check_return(DRM_DIR_NAME, 0, 0); /* root:root */
356fe517fc9Smrg        chmod(DRM_DIR_NAME, DRM_DEV_DIRMODE);
35722944501Smrg    }
35822944501Smrg
35922944501Smrg    /* Check if the device node exists and create it if necessary. */
36022944501Smrg    if (stat(buf, &st)) {
361fe517fc9Smrg        if (!isroot)
362fe517fc9Smrg            return DRM_ERR_NOT_ROOT;
363fe517fc9Smrg        remove(buf);
364fe517fc9Smrg        mknod(buf, S_IFCHR | devmode, dev);
36522944501Smrg    }
36622944501Smrg
367fe517fc9Smrg    if (drm_server_info && drm_server_info->get_perms) {
368fe517fc9Smrg        group = ((int)serv_group >= 0) ? serv_group : DRM_DEV_GID;
369fe517fc9Smrg        chown_check_return(buf, user, group);
370fe517fc9Smrg        chmod(buf, devmode);
37122944501Smrg    }
37222944501Smrg#else
37322944501Smrg    /* if we modprobed then wait for udev */
37422944501Smrg    {
375fe517fc9Smrg        int udev_count = 0;
37622944501Smrgwait_for_udev:
37722944501Smrg        if (stat(DRM_DIR_NAME, &st)) {
378fe517fc9Smrg            usleep(20);
379fe517fc9Smrg            udev_count++;
380fe517fc9Smrg
381fe517fc9Smrg            if (udev_count == 50)
382fe517fc9Smrg                return -1;
383fe517fc9Smrg            goto wait_for_udev;
384fe517fc9Smrg        }
385fe517fc9Smrg
386fe517fc9Smrg        if (stat(buf, &st)) {
387fe517fc9Smrg            usleep(20);
388fe517fc9Smrg            udev_count++;
389fe517fc9Smrg
390fe517fc9Smrg            if (udev_count == 50)
391fe517fc9Smrg                return -1;
392fe517fc9Smrg            goto wait_for_udev;
393fe517fc9Smrg        }
39422944501Smrg    }
39522944501Smrg#endif
39622944501Smrg
39722944501Smrg    fd = open(buf, O_RDWR, 0);
39822944501Smrg    drmMsg("drmOpenDevice: open result is %d, (%s)\n",
399fe517fc9Smrg           fd, fd < 0 ? strerror(errno) : "OK");
40022944501Smrg    if (fd >= 0)
401fe517fc9Smrg        return fd;
40222944501Smrg
4039ce4edccSmrg#if !defined(UDEV)
40422944501Smrg    /* Check if the device node is not what we expect it to be, and recreate it
40522944501Smrg     * and try again if so.
40622944501Smrg     */
40722944501Smrg    if (st.st_rdev != dev) {
408fe517fc9Smrg        if (!isroot)
409fe517fc9Smrg            return DRM_ERR_NOT_ROOT;
410fe517fc9Smrg        remove(buf);
411fe517fc9Smrg        mknod(buf, S_IFCHR | devmode, dev);
412fe517fc9Smrg        if (drm_server_info && drm_server_info->get_perms) {
413fe517fc9Smrg            chown_check_return(buf, user, group);
414fe517fc9Smrg            chmod(buf, devmode);
415fe517fc9Smrg        }
41622944501Smrg    }
41722944501Smrg    fd = open(buf, O_RDWR, 0);
41822944501Smrg    drmMsg("drmOpenDevice: open result is %d, (%s)\n",
419fe517fc9Smrg           fd, fd < 0 ? strerror(errno) : "OK");
42022944501Smrg    if (fd >= 0)
421fe517fc9Smrg        return fd;
42222944501Smrg
42322944501Smrg    drmMsg("drmOpenDevice: Open failed\n");
42422944501Smrg    remove(buf);
4259ce4edccSmrg#endif
42622944501Smrg    return -errno;
42722944501Smrg}
42822944501Smrg
42922944501Smrg
43022944501Smrg/**
43122944501Smrg * Open the DRM device
43222944501Smrg *
43322944501Smrg * \param minor device minor number.
43422944501Smrg * \param create allow to create the device if set.
43522944501Smrg *
43622944501Smrg * \return a file descriptor on success, or a negative value on error.
437fe517fc9Smrg *
43822944501Smrg * \internal
43922944501Smrg * Calls drmOpenDevice() if \p create is set, otherwise assembles the device
44022944501Smrg * name from \p minor and opens it.
44122944501Smrg */
44222944501Smrgstatic int drmOpenMinor(int minor, int create, int type)
44322944501Smrg{
44422944501Smrg    int  fd;
44522944501Smrg    char buf[64];
446424e9256Smrg    const char *dev_name;
447fe517fc9Smrg
44822944501Smrg    if (create)
449fe517fc9Smrg        return drmOpenDevice(makedev(DRM_MAJOR, minor), minor, type);
450fe517fc9Smrg
451424e9256Smrg    switch (type) {
452424e9256Smrg    case DRM_NODE_PRIMARY:
453fe517fc9Smrg        dev_name = DRM_DEV_NAME;
454fe517fc9Smrg        break;
455424e9256Smrg    case DRM_NODE_CONTROL:
456fe517fc9Smrg        dev_name = DRM_CONTROL_DEV_NAME;
457fe517fc9Smrg        break;
458424e9256Smrg    case DRM_NODE_RENDER:
459fe517fc9Smrg        dev_name = DRM_RENDER_DEV_NAME;
460fe517fc9Smrg        break;
461424e9256Smrg    default:
462fe517fc9Smrg        return -EINVAL;
463424e9256Smrg    };
464424e9256Smrg
465424e9256Smrg    sprintf(buf, dev_name, DRM_DIR_NAME, minor);
46622944501Smrg    if ((fd = open(buf, O_RDWR, 0)) >= 0)
467fe517fc9Smrg        return fd;
46822944501Smrg    return -errno;
46922944501Smrg}
47022944501Smrg
47122944501Smrg
47222944501Smrg/**
47322944501Smrg * Determine whether the DRM kernel driver has been loaded.
474fe517fc9Smrg *
47522944501Smrg * \return 1 if the DRM driver is loaded, 0 otherwise.
47622944501Smrg *
477fe517fc9Smrg * \internal
47822944501Smrg * Determine the presence of the kernel driver by attempting to open the 0
47922944501Smrg * minor and get version information.  For backward compatibility with older
48022944501Smrg * Linux implementations, /proc/dri is also checked.
48122944501Smrg */
48222944501Smrgint drmAvailable(void)
48322944501Smrg{
48422944501Smrg    drmVersionPtr version;
48522944501Smrg    int           retval = 0;
48622944501Smrg    int           fd;
48722944501Smrg
488424e9256Smrg    if ((fd = drmOpenMinor(0, 1, DRM_NODE_PRIMARY)) < 0) {
48922944501Smrg#ifdef __linux__
490fe517fc9Smrg        /* Try proc for backward Linux compatibility */
491fe517fc9Smrg        if (!access("/proc/dri/0", R_OK))
492fe517fc9Smrg            return 1;
49322944501Smrg#endif
494fe517fc9Smrg        return 0;
49522944501Smrg    }
496fe517fc9Smrg
49722944501Smrg    if ((version = drmGetVersion(fd))) {
498fe517fc9Smrg        retval = 1;
499fe517fc9Smrg        drmFreeVersion(version);
50022944501Smrg    }
50122944501Smrg    close(fd);
50222944501Smrg
50322944501Smrg    return retval;
50422944501Smrg}
50522944501Smrg
506424e9256Smrgstatic int drmGetMinorBase(int type)
507424e9256Smrg{
508424e9256Smrg    switch (type) {
509424e9256Smrg    case DRM_NODE_PRIMARY:
510424e9256Smrg        return 0;
511424e9256Smrg    case DRM_NODE_CONTROL:
512424e9256Smrg        return 64;
513424e9256Smrg    case DRM_NODE_RENDER:
514424e9256Smrg        return 128;
515424e9256Smrg    default:
516424e9256Smrg        return -1;
517424e9256Smrg    };
518424e9256Smrg}
519424e9256Smrg
520424e9256Smrgstatic int drmGetMinorType(int minor)
521424e9256Smrg{
522424e9256Smrg    int type = minor >> 6;
523424e9256Smrg
524424e9256Smrg    if (minor < 0)
525424e9256Smrg        return -1;
526424e9256Smrg
527424e9256Smrg    switch (type) {
528424e9256Smrg    case DRM_NODE_PRIMARY:
529424e9256Smrg    case DRM_NODE_CONTROL:
530424e9256Smrg    case DRM_NODE_RENDER:
531424e9256Smrg        return type;
532424e9256Smrg    default:
533424e9256Smrg        return -1;
534424e9256Smrg    }
535424e9256Smrg}
536424e9256Smrg
537424e9256Smrgstatic const char *drmGetMinorName(int type)
538424e9256Smrg{
539424e9256Smrg    switch (type) {
540424e9256Smrg    case DRM_NODE_PRIMARY:
541fe517fc9Smrg        return DRM_PRIMARY_MINOR_NAME;
542424e9256Smrg    case DRM_NODE_CONTROL:
543fe517fc9Smrg        return DRM_CONTROL_MINOR_NAME;
544424e9256Smrg    case DRM_NODE_RENDER:
545fe517fc9Smrg        return DRM_RENDER_MINOR_NAME;
546424e9256Smrg    default:
547424e9256Smrg        return NULL;
548424e9256Smrg    }
549424e9256Smrg}
55022944501Smrg
55122944501Smrg/**
55222944501Smrg * Open the device by bus ID.
55322944501Smrg *
55422944501Smrg * \param busid bus ID.
555424e9256Smrg * \param type device node type.
55622944501Smrg *
55722944501Smrg * \return a file descriptor on success, or a negative value on error.
55822944501Smrg *
55922944501Smrg * \internal
56022944501Smrg * This function attempts to open every possible minor (up to DRM_MAX_MINOR),
56122944501Smrg * comparing the device bus ID with the one supplied.
56222944501Smrg *
56322944501Smrg * \sa drmOpenMinor() and drmGetBusid().
56422944501Smrg */
565424e9256Smrgstatic int drmOpenByBusid(const char *busid, int type)
56622944501Smrg{
5676d98c517Smrg    int        i, pci_domain_ok = 1;
56822944501Smrg    int        fd;
56922944501Smrg    const char *buf;
57022944501Smrg    drmSetVersion sv;
571424e9256Smrg    int        base = drmGetMinorBase(type);
572424e9256Smrg
573424e9256Smrg    if (base < 0)
574424e9256Smrg        return -1;
57522944501Smrg
57622944501Smrg    drmMsg("drmOpenByBusid: Searching for BusID %s\n", busid);
577424e9256Smrg    for (i = base; i < base + DRM_MAX_MINOR; i++) {
578fe517fc9Smrg        fd = drmOpenMinor(i, 1, type);
579fe517fc9Smrg        drmMsg("drmOpenByBusid: drmOpenMinor returns %d\n", fd);
580fe517fc9Smrg        if (fd >= 0) {
581fe517fc9Smrg            /* We need to try for 1.4 first for proper PCI domain support
582fe517fc9Smrg             * and if that fails, we know the kernel is busted
583fe517fc9Smrg             */
584fe517fc9Smrg            sv.drm_di_major = 1;
585fe517fc9Smrg            sv.drm_di_minor = 4;
586fe517fc9Smrg            sv.drm_dd_major = -1;        /* Don't care */
587fe517fc9Smrg            sv.drm_dd_minor = -1;        /* Don't care */
588fe517fc9Smrg            if (drmSetInterfaceVersion(fd, &sv)) {
5896d98c517Smrg#ifndef __alpha__
590fe517fc9Smrg                pci_domain_ok = 0;
5916d98c517Smrg#endif
592fe517fc9Smrg                sv.drm_di_major = 1;
593fe517fc9Smrg                sv.drm_di_minor = 1;
594fe517fc9Smrg                sv.drm_dd_major = -1;       /* Don't care */
595fe517fc9Smrg                sv.drm_dd_minor = -1;       /* Don't care */
596fe517fc9Smrg                drmMsg("drmOpenByBusid: Interface 1.4 failed, trying 1.1\n");
597fe517fc9Smrg                drmSetInterfaceVersion(fd, &sv);
598fe517fc9Smrg            }
599fe517fc9Smrg            buf = drmGetBusid(fd);
600fe517fc9Smrg            drmMsg("drmOpenByBusid: drmGetBusid reports %s\n", buf);
601fe517fc9Smrg            if (buf && drmMatchBusID(buf, busid, pci_domain_ok)) {
602fe517fc9Smrg                drmFreeBusid(buf);
603fe517fc9Smrg                return fd;
604fe517fc9Smrg            }
605fe517fc9Smrg            if (buf)
606fe517fc9Smrg                drmFreeBusid(buf);
607fe517fc9Smrg            close(fd);
608fe517fc9Smrg        }
60922944501Smrg    }
61022944501Smrg    return -1;
61122944501Smrg}
61222944501Smrg
61322944501Smrg
61422944501Smrg/**
61522944501Smrg * Open the device by name.
61622944501Smrg *
61722944501Smrg * \param name driver name.
618424e9256Smrg * \param type the device node type.
619fe517fc9Smrg *
62022944501Smrg * \return a file descriptor on success, or a negative value on error.
621fe517fc9Smrg *
62222944501Smrg * \internal
62322944501Smrg * This function opens the first minor number that matches the driver name and
62422944501Smrg * isn't already in use.  If it's in use it then it will already have a bus ID
62522944501Smrg * assigned.
626fe517fc9Smrg *
62722944501Smrg * \sa drmOpenMinor(), drmGetVersion() and drmGetBusid().
62822944501Smrg */
629424e9256Smrgstatic int drmOpenByName(const char *name, int type)
63022944501Smrg{
63122944501Smrg    int           i;
63222944501Smrg    int           fd;
63322944501Smrg    drmVersionPtr version;
63422944501Smrg    char *        id;
635424e9256Smrg    int           base = drmGetMinorBase(type);
636424e9256Smrg
637424e9256Smrg    if (base < 0)
638424e9256Smrg        return -1;
63922944501Smrg
64022944501Smrg    /*
64122944501Smrg     * Open the first minor number that matches the driver name and isn't
64222944501Smrg     * already in use.  If it's in use it will have a busid assigned already.
64322944501Smrg     */
644424e9256Smrg    for (i = base; i < base + DRM_MAX_MINOR; i++) {
645fe517fc9Smrg        if ((fd = drmOpenMinor(i, 1, type)) >= 0) {
646fe517fc9Smrg            if ((version = drmGetVersion(fd))) {
647fe517fc9Smrg                if (!strcmp(version->name, name)) {
648fe517fc9Smrg                    drmFreeVersion(version);
649fe517fc9Smrg                    id = drmGetBusid(fd);
650fe517fc9Smrg                    drmMsg("drmGetBusid returned '%s'\n", id ? id : "NULL");
651fe517fc9Smrg                    if (!id || !*id) {
652fe517fc9Smrg                        if (id)
653fe517fc9Smrg                            drmFreeBusid(id);
654fe517fc9Smrg                        return fd;
655fe517fc9Smrg                    } else {
656fe517fc9Smrg                        drmFreeBusid(id);
657fe517fc9Smrg                    }
658fe517fc9Smrg                } else {
659fe517fc9Smrg                    drmFreeVersion(version);
660fe517fc9Smrg                }
661fe517fc9Smrg            }
662fe517fc9Smrg            close(fd);
663fe517fc9Smrg        }
66422944501Smrg    }
66522944501Smrg
66622944501Smrg#ifdef __linux__
66722944501Smrg    /* Backward-compatibility /proc support */
66822944501Smrg    for (i = 0; i < 8; i++) {
669fe517fc9Smrg        char proc_name[64], buf[512];
670fe517fc9Smrg        char *driver, *pt, *devstring;
671fe517fc9Smrg        int  retcode;
672fe517fc9Smrg
673fe517fc9Smrg        sprintf(proc_name, "/proc/dri/%d/name", i);
674fe517fc9Smrg        if ((fd = open(proc_name, 0, 0)) >= 0) {
675fe517fc9Smrg            retcode = read(fd, buf, sizeof(buf)-1);
676fe517fc9Smrg            close(fd);
677fe517fc9Smrg            if (retcode) {
678fe517fc9Smrg                buf[retcode-1] = '\0';
679fe517fc9Smrg                for (driver = pt = buf; *pt && *pt != ' '; ++pt)
680fe517fc9Smrg                    ;
681fe517fc9Smrg                if (*pt) { /* Device is next */
682fe517fc9Smrg                    *pt = '\0';
683fe517fc9Smrg                    if (!strcmp(driver, name)) { /* Match */
684fe517fc9Smrg                        for (devstring = ++pt; *pt && *pt != ' '; ++pt)
685fe517fc9Smrg                            ;
686fe517fc9Smrg                        if (*pt) { /* Found busid */
687fe517fc9Smrg                            return drmOpenByBusid(++pt, type);
688fe517fc9Smrg                        } else { /* No busid */
689fe517fc9Smrg                            return drmOpenDevice(strtol(devstring, NULL, 0),i, type);
690fe517fc9Smrg                        }
691fe517fc9Smrg                    }
692fe517fc9Smrg                }
693fe517fc9Smrg            }
694fe517fc9Smrg        }
69522944501Smrg    }
69622944501Smrg#endif
69722944501Smrg
69822944501Smrg    return -1;
69922944501Smrg}
70022944501Smrg
70122944501Smrg
70222944501Smrg/**
70322944501Smrg * Open the DRM device.
70422944501Smrg *
70522944501Smrg * Looks up the specified name and bus ID, and opens the device found.  The
70622944501Smrg * entry in /dev/dri is created if necessary and if called by root.
70722944501Smrg *
70822944501Smrg * \param name driver name. Not referenced if bus ID is supplied.
70922944501Smrg * \param busid bus ID. Zero if not known.
710fe517fc9Smrg *
71122944501Smrg * \return a file descriptor on success, or a negative value on error.
712fe517fc9Smrg *
71322944501Smrg * \internal
71422944501Smrg * It calls drmOpenByBusid() if \p busid is specified or drmOpenByName()
71522944501Smrg * otherwise.
71622944501Smrg */
71722944501Smrgint drmOpen(const char *name, const char *busid)
718424e9256Smrg{
719424e9256Smrg    return drmOpenWithType(name, busid, DRM_NODE_PRIMARY);
720424e9256Smrg}
721424e9256Smrg
722424e9256Smrg/**
723424e9256Smrg * Open the DRM device with specified type.
724424e9256Smrg *
725424e9256Smrg * Looks up the specified name and bus ID, and opens the device found.  The
726424e9256Smrg * entry in /dev/dri is created if necessary and if called by root.
727424e9256Smrg *
728424e9256Smrg * \param name driver name. Not referenced if bus ID is supplied.
729424e9256Smrg * \param busid bus ID. Zero if not known.
730424e9256Smrg * \param type the device node type to open, PRIMARY, CONTROL or RENDER
731424e9256Smrg *
732424e9256Smrg * \return a file descriptor on success, or a negative value on error.
733424e9256Smrg *
734424e9256Smrg * \internal
735424e9256Smrg * It calls drmOpenByBusid() if \p busid is specified or drmOpenByName()
736424e9256Smrg * otherwise.
737424e9256Smrg */
738424e9256Smrgint drmOpenWithType(const char *name, const char *busid, int type)
73922944501Smrg{
740fe517fc9Smrg    if (!drmAvailable() && name != NULL && drm_server_info &&
741fe517fc9Smrg        drm_server_info->load_module) {
742fe517fc9Smrg        /* try to load the kernel module */
743fe517fc9Smrg        if (!drm_server_info->load_module(name)) {
744fe517fc9Smrg            drmMsg("[drm] failed to load kernel module \"%s\"\n", name);
745fe517fc9Smrg            return -1;
746fe517fc9Smrg        }
74722944501Smrg    }
74822944501Smrg
74922944501Smrg    if (busid) {
750fe517fc9Smrg        int fd = drmOpenByBusid(busid, type);
751fe517fc9Smrg        if (fd >= 0)
752fe517fc9Smrg            return fd;
75322944501Smrg    }
754fe517fc9Smrg
75522944501Smrg    if (name)
756fe517fc9Smrg        return drmOpenByName(name, type);
75722944501Smrg
75822944501Smrg    return -1;
75922944501Smrg}
76022944501Smrg
76122944501Smrgint drmOpenControl(int minor)
76222944501Smrg{
76322944501Smrg    return drmOpenMinor(minor, 0, DRM_NODE_CONTROL);
76422944501Smrg}
76522944501Smrg
766424e9256Smrgint drmOpenRender(int minor)
767424e9256Smrg{
768424e9256Smrg    return drmOpenMinor(minor, 0, DRM_NODE_RENDER);
769424e9256Smrg}
770424e9256Smrg
77122944501Smrg/**
77222944501Smrg * Free the version information returned by drmGetVersion().
77322944501Smrg *
77422944501Smrg * \param v pointer to the version information.
77522944501Smrg *
77622944501Smrg * \internal
77722944501Smrg * It frees the memory pointed by \p %v as well as all the non-null strings
77822944501Smrg * pointers in it.
77922944501Smrg */
78022944501Smrgvoid drmFreeVersion(drmVersionPtr v)
78122944501Smrg{
78222944501Smrg    if (!v)
783fe517fc9Smrg        return;
78422944501Smrg    drmFree(v->name);
78522944501Smrg    drmFree(v->date);
78622944501Smrg    drmFree(v->desc);
78722944501Smrg    drmFree(v);
78822944501Smrg}
78922944501Smrg
79022944501Smrg
79122944501Smrg/**
79222944501Smrg * Free the non-public version information returned by the kernel.
79322944501Smrg *
79422944501Smrg * \param v pointer to the version information.
79522944501Smrg *
79622944501Smrg * \internal
79722944501Smrg * Used by drmGetVersion() to free the memory pointed by \p %v as well as all
79822944501Smrg * the non-null strings pointers in it.
79922944501Smrg */
80022944501Smrgstatic void drmFreeKernelVersion(drm_version_t *v)
80122944501Smrg{
80222944501Smrg    if (!v)
803fe517fc9Smrg        return;
80422944501Smrg    drmFree(v->name);
80522944501Smrg    drmFree(v->date);
80622944501Smrg    drmFree(v->desc);
80722944501Smrg    drmFree(v);
80822944501Smrg}
80922944501Smrg
81022944501Smrg
81122944501Smrg/**
81222944501Smrg * Copy version information.
813fe517fc9Smrg *
81422944501Smrg * \param d destination pointer.
81522944501Smrg * \param s source pointer.
816fe517fc9Smrg *
81722944501Smrg * \internal
81822944501Smrg * Used by drmGetVersion() to translate the information returned by the ioctl
81922944501Smrg * interface in a private structure into the public structure counterpart.
82022944501Smrg */
82122944501Smrgstatic void drmCopyVersion(drmVersionPtr d, const drm_version_t *s)
82222944501Smrg{
82322944501Smrg    d->version_major      = s->version_major;
82422944501Smrg    d->version_minor      = s->version_minor;
82522944501Smrg    d->version_patchlevel = s->version_patchlevel;
82622944501Smrg    d->name_len           = s->name_len;
8279ce4edccSmrg    d->name               = strdup(s->name);
82822944501Smrg    d->date_len           = s->date_len;
8299ce4edccSmrg    d->date               = strdup(s->date);
83022944501Smrg    d->desc_len           = s->desc_len;
8319ce4edccSmrg    d->desc               = strdup(s->desc);
83222944501Smrg}
83322944501Smrg
83422944501Smrg
83522944501Smrg/**
83622944501Smrg * Query the driver version information.
83722944501Smrg *
83822944501Smrg * \param fd file descriptor.
839fe517fc9Smrg *
84022944501Smrg * \return pointer to a drmVersion structure which should be freed with
84122944501Smrg * drmFreeVersion().
842fe517fc9Smrg *
84322944501Smrg * \note Similar information is available via /proc/dri.
844fe517fc9Smrg *
84522944501Smrg * \internal
84622944501Smrg * It gets the version information via successive DRM_IOCTL_VERSION ioctls,
84722944501Smrg * first with zeros to get the string lengths, and then the actually strings.
84822944501Smrg * It also null-terminates them since they might not be already.
84922944501Smrg */
85022944501SmrgdrmVersionPtr drmGetVersion(int fd)
85122944501Smrg{
85222944501Smrg    drmVersionPtr retval;
85322944501Smrg    drm_version_t *version = drmMalloc(sizeof(*version));
85422944501Smrg
855424e9256Smrg    memclear(*version);
85622944501Smrg
85722944501Smrg    if (drmIoctl(fd, DRM_IOCTL_VERSION, version)) {
858fe517fc9Smrg        drmFreeKernelVersion(version);
859fe517fc9Smrg        return NULL;
86022944501Smrg    }
86122944501Smrg
86222944501Smrg    if (version->name_len)
863fe517fc9Smrg        version->name    = drmMalloc(version->name_len + 1);
86422944501Smrg    if (version->date_len)
865fe517fc9Smrg        version->date    = drmMalloc(version->date_len + 1);
86622944501Smrg    if (version->desc_len)
867fe517fc9Smrg        version->desc    = drmMalloc(version->desc_len + 1);
86822944501Smrg
86922944501Smrg    if (drmIoctl(fd, DRM_IOCTL_VERSION, version)) {
870fe517fc9Smrg        drmMsg("DRM_IOCTL_VERSION: %s\n", strerror(errno));
871fe517fc9Smrg        drmFreeKernelVersion(version);
872fe517fc9Smrg        return NULL;
87322944501Smrg    }
87422944501Smrg
87522944501Smrg    /* The results might not be null-terminated strings, so terminate them. */
87622944501Smrg    if (version->name_len) version->name[version->name_len] = '\0';
87722944501Smrg    if (version->date_len) version->date[version->date_len] = '\0';
87822944501Smrg    if (version->desc_len) version->desc[version->desc_len] = '\0';
87922944501Smrg
88022944501Smrg    retval = drmMalloc(sizeof(*retval));
88122944501Smrg    drmCopyVersion(retval, version);
88222944501Smrg    drmFreeKernelVersion(version);
88322944501Smrg    return retval;
88422944501Smrg}
88522944501Smrg
88622944501Smrg
88722944501Smrg/**
88822944501Smrg * Get version information for the DRM user space library.
889fe517fc9Smrg *
89022944501Smrg * This version number is driver independent.
891fe517fc9Smrg *
89222944501Smrg * \param fd file descriptor.
89322944501Smrg *
89422944501Smrg * \return version information.
895fe517fc9Smrg *
89622944501Smrg * \internal
89722944501Smrg * This function allocates and fills a drm_version structure with a hard coded
89822944501Smrg * version number.
89922944501Smrg */
90022944501SmrgdrmVersionPtr drmGetLibVersion(int fd)
90122944501Smrg{
90222944501Smrg    drm_version_t *version = drmMalloc(sizeof(*version));
90322944501Smrg
90422944501Smrg    /* Version history:
90522944501Smrg     *   NOTE THIS MUST NOT GO ABOVE VERSION 1.X due to drivers needing it
90622944501Smrg     *   revision 1.0.x = original DRM interface with no drmGetLibVersion
90722944501Smrg     *                    entry point and many drm<Device> extensions
90822944501Smrg     *   revision 1.1.x = added drmCommand entry points for device extensions
90922944501Smrg     *                    added drmGetLibVersion to identify libdrm.a version
91022944501Smrg     *   revision 1.2.x = added drmSetInterfaceVersion
91122944501Smrg     *                    modified drmOpen to handle both busid and name
91222944501Smrg     *   revision 1.3.x = added server + memory manager
91322944501Smrg     */
91422944501Smrg    version->version_major      = 1;
91522944501Smrg    version->version_minor      = 3;
91622944501Smrg    version->version_patchlevel = 0;
91722944501Smrg
91822944501Smrg    return (drmVersionPtr)version;
91922944501Smrg}
92022944501Smrg
92120131375Smrgint drmGetCap(int fd, uint64_t capability, uint64_t *value)
92220131375Smrg{
923fe517fc9Smrg    struct drm_get_cap cap;
924fe517fc9Smrg    int ret;
92520131375Smrg
926fe517fc9Smrg    memclear(cap);
927fe517fc9Smrg    cap.capability = capability;
928424e9256Smrg
929fe517fc9Smrg    ret = drmIoctl(fd, DRM_IOCTL_GET_CAP, &cap);
930fe517fc9Smrg    if (ret)
931fe517fc9Smrg        return ret;
93220131375Smrg
933fe517fc9Smrg    *value = cap.value;
934fe517fc9Smrg    return 0;
93520131375Smrg}
93620131375Smrg
93720131375Smrgint drmSetClientCap(int fd, uint64_t capability, uint64_t value)
93820131375Smrg{
939fe517fc9Smrg    struct drm_set_client_cap cap;
940424e9256Smrg
941fe517fc9Smrg    memclear(cap);
942fe517fc9Smrg    cap.capability = capability;
943fe517fc9Smrg    cap.value = value;
94420131375Smrg
945fe517fc9Smrg    return drmIoctl(fd, DRM_IOCTL_SET_CLIENT_CAP, &cap);
94620131375Smrg}
94722944501Smrg
94822944501Smrg/**
94922944501Smrg * Free the bus ID information.
95022944501Smrg *
95122944501Smrg * \param busid bus ID information string as given by drmGetBusid().
95222944501Smrg *
95322944501Smrg * \internal
95422944501Smrg * This function is just frees the memory pointed by \p busid.
95522944501Smrg */
95622944501Smrgvoid drmFreeBusid(const char *busid)
95722944501Smrg{
95822944501Smrg    drmFree((void *)busid);
95922944501Smrg}
96022944501Smrg
96122944501Smrg
96222944501Smrg/**
96322944501Smrg * Get the bus ID of the device.
96422944501Smrg *
96522944501Smrg * \param fd file descriptor.
96622944501Smrg *
96722944501Smrg * \return bus ID string.
96822944501Smrg *
96922944501Smrg * \internal
97022944501Smrg * This function gets the bus ID via successive DRM_IOCTL_GET_UNIQUE ioctls to
97122944501Smrg * get the string length and data, passing the arguments in a drm_unique
97222944501Smrg * structure.
97322944501Smrg */
97422944501Smrgchar *drmGetBusid(int fd)
97522944501Smrg{
97622944501Smrg    drm_unique_t u;
97722944501Smrg
978424e9256Smrg    memclear(u);
97922944501Smrg
98022944501Smrg    if (drmIoctl(fd, DRM_IOCTL_GET_UNIQUE, &u))
981fe517fc9Smrg        return NULL;
98222944501Smrg    u.unique = drmMalloc(u.unique_len + 1);
98322944501Smrg    if (drmIoctl(fd, DRM_IOCTL_GET_UNIQUE, &u))
984fe517fc9Smrg        return NULL;
98522944501Smrg    u.unique[u.unique_len] = '\0';
98622944501Smrg
98722944501Smrg    return u.unique;
98822944501Smrg}
98922944501Smrg
99022944501Smrg
99122944501Smrg/**
99222944501Smrg * Set the bus ID of the device.
99322944501Smrg *
99422944501Smrg * \param fd file descriptor.
99522944501Smrg * \param busid bus ID string.
99622944501Smrg *
99722944501Smrg * \return zero on success, negative on failure.
99822944501Smrg *
99922944501Smrg * \internal
100022944501Smrg * This function is a wrapper around the DRM_IOCTL_SET_UNIQUE ioctl, passing
100122944501Smrg * the arguments in a drm_unique structure.
100222944501Smrg */
100322944501Smrgint drmSetBusid(int fd, const char *busid)
100422944501Smrg{
100522944501Smrg    drm_unique_t u;
100622944501Smrg
1007424e9256Smrg    memclear(u);
100822944501Smrg    u.unique     = (char *)busid;
100922944501Smrg    u.unique_len = strlen(busid);
101022944501Smrg
101122944501Smrg    if (drmIoctl(fd, DRM_IOCTL_SET_UNIQUE, &u)) {
1012fe517fc9Smrg        return -errno;
101322944501Smrg    }
101422944501Smrg    return 0;
101522944501Smrg}
101622944501Smrg
101722944501Smrgint drmGetMagic(int fd, drm_magic_t * magic)
101822944501Smrg{
101922944501Smrg    drm_auth_t auth;
102022944501Smrg
1021424e9256Smrg    memclear(auth);
1022424e9256Smrg
102322944501Smrg    *magic = 0;
102422944501Smrg    if (drmIoctl(fd, DRM_IOCTL_GET_MAGIC, &auth))
1025fe517fc9Smrg        return -errno;
102622944501Smrg    *magic = auth.magic;
102722944501Smrg    return 0;
102822944501Smrg}
102922944501Smrg
103022944501Smrgint drmAuthMagic(int fd, drm_magic_t magic)
103122944501Smrg{
103222944501Smrg    drm_auth_t auth;
103322944501Smrg
1034424e9256Smrg    memclear(auth);
103522944501Smrg    auth.magic = magic;
103622944501Smrg    if (drmIoctl(fd, DRM_IOCTL_AUTH_MAGIC, &auth))
1037fe517fc9Smrg        return -errno;
103822944501Smrg    return 0;
103922944501Smrg}
104022944501Smrg
104122944501Smrg/**
104222944501Smrg * Specifies a range of memory that is available for mapping by a
104322944501Smrg * non-root process.
104422944501Smrg *
104522944501Smrg * \param fd file descriptor.
104622944501Smrg * \param offset usually the physical address. The actual meaning depends of
104722944501Smrg * the \p type parameter. See below.
104822944501Smrg * \param size of the memory in bytes.
104922944501Smrg * \param type type of the memory to be mapped.
105022944501Smrg * \param flags combination of several flags to modify the function actions.
105122944501Smrg * \param handle will be set to a value that may be used as the offset
105222944501Smrg * parameter for mmap().
1053fe517fc9Smrg *
105422944501Smrg * \return zero on success or a negative value on error.
105522944501Smrg *
105622944501Smrg * \par Mapping the frame buffer
105722944501Smrg * For the frame buffer
105822944501Smrg * - \p offset will be the physical address of the start of the frame buffer,
105922944501Smrg * - \p size will be the size of the frame buffer in bytes, and
106022944501Smrg * - \p type will be DRM_FRAME_BUFFER.
106122944501Smrg *
106222944501Smrg * \par
106322944501Smrg * The area mapped will be uncached. If MTRR support is available in the
1064fe517fc9Smrg * kernel, the frame buffer area will be set to write combining.
106522944501Smrg *
106622944501Smrg * \par Mapping the MMIO register area
106722944501Smrg * For the MMIO register area,
106822944501Smrg * - \p offset will be the physical address of the start of the register area,
106922944501Smrg * - \p size will be the size of the register area bytes, and
107022944501Smrg * - \p type will be DRM_REGISTERS.
107122944501Smrg * \par
1072fe517fc9Smrg * The area mapped will be uncached.
1073fe517fc9Smrg *
107422944501Smrg * \par Mapping the SAREA
107522944501Smrg * For the SAREA,
107622944501Smrg * - \p offset will be ignored and should be set to zero,
107722944501Smrg * - \p size will be the desired size of the SAREA in bytes,
107822944501Smrg * - \p type will be DRM_SHM.
1079fe517fc9Smrg *
108022944501Smrg * \par
108122944501Smrg * A shared memory area of the requested size will be created and locked in
108222944501Smrg * kernel memory. This area may be mapped into client-space by using the handle
1083fe517fc9Smrg * returned.
1084fe517fc9Smrg *
108522944501Smrg * \note May only be called by root.
108622944501Smrg *
108722944501Smrg * \internal
108822944501Smrg * This function is a wrapper around the DRM_IOCTL_ADD_MAP ioctl, passing
108922944501Smrg * the arguments in a drm_map structure.
109022944501Smrg */
109122944501Smrgint drmAddMap(int fd, drm_handle_t offset, drmSize size, drmMapType type,
1092fe517fc9Smrg              drmMapFlags flags, drm_handle_t *handle)
109322944501Smrg{
109422944501Smrg    drm_map_t map;
109522944501Smrg
1096424e9256Smrg    memclear(map);
109722944501Smrg    map.offset  = offset;
109822944501Smrg    map.size    = size;
109922944501Smrg    map.type    = type;
110022944501Smrg    map.flags   = flags;
110122944501Smrg    if (drmIoctl(fd, DRM_IOCTL_ADD_MAP, &map))
1102fe517fc9Smrg        return -errno;
110322944501Smrg    if (handle)
1104fe517fc9Smrg        *handle = (drm_handle_t)(uintptr_t)map.handle;
110522944501Smrg    return 0;
110622944501Smrg}
110722944501Smrg
110822944501Smrgint drmRmMap(int fd, drm_handle_t handle)
110922944501Smrg{
111022944501Smrg    drm_map_t map;
111122944501Smrg
1112424e9256Smrg    memclear(map);
111320131375Smrg    map.handle = (void *)(uintptr_t)handle;
111422944501Smrg
111522944501Smrg    if(drmIoctl(fd, DRM_IOCTL_RM_MAP, &map))
1116fe517fc9Smrg        return -errno;
111722944501Smrg    return 0;
111822944501Smrg}
111922944501Smrg
112022944501Smrg/**
112122944501Smrg * Make buffers available for DMA transfers.
1122fe517fc9Smrg *
112322944501Smrg * \param fd file descriptor.
112422944501Smrg * \param count number of buffers.
112522944501Smrg * \param size size of each buffer.
112622944501Smrg * \param flags buffer allocation flags.
1127fe517fc9Smrg * \param agp_offset offset in the AGP aperture
112822944501Smrg *
112922944501Smrg * \return number of buffers allocated, negative on error.
113022944501Smrg *
113122944501Smrg * \internal
113222944501Smrg * This function is a wrapper around DRM_IOCTL_ADD_BUFS ioctl.
113322944501Smrg *
113422944501Smrg * \sa drm_buf_desc.
113522944501Smrg */
113622944501Smrgint drmAddBufs(int fd, int count, int size, drmBufDescFlags flags,
1137fe517fc9Smrg               int agp_offset)
113822944501Smrg{
113922944501Smrg    drm_buf_desc_t request;
114022944501Smrg
1141424e9256Smrg    memclear(request);
114222944501Smrg    request.count     = count;
114322944501Smrg    request.size      = size;
114422944501Smrg    request.flags     = flags;
114522944501Smrg    request.agp_start = agp_offset;
114622944501Smrg
114722944501Smrg    if (drmIoctl(fd, DRM_IOCTL_ADD_BUFS, &request))
1148fe517fc9Smrg        return -errno;
114922944501Smrg    return request.count;
115022944501Smrg}
115122944501Smrg
115222944501Smrgint drmMarkBufs(int fd, double low, double high)
115322944501Smrg{
115422944501Smrg    drm_buf_info_t info;
115522944501Smrg    int            i;
115622944501Smrg
1157424e9256Smrg    memclear(info);
115822944501Smrg
115922944501Smrg    if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info))
1160fe517fc9Smrg        return -EINVAL;
116122944501Smrg
116222944501Smrg    if (!info.count)
1163fe517fc9Smrg        return -EINVAL;
116422944501Smrg
116522944501Smrg    if (!(info.list = drmMalloc(info.count * sizeof(*info.list))))
1166fe517fc9Smrg        return -ENOMEM;
116722944501Smrg
116822944501Smrg    if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info)) {
1169fe517fc9Smrg        int retval = -errno;
1170fe517fc9Smrg        drmFree(info.list);
1171fe517fc9Smrg        return retval;
117222944501Smrg    }
117322944501Smrg
117422944501Smrg    for (i = 0; i < info.count; i++) {
1175fe517fc9Smrg        info.list[i].low_mark  = low  * info.list[i].count;
1176fe517fc9Smrg        info.list[i].high_mark = high * info.list[i].count;
1177fe517fc9Smrg        if (drmIoctl(fd, DRM_IOCTL_MARK_BUFS, &info.list[i])) {
1178fe517fc9Smrg            int retval = -errno;
1179fe517fc9Smrg            drmFree(info.list);
1180fe517fc9Smrg            return retval;
1181fe517fc9Smrg        }
118222944501Smrg    }
118322944501Smrg    drmFree(info.list);
118422944501Smrg
118522944501Smrg    return 0;
118622944501Smrg}
118722944501Smrg
118822944501Smrg/**
118922944501Smrg * Free buffers.
119022944501Smrg *
119122944501Smrg * \param fd file descriptor.
119222944501Smrg * \param count number of buffers to free.
119322944501Smrg * \param list list of buffers to be freed.
119422944501Smrg *
119522944501Smrg * \return zero on success, or a negative value on failure.
1196fe517fc9Smrg *
119722944501Smrg * \note This function is primarily used for debugging.
1198fe517fc9Smrg *
119922944501Smrg * \internal
120022944501Smrg * This function is a wrapper around the DRM_IOCTL_FREE_BUFS ioctl, passing
120122944501Smrg * the arguments in a drm_buf_free structure.
120222944501Smrg */
120322944501Smrgint drmFreeBufs(int fd, int count, int *list)
120422944501Smrg{
120522944501Smrg    drm_buf_free_t request;
120622944501Smrg
1207424e9256Smrg    memclear(request);
120822944501Smrg    request.count = count;
120922944501Smrg    request.list  = list;
121022944501Smrg    if (drmIoctl(fd, DRM_IOCTL_FREE_BUFS, &request))
1211fe517fc9Smrg        return -errno;
121222944501Smrg    return 0;
121322944501Smrg}
121422944501Smrg
121522944501Smrg
121622944501Smrg/**
121722944501Smrg * Close the device.
121822944501Smrg *
121922944501Smrg * \param fd file descriptor.
122022944501Smrg *
122122944501Smrg * \internal
122222944501Smrg * This function closes the file descriptor.
122322944501Smrg */
122422944501Smrgint drmClose(int fd)
122522944501Smrg{
122622944501Smrg    unsigned long key    = drmGetKeyFromFd(fd);
122722944501Smrg    drmHashEntry  *entry = drmGetEntry(fd);
122822944501Smrg
122922944501Smrg    drmHashDestroy(entry->tagTable);
123022944501Smrg    entry->fd       = 0;
123122944501Smrg    entry->f        = NULL;
123222944501Smrg    entry->tagTable = NULL;
123322944501Smrg
123422944501Smrg    drmHashDelete(drmHashTable, key);
123522944501Smrg    drmFree(entry);
123622944501Smrg
123722944501Smrg    return close(fd);
123822944501Smrg}
123922944501Smrg
124022944501Smrg
124122944501Smrg/**
124222944501Smrg * Map a region of memory.
124322944501Smrg *
124422944501Smrg * \param fd file descriptor.
124522944501Smrg * \param handle handle returned by drmAddMap().
124622944501Smrg * \param size size in bytes. Must match the size used by drmAddMap().
124722944501Smrg * \param address will contain the user-space virtual address where the mapping
124822944501Smrg * begins.
124922944501Smrg *
125022944501Smrg * \return zero on success, or a negative value on failure.
1251fe517fc9Smrg *
125222944501Smrg * \internal
125322944501Smrg * This function is a wrapper for mmap().
125422944501Smrg */
125522944501Smrgint drmMap(int fd, drm_handle_t handle, drmSize size, drmAddressPtr address)
125622944501Smrg{
125722944501Smrg    static unsigned long pagesize_mask = 0;
125822944501Smrg
125922944501Smrg    if (fd < 0)
1260fe517fc9Smrg        return -EINVAL;
126122944501Smrg
126222944501Smrg    if (!pagesize_mask)
1263fe517fc9Smrg        pagesize_mask = getpagesize() - 1;
126422944501Smrg
126522944501Smrg    size = (size + pagesize_mask) & ~pagesize_mask;
126622944501Smrg
1267a884aba1Smrg    *address = drm_mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, handle);
126822944501Smrg    if (*address == MAP_FAILED)
1269fe517fc9Smrg        return -errno;
127022944501Smrg    return 0;
127122944501Smrg}
127222944501Smrg
127322944501Smrg
127422944501Smrg/**
127522944501Smrg * Unmap mappings obtained with drmMap().
127622944501Smrg *
127722944501Smrg * \param address address as given by drmMap().
127822944501Smrg * \param size size in bytes. Must match the size used by drmMap().
1279fe517fc9Smrg *
128022944501Smrg * \return zero on success, or a negative value on failure.
128122944501Smrg *
128222944501Smrg * \internal
128322944501Smrg * This function is a wrapper for munmap().
128422944501Smrg */
128522944501Smrgint drmUnmap(drmAddress address, drmSize size)
128622944501Smrg{
1287a884aba1Smrg    return drm_munmap(address, size);
128822944501Smrg}
128922944501Smrg
129022944501SmrgdrmBufInfoPtr drmGetBufInfo(int fd)
129122944501Smrg{
129222944501Smrg    drm_buf_info_t info;
129322944501Smrg    drmBufInfoPtr  retval;
129422944501Smrg    int            i;
129522944501Smrg
1296424e9256Smrg    memclear(info);
129722944501Smrg
129822944501Smrg    if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info))
1299fe517fc9Smrg        return NULL;
130022944501Smrg
130122944501Smrg    if (info.count) {
1302fe517fc9Smrg        if (!(info.list = drmMalloc(info.count * sizeof(*info.list))))
1303fe517fc9Smrg            return NULL;
1304fe517fc9Smrg
1305fe517fc9Smrg        if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info)) {
1306fe517fc9Smrg            drmFree(info.list);
1307fe517fc9Smrg            return NULL;
1308fe517fc9Smrg        }
1309fe517fc9Smrg
1310fe517fc9Smrg        retval = drmMalloc(sizeof(*retval));
1311fe517fc9Smrg        retval->count = info.count;
1312fe517fc9Smrg        retval->list  = drmMalloc(info.count * sizeof(*retval->list));
1313fe517fc9Smrg        for (i = 0; i < info.count; i++) {
1314fe517fc9Smrg            retval->list[i].count     = info.list[i].count;
1315fe517fc9Smrg            retval->list[i].size      = info.list[i].size;
1316fe517fc9Smrg            retval->list[i].low_mark  = info.list[i].low_mark;
1317fe517fc9Smrg            retval->list[i].high_mark = info.list[i].high_mark;
1318fe517fc9Smrg        }
1319fe517fc9Smrg        drmFree(info.list);
1320fe517fc9Smrg        return retval;
132122944501Smrg    }
132222944501Smrg    return NULL;
132322944501Smrg}
132422944501Smrg
132522944501Smrg/**
132622944501Smrg * Map all DMA buffers into client-virtual space.
132722944501Smrg *
132822944501Smrg * \param fd file descriptor.
132922944501Smrg *
133022944501Smrg * \return a pointer to a ::drmBufMap structure.
133122944501Smrg *
133222944501Smrg * \note The client may not use these buffers until obtaining buffer indices
133322944501Smrg * with drmDMA().
1334fe517fc9Smrg *
133522944501Smrg * \internal
133622944501Smrg * This function calls the DRM_IOCTL_MAP_BUFS ioctl and copies the returned
133722944501Smrg * information about the buffers in a drm_buf_map structure into the
133822944501Smrg * client-visible data structures.
1339fe517fc9Smrg */
134022944501SmrgdrmBufMapPtr drmMapBufs(int fd)
134122944501Smrg{
134222944501Smrg    drm_buf_map_t bufs;
134322944501Smrg    drmBufMapPtr  retval;
134422944501Smrg    int           i;
134522944501Smrg
1346424e9256Smrg    memclear(bufs);
134722944501Smrg    if (drmIoctl(fd, DRM_IOCTL_MAP_BUFS, &bufs))
1348fe517fc9Smrg        return NULL;
134922944501Smrg
135022944501Smrg    if (!bufs.count)
1351fe517fc9Smrg        return NULL;
135222944501Smrg
1353fe517fc9Smrg    if (!(bufs.list = drmMalloc(bufs.count * sizeof(*bufs.list))))
1354fe517fc9Smrg        return NULL;
135522944501Smrg
1356fe517fc9Smrg    if (drmIoctl(fd, DRM_IOCTL_MAP_BUFS, &bufs)) {
1357fe517fc9Smrg        drmFree(bufs.list);
1358fe517fc9Smrg        return NULL;
1359fe517fc9Smrg    }
136022944501Smrg
1361fe517fc9Smrg    retval = drmMalloc(sizeof(*retval));
1362fe517fc9Smrg    retval->count = bufs.count;
1363fe517fc9Smrg    retval->list  = drmMalloc(bufs.count * sizeof(*retval->list));
1364fe517fc9Smrg    for (i = 0; i < bufs.count; i++) {
1365fe517fc9Smrg        retval->list[i].idx     = bufs.list[i].idx;
1366fe517fc9Smrg        retval->list[i].total   = bufs.list[i].total;
1367fe517fc9Smrg        retval->list[i].used    = 0;
1368fe517fc9Smrg        retval->list[i].address = bufs.list[i].address;
1369fe517fc9Smrg    }
137022944501Smrg
1371fe517fc9Smrg    drmFree(bufs.list);
1372fe517fc9Smrg    return retval;
137322944501Smrg}
137422944501Smrg
137522944501Smrg
137622944501Smrg/**
137722944501Smrg * Unmap buffers allocated with drmMapBufs().
137822944501Smrg *
137922944501Smrg * \return zero on success, or negative value on failure.
138022944501Smrg *
138122944501Smrg * \internal
138222944501Smrg * Calls munmap() for every buffer stored in \p bufs and frees the
138322944501Smrg * memory allocated by drmMapBufs().
138422944501Smrg */
138522944501Smrgint drmUnmapBufs(drmBufMapPtr bufs)
138622944501Smrg{
138722944501Smrg    int i;
138822944501Smrg
138922944501Smrg    for (i = 0; i < bufs->count; i++) {
1390fe517fc9Smrg        drm_munmap(bufs->list[i].address, bufs->list[i].total);
139122944501Smrg    }
139222944501Smrg
139322944501Smrg    drmFree(bufs->list);
139422944501Smrg    drmFree(bufs);
139522944501Smrg    return 0;
139622944501Smrg}
139722944501Smrg
139822944501Smrg
1399fe517fc9Smrg#define DRM_DMA_RETRY  16
140022944501Smrg
140122944501Smrg/**
140222944501Smrg * Reserve DMA buffers.
140322944501Smrg *
140422944501Smrg * \param fd file descriptor.
1405fe517fc9Smrg * \param request
1406fe517fc9Smrg *
140722944501Smrg * \return zero on success, or a negative value on failure.
140822944501Smrg *
140922944501Smrg * \internal
141022944501Smrg * Assemble the arguments into a drm_dma structure and keeps issuing the
141122944501Smrg * DRM_IOCTL_DMA ioctl until success or until maximum number of retries.
141222944501Smrg */
141322944501Smrgint drmDMA(int fd, drmDMAReqPtr request)
141422944501Smrg{
141522944501Smrg    drm_dma_t dma;
141622944501Smrg    int ret, i = 0;
141722944501Smrg
141822944501Smrg    dma.context         = request->context;
141922944501Smrg    dma.send_count      = request->send_count;
142022944501Smrg    dma.send_indices    = request->send_list;
142122944501Smrg    dma.send_sizes      = request->send_sizes;
142222944501Smrg    dma.flags           = request->flags;
142322944501Smrg    dma.request_count   = request->request_count;
142422944501Smrg    dma.request_size    = request->request_size;
142522944501Smrg    dma.request_indices = request->request_list;
142622944501Smrg    dma.request_sizes   = request->request_sizes;
142722944501Smrg    dma.granted_count   = 0;
142822944501Smrg
142922944501Smrg    do {
1430fe517fc9Smrg        ret = ioctl( fd, DRM_IOCTL_DMA, &dma );
143122944501Smrg    } while ( ret && errno == EAGAIN && i++ < DRM_DMA_RETRY );
143222944501Smrg
143322944501Smrg    if ( ret == 0 ) {
1434fe517fc9Smrg        request->granted_count = dma.granted_count;
1435fe517fc9Smrg        return 0;
143622944501Smrg    } else {
1437fe517fc9Smrg        return -errno;
143822944501Smrg    }
143922944501Smrg}
144022944501Smrg
144122944501Smrg
144222944501Smrg/**
144322944501Smrg * Obtain heavyweight hardware lock.
144422944501Smrg *
144522944501Smrg * \param fd file descriptor.
144622944501Smrg * \param context context.
144722944501Smrg * \param flags flags that determine the sate of the hardware when the function
144822944501Smrg * returns.
1449fe517fc9Smrg *
145022944501Smrg * \return always zero.
1451fe517fc9Smrg *
145222944501Smrg * \internal
145322944501Smrg * This function translates the arguments into a drm_lock structure and issue
145422944501Smrg * the DRM_IOCTL_LOCK ioctl until the lock is successfully acquired.
145522944501Smrg */
145622944501Smrgint drmGetLock(int fd, drm_context_t context, drmLockFlags flags)
145722944501Smrg{
145822944501Smrg    drm_lock_t lock;
145922944501Smrg
1460424e9256Smrg    memclear(lock);
146122944501Smrg    lock.context = context;
146222944501Smrg    lock.flags   = 0;
146322944501Smrg    if (flags & DRM_LOCK_READY)      lock.flags |= _DRM_LOCK_READY;
146422944501Smrg    if (flags & DRM_LOCK_QUIESCENT)  lock.flags |= _DRM_LOCK_QUIESCENT;
146522944501Smrg    if (flags & DRM_LOCK_FLUSH)      lock.flags |= _DRM_LOCK_FLUSH;
146622944501Smrg    if (flags & DRM_LOCK_FLUSH_ALL)  lock.flags |= _DRM_LOCK_FLUSH_ALL;
146722944501Smrg    if (flags & DRM_HALT_ALL_QUEUES) lock.flags |= _DRM_HALT_ALL_QUEUES;
146822944501Smrg    if (flags & DRM_HALT_CUR_QUEUES) lock.flags |= _DRM_HALT_CUR_QUEUES;
146922944501Smrg
147022944501Smrg    while (drmIoctl(fd, DRM_IOCTL_LOCK, &lock))
1471fe517fc9Smrg        ;
147222944501Smrg    return 0;
147322944501Smrg}
147422944501Smrg
147522944501Smrg/**
147622944501Smrg * Release the hardware lock.
147722944501Smrg *
147822944501Smrg * \param fd file descriptor.
147922944501Smrg * \param context context.
1480fe517fc9Smrg *
148122944501Smrg * \return zero on success, or a negative value on failure.
1482fe517fc9Smrg *
148322944501Smrg * \internal
148422944501Smrg * This function is a wrapper around the DRM_IOCTL_UNLOCK ioctl, passing the
148522944501Smrg * argument in a drm_lock structure.
148622944501Smrg */
148722944501Smrgint drmUnlock(int fd, drm_context_t context)
148822944501Smrg{
148922944501Smrg    drm_lock_t lock;
149022944501Smrg
1491424e9256Smrg    memclear(lock);
149222944501Smrg    lock.context = context;
149322944501Smrg    return drmIoctl(fd, DRM_IOCTL_UNLOCK, &lock);
149422944501Smrg}
149522944501Smrg
149622944501Smrgdrm_context_t *drmGetReservedContextList(int fd, int *count)
149722944501Smrg{
149822944501Smrg    drm_ctx_res_t res;
149922944501Smrg    drm_ctx_t     *list;
150022944501Smrg    drm_context_t * retval;
150122944501Smrg    int           i;
150222944501Smrg
1503424e9256Smrg    memclear(res);
150422944501Smrg    if (drmIoctl(fd, DRM_IOCTL_RES_CTX, &res))
1505fe517fc9Smrg        return NULL;
150622944501Smrg
150722944501Smrg    if (!res.count)
1508fe517fc9Smrg        return NULL;
150922944501Smrg
151022944501Smrg    if (!(list   = drmMalloc(res.count * sizeof(*list))))
1511fe517fc9Smrg        return NULL;
151222944501Smrg    if (!(retval = drmMalloc(res.count * sizeof(*retval)))) {
1513fe517fc9Smrg        drmFree(list);
1514fe517fc9Smrg        return NULL;
151522944501Smrg    }
151622944501Smrg
151722944501Smrg    res.contexts = list;
151822944501Smrg    if (drmIoctl(fd, DRM_IOCTL_RES_CTX, &res))
1519fe517fc9Smrg        return NULL;
152022944501Smrg
152122944501Smrg    for (i = 0; i < res.count; i++)
1522fe517fc9Smrg        retval[i] = list[i].handle;
152322944501Smrg    drmFree(list);
152422944501Smrg
152522944501Smrg    *count = res.count;
152622944501Smrg    return retval;
152722944501Smrg}
152822944501Smrg
152922944501Smrgvoid drmFreeReservedContextList(drm_context_t *pt)
153022944501Smrg{
153122944501Smrg    drmFree(pt);
153222944501Smrg}
153322944501Smrg
153422944501Smrg/**
153522944501Smrg * Create context.
153622944501Smrg *
153722944501Smrg * Used by the X server during GLXContext initialization. This causes
153822944501Smrg * per-context kernel-level resources to be allocated.
153922944501Smrg *
154022944501Smrg * \param fd file descriptor.
154122944501Smrg * \param handle is set on success. To be used by the client when requesting DMA
154222944501Smrg * dispatch with drmDMA().
1543fe517fc9Smrg *
154422944501Smrg * \return zero on success, or a negative value on failure.
1545fe517fc9Smrg *
154622944501Smrg * \note May only be called by root.
1547fe517fc9Smrg *
154822944501Smrg * \internal
154922944501Smrg * This function is a wrapper around the DRM_IOCTL_ADD_CTX ioctl, passing the
155022944501Smrg * argument in a drm_ctx structure.
155122944501Smrg */
155222944501Smrgint drmCreateContext(int fd, drm_context_t *handle)
155322944501Smrg{
155422944501Smrg    drm_ctx_t ctx;
155522944501Smrg
1556424e9256Smrg    memclear(ctx);
155722944501Smrg    if (drmIoctl(fd, DRM_IOCTL_ADD_CTX, &ctx))
1558fe517fc9Smrg        return -errno;
155922944501Smrg    *handle = ctx.handle;
156022944501Smrg    return 0;
156122944501Smrg}
156222944501Smrg
156322944501Smrgint drmSwitchToContext(int fd, drm_context_t context)
156422944501Smrg{
156522944501Smrg    drm_ctx_t ctx;
156622944501Smrg
1567424e9256Smrg    memclear(ctx);
156822944501Smrg    ctx.handle = context;
156922944501Smrg    if (drmIoctl(fd, DRM_IOCTL_SWITCH_CTX, &ctx))
1570fe517fc9Smrg        return -errno;
157122944501Smrg    return 0;
157222944501Smrg}
157322944501Smrg
157422944501Smrgint drmSetContextFlags(int fd, drm_context_t context, drm_context_tFlags flags)
157522944501Smrg{
157622944501Smrg    drm_ctx_t ctx;
157722944501Smrg
157822944501Smrg    /*
157922944501Smrg     * Context preserving means that no context switches are done between DMA
158022944501Smrg     * buffers from one context and the next.  This is suitable for use in the
158122944501Smrg     * X server (which promises to maintain hardware context), or in the
158222944501Smrg     * client-side library when buffers are swapped on behalf of two threads.
158322944501Smrg     */
1584424e9256Smrg    memclear(ctx);
158522944501Smrg    ctx.handle = context;
158622944501Smrg    if (flags & DRM_CONTEXT_PRESERVED)
1587fe517fc9Smrg        ctx.flags |= _DRM_CONTEXT_PRESERVED;
158822944501Smrg    if (flags & DRM_CONTEXT_2DONLY)
1589fe517fc9Smrg        ctx.flags |= _DRM_CONTEXT_2DONLY;
159022944501Smrg    if (drmIoctl(fd, DRM_IOCTL_MOD_CTX, &ctx))
1591fe517fc9Smrg        return -errno;
159222944501Smrg    return 0;
159322944501Smrg}
159422944501Smrg
159522944501Smrgint drmGetContextFlags(int fd, drm_context_t context,
159622944501Smrg                       drm_context_tFlagsPtr flags)
159722944501Smrg{
159822944501Smrg    drm_ctx_t ctx;
159922944501Smrg
1600424e9256Smrg    memclear(ctx);
160122944501Smrg    ctx.handle = context;
160222944501Smrg    if (drmIoctl(fd, DRM_IOCTL_GET_CTX, &ctx))
1603fe517fc9Smrg        return -errno;
160422944501Smrg    *flags = 0;
160522944501Smrg    if (ctx.flags & _DRM_CONTEXT_PRESERVED)
1606fe517fc9Smrg        *flags |= DRM_CONTEXT_PRESERVED;
160722944501Smrg    if (ctx.flags & _DRM_CONTEXT_2DONLY)
1608fe517fc9Smrg        *flags |= DRM_CONTEXT_2DONLY;
160922944501Smrg    return 0;
161022944501Smrg}
161122944501Smrg
161222944501Smrg/**
161322944501Smrg * Destroy context.
161422944501Smrg *
161522944501Smrg * Free any kernel-level resources allocated with drmCreateContext() associated
161622944501Smrg * with the context.
1617fe517fc9Smrg *
161822944501Smrg * \param fd file descriptor.
161922944501Smrg * \param handle handle given by drmCreateContext().
1620fe517fc9Smrg *
162122944501Smrg * \return zero on success, or a negative value on failure.
1622fe517fc9Smrg *
162322944501Smrg * \note May only be called by root.
1624fe517fc9Smrg *
162522944501Smrg * \internal
162622944501Smrg * This function is a wrapper around the DRM_IOCTL_RM_CTX ioctl, passing the
162722944501Smrg * argument in a drm_ctx structure.
162822944501Smrg */
162922944501Smrgint drmDestroyContext(int fd, drm_context_t handle)
163022944501Smrg{
163122944501Smrg    drm_ctx_t ctx;
1632424e9256Smrg
1633424e9256Smrg    memclear(ctx);
163422944501Smrg    ctx.handle = handle;
163522944501Smrg    if (drmIoctl(fd, DRM_IOCTL_RM_CTX, &ctx))
1636fe517fc9Smrg        return -errno;
163722944501Smrg    return 0;
163822944501Smrg}
163922944501Smrg
164022944501Smrgint drmCreateDrawable(int fd, drm_drawable_t *handle)
164122944501Smrg{
164222944501Smrg    drm_draw_t draw;
1643424e9256Smrg
1644424e9256Smrg    memclear(draw);
164522944501Smrg    if (drmIoctl(fd, DRM_IOCTL_ADD_DRAW, &draw))
1646fe517fc9Smrg        return -errno;
164722944501Smrg    *handle = draw.handle;
164822944501Smrg    return 0;
164922944501Smrg}
165022944501Smrg
165122944501Smrgint drmDestroyDrawable(int fd, drm_drawable_t handle)
165222944501Smrg{
165322944501Smrg    drm_draw_t draw;
1654424e9256Smrg
1655424e9256Smrg    memclear(draw);
165622944501Smrg    draw.handle = handle;
165722944501Smrg    if (drmIoctl(fd, DRM_IOCTL_RM_DRAW, &draw))
1658fe517fc9Smrg        return -errno;
165922944501Smrg    return 0;
166022944501Smrg}
166122944501Smrg
166222944501Smrgint drmUpdateDrawableInfo(int fd, drm_drawable_t handle,
1663fe517fc9Smrg                          drm_drawable_info_type_t type, unsigned int num,
1664fe517fc9Smrg                          void *data)
166522944501Smrg{
166622944501Smrg    drm_update_draw_t update;
166722944501Smrg
1668424e9256Smrg    memclear(update);
166922944501Smrg    update.handle = handle;
167022944501Smrg    update.type = type;
167122944501Smrg    update.num = num;
167222944501Smrg    update.data = (unsigned long long)(unsigned long)data;
167322944501Smrg
167422944501Smrg    if (drmIoctl(fd, DRM_IOCTL_UPDATE_DRAW, &update))
1675fe517fc9Smrg        return -errno;
167622944501Smrg
167722944501Smrg    return 0;
167822944501Smrg}
167922944501Smrg
168022944501Smrg/**
168122944501Smrg * Acquire the AGP device.
168222944501Smrg *
168322944501Smrg * Must be called before any of the other AGP related calls.
168422944501Smrg *
168522944501Smrg * \param fd file descriptor.
1686fe517fc9Smrg *
168722944501Smrg * \return zero on success, or a negative value on failure.
1688fe517fc9Smrg *
168922944501Smrg * \internal
169022944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_ACQUIRE ioctl.
169122944501Smrg */
169222944501Smrgint drmAgpAcquire(int fd)
169322944501Smrg{
169422944501Smrg    if (drmIoctl(fd, DRM_IOCTL_AGP_ACQUIRE, NULL))
1695fe517fc9Smrg        return -errno;
169622944501Smrg    return 0;
169722944501Smrg}
169822944501Smrg
169922944501Smrg
170022944501Smrg/**
170122944501Smrg * Release the AGP device.
170222944501Smrg *
170322944501Smrg * \param fd file descriptor.
1704fe517fc9Smrg *
170522944501Smrg * \return zero on success, or a negative value on failure.
1706fe517fc9Smrg *
170722944501Smrg * \internal
170822944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_RELEASE ioctl.
170922944501Smrg */
171022944501Smrgint drmAgpRelease(int fd)
171122944501Smrg{
171222944501Smrg    if (drmIoctl(fd, DRM_IOCTL_AGP_RELEASE, NULL))
1713fe517fc9Smrg        return -errno;
171422944501Smrg    return 0;
171522944501Smrg}
171622944501Smrg
171722944501Smrg
171822944501Smrg/**
171922944501Smrg * Set the AGP mode.
172022944501Smrg *
172122944501Smrg * \param fd file descriptor.
172222944501Smrg * \param mode AGP mode.
1723fe517fc9Smrg *
172422944501Smrg * \return zero on success, or a negative value on failure.
1725fe517fc9Smrg *
172622944501Smrg * \internal
172722944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_ENABLE ioctl, passing the
172822944501Smrg * argument in a drm_agp_mode structure.
172922944501Smrg */
173022944501Smrgint drmAgpEnable(int fd, unsigned long mode)
173122944501Smrg{
173222944501Smrg    drm_agp_mode_t m;
173322944501Smrg
1734424e9256Smrg    memclear(m);
173522944501Smrg    m.mode = mode;
173622944501Smrg    if (drmIoctl(fd, DRM_IOCTL_AGP_ENABLE, &m))
1737fe517fc9Smrg        return -errno;
173822944501Smrg    return 0;
173922944501Smrg}
174022944501Smrg
174122944501Smrg
174222944501Smrg/**
174322944501Smrg * Allocate a chunk of AGP memory.
174422944501Smrg *
174522944501Smrg * \param fd file descriptor.
174622944501Smrg * \param size requested memory size in bytes. Will be rounded to page boundary.
174722944501Smrg * \param type type of memory to allocate.
174822944501Smrg * \param address if not zero, will be set to the physical address of the
174922944501Smrg * allocated memory.
175022944501Smrg * \param handle on success will be set to a handle of the allocated memory.
1751fe517fc9Smrg *
175222944501Smrg * \return zero on success, or a negative value on failure.
1753fe517fc9Smrg *
175422944501Smrg * \internal
175522944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_ALLOC ioctl, passing the
175622944501Smrg * arguments in a drm_agp_buffer structure.
175722944501Smrg */
175822944501Smrgint drmAgpAlloc(int fd, unsigned long size, unsigned long type,
1759fe517fc9Smrg                unsigned long *address, drm_handle_t *handle)
176022944501Smrg{
176122944501Smrg    drm_agp_buffer_t b;
176222944501Smrg
1763424e9256Smrg    memclear(b);
176422944501Smrg    *handle = DRM_AGP_NO_HANDLE;
176522944501Smrg    b.size   = size;
176622944501Smrg    b.type   = type;
176722944501Smrg    if (drmIoctl(fd, DRM_IOCTL_AGP_ALLOC, &b))
1768fe517fc9Smrg        return -errno;
176922944501Smrg    if (address != 0UL)
1770fe517fc9Smrg        *address = b.physical;
177122944501Smrg    *handle = b.handle;
177222944501Smrg    return 0;
177322944501Smrg}
177422944501Smrg
177522944501Smrg
177622944501Smrg/**
177722944501Smrg * Free a chunk of AGP memory.
177822944501Smrg *
177922944501Smrg * \param fd file descriptor.
178022944501Smrg * \param handle handle to the allocated memory, as given by drmAgpAllocate().
1781fe517fc9Smrg *
178222944501Smrg * \return zero on success, or a negative value on failure.
1783fe517fc9Smrg *
178422944501Smrg * \internal
178522944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_FREE ioctl, passing the
178622944501Smrg * argument in a drm_agp_buffer structure.
178722944501Smrg */
178822944501Smrgint drmAgpFree(int fd, drm_handle_t handle)
178922944501Smrg{
179022944501Smrg    drm_agp_buffer_t b;
179122944501Smrg
1792424e9256Smrg    memclear(b);
179322944501Smrg    b.handle = handle;
179422944501Smrg    if (drmIoctl(fd, DRM_IOCTL_AGP_FREE, &b))
1795fe517fc9Smrg        return -errno;
179622944501Smrg    return 0;
179722944501Smrg}
179822944501Smrg
179922944501Smrg
180022944501Smrg/**
180122944501Smrg * Bind a chunk of AGP memory.
180222944501Smrg *
180322944501Smrg * \param fd file descriptor.
180422944501Smrg * \param handle handle to the allocated memory, as given by drmAgpAllocate().
180522944501Smrg * \param offset offset in bytes. It will round to page boundary.
1806fe517fc9Smrg *
180722944501Smrg * \return zero on success, or a negative value on failure.
1808fe517fc9Smrg *
180922944501Smrg * \internal
181022944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_BIND ioctl, passing the
181122944501Smrg * argument in a drm_agp_binding structure.
181222944501Smrg */
181322944501Smrgint drmAgpBind(int fd, drm_handle_t handle, unsigned long offset)
181422944501Smrg{
181522944501Smrg    drm_agp_binding_t b;
181622944501Smrg
1817424e9256Smrg    memclear(b);
181822944501Smrg    b.handle = handle;
181922944501Smrg    b.offset = offset;
182022944501Smrg    if (drmIoctl(fd, DRM_IOCTL_AGP_BIND, &b))
1821fe517fc9Smrg        return -errno;
182222944501Smrg    return 0;
182322944501Smrg}
182422944501Smrg
182522944501Smrg
182622944501Smrg/**
182722944501Smrg * Unbind a chunk of AGP memory.
182822944501Smrg *
182922944501Smrg * \param fd file descriptor.
183022944501Smrg * \param handle handle to the allocated memory, as given by drmAgpAllocate().
1831fe517fc9Smrg *
183222944501Smrg * \return zero on success, or a negative value on failure.
1833fe517fc9Smrg *
183422944501Smrg * \internal
183522944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_UNBIND ioctl, passing
183622944501Smrg * the argument in a drm_agp_binding structure.
183722944501Smrg */
183822944501Smrgint drmAgpUnbind(int fd, drm_handle_t handle)
183922944501Smrg{
184022944501Smrg    drm_agp_binding_t b;
184122944501Smrg
1842424e9256Smrg    memclear(b);
184322944501Smrg    b.handle = handle;
184422944501Smrg    if (drmIoctl(fd, DRM_IOCTL_AGP_UNBIND, &b))
1845fe517fc9Smrg        return -errno;
184622944501Smrg    return 0;
184722944501Smrg}
184822944501Smrg
184922944501Smrg
185022944501Smrg/**
185122944501Smrg * Get AGP driver major version number.
185222944501Smrg *
185322944501Smrg * \param fd file descriptor.
1854fe517fc9Smrg *
185522944501Smrg * \return major version number on success, or a negative value on failure..
1856fe517fc9Smrg *
185722944501Smrg * \internal
185822944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
185922944501Smrg * necessary information in a drm_agp_info structure.
186022944501Smrg */
186122944501Smrgint drmAgpVersionMajor(int fd)
186222944501Smrg{
186322944501Smrg    drm_agp_info_t i;
186422944501Smrg
1865424e9256Smrg    memclear(i);
1866424e9256Smrg
186722944501Smrg    if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
1868fe517fc9Smrg        return -errno;
186922944501Smrg    return i.agp_version_major;
187022944501Smrg}
187122944501Smrg
187222944501Smrg
187322944501Smrg/**
187422944501Smrg * Get AGP driver minor version number.
187522944501Smrg *
187622944501Smrg * \param fd file descriptor.
1877fe517fc9Smrg *
187822944501Smrg * \return minor version number on success, or a negative value on failure.
1879fe517fc9Smrg *
188022944501Smrg * \internal
188122944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
188222944501Smrg * necessary information in a drm_agp_info structure.
188322944501Smrg */
188422944501Smrgint drmAgpVersionMinor(int fd)
188522944501Smrg{
188622944501Smrg    drm_agp_info_t i;
188722944501Smrg
1888424e9256Smrg    memclear(i);
1889424e9256Smrg
189022944501Smrg    if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
1891fe517fc9Smrg        return -errno;
189222944501Smrg    return i.agp_version_minor;
189322944501Smrg}
189422944501Smrg
189522944501Smrg
189622944501Smrg/**
189722944501Smrg * Get AGP mode.
189822944501Smrg *
189922944501Smrg * \param fd file descriptor.
1900fe517fc9Smrg *
190122944501Smrg * \return mode on success, or zero on failure.
1902fe517fc9Smrg *
190322944501Smrg * \internal
190422944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
190522944501Smrg * necessary information in a drm_agp_info structure.
190622944501Smrg */
190722944501Smrgunsigned long drmAgpGetMode(int fd)
190822944501Smrg{
190922944501Smrg    drm_agp_info_t i;
191022944501Smrg
1911424e9256Smrg    memclear(i);
1912424e9256Smrg
191322944501Smrg    if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
1914fe517fc9Smrg        return 0;
191522944501Smrg    return i.mode;
191622944501Smrg}
191722944501Smrg
191822944501Smrg
191922944501Smrg/**
192022944501Smrg * Get AGP aperture base.
192122944501Smrg *
192222944501Smrg * \param fd file descriptor.
1923fe517fc9Smrg *
192422944501Smrg * \return aperture base on success, zero on failure.
1925fe517fc9Smrg *
192622944501Smrg * \internal
192722944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
192822944501Smrg * necessary information in a drm_agp_info structure.
192922944501Smrg */
193022944501Smrgunsigned long drmAgpBase(int fd)
193122944501Smrg{
193222944501Smrg    drm_agp_info_t i;
193322944501Smrg
1934424e9256Smrg    memclear(i);
1935424e9256Smrg
193622944501Smrg    if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
1937fe517fc9Smrg        return 0;
193822944501Smrg    return i.aperture_base;
193922944501Smrg}
194022944501Smrg
194122944501Smrg
194222944501Smrg/**
194322944501Smrg * Get AGP aperture size.
194422944501Smrg *
194522944501Smrg * \param fd file descriptor.
1946fe517fc9Smrg *
194722944501Smrg * \return aperture size on success, zero on failure.
1948fe517fc9Smrg *
194922944501Smrg * \internal
195022944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
195122944501Smrg * necessary information in a drm_agp_info structure.
195222944501Smrg */
195322944501Smrgunsigned long drmAgpSize(int fd)
195422944501Smrg{
195522944501Smrg    drm_agp_info_t i;
195622944501Smrg
1957424e9256Smrg    memclear(i);
1958424e9256Smrg
195922944501Smrg    if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
1960fe517fc9Smrg        return 0;
196122944501Smrg    return i.aperture_size;
196222944501Smrg}
196322944501Smrg
196422944501Smrg
196522944501Smrg/**
196622944501Smrg * Get used AGP memory.
196722944501Smrg *
196822944501Smrg * \param fd file descriptor.
1969fe517fc9Smrg *
197022944501Smrg * \return memory used on success, or zero on failure.
1971fe517fc9Smrg *
197222944501Smrg * \internal
197322944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
197422944501Smrg * necessary information in a drm_agp_info structure.
197522944501Smrg */
197622944501Smrgunsigned long drmAgpMemoryUsed(int fd)
197722944501Smrg{
197822944501Smrg    drm_agp_info_t i;
197922944501Smrg
1980424e9256Smrg    memclear(i);
1981424e9256Smrg
198222944501Smrg    if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
1983fe517fc9Smrg        return 0;
198422944501Smrg    return i.memory_used;
198522944501Smrg}
198622944501Smrg
198722944501Smrg
198822944501Smrg/**
198922944501Smrg * Get available AGP memory.
199022944501Smrg *
199122944501Smrg * \param fd file descriptor.
1992fe517fc9Smrg *
199322944501Smrg * \return memory available on success, or zero on failure.
1994fe517fc9Smrg *
199522944501Smrg * \internal
199622944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
199722944501Smrg * necessary information in a drm_agp_info structure.
199822944501Smrg */
199922944501Smrgunsigned long drmAgpMemoryAvail(int fd)
200022944501Smrg{
200122944501Smrg    drm_agp_info_t i;
200222944501Smrg
2003424e9256Smrg    memclear(i);
2004424e9256Smrg
200522944501Smrg    if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
2006fe517fc9Smrg        return 0;
200722944501Smrg    return i.memory_allowed;
200822944501Smrg}
200922944501Smrg
201022944501Smrg
201122944501Smrg/**
201222944501Smrg * Get hardware vendor ID.
201322944501Smrg *
201422944501Smrg * \param fd file descriptor.
2015fe517fc9Smrg *
201622944501Smrg * \return vendor ID on success, or zero on failure.
2017fe517fc9Smrg *
201822944501Smrg * \internal
201922944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
202022944501Smrg * necessary information in a drm_agp_info structure.
202122944501Smrg */
202222944501Smrgunsigned int drmAgpVendorId(int fd)
202322944501Smrg{
202422944501Smrg    drm_agp_info_t i;
202522944501Smrg
2026424e9256Smrg    memclear(i);
2027424e9256Smrg
202822944501Smrg    if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
2029fe517fc9Smrg        return 0;
203022944501Smrg    return i.id_vendor;
203122944501Smrg}
203222944501Smrg
203322944501Smrg
203422944501Smrg/**
203522944501Smrg * Get hardware device ID.
203622944501Smrg *
203722944501Smrg * \param fd file descriptor.
2038fe517fc9Smrg *
203922944501Smrg * \return zero on success, or zero on failure.
2040fe517fc9Smrg *
204122944501Smrg * \internal
204222944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
204322944501Smrg * necessary information in a drm_agp_info structure.
204422944501Smrg */
204522944501Smrgunsigned int drmAgpDeviceId(int fd)
204622944501Smrg{
204722944501Smrg    drm_agp_info_t i;
204822944501Smrg
2049424e9256Smrg    memclear(i);
2050424e9256Smrg
205122944501Smrg    if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
2052fe517fc9Smrg        return 0;
205322944501Smrg    return i.id_device;
205422944501Smrg}
205522944501Smrg
205622944501Smrgint drmScatterGatherAlloc(int fd, unsigned long size, drm_handle_t *handle)
205722944501Smrg{
205822944501Smrg    drm_scatter_gather_t sg;
205922944501Smrg
2060424e9256Smrg    memclear(sg);
2061424e9256Smrg
206222944501Smrg    *handle = 0;
206322944501Smrg    sg.size   = size;
206422944501Smrg    if (drmIoctl(fd, DRM_IOCTL_SG_ALLOC, &sg))
2065fe517fc9Smrg        return -errno;
206622944501Smrg    *handle = sg.handle;
206722944501Smrg    return 0;
206822944501Smrg}
206922944501Smrg
207022944501Smrgint drmScatterGatherFree(int fd, drm_handle_t handle)
207122944501Smrg{
207222944501Smrg    drm_scatter_gather_t sg;
207322944501Smrg
2074424e9256Smrg    memclear(sg);
207522944501Smrg    sg.handle = handle;
207622944501Smrg    if (drmIoctl(fd, DRM_IOCTL_SG_FREE, &sg))
2077fe517fc9Smrg        return -errno;
207822944501Smrg    return 0;
207922944501Smrg}
208022944501Smrg
208122944501Smrg/**
208222944501Smrg * Wait for VBLANK.
208322944501Smrg *
208422944501Smrg * \param fd file descriptor.
208522944501Smrg * \param vbl pointer to a drmVBlank structure.
2086fe517fc9Smrg *
208722944501Smrg * \return zero on success, or a negative value on failure.
2088fe517fc9Smrg *
208922944501Smrg * \internal
209022944501Smrg * This function is a wrapper around the DRM_IOCTL_WAIT_VBLANK ioctl.
209122944501Smrg */
209222944501Smrgint drmWaitVBlank(int fd, drmVBlankPtr vbl)
209322944501Smrg{
209422944501Smrg    struct timespec timeout, cur;
209522944501Smrg    int ret;
209622944501Smrg
209722944501Smrg    ret = clock_gettime(CLOCK_MONOTONIC, &timeout);
209822944501Smrg    if (ret < 0) {
2099fe517fc9Smrg        fprintf(stderr, "clock_gettime failed: %s\n", strerror(errno));
2100fe517fc9Smrg        goto out;
210122944501Smrg    }
210222944501Smrg    timeout.tv_sec++;
210322944501Smrg
210422944501Smrg    do {
210522944501Smrg       ret = ioctl(fd, DRM_IOCTL_WAIT_VBLANK, vbl);
210622944501Smrg       vbl->request.type &= ~DRM_VBLANK_RELATIVE;
210722944501Smrg       if (ret && errno == EINTR) {
2108fe517fc9Smrg           clock_gettime(CLOCK_MONOTONIC, &cur);
2109fe517fc9Smrg           /* Timeout after 1s */
2110fe517fc9Smrg           if (cur.tv_sec > timeout.tv_sec + 1 ||
2111fe517fc9Smrg               (cur.tv_sec == timeout.tv_sec && cur.tv_nsec >=
2112fe517fc9Smrg                timeout.tv_nsec)) {
2113fe517fc9Smrg                   errno = EBUSY;
2114fe517fc9Smrg                   ret = -1;
2115fe517fc9Smrg                   break;
2116fe517fc9Smrg           }
211722944501Smrg       }
211822944501Smrg    } while (ret && errno == EINTR);
211922944501Smrg
212022944501Smrgout:
212122944501Smrg    return ret;
212222944501Smrg}
212322944501Smrg
212422944501Smrgint drmError(int err, const char *label)
212522944501Smrg{
212622944501Smrg    switch (err) {
212722944501Smrg    case DRM_ERR_NO_DEVICE:
2128fe517fc9Smrg        fprintf(stderr, "%s: no device\n", label);
2129fe517fc9Smrg        break;
213022944501Smrg    case DRM_ERR_NO_ACCESS:
2131fe517fc9Smrg        fprintf(stderr, "%s: no access\n", label);
2132fe517fc9Smrg        break;
213322944501Smrg    case DRM_ERR_NOT_ROOT:
2134fe517fc9Smrg        fprintf(stderr, "%s: not root\n", label);
2135fe517fc9Smrg        break;
213622944501Smrg    case DRM_ERR_INVALID:
2137fe517fc9Smrg        fprintf(stderr, "%s: invalid args\n", label);
2138fe517fc9Smrg        break;
213922944501Smrg    default:
2140fe517fc9Smrg        if (err < 0)
2141fe517fc9Smrg            err = -err;
2142fe517fc9Smrg        fprintf( stderr, "%s: error %d (%s)\n", label, err, strerror(err) );
2143fe517fc9Smrg        break;
214422944501Smrg    }
214522944501Smrg
214622944501Smrg    return 1;
214722944501Smrg}
214822944501Smrg
214922944501Smrg/**
215022944501Smrg * Install IRQ handler.
215122944501Smrg *
215222944501Smrg * \param fd file descriptor.
215322944501Smrg * \param irq IRQ number.
2154fe517fc9Smrg *
215522944501Smrg * \return zero on success, or a negative value on failure.
2156fe517fc9Smrg *
215722944501Smrg * \internal
215822944501Smrg * This function is a wrapper around the DRM_IOCTL_CONTROL ioctl, passing the
215922944501Smrg * argument in a drm_control structure.
216022944501Smrg */
216122944501Smrgint drmCtlInstHandler(int fd, int irq)
216222944501Smrg{
216322944501Smrg    drm_control_t ctl;
216422944501Smrg
2165424e9256Smrg    memclear(ctl);
216622944501Smrg    ctl.func  = DRM_INST_HANDLER;
216722944501Smrg    ctl.irq   = irq;
216822944501Smrg    if (drmIoctl(fd, DRM_IOCTL_CONTROL, &ctl))
2169fe517fc9Smrg        return -errno;
217022944501Smrg    return 0;
217122944501Smrg}
217222944501Smrg
217322944501Smrg
217422944501Smrg/**
217522944501Smrg * Uninstall IRQ handler.
217622944501Smrg *
217722944501Smrg * \param fd file descriptor.
2178fe517fc9Smrg *
217922944501Smrg * \return zero on success, or a negative value on failure.
2180fe517fc9Smrg *
218122944501Smrg * \internal
218222944501Smrg * This function is a wrapper around the DRM_IOCTL_CONTROL ioctl, passing the
218322944501Smrg * argument in a drm_control structure.
218422944501Smrg */
218522944501Smrgint drmCtlUninstHandler(int fd)
218622944501Smrg{
218722944501Smrg    drm_control_t ctl;
218822944501Smrg
2189424e9256Smrg    memclear(ctl);
219022944501Smrg    ctl.func  = DRM_UNINST_HANDLER;
219122944501Smrg    ctl.irq   = 0;
219222944501Smrg    if (drmIoctl(fd, DRM_IOCTL_CONTROL, &ctl))
2193fe517fc9Smrg        return -errno;
219422944501Smrg    return 0;
219522944501Smrg}
219622944501Smrg
219722944501Smrgint drmFinish(int fd, int context, drmLockFlags flags)
219822944501Smrg{
219922944501Smrg    drm_lock_t lock;
220022944501Smrg
2201424e9256Smrg    memclear(lock);
220222944501Smrg    lock.context = context;
220322944501Smrg    if (flags & DRM_LOCK_READY)      lock.flags |= _DRM_LOCK_READY;
220422944501Smrg    if (flags & DRM_LOCK_QUIESCENT)  lock.flags |= _DRM_LOCK_QUIESCENT;
220522944501Smrg    if (flags & DRM_LOCK_FLUSH)      lock.flags |= _DRM_LOCK_FLUSH;
220622944501Smrg    if (flags & DRM_LOCK_FLUSH_ALL)  lock.flags |= _DRM_LOCK_FLUSH_ALL;
220722944501Smrg    if (flags & DRM_HALT_ALL_QUEUES) lock.flags |= _DRM_HALT_ALL_QUEUES;
220822944501Smrg    if (flags & DRM_HALT_CUR_QUEUES) lock.flags |= _DRM_HALT_CUR_QUEUES;
220922944501Smrg    if (drmIoctl(fd, DRM_IOCTL_FINISH, &lock))
2210fe517fc9Smrg        return -errno;
221122944501Smrg    return 0;
221222944501Smrg}
221322944501Smrg
221422944501Smrg/**
221522944501Smrg * Get IRQ from bus ID.
221622944501Smrg *
221722944501Smrg * \param fd file descriptor.
221822944501Smrg * \param busnum bus number.
221922944501Smrg * \param devnum device number.
222022944501Smrg * \param funcnum function number.
2221fe517fc9Smrg *
222222944501Smrg * \return IRQ number on success, or a negative value on failure.
2223fe517fc9Smrg *
222422944501Smrg * \internal
222522944501Smrg * This function is a wrapper around the DRM_IOCTL_IRQ_BUSID ioctl, passing the
222622944501Smrg * arguments in a drm_irq_busid structure.
222722944501Smrg */
222822944501Smrgint drmGetInterruptFromBusID(int fd, int busnum, int devnum, int funcnum)
222922944501Smrg{
223022944501Smrg    drm_irq_busid_t p;
223122944501Smrg
2232424e9256Smrg    memclear(p);
223322944501Smrg    p.busnum  = busnum;
223422944501Smrg    p.devnum  = devnum;
223522944501Smrg    p.funcnum = funcnum;
223622944501Smrg    if (drmIoctl(fd, DRM_IOCTL_IRQ_BUSID, &p))
2237fe517fc9Smrg        return -errno;
223822944501Smrg    return p.irq;
223922944501Smrg}
224022944501Smrg
224122944501Smrgint drmAddContextTag(int fd, drm_context_t context, void *tag)
224222944501Smrg{
224322944501Smrg    drmHashEntry  *entry = drmGetEntry(fd);
224422944501Smrg
224522944501Smrg    if (drmHashInsert(entry->tagTable, context, tag)) {
2246fe517fc9Smrg        drmHashDelete(entry->tagTable, context);
2247fe517fc9Smrg        drmHashInsert(entry->tagTable, context, tag);
224822944501Smrg    }
224922944501Smrg    return 0;
225022944501Smrg}
225122944501Smrg
225222944501Smrgint drmDelContextTag(int fd, drm_context_t context)
225322944501Smrg{
225422944501Smrg    drmHashEntry  *entry = drmGetEntry(fd);
225522944501Smrg
225622944501Smrg    return drmHashDelete(entry->tagTable, context);
225722944501Smrg}
225822944501Smrg
225922944501Smrgvoid *drmGetContextTag(int fd, drm_context_t context)
226022944501Smrg{
226122944501Smrg    drmHashEntry  *entry = drmGetEntry(fd);
226222944501Smrg    void          *value;
226322944501Smrg
226422944501Smrg    if (drmHashLookup(entry->tagTable, context, &value))
2265fe517fc9Smrg        return NULL;
226622944501Smrg
226722944501Smrg    return value;
226822944501Smrg}
226922944501Smrg
227022944501Smrgint drmAddContextPrivateMapping(int fd, drm_context_t ctx_id,
227122944501Smrg                                drm_handle_t handle)
227222944501Smrg{
227322944501Smrg    drm_ctx_priv_map_t map;
227422944501Smrg
2275424e9256Smrg    memclear(map);
227622944501Smrg    map.ctx_id = ctx_id;
227720131375Smrg    map.handle = (void *)(uintptr_t)handle;
227822944501Smrg
227922944501Smrg    if (drmIoctl(fd, DRM_IOCTL_SET_SAREA_CTX, &map))
2280fe517fc9Smrg        return -errno;
228122944501Smrg    return 0;
228222944501Smrg}
228322944501Smrg
228422944501Smrgint drmGetContextPrivateMapping(int fd, drm_context_t ctx_id,
228522944501Smrg                                drm_handle_t *handle)
228622944501Smrg{
228722944501Smrg    drm_ctx_priv_map_t map;
228822944501Smrg
2289424e9256Smrg    memclear(map);
229022944501Smrg    map.ctx_id = ctx_id;
229122944501Smrg
229222944501Smrg    if (drmIoctl(fd, DRM_IOCTL_GET_SAREA_CTX, &map))
2293fe517fc9Smrg        return -errno;
229422944501Smrg    if (handle)
2295fe517fc9Smrg        *handle = (drm_handle_t)(uintptr_t)map.handle;
229622944501Smrg
229722944501Smrg    return 0;
229822944501Smrg}
229922944501Smrg
230022944501Smrgint drmGetMap(int fd, int idx, drm_handle_t *offset, drmSize *size,
2301fe517fc9Smrg              drmMapType *type, drmMapFlags *flags, drm_handle_t *handle,
2302fe517fc9Smrg              int *mtrr)
230322944501Smrg{
230422944501Smrg    drm_map_t map;
230522944501Smrg
2306424e9256Smrg    memclear(map);
230722944501Smrg    map.offset = idx;
230822944501Smrg    if (drmIoctl(fd, DRM_IOCTL_GET_MAP, &map))
2309fe517fc9Smrg        return -errno;
231022944501Smrg    *offset = map.offset;
231122944501Smrg    *size   = map.size;
231222944501Smrg    *type   = map.type;
231322944501Smrg    *flags  = map.flags;
231422944501Smrg    *handle = (unsigned long)map.handle;
231522944501Smrg    *mtrr   = map.mtrr;
231622944501Smrg    return 0;
231722944501Smrg}
231822944501Smrg
231922944501Smrgint drmGetClient(int fd, int idx, int *auth, int *pid, int *uid,
2320fe517fc9Smrg                 unsigned long *magic, unsigned long *iocs)
232122944501Smrg{
232222944501Smrg    drm_client_t client;
232322944501Smrg
2324424e9256Smrg    memclear(client);
232522944501Smrg    client.idx = idx;
232622944501Smrg    if (drmIoctl(fd, DRM_IOCTL_GET_CLIENT, &client))
2327fe517fc9Smrg        return -errno;
232822944501Smrg    *auth      = client.auth;
232922944501Smrg    *pid       = client.pid;
233022944501Smrg    *uid       = client.uid;
233122944501Smrg    *magic     = client.magic;
233222944501Smrg    *iocs      = client.iocs;
233322944501Smrg    return 0;
233422944501Smrg}
233522944501Smrg
233622944501Smrgint drmGetStats(int fd, drmStatsT *stats)
233722944501Smrg{
233822944501Smrg    drm_stats_t s;
2339424e9256Smrg    unsigned    i;
234022944501Smrg
2341424e9256Smrg    memclear(s);
234222944501Smrg    if (drmIoctl(fd, DRM_IOCTL_GET_STATS, &s))
2343fe517fc9Smrg        return -errno;
234422944501Smrg
234522944501Smrg    stats->count = 0;
234622944501Smrg    memset(stats, 0, sizeof(*stats));
234722944501Smrg    if (s.count > sizeof(stats->data)/sizeof(stats->data[0]))
2348fe517fc9Smrg        return -1;
234922944501Smrg
235022944501Smrg#define SET_VALUE                              \
235122944501Smrg    stats->data[i].long_format = "%-20.20s";   \
235222944501Smrg    stats->data[i].rate_format = "%8.8s";      \
235322944501Smrg    stats->data[i].isvalue     = 1;            \
235422944501Smrg    stats->data[i].verbose     = 0
235522944501Smrg
235622944501Smrg#define SET_COUNT                              \
235722944501Smrg    stats->data[i].long_format = "%-20.20s";   \
235822944501Smrg    stats->data[i].rate_format = "%5.5s";      \
235922944501Smrg    stats->data[i].isvalue     = 0;            \
236022944501Smrg    stats->data[i].mult_names  = "kgm";        \
236122944501Smrg    stats->data[i].mult        = 1000;         \
236222944501Smrg    stats->data[i].verbose     = 0
236322944501Smrg
236422944501Smrg#define SET_BYTE                               \
236522944501Smrg    stats->data[i].long_format = "%-20.20s";   \
236622944501Smrg    stats->data[i].rate_format = "%5.5s";      \
236722944501Smrg    stats->data[i].isvalue     = 0;            \
236822944501Smrg    stats->data[i].mult_names  = "KGM";        \
236922944501Smrg    stats->data[i].mult        = 1024;         \
237022944501Smrg    stats->data[i].verbose     = 0
237122944501Smrg
237222944501Smrg
237322944501Smrg    stats->count = s.count;
237422944501Smrg    for (i = 0; i < s.count; i++) {
2375fe517fc9Smrg        stats->data[i].value = s.data[i].value;
2376fe517fc9Smrg        switch (s.data[i].type) {
2377fe517fc9Smrg        case _DRM_STAT_LOCK:
2378fe517fc9Smrg            stats->data[i].long_name = "Lock";
2379fe517fc9Smrg            stats->data[i].rate_name = "Lock";
2380fe517fc9Smrg            SET_VALUE;
2381fe517fc9Smrg            break;
2382fe517fc9Smrg        case _DRM_STAT_OPENS:
2383fe517fc9Smrg            stats->data[i].long_name = "Opens";
2384fe517fc9Smrg            stats->data[i].rate_name = "O";
2385fe517fc9Smrg            SET_COUNT;
2386fe517fc9Smrg            stats->data[i].verbose   = 1;
2387fe517fc9Smrg            break;
2388fe517fc9Smrg        case _DRM_STAT_CLOSES:
2389fe517fc9Smrg            stats->data[i].long_name = "Closes";
2390fe517fc9Smrg            stats->data[i].rate_name = "Lock";
2391fe517fc9Smrg            SET_COUNT;
2392fe517fc9Smrg            stats->data[i].verbose   = 1;
2393fe517fc9Smrg            break;
2394fe517fc9Smrg        case _DRM_STAT_IOCTLS:
2395fe517fc9Smrg            stats->data[i].long_name = "Ioctls";
2396fe517fc9Smrg            stats->data[i].rate_name = "Ioc/s";
2397fe517fc9Smrg            SET_COUNT;
2398fe517fc9Smrg            break;
2399fe517fc9Smrg        case _DRM_STAT_LOCKS:
2400fe517fc9Smrg            stats->data[i].long_name = "Locks";
2401fe517fc9Smrg            stats->data[i].rate_name = "Lck/s";
2402fe517fc9Smrg            SET_COUNT;
2403fe517fc9Smrg            break;
2404fe517fc9Smrg        case _DRM_STAT_UNLOCKS:
2405fe517fc9Smrg            stats->data[i].long_name = "Unlocks";
2406fe517fc9Smrg            stats->data[i].rate_name = "Unl/s";
2407fe517fc9Smrg            SET_COUNT;
2408fe517fc9Smrg            break;
2409fe517fc9Smrg        case _DRM_STAT_IRQ:
2410fe517fc9Smrg            stats->data[i].long_name = "IRQs";
2411fe517fc9Smrg            stats->data[i].rate_name = "IRQ/s";
2412fe517fc9Smrg            SET_COUNT;
2413fe517fc9Smrg            break;
2414fe517fc9Smrg        case _DRM_STAT_PRIMARY:
2415fe517fc9Smrg            stats->data[i].long_name = "Primary Bytes";
2416fe517fc9Smrg            stats->data[i].rate_name = "PB/s";
2417fe517fc9Smrg            SET_BYTE;
2418fe517fc9Smrg            break;
2419fe517fc9Smrg        case _DRM_STAT_SECONDARY:
2420fe517fc9Smrg            stats->data[i].long_name = "Secondary Bytes";
2421fe517fc9Smrg            stats->data[i].rate_name = "SB/s";
2422fe517fc9Smrg            SET_BYTE;
2423fe517fc9Smrg            break;
2424fe517fc9Smrg        case _DRM_STAT_DMA:
2425fe517fc9Smrg            stats->data[i].long_name = "DMA";
2426fe517fc9Smrg            stats->data[i].rate_name = "DMA/s";
2427fe517fc9Smrg            SET_COUNT;
2428fe517fc9Smrg            break;
2429fe517fc9Smrg        case _DRM_STAT_SPECIAL:
2430fe517fc9Smrg            stats->data[i].long_name = "Special DMA";
2431fe517fc9Smrg            stats->data[i].rate_name = "dma/s";
2432fe517fc9Smrg            SET_COUNT;
2433fe517fc9Smrg            break;
2434fe517fc9Smrg        case _DRM_STAT_MISSED:
2435fe517fc9Smrg            stats->data[i].long_name = "Miss";
2436fe517fc9Smrg            stats->data[i].rate_name = "Ms/s";
2437fe517fc9Smrg            SET_COUNT;
2438fe517fc9Smrg            break;
2439fe517fc9Smrg        case _DRM_STAT_VALUE:
2440fe517fc9Smrg            stats->data[i].long_name = "Value";
2441fe517fc9Smrg            stats->data[i].rate_name = "Value";
2442fe517fc9Smrg            SET_VALUE;
2443fe517fc9Smrg            break;
2444fe517fc9Smrg        case _DRM_STAT_BYTE:
2445fe517fc9Smrg            stats->data[i].long_name = "Bytes";
2446fe517fc9Smrg            stats->data[i].rate_name = "B/s";
2447fe517fc9Smrg            SET_BYTE;
2448fe517fc9Smrg            break;
2449fe517fc9Smrg        case _DRM_STAT_COUNT:
2450fe517fc9Smrg        default:
2451fe517fc9Smrg            stats->data[i].long_name = "Count";
2452fe517fc9Smrg            stats->data[i].rate_name = "Cnt/s";
2453fe517fc9Smrg            SET_COUNT;
2454fe517fc9Smrg            break;
2455fe517fc9Smrg        }
245622944501Smrg    }
245722944501Smrg    return 0;
245822944501Smrg}
245922944501Smrg
246022944501Smrg/**
246122944501Smrg * Issue a set-version ioctl.
246222944501Smrg *
246322944501Smrg * \param fd file descriptor.
2464fe517fc9Smrg * \param drmCommandIndex command index
246522944501Smrg * \param data source pointer of the data to be read and written.
246622944501Smrg * \param size size of the data to be read and written.
2467fe517fc9Smrg *
246822944501Smrg * \return zero on success, or a negative value on failure.
2469fe517fc9Smrg *
247022944501Smrg * \internal
2471fe517fc9Smrg * It issues a read-write ioctl given by
247222944501Smrg * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
247322944501Smrg */
247422944501Smrgint drmSetInterfaceVersion(int fd, drmSetVersion *version)
247522944501Smrg{
247622944501Smrg    int retcode = 0;
247722944501Smrg    drm_set_version_t sv;
247822944501Smrg
2479424e9256Smrg    memclear(sv);
248022944501Smrg    sv.drm_di_major = version->drm_di_major;
248122944501Smrg    sv.drm_di_minor = version->drm_di_minor;
248222944501Smrg    sv.drm_dd_major = version->drm_dd_major;
248322944501Smrg    sv.drm_dd_minor = version->drm_dd_minor;
248422944501Smrg
248522944501Smrg    if (drmIoctl(fd, DRM_IOCTL_SET_VERSION, &sv)) {
2486fe517fc9Smrg        retcode = -errno;
248722944501Smrg    }
248822944501Smrg
248922944501Smrg    version->drm_di_major = sv.drm_di_major;
249022944501Smrg    version->drm_di_minor = sv.drm_di_minor;
249122944501Smrg    version->drm_dd_major = sv.drm_dd_major;
249222944501Smrg    version->drm_dd_minor = sv.drm_dd_minor;
249322944501Smrg
249422944501Smrg    return retcode;
249522944501Smrg}
249622944501Smrg
249722944501Smrg/**
249822944501Smrg * Send a device-specific command.
249922944501Smrg *
250022944501Smrg * \param fd file descriptor.
2501fe517fc9Smrg * \param drmCommandIndex command index
2502fe517fc9Smrg *
250322944501Smrg * \return zero on success, or a negative value on failure.
2504fe517fc9Smrg *
250522944501Smrg * \internal
2506fe517fc9Smrg * It issues a ioctl given by
250722944501Smrg * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
250822944501Smrg */
250922944501Smrgint drmCommandNone(int fd, unsigned long drmCommandIndex)
251022944501Smrg{
251122944501Smrg    unsigned long request;
251222944501Smrg
251322944501Smrg    request = DRM_IO( DRM_COMMAND_BASE + drmCommandIndex);
251422944501Smrg
2515424e9256Smrg    if (drmIoctl(fd, request, NULL)) {
2516fe517fc9Smrg        return -errno;
251722944501Smrg    }
251822944501Smrg    return 0;
251922944501Smrg}
252022944501Smrg
252122944501Smrg
252222944501Smrg/**
252322944501Smrg * Send a device-specific read command.
252422944501Smrg *
252522944501Smrg * \param fd file descriptor.
2526fe517fc9Smrg * \param drmCommandIndex command index
252722944501Smrg * \param data destination pointer of the data to be read.
252822944501Smrg * \param size size of the data to be read.
2529fe517fc9Smrg *
253022944501Smrg * \return zero on success, or a negative value on failure.
253122944501Smrg *
253222944501Smrg * \internal
2533fe517fc9Smrg * It issues a read ioctl given by
253422944501Smrg * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
253522944501Smrg */
253622944501Smrgint drmCommandRead(int fd, unsigned long drmCommandIndex, void *data,
253722944501Smrg                   unsigned long size)
253822944501Smrg{
253922944501Smrg    unsigned long request;
254022944501Smrg
2541fe517fc9Smrg    request = DRM_IOC( DRM_IOC_READ, DRM_IOCTL_BASE,
2542fe517fc9Smrg        DRM_COMMAND_BASE + drmCommandIndex, size);
254322944501Smrg
254422944501Smrg    if (drmIoctl(fd, request, data)) {
2545fe517fc9Smrg        return -errno;
254622944501Smrg    }
254722944501Smrg    return 0;
254822944501Smrg}
254922944501Smrg
255022944501Smrg
255122944501Smrg/**
255222944501Smrg * Send a device-specific write command.
255322944501Smrg *
255422944501Smrg * \param fd file descriptor.
2555fe517fc9Smrg * \param drmCommandIndex command index
255622944501Smrg * \param data source pointer of the data to be written.
255722944501Smrg * \param size size of the data to be written.
2558fe517fc9Smrg *
255922944501Smrg * \return zero on success, or a negative value on failure.
2560fe517fc9Smrg *
256122944501Smrg * \internal
2562fe517fc9Smrg * It issues a write ioctl given by
256322944501Smrg * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
256422944501Smrg */
256522944501Smrgint drmCommandWrite(int fd, unsigned long drmCommandIndex, void *data,
256622944501Smrg                    unsigned long size)
256722944501Smrg{
256822944501Smrg    unsigned long request;
256922944501Smrg
2570fe517fc9Smrg    request = DRM_IOC( DRM_IOC_WRITE, DRM_IOCTL_BASE,
2571fe517fc9Smrg        DRM_COMMAND_BASE + drmCommandIndex, size);
257222944501Smrg
257322944501Smrg    if (drmIoctl(fd, request, data)) {
2574fe517fc9Smrg        return -errno;
257522944501Smrg    }
257622944501Smrg    return 0;
257722944501Smrg}
257822944501Smrg
257922944501Smrg
258022944501Smrg/**
258122944501Smrg * Send a device-specific read-write command.
258222944501Smrg *
258322944501Smrg * \param fd file descriptor.
2584fe517fc9Smrg * \param drmCommandIndex command index
258522944501Smrg * \param data source pointer of the data to be read and written.
258622944501Smrg * \param size size of the data to be read and written.
2587fe517fc9Smrg *
258822944501Smrg * \return zero on success, or a negative value on failure.
2589fe517fc9Smrg *
259022944501Smrg * \internal
2591fe517fc9Smrg * It issues a read-write ioctl given by
259222944501Smrg * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
259322944501Smrg */
259422944501Smrgint drmCommandWriteRead(int fd, unsigned long drmCommandIndex, void *data,
259522944501Smrg                        unsigned long size)
259622944501Smrg{
259722944501Smrg    unsigned long request;
259822944501Smrg
2599fe517fc9Smrg    request = DRM_IOC( DRM_IOC_READ|DRM_IOC_WRITE, DRM_IOCTL_BASE,
2600fe517fc9Smrg        DRM_COMMAND_BASE + drmCommandIndex, size);
260122944501Smrg
260222944501Smrg    if (drmIoctl(fd, request, data))
2603fe517fc9Smrg        return -errno;
260422944501Smrg    return 0;
260522944501Smrg}
260622944501Smrg
260722944501Smrg#define DRM_MAX_FDS 16
260822944501Smrgstatic struct {
260922944501Smrg    char *BusID;
261022944501Smrg    int fd;
261122944501Smrg    int refcount;
2612424e9256Smrg    int type;
261322944501Smrg} connection[DRM_MAX_FDS];
261422944501Smrg
261522944501Smrgstatic int nr_fds = 0;
261622944501Smrg
2617fe517fc9Smrgint drmOpenOnce(void *unused,
2618fe517fc9Smrg                const char *BusID,
2619fe517fc9Smrg                int *newlyopened)
2620424e9256Smrg{
2621424e9256Smrg    return drmOpenOnceWithType(BusID, newlyopened, DRM_NODE_PRIMARY);
2622424e9256Smrg}
2623424e9256Smrg
2624424e9256Smrgint drmOpenOnceWithType(const char *BusID, int *newlyopened, int type)
262522944501Smrg{
262622944501Smrg    int i;
262722944501Smrg    int fd;
2628fe517fc9Smrg
262922944501Smrg    for (i = 0; i < nr_fds; i++)
2630fe517fc9Smrg        if ((strcmp(BusID, connection[i].BusID) == 0) &&
2631fe517fc9Smrg            (connection[i].type == type)) {
2632fe517fc9Smrg            connection[i].refcount++;
2633fe517fc9Smrg            *newlyopened = 0;
2634fe517fc9Smrg            return connection[i].fd;
2635fe517fc9Smrg        }
263622944501Smrg
2637424e9256Smrg    fd = drmOpenWithType(NULL, BusID, type);
2638fe517fc9Smrg    if (fd < 0 || nr_fds == DRM_MAX_FDS)
2639fe517fc9Smrg        return fd;
2640fe517fc9Smrg
264122944501Smrg    connection[nr_fds].BusID = strdup(BusID);
264222944501Smrg    connection[nr_fds].fd = fd;
264322944501Smrg    connection[nr_fds].refcount = 1;
2644424e9256Smrg    connection[nr_fds].type = type;
264522944501Smrg    *newlyopened = 1;
264622944501Smrg
264722944501Smrg    if (0)
2648fe517fc9Smrg        fprintf(stderr, "saved connection %d for %s %d\n",
2649fe517fc9Smrg                nr_fds, connection[nr_fds].BusID,
2650fe517fc9Smrg                strcmp(BusID, connection[nr_fds].BusID));
265122944501Smrg
265222944501Smrg    nr_fds++;
265322944501Smrg
265422944501Smrg    return fd;
265522944501Smrg}
265622944501Smrg
265722944501Smrgvoid drmCloseOnce(int fd)
265822944501Smrg{
265922944501Smrg    int i;
266022944501Smrg
266122944501Smrg    for (i = 0; i < nr_fds; i++) {
2662fe517fc9Smrg        if (fd == connection[i].fd) {
2663fe517fc9Smrg            if (--connection[i].refcount == 0) {
2664fe517fc9Smrg                drmClose(connection[i].fd);
2665fe517fc9Smrg                free(connection[i].BusID);
2666fe517fc9Smrg
2667fe517fc9Smrg                if (i < --nr_fds)
2668fe517fc9Smrg                    connection[i] = connection[nr_fds];
2669fe517fc9Smrg
2670fe517fc9Smrg                return;
2671fe517fc9Smrg            }
2672fe517fc9Smrg        }
267322944501Smrg    }
267422944501Smrg}
267522944501Smrg
267622944501Smrgint drmSetMaster(int fd)
267722944501Smrg{
2678fe517fc9Smrg        return drmIoctl(fd, DRM_IOCTL_SET_MASTER, NULL);
267922944501Smrg}
268022944501Smrg
268122944501Smrgint drmDropMaster(int fd)
268222944501Smrg{
2683fe517fc9Smrg        return drmIoctl(fd, DRM_IOCTL_DROP_MASTER, NULL);
268422944501Smrg}
268522944501Smrg
268622944501Smrgchar *drmGetDeviceNameFromFd(int fd)
268722944501Smrg{
2688fe517fc9Smrg    char name[128];
2689fe517fc9Smrg    struct stat sbuf;
2690fe517fc9Smrg    dev_t d;
2691fe517fc9Smrg    int i;
269222944501Smrg
2693fe517fc9Smrg    /* The whole drmOpen thing is a fiasco and we need to find a way
2694fe517fc9Smrg     * back to just using open(2).  For now, however, lets just make
2695fe517fc9Smrg     * things worse with even more ad hoc directory walking code to
2696fe517fc9Smrg     * discover the device file name. */
269722944501Smrg
2698fe517fc9Smrg    fstat(fd, &sbuf);
2699fe517fc9Smrg    d = sbuf.st_rdev;
270022944501Smrg
2701fe517fc9Smrg    for (i = 0; i < DRM_MAX_MINOR; i++) {
2702fe517fc9Smrg        snprintf(name, sizeof name, DRM_DEV_NAME, DRM_DIR_NAME, i);
2703fe517fc9Smrg        if (stat(name, &sbuf) == 0 && sbuf.st_rdev == d)
2704fe517fc9Smrg            break;
2705fe517fc9Smrg    }
2706fe517fc9Smrg    if (i == DRM_MAX_MINOR)
2707fe517fc9Smrg        return NULL;
270822944501Smrg
2709fe517fc9Smrg    return strdup(name);
271022944501Smrg}
271120131375Smrg
2712424e9256Smrgint drmGetNodeTypeFromFd(int fd)
2713424e9256Smrg{
2714fe517fc9Smrg    struct stat sbuf;
2715fe517fc9Smrg    int maj, min, type;
2716424e9256Smrg
2717fe517fc9Smrg    if (fstat(fd, &sbuf))
2718fe517fc9Smrg        return -1;
2719424e9256Smrg
2720fe517fc9Smrg    maj = major(sbuf.st_rdev);
2721fe517fc9Smrg    min = minor(sbuf.st_rdev);
2722424e9256Smrg
2723fe517fc9Smrg    if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode)) {
2724fe517fc9Smrg        errno = EINVAL;
2725fe517fc9Smrg        return -1;
2726fe517fc9Smrg    }
2727424e9256Smrg
2728fe517fc9Smrg    type = drmGetMinorType(min);
2729fe517fc9Smrg    if (type == -1)
2730fe517fc9Smrg        errno = ENODEV;
2731fe517fc9Smrg    return type;
2732424e9256Smrg}
2733424e9256Smrg
273420131375Smrgint drmPrimeHandleToFD(int fd, uint32_t handle, uint32_t flags, int *prime_fd)
273520131375Smrg{
2736fe517fc9Smrg    struct drm_prime_handle args;
2737fe517fc9Smrg    int ret;
273820131375Smrg
2739fe517fc9Smrg    memclear(args);
2740fe517fc9Smrg    args.fd = -1;
2741fe517fc9Smrg    args.handle = handle;
2742fe517fc9Smrg    args.flags = flags;
2743fe517fc9Smrg    ret = drmIoctl(fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &args);
2744fe517fc9Smrg    if (ret)
2745fe517fc9Smrg        return ret;
274620131375Smrg
2747fe517fc9Smrg    *prime_fd = args.fd;
2748fe517fc9Smrg    return 0;
274920131375Smrg}
275020131375Smrg
275120131375Smrgint drmPrimeFDToHandle(int fd, int prime_fd, uint32_t *handle)
275220131375Smrg{
2753fe517fc9Smrg    struct drm_prime_handle args;
2754fe517fc9Smrg    int ret;
275520131375Smrg
2756fe517fc9Smrg    memclear(args);
2757fe517fc9Smrg    args.fd = prime_fd;
2758fe517fc9Smrg    ret = drmIoctl(fd, DRM_IOCTL_PRIME_FD_TO_HANDLE, &args);
2759fe517fc9Smrg    if (ret)
2760fe517fc9Smrg        return ret;
276120131375Smrg
2762fe517fc9Smrg    *handle = args.handle;
2763fe517fc9Smrg    return 0;
276420131375Smrg}
2765424e9256Smrg
2766424e9256Smrgstatic char *drmGetMinorNameForFD(int fd, int type)
2767424e9256Smrg{
2768424e9256Smrg#ifdef __linux__
2769fe517fc9Smrg    DIR *sysdir;
2770fe517fc9Smrg    struct dirent *pent, *ent;
2771fe517fc9Smrg    struct stat sbuf;
2772fe517fc9Smrg    const char *name = drmGetMinorName(type);
2773fe517fc9Smrg    int len;
2774fe517fc9Smrg    char dev_name[64], buf[64];
2775fe517fc9Smrg    long name_max;
2776fe517fc9Smrg    int maj, min;
2777fe517fc9Smrg
2778fe517fc9Smrg    if (!name)
2779fe517fc9Smrg        return NULL;
2780424e9256Smrg
2781fe517fc9Smrg    len = strlen(name);
2782424e9256Smrg
2783fe517fc9Smrg    if (fstat(fd, &sbuf))
2784fe517fc9Smrg        return NULL;
2785424e9256Smrg
2786fe517fc9Smrg    maj = major(sbuf.st_rdev);
2787fe517fc9Smrg    min = minor(sbuf.st_rdev);
2788424e9256Smrg
2789fe517fc9Smrg    if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode))
2790fe517fc9Smrg        return NULL;
2791424e9256Smrg
2792fe517fc9Smrg    snprintf(buf, sizeof(buf), "/sys/dev/char/%d:%d/device/drm", maj, min);
2793424e9256Smrg
2794fe517fc9Smrg    sysdir = opendir(buf);
2795fe517fc9Smrg    if (!sysdir)
2796fe517fc9Smrg        return NULL;
2797424e9256Smrg
2798fe517fc9Smrg    name_max = fpathconf(dirfd(sysdir), _PC_NAME_MAX);
2799fe517fc9Smrg    if (name_max == -1)
2800fe517fc9Smrg        goto out_close_dir;
2801424e9256Smrg
2802fe517fc9Smrg    pent = malloc(offsetof(struct dirent, d_name) + name_max + 1);
2803fe517fc9Smrg    if (pent == NULL)
2804fe517fc9Smrg         goto out_close_dir;
2805424e9256Smrg
2806fe517fc9Smrg    while (readdir_r(sysdir, pent, &ent) == 0 && ent != NULL) {
2807fe517fc9Smrg        if (strncmp(ent->d_name, name, len) == 0) {
2808fe517fc9Smrg            snprintf(dev_name, sizeof(dev_name), DRM_DIR_NAME "/%s",
2809fe517fc9Smrg                 ent->d_name);
2810424e9256Smrg
2811fe517fc9Smrg            free(pent);
2812fe517fc9Smrg            closedir(sysdir);
2813424e9256Smrg
2814fe517fc9Smrg            return strdup(dev_name);
2815fe517fc9Smrg        }
2816fe517fc9Smrg    }
2817424e9256Smrg
2818fe517fc9Smrg    free(pent);
2819424e9256Smrg
2820424e9256Smrgout_close_dir:
2821fe517fc9Smrg    closedir(sysdir);
2822fe517fc9Smrg#else
2823fe517fc9Smrg#warning "Missing implementation of drmGetMinorNameForFD"
2824424e9256Smrg#endif
2825fe517fc9Smrg    return NULL;
2826424e9256Smrg}
2827424e9256Smrg
2828424e9256Smrgchar *drmGetPrimaryDeviceNameFromFd(int fd)
2829424e9256Smrg{
2830fe517fc9Smrg    return drmGetMinorNameForFD(fd, DRM_NODE_PRIMARY);
2831424e9256Smrg}
2832424e9256Smrg
2833424e9256Smrgchar *drmGetRenderDeviceNameFromFd(int fd)
2834424e9256Smrg{
2835fe517fc9Smrg    return drmGetMinorNameForFD(fd, DRM_NODE_RENDER);
2836fe517fc9Smrg}
2837fe517fc9Smrg
2838fe517fc9Smrgstatic int drmParseSubsystemType(int maj, int min)
2839fe517fc9Smrg{
2840fe517fc9Smrg#ifdef __linux__
2841fe517fc9Smrg    char path[PATH_MAX + 1];
2842fe517fc9Smrg    char link[PATH_MAX + 1] = "";
2843fe517fc9Smrg    char *name;
2844fe517fc9Smrg
2845fe517fc9Smrg    snprintf(path, PATH_MAX, "/sys/dev/char/%d:%d/device/subsystem",
2846fe517fc9Smrg             maj, min);
2847fe517fc9Smrg
2848fe517fc9Smrg    if (readlink(path, link, PATH_MAX) < 0)
2849fe517fc9Smrg        return -errno;
2850fe517fc9Smrg
2851fe517fc9Smrg    name = strrchr(link, '/');
2852fe517fc9Smrg    if (!name)
2853fe517fc9Smrg        return -EINVAL;
2854fe517fc9Smrg
2855fe517fc9Smrg    if (strncmp(name, "/pci", 4) == 0)
2856fe517fc9Smrg        return DRM_BUS_PCI;
2857fe517fc9Smrg
2858fe517fc9Smrg    return -EINVAL;
2859fe517fc9Smrg#else
2860fe517fc9Smrg#warning "Missing implementation of drmParseSubsystemType"
2861fe517fc9Smrg    return -EINVAL;
2862fe517fc9Smrg#endif
2863fe517fc9Smrg}
2864fe517fc9Smrg
2865fe517fc9Smrgstatic int drmParsePciBusInfo(int maj, int min, drmPciBusInfoPtr info)
2866fe517fc9Smrg{
2867fe517fc9Smrg#ifdef __linux__
2868fe517fc9Smrg    char path[PATH_MAX + 1];
2869fe517fc9Smrg    char data[128 + 1];
2870fe517fc9Smrg    char *str;
2871fe517fc9Smrg    int domain, bus, dev, func;
2872fe517fc9Smrg    int fd, ret;
2873fe517fc9Smrg
2874fe517fc9Smrg    snprintf(path, PATH_MAX, "/sys/dev/char/%d:%d/device/uevent", maj, min);
2875fe517fc9Smrg    fd = open(path, O_RDONLY);
2876fe517fc9Smrg    if (fd < 0)
2877fe517fc9Smrg        return -errno;
2878fe517fc9Smrg
2879fe517fc9Smrg    ret = read(fd, data, sizeof(data));
2880fe517fc9Smrg    data[128] = '\0';
2881fe517fc9Smrg    close(fd);
2882fe517fc9Smrg    if (ret < 0)
2883fe517fc9Smrg        return -errno;
2884fe517fc9Smrg
2885fe517fc9Smrg#define TAG "PCI_SLOT_NAME="
2886fe517fc9Smrg    str = strstr(data, TAG);
2887fe517fc9Smrg    if (str == NULL)
2888fe517fc9Smrg        return -EINVAL;
2889fe517fc9Smrg
2890fe517fc9Smrg    if (sscanf(str, TAG "%04x:%02x:%02x.%1u",
2891fe517fc9Smrg               &domain, &bus, &dev, &func) != 4)
2892fe517fc9Smrg        return -EINVAL;
2893fe517fc9Smrg#undef TAG
2894fe517fc9Smrg
2895fe517fc9Smrg    info->domain = domain;
2896fe517fc9Smrg    info->bus = bus;
2897fe517fc9Smrg    info->dev = dev;
2898fe517fc9Smrg    info->func = func;
2899fe517fc9Smrg
2900fe517fc9Smrg    return 0;
2901fe517fc9Smrg#else
2902fe517fc9Smrg#warning "Missing implementation of drmParsePciBusInfo"
2903fe517fc9Smrg    return -EINVAL;
2904fe517fc9Smrg#endif
2905fe517fc9Smrg}
2906fe517fc9Smrg
2907fe517fc9Smrgstatic int drmCompareBusInfo(drmDevicePtr a, drmDevicePtr b)
2908fe517fc9Smrg{
2909fe517fc9Smrg    if (a == NULL || b == NULL)
2910fe517fc9Smrg        return -1;
2911fe517fc9Smrg
2912fe517fc9Smrg    if (a->bustype != b->bustype)
2913fe517fc9Smrg        return -1;
2914fe517fc9Smrg
2915fe517fc9Smrg    switch (a->bustype) {
2916fe517fc9Smrg    case DRM_BUS_PCI:
2917fe517fc9Smrg        return memcmp(a->businfo.pci, b->businfo.pci, sizeof(drmPciBusInfo));
2918fe517fc9Smrg    default:
2919fe517fc9Smrg        break;
2920fe517fc9Smrg    }
2921fe517fc9Smrg
2922fe517fc9Smrg    return -1;
2923fe517fc9Smrg}
2924fe517fc9Smrg
2925fe517fc9Smrgstatic int drmGetNodeType(const char *name)
2926fe517fc9Smrg{
2927fe517fc9Smrg    if (strncmp(name, DRM_PRIMARY_MINOR_NAME,
2928fe517fc9Smrg        sizeof(DRM_PRIMARY_MINOR_NAME) - 1) == 0)
2929fe517fc9Smrg        return DRM_NODE_PRIMARY;
2930fe517fc9Smrg
2931fe517fc9Smrg    if (strncmp(name, DRM_CONTROL_MINOR_NAME,
2932fe517fc9Smrg        sizeof(DRM_CONTROL_MINOR_NAME ) - 1) == 0)
2933fe517fc9Smrg        return DRM_NODE_CONTROL;
2934fe517fc9Smrg
2935fe517fc9Smrg    if (strncmp(name, DRM_RENDER_MINOR_NAME,
2936fe517fc9Smrg        sizeof(DRM_RENDER_MINOR_NAME) - 1) == 0)
2937fe517fc9Smrg        return DRM_NODE_RENDER;
2938fe517fc9Smrg
2939fe517fc9Smrg    return -EINVAL;
2940fe517fc9Smrg}
2941fe517fc9Smrg
2942fe517fc9Smrgstatic int drmGetMaxNodeName(void)
2943fe517fc9Smrg{
2944fe517fc9Smrg    return sizeof(DRM_DIR_NAME) +
2945fe517fc9Smrg           MAX3(sizeof(DRM_PRIMARY_MINOR_NAME),
2946fe517fc9Smrg                sizeof(DRM_CONTROL_MINOR_NAME),
2947fe517fc9Smrg                sizeof(DRM_RENDER_MINOR_NAME)) +
2948fe517fc9Smrg           3 /* length of the node number */;
2949fe517fc9Smrg}
2950fe517fc9Smrg
2951fe517fc9Smrgstatic int drmParsePciDeviceInfo(const char *d_name,
2952fe517fc9Smrg                                 drmPciDeviceInfoPtr device)
2953fe517fc9Smrg{
2954fe517fc9Smrg#ifdef __linux__
2955fe517fc9Smrg    char path[PATH_MAX + 1];
2956fe517fc9Smrg    unsigned char config[64];
2957fe517fc9Smrg    int fd, ret;
2958fe517fc9Smrg
2959fe517fc9Smrg    snprintf(path, PATH_MAX, "/sys/class/drm/%s/device/config", d_name);
2960fe517fc9Smrg    fd = open(path, O_RDONLY);
2961fe517fc9Smrg    if (fd < 0)
2962fe517fc9Smrg        return -errno;
2963fe517fc9Smrg
2964fe517fc9Smrg    ret = read(fd, config, sizeof(config));
2965fe517fc9Smrg    close(fd);
2966fe517fc9Smrg    if (ret < 0)
2967fe517fc9Smrg        return -errno;
2968fe517fc9Smrg
2969fe517fc9Smrg    device->vendor_id = config[0] | (config[1] << 8);
2970fe517fc9Smrg    device->device_id = config[2] | (config[3] << 8);
2971fe517fc9Smrg    device->revision_id = config[8];
2972fe517fc9Smrg    device->subvendor_id = config[44] | (config[45] << 8);
2973fe517fc9Smrg    device->subdevice_id = config[46] | (config[47] << 8);
2974fe517fc9Smrg
2975fe517fc9Smrg    return 0;
2976fe517fc9Smrg#else
2977fe517fc9Smrg#warning "Missing implementation of drmParsePciDeviceInfo"
2978fe517fc9Smrg    return -EINVAL;
2979fe517fc9Smrg#endif
2980fe517fc9Smrg}
2981fe517fc9Smrg
2982fe517fc9Smrgvoid drmFreeDevice(drmDevicePtr *device)
2983fe517fc9Smrg{
2984fe517fc9Smrg    if (device == NULL)
2985fe517fc9Smrg        return;
2986fe517fc9Smrg
2987fe517fc9Smrg    free(*device);
2988fe517fc9Smrg    *device = NULL;
2989fe517fc9Smrg}
2990fe517fc9Smrg
2991fe517fc9Smrgvoid drmFreeDevices(drmDevicePtr devices[], int count)
2992fe517fc9Smrg{
2993fe517fc9Smrg    int i;
2994fe517fc9Smrg
2995fe517fc9Smrg    if (devices == NULL)
2996fe517fc9Smrg        return;
2997fe517fc9Smrg
2998fe517fc9Smrg    for (i = 0; i < count; i++)
2999fe517fc9Smrg        if (devices[i])
3000fe517fc9Smrg            drmFreeDevice(&devices[i]);
3001fe517fc9Smrg}
3002fe517fc9Smrg
3003fe517fc9Smrgstatic int drmProcessPciDevice(drmDevicePtr *device, const char *d_name,
3004fe517fc9Smrg                               const char *node, int node_type,
3005fe517fc9Smrg                               int maj, int min, bool fetch_deviceinfo)
3006fe517fc9Smrg{
3007fe517fc9Smrg    const int max_node_str = ALIGN(drmGetMaxNodeName(), sizeof(void *));
3008fe517fc9Smrg    int ret, i;
3009fe517fc9Smrg    char *addr;
3010fe517fc9Smrg
3011fe517fc9Smrg    *device = calloc(1, sizeof(drmDevice) +
3012fe517fc9Smrg                     (DRM_NODE_MAX * (sizeof(void *) + max_node_str)) +
3013fe517fc9Smrg                     sizeof(drmPciBusInfo) +
3014fe517fc9Smrg                     sizeof(drmPciDeviceInfo));
3015fe517fc9Smrg    if (!*device)
3016fe517fc9Smrg        return -ENOMEM;
3017fe517fc9Smrg
3018fe517fc9Smrg    addr = (char*)*device;
3019fe517fc9Smrg
3020fe517fc9Smrg    (*device)->bustype = DRM_BUS_PCI;
3021fe517fc9Smrg    (*device)->available_nodes = 1 << node_type;
3022fe517fc9Smrg
3023fe517fc9Smrg    addr += sizeof(drmDevice);
3024fe517fc9Smrg    (*device)->nodes = (char**)addr;
3025fe517fc9Smrg
3026fe517fc9Smrg    addr += DRM_NODE_MAX * sizeof(void *);
3027fe517fc9Smrg    for (i = 0; i < DRM_NODE_MAX; i++) {
3028fe517fc9Smrg        (*device)->nodes[i] = addr;
3029fe517fc9Smrg        addr += max_node_str;
3030fe517fc9Smrg    }
3031fe517fc9Smrg    memcpy((*device)->nodes[node_type], node, max_node_str);
3032fe517fc9Smrg
3033fe517fc9Smrg    (*device)->businfo.pci = (drmPciBusInfoPtr)addr;
3034fe517fc9Smrg
3035fe517fc9Smrg    ret = drmParsePciBusInfo(maj, min, (*device)->businfo.pci);
3036fe517fc9Smrg    if (ret)
3037fe517fc9Smrg        goto free_device;
3038fe517fc9Smrg
3039fe517fc9Smrg    // Fetch the device info if the user has requested it
3040fe517fc9Smrg    if (fetch_deviceinfo) {
3041fe517fc9Smrg        addr += sizeof(drmPciBusInfo);
3042fe517fc9Smrg        (*device)->deviceinfo.pci = (drmPciDeviceInfoPtr)addr;
3043fe517fc9Smrg
3044fe517fc9Smrg        ret = drmParsePciDeviceInfo(d_name, (*device)->deviceinfo.pci);
3045fe517fc9Smrg        if (ret)
3046fe517fc9Smrg            goto free_device;
3047fe517fc9Smrg    }
3048fe517fc9Smrg    return 0;
3049fe517fc9Smrg
3050fe517fc9Smrgfree_device:
3051fe517fc9Smrg    free(*device);
3052fe517fc9Smrg    *device = NULL;
3053fe517fc9Smrg    return ret;
3054fe517fc9Smrg}
3055fe517fc9Smrg
3056fe517fc9Smrg/* Consider devices located on the same bus as duplicate and fold the respective
3057fe517fc9Smrg * entries into a single one.
3058fe517fc9Smrg *
3059fe517fc9Smrg * Note: this leaves "gaps" in the array, while preserving the length.
3060fe517fc9Smrg */
3061fe517fc9Smrgstatic void drmFoldDuplicatedDevices(drmDevicePtr local_devices[], int count)
3062fe517fc9Smrg{
3063fe517fc9Smrg    int node_type, i, j;
3064fe517fc9Smrg
3065fe517fc9Smrg    for (i = 0; i < count; i++) {
3066fe517fc9Smrg        for (j = i + 1; j < count; j++) {
3067fe517fc9Smrg            if (drmCompareBusInfo(local_devices[i], local_devices[j]) == 0) {
3068fe517fc9Smrg                local_devices[i]->available_nodes |= local_devices[j]->available_nodes;
3069fe517fc9Smrg                node_type = log2(local_devices[j]->available_nodes);
3070fe517fc9Smrg                memcpy(local_devices[i]->nodes[node_type],
3071fe517fc9Smrg                       local_devices[j]->nodes[node_type], drmGetMaxNodeName());
3072fe517fc9Smrg                drmFreeDevice(&local_devices[j]);
3073fe517fc9Smrg            }
3074fe517fc9Smrg        }
3075fe517fc9Smrg    }
3076fe517fc9Smrg}
3077fe517fc9Smrg
3078fe517fc9Smrg/**
3079fe517fc9Smrg * Get information about the opened drm device
3080fe517fc9Smrg *
3081fe517fc9Smrg * \param fd file descriptor of the drm device
3082fe517fc9Smrg * \param device the address of a drmDevicePtr where the information
3083fe517fc9Smrg *               will be allocated in stored
3084fe517fc9Smrg *
3085fe517fc9Smrg * \return zero on success, negative error code otherwise.
3086fe517fc9Smrg */
3087fe517fc9Smrgint drmGetDevice(int fd, drmDevicePtr *device)
3088fe517fc9Smrg{
3089fe517fc9Smrg    drmDevicePtr *local_devices;
3090fe517fc9Smrg    drmDevicePtr d;
3091fe517fc9Smrg    DIR *sysdir;
3092fe517fc9Smrg    struct dirent *dent;
3093fe517fc9Smrg    struct stat sbuf;
3094fe517fc9Smrg    char node[PATH_MAX + 1];
3095fe517fc9Smrg    int node_type, subsystem_type;
3096fe517fc9Smrg    int maj, min;
3097fe517fc9Smrg    int ret, i, node_count;
3098fe517fc9Smrg    int max_count = 16;
3099fe517fc9Smrg    dev_t find_rdev;
3100fe517fc9Smrg
3101fe517fc9Smrg    if (fd == -1 || device == NULL)
3102fe517fc9Smrg        return -EINVAL;
3103fe517fc9Smrg
3104fe517fc9Smrg    if (fstat(fd, &sbuf))
3105fe517fc9Smrg        return -errno;
3106fe517fc9Smrg
3107fe517fc9Smrg    find_rdev = sbuf.st_rdev;
3108fe517fc9Smrg    maj = major(sbuf.st_rdev);
3109fe517fc9Smrg    min = minor(sbuf.st_rdev);
3110fe517fc9Smrg
3111fe517fc9Smrg    if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode))
3112fe517fc9Smrg        return -EINVAL;
3113fe517fc9Smrg
3114fe517fc9Smrg    subsystem_type = drmParseSubsystemType(maj, min);
3115fe517fc9Smrg
3116fe517fc9Smrg    local_devices = calloc(max_count, sizeof(drmDevicePtr));
3117fe517fc9Smrg    if (local_devices == NULL)
3118fe517fc9Smrg        return -ENOMEM;
3119fe517fc9Smrg
3120fe517fc9Smrg    sysdir = opendir(DRM_DIR_NAME);
3121fe517fc9Smrg    if (!sysdir) {
3122fe517fc9Smrg        ret = -errno;
3123fe517fc9Smrg        goto free_locals;
3124fe517fc9Smrg    }
3125fe517fc9Smrg
3126fe517fc9Smrg    i = 0;
3127fe517fc9Smrg    while ((dent = readdir(sysdir))) {
3128fe517fc9Smrg        node_type = drmGetNodeType(dent->d_name);
3129fe517fc9Smrg        if (node_type < 0)
3130fe517fc9Smrg            continue;
3131fe517fc9Smrg
3132fe517fc9Smrg        snprintf(node, PATH_MAX, "%s/%s", DRM_DIR_NAME, dent->d_name);
3133fe517fc9Smrg        if (stat(node, &sbuf))
3134fe517fc9Smrg            continue;
3135fe517fc9Smrg
3136fe517fc9Smrg        maj = major(sbuf.st_rdev);
3137fe517fc9Smrg        min = minor(sbuf.st_rdev);
3138fe517fc9Smrg
3139fe517fc9Smrg        if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode))
3140fe517fc9Smrg            continue;
3141fe517fc9Smrg
3142fe517fc9Smrg        if (drmParseSubsystemType(maj, min) != subsystem_type)
3143fe517fc9Smrg            continue;
3144fe517fc9Smrg
3145fe517fc9Smrg        switch (subsystem_type) {
3146fe517fc9Smrg        case DRM_BUS_PCI:
3147fe517fc9Smrg            ret = drmProcessPciDevice(&d, dent->d_name, node, node_type,
3148fe517fc9Smrg                                      maj, min, true);
3149fe517fc9Smrg            if (ret)
3150fe517fc9Smrg                goto free_devices;
3151fe517fc9Smrg
3152fe517fc9Smrg            break;
3153fe517fc9Smrg        default:
3154fe517fc9Smrg            fprintf(stderr, "The subsystem type is not supported yet\n");
3155fe517fc9Smrg            continue;
3156fe517fc9Smrg        }
3157fe517fc9Smrg
3158fe517fc9Smrg        if (i >= max_count) {
3159fe517fc9Smrg            drmDevicePtr *temp;
3160fe517fc9Smrg
3161fe517fc9Smrg            max_count += 16;
3162fe517fc9Smrg            temp = realloc(local_devices, max_count * sizeof(drmDevicePtr));
3163fe517fc9Smrg            if (!temp)
3164fe517fc9Smrg                goto free_devices;
3165fe517fc9Smrg            local_devices = temp;
3166fe517fc9Smrg        }
3167fe517fc9Smrg
3168fe517fc9Smrg        /* store target at local_devices[0] for ease to use below */
3169fe517fc9Smrg        if (find_rdev == sbuf.st_rdev && i) {
3170fe517fc9Smrg            local_devices[i] = local_devices[0];
3171fe517fc9Smrg            local_devices[0] = d;
3172fe517fc9Smrg        }
3173fe517fc9Smrg        else
3174fe517fc9Smrg            local_devices[i] = d;
3175fe517fc9Smrg        i++;
3176fe517fc9Smrg    }
3177fe517fc9Smrg    node_count = i;
3178fe517fc9Smrg
3179fe517fc9Smrg    drmFoldDuplicatedDevices(local_devices, node_count);
3180fe517fc9Smrg
3181fe517fc9Smrg    *device = local_devices[0];
3182fe517fc9Smrg    drmFreeDevices(&local_devices[1], node_count - 1);
3183fe517fc9Smrg
3184fe517fc9Smrg    closedir(sysdir);
3185fe517fc9Smrg    free(local_devices);
3186fe517fc9Smrg    return 0;
3187fe517fc9Smrg
3188fe517fc9Smrgfree_devices:
3189fe517fc9Smrg    drmFreeDevices(local_devices, i);
3190fe517fc9Smrg    closedir(sysdir);
3191fe517fc9Smrg
3192fe517fc9Smrgfree_locals:
3193fe517fc9Smrg    free(local_devices);
3194fe517fc9Smrg    return ret;
3195fe517fc9Smrg}
3196fe517fc9Smrg
3197fe517fc9Smrg/**
3198fe517fc9Smrg * Get drm devices on the system
3199fe517fc9Smrg *
3200fe517fc9Smrg * \param devices the array of devices with drmDevicePtr elements
3201fe517fc9Smrg *                can be NULL to get the device number first
3202fe517fc9Smrg * \param max_devices the maximum number of devices for the array
3203fe517fc9Smrg *
3204fe517fc9Smrg * \return on error - negative error code,
3205fe517fc9Smrg *         if devices is NULL - total number of devices available on the system,
3206fe517fc9Smrg *         alternatively the number of devices stored in devices[], which is
3207fe517fc9Smrg *         capped by the max_devices.
3208fe517fc9Smrg */
3209fe517fc9Smrgint drmGetDevices(drmDevicePtr devices[], int max_devices)
3210fe517fc9Smrg{
3211fe517fc9Smrg    drmDevicePtr *local_devices;
3212fe517fc9Smrg    drmDevicePtr device;
3213fe517fc9Smrg    DIR *sysdir;
3214fe517fc9Smrg    struct dirent *dent;
3215fe517fc9Smrg    struct stat sbuf;
3216fe517fc9Smrg    char node[PATH_MAX + 1];
3217fe517fc9Smrg    int node_type, subsystem_type;
3218fe517fc9Smrg    int maj, min;
3219fe517fc9Smrg    int ret, i, node_count, device_count;
3220fe517fc9Smrg    int max_count = 16;
3221fe517fc9Smrg
3222fe517fc9Smrg    local_devices = calloc(max_count, sizeof(drmDevicePtr));
3223fe517fc9Smrg    if (local_devices == NULL)
3224fe517fc9Smrg        return -ENOMEM;
3225fe517fc9Smrg
3226fe517fc9Smrg    sysdir = opendir(DRM_DIR_NAME);
3227fe517fc9Smrg    if (!sysdir) {
3228fe517fc9Smrg        ret = -errno;
3229fe517fc9Smrg        goto free_locals;
3230fe517fc9Smrg    }
3231fe517fc9Smrg
3232fe517fc9Smrg    i = 0;
3233fe517fc9Smrg    while ((dent = readdir(sysdir))) {
3234fe517fc9Smrg        node_type = drmGetNodeType(dent->d_name);
3235fe517fc9Smrg        if (node_type < 0)
3236fe517fc9Smrg            continue;
3237fe517fc9Smrg
3238fe517fc9Smrg        snprintf(node, PATH_MAX, "%s/%s", DRM_DIR_NAME, dent->d_name);
3239fe517fc9Smrg        if (stat(node, &sbuf))
3240fe517fc9Smrg            continue;
3241fe517fc9Smrg
3242fe517fc9Smrg        maj = major(sbuf.st_rdev);
3243fe517fc9Smrg        min = minor(sbuf.st_rdev);
3244fe517fc9Smrg
3245fe517fc9Smrg        if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode))
3246fe517fc9Smrg            continue;
3247fe517fc9Smrg
3248fe517fc9Smrg        subsystem_type = drmParseSubsystemType(maj, min);
3249fe517fc9Smrg
3250fe517fc9Smrg        if (subsystem_type < 0)
3251fe517fc9Smrg            continue;
3252fe517fc9Smrg
3253fe517fc9Smrg        switch (subsystem_type) {
3254fe517fc9Smrg        case DRM_BUS_PCI:
3255fe517fc9Smrg            ret = drmProcessPciDevice(&device, dent->d_name, node, node_type,
3256fe517fc9Smrg                                      maj, min, devices != NULL);
3257fe517fc9Smrg            if (ret)
3258fe517fc9Smrg                goto free_devices;
3259fe517fc9Smrg
3260fe517fc9Smrg            break;
3261fe517fc9Smrg        default:
3262fe517fc9Smrg            fprintf(stderr, "The subsystem type is not supported yet\n");
3263fe517fc9Smrg            continue;
3264fe517fc9Smrg        }
3265fe517fc9Smrg
3266fe517fc9Smrg        if (i >= max_count) {
3267fe517fc9Smrg            drmDevicePtr *temp;
3268fe517fc9Smrg
3269fe517fc9Smrg            max_count += 16;
3270fe517fc9Smrg            temp = realloc(local_devices, max_count * sizeof(drmDevicePtr));
3271fe517fc9Smrg            if (!temp)
3272fe517fc9Smrg                goto free_devices;
3273fe517fc9Smrg            local_devices = temp;
3274fe517fc9Smrg        }
3275fe517fc9Smrg
3276fe517fc9Smrg        local_devices[i] = device;
3277fe517fc9Smrg        i++;
3278fe517fc9Smrg    }
3279fe517fc9Smrg    node_count = i;
3280fe517fc9Smrg
3281fe517fc9Smrg    drmFoldDuplicatedDevices(local_devices, node_count);
3282fe517fc9Smrg
3283fe517fc9Smrg    device_count = 0;
3284fe517fc9Smrg    for (i = 0; i < node_count; i++) {
3285fe517fc9Smrg        if (!local_devices[i])
3286fe517fc9Smrg            continue;
3287fe517fc9Smrg
3288fe517fc9Smrg        if ((devices != NULL) && (device_count < max_devices))
3289fe517fc9Smrg            devices[device_count] = local_devices[i];
3290fe517fc9Smrg        else
3291fe517fc9Smrg            drmFreeDevice(&local_devices[i]);
3292fe517fc9Smrg
3293fe517fc9Smrg        device_count++;
3294fe517fc9Smrg    }
3295fe517fc9Smrg
3296fe517fc9Smrg    closedir(sysdir);
3297fe517fc9Smrg    free(local_devices);
3298fe517fc9Smrg    return device_count;
3299fe517fc9Smrg
3300fe517fc9Smrgfree_devices:
3301fe517fc9Smrg    drmFreeDevices(local_devices, i);
3302fe517fc9Smrg    closedir(sysdir);
3303fe517fc9Smrg
3304fe517fc9Smrgfree_locals:
3305fe517fc9Smrg    free(local_devices);
3306fe517fc9Smrg    return ret;
3307424e9256Smrg}
3308