xf86drm.c revision 4545e80c
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 74fe517fc9Smrg#ifdef __OpenBSD__ 75fe517fc9Smrg#define DRM_PRIMARY_MINOR_NAME "drm" 76fe517fc9Smrg#define DRM_CONTROL_MINOR_NAME "drmC" 77fe517fc9Smrg#define DRM_RENDER_MINOR_NAME "drmR" 78fe517fc9Smrg#else 79fe517fc9Smrg#define DRM_PRIMARY_MINOR_NAME "card" 80fe517fc9Smrg#define DRM_CONTROL_MINOR_NAME "controlD" 81fe517fc9Smrg#define DRM_RENDER_MINOR_NAME "renderD" 82fe517fc9Smrg#endif 83fe517fc9Smrg 8422944501Smrg#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) 8522944501Smrg#define DRM_MAJOR 145 8622944501Smrg#endif 8722944501Smrg 8822944501Smrg#ifdef __NetBSD__ 892e6867f6Smrg#undef DRM_MAJOR 902e6867f6Smrg#define DRM_MAJOR 180 9106815bcbSmaya#include <sys/param.h> 92a970b457Sriastradh#include <dev/pci/pcireg.h> 93a970b457Sriastradh#include <pci.h> 9422944501Smrg#endif 9522944501Smrg 96fe517fc9Smrg#ifdef __OpenBSD__ 97fe517fc9Smrg#ifdef __i386__ 98fe517fc9Smrg#define DRM_MAJOR 88 99fe517fc9Smrg#else 100fe517fc9Smrg#define DRM_MAJOR 87 10122944501Smrg#endif 102fe517fc9Smrg#endif /* __OpenBSD__ */ 10322944501Smrg 104fe517fc9Smrg#ifndef DRM_MAJOR 105fe517fc9Smrg#define DRM_MAJOR 226 /* Linux */ 10622944501Smrg#endif 10722944501Smrg 1084545e80cSmrg#if defined(__OpenBSD__) || defined(__DragonFly__) 1092ee35494Smrgstruct drm_pciinfo { 1102ee35494Smrg uint16_t domain; 1112ee35494Smrg uint8_t bus; 1122ee35494Smrg uint8_t dev; 1132ee35494Smrg uint8_t func; 1142ee35494Smrg uint16_t vendor_id; 1152ee35494Smrg uint16_t device_id; 1162ee35494Smrg uint16_t subvendor_id; 1172ee35494Smrg uint16_t subdevice_id; 1182ee35494Smrg uint8_t revision_id; 1192ee35494Smrg}; 1202ee35494Smrg 1212ee35494Smrg#define DRM_IOCTL_GET_PCIINFO DRM_IOR(0x15, struct drm_pciinfo) 12211c53d23Schristos#endif 12311c53d23Schristos 12422944501Smrg#define DRM_MSG_VERBOSITY 3 12522944501Smrg 126424e9256Smrg#define memclear(s) memset(&s, 0, sizeof(s)) 12722944501Smrg 12822944501Smrgstatic drmServerInfoPtr drm_server_info; 12922944501Smrg 1306260e5d5Smrgdrm_public void drmSetServerInfo(drmServerInfoPtr info) 13122944501Smrg{ 13222944501Smrg drm_server_info = info; 13322944501Smrg} 13422944501Smrg 13522944501Smrg/** 13622944501Smrg * Output a message to stderr. 13722944501Smrg * 13822944501Smrg * \param format printf() like format string. 13922944501Smrg * 14022944501Smrg * \internal 14122944501Smrg * This function is a wrapper around vfprintf(). 14222944501Smrg */ 14322944501Smrg 144a7d7de1eSmrgstatic int DRM_PRINTFLIKE(1, 0) 145a7d7de1eSmrgdrmDebugPrint(const char *format, va_list ap) 14622944501Smrg{ 14722944501Smrg return vfprintf(stderr, format, ap); 14822944501Smrg} 14922944501Smrg 1506260e5d5Smrgdrm_public void 15122944501SmrgdrmMsg(const char *format, ...) 15222944501Smrg{ 153fe517fc9Smrg va_list ap; 15422944501Smrg const char *env; 155fe517fc9Smrg if (((env = getenv("LIBGL_DEBUG")) && strstr(env, "verbose")) || 156fe517fc9Smrg (drm_server_info && drm_server_info->debug_print)) 15722944501Smrg { 158fe517fc9Smrg va_start(ap, format); 159fe517fc9Smrg if (drm_server_info) { 160fe517fc9Smrg drm_server_info->debug_print(format,ap); 161fe517fc9Smrg } else { 162fe517fc9Smrg drmDebugPrint(format, ap); 163fe517fc9Smrg } 164fe517fc9Smrg va_end(ap); 16522944501Smrg } 16622944501Smrg} 16722944501Smrg 16822944501Smrgstatic void *drmHashTable = NULL; /* Context switch callbacks */ 16922944501Smrg 1706260e5d5Smrgdrm_public void *drmGetHashTable(void) 17122944501Smrg{ 17222944501Smrg return drmHashTable; 17322944501Smrg} 17422944501Smrg 1756260e5d5Smrgdrm_public void *drmMalloc(int size) 17622944501Smrg{ 177424e9256Smrg return calloc(1, size); 17822944501Smrg} 17922944501Smrg 1806260e5d5Smrgdrm_public void drmFree(void *pt) 18122944501Smrg{ 182424e9256Smrg free(pt); 18322944501Smrg} 18422944501Smrg 18522944501Smrg/** 18622944501Smrg * Call ioctl, restarting if it is interupted 18722944501Smrg */ 1886260e5d5Smrgdrm_public int 18922944501SmrgdrmIoctl(int fd, unsigned long request, void *arg) 19022944501Smrg{ 191fe517fc9Smrg int ret; 19222944501Smrg 19322944501Smrg do { 194fe517fc9Smrg ret = ioctl(fd, request, arg); 19522944501Smrg } while (ret == -1 && (errno == EINTR || errno == EAGAIN)); 19622944501Smrg return ret; 19722944501Smrg} 19822944501Smrg 19922944501Smrgstatic unsigned long drmGetKeyFromFd(int fd) 20022944501Smrg{ 20122944501Smrg stat_t st; 20222944501Smrg 20322944501Smrg st.st_rdev = 0; 20422944501Smrg fstat(fd, &st); 20522944501Smrg return st.st_rdev; 20622944501Smrg} 20722944501Smrg 2086260e5d5Smrgdrm_public drmHashEntry *drmGetEntry(int fd) 20922944501Smrg{ 21022944501Smrg unsigned long key = drmGetKeyFromFd(fd); 21122944501Smrg void *value; 21222944501Smrg drmHashEntry *entry; 21322944501Smrg 21422944501Smrg if (!drmHashTable) 215fe517fc9Smrg drmHashTable = drmHashCreate(); 21622944501Smrg 21722944501Smrg if (drmHashLookup(drmHashTable, key, &value)) { 218fe517fc9Smrg entry = drmMalloc(sizeof(*entry)); 219fe517fc9Smrg entry->fd = fd; 220fe517fc9Smrg entry->f = NULL; 221fe517fc9Smrg entry->tagTable = drmHashCreate(); 222fe517fc9Smrg drmHashInsert(drmHashTable, key, entry); 22322944501Smrg } else { 224fe517fc9Smrg entry = value; 22522944501Smrg } 22622944501Smrg return entry; 22722944501Smrg} 22822944501Smrg 22922944501Smrg/** 23022944501Smrg * Compare two busid strings 23122944501Smrg * 23222944501Smrg * \param first 23322944501Smrg * \param second 23422944501Smrg * 23522944501Smrg * \return 1 if matched. 23622944501Smrg * 23722944501Smrg * \internal 23822944501Smrg * This function compares two bus ID strings. It understands the older 23922944501Smrg * PCI:b:d:f format and the newer pci:oooo:bb:dd.f format. In the format, o is 24022944501Smrg * domain, b is bus, d is device, f is function. 24122944501Smrg */ 2426d98c517Smrgstatic int drmMatchBusID(const char *id1, const char *id2, int pci_domain_ok) 24322944501Smrg{ 24422944501Smrg /* First, check if the IDs are exactly the same */ 24522944501Smrg if (strcasecmp(id1, id2) == 0) 246fe517fc9Smrg return 1; 24722944501Smrg 24822944501Smrg /* Try to match old/new-style PCI bus IDs. */ 24922944501Smrg if (strncasecmp(id1, "pci", 3) == 0) { 250fe517fc9Smrg unsigned int o1, b1, d1, f1; 251fe517fc9Smrg unsigned int o2, b2, d2, f2; 252fe517fc9Smrg int ret; 253fe517fc9Smrg 254fe517fc9Smrg ret = sscanf(id1, "pci:%04x:%02x:%02x.%u", &o1, &b1, &d1, &f1); 255fe517fc9Smrg if (ret != 4) { 256fe517fc9Smrg o1 = 0; 257fe517fc9Smrg ret = sscanf(id1, "PCI:%u:%u:%u", &b1, &d1, &f1); 258fe517fc9Smrg if (ret != 3) 259fe517fc9Smrg return 0; 260fe517fc9Smrg } 261fe517fc9Smrg 262fe517fc9Smrg ret = sscanf(id2, "pci:%04x:%02x:%02x.%u", &o2, &b2, &d2, &f2); 263fe517fc9Smrg if (ret != 4) { 264fe517fc9Smrg o2 = 0; 265fe517fc9Smrg ret = sscanf(id2, "PCI:%u:%u:%u", &b2, &d2, &f2); 266fe517fc9Smrg if (ret != 3) 267fe517fc9Smrg return 0; 268fe517fc9Smrg } 269fe517fc9Smrg 270fe517fc9Smrg /* If domains aren't properly supported by the kernel interface, 271fe517fc9Smrg * just ignore them, which sucks less than picking a totally random 272fe517fc9Smrg * card with "open by name" 273fe517fc9Smrg */ 274fe517fc9Smrg if (!pci_domain_ok) 275fe517fc9Smrg o1 = o2 = 0; 276fe517fc9Smrg 277fe517fc9Smrg if ((o1 != o2) || (b1 != b2) || (d1 != d2) || (f1 != f2)) 278fe517fc9Smrg return 0; 279fe517fc9Smrg else 280fe517fc9Smrg return 1; 28122944501Smrg } 28222944501Smrg return 0; 28322944501Smrg} 28422944501Smrg 28522944501Smrg/** 28622944501Smrg * Handles error checking for chown call. 28722944501Smrg * 28822944501Smrg * \param path to file. 28922944501Smrg * \param id of the new owner. 29022944501Smrg * \param id of the new group. 29122944501Smrg * 29222944501Smrg * \return zero if success or -1 if failure. 29322944501Smrg * 29422944501Smrg * \internal 29522944501Smrg * Checks for failure. If failure was caused by signal call chown again. 29622944501Smrg * If any other failure happened then it will output error mesage using 29722944501Smrg * drmMsg() call. 29822944501Smrg */ 2996260e5d5Smrg#if !UDEV 30022944501Smrgstatic int chown_check_return(const char *path, uid_t owner, gid_t group) 30122944501Smrg{ 302fe517fc9Smrg int rv; 30322944501Smrg 304fe517fc9Smrg do { 305fe517fc9Smrg rv = chown(path, owner, group); 306fe517fc9Smrg } while (rv != 0 && errno == EINTR); 30722944501Smrg 308fe517fc9Smrg if (rv == 0) 309fe517fc9Smrg return 0; 31022944501Smrg 311fe517fc9Smrg drmMsg("Failed to change owner or group for file %s! %d: %s\n", 312fe517fc9Smrg path, errno, strerror(errno)); 313fe517fc9Smrg return -1; 31422944501Smrg} 315424e9256Smrg#endif 31622944501Smrg 31722944501Smrg/** 31822944501Smrg * Open the DRM device, creating it if necessary. 31922944501Smrg * 32022944501Smrg * \param dev major and minor numbers of the device. 32122944501Smrg * \param minor minor number of the device. 322fe517fc9Smrg * 32322944501Smrg * \return a file descriptor on success, or a negative value on error. 32422944501Smrg * 32522944501Smrg * \internal 32622944501Smrg * Assembles the device name from \p minor and opens it, creating the device 32722944501Smrg * special file node with the major and minor numbers specified by \p dev and 32822944501Smrg * parent directory if necessary and was called by root. 32922944501Smrg */ 330424e9256Smrgstatic int drmOpenDevice(dev_t dev, int minor, int type) 33122944501Smrg{ 33222944501Smrg stat_t st; 333424e9256Smrg const char *dev_name; 33422944501Smrg char buf[64]; 33522944501Smrg int fd; 33622944501Smrg mode_t devmode = DRM_DEV_MODE, serv_mode; 337424e9256Smrg gid_t serv_group; 3386260e5d5Smrg#if !UDEV 33922944501Smrg int isroot = !geteuid(); 34022944501Smrg uid_t user = DRM_DEV_UID; 341424e9256Smrg gid_t group = DRM_DEV_GID; 342424e9256Smrg#endif 343424e9256Smrg 344424e9256Smrg switch (type) { 345424e9256Smrg case DRM_NODE_PRIMARY: 346fe517fc9Smrg dev_name = DRM_DEV_NAME; 347fe517fc9Smrg break; 348424e9256Smrg case DRM_NODE_CONTROL: 349fe517fc9Smrg dev_name = DRM_CONTROL_DEV_NAME; 350fe517fc9Smrg break; 351424e9256Smrg case DRM_NODE_RENDER: 352fe517fc9Smrg dev_name = DRM_RENDER_DEV_NAME; 353fe517fc9Smrg break; 354424e9256Smrg default: 355fe517fc9Smrg return -EINVAL; 356424e9256Smrg }; 357424e9256Smrg 358424e9256Smrg sprintf(buf, dev_name, DRM_DIR_NAME, minor); 35922944501Smrg drmMsg("drmOpenDevice: node name is %s\n", buf); 36022944501Smrg 361fe517fc9Smrg if (drm_server_info && drm_server_info->get_perms) { 362fe517fc9Smrg drm_server_info->get_perms(&serv_group, &serv_mode); 363fe517fc9Smrg devmode = serv_mode ? serv_mode : DRM_DEV_MODE; 364fe517fc9Smrg devmode &= ~(S_IXUSR|S_IXGRP|S_IXOTH); 36522944501Smrg } 36622944501Smrg 3676260e5d5Smrg#if !UDEV 36822944501Smrg if (stat(DRM_DIR_NAME, &st)) { 369fe517fc9Smrg if (!isroot) 370fe517fc9Smrg return DRM_ERR_NOT_ROOT; 371fe517fc9Smrg mkdir(DRM_DIR_NAME, DRM_DEV_DIRMODE); 372fe517fc9Smrg chown_check_return(DRM_DIR_NAME, 0, 0); /* root:root */ 373fe517fc9Smrg chmod(DRM_DIR_NAME, DRM_DEV_DIRMODE); 37422944501Smrg } 37522944501Smrg 37622944501Smrg /* Check if the device node exists and create it if necessary. */ 37722944501Smrg if (stat(buf, &st)) { 378fe517fc9Smrg if (!isroot) 379fe517fc9Smrg return DRM_ERR_NOT_ROOT; 380fe517fc9Smrg remove(buf); 381fe517fc9Smrg mknod(buf, S_IFCHR | devmode, dev); 38222944501Smrg } 38322944501Smrg 384fe517fc9Smrg if (drm_server_info && drm_server_info->get_perms) { 385fe517fc9Smrg group = ((int)serv_group >= 0) ? serv_group : DRM_DEV_GID; 386fe517fc9Smrg chown_check_return(buf, user, group); 387fe517fc9Smrg chmod(buf, devmode); 38822944501Smrg } 38922944501Smrg#else 39022944501Smrg /* if we modprobed then wait for udev */ 39122944501Smrg { 392fe517fc9Smrg int udev_count = 0; 39322944501Smrgwait_for_udev: 39422944501Smrg if (stat(DRM_DIR_NAME, &st)) { 395fe517fc9Smrg usleep(20); 396fe517fc9Smrg udev_count++; 397fe517fc9Smrg 398fe517fc9Smrg if (udev_count == 50) 399fe517fc9Smrg return -1; 400fe517fc9Smrg goto wait_for_udev; 401fe517fc9Smrg } 402fe517fc9Smrg 403fe517fc9Smrg if (stat(buf, &st)) { 404fe517fc9Smrg usleep(20); 405fe517fc9Smrg udev_count++; 406fe517fc9Smrg 407fe517fc9Smrg if (udev_count == 50) 408fe517fc9Smrg return -1; 409fe517fc9Smrg goto wait_for_udev; 410fe517fc9Smrg } 41122944501Smrg } 41222944501Smrg#endif 41322944501Smrg 4146260e5d5Smrg fd = open(buf, O_RDWR | O_CLOEXEC, 0); 41522944501Smrg drmMsg("drmOpenDevice: open result is %d, (%s)\n", 416fe517fc9Smrg fd, fd < 0 ? strerror(errno) : "OK"); 41722944501Smrg if (fd >= 0) 418fe517fc9Smrg return fd; 41922944501Smrg 4206260e5d5Smrg#if !UDEV 42122944501Smrg /* Check if the device node is not what we expect it to be, and recreate it 42222944501Smrg * and try again if so. 42322944501Smrg */ 42422944501Smrg if (st.st_rdev != dev) { 425fe517fc9Smrg if (!isroot) 426fe517fc9Smrg return DRM_ERR_NOT_ROOT; 427fe517fc9Smrg remove(buf); 428fe517fc9Smrg mknod(buf, S_IFCHR | devmode, dev); 429fe517fc9Smrg if (drm_server_info && drm_server_info->get_perms) { 430fe517fc9Smrg chown_check_return(buf, user, group); 431fe517fc9Smrg chmod(buf, devmode); 432fe517fc9Smrg } 43322944501Smrg } 4346260e5d5Smrg fd = open(buf, O_RDWR | O_CLOEXEC, 0); 43522944501Smrg drmMsg("drmOpenDevice: open result is %d, (%s)\n", 436fe517fc9Smrg fd, fd < 0 ? strerror(errno) : "OK"); 43722944501Smrg if (fd >= 0) 438fe517fc9Smrg return fd; 43922944501Smrg 44022944501Smrg drmMsg("drmOpenDevice: Open failed\n"); 44122944501Smrg remove(buf); 4429ce4edccSmrg#endif 44322944501Smrg return -errno; 44422944501Smrg} 44522944501Smrg 44622944501Smrg 44722944501Smrg/** 44822944501Smrg * Open the DRM device 44922944501Smrg * 45022944501Smrg * \param minor device minor number. 45122944501Smrg * \param create allow to create the device if set. 45222944501Smrg * 45322944501Smrg * \return a file descriptor on success, or a negative value on error. 454fe517fc9Smrg * 45522944501Smrg * \internal 45622944501Smrg * Calls drmOpenDevice() if \p create is set, otherwise assembles the device 45722944501Smrg * name from \p minor and opens it. 45822944501Smrg */ 45922944501Smrgstatic int drmOpenMinor(int minor, int create, int type) 46022944501Smrg{ 46122944501Smrg int fd; 46222944501Smrg char buf[64]; 463424e9256Smrg const char *dev_name; 464fe517fc9Smrg 46522944501Smrg if (create) 466fe517fc9Smrg return drmOpenDevice(makedev(DRM_MAJOR, minor), minor, type); 467fe517fc9Smrg 468424e9256Smrg switch (type) { 469424e9256Smrg case DRM_NODE_PRIMARY: 470fe517fc9Smrg dev_name = DRM_DEV_NAME; 471fe517fc9Smrg break; 472424e9256Smrg case DRM_NODE_CONTROL: 473fe517fc9Smrg dev_name = DRM_CONTROL_DEV_NAME; 474fe517fc9Smrg break; 475424e9256Smrg case DRM_NODE_RENDER: 476fe517fc9Smrg dev_name = DRM_RENDER_DEV_NAME; 477fe517fc9Smrg break; 478424e9256Smrg default: 479fe517fc9Smrg return -EINVAL; 480424e9256Smrg }; 481424e9256Smrg 482424e9256Smrg sprintf(buf, dev_name, DRM_DIR_NAME, minor); 4836260e5d5Smrg if ((fd = open(buf, O_RDWR | O_CLOEXEC, 0)) >= 0) 484fe517fc9Smrg return fd; 48522944501Smrg return -errno; 48622944501Smrg} 48722944501Smrg 48822944501Smrg 48922944501Smrg/** 49022944501Smrg * Determine whether the DRM kernel driver has been loaded. 491fe517fc9Smrg * 49222944501Smrg * \return 1 if the DRM driver is loaded, 0 otherwise. 49322944501Smrg * 494fe517fc9Smrg * \internal 49522944501Smrg * Determine the presence of the kernel driver by attempting to open the 0 49622944501Smrg * minor and get version information. For backward compatibility with older 49722944501Smrg * Linux implementations, /proc/dri is also checked. 49822944501Smrg */ 4996260e5d5Smrgdrm_public int drmAvailable(void) 50022944501Smrg{ 50122944501Smrg drmVersionPtr version; 50222944501Smrg int retval = 0; 50322944501Smrg int fd; 50422944501Smrg 505424e9256Smrg if ((fd = drmOpenMinor(0, 1, DRM_NODE_PRIMARY)) < 0) { 50622944501Smrg#ifdef __linux__ 507fe517fc9Smrg /* Try proc for backward Linux compatibility */ 508fe517fc9Smrg if (!access("/proc/dri/0", R_OK)) 509fe517fc9Smrg return 1; 51022944501Smrg#endif 511fe517fc9Smrg return 0; 51222944501Smrg } 513fe517fc9Smrg 51422944501Smrg if ((version = drmGetVersion(fd))) { 515fe517fc9Smrg retval = 1; 516fe517fc9Smrg drmFreeVersion(version); 51722944501Smrg } 51822944501Smrg close(fd); 51922944501Smrg 52022944501Smrg return retval; 52122944501Smrg} 52222944501Smrg 523424e9256Smrgstatic int drmGetMinorBase(int type) 524424e9256Smrg{ 525424e9256Smrg switch (type) { 526424e9256Smrg case DRM_NODE_PRIMARY: 527424e9256Smrg return 0; 528424e9256Smrg case DRM_NODE_CONTROL: 529424e9256Smrg return 64; 530424e9256Smrg case DRM_NODE_RENDER: 531424e9256Smrg return 128; 532424e9256Smrg default: 533424e9256Smrg return -1; 534424e9256Smrg }; 535424e9256Smrg} 536424e9256Smrg 537424e9256Smrgstatic int drmGetMinorType(int minor) 538424e9256Smrg{ 539424e9256Smrg int type = minor >> 6; 540424e9256Smrg 541424e9256Smrg if (minor < 0) 542424e9256Smrg return -1; 543424e9256Smrg 544424e9256Smrg switch (type) { 545424e9256Smrg case DRM_NODE_PRIMARY: 546424e9256Smrg case DRM_NODE_CONTROL: 547424e9256Smrg case DRM_NODE_RENDER: 548424e9256Smrg return type; 549424e9256Smrg default: 550424e9256Smrg return -1; 551424e9256Smrg } 552424e9256Smrg} 553424e9256Smrg 554424e9256Smrgstatic const char *drmGetMinorName(int type) 555424e9256Smrg{ 556424e9256Smrg switch (type) { 557424e9256Smrg case DRM_NODE_PRIMARY: 558fe517fc9Smrg return DRM_PRIMARY_MINOR_NAME; 559424e9256Smrg case DRM_NODE_CONTROL: 560fe517fc9Smrg return DRM_CONTROL_MINOR_NAME; 561424e9256Smrg case DRM_NODE_RENDER: 562fe517fc9Smrg return DRM_RENDER_MINOR_NAME; 563424e9256Smrg default: 564424e9256Smrg return NULL; 565424e9256Smrg } 566424e9256Smrg} 56722944501Smrg 56822944501Smrg/** 56922944501Smrg * Open the device by bus ID. 57022944501Smrg * 57122944501Smrg * \param busid bus ID. 572424e9256Smrg * \param type device node type. 57322944501Smrg * 57422944501Smrg * \return a file descriptor on success, or a negative value on error. 57522944501Smrg * 57622944501Smrg * \internal 57722944501Smrg * This function attempts to open every possible minor (up to DRM_MAX_MINOR), 57822944501Smrg * comparing the device bus ID with the one supplied. 57922944501Smrg * 58022944501Smrg * \sa drmOpenMinor() and drmGetBusid(). 58122944501Smrg */ 582424e9256Smrgstatic int drmOpenByBusid(const char *busid, int type) 58322944501Smrg{ 5846d98c517Smrg int i, pci_domain_ok = 1; 58522944501Smrg int fd; 58622944501Smrg const char *buf; 58722944501Smrg drmSetVersion sv; 588424e9256Smrg int base = drmGetMinorBase(type); 589424e9256Smrg 590424e9256Smrg if (base < 0) 591424e9256Smrg return -1; 59222944501Smrg 59322944501Smrg drmMsg("drmOpenByBusid: Searching for BusID %s\n", busid); 594424e9256Smrg for (i = base; i < base + DRM_MAX_MINOR; i++) { 595fe517fc9Smrg fd = drmOpenMinor(i, 1, type); 596fe517fc9Smrg drmMsg("drmOpenByBusid: drmOpenMinor returns %d\n", fd); 597fe517fc9Smrg if (fd >= 0) { 598fe517fc9Smrg /* We need to try for 1.4 first for proper PCI domain support 599fe517fc9Smrg * and if that fails, we know the kernel is busted 600fe517fc9Smrg */ 601fe517fc9Smrg sv.drm_di_major = 1; 602fe517fc9Smrg sv.drm_di_minor = 4; 603fe517fc9Smrg sv.drm_dd_major = -1; /* Don't care */ 604fe517fc9Smrg sv.drm_dd_minor = -1; /* Don't care */ 605fe517fc9Smrg if (drmSetInterfaceVersion(fd, &sv)) { 6066d98c517Smrg#ifndef __alpha__ 607fe517fc9Smrg pci_domain_ok = 0; 6086d98c517Smrg#endif 609fe517fc9Smrg sv.drm_di_major = 1; 610fe517fc9Smrg sv.drm_di_minor = 1; 611fe517fc9Smrg sv.drm_dd_major = -1; /* Don't care */ 612fe517fc9Smrg sv.drm_dd_minor = -1; /* Don't care */ 613fe517fc9Smrg drmMsg("drmOpenByBusid: Interface 1.4 failed, trying 1.1\n"); 614fe517fc9Smrg drmSetInterfaceVersion(fd, &sv); 615fe517fc9Smrg } 616fe517fc9Smrg buf = drmGetBusid(fd); 617fe517fc9Smrg drmMsg("drmOpenByBusid: drmGetBusid reports %s\n", buf); 618fe517fc9Smrg if (buf && drmMatchBusID(buf, busid, pci_domain_ok)) { 619fe517fc9Smrg drmFreeBusid(buf); 620fe517fc9Smrg return fd; 621fe517fc9Smrg } 622fe517fc9Smrg if (buf) 623fe517fc9Smrg drmFreeBusid(buf); 624fe517fc9Smrg close(fd); 625fe517fc9Smrg } 62622944501Smrg } 62722944501Smrg return -1; 62822944501Smrg} 62922944501Smrg 63022944501Smrg 63122944501Smrg/** 63222944501Smrg * Open the device by name. 63322944501Smrg * 63422944501Smrg * \param name driver name. 635424e9256Smrg * \param type the device node type. 636fe517fc9Smrg * 63722944501Smrg * \return a file descriptor on success, or a negative value on error. 638fe517fc9Smrg * 63922944501Smrg * \internal 64022944501Smrg * This function opens the first minor number that matches the driver name and 64122944501Smrg * isn't already in use. If it's in use it then it will already have a bus ID 64222944501Smrg * assigned. 643fe517fc9Smrg * 64422944501Smrg * \sa drmOpenMinor(), drmGetVersion() and drmGetBusid(). 64522944501Smrg */ 646424e9256Smrgstatic int drmOpenByName(const char *name, int type) 64722944501Smrg{ 64822944501Smrg int i; 64922944501Smrg int fd; 65022944501Smrg drmVersionPtr version; 65122944501Smrg char * id; 652424e9256Smrg int base = drmGetMinorBase(type); 653424e9256Smrg 654424e9256Smrg if (base < 0) 655424e9256Smrg return -1; 65622944501Smrg 65722944501Smrg /* 65822944501Smrg * Open the first minor number that matches the driver name and isn't 65922944501Smrg * already in use. If it's in use it will have a busid assigned already. 66022944501Smrg */ 661424e9256Smrg for (i = base; i < base + DRM_MAX_MINOR; i++) { 662fe517fc9Smrg if ((fd = drmOpenMinor(i, 1, type)) >= 0) { 663fe517fc9Smrg if ((version = drmGetVersion(fd))) { 664fe517fc9Smrg if (!strcmp(version->name, name)) { 665fe517fc9Smrg drmFreeVersion(version); 666fe517fc9Smrg id = drmGetBusid(fd); 667fe517fc9Smrg drmMsg("drmGetBusid returned '%s'\n", id ? id : "NULL"); 668fe517fc9Smrg if (!id || !*id) { 669fe517fc9Smrg if (id) 670fe517fc9Smrg drmFreeBusid(id); 671fe517fc9Smrg return fd; 672fe517fc9Smrg } else { 673fe517fc9Smrg drmFreeBusid(id); 674fe517fc9Smrg } 675fe517fc9Smrg } else { 676fe517fc9Smrg drmFreeVersion(version); 677fe517fc9Smrg } 678fe517fc9Smrg } 679fe517fc9Smrg close(fd); 680fe517fc9Smrg } 68122944501Smrg } 68222944501Smrg 68322944501Smrg#ifdef __linux__ 68422944501Smrg /* Backward-compatibility /proc support */ 68522944501Smrg for (i = 0; i < 8; i++) { 686fe517fc9Smrg char proc_name[64], buf[512]; 687fe517fc9Smrg char *driver, *pt, *devstring; 688fe517fc9Smrg int retcode; 689fe517fc9Smrg 690fe517fc9Smrg sprintf(proc_name, "/proc/dri/%d/name", i); 691fe517fc9Smrg if ((fd = open(proc_name, 0, 0)) >= 0) { 692fe517fc9Smrg retcode = read(fd, buf, sizeof(buf)-1); 693fe517fc9Smrg close(fd); 694fe517fc9Smrg if (retcode) { 695fe517fc9Smrg buf[retcode-1] = '\0'; 696fe517fc9Smrg for (driver = pt = buf; *pt && *pt != ' '; ++pt) 697fe517fc9Smrg ; 698fe517fc9Smrg if (*pt) { /* Device is next */ 699fe517fc9Smrg *pt = '\0'; 700fe517fc9Smrg if (!strcmp(driver, name)) { /* Match */ 701fe517fc9Smrg for (devstring = ++pt; *pt && *pt != ' '; ++pt) 702fe517fc9Smrg ; 703fe517fc9Smrg if (*pt) { /* Found busid */ 704fe517fc9Smrg return drmOpenByBusid(++pt, type); 705fe517fc9Smrg } else { /* No busid */ 706fe517fc9Smrg return drmOpenDevice(strtol(devstring, NULL, 0),i, type); 707fe517fc9Smrg } 708fe517fc9Smrg } 709fe517fc9Smrg } 710fe517fc9Smrg } 711fe517fc9Smrg } 71222944501Smrg } 71322944501Smrg#endif 71422944501Smrg 71522944501Smrg return -1; 71622944501Smrg} 71722944501Smrg 71822944501Smrg 71922944501Smrg/** 72022944501Smrg * Open the DRM device. 72122944501Smrg * 72222944501Smrg * Looks up the specified name and bus ID, and opens the device found. The 72322944501Smrg * entry in /dev/dri is created if necessary and if called by root. 72422944501Smrg * 72522944501Smrg * \param name driver name. Not referenced if bus ID is supplied. 72622944501Smrg * \param busid bus ID. Zero if not known. 727fe517fc9Smrg * 72822944501Smrg * \return a file descriptor on success, or a negative value on error. 729fe517fc9Smrg * 73022944501Smrg * \internal 73122944501Smrg * It calls drmOpenByBusid() if \p busid is specified or drmOpenByName() 73222944501Smrg * otherwise. 73322944501Smrg */ 7346260e5d5Smrgdrm_public int drmOpen(const char *name, const char *busid) 735424e9256Smrg{ 736424e9256Smrg return drmOpenWithType(name, busid, DRM_NODE_PRIMARY); 737424e9256Smrg} 738424e9256Smrg 739424e9256Smrg/** 740424e9256Smrg * Open the DRM device with specified type. 741424e9256Smrg * 742424e9256Smrg * Looks up the specified name and bus ID, and opens the device found. The 743424e9256Smrg * entry in /dev/dri is created if necessary and if called by root. 744424e9256Smrg * 745424e9256Smrg * \param name driver name. Not referenced if bus ID is supplied. 746424e9256Smrg * \param busid bus ID. Zero if not known. 747424e9256Smrg * \param type the device node type to open, PRIMARY, CONTROL or RENDER 748424e9256Smrg * 749424e9256Smrg * \return a file descriptor on success, or a negative value on error. 750424e9256Smrg * 751424e9256Smrg * \internal 752424e9256Smrg * It calls drmOpenByBusid() if \p busid is specified or drmOpenByName() 753424e9256Smrg * otherwise. 754424e9256Smrg */ 7556260e5d5Smrgdrm_public int drmOpenWithType(const char *name, const char *busid, int type) 75622944501Smrg{ 757fe517fc9Smrg if (!drmAvailable() && name != NULL && drm_server_info && 758fe517fc9Smrg drm_server_info->load_module) { 759fe517fc9Smrg /* try to load the kernel module */ 760fe517fc9Smrg if (!drm_server_info->load_module(name)) { 761fe517fc9Smrg drmMsg("[drm] failed to load kernel module \"%s\"\n", name); 762fe517fc9Smrg return -1; 763fe517fc9Smrg } 76422944501Smrg } 76522944501Smrg 76622944501Smrg if (busid) { 767fe517fc9Smrg int fd = drmOpenByBusid(busid, type); 768fe517fc9Smrg if (fd >= 0) 769fe517fc9Smrg return fd; 77022944501Smrg } 771fe517fc9Smrg 77222944501Smrg if (name) 773fe517fc9Smrg return drmOpenByName(name, type); 77422944501Smrg 77522944501Smrg return -1; 77622944501Smrg} 77722944501Smrg 7786260e5d5Smrgdrm_public int drmOpenControl(int minor) 77922944501Smrg{ 78022944501Smrg return drmOpenMinor(minor, 0, DRM_NODE_CONTROL); 78122944501Smrg} 78222944501Smrg 7836260e5d5Smrgdrm_public int drmOpenRender(int minor) 784424e9256Smrg{ 785424e9256Smrg return drmOpenMinor(minor, 0, DRM_NODE_RENDER); 786424e9256Smrg} 787424e9256Smrg 78822944501Smrg/** 78922944501Smrg * Free the version information returned by drmGetVersion(). 79022944501Smrg * 79122944501Smrg * \param v pointer to the version information. 79222944501Smrg * 79322944501Smrg * \internal 79422944501Smrg * It frees the memory pointed by \p %v as well as all the non-null strings 79522944501Smrg * pointers in it. 79622944501Smrg */ 7976260e5d5Smrgdrm_public void drmFreeVersion(drmVersionPtr v) 79822944501Smrg{ 79922944501Smrg if (!v) 800fe517fc9Smrg return; 80122944501Smrg drmFree(v->name); 80222944501Smrg drmFree(v->date); 80322944501Smrg drmFree(v->desc); 80422944501Smrg drmFree(v); 80522944501Smrg} 80622944501Smrg 80722944501Smrg 80822944501Smrg/** 80922944501Smrg * Free the non-public version information returned by the kernel. 81022944501Smrg * 81122944501Smrg * \param v pointer to the version information. 81222944501Smrg * 81322944501Smrg * \internal 81422944501Smrg * Used by drmGetVersion() to free the memory pointed by \p %v as well as all 81522944501Smrg * the non-null strings pointers in it. 81622944501Smrg */ 81722944501Smrgstatic void drmFreeKernelVersion(drm_version_t *v) 81822944501Smrg{ 81922944501Smrg if (!v) 820fe517fc9Smrg return; 82122944501Smrg drmFree(v->name); 82222944501Smrg drmFree(v->date); 82322944501Smrg drmFree(v->desc); 82422944501Smrg drmFree(v); 82522944501Smrg} 82622944501Smrg 82722944501Smrg 82822944501Smrg/** 82922944501Smrg * Copy version information. 830fe517fc9Smrg * 83122944501Smrg * \param d destination pointer. 83222944501Smrg * \param s source pointer. 833fe517fc9Smrg * 83422944501Smrg * \internal 83522944501Smrg * Used by drmGetVersion() to translate the information returned by the ioctl 83622944501Smrg * interface in a private structure into the public structure counterpart. 83722944501Smrg */ 83822944501Smrgstatic void drmCopyVersion(drmVersionPtr d, const drm_version_t *s) 83922944501Smrg{ 84022944501Smrg d->version_major = s->version_major; 84122944501Smrg d->version_minor = s->version_minor; 84222944501Smrg d->version_patchlevel = s->version_patchlevel; 84322944501Smrg d->name_len = s->name_len; 8449ce4edccSmrg d->name = strdup(s->name); 84522944501Smrg d->date_len = s->date_len; 8469ce4edccSmrg d->date = strdup(s->date); 84722944501Smrg d->desc_len = s->desc_len; 8489ce4edccSmrg d->desc = strdup(s->desc); 84922944501Smrg} 85022944501Smrg 85122944501Smrg 85222944501Smrg/** 85322944501Smrg * Query the driver version information. 85422944501Smrg * 85522944501Smrg * \param fd file descriptor. 856fe517fc9Smrg * 85722944501Smrg * \return pointer to a drmVersion structure which should be freed with 85822944501Smrg * drmFreeVersion(). 859fe517fc9Smrg * 86022944501Smrg * \note Similar information is available via /proc/dri. 861fe517fc9Smrg * 86222944501Smrg * \internal 86322944501Smrg * It gets the version information via successive DRM_IOCTL_VERSION ioctls, 86422944501Smrg * first with zeros to get the string lengths, and then the actually strings. 86522944501Smrg * It also null-terminates them since they might not be already. 86622944501Smrg */ 8676260e5d5Smrgdrm_public drmVersionPtr drmGetVersion(int fd) 86822944501Smrg{ 86922944501Smrg drmVersionPtr retval; 87022944501Smrg drm_version_t *version = drmMalloc(sizeof(*version)); 87122944501Smrg 87222944501Smrg if (drmIoctl(fd, DRM_IOCTL_VERSION, version)) { 873fe517fc9Smrg drmFreeKernelVersion(version); 874fe517fc9Smrg return NULL; 87522944501Smrg } 87622944501Smrg 87722944501Smrg if (version->name_len) 878fe517fc9Smrg version->name = drmMalloc(version->name_len + 1); 87922944501Smrg if (version->date_len) 880fe517fc9Smrg version->date = drmMalloc(version->date_len + 1); 88122944501Smrg if (version->desc_len) 882fe517fc9Smrg version->desc = drmMalloc(version->desc_len + 1); 88322944501Smrg 88422944501Smrg if (drmIoctl(fd, DRM_IOCTL_VERSION, version)) { 885fe517fc9Smrg drmMsg("DRM_IOCTL_VERSION: %s\n", strerror(errno)); 886fe517fc9Smrg drmFreeKernelVersion(version); 887fe517fc9Smrg return NULL; 88822944501Smrg } 88922944501Smrg 89022944501Smrg /* The results might not be null-terminated strings, so terminate them. */ 89122944501Smrg if (version->name_len) version->name[version->name_len] = '\0'; 89222944501Smrg if (version->date_len) version->date[version->date_len] = '\0'; 89322944501Smrg if (version->desc_len) version->desc[version->desc_len] = '\0'; 89422944501Smrg 89522944501Smrg retval = drmMalloc(sizeof(*retval)); 89622944501Smrg drmCopyVersion(retval, version); 89722944501Smrg drmFreeKernelVersion(version); 89822944501Smrg return retval; 89922944501Smrg} 90022944501Smrg 90122944501Smrg 90222944501Smrg/** 90322944501Smrg * Get version information for the DRM user space library. 904fe517fc9Smrg * 90522944501Smrg * This version number is driver independent. 906fe517fc9Smrg * 90722944501Smrg * \param fd file descriptor. 90822944501Smrg * 90922944501Smrg * \return version information. 910fe517fc9Smrg * 91122944501Smrg * \internal 91222944501Smrg * This function allocates and fills a drm_version structure with a hard coded 91322944501Smrg * version number. 91422944501Smrg */ 9156260e5d5Smrgdrm_public drmVersionPtr drmGetLibVersion(int fd) 91622944501Smrg{ 91722944501Smrg drm_version_t *version = drmMalloc(sizeof(*version)); 91822944501Smrg 91922944501Smrg /* Version history: 92022944501Smrg * NOTE THIS MUST NOT GO ABOVE VERSION 1.X due to drivers needing it 92122944501Smrg * revision 1.0.x = original DRM interface with no drmGetLibVersion 92222944501Smrg * entry point and many drm<Device> extensions 92322944501Smrg * revision 1.1.x = added drmCommand entry points for device extensions 92422944501Smrg * added drmGetLibVersion to identify libdrm.a version 92522944501Smrg * revision 1.2.x = added drmSetInterfaceVersion 92622944501Smrg * modified drmOpen to handle both busid and name 92722944501Smrg * revision 1.3.x = added server + memory manager 92822944501Smrg */ 92922944501Smrg version->version_major = 1; 93022944501Smrg version->version_minor = 3; 93122944501Smrg version->version_patchlevel = 0; 93222944501Smrg 93322944501Smrg return (drmVersionPtr)version; 93422944501Smrg} 93522944501Smrg 9366260e5d5Smrgdrm_public int drmGetCap(int fd, uint64_t capability, uint64_t *value) 93720131375Smrg{ 938fe517fc9Smrg struct drm_get_cap cap; 939fe517fc9Smrg int ret; 94020131375Smrg 941fe517fc9Smrg memclear(cap); 942fe517fc9Smrg cap.capability = capability; 943424e9256Smrg 944fe517fc9Smrg ret = drmIoctl(fd, DRM_IOCTL_GET_CAP, &cap); 945fe517fc9Smrg if (ret) 946fe517fc9Smrg return ret; 94720131375Smrg 948fe517fc9Smrg *value = cap.value; 949fe517fc9Smrg return 0; 95020131375Smrg} 95120131375Smrg 9526260e5d5Smrgdrm_public int drmSetClientCap(int fd, uint64_t capability, uint64_t value) 95320131375Smrg{ 954fe517fc9Smrg struct drm_set_client_cap cap; 955424e9256Smrg 956fe517fc9Smrg memclear(cap); 957fe517fc9Smrg cap.capability = capability; 958fe517fc9Smrg cap.value = value; 95920131375Smrg 960fe517fc9Smrg return drmIoctl(fd, DRM_IOCTL_SET_CLIENT_CAP, &cap); 96120131375Smrg} 96222944501Smrg 96322944501Smrg/** 96422944501Smrg * Free the bus ID information. 96522944501Smrg * 96622944501Smrg * \param busid bus ID information string as given by drmGetBusid(). 96722944501Smrg * 96822944501Smrg * \internal 96922944501Smrg * This function is just frees the memory pointed by \p busid. 97022944501Smrg */ 9716260e5d5Smrgdrm_public void drmFreeBusid(const char *busid) 97222944501Smrg{ 97322944501Smrg drmFree((void *)busid); 97422944501Smrg} 97522944501Smrg 97622944501Smrg 97722944501Smrg/** 97822944501Smrg * Get the bus ID of the device. 97922944501Smrg * 98022944501Smrg * \param fd file descriptor. 98122944501Smrg * 98222944501Smrg * \return bus ID string. 98322944501Smrg * 98422944501Smrg * \internal 98522944501Smrg * This function gets the bus ID via successive DRM_IOCTL_GET_UNIQUE ioctls to 98622944501Smrg * get the string length and data, passing the arguments in a drm_unique 98722944501Smrg * structure. 98822944501Smrg */ 9896260e5d5Smrgdrm_public char *drmGetBusid(int fd) 99022944501Smrg{ 99122944501Smrg drm_unique_t u; 99222944501Smrg 993424e9256Smrg memclear(u); 99422944501Smrg 99522944501Smrg if (drmIoctl(fd, DRM_IOCTL_GET_UNIQUE, &u)) 996fe517fc9Smrg return NULL; 99722944501Smrg u.unique = drmMalloc(u.unique_len + 1); 9980655efefSmrg if (drmIoctl(fd, DRM_IOCTL_GET_UNIQUE, &u)) { 9990655efefSmrg drmFree(u.unique); 1000fe517fc9Smrg return NULL; 10010655efefSmrg } 100222944501Smrg u.unique[u.unique_len] = '\0'; 100322944501Smrg 100422944501Smrg return u.unique; 100522944501Smrg} 100622944501Smrg 100722944501Smrg 100822944501Smrg/** 100922944501Smrg * Set the bus ID of the device. 101022944501Smrg * 101122944501Smrg * \param fd file descriptor. 101222944501Smrg * \param busid bus ID string. 101322944501Smrg * 101422944501Smrg * \return zero on success, negative on failure. 101522944501Smrg * 101622944501Smrg * \internal 101722944501Smrg * This function is a wrapper around the DRM_IOCTL_SET_UNIQUE ioctl, passing 101822944501Smrg * the arguments in a drm_unique structure. 101922944501Smrg */ 10206260e5d5Smrgdrm_public int drmSetBusid(int fd, const char *busid) 102122944501Smrg{ 102222944501Smrg drm_unique_t u; 102322944501Smrg 1024424e9256Smrg memclear(u); 102522944501Smrg u.unique = (char *)busid; 102622944501Smrg u.unique_len = strlen(busid); 102722944501Smrg 102822944501Smrg if (drmIoctl(fd, DRM_IOCTL_SET_UNIQUE, &u)) { 1029fe517fc9Smrg return -errno; 103022944501Smrg } 103122944501Smrg return 0; 103222944501Smrg} 103322944501Smrg 10346260e5d5Smrgdrm_public int drmGetMagic(int fd, drm_magic_t * magic) 103522944501Smrg{ 103622944501Smrg drm_auth_t auth; 103722944501Smrg 1038424e9256Smrg memclear(auth); 1039424e9256Smrg 104022944501Smrg *magic = 0; 104122944501Smrg if (drmIoctl(fd, DRM_IOCTL_GET_MAGIC, &auth)) 1042fe517fc9Smrg return -errno; 104322944501Smrg *magic = auth.magic; 104422944501Smrg return 0; 104522944501Smrg} 104622944501Smrg 10476260e5d5Smrgdrm_public int drmAuthMagic(int fd, drm_magic_t magic) 104822944501Smrg{ 104922944501Smrg drm_auth_t auth; 105022944501Smrg 1051424e9256Smrg memclear(auth); 105222944501Smrg auth.magic = magic; 105322944501Smrg if (drmIoctl(fd, DRM_IOCTL_AUTH_MAGIC, &auth)) 1054fe517fc9Smrg return -errno; 105522944501Smrg return 0; 105622944501Smrg} 105722944501Smrg 105822944501Smrg/** 105922944501Smrg * Specifies a range of memory that is available for mapping by a 106022944501Smrg * non-root process. 106122944501Smrg * 106222944501Smrg * \param fd file descriptor. 106322944501Smrg * \param offset usually the physical address. The actual meaning depends of 106422944501Smrg * the \p type parameter. See below. 106522944501Smrg * \param size of the memory in bytes. 106622944501Smrg * \param type type of the memory to be mapped. 106722944501Smrg * \param flags combination of several flags to modify the function actions. 106822944501Smrg * \param handle will be set to a value that may be used as the offset 106922944501Smrg * parameter for mmap(). 1070fe517fc9Smrg * 107122944501Smrg * \return zero on success or a negative value on error. 107222944501Smrg * 107322944501Smrg * \par Mapping the frame buffer 107422944501Smrg * For the frame buffer 107522944501Smrg * - \p offset will be the physical address of the start of the frame buffer, 107622944501Smrg * - \p size will be the size of the frame buffer in bytes, and 107722944501Smrg * - \p type will be DRM_FRAME_BUFFER. 107822944501Smrg * 107922944501Smrg * \par 108022944501Smrg * The area mapped will be uncached. If MTRR support is available in the 1081fe517fc9Smrg * kernel, the frame buffer area will be set to write combining. 108222944501Smrg * 108322944501Smrg * \par Mapping the MMIO register area 108422944501Smrg * For the MMIO register area, 108522944501Smrg * - \p offset will be the physical address of the start of the register area, 108622944501Smrg * - \p size will be the size of the register area bytes, and 108722944501Smrg * - \p type will be DRM_REGISTERS. 108822944501Smrg * \par 1089fe517fc9Smrg * The area mapped will be uncached. 1090fe517fc9Smrg * 109122944501Smrg * \par Mapping the SAREA 109222944501Smrg * For the SAREA, 109322944501Smrg * - \p offset will be ignored and should be set to zero, 109422944501Smrg * - \p size will be the desired size of the SAREA in bytes, 109522944501Smrg * - \p type will be DRM_SHM. 1096fe517fc9Smrg * 109722944501Smrg * \par 109822944501Smrg * A shared memory area of the requested size will be created and locked in 109922944501Smrg * kernel memory. This area may be mapped into client-space by using the handle 1100fe517fc9Smrg * returned. 1101fe517fc9Smrg * 110222944501Smrg * \note May only be called by root. 110322944501Smrg * 110422944501Smrg * \internal 110522944501Smrg * This function is a wrapper around the DRM_IOCTL_ADD_MAP ioctl, passing 110622944501Smrg * the arguments in a drm_map structure. 110722944501Smrg */ 11086260e5d5Smrgdrm_public int drmAddMap(int fd, drm_handle_t offset, drmSize size, drmMapType type, 11096260e5d5Smrg drmMapFlags flags, drm_handle_t *handle) 111022944501Smrg{ 111122944501Smrg drm_map_t map; 111222944501Smrg 1113424e9256Smrg memclear(map); 111422944501Smrg map.offset = offset; 111522944501Smrg map.size = size; 111622944501Smrg map.type = type; 111722944501Smrg map.flags = flags; 111822944501Smrg if (drmIoctl(fd, DRM_IOCTL_ADD_MAP, &map)) 1119fe517fc9Smrg return -errno; 112022944501Smrg if (handle) 1121fe517fc9Smrg *handle = (drm_handle_t)(uintptr_t)map.handle; 112222944501Smrg return 0; 112322944501Smrg} 112422944501Smrg 11256260e5d5Smrgdrm_public int drmRmMap(int fd, drm_handle_t handle) 112622944501Smrg{ 112722944501Smrg drm_map_t map; 112822944501Smrg 1129424e9256Smrg memclear(map); 113020131375Smrg map.handle = (void *)(uintptr_t)handle; 113122944501Smrg 113222944501Smrg if(drmIoctl(fd, DRM_IOCTL_RM_MAP, &map)) 1133fe517fc9Smrg return -errno; 113422944501Smrg return 0; 113522944501Smrg} 113622944501Smrg 113722944501Smrg/** 113822944501Smrg * Make buffers available for DMA transfers. 1139fe517fc9Smrg * 114022944501Smrg * \param fd file descriptor. 114122944501Smrg * \param count number of buffers. 114222944501Smrg * \param size size of each buffer. 114322944501Smrg * \param flags buffer allocation flags. 1144fe517fc9Smrg * \param agp_offset offset in the AGP aperture 114522944501Smrg * 114622944501Smrg * \return number of buffers allocated, negative on error. 114722944501Smrg * 114822944501Smrg * \internal 114922944501Smrg * This function is a wrapper around DRM_IOCTL_ADD_BUFS ioctl. 115022944501Smrg * 115122944501Smrg * \sa drm_buf_desc. 115222944501Smrg */ 11536260e5d5Smrgdrm_public int drmAddBufs(int fd, int count, int size, drmBufDescFlags flags, 11546260e5d5Smrg int agp_offset) 115522944501Smrg{ 115622944501Smrg drm_buf_desc_t request; 115722944501Smrg 1158424e9256Smrg memclear(request); 115922944501Smrg request.count = count; 116022944501Smrg request.size = size; 116122944501Smrg request.flags = flags; 116222944501Smrg request.agp_start = agp_offset; 116322944501Smrg 116422944501Smrg if (drmIoctl(fd, DRM_IOCTL_ADD_BUFS, &request)) 1165fe517fc9Smrg return -errno; 116622944501Smrg return request.count; 116722944501Smrg} 116822944501Smrg 11696260e5d5Smrgdrm_public int drmMarkBufs(int fd, double low, double high) 117022944501Smrg{ 117122944501Smrg drm_buf_info_t info; 117222944501Smrg int i; 117322944501Smrg 1174424e9256Smrg memclear(info); 117522944501Smrg 117622944501Smrg if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info)) 1177fe517fc9Smrg return -EINVAL; 117822944501Smrg 117922944501Smrg if (!info.count) 1180fe517fc9Smrg return -EINVAL; 118122944501Smrg 118222944501Smrg if (!(info.list = drmMalloc(info.count * sizeof(*info.list)))) 1183fe517fc9Smrg return -ENOMEM; 118422944501Smrg 118522944501Smrg if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info)) { 1186fe517fc9Smrg int retval = -errno; 1187fe517fc9Smrg drmFree(info.list); 1188fe517fc9Smrg return retval; 118922944501Smrg } 119022944501Smrg 119122944501Smrg for (i = 0; i < info.count; i++) { 1192fe517fc9Smrg info.list[i].low_mark = low * info.list[i].count; 1193fe517fc9Smrg info.list[i].high_mark = high * info.list[i].count; 1194fe517fc9Smrg if (drmIoctl(fd, DRM_IOCTL_MARK_BUFS, &info.list[i])) { 1195fe517fc9Smrg int retval = -errno; 1196fe517fc9Smrg drmFree(info.list); 1197fe517fc9Smrg return retval; 1198fe517fc9Smrg } 119922944501Smrg } 120022944501Smrg drmFree(info.list); 120122944501Smrg 120222944501Smrg return 0; 120322944501Smrg} 120422944501Smrg 120522944501Smrg/** 120622944501Smrg * Free buffers. 120722944501Smrg * 120822944501Smrg * \param fd file descriptor. 120922944501Smrg * \param count number of buffers to free. 121022944501Smrg * \param list list of buffers to be freed. 121122944501Smrg * 121222944501Smrg * \return zero on success, or a negative value on failure. 1213fe517fc9Smrg * 121422944501Smrg * \note This function is primarily used for debugging. 1215fe517fc9Smrg * 121622944501Smrg * \internal 121722944501Smrg * This function is a wrapper around the DRM_IOCTL_FREE_BUFS ioctl, passing 121822944501Smrg * the arguments in a drm_buf_free structure. 121922944501Smrg */ 12206260e5d5Smrgdrm_public int drmFreeBufs(int fd, int count, int *list) 122122944501Smrg{ 122222944501Smrg drm_buf_free_t request; 122322944501Smrg 1224424e9256Smrg memclear(request); 122522944501Smrg request.count = count; 122622944501Smrg request.list = list; 122722944501Smrg if (drmIoctl(fd, DRM_IOCTL_FREE_BUFS, &request)) 1228fe517fc9Smrg return -errno; 122922944501Smrg return 0; 123022944501Smrg} 123122944501Smrg 123222944501Smrg 123322944501Smrg/** 123422944501Smrg * Close the device. 123522944501Smrg * 123622944501Smrg * \param fd file descriptor. 123722944501Smrg * 123822944501Smrg * \internal 123922944501Smrg * This function closes the file descriptor. 124022944501Smrg */ 12416260e5d5Smrgdrm_public int drmClose(int fd) 124222944501Smrg{ 124322944501Smrg unsigned long key = drmGetKeyFromFd(fd); 124422944501Smrg drmHashEntry *entry = drmGetEntry(fd); 124522944501Smrg 124622944501Smrg drmHashDestroy(entry->tagTable); 124722944501Smrg entry->fd = 0; 124822944501Smrg entry->f = NULL; 124922944501Smrg entry->tagTable = NULL; 125022944501Smrg 125122944501Smrg drmHashDelete(drmHashTable, key); 125222944501Smrg drmFree(entry); 125322944501Smrg 125422944501Smrg return close(fd); 125522944501Smrg} 125622944501Smrg 125722944501Smrg 125822944501Smrg/** 125922944501Smrg * Map a region of memory. 126022944501Smrg * 126122944501Smrg * \param fd file descriptor. 126222944501Smrg * \param handle handle returned by drmAddMap(). 126322944501Smrg * \param size size in bytes. Must match the size used by drmAddMap(). 126422944501Smrg * \param address will contain the user-space virtual address where the mapping 126522944501Smrg * begins. 126622944501Smrg * 126722944501Smrg * \return zero on success, or a negative value on failure. 1268fe517fc9Smrg * 126922944501Smrg * \internal 127022944501Smrg * This function is a wrapper for mmap(). 127122944501Smrg */ 12726260e5d5Smrgdrm_public int drmMap(int fd, drm_handle_t handle, drmSize size, 12736260e5d5Smrg drmAddressPtr address) 127422944501Smrg{ 127522944501Smrg static unsigned long pagesize_mask = 0; 127622944501Smrg 127722944501Smrg if (fd < 0) 1278fe517fc9Smrg return -EINVAL; 127922944501Smrg 128022944501Smrg if (!pagesize_mask) 1281fe517fc9Smrg pagesize_mask = getpagesize() - 1; 128222944501Smrg 128322944501Smrg size = (size + pagesize_mask) & ~pagesize_mask; 128422944501Smrg 1285a884aba1Smrg *address = drm_mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, handle); 128622944501Smrg if (*address == MAP_FAILED) 1287fe517fc9Smrg return -errno; 128822944501Smrg return 0; 128922944501Smrg} 129022944501Smrg 129122944501Smrg 129222944501Smrg/** 129322944501Smrg * Unmap mappings obtained with drmMap(). 129422944501Smrg * 129522944501Smrg * \param address address as given by drmMap(). 129622944501Smrg * \param size size in bytes. Must match the size used by drmMap(). 1297fe517fc9Smrg * 129822944501Smrg * \return zero on success, or a negative value on failure. 129922944501Smrg * 130022944501Smrg * \internal 130122944501Smrg * This function is a wrapper for munmap(). 130222944501Smrg */ 13036260e5d5Smrgdrm_public int drmUnmap(drmAddress address, drmSize size) 130422944501Smrg{ 1305a884aba1Smrg return drm_munmap(address, size); 130622944501Smrg} 130722944501Smrg 13086260e5d5Smrgdrm_public drmBufInfoPtr drmGetBufInfo(int fd) 130922944501Smrg{ 131022944501Smrg drm_buf_info_t info; 131122944501Smrg drmBufInfoPtr retval; 131222944501Smrg int i; 131322944501Smrg 1314424e9256Smrg memclear(info); 131522944501Smrg 131622944501Smrg if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info)) 1317fe517fc9Smrg return NULL; 131822944501Smrg 131922944501Smrg if (info.count) { 1320fe517fc9Smrg if (!(info.list = drmMalloc(info.count * sizeof(*info.list)))) 1321fe517fc9Smrg return NULL; 1322fe517fc9Smrg 1323fe517fc9Smrg if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info)) { 1324fe517fc9Smrg drmFree(info.list); 1325fe517fc9Smrg return NULL; 1326fe517fc9Smrg } 1327fe517fc9Smrg 1328fe517fc9Smrg retval = drmMalloc(sizeof(*retval)); 1329fe517fc9Smrg retval->count = info.count; 1330fe517fc9Smrg retval->list = drmMalloc(info.count * sizeof(*retval->list)); 1331fe517fc9Smrg for (i = 0; i < info.count; i++) { 1332fe517fc9Smrg retval->list[i].count = info.list[i].count; 1333fe517fc9Smrg retval->list[i].size = info.list[i].size; 1334fe517fc9Smrg retval->list[i].low_mark = info.list[i].low_mark; 1335fe517fc9Smrg retval->list[i].high_mark = info.list[i].high_mark; 1336fe517fc9Smrg } 1337fe517fc9Smrg drmFree(info.list); 1338fe517fc9Smrg return retval; 133922944501Smrg } 134022944501Smrg return NULL; 134122944501Smrg} 134222944501Smrg 134322944501Smrg/** 134422944501Smrg * Map all DMA buffers into client-virtual space. 134522944501Smrg * 134622944501Smrg * \param fd file descriptor. 134722944501Smrg * 134822944501Smrg * \return a pointer to a ::drmBufMap structure. 134922944501Smrg * 135022944501Smrg * \note The client may not use these buffers until obtaining buffer indices 135122944501Smrg * with drmDMA(). 1352fe517fc9Smrg * 135322944501Smrg * \internal 135422944501Smrg * This function calls the DRM_IOCTL_MAP_BUFS ioctl and copies the returned 135522944501Smrg * information about the buffers in a drm_buf_map structure into the 135622944501Smrg * client-visible data structures. 1357fe517fc9Smrg */ 13586260e5d5Smrgdrm_public drmBufMapPtr drmMapBufs(int fd) 135922944501Smrg{ 136022944501Smrg drm_buf_map_t bufs; 136122944501Smrg drmBufMapPtr retval; 136222944501Smrg int i; 136322944501Smrg 1364424e9256Smrg memclear(bufs); 136522944501Smrg if (drmIoctl(fd, DRM_IOCTL_MAP_BUFS, &bufs)) 1366fe517fc9Smrg return NULL; 136722944501Smrg 136822944501Smrg if (!bufs.count) 1369fe517fc9Smrg return NULL; 137022944501Smrg 1371fe517fc9Smrg if (!(bufs.list = drmMalloc(bufs.count * sizeof(*bufs.list)))) 1372fe517fc9Smrg return NULL; 137322944501Smrg 1374fe517fc9Smrg if (drmIoctl(fd, DRM_IOCTL_MAP_BUFS, &bufs)) { 1375fe517fc9Smrg drmFree(bufs.list); 1376fe517fc9Smrg return NULL; 1377fe517fc9Smrg } 137822944501Smrg 1379fe517fc9Smrg retval = drmMalloc(sizeof(*retval)); 1380fe517fc9Smrg retval->count = bufs.count; 1381fe517fc9Smrg retval->list = drmMalloc(bufs.count * sizeof(*retval->list)); 1382fe517fc9Smrg for (i = 0; i < bufs.count; i++) { 1383fe517fc9Smrg retval->list[i].idx = bufs.list[i].idx; 1384fe517fc9Smrg retval->list[i].total = bufs.list[i].total; 1385fe517fc9Smrg retval->list[i].used = 0; 1386fe517fc9Smrg retval->list[i].address = bufs.list[i].address; 1387fe517fc9Smrg } 138822944501Smrg 1389fe517fc9Smrg drmFree(bufs.list); 1390fe517fc9Smrg return retval; 139122944501Smrg} 139222944501Smrg 139322944501Smrg 139422944501Smrg/** 139522944501Smrg * Unmap buffers allocated with drmMapBufs(). 139622944501Smrg * 139722944501Smrg * \return zero on success, or negative value on failure. 139822944501Smrg * 139922944501Smrg * \internal 140022944501Smrg * Calls munmap() for every buffer stored in \p bufs and frees the 140122944501Smrg * memory allocated by drmMapBufs(). 140222944501Smrg */ 14036260e5d5Smrgdrm_public int drmUnmapBufs(drmBufMapPtr bufs) 140422944501Smrg{ 140522944501Smrg int i; 140622944501Smrg 140722944501Smrg for (i = 0; i < bufs->count; i++) { 1408fe517fc9Smrg drm_munmap(bufs->list[i].address, bufs->list[i].total); 140922944501Smrg } 141022944501Smrg 141122944501Smrg drmFree(bufs->list); 141222944501Smrg drmFree(bufs); 141322944501Smrg return 0; 141422944501Smrg} 141522944501Smrg 141622944501Smrg 1417fe517fc9Smrg#define DRM_DMA_RETRY 16 141822944501Smrg 141922944501Smrg/** 142022944501Smrg * Reserve DMA buffers. 142122944501Smrg * 142222944501Smrg * \param fd file descriptor. 1423fe517fc9Smrg * \param request 1424fe517fc9Smrg * 142522944501Smrg * \return zero on success, or a negative value on failure. 142622944501Smrg * 142722944501Smrg * \internal 142822944501Smrg * Assemble the arguments into a drm_dma structure and keeps issuing the 142922944501Smrg * DRM_IOCTL_DMA ioctl until success or until maximum number of retries. 143022944501Smrg */ 14316260e5d5Smrgdrm_public int drmDMA(int fd, drmDMAReqPtr request) 143222944501Smrg{ 143322944501Smrg drm_dma_t dma; 143422944501Smrg int ret, i = 0; 143522944501Smrg 143622944501Smrg dma.context = request->context; 143722944501Smrg dma.send_count = request->send_count; 143822944501Smrg dma.send_indices = request->send_list; 143922944501Smrg dma.send_sizes = request->send_sizes; 144022944501Smrg dma.flags = request->flags; 144122944501Smrg dma.request_count = request->request_count; 144222944501Smrg dma.request_size = request->request_size; 144322944501Smrg dma.request_indices = request->request_list; 144422944501Smrg dma.request_sizes = request->request_sizes; 144522944501Smrg dma.granted_count = 0; 144622944501Smrg 144722944501Smrg do { 1448fe517fc9Smrg ret = ioctl( fd, DRM_IOCTL_DMA, &dma ); 144922944501Smrg } while ( ret && errno == EAGAIN && i++ < DRM_DMA_RETRY ); 145022944501Smrg 145122944501Smrg if ( ret == 0 ) { 1452fe517fc9Smrg request->granted_count = dma.granted_count; 1453fe517fc9Smrg return 0; 145422944501Smrg } else { 1455fe517fc9Smrg return -errno; 145622944501Smrg } 145722944501Smrg} 145822944501Smrg 145922944501Smrg 146022944501Smrg/** 146122944501Smrg * Obtain heavyweight hardware lock. 146222944501Smrg * 146322944501Smrg * \param fd file descriptor. 146422944501Smrg * \param context context. 146522944501Smrg * \param flags flags that determine the sate of the hardware when the function 146622944501Smrg * returns. 1467fe517fc9Smrg * 146822944501Smrg * \return always zero. 1469fe517fc9Smrg * 147022944501Smrg * \internal 147122944501Smrg * This function translates the arguments into a drm_lock structure and issue 147222944501Smrg * the DRM_IOCTL_LOCK ioctl until the lock is successfully acquired. 147322944501Smrg */ 14746260e5d5Smrgdrm_public int drmGetLock(int fd, drm_context_t context, drmLockFlags flags) 147522944501Smrg{ 147622944501Smrg drm_lock_t lock; 147722944501Smrg 1478424e9256Smrg memclear(lock); 147922944501Smrg lock.context = context; 148022944501Smrg lock.flags = 0; 148122944501Smrg if (flags & DRM_LOCK_READY) lock.flags |= _DRM_LOCK_READY; 148222944501Smrg if (flags & DRM_LOCK_QUIESCENT) lock.flags |= _DRM_LOCK_QUIESCENT; 148322944501Smrg if (flags & DRM_LOCK_FLUSH) lock.flags |= _DRM_LOCK_FLUSH; 148422944501Smrg if (flags & DRM_LOCK_FLUSH_ALL) lock.flags |= _DRM_LOCK_FLUSH_ALL; 148522944501Smrg if (flags & DRM_HALT_ALL_QUEUES) lock.flags |= _DRM_HALT_ALL_QUEUES; 148622944501Smrg if (flags & DRM_HALT_CUR_QUEUES) lock.flags |= _DRM_HALT_CUR_QUEUES; 148722944501Smrg 148822944501Smrg while (drmIoctl(fd, DRM_IOCTL_LOCK, &lock)) 1489fe517fc9Smrg ; 149022944501Smrg return 0; 149122944501Smrg} 149222944501Smrg 149322944501Smrg/** 149422944501Smrg * Release the hardware lock. 149522944501Smrg * 149622944501Smrg * \param fd file descriptor. 149722944501Smrg * \param context context. 1498fe517fc9Smrg * 149922944501Smrg * \return zero on success, or a negative value on failure. 1500fe517fc9Smrg * 150122944501Smrg * \internal 150222944501Smrg * This function is a wrapper around the DRM_IOCTL_UNLOCK ioctl, passing the 150322944501Smrg * argument in a drm_lock structure. 150422944501Smrg */ 15056260e5d5Smrgdrm_public int drmUnlock(int fd, drm_context_t context) 150622944501Smrg{ 150722944501Smrg drm_lock_t lock; 150822944501Smrg 1509424e9256Smrg memclear(lock); 151022944501Smrg lock.context = context; 151122944501Smrg return drmIoctl(fd, DRM_IOCTL_UNLOCK, &lock); 151222944501Smrg} 151322944501Smrg 15146260e5d5Smrgdrm_public drm_context_t *drmGetReservedContextList(int fd, int *count) 151522944501Smrg{ 151622944501Smrg drm_ctx_res_t res; 151722944501Smrg drm_ctx_t *list; 151822944501Smrg drm_context_t * retval; 151922944501Smrg int i; 152022944501Smrg 1521424e9256Smrg memclear(res); 152222944501Smrg if (drmIoctl(fd, DRM_IOCTL_RES_CTX, &res)) 1523fe517fc9Smrg return NULL; 152422944501Smrg 152522944501Smrg if (!res.count) 1526fe517fc9Smrg return NULL; 152722944501Smrg 152822944501Smrg if (!(list = drmMalloc(res.count * sizeof(*list)))) 1529fe517fc9Smrg return NULL; 15300655efefSmrg if (!(retval = drmMalloc(res.count * sizeof(*retval)))) 15310655efefSmrg goto err_free_list; 153222944501Smrg 153322944501Smrg res.contexts = list; 153422944501Smrg if (drmIoctl(fd, DRM_IOCTL_RES_CTX, &res)) 15350655efefSmrg goto err_free_context; 153622944501Smrg 153722944501Smrg for (i = 0; i < res.count; i++) 1538fe517fc9Smrg retval[i] = list[i].handle; 153922944501Smrg drmFree(list); 154022944501Smrg 154122944501Smrg *count = res.count; 154222944501Smrg return retval; 15430655efefSmrg 15440655efefSmrgerr_free_list: 15450655efefSmrg drmFree(list); 15460655efefSmrgerr_free_context: 15470655efefSmrg drmFree(retval); 15480655efefSmrg return NULL; 154922944501Smrg} 155022944501Smrg 15516260e5d5Smrgdrm_public void drmFreeReservedContextList(drm_context_t *pt) 155222944501Smrg{ 155322944501Smrg drmFree(pt); 155422944501Smrg} 155522944501Smrg 155622944501Smrg/** 155722944501Smrg * Create context. 155822944501Smrg * 155922944501Smrg * Used by the X server during GLXContext initialization. This causes 156022944501Smrg * per-context kernel-level resources to be allocated. 156122944501Smrg * 156222944501Smrg * \param fd file descriptor. 156322944501Smrg * \param handle is set on success. To be used by the client when requesting DMA 156422944501Smrg * dispatch with drmDMA(). 1565fe517fc9Smrg * 156622944501Smrg * \return zero on success, or a negative value on failure. 1567fe517fc9Smrg * 156822944501Smrg * \note May only be called by root. 1569fe517fc9Smrg * 157022944501Smrg * \internal 157122944501Smrg * This function is a wrapper around the DRM_IOCTL_ADD_CTX ioctl, passing the 157222944501Smrg * argument in a drm_ctx structure. 157322944501Smrg */ 15746260e5d5Smrgdrm_public int drmCreateContext(int fd, drm_context_t *handle) 157522944501Smrg{ 157622944501Smrg drm_ctx_t ctx; 157722944501Smrg 1578424e9256Smrg memclear(ctx); 157922944501Smrg if (drmIoctl(fd, DRM_IOCTL_ADD_CTX, &ctx)) 1580fe517fc9Smrg return -errno; 158122944501Smrg *handle = ctx.handle; 158222944501Smrg return 0; 158322944501Smrg} 158422944501Smrg 15856260e5d5Smrgdrm_public int drmSwitchToContext(int fd, drm_context_t context) 158622944501Smrg{ 158722944501Smrg drm_ctx_t ctx; 158822944501Smrg 1589424e9256Smrg memclear(ctx); 159022944501Smrg ctx.handle = context; 159122944501Smrg if (drmIoctl(fd, DRM_IOCTL_SWITCH_CTX, &ctx)) 1592fe517fc9Smrg return -errno; 159322944501Smrg return 0; 159422944501Smrg} 159522944501Smrg 15966260e5d5Smrgdrm_public int drmSetContextFlags(int fd, drm_context_t context, 15976260e5d5Smrg drm_context_tFlags flags) 159822944501Smrg{ 159922944501Smrg drm_ctx_t ctx; 160022944501Smrg 160122944501Smrg /* 160222944501Smrg * Context preserving means that no context switches are done between DMA 160322944501Smrg * buffers from one context and the next. This is suitable for use in the 160422944501Smrg * X server (which promises to maintain hardware context), or in the 160522944501Smrg * client-side library when buffers are swapped on behalf of two threads. 160622944501Smrg */ 1607424e9256Smrg memclear(ctx); 160822944501Smrg ctx.handle = context; 160922944501Smrg if (flags & DRM_CONTEXT_PRESERVED) 1610fe517fc9Smrg ctx.flags |= _DRM_CONTEXT_PRESERVED; 161122944501Smrg if (flags & DRM_CONTEXT_2DONLY) 1612fe517fc9Smrg ctx.flags |= _DRM_CONTEXT_2DONLY; 161322944501Smrg if (drmIoctl(fd, DRM_IOCTL_MOD_CTX, &ctx)) 1614fe517fc9Smrg return -errno; 161522944501Smrg return 0; 161622944501Smrg} 161722944501Smrg 16186260e5d5Smrgdrm_public int drmGetContextFlags(int fd, drm_context_t context, 16196260e5d5Smrg drm_context_tFlagsPtr flags) 162022944501Smrg{ 162122944501Smrg drm_ctx_t ctx; 162222944501Smrg 1623424e9256Smrg memclear(ctx); 162422944501Smrg ctx.handle = context; 162522944501Smrg if (drmIoctl(fd, DRM_IOCTL_GET_CTX, &ctx)) 1626fe517fc9Smrg return -errno; 162722944501Smrg *flags = 0; 162822944501Smrg if (ctx.flags & _DRM_CONTEXT_PRESERVED) 1629fe517fc9Smrg *flags |= DRM_CONTEXT_PRESERVED; 163022944501Smrg if (ctx.flags & _DRM_CONTEXT_2DONLY) 1631fe517fc9Smrg *flags |= DRM_CONTEXT_2DONLY; 163222944501Smrg return 0; 163322944501Smrg} 163422944501Smrg 163522944501Smrg/** 163622944501Smrg * Destroy context. 163722944501Smrg * 163822944501Smrg * Free any kernel-level resources allocated with drmCreateContext() associated 163922944501Smrg * with the context. 1640fe517fc9Smrg * 164122944501Smrg * \param fd file descriptor. 164222944501Smrg * \param handle handle given by drmCreateContext(). 1643fe517fc9Smrg * 164422944501Smrg * \return zero on success, or a negative value on failure. 1645fe517fc9Smrg * 164622944501Smrg * \note May only be called by root. 1647fe517fc9Smrg * 164822944501Smrg * \internal 164922944501Smrg * This function is a wrapper around the DRM_IOCTL_RM_CTX ioctl, passing the 165022944501Smrg * argument in a drm_ctx structure. 165122944501Smrg */ 16526260e5d5Smrgdrm_public int drmDestroyContext(int fd, drm_context_t handle) 165322944501Smrg{ 165422944501Smrg drm_ctx_t ctx; 1655424e9256Smrg 1656424e9256Smrg memclear(ctx); 165722944501Smrg ctx.handle = handle; 165822944501Smrg if (drmIoctl(fd, DRM_IOCTL_RM_CTX, &ctx)) 1659fe517fc9Smrg return -errno; 166022944501Smrg return 0; 166122944501Smrg} 166222944501Smrg 16636260e5d5Smrgdrm_public int drmCreateDrawable(int fd, drm_drawable_t *handle) 166422944501Smrg{ 166522944501Smrg drm_draw_t draw; 1666424e9256Smrg 1667424e9256Smrg memclear(draw); 166822944501Smrg if (drmIoctl(fd, DRM_IOCTL_ADD_DRAW, &draw)) 1669fe517fc9Smrg return -errno; 167022944501Smrg *handle = draw.handle; 167122944501Smrg return 0; 167222944501Smrg} 167322944501Smrg 16746260e5d5Smrgdrm_public int drmDestroyDrawable(int fd, drm_drawable_t handle) 167522944501Smrg{ 167622944501Smrg drm_draw_t draw; 1677424e9256Smrg 1678424e9256Smrg memclear(draw); 167922944501Smrg draw.handle = handle; 168022944501Smrg if (drmIoctl(fd, DRM_IOCTL_RM_DRAW, &draw)) 1681fe517fc9Smrg return -errno; 168222944501Smrg return 0; 168322944501Smrg} 168422944501Smrg 16856260e5d5Smrgdrm_public int drmUpdateDrawableInfo(int fd, drm_drawable_t handle, 16866260e5d5Smrg drm_drawable_info_type_t type, 16876260e5d5Smrg unsigned int num, void *data) 168822944501Smrg{ 168922944501Smrg drm_update_draw_t update; 169022944501Smrg 1691424e9256Smrg memclear(update); 169222944501Smrg update.handle = handle; 169322944501Smrg update.type = type; 169422944501Smrg update.num = num; 169522944501Smrg update.data = (unsigned long long)(unsigned long)data; 169622944501Smrg 169722944501Smrg if (drmIoctl(fd, DRM_IOCTL_UPDATE_DRAW, &update)) 1698fe517fc9Smrg return -errno; 169922944501Smrg 170022944501Smrg return 0; 170122944501Smrg} 170222944501Smrg 17036260e5d5Smrgdrm_public int drmCrtcGetSequence(int fd, uint32_t crtcId, uint64_t *sequence, 17046260e5d5Smrg uint64_t *ns) 17052b90624aSmrg{ 17062b90624aSmrg struct drm_crtc_get_sequence get_seq; 17072b90624aSmrg int ret; 17082b90624aSmrg 17092b90624aSmrg memclear(get_seq); 17102b90624aSmrg get_seq.crtc_id = crtcId; 17112b90624aSmrg ret = drmIoctl(fd, DRM_IOCTL_CRTC_GET_SEQUENCE, &get_seq); 17122b90624aSmrg if (ret) 17132b90624aSmrg return ret; 17142b90624aSmrg 17152b90624aSmrg if (sequence) 17162b90624aSmrg *sequence = get_seq.sequence; 17172b90624aSmrg if (ns) 17182b90624aSmrg *ns = get_seq.sequence_ns; 17192b90624aSmrg return 0; 17202b90624aSmrg} 17212b90624aSmrg 17226260e5d5Smrgdrm_public int drmCrtcQueueSequence(int fd, uint32_t crtcId, uint32_t flags, 17236260e5d5Smrg uint64_t sequence, 17246260e5d5Smrg uint64_t *sequence_queued, 17256260e5d5Smrg uint64_t user_data) 17262b90624aSmrg{ 17272b90624aSmrg struct drm_crtc_queue_sequence queue_seq; 17282b90624aSmrg int ret; 17292b90624aSmrg 17302b90624aSmrg memclear(queue_seq); 17312b90624aSmrg queue_seq.crtc_id = crtcId; 17322b90624aSmrg queue_seq.flags = flags; 17332b90624aSmrg queue_seq.sequence = sequence; 17342b90624aSmrg queue_seq.user_data = user_data; 17352b90624aSmrg 17362b90624aSmrg ret = drmIoctl(fd, DRM_IOCTL_CRTC_QUEUE_SEQUENCE, &queue_seq); 17372b90624aSmrg if (ret == 0 && sequence_queued) 17382b90624aSmrg *sequence_queued = queue_seq.sequence; 17392b90624aSmrg 17402b90624aSmrg return ret; 17412b90624aSmrg} 17422b90624aSmrg 174322944501Smrg/** 174422944501Smrg * Acquire the AGP device. 174522944501Smrg * 174622944501Smrg * Must be called before any of the other AGP related calls. 174722944501Smrg * 174822944501Smrg * \param fd file descriptor. 1749fe517fc9Smrg * 175022944501Smrg * \return zero on success, or a negative value on failure. 1751fe517fc9Smrg * 175222944501Smrg * \internal 175322944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_ACQUIRE ioctl. 175422944501Smrg */ 17556260e5d5Smrgdrm_public int drmAgpAcquire(int fd) 175622944501Smrg{ 175722944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_ACQUIRE, NULL)) 1758fe517fc9Smrg return -errno; 175922944501Smrg return 0; 176022944501Smrg} 176122944501Smrg 176222944501Smrg 176322944501Smrg/** 176422944501Smrg * Release the AGP device. 176522944501Smrg * 176622944501Smrg * \param fd file descriptor. 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_RELEASE ioctl. 177222944501Smrg */ 17736260e5d5Smrgdrm_public int drmAgpRelease(int fd) 177422944501Smrg{ 177522944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_RELEASE, NULL)) 1776fe517fc9Smrg return -errno; 177722944501Smrg return 0; 177822944501Smrg} 177922944501Smrg 178022944501Smrg 178122944501Smrg/** 178222944501Smrg * Set the AGP mode. 178322944501Smrg * 178422944501Smrg * \param fd file descriptor. 178522944501Smrg * \param mode AGP mode. 1786fe517fc9Smrg * 178722944501Smrg * \return zero on success, or a negative value on failure. 1788fe517fc9Smrg * 178922944501Smrg * \internal 179022944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_ENABLE ioctl, passing the 179122944501Smrg * argument in a drm_agp_mode structure. 179222944501Smrg */ 17936260e5d5Smrgdrm_public int drmAgpEnable(int fd, unsigned long mode) 179422944501Smrg{ 179522944501Smrg drm_agp_mode_t m; 179622944501Smrg 1797424e9256Smrg memclear(m); 179822944501Smrg m.mode = mode; 179922944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_ENABLE, &m)) 1800fe517fc9Smrg return -errno; 180122944501Smrg return 0; 180222944501Smrg} 180322944501Smrg 180422944501Smrg 180522944501Smrg/** 180622944501Smrg * Allocate a chunk of AGP memory. 180722944501Smrg * 180822944501Smrg * \param fd file descriptor. 180922944501Smrg * \param size requested memory size in bytes. Will be rounded to page boundary. 181022944501Smrg * \param type type of memory to allocate. 181122944501Smrg * \param address if not zero, will be set to the physical address of the 181222944501Smrg * allocated memory. 181322944501Smrg * \param handle on success will be set to a handle of the allocated memory. 1814fe517fc9Smrg * 181522944501Smrg * \return zero on success, or a negative value on failure. 1816fe517fc9Smrg * 181722944501Smrg * \internal 181822944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_ALLOC ioctl, passing the 181922944501Smrg * arguments in a drm_agp_buffer structure. 182022944501Smrg */ 18216260e5d5Smrgdrm_public int drmAgpAlloc(int fd, unsigned long size, unsigned long type, 18226260e5d5Smrg unsigned long *address, drm_handle_t *handle) 182322944501Smrg{ 182422944501Smrg drm_agp_buffer_t b; 182522944501Smrg 1826424e9256Smrg memclear(b); 182722944501Smrg *handle = DRM_AGP_NO_HANDLE; 182822944501Smrg b.size = size; 182922944501Smrg b.type = type; 183022944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_ALLOC, &b)) 1831fe517fc9Smrg return -errno; 183222944501Smrg if (address != 0UL) 1833fe517fc9Smrg *address = b.physical; 183422944501Smrg *handle = b.handle; 183522944501Smrg return 0; 183622944501Smrg} 183722944501Smrg 183822944501Smrg 183922944501Smrg/** 184022944501Smrg * Free a chunk of AGP memory. 184122944501Smrg * 184222944501Smrg * \param fd file descriptor. 184322944501Smrg * \param handle handle to the allocated memory, as given by drmAgpAllocate(). 1844fe517fc9Smrg * 184522944501Smrg * \return zero on success, or a negative value on failure. 1846fe517fc9Smrg * 184722944501Smrg * \internal 184822944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_FREE ioctl, passing the 184922944501Smrg * argument in a drm_agp_buffer structure. 185022944501Smrg */ 18516260e5d5Smrgdrm_public int drmAgpFree(int fd, drm_handle_t handle) 185222944501Smrg{ 185322944501Smrg drm_agp_buffer_t b; 185422944501Smrg 1855424e9256Smrg memclear(b); 185622944501Smrg b.handle = handle; 185722944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_FREE, &b)) 1858fe517fc9Smrg return -errno; 185922944501Smrg return 0; 186022944501Smrg} 186122944501Smrg 186222944501Smrg 186322944501Smrg/** 186422944501Smrg * Bind a chunk of AGP memory. 186522944501Smrg * 186622944501Smrg * \param fd file descriptor. 186722944501Smrg * \param handle handle to the allocated memory, as given by drmAgpAllocate(). 186822944501Smrg * \param offset offset in bytes. It will round to page boundary. 1869fe517fc9Smrg * 187022944501Smrg * \return zero on success, or a negative value on failure. 1871fe517fc9Smrg * 187222944501Smrg * \internal 187322944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_BIND ioctl, passing the 187422944501Smrg * argument in a drm_agp_binding structure. 187522944501Smrg */ 18766260e5d5Smrgdrm_public int drmAgpBind(int fd, drm_handle_t handle, unsigned long offset) 187722944501Smrg{ 187822944501Smrg drm_agp_binding_t b; 187922944501Smrg 1880424e9256Smrg memclear(b); 188122944501Smrg b.handle = handle; 188222944501Smrg b.offset = offset; 188322944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_BIND, &b)) 1884fe517fc9Smrg return -errno; 188522944501Smrg return 0; 188622944501Smrg} 188722944501Smrg 188822944501Smrg 188922944501Smrg/** 189022944501Smrg * Unbind a chunk of AGP memory. 189122944501Smrg * 189222944501Smrg * \param fd file descriptor. 189322944501Smrg * \param handle handle to the allocated memory, as given by drmAgpAllocate(). 1894fe517fc9Smrg * 189522944501Smrg * \return zero on success, or a negative value on failure. 1896fe517fc9Smrg * 189722944501Smrg * \internal 189822944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_UNBIND ioctl, passing 189922944501Smrg * the argument in a drm_agp_binding structure. 190022944501Smrg */ 19016260e5d5Smrgdrm_public int drmAgpUnbind(int fd, drm_handle_t handle) 190222944501Smrg{ 190322944501Smrg drm_agp_binding_t b; 190422944501Smrg 1905424e9256Smrg memclear(b); 190622944501Smrg b.handle = handle; 190722944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_UNBIND, &b)) 1908fe517fc9Smrg return -errno; 190922944501Smrg return 0; 191022944501Smrg} 191122944501Smrg 191222944501Smrg 191322944501Smrg/** 191422944501Smrg * Get AGP driver major version number. 191522944501Smrg * 191622944501Smrg * \param fd file descriptor. 1917fe517fc9Smrg * 191822944501Smrg * \return major version number on success, or a negative value on failure.. 1919fe517fc9Smrg * 192022944501Smrg * \internal 192122944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the 192222944501Smrg * necessary information in a drm_agp_info structure. 192322944501Smrg */ 19246260e5d5Smrgdrm_public int drmAgpVersionMajor(int fd) 192522944501Smrg{ 192622944501Smrg drm_agp_info_t i; 192722944501Smrg 1928424e9256Smrg memclear(i); 1929424e9256Smrg 193022944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i)) 1931fe517fc9Smrg return -errno; 193222944501Smrg return i.agp_version_major; 193322944501Smrg} 193422944501Smrg 193522944501Smrg 193622944501Smrg/** 193722944501Smrg * Get AGP driver minor version number. 193822944501Smrg * 193922944501Smrg * \param fd file descriptor. 1940fe517fc9Smrg * 194122944501Smrg * \return minor version number on success, or a negative value on failure. 1942fe517fc9Smrg * 194322944501Smrg * \internal 194422944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the 194522944501Smrg * necessary information in a drm_agp_info structure. 194622944501Smrg */ 19476260e5d5Smrgdrm_public int drmAgpVersionMinor(int fd) 194822944501Smrg{ 194922944501Smrg drm_agp_info_t i; 195022944501Smrg 1951424e9256Smrg memclear(i); 1952424e9256Smrg 195322944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i)) 1954fe517fc9Smrg return -errno; 195522944501Smrg return i.agp_version_minor; 195622944501Smrg} 195722944501Smrg 195822944501Smrg 195922944501Smrg/** 196022944501Smrg * Get AGP mode. 196122944501Smrg * 196222944501Smrg * \param fd file descriptor. 1963fe517fc9Smrg * 196422944501Smrg * \return mode on success, or zero on failure. 1965fe517fc9Smrg * 196622944501Smrg * \internal 196722944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the 196822944501Smrg * necessary information in a drm_agp_info structure. 196922944501Smrg */ 19706260e5d5Smrgdrm_public unsigned long drmAgpGetMode(int fd) 197122944501Smrg{ 197222944501Smrg drm_agp_info_t i; 197322944501Smrg 1974424e9256Smrg memclear(i); 1975424e9256Smrg 197622944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i)) 1977fe517fc9Smrg return 0; 197822944501Smrg return i.mode; 197922944501Smrg} 198022944501Smrg 198122944501Smrg 198222944501Smrg/** 198322944501Smrg * Get AGP aperture base. 198422944501Smrg * 198522944501Smrg * \param fd file descriptor. 1986fe517fc9Smrg * 198722944501Smrg * \return aperture base on success, zero on failure. 1988fe517fc9Smrg * 198922944501Smrg * \internal 199022944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the 199122944501Smrg * necessary information in a drm_agp_info structure. 199222944501Smrg */ 19936260e5d5Smrgdrm_public unsigned long drmAgpBase(int fd) 199422944501Smrg{ 199522944501Smrg drm_agp_info_t i; 199622944501Smrg 1997424e9256Smrg memclear(i); 1998424e9256Smrg 199922944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i)) 2000fe517fc9Smrg return 0; 200122944501Smrg return i.aperture_base; 200222944501Smrg} 200322944501Smrg 200422944501Smrg 200522944501Smrg/** 200622944501Smrg * Get AGP aperture size. 200722944501Smrg * 200822944501Smrg * \param fd file descriptor. 2009fe517fc9Smrg * 201022944501Smrg * \return aperture size on success, zero on failure. 2011fe517fc9Smrg * 201222944501Smrg * \internal 201322944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the 201422944501Smrg * necessary information in a drm_agp_info structure. 201522944501Smrg */ 20166260e5d5Smrgdrm_public unsigned long drmAgpSize(int fd) 201722944501Smrg{ 201822944501Smrg drm_agp_info_t i; 201922944501Smrg 2020424e9256Smrg memclear(i); 2021424e9256Smrg 202222944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i)) 2023fe517fc9Smrg return 0; 202422944501Smrg return i.aperture_size; 202522944501Smrg} 202622944501Smrg 202722944501Smrg 202822944501Smrg/** 202922944501Smrg * Get used AGP memory. 203022944501Smrg * 203122944501Smrg * \param fd file descriptor. 2032fe517fc9Smrg * 203322944501Smrg * \return memory used on success, or zero on failure. 2034fe517fc9Smrg * 203522944501Smrg * \internal 203622944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the 203722944501Smrg * necessary information in a drm_agp_info structure. 203822944501Smrg */ 20396260e5d5Smrgdrm_public unsigned long drmAgpMemoryUsed(int fd) 204022944501Smrg{ 204122944501Smrg drm_agp_info_t i; 204222944501Smrg 2043424e9256Smrg memclear(i); 2044424e9256Smrg 204522944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i)) 2046fe517fc9Smrg return 0; 204722944501Smrg return i.memory_used; 204822944501Smrg} 204922944501Smrg 205022944501Smrg 205122944501Smrg/** 205222944501Smrg * Get available AGP memory. 205322944501Smrg * 205422944501Smrg * \param fd file descriptor. 2055fe517fc9Smrg * 205622944501Smrg * \return memory available on success, or zero on failure. 2057fe517fc9Smrg * 205822944501Smrg * \internal 205922944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the 206022944501Smrg * necessary information in a drm_agp_info structure. 206122944501Smrg */ 20626260e5d5Smrgdrm_public unsigned long drmAgpMemoryAvail(int fd) 206322944501Smrg{ 206422944501Smrg drm_agp_info_t i; 206522944501Smrg 2066424e9256Smrg memclear(i); 2067424e9256Smrg 206822944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i)) 2069fe517fc9Smrg return 0; 207022944501Smrg return i.memory_allowed; 207122944501Smrg} 207222944501Smrg 207322944501Smrg 207422944501Smrg/** 207522944501Smrg * Get hardware vendor ID. 207622944501Smrg * 207722944501Smrg * \param fd file descriptor. 2078fe517fc9Smrg * 207922944501Smrg * \return vendor ID on success, or zero on failure. 2080fe517fc9Smrg * 208122944501Smrg * \internal 208222944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the 208322944501Smrg * necessary information in a drm_agp_info structure. 208422944501Smrg */ 20856260e5d5Smrgdrm_public unsigned int drmAgpVendorId(int fd) 208622944501Smrg{ 208722944501Smrg drm_agp_info_t i; 208822944501Smrg 2089424e9256Smrg memclear(i); 2090424e9256Smrg 209122944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i)) 2092fe517fc9Smrg return 0; 209322944501Smrg return i.id_vendor; 209422944501Smrg} 209522944501Smrg 209622944501Smrg 209722944501Smrg/** 209822944501Smrg * Get hardware device ID. 209922944501Smrg * 210022944501Smrg * \param fd file descriptor. 2101fe517fc9Smrg * 210222944501Smrg * \return zero on success, or zero on failure. 2103fe517fc9Smrg * 210422944501Smrg * \internal 210522944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the 210622944501Smrg * necessary information in a drm_agp_info structure. 210722944501Smrg */ 21086260e5d5Smrgdrm_public unsigned int drmAgpDeviceId(int fd) 210922944501Smrg{ 211022944501Smrg drm_agp_info_t i; 211122944501Smrg 2112424e9256Smrg memclear(i); 2113424e9256Smrg 211422944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i)) 2115fe517fc9Smrg return 0; 211622944501Smrg return i.id_device; 211722944501Smrg} 211822944501Smrg 21196260e5d5Smrgdrm_public int drmScatterGatherAlloc(int fd, unsigned long size, 21206260e5d5Smrg drm_handle_t *handle) 212122944501Smrg{ 212222944501Smrg drm_scatter_gather_t sg; 212322944501Smrg 2124424e9256Smrg memclear(sg); 2125424e9256Smrg 212622944501Smrg *handle = 0; 212722944501Smrg sg.size = size; 212822944501Smrg if (drmIoctl(fd, DRM_IOCTL_SG_ALLOC, &sg)) 2129fe517fc9Smrg return -errno; 213022944501Smrg *handle = sg.handle; 213122944501Smrg return 0; 213222944501Smrg} 213322944501Smrg 21346260e5d5Smrgdrm_public int drmScatterGatherFree(int fd, drm_handle_t handle) 213522944501Smrg{ 213622944501Smrg drm_scatter_gather_t sg; 213722944501Smrg 2138424e9256Smrg memclear(sg); 213922944501Smrg sg.handle = handle; 214022944501Smrg if (drmIoctl(fd, DRM_IOCTL_SG_FREE, &sg)) 2141fe517fc9Smrg return -errno; 214222944501Smrg return 0; 214322944501Smrg} 214422944501Smrg 214522944501Smrg/** 214622944501Smrg * Wait for VBLANK. 214722944501Smrg * 214822944501Smrg * \param fd file descriptor. 214922944501Smrg * \param vbl pointer to a drmVBlank structure. 2150fe517fc9Smrg * 215122944501Smrg * \return zero on success, or a negative value on failure. 2152fe517fc9Smrg * 215322944501Smrg * \internal 215422944501Smrg * This function is a wrapper around the DRM_IOCTL_WAIT_VBLANK ioctl. 215522944501Smrg */ 21566260e5d5Smrgdrm_public int drmWaitVBlank(int fd, drmVBlankPtr vbl) 215722944501Smrg{ 215822944501Smrg struct timespec timeout, cur; 215922944501Smrg int ret; 216022944501Smrg 216122944501Smrg ret = clock_gettime(CLOCK_MONOTONIC, &timeout); 216222944501Smrg if (ret < 0) { 2163fe517fc9Smrg fprintf(stderr, "clock_gettime failed: %s\n", strerror(errno)); 2164fe517fc9Smrg goto out; 216522944501Smrg } 216622944501Smrg timeout.tv_sec++; 216722944501Smrg 216822944501Smrg do { 216922944501Smrg ret = ioctl(fd, DRM_IOCTL_WAIT_VBLANK, vbl); 217022944501Smrg vbl->request.type &= ~DRM_VBLANK_RELATIVE; 217122944501Smrg if (ret && errno == EINTR) { 2172fe517fc9Smrg clock_gettime(CLOCK_MONOTONIC, &cur); 2173fe517fc9Smrg /* Timeout after 1s */ 2174fe517fc9Smrg if (cur.tv_sec > timeout.tv_sec + 1 || 2175fe517fc9Smrg (cur.tv_sec == timeout.tv_sec && cur.tv_nsec >= 2176fe517fc9Smrg timeout.tv_nsec)) { 2177fe517fc9Smrg errno = EBUSY; 2178fe517fc9Smrg ret = -1; 2179fe517fc9Smrg break; 2180fe517fc9Smrg } 218122944501Smrg } 218222944501Smrg } while (ret && errno == EINTR); 218322944501Smrg 218422944501Smrgout: 218522944501Smrg return ret; 218622944501Smrg} 218722944501Smrg 21886260e5d5Smrgdrm_public int drmError(int err, const char *label) 218922944501Smrg{ 219022944501Smrg switch (err) { 219122944501Smrg case DRM_ERR_NO_DEVICE: 2192fe517fc9Smrg fprintf(stderr, "%s: no device\n", label); 2193fe517fc9Smrg break; 219422944501Smrg case DRM_ERR_NO_ACCESS: 2195fe517fc9Smrg fprintf(stderr, "%s: no access\n", label); 2196fe517fc9Smrg break; 219722944501Smrg case DRM_ERR_NOT_ROOT: 2198fe517fc9Smrg fprintf(stderr, "%s: not root\n", label); 2199fe517fc9Smrg break; 220022944501Smrg case DRM_ERR_INVALID: 2201fe517fc9Smrg fprintf(stderr, "%s: invalid args\n", label); 2202fe517fc9Smrg break; 220322944501Smrg default: 2204fe517fc9Smrg if (err < 0) 2205fe517fc9Smrg err = -err; 2206fe517fc9Smrg fprintf( stderr, "%s: error %d (%s)\n", label, err, strerror(err) ); 2207fe517fc9Smrg break; 220822944501Smrg } 220922944501Smrg 221022944501Smrg return 1; 221122944501Smrg} 221222944501Smrg 221322944501Smrg/** 221422944501Smrg * Install IRQ handler. 221522944501Smrg * 221622944501Smrg * \param fd file descriptor. 221722944501Smrg * \param irq IRQ number. 2218fe517fc9Smrg * 221922944501Smrg * \return zero on success, or a negative value on failure. 2220fe517fc9Smrg * 222122944501Smrg * \internal 222222944501Smrg * This function is a wrapper around the DRM_IOCTL_CONTROL ioctl, passing the 222322944501Smrg * argument in a drm_control structure. 222422944501Smrg */ 22256260e5d5Smrgdrm_public int drmCtlInstHandler(int fd, int irq) 222622944501Smrg{ 222722944501Smrg drm_control_t ctl; 222822944501Smrg 2229424e9256Smrg memclear(ctl); 223022944501Smrg ctl.func = DRM_INST_HANDLER; 223122944501Smrg ctl.irq = irq; 223222944501Smrg if (drmIoctl(fd, DRM_IOCTL_CONTROL, &ctl)) 2233fe517fc9Smrg return -errno; 223422944501Smrg return 0; 223522944501Smrg} 223622944501Smrg 223722944501Smrg 223822944501Smrg/** 223922944501Smrg * Uninstall IRQ handler. 224022944501Smrg * 224122944501Smrg * \param fd file descriptor. 2242fe517fc9Smrg * 224322944501Smrg * \return zero on success, or a negative value on failure. 2244fe517fc9Smrg * 224522944501Smrg * \internal 224622944501Smrg * This function is a wrapper around the DRM_IOCTL_CONTROL ioctl, passing the 224722944501Smrg * argument in a drm_control structure. 224822944501Smrg */ 22496260e5d5Smrgdrm_public int drmCtlUninstHandler(int fd) 225022944501Smrg{ 225122944501Smrg drm_control_t ctl; 225222944501Smrg 2253424e9256Smrg memclear(ctl); 225422944501Smrg ctl.func = DRM_UNINST_HANDLER; 225522944501Smrg ctl.irq = 0; 225622944501Smrg if (drmIoctl(fd, DRM_IOCTL_CONTROL, &ctl)) 2257fe517fc9Smrg return -errno; 225822944501Smrg return 0; 225922944501Smrg} 226022944501Smrg 22616260e5d5Smrgdrm_public int drmFinish(int fd, int context, drmLockFlags flags) 226222944501Smrg{ 226322944501Smrg drm_lock_t lock; 226422944501Smrg 2265424e9256Smrg memclear(lock); 226622944501Smrg lock.context = context; 226722944501Smrg if (flags & DRM_LOCK_READY) lock.flags |= _DRM_LOCK_READY; 226822944501Smrg if (flags & DRM_LOCK_QUIESCENT) lock.flags |= _DRM_LOCK_QUIESCENT; 226922944501Smrg if (flags & DRM_LOCK_FLUSH) lock.flags |= _DRM_LOCK_FLUSH; 227022944501Smrg if (flags & DRM_LOCK_FLUSH_ALL) lock.flags |= _DRM_LOCK_FLUSH_ALL; 227122944501Smrg if (flags & DRM_HALT_ALL_QUEUES) lock.flags |= _DRM_HALT_ALL_QUEUES; 227222944501Smrg if (flags & DRM_HALT_CUR_QUEUES) lock.flags |= _DRM_HALT_CUR_QUEUES; 227322944501Smrg if (drmIoctl(fd, DRM_IOCTL_FINISH, &lock)) 2274fe517fc9Smrg return -errno; 227522944501Smrg return 0; 227622944501Smrg} 227722944501Smrg 227822944501Smrg/** 227922944501Smrg * Get IRQ from bus ID. 228022944501Smrg * 228122944501Smrg * \param fd file descriptor. 228222944501Smrg * \param busnum bus number. 228322944501Smrg * \param devnum device number. 228422944501Smrg * \param funcnum function number. 2285fe517fc9Smrg * 228622944501Smrg * \return IRQ number on success, or a negative value on failure. 2287fe517fc9Smrg * 228822944501Smrg * \internal 228922944501Smrg * This function is a wrapper around the DRM_IOCTL_IRQ_BUSID ioctl, passing the 229022944501Smrg * arguments in a drm_irq_busid structure. 229122944501Smrg */ 22926260e5d5Smrgdrm_public int drmGetInterruptFromBusID(int fd, int busnum, int devnum, 22936260e5d5Smrg int funcnum) 229422944501Smrg{ 229522944501Smrg drm_irq_busid_t p; 229622944501Smrg 2297424e9256Smrg memclear(p); 229822944501Smrg p.busnum = busnum; 229922944501Smrg p.devnum = devnum; 230022944501Smrg p.funcnum = funcnum; 230122944501Smrg if (drmIoctl(fd, DRM_IOCTL_IRQ_BUSID, &p)) 2302fe517fc9Smrg return -errno; 230322944501Smrg return p.irq; 230422944501Smrg} 230522944501Smrg 23066260e5d5Smrgdrm_public int drmAddContextTag(int fd, drm_context_t context, void *tag) 230722944501Smrg{ 230822944501Smrg drmHashEntry *entry = drmGetEntry(fd); 230922944501Smrg 231022944501Smrg if (drmHashInsert(entry->tagTable, context, tag)) { 2311fe517fc9Smrg drmHashDelete(entry->tagTable, context); 2312fe517fc9Smrg drmHashInsert(entry->tagTable, context, tag); 231322944501Smrg } 231422944501Smrg return 0; 231522944501Smrg} 231622944501Smrg 23176260e5d5Smrgdrm_public int drmDelContextTag(int fd, drm_context_t context) 231822944501Smrg{ 231922944501Smrg drmHashEntry *entry = drmGetEntry(fd); 232022944501Smrg 232122944501Smrg return drmHashDelete(entry->tagTable, context); 232222944501Smrg} 232322944501Smrg 23246260e5d5Smrgdrm_public void *drmGetContextTag(int fd, drm_context_t context) 232522944501Smrg{ 232622944501Smrg drmHashEntry *entry = drmGetEntry(fd); 232722944501Smrg void *value; 232822944501Smrg 232922944501Smrg if (drmHashLookup(entry->tagTable, context, &value)) 2330fe517fc9Smrg return NULL; 233122944501Smrg 233222944501Smrg return value; 233322944501Smrg} 233422944501Smrg 23356260e5d5Smrgdrm_public int drmAddContextPrivateMapping(int fd, drm_context_t ctx_id, 23366260e5d5Smrg drm_handle_t handle) 233722944501Smrg{ 233822944501Smrg drm_ctx_priv_map_t map; 233922944501Smrg 2340424e9256Smrg memclear(map); 234122944501Smrg map.ctx_id = ctx_id; 234220131375Smrg map.handle = (void *)(uintptr_t)handle; 234322944501Smrg 234422944501Smrg if (drmIoctl(fd, DRM_IOCTL_SET_SAREA_CTX, &map)) 2345fe517fc9Smrg return -errno; 234622944501Smrg return 0; 234722944501Smrg} 234822944501Smrg 23496260e5d5Smrgdrm_public int drmGetContextPrivateMapping(int fd, drm_context_t ctx_id, 23506260e5d5Smrg drm_handle_t *handle) 235122944501Smrg{ 235222944501Smrg drm_ctx_priv_map_t map; 235322944501Smrg 2354424e9256Smrg memclear(map); 235522944501Smrg map.ctx_id = ctx_id; 235622944501Smrg 235722944501Smrg if (drmIoctl(fd, DRM_IOCTL_GET_SAREA_CTX, &map)) 2358fe517fc9Smrg return -errno; 235922944501Smrg if (handle) 2360fe517fc9Smrg *handle = (drm_handle_t)(uintptr_t)map.handle; 236122944501Smrg 236222944501Smrg return 0; 236322944501Smrg} 236422944501Smrg 23656260e5d5Smrgdrm_public int drmGetMap(int fd, int idx, drm_handle_t *offset, drmSize *size, 23666260e5d5Smrg drmMapType *type, drmMapFlags *flags, 23676260e5d5Smrg drm_handle_t *handle, int *mtrr) 236822944501Smrg{ 236922944501Smrg drm_map_t map; 237022944501Smrg 2371424e9256Smrg memclear(map); 237222944501Smrg map.offset = idx; 237322944501Smrg if (drmIoctl(fd, DRM_IOCTL_GET_MAP, &map)) 2374fe517fc9Smrg return -errno; 237522944501Smrg *offset = map.offset; 237622944501Smrg *size = map.size; 237722944501Smrg *type = map.type; 237822944501Smrg *flags = map.flags; 237922944501Smrg *handle = (unsigned long)map.handle; 238022944501Smrg *mtrr = map.mtrr; 238122944501Smrg return 0; 238222944501Smrg} 238322944501Smrg 23846260e5d5Smrgdrm_public int drmGetClient(int fd, int idx, int *auth, int *pid, int *uid, 23856260e5d5Smrg unsigned long *magic, unsigned long *iocs) 238622944501Smrg{ 238722944501Smrg drm_client_t client; 238822944501Smrg 2389424e9256Smrg memclear(client); 239022944501Smrg client.idx = idx; 239122944501Smrg if (drmIoctl(fd, DRM_IOCTL_GET_CLIENT, &client)) 2392fe517fc9Smrg return -errno; 239322944501Smrg *auth = client.auth; 239422944501Smrg *pid = client.pid; 239522944501Smrg *uid = client.uid; 239622944501Smrg *magic = client.magic; 239722944501Smrg *iocs = client.iocs; 239822944501Smrg return 0; 239922944501Smrg} 240022944501Smrg 24016260e5d5Smrgdrm_public int drmGetStats(int fd, drmStatsT *stats) 240222944501Smrg{ 240322944501Smrg drm_stats_t s; 2404424e9256Smrg unsigned i; 240522944501Smrg 2406424e9256Smrg memclear(s); 240722944501Smrg if (drmIoctl(fd, DRM_IOCTL_GET_STATS, &s)) 2408fe517fc9Smrg return -errno; 240922944501Smrg 241022944501Smrg stats->count = 0; 241122944501Smrg memset(stats, 0, sizeof(*stats)); 241222944501Smrg if (s.count > sizeof(stats->data)/sizeof(stats->data[0])) 2413fe517fc9Smrg return -1; 241422944501Smrg 241522944501Smrg#define SET_VALUE \ 241622944501Smrg stats->data[i].long_format = "%-20.20s"; \ 241722944501Smrg stats->data[i].rate_format = "%8.8s"; \ 241822944501Smrg stats->data[i].isvalue = 1; \ 241922944501Smrg stats->data[i].verbose = 0 242022944501Smrg 242122944501Smrg#define SET_COUNT \ 242222944501Smrg stats->data[i].long_format = "%-20.20s"; \ 242322944501Smrg stats->data[i].rate_format = "%5.5s"; \ 242422944501Smrg stats->data[i].isvalue = 0; \ 242522944501Smrg stats->data[i].mult_names = "kgm"; \ 242622944501Smrg stats->data[i].mult = 1000; \ 242722944501Smrg stats->data[i].verbose = 0 242822944501Smrg 242922944501Smrg#define SET_BYTE \ 243022944501Smrg stats->data[i].long_format = "%-20.20s"; \ 243122944501Smrg stats->data[i].rate_format = "%5.5s"; \ 243222944501Smrg stats->data[i].isvalue = 0; \ 243322944501Smrg stats->data[i].mult_names = "KGM"; \ 243422944501Smrg stats->data[i].mult = 1024; \ 243522944501Smrg stats->data[i].verbose = 0 243622944501Smrg 243722944501Smrg 243822944501Smrg stats->count = s.count; 243922944501Smrg for (i = 0; i < s.count; i++) { 2440fe517fc9Smrg stats->data[i].value = s.data[i].value; 2441fe517fc9Smrg switch (s.data[i].type) { 2442fe517fc9Smrg case _DRM_STAT_LOCK: 2443fe517fc9Smrg stats->data[i].long_name = "Lock"; 2444fe517fc9Smrg stats->data[i].rate_name = "Lock"; 2445fe517fc9Smrg SET_VALUE; 2446fe517fc9Smrg break; 2447fe517fc9Smrg case _DRM_STAT_OPENS: 2448fe517fc9Smrg stats->data[i].long_name = "Opens"; 2449fe517fc9Smrg stats->data[i].rate_name = "O"; 2450fe517fc9Smrg SET_COUNT; 2451fe517fc9Smrg stats->data[i].verbose = 1; 2452fe517fc9Smrg break; 2453fe517fc9Smrg case _DRM_STAT_CLOSES: 2454fe517fc9Smrg stats->data[i].long_name = "Closes"; 2455fe517fc9Smrg stats->data[i].rate_name = "Lock"; 2456fe517fc9Smrg SET_COUNT; 2457fe517fc9Smrg stats->data[i].verbose = 1; 2458fe517fc9Smrg break; 2459fe517fc9Smrg case _DRM_STAT_IOCTLS: 2460fe517fc9Smrg stats->data[i].long_name = "Ioctls"; 2461fe517fc9Smrg stats->data[i].rate_name = "Ioc/s"; 2462fe517fc9Smrg SET_COUNT; 2463fe517fc9Smrg break; 2464fe517fc9Smrg case _DRM_STAT_LOCKS: 2465fe517fc9Smrg stats->data[i].long_name = "Locks"; 2466fe517fc9Smrg stats->data[i].rate_name = "Lck/s"; 2467fe517fc9Smrg SET_COUNT; 2468fe517fc9Smrg break; 2469fe517fc9Smrg case _DRM_STAT_UNLOCKS: 2470fe517fc9Smrg stats->data[i].long_name = "Unlocks"; 2471fe517fc9Smrg stats->data[i].rate_name = "Unl/s"; 2472fe517fc9Smrg SET_COUNT; 2473fe517fc9Smrg break; 2474fe517fc9Smrg case _DRM_STAT_IRQ: 2475fe517fc9Smrg stats->data[i].long_name = "IRQs"; 2476fe517fc9Smrg stats->data[i].rate_name = "IRQ/s"; 2477fe517fc9Smrg SET_COUNT; 2478fe517fc9Smrg break; 2479fe517fc9Smrg case _DRM_STAT_PRIMARY: 2480fe517fc9Smrg stats->data[i].long_name = "Primary Bytes"; 2481fe517fc9Smrg stats->data[i].rate_name = "PB/s"; 2482fe517fc9Smrg SET_BYTE; 2483fe517fc9Smrg break; 2484fe517fc9Smrg case _DRM_STAT_SECONDARY: 2485fe517fc9Smrg stats->data[i].long_name = "Secondary Bytes"; 2486fe517fc9Smrg stats->data[i].rate_name = "SB/s"; 2487fe517fc9Smrg SET_BYTE; 2488fe517fc9Smrg break; 2489fe517fc9Smrg case _DRM_STAT_DMA: 2490fe517fc9Smrg stats->data[i].long_name = "DMA"; 2491fe517fc9Smrg stats->data[i].rate_name = "DMA/s"; 2492fe517fc9Smrg SET_COUNT; 2493fe517fc9Smrg break; 2494fe517fc9Smrg case _DRM_STAT_SPECIAL: 2495fe517fc9Smrg stats->data[i].long_name = "Special DMA"; 2496fe517fc9Smrg stats->data[i].rate_name = "dma/s"; 2497fe517fc9Smrg SET_COUNT; 2498fe517fc9Smrg break; 2499fe517fc9Smrg case _DRM_STAT_MISSED: 2500fe517fc9Smrg stats->data[i].long_name = "Miss"; 2501fe517fc9Smrg stats->data[i].rate_name = "Ms/s"; 2502fe517fc9Smrg SET_COUNT; 2503fe517fc9Smrg break; 2504fe517fc9Smrg case _DRM_STAT_VALUE: 2505fe517fc9Smrg stats->data[i].long_name = "Value"; 2506fe517fc9Smrg stats->data[i].rate_name = "Value"; 2507fe517fc9Smrg SET_VALUE; 2508fe517fc9Smrg break; 2509fe517fc9Smrg case _DRM_STAT_BYTE: 2510fe517fc9Smrg stats->data[i].long_name = "Bytes"; 2511fe517fc9Smrg stats->data[i].rate_name = "B/s"; 2512fe517fc9Smrg SET_BYTE; 2513fe517fc9Smrg break; 2514fe517fc9Smrg case _DRM_STAT_COUNT: 2515fe517fc9Smrg default: 2516fe517fc9Smrg stats->data[i].long_name = "Count"; 2517fe517fc9Smrg stats->data[i].rate_name = "Cnt/s"; 2518fe517fc9Smrg SET_COUNT; 2519fe517fc9Smrg break; 2520fe517fc9Smrg } 252122944501Smrg } 252222944501Smrg return 0; 252322944501Smrg} 252422944501Smrg 252522944501Smrg/** 252622944501Smrg * Issue a set-version ioctl. 252722944501Smrg * 252822944501Smrg * \param fd file descriptor. 2529fe517fc9Smrg * \param drmCommandIndex command index 253022944501Smrg * \param data source pointer of the data to be read and written. 253122944501Smrg * \param size size of the data to be read and written. 2532fe517fc9Smrg * 253322944501Smrg * \return zero on success, or a negative value on failure. 2534fe517fc9Smrg * 253522944501Smrg * \internal 2536fe517fc9Smrg * It issues a read-write ioctl given by 253722944501Smrg * \code DRM_COMMAND_BASE + drmCommandIndex \endcode. 253822944501Smrg */ 25396260e5d5Smrgdrm_public int drmSetInterfaceVersion(int fd, drmSetVersion *version) 254022944501Smrg{ 254122944501Smrg int retcode = 0; 254222944501Smrg drm_set_version_t sv; 254322944501Smrg 2544424e9256Smrg memclear(sv); 254522944501Smrg sv.drm_di_major = version->drm_di_major; 254622944501Smrg sv.drm_di_minor = version->drm_di_minor; 254722944501Smrg sv.drm_dd_major = version->drm_dd_major; 254822944501Smrg sv.drm_dd_minor = version->drm_dd_minor; 254922944501Smrg 255022944501Smrg if (drmIoctl(fd, DRM_IOCTL_SET_VERSION, &sv)) { 2551fe517fc9Smrg retcode = -errno; 255222944501Smrg } 255322944501Smrg 255422944501Smrg version->drm_di_major = sv.drm_di_major; 255522944501Smrg version->drm_di_minor = sv.drm_di_minor; 255622944501Smrg version->drm_dd_major = sv.drm_dd_major; 255722944501Smrg version->drm_dd_minor = sv.drm_dd_minor; 255822944501Smrg 255922944501Smrg return retcode; 256022944501Smrg} 256122944501Smrg 256222944501Smrg/** 256322944501Smrg * Send a device-specific command. 256422944501Smrg * 256522944501Smrg * \param fd file descriptor. 2566fe517fc9Smrg * \param drmCommandIndex command index 2567fe517fc9Smrg * 256822944501Smrg * \return zero on success, or a negative value on failure. 2569fe517fc9Smrg * 257022944501Smrg * \internal 2571fe517fc9Smrg * It issues a ioctl given by 257222944501Smrg * \code DRM_COMMAND_BASE + drmCommandIndex \endcode. 257322944501Smrg */ 25746260e5d5Smrgdrm_public int drmCommandNone(int fd, unsigned long drmCommandIndex) 257522944501Smrg{ 257622944501Smrg unsigned long request; 257722944501Smrg 257822944501Smrg request = DRM_IO( DRM_COMMAND_BASE + drmCommandIndex); 257922944501Smrg 2580424e9256Smrg if (drmIoctl(fd, request, NULL)) { 2581fe517fc9Smrg return -errno; 258222944501Smrg } 258322944501Smrg return 0; 258422944501Smrg} 258522944501Smrg 258622944501Smrg 258722944501Smrg/** 258822944501Smrg * Send a device-specific read command. 258922944501Smrg * 259022944501Smrg * \param fd file descriptor. 2591fe517fc9Smrg * \param drmCommandIndex command index 259222944501Smrg * \param data destination pointer of the data to be read. 259322944501Smrg * \param size size of the data to be read. 2594fe517fc9Smrg * 259522944501Smrg * \return zero on success, or a negative value on failure. 259622944501Smrg * 259722944501Smrg * \internal 2598fe517fc9Smrg * It issues a read ioctl given by 259922944501Smrg * \code DRM_COMMAND_BASE + drmCommandIndex \endcode. 260022944501Smrg */ 26016260e5d5Smrgdrm_public int drmCommandRead(int fd, unsigned long drmCommandIndex, 26026260e5d5Smrg void *data, unsigned long size) 260322944501Smrg{ 260422944501Smrg unsigned long request; 260522944501Smrg 2606fe517fc9Smrg request = DRM_IOC( DRM_IOC_READ, DRM_IOCTL_BASE, 2607fe517fc9Smrg DRM_COMMAND_BASE + drmCommandIndex, size); 260822944501Smrg 260922944501Smrg if (drmIoctl(fd, request, data)) { 2610fe517fc9Smrg return -errno; 261122944501Smrg } 261222944501Smrg return 0; 261322944501Smrg} 261422944501Smrg 261522944501Smrg 261622944501Smrg/** 261722944501Smrg * Send a device-specific write command. 261822944501Smrg * 261922944501Smrg * \param fd file descriptor. 2620fe517fc9Smrg * \param drmCommandIndex command index 262122944501Smrg * \param data source pointer of the data to be written. 262222944501Smrg * \param size size of the data to be written. 2623fe517fc9Smrg * 262422944501Smrg * \return zero on success, or a negative value on failure. 2625fe517fc9Smrg * 262622944501Smrg * \internal 2627fe517fc9Smrg * It issues a write ioctl given by 262822944501Smrg * \code DRM_COMMAND_BASE + drmCommandIndex \endcode. 262922944501Smrg */ 26306260e5d5Smrgdrm_public int drmCommandWrite(int fd, unsigned long drmCommandIndex, 26316260e5d5Smrg void *data, unsigned long size) 263222944501Smrg{ 263322944501Smrg unsigned long request; 263422944501Smrg 2635fe517fc9Smrg request = DRM_IOC( DRM_IOC_WRITE, DRM_IOCTL_BASE, 2636fe517fc9Smrg DRM_COMMAND_BASE + drmCommandIndex, size); 263722944501Smrg 263822944501Smrg if (drmIoctl(fd, request, data)) { 2639fe517fc9Smrg return -errno; 264022944501Smrg } 264122944501Smrg return 0; 264222944501Smrg} 264322944501Smrg 264422944501Smrg 264522944501Smrg/** 264622944501Smrg * Send a device-specific read-write command. 264722944501Smrg * 264822944501Smrg * \param fd file descriptor. 2649fe517fc9Smrg * \param drmCommandIndex command index 265022944501Smrg * \param data source pointer of the data to be read and written. 265122944501Smrg * \param size size of the data to be read and written. 2652fe517fc9Smrg * 265322944501Smrg * \return zero on success, or a negative value on failure. 2654fe517fc9Smrg * 265522944501Smrg * \internal 2656fe517fc9Smrg * It issues a read-write ioctl given by 265722944501Smrg * \code DRM_COMMAND_BASE + drmCommandIndex \endcode. 265822944501Smrg */ 26596260e5d5Smrgdrm_public int drmCommandWriteRead(int fd, unsigned long drmCommandIndex, 26606260e5d5Smrg void *data, unsigned long size) 266122944501Smrg{ 266222944501Smrg unsigned long request; 266322944501Smrg 2664fe517fc9Smrg request = DRM_IOC( DRM_IOC_READ|DRM_IOC_WRITE, DRM_IOCTL_BASE, 2665fe517fc9Smrg DRM_COMMAND_BASE + drmCommandIndex, size); 266622944501Smrg 266722944501Smrg if (drmIoctl(fd, request, data)) 2668fe517fc9Smrg return -errno; 266922944501Smrg return 0; 267022944501Smrg} 267122944501Smrg 267222944501Smrg#define DRM_MAX_FDS 16 267322944501Smrgstatic struct { 267422944501Smrg char *BusID; 267522944501Smrg int fd; 267622944501Smrg int refcount; 2677424e9256Smrg int type; 267822944501Smrg} connection[DRM_MAX_FDS]; 267922944501Smrg 268022944501Smrgstatic int nr_fds = 0; 268122944501Smrg 26826260e5d5Smrgdrm_public int drmOpenOnce(void *unused, const char *BusID, int *newlyopened) 2683424e9256Smrg{ 2684424e9256Smrg return drmOpenOnceWithType(BusID, newlyopened, DRM_NODE_PRIMARY); 2685424e9256Smrg} 2686424e9256Smrg 26876260e5d5Smrgdrm_public int drmOpenOnceWithType(const char *BusID, int *newlyopened, 26886260e5d5Smrg int type) 268922944501Smrg{ 269022944501Smrg int i; 269122944501Smrg int fd; 2692fe517fc9Smrg 269322944501Smrg for (i = 0; i < nr_fds; i++) 2694fe517fc9Smrg if ((strcmp(BusID, connection[i].BusID) == 0) && 2695fe517fc9Smrg (connection[i].type == type)) { 2696fe517fc9Smrg connection[i].refcount++; 2697fe517fc9Smrg *newlyopened = 0; 2698fe517fc9Smrg return connection[i].fd; 2699fe517fc9Smrg } 270022944501Smrg 2701424e9256Smrg fd = drmOpenWithType(NULL, BusID, type); 2702fe517fc9Smrg if (fd < 0 || nr_fds == DRM_MAX_FDS) 2703fe517fc9Smrg return fd; 2704fe517fc9Smrg 270522944501Smrg connection[nr_fds].BusID = strdup(BusID); 270622944501Smrg connection[nr_fds].fd = fd; 270722944501Smrg connection[nr_fds].refcount = 1; 2708424e9256Smrg connection[nr_fds].type = type; 270922944501Smrg *newlyopened = 1; 271022944501Smrg 271122944501Smrg if (0) 2712fe517fc9Smrg fprintf(stderr, "saved connection %d for %s %d\n", 2713fe517fc9Smrg nr_fds, connection[nr_fds].BusID, 2714fe517fc9Smrg strcmp(BusID, connection[nr_fds].BusID)); 271522944501Smrg 271622944501Smrg nr_fds++; 271722944501Smrg 271822944501Smrg return fd; 271922944501Smrg} 272022944501Smrg 27216260e5d5Smrgdrm_public void drmCloseOnce(int fd) 272222944501Smrg{ 272322944501Smrg int i; 272422944501Smrg 272522944501Smrg for (i = 0; i < nr_fds; i++) { 2726fe517fc9Smrg if (fd == connection[i].fd) { 2727fe517fc9Smrg if (--connection[i].refcount == 0) { 2728fe517fc9Smrg drmClose(connection[i].fd); 2729fe517fc9Smrg free(connection[i].BusID); 2730fe517fc9Smrg 2731fe517fc9Smrg if (i < --nr_fds) 2732fe517fc9Smrg connection[i] = connection[nr_fds]; 2733fe517fc9Smrg 2734fe517fc9Smrg return; 2735fe517fc9Smrg } 2736fe517fc9Smrg } 273722944501Smrg } 273822944501Smrg} 273922944501Smrg 27406260e5d5Smrgdrm_public int drmSetMaster(int fd) 274122944501Smrg{ 2742fe517fc9Smrg return drmIoctl(fd, DRM_IOCTL_SET_MASTER, NULL); 274322944501Smrg} 274422944501Smrg 27456260e5d5Smrgdrm_public int drmDropMaster(int fd) 274622944501Smrg{ 2747fe517fc9Smrg return drmIoctl(fd, DRM_IOCTL_DROP_MASTER, NULL); 274822944501Smrg} 274922944501Smrg 27506260e5d5Smrgdrm_public char *drmGetDeviceNameFromFd(int fd) 275122944501Smrg{ 2752fe517fc9Smrg char name[128]; 2753fe517fc9Smrg struct stat sbuf; 2754fe517fc9Smrg dev_t d; 2755fe517fc9Smrg int i; 275622944501Smrg 2757fe517fc9Smrg /* The whole drmOpen thing is a fiasco and we need to find a way 2758fe517fc9Smrg * back to just using open(2). For now, however, lets just make 2759fe517fc9Smrg * things worse with even more ad hoc directory walking code to 2760fe517fc9Smrg * discover the device file name. */ 276122944501Smrg 2762fe517fc9Smrg fstat(fd, &sbuf); 2763fe517fc9Smrg d = sbuf.st_rdev; 276422944501Smrg 2765fe517fc9Smrg for (i = 0; i < DRM_MAX_MINOR; i++) { 2766fe517fc9Smrg snprintf(name, sizeof name, DRM_DEV_NAME, DRM_DIR_NAME, i); 2767fe517fc9Smrg if (stat(name, &sbuf) == 0 && sbuf.st_rdev == d) 2768fe517fc9Smrg break; 2769fe517fc9Smrg } 2770fe517fc9Smrg if (i == DRM_MAX_MINOR) 2771fe517fc9Smrg return NULL; 277222944501Smrg 2773fe517fc9Smrg return strdup(name); 277422944501Smrg} 277520131375Smrg 27766260e5d5Smrgstatic bool drmNodeIsDRM(int maj, int min) 27776260e5d5Smrg{ 27786260e5d5Smrg#ifdef __linux__ 27796260e5d5Smrg char path[64]; 27806260e5d5Smrg struct stat sbuf; 27816260e5d5Smrg 27826260e5d5Smrg snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device/drm", 27836260e5d5Smrg maj, min); 27846260e5d5Smrg return stat(path, &sbuf) == 0; 27856260e5d5Smrg#else 27866260e5d5Smrg return maj == DRM_MAJOR; 27876260e5d5Smrg#endif 27886260e5d5Smrg} 27896260e5d5Smrg 27906260e5d5Smrgdrm_public int drmGetNodeTypeFromFd(int fd) 2791424e9256Smrg{ 2792fe517fc9Smrg struct stat sbuf; 2793fe517fc9Smrg int maj, min, type; 2794424e9256Smrg 2795fe517fc9Smrg if (fstat(fd, &sbuf)) 2796fe517fc9Smrg return -1; 2797424e9256Smrg 2798fe517fc9Smrg maj = major(sbuf.st_rdev); 2799fe517fc9Smrg min = minor(sbuf.st_rdev); 2800424e9256Smrg 28016260e5d5Smrg if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode)) { 2802fe517fc9Smrg errno = EINVAL; 2803fe517fc9Smrg return -1; 2804fe517fc9Smrg } 2805424e9256Smrg 2806fe517fc9Smrg type = drmGetMinorType(min); 2807fe517fc9Smrg if (type == -1) 2808fe517fc9Smrg errno = ENODEV; 2809fe517fc9Smrg return type; 2810424e9256Smrg} 2811424e9256Smrg 28126260e5d5Smrgdrm_public int drmPrimeHandleToFD(int fd, uint32_t handle, uint32_t flags, 28136260e5d5Smrg int *prime_fd) 281420131375Smrg{ 2815fe517fc9Smrg struct drm_prime_handle args; 2816fe517fc9Smrg int ret; 281720131375Smrg 2818fe517fc9Smrg memclear(args); 2819fe517fc9Smrg args.fd = -1; 2820fe517fc9Smrg args.handle = handle; 2821fe517fc9Smrg args.flags = flags; 2822fe517fc9Smrg ret = drmIoctl(fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &args); 2823fe517fc9Smrg if (ret) 2824fe517fc9Smrg return ret; 282520131375Smrg 2826fe517fc9Smrg *prime_fd = args.fd; 2827fe517fc9Smrg return 0; 282820131375Smrg} 282920131375Smrg 28306260e5d5Smrgdrm_public int drmPrimeFDToHandle(int fd, int prime_fd, uint32_t *handle) 283120131375Smrg{ 2832fe517fc9Smrg struct drm_prime_handle args; 2833fe517fc9Smrg int ret; 283420131375Smrg 2835fe517fc9Smrg memclear(args); 2836fe517fc9Smrg args.fd = prime_fd; 2837fe517fc9Smrg ret = drmIoctl(fd, DRM_IOCTL_PRIME_FD_TO_HANDLE, &args); 2838fe517fc9Smrg if (ret) 2839fe517fc9Smrg return ret; 284020131375Smrg 2841fe517fc9Smrg *handle = args.handle; 2842fe517fc9Smrg return 0; 284320131375Smrg} 2844424e9256Smrg 2845424e9256Smrgstatic char *drmGetMinorNameForFD(int fd, int type) 2846424e9256Smrg{ 2847424e9256Smrg#ifdef __linux__ 2848fe517fc9Smrg DIR *sysdir; 28496260e5d5Smrg struct dirent *ent; 2850fe517fc9Smrg struct stat sbuf; 2851fe517fc9Smrg const char *name = drmGetMinorName(type); 2852fe517fc9Smrg int len; 2853fe517fc9Smrg char dev_name[64], buf[64]; 2854fe517fc9Smrg int maj, min; 2855fe517fc9Smrg 2856fe517fc9Smrg if (!name) 2857fe517fc9Smrg return NULL; 2858424e9256Smrg 2859fe517fc9Smrg len = strlen(name); 2860424e9256Smrg 2861fe517fc9Smrg if (fstat(fd, &sbuf)) 2862fe517fc9Smrg return NULL; 2863424e9256Smrg 2864fe517fc9Smrg maj = major(sbuf.st_rdev); 2865fe517fc9Smrg min = minor(sbuf.st_rdev); 2866424e9256Smrg 28676260e5d5Smrg if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode)) 2868fe517fc9Smrg return NULL; 2869424e9256Smrg 2870fe517fc9Smrg snprintf(buf, sizeof(buf), "/sys/dev/char/%d:%d/device/drm", maj, min); 2871424e9256Smrg 2872fe517fc9Smrg sysdir = opendir(buf); 2873fe517fc9Smrg if (!sysdir) 2874fe517fc9Smrg return NULL; 2875424e9256Smrg 28766260e5d5Smrg while ((ent = readdir(sysdir))) { 2877fe517fc9Smrg if (strncmp(ent->d_name, name, len) == 0) { 2878fe517fc9Smrg snprintf(dev_name, sizeof(dev_name), DRM_DIR_NAME "/%s", 2879fe517fc9Smrg ent->d_name); 2880424e9256Smrg 2881fe517fc9Smrg closedir(sysdir); 2882fe517fc9Smrg return strdup(dev_name); 2883fe517fc9Smrg } 2884fe517fc9Smrg } 2885424e9256Smrg 2886fe517fc9Smrg closedir(sysdir); 28876260e5d5Smrg return NULL; 2888fe517fc9Smrg#else 28892ee35494Smrg struct stat sbuf; 28902ee35494Smrg char buf[PATH_MAX + 1]; 28912ee35494Smrg const char *dev_name; 28922ee35494Smrg unsigned int maj, min; 28932ee35494Smrg int n, base; 28942ee35494Smrg 28952ee35494Smrg if (fstat(fd, &sbuf)) 28962ee35494Smrg return NULL; 28972ee35494Smrg 28982ee35494Smrg maj = major(sbuf.st_rdev); 28992ee35494Smrg min = minor(sbuf.st_rdev); 29002ee35494Smrg 29016260e5d5Smrg if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode)) 29022ee35494Smrg return NULL; 29032ee35494Smrg 29042ee35494Smrg switch (type) { 29052ee35494Smrg case DRM_NODE_PRIMARY: 29062ee35494Smrg dev_name = DRM_DEV_NAME; 29072ee35494Smrg break; 29082ee35494Smrg case DRM_NODE_CONTROL: 29092ee35494Smrg dev_name = DRM_CONTROL_DEV_NAME; 29102ee35494Smrg break; 29112ee35494Smrg case DRM_NODE_RENDER: 29122ee35494Smrg dev_name = DRM_RENDER_DEV_NAME; 29132ee35494Smrg break; 29142ee35494Smrg default: 29152ee35494Smrg return NULL; 29162ee35494Smrg }; 29172ee35494Smrg 29182ee35494Smrg base = drmGetMinorBase(type); 29192ee35494Smrg if (base < 0) 29202ee35494Smrg return NULL; 29212ee35494Smrg 29222ee35494Smrg n = snprintf(buf, sizeof(buf), dev_name, DRM_DIR_NAME, min - base); 29232ee35494Smrg if (n == -1 || n >= sizeof(buf)) 29242ee35494Smrg return NULL; 29252ee35494Smrg 29262ee35494Smrg return strdup(buf); 2927424e9256Smrg#endif 2928424e9256Smrg} 2929424e9256Smrg 29306260e5d5Smrgdrm_public char *drmGetPrimaryDeviceNameFromFd(int fd) 2931424e9256Smrg{ 2932fe517fc9Smrg return drmGetMinorNameForFD(fd, DRM_NODE_PRIMARY); 2933424e9256Smrg} 2934424e9256Smrg 29356260e5d5Smrgdrm_public char *drmGetRenderDeviceNameFromFd(int fd) 2936424e9256Smrg{ 2937fe517fc9Smrg return drmGetMinorNameForFD(fd, DRM_NODE_RENDER); 2938fe517fc9Smrg} 2939fe517fc9Smrg 29402ee35494Smrg#ifdef __linux__ 29412ee35494Smrgstatic char * DRM_PRINTFLIKE(2, 3) 29422ee35494Smrgsysfs_uevent_get(const char *path, const char *fmt, ...) 29432ee35494Smrg{ 29442ee35494Smrg char filename[PATH_MAX + 1], *key, *line = NULL, *value = NULL; 29452ee35494Smrg size_t size = 0, len; 29462ee35494Smrg ssize_t num; 29472ee35494Smrg va_list ap; 29482ee35494Smrg FILE *fp; 29492ee35494Smrg 29502ee35494Smrg va_start(ap, fmt); 29512ee35494Smrg num = vasprintf(&key, fmt, ap); 29522ee35494Smrg va_end(ap); 29532ee35494Smrg len = num; 29542ee35494Smrg 29552ee35494Smrg snprintf(filename, sizeof(filename), "%s/uevent", path); 29562ee35494Smrg 29572ee35494Smrg fp = fopen(filename, "r"); 29582ee35494Smrg if (!fp) { 29592ee35494Smrg free(key); 29602ee35494Smrg return NULL; 29612ee35494Smrg } 29622ee35494Smrg 29632ee35494Smrg while ((num = getline(&line, &size, fp)) >= 0) { 29642ee35494Smrg if ((strncmp(line, key, len) == 0) && (line[len] == '=')) { 29652ee35494Smrg char *start = line + len + 1, *end = line + num - 1; 29662ee35494Smrg 29672ee35494Smrg if (*end != '\n') 29682ee35494Smrg end++; 29692ee35494Smrg 29702ee35494Smrg value = strndup(start, end - start); 29712ee35494Smrg break; 29722ee35494Smrg } 29732ee35494Smrg } 29742ee35494Smrg 29752ee35494Smrg free(line); 29762ee35494Smrg fclose(fp); 29772ee35494Smrg 29782ee35494Smrg free(key); 29792ee35494Smrg 29802ee35494Smrg return value; 29812ee35494Smrg} 29822ee35494Smrg#endif 29832ee35494Smrg 29846260e5d5Smrg/* Little white lie to avoid major rework of the existing code */ 29856260e5d5Smrg#define DRM_BUS_VIRTIO 0x10 29866260e5d5Smrg 2987fe517fc9Smrgstatic int drmParseSubsystemType(int maj, int min) 2988fe517fc9Smrg{ 2989fe517fc9Smrg#ifdef __linux__ 2990fe517fc9Smrg char path[PATH_MAX + 1]; 2991fe517fc9Smrg char link[PATH_MAX + 1] = ""; 2992fe517fc9Smrg char *name; 29934545e80cSmrg struct { 29944545e80cSmrg const char *name; 29954545e80cSmrg int bus_type; 29964545e80cSmrg } bus_types[] = { 29974545e80cSmrg { "/pci", DRM_BUS_PCI }, 29984545e80cSmrg { "/usb", DRM_BUS_USB }, 29994545e80cSmrg { "/platform", DRM_BUS_PLATFORM }, 30004545e80cSmrg { "/spi", DRM_BUS_PLATFORM }, 30014545e80cSmrg { "/host1x", DRM_BUS_HOST1X }, 30024545e80cSmrg { "/virtio", DRM_BUS_VIRTIO }, 30034545e80cSmrg }; 3004fe517fc9Smrg 3005fe517fc9Smrg snprintf(path, PATH_MAX, "/sys/dev/char/%d:%d/device/subsystem", 3006fe517fc9Smrg maj, min); 3007fe517fc9Smrg 3008fe517fc9Smrg if (readlink(path, link, PATH_MAX) < 0) 3009fe517fc9Smrg return -errno; 3010fe517fc9Smrg 3011fe517fc9Smrg name = strrchr(link, '/'); 3012fe517fc9Smrg if (!name) 3013fe517fc9Smrg return -EINVAL; 3014fe517fc9Smrg 30154545e80cSmrg for (unsigned i = 0; i < ARRAY_SIZE(bus_types); i++) { 30164545e80cSmrg if (strncmp(name, bus_types[i].name, strlen(bus_types[i].name)) == 0) 30174545e80cSmrg return bus_types[i].bus_type; 30184545e80cSmrg } 30196260e5d5Smrg 3020fe517fc9Smrg return -EINVAL; 3021a970b457Sriastradh#elif defined(__NetBSD__) 3022a970b457Sriastradh int type, fd; 3023a970b457Sriastradh drmSetVersion sv; 3024a970b457Sriastradh char *buf; 3025a970b457Sriastradh unsigned domain, bus, dev; 3026a970b457Sriastradh int func; 3027a970b457Sriastradh int ret; 3028a970b457Sriastradh 3029a970b457Sriastradh /* Get the type of device we're looking for to pick the right pathname. */ 3030a970b457Sriastradh type = drmGetMinorType(min); 3031a970b457Sriastradh if (type == -1) 3032a970b457Sriastradh return -ENODEV; 3033a970b457Sriastradh 3034a970b457Sriastradh /* Open the device. Don't try to create it if it's not there. */ 3035a970b457Sriastradh fd = drmOpenMinor(min, 0, type); 3036a970b457Sriastradh if (fd < 0) 3037a970b457Sriastradh return -errno; 3038a970b457Sriastradh 3039a970b457Sriastradh /* 3040a970b457Sriastradh * Set the interface version to 1.4 or 1.1, which has the effect of 3041a970b457Sriastradh * populating the bus id for us. 3042a970b457Sriastradh */ 3043a970b457Sriastradh sv.drm_di_major = 1; 3044a970b457Sriastradh sv.drm_di_minor = 4; 3045a970b457Sriastradh sv.drm_dd_major = -1; 3046a970b457Sriastradh sv.drm_dd_minor = -1; 3047a970b457Sriastradh if (drmSetInterfaceVersion(fd, &sv)) { 3048a970b457Sriastradh sv.drm_di_major = 1; 3049a970b457Sriastradh sv.drm_di_minor = 1; 3050a970b457Sriastradh sv.drm_dd_major = -1; 3051a970b457Sriastradh sv.drm_dd_minor = -1; 3052a970b457Sriastradh if (drmSetInterfaceVersion(fd, &sv)) { 30535046d36bSriastradh /* 30545046d36bSriastradh * We're probably not the master. Hope the master already 30555046d36bSriastradh * set the version to >=1.1 so that we can get the busid. 30565046d36bSriastradh */ 3057a970b457Sriastradh } 3058a970b457Sriastradh } 3059a970b457Sriastradh 3060a970b457Sriastradh /* Get the bus id. */ 3061a970b457Sriastradh buf = drmGetBusid(fd); 3062a970b457Sriastradh 3063a970b457Sriastradh /* We're done with the device now. */ 3064a970b457Sriastradh (void)close(fd); 3065a970b457Sriastradh 3066a970b457Sriastradh /* If there is no bus id, fail. */ 3067a970b457Sriastradh if (buf == NULL) 3068a970b457Sriastradh return -ENODEV; 3069a970b457Sriastradh 3070a970b457Sriastradh /* Find a string we know about; otherwise -EINVAL. */ 3071a970b457Sriastradh ret = -EINVAL; 307248994cb0Sriastradh if (strncmp(buf, "pci:", 4) == 0) 3073a970b457Sriastradh ret = DRM_BUS_PCI; 3074a970b457Sriastradh 3075a970b457Sriastradh /* We're done with the bus id. */ 3076a970b457Sriastradh free(buf); 3077a970b457Sriastradh 3078a970b457Sriastradh /* Success or not, we're done. */ 3079a970b457Sriastradh return ret; 30804545e80cSmrg#elif defined(__OpenBSD__) || defined(__DragonFly__) 30812ee35494Smrg return DRM_BUS_PCI; 3082fe517fc9Smrg#else 3083fe517fc9Smrg#warning "Missing implementation of drmParseSubsystemType" 3084fe517fc9Smrg return -EINVAL; 3085fe517fc9Smrg#endif 3086fe517fc9Smrg} 3087fe517fc9Smrg 30886260e5d5Smrgstatic void 30896260e5d5Smrgget_pci_path(int maj, int min, char *pci_path) 30906260e5d5Smrg{ 30916260e5d5Smrg char path[PATH_MAX + 1], *term; 30926260e5d5Smrg 30936260e5d5Smrg snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min); 30946260e5d5Smrg if (!realpath(path, pci_path)) { 30956260e5d5Smrg strcpy(pci_path, path); 30966260e5d5Smrg return; 30976260e5d5Smrg } 30986260e5d5Smrg 30996260e5d5Smrg term = strrchr(pci_path, '/'); 31006260e5d5Smrg if (term && strncmp(term, "/virtio", 7) == 0) 31016260e5d5Smrg *term = 0; 31026260e5d5Smrg} 31036260e5d5Smrg 3104fe517fc9Smrgstatic int drmParsePciBusInfo(int maj, int min, drmPciBusInfoPtr info) 3105fe517fc9Smrg{ 3106fe517fc9Smrg#ifdef __linux__ 31072ee35494Smrg unsigned int domain, bus, dev, func; 31086260e5d5Smrg char pci_path[PATH_MAX + 1], *value; 31092ee35494Smrg int num; 3110fe517fc9Smrg 31116260e5d5Smrg get_pci_path(maj, min, pci_path); 3112fe517fc9Smrg 31136260e5d5Smrg value = sysfs_uevent_get(pci_path, "PCI_SLOT_NAME"); 31142ee35494Smrg if (!value) 31152ee35494Smrg return -ENOENT; 3116fe517fc9Smrg 31172ee35494Smrg num = sscanf(value, "%04x:%02x:%02x.%1u", &domain, &bus, &dev, &func); 31182ee35494Smrg free(value); 3119fe517fc9Smrg 31202ee35494Smrg if (num != 4) 3121fe517fc9Smrg return -EINVAL; 3122fe517fc9Smrg 3123fe517fc9Smrg info->domain = domain; 3124fe517fc9Smrg info->bus = bus; 3125fe517fc9Smrg info->dev = dev; 3126fe517fc9Smrg info->func = func; 3127fe517fc9Smrg 3128a970b457Sriastradh return 0; 3129a970b457Sriastradh#elif defined(__NetBSD__) 3130a970b457Sriastradh int type, fd; 3131a970b457Sriastradh drmSetVersion sv; 3132a970b457Sriastradh char *buf; 3133a970b457Sriastradh unsigned domain, bus, dev; 3134a970b457Sriastradh int func; 3135a970b457Sriastradh int ret; 3136a970b457Sriastradh 3137a970b457Sriastradh /* Get the type of device we're looking for to pick the right pathname. */ 3138a970b457Sriastradh type = drmGetMinorType(min); 3139a970b457Sriastradh if (type == -1) 3140a970b457Sriastradh return -ENODEV; 3141a970b457Sriastradh 3142a970b457Sriastradh /* Open the device. Don't try to create it if it's not there. */ 3143a970b457Sriastradh fd = drmOpenMinor(min, 0, type); 3144a970b457Sriastradh if (fd < 0) 3145a970b457Sriastradh return -errno; 3146a970b457Sriastradh 3147a970b457Sriastradh /* 3148a970b457Sriastradh * Set the interface version to 1.4 or 1.1, which has the effect of 3149a970b457Sriastradh * populating the bus id for us. 3150a970b457Sriastradh */ 3151a970b457Sriastradh sv.drm_di_major = 1; 3152a970b457Sriastradh sv.drm_di_minor = 4; 3153a970b457Sriastradh sv.drm_dd_major = -1; 3154a970b457Sriastradh sv.drm_dd_minor = -1; 3155a970b457Sriastradh if (drmSetInterfaceVersion(fd, &sv)) { 3156a970b457Sriastradh sv.drm_di_major = 1; 3157a970b457Sriastradh sv.drm_di_minor = 1; 3158a970b457Sriastradh sv.drm_dd_major = -1; 3159a970b457Sriastradh sv.drm_dd_minor = -1; 3160a970b457Sriastradh if (drmSetInterfaceVersion(fd, &sv)) { 316106815bcbSmaya /* 316206815bcbSmaya * We're probably not the master. Hope the master already 316306815bcbSmaya * set the version to >=1.1 so that we can get the busid. 316406815bcbSmaya */ 3165a970b457Sriastradh } 3166a970b457Sriastradh } 3167a970b457Sriastradh 3168a970b457Sriastradh /* Get the bus id. */ 3169a970b457Sriastradh buf = drmGetBusid(fd); 3170a970b457Sriastradh 3171a970b457Sriastradh /* We're done with the device now. */ 3172a970b457Sriastradh (void)close(fd); 3173a970b457Sriastradh 3174a970b457Sriastradh /* If there is no bus id, fail. */ 3175a970b457Sriastradh if (buf == NULL) 3176a970b457Sriastradh return -ENODEV; 3177a970b457Sriastradh 3178a970b457Sriastradh /* Parse the bus id. */ 3179a970b457Sriastradh ret = sscanf(buf, "pci:%04x:%02x:%02x.%d", &domain, &bus, &dev, &func); 3180a970b457Sriastradh 3181a970b457Sriastradh /* We're done with the bus id. */ 3182a970b457Sriastradh free(buf); 3183a970b457Sriastradh 3184a970b457Sriastradh /* If scanf didn't return 4 -- domain, bus, dev, func -- then fail. */ 3185a970b457Sriastradh if (ret != 4) 3186a970b457Sriastradh return -ENODEV; 3187a970b457Sriastradh 3188a970b457Sriastradh /* Populate the results. */ 3189a970b457Sriastradh info->domain = domain; 3190a970b457Sriastradh info->bus = bus; 3191a970b457Sriastradh info->dev = dev; 3192a970b457Sriastradh info->func = func; 3193a970b457Sriastradh 3194a970b457Sriastradh /* Success! */ 31952ee35494Smrg return 0; 31964545e80cSmrg#elif defined(__OpenBSD__) || defined(__DragonFly__) 31972ee35494Smrg struct drm_pciinfo pinfo; 31982ee35494Smrg int fd, type; 31992ee35494Smrg 32002ee35494Smrg type = drmGetMinorType(min); 32012ee35494Smrg if (type == -1) 32022ee35494Smrg return -ENODEV; 32032ee35494Smrg 32042ee35494Smrg fd = drmOpenMinor(min, 0, type); 32052ee35494Smrg if (fd < 0) 32062ee35494Smrg return -errno; 32072ee35494Smrg 32082ee35494Smrg if (drmIoctl(fd, DRM_IOCTL_GET_PCIINFO, &pinfo)) { 32092ee35494Smrg close(fd); 32102ee35494Smrg return -errno; 32112ee35494Smrg } 32122ee35494Smrg close(fd); 32132ee35494Smrg 32142ee35494Smrg info->domain = pinfo.domain; 32152ee35494Smrg info->bus = pinfo.bus; 32162ee35494Smrg info->dev = pinfo.dev; 32172ee35494Smrg info->func = pinfo.func; 32182ee35494Smrg 3219fe517fc9Smrg return 0; 3220fe517fc9Smrg#else 3221fe517fc9Smrg#warning "Missing implementation of drmParsePciBusInfo" 3222fe517fc9Smrg return -EINVAL; 3223fe517fc9Smrg#endif 3224fe517fc9Smrg} 3225fe517fc9Smrg 32266260e5d5Smrgdrm_public int drmDevicesEqual(drmDevicePtr a, drmDevicePtr b) 3227fe517fc9Smrg{ 3228fe517fc9Smrg if (a == NULL || b == NULL) 32290655efefSmrg return 0; 3230fe517fc9Smrg 3231fe517fc9Smrg if (a->bustype != b->bustype) 32320655efefSmrg return 0; 3233fe517fc9Smrg 3234fe517fc9Smrg switch (a->bustype) { 3235fe517fc9Smrg case DRM_BUS_PCI: 32360655efefSmrg return memcmp(a->businfo.pci, b->businfo.pci, sizeof(drmPciBusInfo)) == 0; 32372ee35494Smrg 32382ee35494Smrg case DRM_BUS_USB: 32390655efefSmrg return memcmp(a->businfo.usb, b->businfo.usb, sizeof(drmUsbBusInfo)) == 0; 32402ee35494Smrg 32412ee35494Smrg case DRM_BUS_PLATFORM: 32420655efefSmrg return memcmp(a->businfo.platform, b->businfo.platform, sizeof(drmPlatformBusInfo)) == 0; 32432ee35494Smrg 32442ee35494Smrg case DRM_BUS_HOST1X: 32450655efefSmrg return memcmp(a->businfo.host1x, b->businfo.host1x, sizeof(drmHost1xBusInfo)) == 0; 32462ee35494Smrg 3247fe517fc9Smrg default: 3248fe517fc9Smrg break; 3249fe517fc9Smrg } 3250fe517fc9Smrg 32510655efefSmrg return 0; 3252fe517fc9Smrg} 3253fe517fc9Smrg 3254fe517fc9Smrgstatic int drmGetNodeType(const char *name) 3255fe517fc9Smrg{ 3256fe517fc9Smrg if (strncmp(name, DRM_PRIMARY_MINOR_NAME, 3257fe517fc9Smrg sizeof(DRM_PRIMARY_MINOR_NAME) - 1) == 0) 3258fe517fc9Smrg return DRM_NODE_PRIMARY; 3259fe517fc9Smrg 3260fe517fc9Smrg if (strncmp(name, DRM_CONTROL_MINOR_NAME, 3261fe517fc9Smrg sizeof(DRM_CONTROL_MINOR_NAME ) - 1) == 0) 3262fe517fc9Smrg return DRM_NODE_CONTROL; 3263fe517fc9Smrg 3264fe517fc9Smrg if (strncmp(name, DRM_RENDER_MINOR_NAME, 3265fe517fc9Smrg sizeof(DRM_RENDER_MINOR_NAME) - 1) == 0) 3266fe517fc9Smrg return DRM_NODE_RENDER; 3267fe517fc9Smrg 3268fe517fc9Smrg return -EINVAL; 3269fe517fc9Smrg} 3270fe517fc9Smrg 3271fe517fc9Smrgstatic int drmGetMaxNodeName(void) 3272fe517fc9Smrg{ 3273fe517fc9Smrg return sizeof(DRM_DIR_NAME) + 3274fe517fc9Smrg MAX3(sizeof(DRM_PRIMARY_MINOR_NAME), 3275fe517fc9Smrg sizeof(DRM_CONTROL_MINOR_NAME), 3276fe517fc9Smrg sizeof(DRM_RENDER_MINOR_NAME)) + 3277fe517fc9Smrg 3 /* length of the node number */; 3278fe517fc9Smrg} 3279fe517fc9Smrg 3280fe517fc9Smrg#ifdef __linux__ 32812ee35494Smrgstatic int parse_separate_sysfs_files(int maj, int min, 32822ee35494Smrg drmPciDeviceInfoPtr device, 32832ee35494Smrg bool ignore_revision) 32842ee35494Smrg{ 32852ee35494Smrg static const char *attrs[] = { 32862ee35494Smrg "revision", /* Older kernels are missing the file, so check for it first */ 32872ee35494Smrg "vendor", 32882ee35494Smrg "device", 32892ee35494Smrg "subsystem_vendor", 32902ee35494Smrg "subsystem_device", 32912ee35494Smrg }; 32926260e5d5Smrg char path[PATH_MAX + 1], pci_path[PATH_MAX + 1]; 32932ee35494Smrg unsigned int data[ARRAY_SIZE(attrs)]; 32942ee35494Smrg FILE *fp; 32952ee35494Smrg int ret; 32962ee35494Smrg 32976260e5d5Smrg get_pci_path(maj, min, pci_path); 32986260e5d5Smrg 32992ee35494Smrg for (unsigned i = ignore_revision ? 1 : 0; i < ARRAY_SIZE(attrs); i++) { 33006260e5d5Smrg snprintf(path, PATH_MAX, "%s/%s", pci_path, attrs[i]); 33012ee35494Smrg fp = fopen(path, "r"); 33022ee35494Smrg if (!fp) 33032ee35494Smrg return -errno; 33042ee35494Smrg 33052ee35494Smrg ret = fscanf(fp, "%x", &data[i]); 33062ee35494Smrg fclose(fp); 33072ee35494Smrg if (ret != 1) 33082ee35494Smrg return -errno; 33092ee35494Smrg 33102ee35494Smrg } 33112ee35494Smrg 33122ee35494Smrg device->revision_id = ignore_revision ? 0xff : data[0] & 0xff; 33132ee35494Smrg device->vendor_id = data[1] & 0xffff; 33142ee35494Smrg device->device_id = data[2] & 0xffff; 33152ee35494Smrg device->subvendor_id = data[3] & 0xffff; 33162ee35494Smrg device->subdevice_id = data[4] & 0xffff; 33172ee35494Smrg 33182ee35494Smrg return 0; 33192ee35494Smrg} 33202ee35494Smrg 33212ee35494Smrgstatic int parse_config_sysfs_file(int maj, int min, 33222ee35494Smrg drmPciDeviceInfoPtr device) 33232ee35494Smrg{ 33246260e5d5Smrg char path[PATH_MAX + 1], pci_path[PATH_MAX + 1]; 3325fe517fc9Smrg unsigned char config[64]; 3326fe517fc9Smrg int fd, ret; 3327fe517fc9Smrg 33286260e5d5Smrg get_pci_path(maj, min, pci_path); 33296260e5d5Smrg 33306260e5d5Smrg snprintf(path, PATH_MAX, "%s/config", pci_path); 3331fe517fc9Smrg fd = open(path, O_RDONLY); 3332fe517fc9Smrg if (fd < 0) 3333fe517fc9Smrg return -errno; 3334fe517fc9Smrg 3335fe517fc9Smrg ret = read(fd, config, sizeof(config)); 3336fe517fc9Smrg close(fd); 3337fe517fc9Smrg if (ret < 0) 3338fe517fc9Smrg return -errno; 3339fe517fc9Smrg 3340fe517fc9Smrg device->vendor_id = config[0] | (config[1] << 8); 3341fe517fc9Smrg device->device_id = config[2] | (config[3] << 8); 3342fe517fc9Smrg device->revision_id = config[8]; 3343fe517fc9Smrg device->subvendor_id = config[44] | (config[45] << 8); 3344fe517fc9Smrg device->subdevice_id = config[46] | (config[47] << 8); 3345fe517fc9Smrg 33462ee35494Smrg return 0; 33472ee35494Smrg} 33482ee35494Smrg#endif 33492ee35494Smrg 33502ee35494Smrgstatic int drmParsePciDeviceInfo(int maj, int min, 33512ee35494Smrg drmPciDeviceInfoPtr device, 33522ee35494Smrg uint32_t flags) 33532ee35494Smrg{ 33542ee35494Smrg#ifdef __linux__ 33552ee35494Smrg if (!(flags & DRM_DEVICE_GET_PCI_REVISION)) 33562ee35494Smrg return parse_separate_sysfs_files(maj, min, device, true); 33572ee35494Smrg 33582ee35494Smrg if (parse_separate_sysfs_files(maj, min, device, false)) 33592ee35494Smrg return parse_config_sysfs_file(maj, min, device); 33602ee35494Smrg 33612ee35494Smrg return 0; 3362a970b457Sriastradh#elif defined(__NetBSD__) 3363a970b457Sriastradh drmPciBusInfo businfo; 3364a970b457Sriastradh char fname[PATH_MAX]; 3365a970b457Sriastradh int pcifd; 3366a970b457Sriastradh pcireg_t id, class, subsys; 3367a970b457Sriastradh int ret; 3368a970b457Sriastradh 3369a970b457Sriastradh /* Find where on the bus the device lives. */ 3370a970b457Sriastradh ret = drmParsePciBusInfo(maj, min, &businfo); 3371a970b457Sriastradh if (ret) 3372a970b457Sriastradh return ret; 3373a970b457Sriastradh 3374a970b457Sriastradh /* Open the pciN device node to get at its config registers. */ 3375a970b457Sriastradh if (snprintf(fname, sizeof fname, "/dev/pci%u", businfo.domain) 3376a970b457Sriastradh >= sizeof fname) 3377a970b457Sriastradh return -ENODEV; 3378a970b457Sriastradh if ((pcifd = open(fname, O_RDONLY)) == -1) 3379a970b457Sriastradh return -errno; 3380a970b457Sriastradh 3381f8b67707Schristos ret = -1; 3382a970b457Sriastradh /* Read the id and class pci config registers. */ 3383a970b457Sriastradh if (pcibus_conf_read(pcifd, businfo.bus, businfo.dev, businfo.func, 3384a970b457Sriastradh PCI_ID_REG, &id) == -1) 3385f8b67707Schristos goto out; 3386a970b457Sriastradh if (pcibus_conf_read(pcifd, businfo.bus, businfo.dev, businfo.func, 3387a970b457Sriastradh PCI_CLASS_REG, &class) == -1) 3388f8b67707Schristos goto out; 3389a970b457Sriastradh if (pcibus_conf_read(pcifd, businfo.bus, businfo.dev, businfo.func, 3390a970b457Sriastradh PCI_SUBSYS_ID_REG, &subsys) == -1) 3391f8b67707Schristos goto out; 3392a970b457Sriastradh 3393f8b67707Schristos ret = 0; 3394a970b457Sriastradh device->vendor_id = PCI_VENDOR(id); 3395a970b457Sriastradh device->device_id = PCI_PRODUCT(id); 3396a970b457Sriastradh device->subvendor_id = PCI_SUBSYS_VENDOR(subsys); 3397a970b457Sriastradh device->subdevice_id = PCI_SUBSYS_ID(subsys); 3398a970b457Sriastradh device->revision_id = PCI_REVISION(class); 3399f8b67707Schristosout: 3400f8b67707Schristos if (ret == -1) 3401f8b67707Schristos ret = -errno; 3402f8b67707Schristos close(pcifd); 3403f8b67707Schristos return ret; 34044545e80cSmrg#elif defined(__OpenBSD__) || defined(__DragonFly__) 34052ee35494Smrg struct drm_pciinfo pinfo; 34062ee35494Smrg int fd, type; 34072ee35494Smrg 34082ee35494Smrg type = drmGetMinorType(min); 34092ee35494Smrg if (type == -1) 34102ee35494Smrg return -ENODEV; 34112ee35494Smrg 34122ee35494Smrg fd = drmOpenMinor(min, 0, type); 34132ee35494Smrg if (fd < 0) 34142ee35494Smrg return -errno; 34152ee35494Smrg 34162ee35494Smrg if (drmIoctl(fd, DRM_IOCTL_GET_PCIINFO, &pinfo)) { 34172ee35494Smrg close(fd); 34182ee35494Smrg return -errno; 34192ee35494Smrg } 34202ee35494Smrg close(fd); 34212ee35494Smrg 34222ee35494Smrg device->vendor_id = pinfo.vendor_id; 34232ee35494Smrg device->device_id = pinfo.device_id; 34242ee35494Smrg device->revision_id = pinfo.revision_id; 34252ee35494Smrg device->subvendor_id = pinfo.subvendor_id; 34262ee35494Smrg device->subdevice_id = pinfo.subdevice_id; 34272ee35494Smrg 3428fe517fc9Smrg return 0; 3429fe517fc9Smrg#else 3430fe517fc9Smrg#warning "Missing implementation of drmParsePciDeviceInfo" 3431fe517fc9Smrg return -EINVAL; 3432fe517fc9Smrg#endif 3433fe517fc9Smrg} 3434fe517fc9Smrg 34352ee35494Smrgstatic void drmFreePlatformDevice(drmDevicePtr device) 34362ee35494Smrg{ 34372ee35494Smrg if (device->deviceinfo.platform) { 34382ee35494Smrg if (device->deviceinfo.platform->compatible) { 34392ee35494Smrg char **compatible = device->deviceinfo.platform->compatible; 34402ee35494Smrg 34412ee35494Smrg while (*compatible) { 34422ee35494Smrg free(*compatible); 34432ee35494Smrg compatible++; 34442ee35494Smrg } 34452ee35494Smrg 34462ee35494Smrg free(device->deviceinfo.platform->compatible); 34472ee35494Smrg } 34482ee35494Smrg } 34492ee35494Smrg} 34502ee35494Smrg 34512ee35494Smrgstatic void drmFreeHost1xDevice(drmDevicePtr device) 34522ee35494Smrg{ 34532ee35494Smrg if (device->deviceinfo.host1x) { 34542ee35494Smrg if (device->deviceinfo.host1x->compatible) { 34552ee35494Smrg char **compatible = device->deviceinfo.host1x->compatible; 34562ee35494Smrg 34572ee35494Smrg while (*compatible) { 34582ee35494Smrg free(*compatible); 34592ee35494Smrg compatible++; 34602ee35494Smrg } 34612ee35494Smrg 34622ee35494Smrg free(device->deviceinfo.host1x->compatible); 34632ee35494Smrg } 34642ee35494Smrg } 34652ee35494Smrg} 34662ee35494Smrg 34676260e5d5Smrgdrm_public void drmFreeDevice(drmDevicePtr *device) 3468fe517fc9Smrg{ 3469fe517fc9Smrg if (device == NULL) 3470fe517fc9Smrg return; 3471fe517fc9Smrg 34722ee35494Smrg if (*device) { 34732ee35494Smrg switch ((*device)->bustype) { 34742ee35494Smrg case DRM_BUS_PLATFORM: 34752ee35494Smrg drmFreePlatformDevice(*device); 34762ee35494Smrg break; 34772ee35494Smrg 34782ee35494Smrg case DRM_BUS_HOST1X: 34792ee35494Smrg drmFreeHost1xDevice(*device); 34802ee35494Smrg break; 34812ee35494Smrg } 34822ee35494Smrg } 34832ee35494Smrg 3484fe517fc9Smrg free(*device); 3485fe517fc9Smrg *device = NULL; 3486fe517fc9Smrg} 3487fe517fc9Smrg 34886260e5d5Smrgdrm_public void drmFreeDevices(drmDevicePtr devices[], int count) 3489fe517fc9Smrg{ 3490fe517fc9Smrg int i; 3491fe517fc9Smrg 3492fe517fc9Smrg if (devices == NULL) 3493fe517fc9Smrg return; 3494fe517fc9Smrg 3495fe517fc9Smrg for (i = 0; i < count; i++) 3496fe517fc9Smrg if (devices[i]) 3497fe517fc9Smrg drmFreeDevice(&devices[i]); 3498fe517fc9Smrg} 3499fe517fc9Smrg 35002ee35494Smrgstatic drmDevicePtr drmDeviceAlloc(unsigned int type, const char *node, 35012ee35494Smrg size_t bus_size, size_t device_size, 35022ee35494Smrg char **ptrp) 3503fe517fc9Smrg{ 35042ee35494Smrg size_t max_node_length, extra, size; 35052ee35494Smrg drmDevicePtr device; 35062ee35494Smrg unsigned int i; 35072ee35494Smrg char *ptr; 3508fe517fc9Smrg 35092ee35494Smrg max_node_length = ALIGN(drmGetMaxNodeName(), sizeof(void *)); 35102ee35494Smrg extra = DRM_NODE_MAX * (sizeof(void *) + max_node_length); 3511fe517fc9Smrg 35122ee35494Smrg size = sizeof(*device) + extra + bus_size + device_size; 3513fe517fc9Smrg 35142ee35494Smrg device = calloc(1, size); 35152ee35494Smrg if (!device) 35162ee35494Smrg return NULL; 35172ee35494Smrg 35182ee35494Smrg device->available_nodes = 1 << type; 3519fe517fc9Smrg 35202ee35494Smrg ptr = (char *)device + sizeof(*device); 35212ee35494Smrg device->nodes = (char **)ptr; 35222ee35494Smrg 35232ee35494Smrg ptr += DRM_NODE_MAX * sizeof(void *); 3524fe517fc9Smrg 3525fe517fc9Smrg for (i = 0; i < DRM_NODE_MAX; i++) { 35262ee35494Smrg device->nodes[i] = ptr; 35272ee35494Smrg ptr += max_node_length; 3528fe517fc9Smrg } 3529fe517fc9Smrg 35302ee35494Smrg memcpy(device->nodes[type], node, max_node_length); 35312ee35494Smrg 35322ee35494Smrg *ptrp = ptr; 35332ee35494Smrg 35342ee35494Smrg return device; 35352ee35494Smrg} 35362ee35494Smrg 35372ee35494Smrgstatic int drmProcessPciDevice(drmDevicePtr *device, 35382ee35494Smrg const char *node, int node_type, 35392ee35494Smrg int maj, int min, bool fetch_deviceinfo, 35402ee35494Smrg uint32_t flags) 35412ee35494Smrg{ 35422ee35494Smrg drmDevicePtr dev; 35432ee35494Smrg char *addr; 35442ee35494Smrg int ret; 35452ee35494Smrg 35462ee35494Smrg dev = drmDeviceAlloc(node_type, node, sizeof(drmPciBusInfo), 35472ee35494Smrg sizeof(drmPciDeviceInfo), &addr); 35482ee35494Smrg if (!dev) 35492ee35494Smrg return -ENOMEM; 35502ee35494Smrg 35512ee35494Smrg dev->bustype = DRM_BUS_PCI; 3552fe517fc9Smrg 35532ee35494Smrg dev->businfo.pci = (drmPciBusInfoPtr)addr; 35542ee35494Smrg 35552ee35494Smrg ret = drmParsePciBusInfo(maj, min, dev->businfo.pci); 3556fe517fc9Smrg if (ret) 3557fe517fc9Smrg goto free_device; 3558fe517fc9Smrg 3559fe517fc9Smrg // Fetch the device info if the user has requested it 3560fe517fc9Smrg if (fetch_deviceinfo) { 3561fe517fc9Smrg addr += sizeof(drmPciBusInfo); 35622ee35494Smrg dev->deviceinfo.pci = (drmPciDeviceInfoPtr)addr; 3563fe517fc9Smrg 35642ee35494Smrg ret = drmParsePciDeviceInfo(maj, min, dev->deviceinfo.pci, flags); 3565fe517fc9Smrg if (ret) 3566fe517fc9Smrg goto free_device; 3567fe517fc9Smrg } 35682ee35494Smrg 35692ee35494Smrg *device = dev; 35702ee35494Smrg 3571fe517fc9Smrg return 0; 3572fe517fc9Smrg 3573fe517fc9Smrgfree_device: 35742ee35494Smrg free(dev); 35752ee35494Smrg return ret; 35762ee35494Smrg} 35772ee35494Smrg 35782ee35494Smrgstatic int drmParseUsbBusInfo(int maj, int min, drmUsbBusInfoPtr info) 35792ee35494Smrg{ 35802ee35494Smrg#ifdef __linux__ 35812ee35494Smrg char path[PATH_MAX + 1], *value; 35822ee35494Smrg unsigned int bus, dev; 35832ee35494Smrg int ret; 35842ee35494Smrg 35852ee35494Smrg snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min); 35862ee35494Smrg 35872ee35494Smrg value = sysfs_uevent_get(path, "BUSNUM"); 35882ee35494Smrg if (!value) 35892ee35494Smrg return -ENOENT; 35902ee35494Smrg 35912ee35494Smrg ret = sscanf(value, "%03u", &bus); 35922ee35494Smrg free(value); 35932ee35494Smrg 35942ee35494Smrg if (ret <= 0) 35952ee35494Smrg return -errno; 35962ee35494Smrg 35972ee35494Smrg value = sysfs_uevent_get(path, "DEVNUM"); 35982ee35494Smrg if (!value) 35992ee35494Smrg return -ENOENT; 36002ee35494Smrg 36012ee35494Smrg ret = sscanf(value, "%03u", &dev); 36022ee35494Smrg free(value); 36032ee35494Smrg 36042ee35494Smrg if (ret <= 0) 36052ee35494Smrg return -errno; 36062ee35494Smrg 36072ee35494Smrg info->bus = bus; 36082ee35494Smrg info->dev = dev; 36092ee35494Smrg 36102ee35494Smrg return 0; 36112ee35494Smrg#else 36122ee35494Smrg#warning "Missing implementation of drmParseUsbBusInfo" 36132ee35494Smrg return -EINVAL; 36142ee35494Smrg#endif 36152ee35494Smrg} 36162ee35494Smrg 36172ee35494Smrgstatic int drmParseUsbDeviceInfo(int maj, int min, drmUsbDeviceInfoPtr info) 36182ee35494Smrg{ 36192ee35494Smrg#ifdef __linux__ 36202ee35494Smrg char path[PATH_MAX + 1], *value; 36212ee35494Smrg unsigned int vendor, product; 36222ee35494Smrg int ret; 36232ee35494Smrg 36242ee35494Smrg snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min); 36252ee35494Smrg 36262ee35494Smrg value = sysfs_uevent_get(path, "PRODUCT"); 36272ee35494Smrg if (!value) 36282ee35494Smrg return -ENOENT; 36292ee35494Smrg 36302ee35494Smrg ret = sscanf(value, "%x/%x", &vendor, &product); 36312ee35494Smrg free(value); 36322ee35494Smrg 36332ee35494Smrg if (ret <= 0) 36342ee35494Smrg return -errno; 36352ee35494Smrg 36362ee35494Smrg info->vendor = vendor; 36372ee35494Smrg info->product = product; 36382ee35494Smrg 36392ee35494Smrg return 0; 36402ee35494Smrg#else 36412ee35494Smrg#warning "Missing implementation of drmParseUsbDeviceInfo" 36422ee35494Smrg return -EINVAL; 36432ee35494Smrg#endif 36442ee35494Smrg} 36452ee35494Smrg 36462ee35494Smrgstatic int drmProcessUsbDevice(drmDevicePtr *device, const char *node, 36472ee35494Smrg int node_type, int maj, int min, 36482ee35494Smrg bool fetch_deviceinfo, uint32_t flags) 36492ee35494Smrg{ 36502ee35494Smrg drmDevicePtr dev; 36512ee35494Smrg char *ptr; 36522ee35494Smrg int ret; 36532ee35494Smrg 36542ee35494Smrg dev = drmDeviceAlloc(node_type, node, sizeof(drmUsbBusInfo), 36552ee35494Smrg sizeof(drmUsbDeviceInfo), &ptr); 36562ee35494Smrg if (!dev) 36572ee35494Smrg return -ENOMEM; 36582ee35494Smrg 36592ee35494Smrg dev->bustype = DRM_BUS_USB; 36602ee35494Smrg 36612ee35494Smrg dev->businfo.usb = (drmUsbBusInfoPtr)ptr; 36622ee35494Smrg 36632ee35494Smrg ret = drmParseUsbBusInfo(maj, min, dev->businfo.usb); 36642ee35494Smrg if (ret < 0) 36652ee35494Smrg goto free_device; 36662ee35494Smrg 36672ee35494Smrg if (fetch_deviceinfo) { 36682ee35494Smrg ptr += sizeof(drmUsbBusInfo); 36692ee35494Smrg dev->deviceinfo.usb = (drmUsbDeviceInfoPtr)ptr; 36702ee35494Smrg 36712ee35494Smrg ret = drmParseUsbDeviceInfo(maj, min, dev->deviceinfo.usb); 36722ee35494Smrg if (ret < 0) 36732ee35494Smrg goto free_device; 36742ee35494Smrg } 36752ee35494Smrg 36762ee35494Smrg *device = dev; 36772ee35494Smrg 36782ee35494Smrg return 0; 36792ee35494Smrg 36802ee35494Smrgfree_device: 36812ee35494Smrg free(dev); 36822ee35494Smrg return ret; 36832ee35494Smrg} 36842ee35494Smrg 36852ee35494Smrgstatic int drmParsePlatformBusInfo(int maj, int min, drmPlatformBusInfoPtr info) 36862ee35494Smrg{ 36872ee35494Smrg#ifdef __linux__ 36882ee35494Smrg char path[PATH_MAX + 1], *name; 36892ee35494Smrg 36902ee35494Smrg snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min); 36912ee35494Smrg 36922ee35494Smrg name = sysfs_uevent_get(path, "OF_FULLNAME"); 36932ee35494Smrg if (!name) 36942ee35494Smrg return -ENOENT; 36952ee35494Smrg 36962ee35494Smrg strncpy(info->fullname, name, DRM_PLATFORM_DEVICE_NAME_LEN); 36972ee35494Smrg info->fullname[DRM_PLATFORM_DEVICE_NAME_LEN - 1] = '\0'; 36982ee35494Smrg free(name); 36992ee35494Smrg 37002ee35494Smrg return 0; 37012ee35494Smrg#else 37022ee35494Smrg#warning "Missing implementation of drmParsePlatformBusInfo" 37032ee35494Smrg return -EINVAL; 37042ee35494Smrg#endif 37052ee35494Smrg} 37062ee35494Smrg 37072ee35494Smrgstatic int drmParsePlatformDeviceInfo(int maj, int min, 37082ee35494Smrg drmPlatformDeviceInfoPtr info) 37092ee35494Smrg{ 37102ee35494Smrg#ifdef __linux__ 37112ee35494Smrg char path[PATH_MAX + 1], *value; 37122ee35494Smrg unsigned int count, i; 37132ee35494Smrg int err; 37142ee35494Smrg 37152ee35494Smrg snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min); 37162ee35494Smrg 37172ee35494Smrg value = sysfs_uevent_get(path, "OF_COMPATIBLE_N"); 37182ee35494Smrg if (!value) 37192ee35494Smrg return -ENOENT; 37202ee35494Smrg 37212ee35494Smrg sscanf(value, "%u", &count); 37222ee35494Smrg free(value); 37232ee35494Smrg 37242ee35494Smrg info->compatible = calloc(count + 1, sizeof(*info->compatible)); 37252ee35494Smrg if (!info->compatible) 37262ee35494Smrg return -ENOMEM; 37272ee35494Smrg 37282ee35494Smrg for (i = 0; i < count; i++) { 37292ee35494Smrg value = sysfs_uevent_get(path, "OF_COMPATIBLE_%u", i); 37302ee35494Smrg if (!value) { 37312ee35494Smrg err = -ENOENT; 37322ee35494Smrg goto free; 37332ee35494Smrg } 37342ee35494Smrg 37352ee35494Smrg info->compatible[i] = value; 37362ee35494Smrg } 37372ee35494Smrg 37382ee35494Smrg return 0; 37392ee35494Smrg 37402ee35494Smrgfree: 37412ee35494Smrg while (i--) 37422ee35494Smrg free(info->compatible[i]); 37432ee35494Smrg 37442ee35494Smrg free(info->compatible); 37452ee35494Smrg return err; 37462ee35494Smrg#else 37472ee35494Smrg#warning "Missing implementation of drmParsePlatformDeviceInfo" 37482ee35494Smrg return -EINVAL; 37492ee35494Smrg#endif 37502ee35494Smrg} 37512ee35494Smrg 37522ee35494Smrgstatic int drmProcessPlatformDevice(drmDevicePtr *device, 37532ee35494Smrg const char *node, int node_type, 37542ee35494Smrg int maj, int min, bool fetch_deviceinfo, 37552ee35494Smrg uint32_t flags) 37562ee35494Smrg{ 37572ee35494Smrg drmDevicePtr dev; 37582ee35494Smrg char *ptr; 37592ee35494Smrg int ret; 37602ee35494Smrg 37612ee35494Smrg dev = drmDeviceAlloc(node_type, node, sizeof(drmPlatformBusInfo), 37622ee35494Smrg sizeof(drmPlatformDeviceInfo), &ptr); 37632ee35494Smrg if (!dev) 37642ee35494Smrg return -ENOMEM; 37652ee35494Smrg 37662ee35494Smrg dev->bustype = DRM_BUS_PLATFORM; 37672ee35494Smrg 37682ee35494Smrg dev->businfo.platform = (drmPlatformBusInfoPtr)ptr; 37692ee35494Smrg 37702ee35494Smrg ret = drmParsePlatformBusInfo(maj, min, dev->businfo.platform); 37712ee35494Smrg if (ret < 0) 37722ee35494Smrg goto free_device; 37732ee35494Smrg 37742ee35494Smrg if (fetch_deviceinfo) { 37752ee35494Smrg ptr += sizeof(drmPlatformBusInfo); 37762ee35494Smrg dev->deviceinfo.platform = (drmPlatformDeviceInfoPtr)ptr; 37772ee35494Smrg 37782ee35494Smrg ret = drmParsePlatformDeviceInfo(maj, min, dev->deviceinfo.platform); 37792ee35494Smrg if (ret < 0) 37802ee35494Smrg goto free_device; 37812ee35494Smrg } 37822ee35494Smrg 37832ee35494Smrg *device = dev; 37842ee35494Smrg 37852ee35494Smrg return 0; 37862ee35494Smrg 37872ee35494Smrgfree_device: 37882ee35494Smrg free(dev); 37892ee35494Smrg return ret; 37902ee35494Smrg} 37912ee35494Smrg 37922ee35494Smrgstatic int drmParseHost1xBusInfo(int maj, int min, drmHost1xBusInfoPtr info) 37932ee35494Smrg{ 37942ee35494Smrg#ifdef __linux__ 37952ee35494Smrg char path[PATH_MAX + 1], *name; 37962ee35494Smrg 37972ee35494Smrg snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min); 37982ee35494Smrg 37992ee35494Smrg name = sysfs_uevent_get(path, "OF_FULLNAME"); 38002ee35494Smrg if (!name) 38012ee35494Smrg return -ENOENT; 38022ee35494Smrg 38032ee35494Smrg strncpy(info->fullname, name, DRM_HOST1X_DEVICE_NAME_LEN); 38042ee35494Smrg info->fullname[DRM_HOST1X_DEVICE_NAME_LEN - 1] = '\0'; 38052ee35494Smrg free(name); 38062ee35494Smrg 38072ee35494Smrg return 0; 38082ee35494Smrg#else 38092ee35494Smrg#warning "Missing implementation of drmParseHost1xBusInfo" 38102ee35494Smrg return -EINVAL; 38112ee35494Smrg#endif 38122ee35494Smrg} 38132ee35494Smrg 38142ee35494Smrgstatic int drmParseHost1xDeviceInfo(int maj, int min, 38152ee35494Smrg drmHost1xDeviceInfoPtr info) 38162ee35494Smrg{ 38172ee35494Smrg#ifdef __linux__ 38182ee35494Smrg char path[PATH_MAX + 1], *value; 38192ee35494Smrg unsigned int count, i; 38202ee35494Smrg int err; 38212ee35494Smrg 38222ee35494Smrg snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min); 38232ee35494Smrg 38242ee35494Smrg value = sysfs_uevent_get(path, "OF_COMPATIBLE_N"); 38252ee35494Smrg if (!value) 38262ee35494Smrg return -ENOENT; 38272ee35494Smrg 38282ee35494Smrg sscanf(value, "%u", &count); 38292ee35494Smrg free(value); 38302ee35494Smrg 38312ee35494Smrg info->compatible = calloc(count + 1, sizeof(*info->compatible)); 38322ee35494Smrg if (!info->compatible) 38332ee35494Smrg return -ENOMEM; 38342ee35494Smrg 38352ee35494Smrg for (i = 0; i < count; i++) { 38362ee35494Smrg value = sysfs_uevent_get(path, "OF_COMPATIBLE_%u", i); 38372ee35494Smrg if (!value) { 38382ee35494Smrg err = -ENOENT; 38392ee35494Smrg goto free; 38402ee35494Smrg } 38412ee35494Smrg 38422ee35494Smrg info->compatible[i] = value; 38432ee35494Smrg } 38442ee35494Smrg 38452ee35494Smrg return 0; 38462ee35494Smrg 38472ee35494Smrgfree: 38482ee35494Smrg while (i--) 38492ee35494Smrg free(info->compatible[i]); 38502ee35494Smrg 38512ee35494Smrg free(info->compatible); 38522ee35494Smrg return err; 38532ee35494Smrg#else 38542ee35494Smrg#warning "Missing implementation of drmParseHost1xDeviceInfo" 38552ee35494Smrg return -EINVAL; 38562ee35494Smrg#endif 38572ee35494Smrg} 38582ee35494Smrg 38592ee35494Smrgstatic int drmProcessHost1xDevice(drmDevicePtr *device, 38602ee35494Smrg const char *node, int node_type, 38612ee35494Smrg int maj, int min, bool fetch_deviceinfo, 38622ee35494Smrg uint32_t flags) 38632ee35494Smrg{ 38642ee35494Smrg drmDevicePtr dev; 38652ee35494Smrg char *ptr; 38662ee35494Smrg int ret; 38672ee35494Smrg 38682ee35494Smrg dev = drmDeviceAlloc(node_type, node, sizeof(drmHost1xBusInfo), 38692ee35494Smrg sizeof(drmHost1xDeviceInfo), &ptr); 38702ee35494Smrg if (!dev) 38712ee35494Smrg return -ENOMEM; 38722ee35494Smrg 38732ee35494Smrg dev->bustype = DRM_BUS_HOST1X; 38742ee35494Smrg 38752ee35494Smrg dev->businfo.host1x = (drmHost1xBusInfoPtr)ptr; 38762ee35494Smrg 38772ee35494Smrg ret = drmParseHost1xBusInfo(maj, min, dev->businfo.host1x); 38782ee35494Smrg if (ret < 0) 38792ee35494Smrg goto free_device; 38802ee35494Smrg 38812ee35494Smrg if (fetch_deviceinfo) { 38822ee35494Smrg ptr += sizeof(drmHost1xBusInfo); 38832ee35494Smrg dev->deviceinfo.host1x = (drmHost1xDeviceInfoPtr)ptr; 38842ee35494Smrg 38852ee35494Smrg ret = drmParseHost1xDeviceInfo(maj, min, dev->deviceinfo.host1x); 38862ee35494Smrg if (ret < 0) 38872ee35494Smrg goto free_device; 38882ee35494Smrg } 38892ee35494Smrg 38902ee35494Smrg *device = dev; 38912ee35494Smrg 38922ee35494Smrg return 0; 38932ee35494Smrg 38942ee35494Smrgfree_device: 38952ee35494Smrg free(dev); 3896fe517fc9Smrg return ret; 3897fe517fc9Smrg} 3898fe517fc9Smrg 38996260e5d5Smrgstatic int 39006260e5d5Smrgprocess_device(drmDevicePtr *device, const char *d_name, 39016260e5d5Smrg int req_subsystem_type, 39026260e5d5Smrg bool fetch_deviceinfo, uint32_t flags) 39036260e5d5Smrg{ 39046260e5d5Smrg struct stat sbuf; 39056260e5d5Smrg char node[PATH_MAX + 1]; 39066260e5d5Smrg int node_type, subsystem_type; 39076260e5d5Smrg unsigned int maj, min; 39086260e5d5Smrg 39096260e5d5Smrg node_type = drmGetNodeType(d_name); 39106260e5d5Smrg if (node_type < 0) 39116260e5d5Smrg return -1; 39126260e5d5Smrg 39136260e5d5Smrg snprintf(node, PATH_MAX, "%s/%s", DRM_DIR_NAME, d_name); 39146260e5d5Smrg if (stat(node, &sbuf)) 39156260e5d5Smrg return -1; 39166260e5d5Smrg 39176260e5d5Smrg maj = major(sbuf.st_rdev); 39186260e5d5Smrg min = minor(sbuf.st_rdev); 39196260e5d5Smrg 39206260e5d5Smrg if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode)) 39216260e5d5Smrg return -1; 39226260e5d5Smrg 39236260e5d5Smrg subsystem_type = drmParseSubsystemType(maj, min); 39246260e5d5Smrg if (req_subsystem_type != -1 && req_subsystem_type != subsystem_type) 39256260e5d5Smrg return -1; 39266260e5d5Smrg 39276260e5d5Smrg switch (subsystem_type) { 39286260e5d5Smrg case DRM_BUS_PCI: 39296260e5d5Smrg case DRM_BUS_VIRTIO: 39306260e5d5Smrg return drmProcessPciDevice(device, node, node_type, maj, min, 39316260e5d5Smrg fetch_deviceinfo, flags); 39326260e5d5Smrg case DRM_BUS_USB: 39336260e5d5Smrg return drmProcessUsbDevice(device, node, node_type, maj, min, 39346260e5d5Smrg fetch_deviceinfo, flags); 39356260e5d5Smrg case DRM_BUS_PLATFORM: 39366260e5d5Smrg return drmProcessPlatformDevice(device, node, node_type, maj, min, 39376260e5d5Smrg fetch_deviceinfo, flags); 39386260e5d5Smrg case DRM_BUS_HOST1X: 39396260e5d5Smrg return drmProcessHost1xDevice(device, node, node_type, maj, min, 39406260e5d5Smrg fetch_deviceinfo, flags); 39416260e5d5Smrg default: 39426260e5d5Smrg return -1; 39436260e5d5Smrg } 39446260e5d5Smrg} 39456260e5d5Smrg 3946fe517fc9Smrg/* Consider devices located on the same bus as duplicate and fold the respective 3947fe517fc9Smrg * entries into a single one. 3948fe517fc9Smrg * 3949fe517fc9Smrg * Note: this leaves "gaps" in the array, while preserving the length. 3950fe517fc9Smrg */ 3951fe517fc9Smrgstatic void drmFoldDuplicatedDevices(drmDevicePtr local_devices[], int count) 3952fe517fc9Smrg{ 3953fe517fc9Smrg int node_type, i, j; 3954fe517fc9Smrg 3955fe517fc9Smrg for (i = 0; i < count; i++) { 3956fe517fc9Smrg for (j = i + 1; j < count; j++) { 39570655efefSmrg if (drmDevicesEqual(local_devices[i], local_devices[j])) { 3958fe517fc9Smrg local_devices[i]->available_nodes |= local_devices[j]->available_nodes; 3959fe517fc9Smrg node_type = log2(local_devices[j]->available_nodes); 3960fe517fc9Smrg memcpy(local_devices[i]->nodes[node_type], 3961fe517fc9Smrg local_devices[j]->nodes[node_type], drmGetMaxNodeName()); 3962fe517fc9Smrg drmFreeDevice(&local_devices[j]); 3963fe517fc9Smrg } 3964fe517fc9Smrg } 3965fe517fc9Smrg } 3966fe517fc9Smrg} 3967fe517fc9Smrg 39682ee35494Smrg/* Check that the given flags are valid returning 0 on success */ 39692ee35494Smrgstatic int 39702ee35494Smrgdrm_device_validate_flags(uint32_t flags) 39712ee35494Smrg{ 39722ee35494Smrg return (flags & ~DRM_DEVICE_GET_PCI_REVISION); 39732ee35494Smrg} 39742ee35494Smrg 39756260e5d5Smrgstatic bool 39766260e5d5Smrgdrm_device_has_rdev(drmDevicePtr device, dev_t find_rdev) 39776260e5d5Smrg{ 39786260e5d5Smrg struct stat sbuf; 39796260e5d5Smrg 39806260e5d5Smrg for (int i = 0; i < DRM_NODE_MAX; i++) { 39816260e5d5Smrg if (device->available_nodes & 1 << i) { 39826260e5d5Smrg if (stat(device->nodes[i], &sbuf) == 0 && 39836260e5d5Smrg sbuf.st_rdev == find_rdev) 39846260e5d5Smrg return true; 39856260e5d5Smrg } 39866260e5d5Smrg } 39876260e5d5Smrg return false; 39886260e5d5Smrg} 39896260e5d5Smrg 39906260e5d5Smrg/* 39916260e5d5Smrg * The kernel drm core has a number of places that assume maximum of 39926260e5d5Smrg * 3x64 devices nodes. That's 64 for each of primary, control and 39936260e5d5Smrg * render nodes. Rounded it up to 256 for simplicity. 39946260e5d5Smrg */ 39956260e5d5Smrg#define MAX_DRM_NODES 256 39966260e5d5Smrg 3997fe517fc9Smrg/** 3998fe517fc9Smrg * Get information about the opened drm device 3999fe517fc9Smrg * 4000fe517fc9Smrg * \param fd file descriptor of the drm device 40012ee35494Smrg * \param flags feature/behaviour bitmask 4002fe517fc9Smrg * \param device the address of a drmDevicePtr where the information 4003fe517fc9Smrg * will be allocated in stored 4004fe517fc9Smrg * 4005fe517fc9Smrg * \return zero on success, negative error code otherwise. 40062ee35494Smrg * 40072ee35494Smrg * \note Unlike drmGetDevice it does not retrieve the pci device revision field 40082ee35494Smrg * unless the DRM_DEVICE_GET_PCI_REVISION \p flag is set. 4009fe517fc9Smrg */ 40106260e5d5Smrgdrm_public int drmGetDevice2(int fd, uint32_t flags, drmDevicePtr *device) 4011fe517fc9Smrg{ 40122ee35494Smrg#ifdef __OpenBSD__ 40132ee35494Smrg /* 40142ee35494Smrg * DRI device nodes on OpenBSD are not in their own directory, they reside 40152ee35494Smrg * in /dev along with a large number of statically generated /dev nodes. 40162ee35494Smrg * Avoid stat'ing all of /dev needlessly by implementing this custom path. 40172ee35494Smrg */ 40182ee35494Smrg drmDevicePtr d; 40192ee35494Smrg struct stat sbuf; 40202ee35494Smrg char node[PATH_MAX + 1]; 40212ee35494Smrg const char *dev_name; 40222ee35494Smrg int node_type, subsystem_type; 40232ee35494Smrg int maj, min, n, ret, base; 40242ee35494Smrg 40252ee35494Smrg if (fd == -1 || device == NULL) 40262ee35494Smrg return -EINVAL; 40272ee35494Smrg 40282ee35494Smrg if (fstat(fd, &sbuf)) 40292ee35494Smrg return -errno; 40302ee35494Smrg 40312ee35494Smrg maj = major(sbuf.st_rdev); 40322ee35494Smrg min = minor(sbuf.st_rdev); 40332ee35494Smrg 40346260e5d5Smrg if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode)) 40352ee35494Smrg return -EINVAL; 40362ee35494Smrg 40372ee35494Smrg node_type = drmGetMinorType(min); 40382ee35494Smrg if (node_type == -1) 40392ee35494Smrg return -ENODEV; 40402ee35494Smrg 40412ee35494Smrg switch (node_type) { 40422ee35494Smrg case DRM_NODE_PRIMARY: 40432ee35494Smrg dev_name = DRM_DEV_NAME; 40442ee35494Smrg break; 40452ee35494Smrg case DRM_NODE_CONTROL: 40462ee35494Smrg dev_name = DRM_CONTROL_DEV_NAME; 40472ee35494Smrg break; 40482ee35494Smrg case DRM_NODE_RENDER: 40492ee35494Smrg dev_name = DRM_RENDER_DEV_NAME; 40502ee35494Smrg break; 40512ee35494Smrg default: 40522ee35494Smrg return -EINVAL; 40532ee35494Smrg }; 40542ee35494Smrg 40552ee35494Smrg base = drmGetMinorBase(node_type); 40562ee35494Smrg if (base < 0) 40572ee35494Smrg return -EINVAL; 40582ee35494Smrg 40592ee35494Smrg n = snprintf(node, PATH_MAX, dev_name, DRM_DIR_NAME, min - base); 40602ee35494Smrg if (n == -1 || n >= PATH_MAX) 40612ee35494Smrg return -errno; 40622ee35494Smrg if (stat(node, &sbuf)) 40632ee35494Smrg return -EINVAL; 40642ee35494Smrg 40652ee35494Smrg subsystem_type = drmParseSubsystemType(maj, min); 40662ee35494Smrg if (subsystem_type != DRM_BUS_PCI) 40672ee35494Smrg return -ENODEV; 40682ee35494Smrg 40692ee35494Smrg ret = drmProcessPciDevice(&d, node, node_type, maj, min, true, flags); 40702ee35494Smrg if (ret) 40712ee35494Smrg return ret; 40722ee35494Smrg 40732ee35494Smrg *device = d; 40742ee35494Smrg 40752ee35494Smrg return 0; 40762ee35494Smrg#else 40776260e5d5Smrg drmDevicePtr local_devices[MAX_DRM_NODES]; 4078fe517fc9Smrg drmDevicePtr d; 4079fe517fc9Smrg DIR *sysdir; 4080fe517fc9Smrg struct dirent *dent; 4081fe517fc9Smrg struct stat sbuf; 40826260e5d5Smrg int subsystem_type; 4083fe517fc9Smrg int maj, min; 4084fe517fc9Smrg int ret, i, node_count; 4085fe517fc9Smrg dev_t find_rdev; 4086fe517fc9Smrg 40872ee35494Smrg if (drm_device_validate_flags(flags)) 40882ee35494Smrg return -EINVAL; 40892ee35494Smrg 4090fe517fc9Smrg if (fd == -1 || device == NULL) 4091fe517fc9Smrg return -EINVAL; 4092fe517fc9Smrg 4093fe517fc9Smrg if (fstat(fd, &sbuf)) 4094fe517fc9Smrg return -errno; 4095fe517fc9Smrg 4096fe517fc9Smrg find_rdev = sbuf.st_rdev; 4097fe517fc9Smrg maj = major(sbuf.st_rdev); 4098fe517fc9Smrg min = minor(sbuf.st_rdev); 4099fe517fc9Smrg 41006260e5d5Smrg if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode)) 4101fe517fc9Smrg return -EINVAL; 4102fe517fc9Smrg 4103fe517fc9Smrg subsystem_type = drmParseSubsystemType(maj, min); 41046260e5d5Smrg if (subsystem_type < 0) 41056260e5d5Smrg return subsystem_type; 4106fe517fc9Smrg 4107fe517fc9Smrg sysdir = opendir(DRM_DIR_NAME); 41086260e5d5Smrg if (!sysdir) 41096260e5d5Smrg return -errno; 4110fe517fc9Smrg 4111fe517fc9Smrg i = 0; 4112fe517fc9Smrg while ((dent = readdir(sysdir))) { 41136260e5d5Smrg ret = process_device(&d, dent->d_name, subsystem_type, true, flags); 41146260e5d5Smrg if (ret) 4115fe517fc9Smrg continue; 4116fe517fc9Smrg 41176260e5d5Smrg if (i >= MAX_DRM_NODES) { 41186260e5d5Smrg fprintf(stderr, "More than %d drm nodes detected. " 41196260e5d5Smrg "Please report a bug - that should not happen.\n" 41206260e5d5Smrg "Skipping extra nodes\n", MAX_DRM_NODES); 4121fe517fc9Smrg break; 4122fe517fc9Smrg } 41236260e5d5Smrg local_devices[i] = d; 4124fe517fc9Smrg i++; 4125fe517fc9Smrg } 4126fe517fc9Smrg node_count = i; 4127fe517fc9Smrg 4128fe517fc9Smrg drmFoldDuplicatedDevices(local_devices, node_count); 4129fe517fc9Smrg 41306260e5d5Smrg *device = NULL; 41316260e5d5Smrg 41326260e5d5Smrg for (i = 0; i < node_count; i++) { 41336260e5d5Smrg if (!local_devices[i]) 41346260e5d5Smrg continue; 41356260e5d5Smrg 41366260e5d5Smrg if (drm_device_has_rdev(local_devices[i], find_rdev)) 41376260e5d5Smrg *device = local_devices[i]; 41386260e5d5Smrg else 41396260e5d5Smrg drmFreeDevice(&local_devices[i]); 41406260e5d5Smrg } 4141fe517fc9Smrg 4142fe517fc9Smrg closedir(sysdir); 41432ee35494Smrg if (*device == NULL) 41442ee35494Smrg return -ENODEV; 4145fe517fc9Smrg return 0; 41462ee35494Smrg#endif 41472ee35494Smrg} 41482ee35494Smrg 41492ee35494Smrg/** 41502ee35494Smrg * Get information about the opened drm device 41512ee35494Smrg * 41522ee35494Smrg * \param fd file descriptor of the drm device 41532ee35494Smrg * \param device the address of a drmDevicePtr where the information 41542ee35494Smrg * will be allocated in stored 41552ee35494Smrg * 41562ee35494Smrg * \return zero on success, negative error code otherwise. 41572ee35494Smrg */ 41586260e5d5Smrgdrm_public int drmGetDevice(int fd, drmDevicePtr *device) 41592ee35494Smrg{ 41602ee35494Smrg return drmGetDevice2(fd, DRM_DEVICE_GET_PCI_REVISION, device); 4161fe517fc9Smrg} 4162fe517fc9Smrg 4163fe517fc9Smrg/** 4164fe517fc9Smrg * Get drm devices on the system 4165fe517fc9Smrg * 41662ee35494Smrg * \param flags feature/behaviour bitmask 4167fe517fc9Smrg * \param devices the array of devices with drmDevicePtr elements 4168fe517fc9Smrg * can be NULL to get the device number first 4169fe517fc9Smrg * \param max_devices the maximum number of devices for the array 4170fe517fc9Smrg * 4171fe517fc9Smrg * \return on error - negative error code, 4172fe517fc9Smrg * if devices is NULL - total number of devices available on the system, 4173fe517fc9Smrg * alternatively the number of devices stored in devices[], which is 4174fe517fc9Smrg * capped by the max_devices. 41752ee35494Smrg * 41762ee35494Smrg * \note Unlike drmGetDevices it does not retrieve the pci device revision field 41772ee35494Smrg * unless the DRM_DEVICE_GET_PCI_REVISION \p flag is set. 4178fe517fc9Smrg */ 41796260e5d5Smrgdrm_public int drmGetDevices2(uint32_t flags, drmDevicePtr devices[], 41806260e5d5Smrg int max_devices) 4181fe517fc9Smrg{ 41826260e5d5Smrg drmDevicePtr local_devices[MAX_DRM_NODES]; 4183fe517fc9Smrg drmDevicePtr device; 4184fe517fc9Smrg DIR *sysdir; 4185fe517fc9Smrg struct dirent *dent; 4186fe517fc9Smrg int ret, i, node_count, device_count; 4187fe517fc9Smrg 41882ee35494Smrg if (drm_device_validate_flags(flags)) 41892ee35494Smrg return -EINVAL; 41902ee35494Smrg 4191fe517fc9Smrg sysdir = opendir(DRM_DIR_NAME); 41926260e5d5Smrg if (!sysdir) 41936260e5d5Smrg return -errno; 4194fe517fc9Smrg 4195fe517fc9Smrg i = 0; 4196fe517fc9Smrg while ((dent = readdir(sysdir))) { 41976260e5d5Smrg ret = process_device(&device, dent->d_name, -1, devices != NULL, flags); 41986260e5d5Smrg if (ret) 4199fe517fc9Smrg continue; 4200fe517fc9Smrg 42016260e5d5Smrg if (i >= MAX_DRM_NODES) { 42026260e5d5Smrg fprintf(stderr, "More than %d drm nodes detected. " 42036260e5d5Smrg "Please report a bug - that should not happen.\n" 42046260e5d5Smrg "Skipping extra nodes\n", MAX_DRM_NODES); 42052ee35494Smrg break; 4206fe517fc9Smrg } 4207fe517fc9Smrg local_devices[i] = device; 4208fe517fc9Smrg i++; 4209fe517fc9Smrg } 4210fe517fc9Smrg node_count = i; 4211fe517fc9Smrg 4212fe517fc9Smrg drmFoldDuplicatedDevices(local_devices, node_count); 4213fe517fc9Smrg 4214fe517fc9Smrg device_count = 0; 4215fe517fc9Smrg for (i = 0; i < node_count; i++) { 4216fe517fc9Smrg if (!local_devices[i]) 4217fe517fc9Smrg continue; 4218fe517fc9Smrg 4219fe517fc9Smrg if ((devices != NULL) && (device_count < max_devices)) 4220fe517fc9Smrg devices[device_count] = local_devices[i]; 4221fe517fc9Smrg else 4222fe517fc9Smrg drmFreeDevice(&local_devices[i]); 4223fe517fc9Smrg 4224fe517fc9Smrg device_count++; 4225fe517fc9Smrg } 4226fe517fc9Smrg 4227fe517fc9Smrg closedir(sysdir); 4228fe517fc9Smrg return device_count; 4229424e9256Smrg} 42302ee35494Smrg 42312ee35494Smrg/** 42322ee35494Smrg * Get drm devices on the system 42332ee35494Smrg * 42342ee35494Smrg * \param devices the array of devices with drmDevicePtr elements 42352ee35494Smrg * can be NULL to get the device number first 42362ee35494Smrg * \param max_devices the maximum number of devices for the array 42372ee35494Smrg * 42382ee35494Smrg * \return on error - negative error code, 42392ee35494Smrg * if devices is NULL - total number of devices available on the system, 42402ee35494Smrg * alternatively the number of devices stored in devices[], which is 42412ee35494Smrg * capped by the max_devices. 42422ee35494Smrg */ 42436260e5d5Smrgdrm_public int drmGetDevices(drmDevicePtr devices[], int max_devices) 42442ee35494Smrg{ 42452ee35494Smrg return drmGetDevices2(DRM_DEVICE_GET_PCI_REVISION, devices, max_devices); 42462ee35494Smrg} 42472ee35494Smrg 42486260e5d5Smrgdrm_public char *drmGetDeviceNameFromFd2(int fd) 42492ee35494Smrg{ 42502ee35494Smrg#ifdef __linux__ 42512ee35494Smrg struct stat sbuf; 42522ee35494Smrg char path[PATH_MAX + 1], *value; 42532ee35494Smrg unsigned int maj, min; 42542ee35494Smrg 42552ee35494Smrg if (fstat(fd, &sbuf)) 42562ee35494Smrg return NULL; 42572ee35494Smrg 42582ee35494Smrg maj = major(sbuf.st_rdev); 42592ee35494Smrg min = minor(sbuf.st_rdev); 42602ee35494Smrg 42616260e5d5Smrg if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode)) 42622ee35494Smrg return NULL; 42632ee35494Smrg 42642ee35494Smrg snprintf(path, sizeof(path), "/sys/dev/char/%d:%d", maj, min); 42652ee35494Smrg 42662ee35494Smrg value = sysfs_uevent_get(path, "DEVNAME"); 42672ee35494Smrg if (!value) 42682ee35494Smrg return NULL; 42692ee35494Smrg 42702ee35494Smrg snprintf(path, sizeof(path), "/dev/%s", value); 42712ee35494Smrg free(value); 42722ee35494Smrg 42732ee35494Smrg return strdup(path); 42742ee35494Smrg#else 42752ee35494Smrg struct stat sbuf; 42762ee35494Smrg char node[PATH_MAX + 1]; 42772ee35494Smrg const char *dev_name; 42782ee35494Smrg int node_type; 42792ee35494Smrg int maj, min, n, base; 42802ee35494Smrg 42812ee35494Smrg if (fstat(fd, &sbuf)) 42822ee35494Smrg return NULL; 42832ee35494Smrg 42842ee35494Smrg maj = major(sbuf.st_rdev); 42852ee35494Smrg min = minor(sbuf.st_rdev); 42862ee35494Smrg 42876260e5d5Smrg if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode)) 42882ee35494Smrg return NULL; 42892ee35494Smrg 42902ee35494Smrg node_type = drmGetMinorType(min); 42912ee35494Smrg if (node_type == -1) 42922ee35494Smrg return NULL; 42932ee35494Smrg 42942ee35494Smrg switch (node_type) { 42952ee35494Smrg case DRM_NODE_PRIMARY: 42962ee35494Smrg dev_name = DRM_DEV_NAME; 42972ee35494Smrg break; 42982ee35494Smrg case DRM_NODE_CONTROL: 42992ee35494Smrg dev_name = DRM_CONTROL_DEV_NAME; 43002ee35494Smrg break; 43012ee35494Smrg case DRM_NODE_RENDER: 43022ee35494Smrg dev_name = DRM_RENDER_DEV_NAME; 43032ee35494Smrg break; 43042ee35494Smrg default: 43052ee35494Smrg return NULL; 43062ee35494Smrg }; 43072ee35494Smrg 43082ee35494Smrg base = drmGetMinorBase(node_type); 43092ee35494Smrg if (base < 0) 43102ee35494Smrg return NULL; 43112ee35494Smrg 43122ee35494Smrg n = snprintf(node, PATH_MAX, dev_name, DRM_DIR_NAME, min - base); 43132ee35494Smrg if (n == -1 || n >= PATH_MAX) 43142ee35494Smrg return NULL; 43152ee35494Smrg 43162ee35494Smrg return strdup(node); 43172ee35494Smrg#endif 43182ee35494Smrg} 43190655efefSmrg 43206260e5d5Smrgdrm_public int drmSyncobjCreate(int fd, uint32_t flags, uint32_t *handle) 43210655efefSmrg{ 43220655efefSmrg struct drm_syncobj_create args; 43230655efefSmrg int ret; 43240655efefSmrg 43250655efefSmrg memclear(args); 43260655efefSmrg args.flags = flags; 43270655efefSmrg args.handle = 0; 43280655efefSmrg ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_CREATE, &args); 43290655efefSmrg if (ret) 43302b90624aSmrg return ret; 43310655efefSmrg *handle = args.handle; 43320655efefSmrg return 0; 43330655efefSmrg} 43340655efefSmrg 43356260e5d5Smrgdrm_public int drmSyncobjDestroy(int fd, uint32_t handle) 43360655efefSmrg{ 43370655efefSmrg struct drm_syncobj_destroy args; 43380655efefSmrg 43390655efefSmrg memclear(args); 43400655efefSmrg args.handle = handle; 43410655efefSmrg return drmIoctl(fd, DRM_IOCTL_SYNCOBJ_DESTROY, &args); 43420655efefSmrg} 43430655efefSmrg 43446260e5d5Smrgdrm_public int drmSyncobjHandleToFD(int fd, uint32_t handle, int *obj_fd) 43450655efefSmrg{ 43460655efefSmrg struct drm_syncobj_handle args; 43470655efefSmrg int ret; 43480655efefSmrg 43490655efefSmrg memclear(args); 43500655efefSmrg args.fd = -1; 43510655efefSmrg args.handle = handle; 43520655efefSmrg ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD, &args); 43530655efefSmrg if (ret) 43542b90624aSmrg return ret; 43550655efefSmrg *obj_fd = args.fd; 43560655efefSmrg return 0; 43570655efefSmrg} 43580655efefSmrg 43596260e5d5Smrgdrm_public int drmSyncobjFDToHandle(int fd, int obj_fd, uint32_t *handle) 43600655efefSmrg{ 43610655efefSmrg struct drm_syncobj_handle args; 43620655efefSmrg int ret; 43630655efefSmrg 43640655efefSmrg memclear(args); 43650655efefSmrg args.fd = obj_fd; 43660655efefSmrg args.handle = 0; 43670655efefSmrg ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE, &args); 43680655efefSmrg if (ret) 43692b90624aSmrg return ret; 43700655efefSmrg *handle = args.handle; 43710655efefSmrg return 0; 43720655efefSmrg} 43730655efefSmrg 43746260e5d5Smrgdrm_public int drmSyncobjImportSyncFile(int fd, uint32_t handle, 43756260e5d5Smrg int sync_file_fd) 43760655efefSmrg{ 43770655efefSmrg struct drm_syncobj_handle args; 43780655efefSmrg 43790655efefSmrg memclear(args); 43800655efefSmrg args.fd = sync_file_fd; 43810655efefSmrg args.handle = handle; 43820655efefSmrg args.flags = DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_IMPORT_SYNC_FILE; 43830655efefSmrg return drmIoctl(fd, DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE, &args); 43840655efefSmrg} 43850655efefSmrg 43866260e5d5Smrgdrm_public int drmSyncobjExportSyncFile(int fd, uint32_t handle, 43876260e5d5Smrg int *sync_file_fd) 43880655efefSmrg{ 43890655efefSmrg struct drm_syncobj_handle args; 43900655efefSmrg int ret; 43910655efefSmrg 43920655efefSmrg memclear(args); 43930655efefSmrg args.fd = -1; 43940655efefSmrg args.handle = handle; 43950655efefSmrg args.flags = DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_EXPORT_SYNC_FILE; 43960655efefSmrg ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD, &args); 43970655efefSmrg if (ret) 43982b90624aSmrg return ret; 43990655efefSmrg *sync_file_fd = args.fd; 44000655efefSmrg return 0; 44010655efefSmrg} 44022b90624aSmrg 44036260e5d5Smrgdrm_public int drmSyncobjWait(int fd, uint32_t *handles, unsigned num_handles, 44046260e5d5Smrg int64_t timeout_nsec, unsigned flags, 44056260e5d5Smrg uint32_t *first_signaled) 44062b90624aSmrg{ 44072b90624aSmrg struct drm_syncobj_wait args; 44082b90624aSmrg int ret; 44092b90624aSmrg 44102b90624aSmrg memclear(args); 44112b90624aSmrg args.handles = (uintptr_t)handles; 44122b90624aSmrg args.timeout_nsec = timeout_nsec; 44132b90624aSmrg args.count_handles = num_handles; 44142b90624aSmrg args.flags = flags; 44152b90624aSmrg 44162b90624aSmrg ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_WAIT, &args); 44172b90624aSmrg if (ret < 0) 44182b90624aSmrg return -errno; 44192b90624aSmrg 44202b90624aSmrg if (first_signaled) 44212b90624aSmrg *first_signaled = args.first_signaled; 44222b90624aSmrg return ret; 44232b90624aSmrg} 44242b90624aSmrg 44256260e5d5Smrgdrm_public int drmSyncobjReset(int fd, const uint32_t *handles, 44266260e5d5Smrg uint32_t handle_count) 44272b90624aSmrg{ 44282b90624aSmrg struct drm_syncobj_array args; 44292b90624aSmrg int ret; 44302b90624aSmrg 44312b90624aSmrg memclear(args); 44322b90624aSmrg args.handles = (uintptr_t)handles; 44332b90624aSmrg args.count_handles = handle_count; 44342b90624aSmrg 44352b90624aSmrg ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_RESET, &args); 44362b90624aSmrg return ret; 44372b90624aSmrg} 44382b90624aSmrg 44396260e5d5Smrgdrm_public int drmSyncobjSignal(int fd, const uint32_t *handles, 44406260e5d5Smrg uint32_t handle_count) 44412b90624aSmrg{ 44422b90624aSmrg struct drm_syncobj_array args; 44432b90624aSmrg int ret; 44442b90624aSmrg 44452b90624aSmrg memclear(args); 44462b90624aSmrg args.handles = (uintptr_t)handles; 44472b90624aSmrg args.count_handles = handle_count; 44482b90624aSmrg 44492b90624aSmrg ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_SIGNAL, &args); 44502b90624aSmrg return ret; 44512b90624aSmrg} 4452