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