xf86drm.c revision 87bf8e7c
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 6087bf8e7cSmrg#if HAVE_SYS_SYSCTL_H 6187bf8e7cSmrg#include <sys/sysctl.h> 6287bf8e7cSmrg#endif 63fe517fc9Smrg#include <math.h> 6422944501Smrg 6587bf8e7cSmrg#if defined(__FreeBSD__) 6687bf8e7cSmrg#include <sys/param.h> 6787bf8e7cSmrg#include <sys/pciio.h> 6887bf8e7cSmrg#endif 6987bf8e7cSmrg 704545e80cSmrg#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) 714545e80cSmrg 722ee35494Smrg/* Not all systems have MAP_FAILED defined */ 732ee35494Smrg#ifndef MAP_FAILED 742ee35494Smrg#define MAP_FAILED ((void *)-1) 752ee35494Smrg#endif 7622944501Smrg 7722944501Smrg#include "xf86drm.h" 78424e9256Smrg#include "libdrm_macros.h" 7922944501Smrg 80fe517fc9Smrg#include "util_math.h" 81fe517fc9Smrg 8287bf8e7cSmrg#ifdef __DragonFly__ 8322944501Smrg#define DRM_MAJOR 145 8422944501Smrg#endif 8522944501Smrg 8622944501Smrg#ifdef __NetBSD__ 872e6867f6Smrg#undef DRM_MAJOR 882e6867f6Smrg#define DRM_MAJOR 180 8906815bcbSmaya#include <sys/param.h> 90a970b457Sriastradh#include <dev/pci/pcireg.h> 91a970b457Sriastradh#include <pci.h> 9222944501Smrg#endif 9322944501Smrg 94fe517fc9Smrg#ifdef __OpenBSD__ 95fe517fc9Smrg#ifdef __i386__ 96fe517fc9Smrg#define DRM_MAJOR 88 97fe517fc9Smrg#else 98fe517fc9Smrg#define DRM_MAJOR 87 9922944501Smrg#endif 100fe517fc9Smrg#endif /* __OpenBSD__ */ 10122944501Smrg 102fe517fc9Smrg#ifndef DRM_MAJOR 103fe517fc9Smrg#define DRM_MAJOR 226 /* Linux */ 10422944501Smrg#endif 10522944501Smrg 1064545e80cSmrg#if defined(__OpenBSD__) || defined(__DragonFly__) 1072ee35494Smrgstruct drm_pciinfo { 1082ee35494Smrg uint16_t domain; 1092ee35494Smrg uint8_t bus; 1102ee35494Smrg uint8_t dev; 1112ee35494Smrg uint8_t func; 1122ee35494Smrg uint16_t vendor_id; 1132ee35494Smrg uint16_t device_id; 1142ee35494Smrg uint16_t subvendor_id; 1152ee35494Smrg uint16_t subdevice_id; 1162ee35494Smrg uint8_t revision_id; 1172ee35494Smrg}; 1182ee35494Smrg 1192ee35494Smrg#define DRM_IOCTL_GET_PCIINFO DRM_IOR(0x15, struct drm_pciinfo) 12011c53d23Schristos#endif 12111c53d23Schristos 12222944501Smrg#define DRM_MSG_VERBOSITY 3 12322944501Smrg 124424e9256Smrg#define memclear(s) memset(&s, 0, sizeof(s)) 12522944501Smrg 12622944501Smrgstatic drmServerInfoPtr drm_server_info; 12722944501Smrg 12887bf8e7cSmrgstatic bool drmNodeIsDRM(int maj, int min); 12987bf8e7cSmrgstatic char *drmGetMinorNameForFD(int fd, int type); 13087bf8e7cSmrg 1316260e5d5Smrgdrm_public void drmSetServerInfo(drmServerInfoPtr info) 13222944501Smrg{ 13322944501Smrg drm_server_info = info; 13422944501Smrg} 13522944501Smrg 13622944501Smrg/** 13722944501Smrg * Output a message to stderr. 13822944501Smrg * 13922944501Smrg * \param format printf() like format string. 14022944501Smrg * 14122944501Smrg * \internal 14222944501Smrg * This function is a wrapper around vfprintf(). 14322944501Smrg */ 14422944501Smrg 145a7d7de1eSmrgstatic int DRM_PRINTFLIKE(1, 0) 146a7d7de1eSmrgdrmDebugPrint(const char *format, va_list ap) 14722944501Smrg{ 14822944501Smrg return vfprintf(stderr, format, ap); 14922944501Smrg} 15022944501Smrg 1516260e5d5Smrgdrm_public void 15222944501SmrgdrmMsg(const char *format, ...) 15322944501Smrg{ 154fe517fc9Smrg va_list ap; 15522944501Smrg const char *env; 156fe517fc9Smrg if (((env = getenv("LIBGL_DEBUG")) && strstr(env, "verbose")) || 157fe517fc9Smrg (drm_server_info && drm_server_info->debug_print)) 15822944501Smrg { 159fe517fc9Smrg va_start(ap, format); 160fe517fc9Smrg if (drm_server_info) { 161fe517fc9Smrg drm_server_info->debug_print(format,ap); 162fe517fc9Smrg } else { 163fe517fc9Smrg drmDebugPrint(format, ap); 164fe517fc9Smrg } 165fe517fc9Smrg va_end(ap); 16622944501Smrg } 16722944501Smrg} 16822944501Smrg 16922944501Smrgstatic void *drmHashTable = NULL; /* Context switch callbacks */ 17022944501Smrg 1716260e5d5Smrgdrm_public void *drmGetHashTable(void) 17222944501Smrg{ 17322944501Smrg return drmHashTable; 17422944501Smrg} 17522944501Smrg 1766260e5d5Smrgdrm_public void *drmMalloc(int size) 17722944501Smrg{ 178424e9256Smrg return calloc(1, size); 17922944501Smrg} 18022944501Smrg 1816260e5d5Smrgdrm_public void drmFree(void *pt) 18222944501Smrg{ 183424e9256Smrg free(pt); 18422944501Smrg} 18522944501Smrg 18622944501Smrg/** 187bf6cc7dcSmrg * Call ioctl, restarting if it is interrupted 18822944501Smrg */ 1896260e5d5Smrgdrm_public int 19022944501SmrgdrmIoctl(int fd, unsigned long request, void *arg) 19122944501Smrg{ 192fe517fc9Smrg int ret; 19322944501Smrg 19422944501Smrg do { 195fe517fc9Smrg ret = ioctl(fd, request, arg); 19622944501Smrg } while (ret == -1 && (errno == EINTR || errno == EAGAIN)); 19722944501Smrg return ret; 19822944501Smrg} 19922944501Smrg 20022944501Smrgstatic unsigned long drmGetKeyFromFd(int fd) 20122944501Smrg{ 20222944501Smrg stat_t st; 20322944501Smrg 20422944501Smrg st.st_rdev = 0; 20522944501Smrg fstat(fd, &st); 20622944501Smrg return st.st_rdev; 20722944501Smrg} 20822944501Smrg 2096260e5d5Smrgdrm_public drmHashEntry *drmGetEntry(int fd) 21022944501Smrg{ 21122944501Smrg unsigned long key = drmGetKeyFromFd(fd); 21222944501Smrg void *value; 21322944501Smrg drmHashEntry *entry; 21422944501Smrg 21522944501Smrg if (!drmHashTable) 216fe517fc9Smrg drmHashTable = drmHashCreate(); 21722944501Smrg 21822944501Smrg if (drmHashLookup(drmHashTable, key, &value)) { 219fe517fc9Smrg entry = drmMalloc(sizeof(*entry)); 220fe517fc9Smrg entry->fd = fd; 221fe517fc9Smrg entry->f = NULL; 222fe517fc9Smrg entry->tagTable = drmHashCreate(); 223fe517fc9Smrg drmHashInsert(drmHashTable, key, entry); 22422944501Smrg } else { 225fe517fc9Smrg entry = value; 22622944501Smrg } 22722944501Smrg return entry; 22822944501Smrg} 22922944501Smrg 23022944501Smrg/** 23122944501Smrg * Compare two busid strings 23222944501Smrg * 23322944501Smrg * \param first 23422944501Smrg * \param second 23522944501Smrg * 23622944501Smrg * \return 1 if matched. 23722944501Smrg * 23822944501Smrg * \internal 23922944501Smrg * This function compares two bus ID strings. It understands the older 24022944501Smrg * PCI:b:d:f format and the newer pci:oooo:bb:dd.f format. In the format, o is 24122944501Smrg * domain, b is bus, d is device, f is function. 24222944501Smrg */ 2436d98c517Smrgstatic int drmMatchBusID(const char *id1, const char *id2, int pci_domain_ok) 24422944501Smrg{ 24522944501Smrg /* First, check if the IDs are exactly the same */ 24622944501Smrg if (strcasecmp(id1, id2) == 0) 247fe517fc9Smrg return 1; 24822944501Smrg 24922944501Smrg /* Try to match old/new-style PCI bus IDs. */ 25022944501Smrg if (strncasecmp(id1, "pci", 3) == 0) { 251fe517fc9Smrg unsigned int o1, b1, d1, f1; 252fe517fc9Smrg unsigned int o2, b2, d2, f2; 253fe517fc9Smrg int ret; 254fe517fc9Smrg 255fe517fc9Smrg ret = sscanf(id1, "pci:%04x:%02x:%02x.%u", &o1, &b1, &d1, &f1); 256fe517fc9Smrg if (ret != 4) { 257fe517fc9Smrg o1 = 0; 258fe517fc9Smrg ret = sscanf(id1, "PCI:%u:%u:%u", &b1, &d1, &f1); 259fe517fc9Smrg if (ret != 3) 260fe517fc9Smrg return 0; 261fe517fc9Smrg } 262fe517fc9Smrg 263fe517fc9Smrg ret = sscanf(id2, "pci:%04x:%02x:%02x.%u", &o2, &b2, &d2, &f2); 264fe517fc9Smrg if (ret != 4) { 265fe517fc9Smrg o2 = 0; 266fe517fc9Smrg ret = sscanf(id2, "PCI:%u:%u:%u", &b2, &d2, &f2); 267fe517fc9Smrg if (ret != 3) 268fe517fc9Smrg return 0; 269fe517fc9Smrg } 270fe517fc9Smrg 271fe517fc9Smrg /* If domains aren't properly supported by the kernel interface, 272fe517fc9Smrg * just ignore them, which sucks less than picking a totally random 273fe517fc9Smrg * card with "open by name" 274fe517fc9Smrg */ 275fe517fc9Smrg if (!pci_domain_ok) 276fe517fc9Smrg o1 = o2 = 0; 277fe517fc9Smrg 278fe517fc9Smrg if ((o1 != o2) || (b1 != b2) || (d1 != d2) || (f1 != f2)) 279fe517fc9Smrg return 0; 280fe517fc9Smrg else 281fe517fc9Smrg return 1; 28222944501Smrg } 28322944501Smrg return 0; 28422944501Smrg} 28522944501Smrg 28622944501Smrg/** 28722944501Smrg * Handles error checking for chown call. 28822944501Smrg * 28922944501Smrg * \param path to file. 29022944501Smrg * \param id of the new owner. 29122944501Smrg * \param id of the new group. 29222944501Smrg * 29322944501Smrg * \return zero if success or -1 if failure. 29422944501Smrg * 29522944501Smrg * \internal 29622944501Smrg * Checks for failure. If failure was caused by signal call chown again. 297bf6cc7dcSmrg * If any other failure happened then it will output error message using 29822944501Smrg * drmMsg() call. 29922944501Smrg */ 3006260e5d5Smrg#if !UDEV 30122944501Smrgstatic int chown_check_return(const char *path, uid_t owner, gid_t group) 30222944501Smrg{ 303fe517fc9Smrg int rv; 30422944501Smrg 305fe517fc9Smrg do { 306fe517fc9Smrg rv = chown(path, owner, group); 307fe517fc9Smrg } while (rv != 0 && errno == EINTR); 30822944501Smrg 309fe517fc9Smrg if (rv == 0) 310fe517fc9Smrg return 0; 31122944501Smrg 312fe517fc9Smrg drmMsg("Failed to change owner or group for file %s! %d: %s\n", 313fe517fc9Smrg path, errno, strerror(errno)); 314fe517fc9Smrg return -1; 31522944501Smrg} 316424e9256Smrg#endif 31722944501Smrg 31882025ec7Smrgstatic const char *drmGetDeviceName(int type) 31982025ec7Smrg{ 32082025ec7Smrg switch (type) { 32182025ec7Smrg case DRM_NODE_PRIMARY: 32282025ec7Smrg return DRM_DEV_NAME; 32382025ec7Smrg case DRM_NODE_CONTROL: 32482025ec7Smrg return DRM_CONTROL_DEV_NAME; 32582025ec7Smrg case DRM_NODE_RENDER: 32682025ec7Smrg return DRM_RENDER_DEV_NAME; 32782025ec7Smrg } 32882025ec7Smrg return NULL; 32982025ec7Smrg} 33082025ec7Smrg 33122944501Smrg/** 33222944501Smrg * Open the DRM device, creating it if necessary. 33322944501Smrg * 33422944501Smrg * \param dev major and minor numbers of the device. 33522944501Smrg * \param minor minor number of the device. 336fe517fc9Smrg * 33722944501Smrg * \return a file descriptor on success, or a negative value on error. 33822944501Smrg * 33922944501Smrg * \internal 34022944501Smrg * Assembles the device name from \p minor and opens it, creating the device 34122944501Smrg * special file node with the major and minor numbers specified by \p dev and 34222944501Smrg * parent directory if necessary and was called by root. 34322944501Smrg */ 344424e9256Smrgstatic int drmOpenDevice(dev_t dev, int minor, int type) 34522944501Smrg{ 34622944501Smrg stat_t st; 34782025ec7Smrg const char *dev_name = drmGetDeviceName(type); 34882025ec7Smrg char buf[DRM_NODE_NAME_MAX]; 34922944501Smrg int fd; 35022944501Smrg mode_t devmode = DRM_DEV_MODE, serv_mode; 351424e9256Smrg gid_t serv_group; 3526260e5d5Smrg#if !UDEV 35322944501Smrg int isroot = !geteuid(); 35422944501Smrg uid_t user = DRM_DEV_UID; 355424e9256Smrg gid_t group = DRM_DEV_GID; 356424e9256Smrg#endif 357424e9256Smrg 35882025ec7Smrg if (!dev_name) 359fe517fc9Smrg return -EINVAL; 360424e9256Smrg 361424e9256Smrg sprintf(buf, dev_name, DRM_DIR_NAME, minor); 36222944501Smrg drmMsg("drmOpenDevice: node name is %s\n", buf); 36322944501Smrg 364fe517fc9Smrg if (drm_server_info && drm_server_info->get_perms) { 365fe517fc9Smrg drm_server_info->get_perms(&serv_group, &serv_mode); 366fe517fc9Smrg devmode = serv_mode ? serv_mode : DRM_DEV_MODE; 367fe517fc9Smrg devmode &= ~(S_IXUSR|S_IXGRP|S_IXOTH); 36822944501Smrg } 36922944501Smrg 3706260e5d5Smrg#if !UDEV 37122944501Smrg if (stat(DRM_DIR_NAME, &st)) { 372fe517fc9Smrg if (!isroot) 373fe517fc9Smrg return DRM_ERR_NOT_ROOT; 374fe517fc9Smrg mkdir(DRM_DIR_NAME, DRM_DEV_DIRMODE); 375fe517fc9Smrg chown_check_return(DRM_DIR_NAME, 0, 0); /* root:root */ 376fe517fc9Smrg chmod(DRM_DIR_NAME, DRM_DEV_DIRMODE); 37722944501Smrg } 37822944501Smrg 37922944501Smrg /* Check if the device node exists and create it if necessary. */ 38022944501Smrg if (stat(buf, &st)) { 381fe517fc9Smrg if (!isroot) 382fe517fc9Smrg return DRM_ERR_NOT_ROOT; 383fe517fc9Smrg remove(buf); 384fe517fc9Smrg mknod(buf, S_IFCHR | devmode, dev); 38522944501Smrg } 38622944501Smrg 387fe517fc9Smrg if (drm_server_info && drm_server_info->get_perms) { 388fe517fc9Smrg group = ((int)serv_group >= 0) ? serv_group : DRM_DEV_GID; 389fe517fc9Smrg chown_check_return(buf, user, group); 390fe517fc9Smrg chmod(buf, devmode); 39122944501Smrg } 39222944501Smrg#else 39322944501Smrg /* if we modprobed then wait for udev */ 39422944501Smrg { 395fe517fc9Smrg int udev_count = 0; 39622944501Smrgwait_for_udev: 39722944501Smrg if (stat(DRM_DIR_NAME, &st)) { 398fe517fc9Smrg usleep(20); 399fe517fc9Smrg udev_count++; 400fe517fc9Smrg 401fe517fc9Smrg if (udev_count == 50) 402fe517fc9Smrg return -1; 403fe517fc9Smrg goto wait_for_udev; 404fe517fc9Smrg } 405fe517fc9Smrg 406fe517fc9Smrg if (stat(buf, &st)) { 407fe517fc9Smrg usleep(20); 408fe517fc9Smrg udev_count++; 409fe517fc9Smrg 410fe517fc9Smrg if (udev_count == 50) 411fe517fc9Smrg return -1; 412fe517fc9Smrg goto wait_for_udev; 413fe517fc9Smrg } 41422944501Smrg } 41522944501Smrg#endif 41622944501Smrg 4176260e5d5Smrg fd = open(buf, O_RDWR | O_CLOEXEC, 0); 41822944501Smrg drmMsg("drmOpenDevice: open result is %d, (%s)\n", 419fe517fc9Smrg fd, fd < 0 ? strerror(errno) : "OK"); 42022944501Smrg if (fd >= 0) 421fe517fc9Smrg return fd; 42222944501Smrg 4236260e5d5Smrg#if !UDEV 42422944501Smrg /* Check if the device node is not what we expect it to be, and recreate it 42522944501Smrg * and try again if so. 42622944501Smrg */ 42722944501Smrg if (st.st_rdev != dev) { 428fe517fc9Smrg if (!isroot) 429fe517fc9Smrg return DRM_ERR_NOT_ROOT; 430fe517fc9Smrg remove(buf); 431fe517fc9Smrg mknod(buf, S_IFCHR | devmode, dev); 432fe517fc9Smrg if (drm_server_info && drm_server_info->get_perms) { 433fe517fc9Smrg chown_check_return(buf, user, group); 434fe517fc9Smrg chmod(buf, devmode); 435fe517fc9Smrg } 43622944501Smrg } 4376260e5d5Smrg fd = open(buf, O_RDWR | O_CLOEXEC, 0); 43822944501Smrg drmMsg("drmOpenDevice: open result is %d, (%s)\n", 439fe517fc9Smrg fd, fd < 0 ? strerror(errno) : "OK"); 44022944501Smrg if (fd >= 0) 441fe517fc9Smrg return fd; 44222944501Smrg 44322944501Smrg drmMsg("drmOpenDevice: Open failed\n"); 44422944501Smrg remove(buf); 4459ce4edccSmrg#endif 44622944501Smrg return -errno; 44722944501Smrg} 44822944501Smrg 44922944501Smrg 45022944501Smrg/** 45122944501Smrg * Open the DRM device 45222944501Smrg * 45322944501Smrg * \param minor device minor number. 45422944501Smrg * \param create allow to create the device if set. 45522944501Smrg * 45622944501Smrg * \return a file descriptor on success, or a negative value on error. 457fe517fc9Smrg * 45822944501Smrg * \internal 45922944501Smrg * Calls drmOpenDevice() if \p create is set, otherwise assembles the device 46022944501Smrg * name from \p minor and opens it. 46122944501Smrg */ 46222944501Smrgstatic int drmOpenMinor(int minor, int create, int type) 46322944501Smrg{ 46422944501Smrg int fd; 46582025ec7Smrg char buf[DRM_NODE_NAME_MAX]; 46682025ec7Smrg const char *dev_name = drmGetDeviceName(type); 467fe517fc9Smrg 46822944501Smrg if (create) 469fe517fc9Smrg return drmOpenDevice(makedev(DRM_MAJOR, minor), minor, type); 470fe517fc9Smrg 47182025ec7Smrg if (!dev_name) 472fe517fc9Smrg return -EINVAL; 473424e9256Smrg 474424e9256Smrg sprintf(buf, dev_name, DRM_DIR_NAME, minor); 4756260e5d5Smrg if ((fd = open(buf, O_RDWR | O_CLOEXEC, 0)) >= 0) 476fe517fc9Smrg return fd; 47722944501Smrg return -errno; 47822944501Smrg} 47922944501Smrg 48022944501Smrg 48122944501Smrg/** 48222944501Smrg * Determine whether the DRM kernel driver has been loaded. 483fe517fc9Smrg * 48422944501Smrg * \return 1 if the DRM driver is loaded, 0 otherwise. 48522944501Smrg * 486fe517fc9Smrg * \internal 48722944501Smrg * Determine the presence of the kernel driver by attempting to open the 0 48822944501Smrg * minor and get version information. For backward compatibility with older 48922944501Smrg * Linux implementations, /proc/dri is also checked. 49022944501Smrg */ 4916260e5d5Smrgdrm_public int drmAvailable(void) 49222944501Smrg{ 49322944501Smrg drmVersionPtr version; 49422944501Smrg int retval = 0; 49522944501Smrg int fd; 49622944501Smrg 497424e9256Smrg if ((fd = drmOpenMinor(0, 1, DRM_NODE_PRIMARY)) < 0) { 49822944501Smrg#ifdef __linux__ 499fe517fc9Smrg /* Try proc for backward Linux compatibility */ 500fe517fc9Smrg if (!access("/proc/dri/0", R_OK)) 501fe517fc9Smrg return 1; 50222944501Smrg#endif 503fe517fc9Smrg return 0; 50422944501Smrg } 505fe517fc9Smrg 50622944501Smrg if ((version = drmGetVersion(fd))) { 507fe517fc9Smrg retval = 1; 508fe517fc9Smrg drmFreeVersion(version); 50922944501Smrg } 51022944501Smrg close(fd); 51122944501Smrg 51222944501Smrg return retval; 51322944501Smrg} 51422944501Smrg 515424e9256Smrgstatic int drmGetMinorBase(int type) 516424e9256Smrg{ 517424e9256Smrg switch (type) { 518424e9256Smrg case DRM_NODE_PRIMARY: 519424e9256Smrg return 0; 520424e9256Smrg case DRM_NODE_CONTROL: 521424e9256Smrg return 64; 522424e9256Smrg case DRM_NODE_RENDER: 523424e9256Smrg return 128; 524424e9256Smrg default: 525424e9256Smrg return -1; 526424e9256Smrg }; 527424e9256Smrg} 528424e9256Smrg 52987bf8e7cSmrgstatic int drmGetMinorType(int major, int minor) 530424e9256Smrg{ 53187bf8e7cSmrg#ifdef __FreeBSD__ 53287bf8e7cSmrg char name[SPECNAMELEN]; 53387bf8e7cSmrg int id; 53487bf8e7cSmrg 53587bf8e7cSmrg if (!devname_r(makedev(major, minor), S_IFCHR, name, sizeof(name))) 53687bf8e7cSmrg return -1; 53787bf8e7cSmrg 53887bf8e7cSmrg if (sscanf(name, "drm/%d", &id) != 1) { 53987bf8e7cSmrg // If not in /dev/drm/ we have the type in the name 54087bf8e7cSmrg if (sscanf(name, "dri/card%d\n", &id) >= 1) 54187bf8e7cSmrg return DRM_NODE_PRIMARY; 54287bf8e7cSmrg else if (sscanf(name, "dri/control%d\n", &id) >= 1) 54387bf8e7cSmrg return DRM_NODE_CONTROL; 54487bf8e7cSmrg else if (sscanf(name, "dri/renderD%d\n", &id) >= 1) 54587bf8e7cSmrg return DRM_NODE_RENDER; 54687bf8e7cSmrg return -1; 54787bf8e7cSmrg } 54887bf8e7cSmrg 54987bf8e7cSmrg minor = id; 55087bf8e7cSmrg#endif 551424e9256Smrg int type = minor >> 6; 552424e9256Smrg 553424e9256Smrg if (minor < 0) 554424e9256Smrg return -1; 555424e9256Smrg 556424e9256Smrg switch (type) { 557424e9256Smrg case DRM_NODE_PRIMARY: 558424e9256Smrg case DRM_NODE_CONTROL: 559424e9256Smrg case DRM_NODE_RENDER: 560424e9256Smrg return type; 561424e9256Smrg default: 562424e9256Smrg return -1; 563424e9256Smrg } 564424e9256Smrg} 565424e9256Smrg 566424e9256Smrgstatic const char *drmGetMinorName(int type) 567424e9256Smrg{ 568424e9256Smrg switch (type) { 569424e9256Smrg case DRM_NODE_PRIMARY: 570fe517fc9Smrg return DRM_PRIMARY_MINOR_NAME; 571424e9256Smrg case DRM_NODE_CONTROL: 572fe517fc9Smrg return DRM_CONTROL_MINOR_NAME; 573424e9256Smrg case DRM_NODE_RENDER: 574fe517fc9Smrg return DRM_RENDER_MINOR_NAME; 575424e9256Smrg default: 576424e9256Smrg return NULL; 577424e9256Smrg } 578424e9256Smrg} 57922944501Smrg 58022944501Smrg/** 58122944501Smrg * Open the device by bus ID. 58222944501Smrg * 58322944501Smrg * \param busid bus ID. 584424e9256Smrg * \param type device node type. 58522944501Smrg * 58622944501Smrg * \return a file descriptor on success, or a negative value on error. 58722944501Smrg * 58822944501Smrg * \internal 58922944501Smrg * This function attempts to open every possible minor (up to DRM_MAX_MINOR), 59022944501Smrg * comparing the device bus ID with the one supplied. 59122944501Smrg * 59222944501Smrg * \sa drmOpenMinor() and drmGetBusid(). 59322944501Smrg */ 594424e9256Smrgstatic int drmOpenByBusid(const char *busid, int type) 59522944501Smrg{ 5966d98c517Smrg int i, pci_domain_ok = 1; 59722944501Smrg int fd; 59822944501Smrg const char *buf; 59922944501Smrg drmSetVersion sv; 600424e9256Smrg int base = drmGetMinorBase(type); 601424e9256Smrg 602424e9256Smrg if (base < 0) 603424e9256Smrg return -1; 60422944501Smrg 60522944501Smrg drmMsg("drmOpenByBusid: Searching for BusID %s\n", busid); 606424e9256Smrg for (i = base; i < base + DRM_MAX_MINOR; i++) { 607fe517fc9Smrg fd = drmOpenMinor(i, 1, type); 608fe517fc9Smrg drmMsg("drmOpenByBusid: drmOpenMinor returns %d\n", fd); 609fe517fc9Smrg if (fd >= 0) { 610fe517fc9Smrg /* We need to try for 1.4 first for proper PCI domain support 611fe517fc9Smrg * and if that fails, we know the kernel is busted 612fe517fc9Smrg */ 613fe517fc9Smrg sv.drm_di_major = 1; 614fe517fc9Smrg sv.drm_di_minor = 4; 615fe517fc9Smrg sv.drm_dd_major = -1; /* Don't care */ 616fe517fc9Smrg sv.drm_dd_minor = -1; /* Don't care */ 617fe517fc9Smrg if (drmSetInterfaceVersion(fd, &sv)) { 6186d98c517Smrg#ifndef __alpha__ 619fe517fc9Smrg pci_domain_ok = 0; 6206d98c517Smrg#endif 621fe517fc9Smrg sv.drm_di_major = 1; 622fe517fc9Smrg sv.drm_di_minor = 1; 623fe517fc9Smrg sv.drm_dd_major = -1; /* Don't care */ 624fe517fc9Smrg sv.drm_dd_minor = -1; /* Don't care */ 625fe517fc9Smrg drmMsg("drmOpenByBusid: Interface 1.4 failed, trying 1.1\n"); 626fe517fc9Smrg drmSetInterfaceVersion(fd, &sv); 627fe517fc9Smrg } 628fe517fc9Smrg buf = drmGetBusid(fd); 629fe517fc9Smrg drmMsg("drmOpenByBusid: drmGetBusid reports %s\n", buf); 630fe517fc9Smrg if (buf && drmMatchBusID(buf, busid, pci_domain_ok)) { 631fe517fc9Smrg drmFreeBusid(buf); 632fe517fc9Smrg return fd; 633fe517fc9Smrg } 634fe517fc9Smrg if (buf) 635fe517fc9Smrg drmFreeBusid(buf); 636fe517fc9Smrg close(fd); 637fe517fc9Smrg } 63822944501Smrg } 63922944501Smrg return -1; 64022944501Smrg} 64122944501Smrg 64222944501Smrg 64322944501Smrg/** 64422944501Smrg * Open the device by name. 64522944501Smrg * 64622944501Smrg * \param name driver name. 647424e9256Smrg * \param type the device node type. 648fe517fc9Smrg * 64922944501Smrg * \return a file descriptor on success, or a negative value on error. 650fe517fc9Smrg * 65122944501Smrg * \internal 65222944501Smrg * This function opens the first minor number that matches the driver name and 65322944501Smrg * isn't already in use. If it's in use it then it will already have a bus ID 65422944501Smrg * assigned. 655fe517fc9Smrg * 65622944501Smrg * \sa drmOpenMinor(), drmGetVersion() and drmGetBusid(). 65722944501Smrg */ 658424e9256Smrgstatic int drmOpenByName(const char *name, int type) 65922944501Smrg{ 66022944501Smrg int i; 66122944501Smrg int fd; 66222944501Smrg drmVersionPtr version; 66322944501Smrg char * id; 664424e9256Smrg int base = drmGetMinorBase(type); 665424e9256Smrg 666424e9256Smrg if (base < 0) 667424e9256Smrg return -1; 66822944501Smrg 66922944501Smrg /* 67022944501Smrg * Open the first minor number that matches the driver name and isn't 67122944501Smrg * already in use. If it's in use it will have a busid assigned already. 67222944501Smrg */ 673424e9256Smrg for (i = base; i < base + DRM_MAX_MINOR; i++) { 674fe517fc9Smrg if ((fd = drmOpenMinor(i, 1, type)) >= 0) { 675fe517fc9Smrg if ((version = drmGetVersion(fd))) { 676fe517fc9Smrg if (!strcmp(version->name, name)) { 677fe517fc9Smrg drmFreeVersion(version); 678fe517fc9Smrg id = drmGetBusid(fd); 679fe517fc9Smrg drmMsg("drmGetBusid returned '%s'\n", id ? id : "NULL"); 680fe517fc9Smrg if (!id || !*id) { 681fe517fc9Smrg if (id) 682fe517fc9Smrg drmFreeBusid(id); 683fe517fc9Smrg return fd; 684fe517fc9Smrg } else { 685fe517fc9Smrg drmFreeBusid(id); 686fe517fc9Smrg } 687fe517fc9Smrg } else { 688fe517fc9Smrg drmFreeVersion(version); 689fe517fc9Smrg } 690fe517fc9Smrg } 691fe517fc9Smrg close(fd); 692fe517fc9Smrg } 69322944501Smrg } 69422944501Smrg 69522944501Smrg#ifdef __linux__ 69622944501Smrg /* Backward-compatibility /proc support */ 69722944501Smrg for (i = 0; i < 8; i++) { 698fe517fc9Smrg char proc_name[64], buf[512]; 699fe517fc9Smrg char *driver, *pt, *devstring; 700fe517fc9Smrg int retcode; 701fe517fc9Smrg 702fe517fc9Smrg sprintf(proc_name, "/proc/dri/%d/name", i); 703fe517fc9Smrg if ((fd = open(proc_name, 0, 0)) >= 0) { 704fe517fc9Smrg retcode = read(fd, buf, sizeof(buf)-1); 705fe517fc9Smrg close(fd); 706fe517fc9Smrg if (retcode) { 707fe517fc9Smrg buf[retcode-1] = '\0'; 708fe517fc9Smrg for (driver = pt = buf; *pt && *pt != ' '; ++pt) 709fe517fc9Smrg ; 710fe517fc9Smrg if (*pt) { /* Device is next */ 711fe517fc9Smrg *pt = '\0'; 712fe517fc9Smrg if (!strcmp(driver, name)) { /* Match */ 713fe517fc9Smrg for (devstring = ++pt; *pt && *pt != ' '; ++pt) 714fe517fc9Smrg ; 715fe517fc9Smrg if (*pt) { /* Found busid */ 716fe517fc9Smrg return drmOpenByBusid(++pt, type); 717fe517fc9Smrg } else { /* No busid */ 718fe517fc9Smrg return drmOpenDevice(strtol(devstring, NULL, 0),i, type); 719fe517fc9Smrg } 720fe517fc9Smrg } 721fe517fc9Smrg } 722fe517fc9Smrg } 723fe517fc9Smrg } 72422944501Smrg } 72522944501Smrg#endif 72622944501Smrg 72722944501Smrg return -1; 72822944501Smrg} 72922944501Smrg 73022944501Smrg 73122944501Smrg/** 73222944501Smrg * Open the DRM device. 73322944501Smrg * 73422944501Smrg * Looks up the specified name and bus ID, and opens the device found. The 73522944501Smrg * entry in /dev/dri is created if necessary and if called by root. 73622944501Smrg * 73722944501Smrg * \param name driver name. Not referenced if bus ID is supplied. 73822944501Smrg * \param busid bus ID. Zero if not known. 739fe517fc9Smrg * 74022944501Smrg * \return a file descriptor on success, or a negative value on error. 741fe517fc9Smrg * 74222944501Smrg * \internal 74322944501Smrg * It calls drmOpenByBusid() if \p busid is specified or drmOpenByName() 74422944501Smrg * otherwise. 74522944501Smrg */ 7466260e5d5Smrgdrm_public int drmOpen(const char *name, const char *busid) 747424e9256Smrg{ 748424e9256Smrg return drmOpenWithType(name, busid, DRM_NODE_PRIMARY); 749424e9256Smrg} 750424e9256Smrg 751424e9256Smrg/** 752424e9256Smrg * Open the DRM device with specified type. 753424e9256Smrg * 754424e9256Smrg * Looks up the specified name and bus ID, and opens the device found. The 755424e9256Smrg * entry in /dev/dri is created if necessary and if called by root. 756424e9256Smrg * 757424e9256Smrg * \param name driver name. Not referenced if bus ID is supplied. 758424e9256Smrg * \param busid bus ID. Zero if not known. 759424e9256Smrg * \param type the device node type to open, PRIMARY, CONTROL or RENDER 760424e9256Smrg * 761424e9256Smrg * \return a file descriptor on success, or a negative value on error. 762424e9256Smrg * 763424e9256Smrg * \internal 764424e9256Smrg * It calls drmOpenByBusid() if \p busid is specified or drmOpenByName() 765424e9256Smrg * otherwise. 766424e9256Smrg */ 7676260e5d5Smrgdrm_public int drmOpenWithType(const char *name, const char *busid, int type) 76822944501Smrg{ 769bf6cc7dcSmrg if (name != NULL && drm_server_info && 770bf6cc7dcSmrg drm_server_info->load_module && !drmAvailable()) { 771fe517fc9Smrg /* try to load the kernel module */ 772fe517fc9Smrg if (!drm_server_info->load_module(name)) { 773fe517fc9Smrg drmMsg("[drm] failed to load kernel module \"%s\"\n", name); 774fe517fc9Smrg return -1; 775fe517fc9Smrg } 77622944501Smrg } 77722944501Smrg 77822944501Smrg if (busid) { 779fe517fc9Smrg int fd = drmOpenByBusid(busid, type); 780fe517fc9Smrg if (fd >= 0) 781fe517fc9Smrg return fd; 78222944501Smrg } 783fe517fc9Smrg 78422944501Smrg if (name) 785fe517fc9Smrg return drmOpenByName(name, type); 78622944501Smrg 78722944501Smrg return -1; 78822944501Smrg} 78922944501Smrg 7906260e5d5Smrgdrm_public int drmOpenControl(int minor) 79122944501Smrg{ 79222944501Smrg return drmOpenMinor(minor, 0, DRM_NODE_CONTROL); 79322944501Smrg} 79422944501Smrg 7956260e5d5Smrgdrm_public int drmOpenRender(int minor) 796424e9256Smrg{ 797424e9256Smrg return drmOpenMinor(minor, 0, DRM_NODE_RENDER); 798424e9256Smrg} 799424e9256Smrg 80022944501Smrg/** 80122944501Smrg * Free the version information returned by drmGetVersion(). 80222944501Smrg * 80322944501Smrg * \param v pointer to the version information. 80422944501Smrg * 80522944501Smrg * \internal 80622944501Smrg * It frees the memory pointed by \p %v as well as all the non-null strings 80722944501Smrg * pointers in it. 80822944501Smrg */ 8096260e5d5Smrgdrm_public void drmFreeVersion(drmVersionPtr v) 81022944501Smrg{ 81122944501Smrg if (!v) 812fe517fc9Smrg return; 81322944501Smrg drmFree(v->name); 81422944501Smrg drmFree(v->date); 81522944501Smrg drmFree(v->desc); 81622944501Smrg drmFree(v); 81722944501Smrg} 81822944501Smrg 81922944501Smrg 82022944501Smrg/** 82122944501Smrg * Free the non-public version information returned by the kernel. 82222944501Smrg * 82322944501Smrg * \param v pointer to the version information. 82422944501Smrg * 82522944501Smrg * \internal 82622944501Smrg * Used by drmGetVersion() to free the memory pointed by \p %v as well as all 82722944501Smrg * the non-null strings pointers in it. 82822944501Smrg */ 82922944501Smrgstatic void drmFreeKernelVersion(drm_version_t *v) 83022944501Smrg{ 83122944501Smrg if (!v) 832fe517fc9Smrg return; 83322944501Smrg drmFree(v->name); 83422944501Smrg drmFree(v->date); 83522944501Smrg drmFree(v->desc); 83622944501Smrg drmFree(v); 83722944501Smrg} 83822944501Smrg 83922944501Smrg 84022944501Smrg/** 84122944501Smrg * Copy version information. 842fe517fc9Smrg * 84322944501Smrg * \param d destination pointer. 84422944501Smrg * \param s source pointer. 845fe517fc9Smrg * 84622944501Smrg * \internal 84722944501Smrg * Used by drmGetVersion() to translate the information returned by the ioctl 84822944501Smrg * interface in a private structure into the public structure counterpart. 84922944501Smrg */ 85022944501Smrgstatic void drmCopyVersion(drmVersionPtr d, const drm_version_t *s) 85122944501Smrg{ 85222944501Smrg d->version_major = s->version_major; 85322944501Smrg d->version_minor = s->version_minor; 85422944501Smrg d->version_patchlevel = s->version_patchlevel; 85522944501Smrg d->name_len = s->name_len; 8569ce4edccSmrg d->name = strdup(s->name); 85722944501Smrg d->date_len = s->date_len; 8589ce4edccSmrg d->date = strdup(s->date); 85922944501Smrg d->desc_len = s->desc_len; 8609ce4edccSmrg d->desc = strdup(s->desc); 86122944501Smrg} 86222944501Smrg 86322944501Smrg 86422944501Smrg/** 86522944501Smrg * Query the driver version information. 86622944501Smrg * 86722944501Smrg * \param fd file descriptor. 868fe517fc9Smrg * 86922944501Smrg * \return pointer to a drmVersion structure which should be freed with 87022944501Smrg * drmFreeVersion(). 871fe517fc9Smrg * 87222944501Smrg * \note Similar information is available via /proc/dri. 873fe517fc9Smrg * 87422944501Smrg * \internal 87522944501Smrg * It gets the version information via successive DRM_IOCTL_VERSION ioctls, 87622944501Smrg * first with zeros to get the string lengths, and then the actually strings. 87722944501Smrg * It also null-terminates them since they might not be already. 87822944501Smrg */ 8796260e5d5Smrgdrm_public drmVersionPtr drmGetVersion(int fd) 88022944501Smrg{ 88122944501Smrg drmVersionPtr retval; 88222944501Smrg drm_version_t *version = drmMalloc(sizeof(*version)); 88322944501Smrg 88422944501Smrg if (drmIoctl(fd, DRM_IOCTL_VERSION, version)) { 885fe517fc9Smrg drmFreeKernelVersion(version); 886fe517fc9Smrg return NULL; 88722944501Smrg } 88822944501Smrg 88922944501Smrg if (version->name_len) 890fe517fc9Smrg version->name = drmMalloc(version->name_len + 1); 89122944501Smrg if (version->date_len) 892fe517fc9Smrg version->date = drmMalloc(version->date_len + 1); 89322944501Smrg if (version->desc_len) 894fe517fc9Smrg version->desc = drmMalloc(version->desc_len + 1); 89522944501Smrg 89622944501Smrg if (drmIoctl(fd, DRM_IOCTL_VERSION, version)) { 897fe517fc9Smrg drmMsg("DRM_IOCTL_VERSION: %s\n", strerror(errno)); 898fe517fc9Smrg drmFreeKernelVersion(version); 899fe517fc9Smrg return NULL; 90022944501Smrg } 90122944501Smrg 90222944501Smrg /* The results might not be null-terminated strings, so terminate them. */ 90322944501Smrg if (version->name_len) version->name[version->name_len] = '\0'; 90422944501Smrg if (version->date_len) version->date[version->date_len] = '\0'; 90522944501Smrg if (version->desc_len) version->desc[version->desc_len] = '\0'; 90622944501Smrg 90722944501Smrg retval = drmMalloc(sizeof(*retval)); 90822944501Smrg drmCopyVersion(retval, version); 90922944501Smrg drmFreeKernelVersion(version); 91022944501Smrg return retval; 91122944501Smrg} 91222944501Smrg 91322944501Smrg 91422944501Smrg/** 91522944501Smrg * Get version information for the DRM user space library. 916fe517fc9Smrg * 91722944501Smrg * This version number is driver independent. 918fe517fc9Smrg * 91922944501Smrg * \param fd file descriptor. 92022944501Smrg * 92122944501Smrg * \return version information. 922fe517fc9Smrg * 92322944501Smrg * \internal 92422944501Smrg * This function allocates and fills a drm_version structure with a hard coded 92522944501Smrg * version number. 92622944501Smrg */ 9276260e5d5Smrgdrm_public drmVersionPtr drmGetLibVersion(int fd) 92822944501Smrg{ 92922944501Smrg drm_version_t *version = drmMalloc(sizeof(*version)); 93022944501Smrg 93122944501Smrg /* Version history: 93222944501Smrg * NOTE THIS MUST NOT GO ABOVE VERSION 1.X due to drivers needing it 93322944501Smrg * revision 1.0.x = original DRM interface with no drmGetLibVersion 93422944501Smrg * entry point and many drm<Device> extensions 93522944501Smrg * revision 1.1.x = added drmCommand entry points for device extensions 93622944501Smrg * added drmGetLibVersion to identify libdrm.a version 93722944501Smrg * revision 1.2.x = added drmSetInterfaceVersion 93822944501Smrg * modified drmOpen to handle both busid and name 93922944501Smrg * revision 1.3.x = added server + memory manager 94022944501Smrg */ 94122944501Smrg version->version_major = 1; 94222944501Smrg version->version_minor = 3; 94322944501Smrg version->version_patchlevel = 0; 94422944501Smrg 94522944501Smrg return (drmVersionPtr)version; 94622944501Smrg} 94722944501Smrg 9486260e5d5Smrgdrm_public int drmGetCap(int fd, uint64_t capability, uint64_t *value) 94920131375Smrg{ 950fe517fc9Smrg struct drm_get_cap cap; 951fe517fc9Smrg int ret; 95220131375Smrg 953fe517fc9Smrg memclear(cap); 954fe517fc9Smrg cap.capability = capability; 955424e9256Smrg 956fe517fc9Smrg ret = drmIoctl(fd, DRM_IOCTL_GET_CAP, &cap); 957fe517fc9Smrg if (ret) 958fe517fc9Smrg return ret; 95920131375Smrg 960fe517fc9Smrg *value = cap.value; 961fe517fc9Smrg return 0; 96220131375Smrg} 96320131375Smrg 9646260e5d5Smrgdrm_public int drmSetClientCap(int fd, uint64_t capability, uint64_t value) 96520131375Smrg{ 966fe517fc9Smrg struct drm_set_client_cap cap; 967424e9256Smrg 968fe517fc9Smrg memclear(cap); 969fe517fc9Smrg cap.capability = capability; 970fe517fc9Smrg cap.value = value; 97120131375Smrg 972fe517fc9Smrg return drmIoctl(fd, DRM_IOCTL_SET_CLIENT_CAP, &cap); 97320131375Smrg} 97422944501Smrg 97522944501Smrg/** 97622944501Smrg * Free the bus ID information. 97722944501Smrg * 97822944501Smrg * \param busid bus ID information string as given by drmGetBusid(). 97922944501Smrg * 98022944501Smrg * \internal 98122944501Smrg * This function is just frees the memory pointed by \p busid. 98222944501Smrg */ 9836260e5d5Smrgdrm_public void drmFreeBusid(const char *busid) 98422944501Smrg{ 98522944501Smrg drmFree((void *)busid); 98622944501Smrg} 98722944501Smrg 98822944501Smrg 98922944501Smrg/** 99022944501Smrg * Get the bus ID of the device. 99122944501Smrg * 99222944501Smrg * \param fd file descriptor. 99322944501Smrg * 99422944501Smrg * \return bus ID string. 99522944501Smrg * 99622944501Smrg * \internal 99722944501Smrg * This function gets the bus ID via successive DRM_IOCTL_GET_UNIQUE ioctls to 99822944501Smrg * get the string length and data, passing the arguments in a drm_unique 99922944501Smrg * structure. 100022944501Smrg */ 10016260e5d5Smrgdrm_public char *drmGetBusid(int fd) 100222944501Smrg{ 100322944501Smrg drm_unique_t u; 100422944501Smrg 1005424e9256Smrg memclear(u); 100622944501Smrg 100722944501Smrg if (drmIoctl(fd, DRM_IOCTL_GET_UNIQUE, &u)) 1008fe517fc9Smrg return NULL; 100922944501Smrg u.unique = drmMalloc(u.unique_len + 1); 10100655efefSmrg if (drmIoctl(fd, DRM_IOCTL_GET_UNIQUE, &u)) { 10110655efefSmrg drmFree(u.unique); 1012fe517fc9Smrg return NULL; 10130655efefSmrg } 101422944501Smrg u.unique[u.unique_len] = '\0'; 101522944501Smrg 101622944501Smrg return u.unique; 101722944501Smrg} 101822944501Smrg 101922944501Smrg 102022944501Smrg/** 102122944501Smrg * Set the bus ID of the device. 102222944501Smrg * 102322944501Smrg * \param fd file descriptor. 102422944501Smrg * \param busid bus ID string. 102522944501Smrg * 102622944501Smrg * \return zero on success, negative on failure. 102722944501Smrg * 102822944501Smrg * \internal 102922944501Smrg * This function is a wrapper around the DRM_IOCTL_SET_UNIQUE ioctl, passing 103022944501Smrg * the arguments in a drm_unique structure. 103122944501Smrg */ 10326260e5d5Smrgdrm_public int drmSetBusid(int fd, const char *busid) 103322944501Smrg{ 103422944501Smrg drm_unique_t u; 103522944501Smrg 1036424e9256Smrg memclear(u); 103722944501Smrg u.unique = (char *)busid; 103822944501Smrg u.unique_len = strlen(busid); 103922944501Smrg 104022944501Smrg if (drmIoctl(fd, DRM_IOCTL_SET_UNIQUE, &u)) { 1041fe517fc9Smrg return -errno; 104222944501Smrg } 104322944501Smrg return 0; 104422944501Smrg} 104522944501Smrg 10466260e5d5Smrgdrm_public int drmGetMagic(int fd, drm_magic_t * magic) 104722944501Smrg{ 104822944501Smrg drm_auth_t auth; 104922944501Smrg 1050424e9256Smrg memclear(auth); 1051424e9256Smrg 105222944501Smrg *magic = 0; 105322944501Smrg if (drmIoctl(fd, DRM_IOCTL_GET_MAGIC, &auth)) 1054fe517fc9Smrg return -errno; 105522944501Smrg *magic = auth.magic; 105622944501Smrg return 0; 105722944501Smrg} 105822944501Smrg 10596260e5d5Smrgdrm_public int drmAuthMagic(int fd, drm_magic_t magic) 106022944501Smrg{ 106122944501Smrg drm_auth_t auth; 106222944501Smrg 1063424e9256Smrg memclear(auth); 106422944501Smrg auth.magic = magic; 106522944501Smrg if (drmIoctl(fd, DRM_IOCTL_AUTH_MAGIC, &auth)) 1066fe517fc9Smrg return -errno; 106722944501Smrg return 0; 106822944501Smrg} 106922944501Smrg 107022944501Smrg/** 107122944501Smrg * Specifies a range of memory that is available for mapping by a 107222944501Smrg * non-root process. 107322944501Smrg * 107422944501Smrg * \param fd file descriptor. 107522944501Smrg * \param offset usually the physical address. The actual meaning depends of 107622944501Smrg * the \p type parameter. See below. 107722944501Smrg * \param size of the memory in bytes. 107822944501Smrg * \param type type of the memory to be mapped. 107922944501Smrg * \param flags combination of several flags to modify the function actions. 108022944501Smrg * \param handle will be set to a value that may be used as the offset 108122944501Smrg * parameter for mmap(). 1082fe517fc9Smrg * 108322944501Smrg * \return zero on success or a negative value on error. 108422944501Smrg * 108522944501Smrg * \par Mapping the frame buffer 108622944501Smrg * For the frame buffer 108722944501Smrg * - \p offset will be the physical address of the start of the frame buffer, 108822944501Smrg * - \p size will be the size of the frame buffer in bytes, and 108922944501Smrg * - \p type will be DRM_FRAME_BUFFER. 109022944501Smrg * 109122944501Smrg * \par 109222944501Smrg * The area mapped will be uncached. If MTRR support is available in the 1093fe517fc9Smrg * kernel, the frame buffer area will be set to write combining. 109422944501Smrg * 109522944501Smrg * \par Mapping the MMIO register area 109622944501Smrg * For the MMIO register area, 109722944501Smrg * - \p offset will be the physical address of the start of the register area, 109822944501Smrg * - \p size will be the size of the register area bytes, and 109922944501Smrg * - \p type will be DRM_REGISTERS. 110022944501Smrg * \par 1101fe517fc9Smrg * The area mapped will be uncached. 1102fe517fc9Smrg * 110322944501Smrg * \par Mapping the SAREA 110422944501Smrg * For the SAREA, 110522944501Smrg * - \p offset will be ignored and should be set to zero, 110622944501Smrg * - \p size will be the desired size of the SAREA in bytes, 110722944501Smrg * - \p type will be DRM_SHM. 1108fe517fc9Smrg * 110922944501Smrg * \par 111022944501Smrg * A shared memory area of the requested size will be created and locked in 111122944501Smrg * kernel memory. This area may be mapped into client-space by using the handle 1112fe517fc9Smrg * returned. 1113fe517fc9Smrg * 111422944501Smrg * \note May only be called by root. 111522944501Smrg * 111622944501Smrg * \internal 111722944501Smrg * This function is a wrapper around the DRM_IOCTL_ADD_MAP ioctl, passing 111822944501Smrg * the arguments in a drm_map structure. 111922944501Smrg */ 11206260e5d5Smrgdrm_public int drmAddMap(int fd, drm_handle_t offset, drmSize size, drmMapType type, 11216260e5d5Smrg drmMapFlags flags, drm_handle_t *handle) 112222944501Smrg{ 112322944501Smrg drm_map_t map; 112422944501Smrg 1125424e9256Smrg memclear(map); 112622944501Smrg map.offset = offset; 112722944501Smrg map.size = size; 112822944501Smrg map.type = type; 112922944501Smrg map.flags = flags; 113022944501Smrg if (drmIoctl(fd, DRM_IOCTL_ADD_MAP, &map)) 1131fe517fc9Smrg return -errno; 113222944501Smrg if (handle) 1133fe517fc9Smrg *handle = (drm_handle_t)(uintptr_t)map.handle; 113422944501Smrg return 0; 113522944501Smrg} 113622944501Smrg 11376260e5d5Smrgdrm_public int drmRmMap(int fd, drm_handle_t handle) 113822944501Smrg{ 113922944501Smrg drm_map_t map; 114022944501Smrg 1141424e9256Smrg memclear(map); 114220131375Smrg map.handle = (void *)(uintptr_t)handle; 114322944501Smrg 114422944501Smrg if(drmIoctl(fd, DRM_IOCTL_RM_MAP, &map)) 1145fe517fc9Smrg return -errno; 114622944501Smrg return 0; 114722944501Smrg} 114822944501Smrg 114922944501Smrg/** 115022944501Smrg * Make buffers available for DMA transfers. 1151fe517fc9Smrg * 115222944501Smrg * \param fd file descriptor. 115322944501Smrg * \param count number of buffers. 115422944501Smrg * \param size size of each buffer. 115522944501Smrg * \param flags buffer allocation flags. 1156fe517fc9Smrg * \param agp_offset offset in the AGP aperture 115722944501Smrg * 115822944501Smrg * \return number of buffers allocated, negative on error. 115922944501Smrg * 116022944501Smrg * \internal 116122944501Smrg * This function is a wrapper around DRM_IOCTL_ADD_BUFS ioctl. 116222944501Smrg * 116322944501Smrg * \sa drm_buf_desc. 116422944501Smrg */ 11656260e5d5Smrgdrm_public int drmAddBufs(int fd, int count, int size, drmBufDescFlags flags, 11666260e5d5Smrg int agp_offset) 116722944501Smrg{ 116822944501Smrg drm_buf_desc_t request; 116922944501Smrg 1170424e9256Smrg memclear(request); 117122944501Smrg request.count = count; 117222944501Smrg request.size = size; 117322944501Smrg request.flags = flags; 117422944501Smrg request.agp_start = agp_offset; 117522944501Smrg 117622944501Smrg if (drmIoctl(fd, DRM_IOCTL_ADD_BUFS, &request)) 1177fe517fc9Smrg return -errno; 117822944501Smrg return request.count; 117922944501Smrg} 118022944501Smrg 11816260e5d5Smrgdrm_public int drmMarkBufs(int fd, double low, double high) 118222944501Smrg{ 118322944501Smrg drm_buf_info_t info; 118422944501Smrg int i; 118522944501Smrg 1186424e9256Smrg memclear(info); 118722944501Smrg 118822944501Smrg if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info)) 1189fe517fc9Smrg return -EINVAL; 119022944501Smrg 119122944501Smrg if (!info.count) 1192fe517fc9Smrg return -EINVAL; 119322944501Smrg 119422944501Smrg if (!(info.list = drmMalloc(info.count * sizeof(*info.list)))) 1195fe517fc9Smrg return -ENOMEM; 119622944501Smrg 119722944501Smrg if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info)) { 1198fe517fc9Smrg int retval = -errno; 1199fe517fc9Smrg drmFree(info.list); 1200fe517fc9Smrg return retval; 120122944501Smrg } 120222944501Smrg 120322944501Smrg for (i = 0; i < info.count; i++) { 1204fe517fc9Smrg info.list[i].low_mark = low * info.list[i].count; 1205fe517fc9Smrg info.list[i].high_mark = high * info.list[i].count; 1206fe517fc9Smrg if (drmIoctl(fd, DRM_IOCTL_MARK_BUFS, &info.list[i])) { 1207fe517fc9Smrg int retval = -errno; 1208fe517fc9Smrg drmFree(info.list); 1209fe517fc9Smrg return retval; 1210fe517fc9Smrg } 121122944501Smrg } 121222944501Smrg drmFree(info.list); 121322944501Smrg 121422944501Smrg return 0; 121522944501Smrg} 121622944501Smrg 121722944501Smrg/** 121822944501Smrg * Free buffers. 121922944501Smrg * 122022944501Smrg * \param fd file descriptor. 122122944501Smrg * \param count number of buffers to free. 122222944501Smrg * \param list list of buffers to be freed. 122322944501Smrg * 122422944501Smrg * \return zero on success, or a negative value on failure. 1225fe517fc9Smrg * 122622944501Smrg * \note This function is primarily used for debugging. 1227fe517fc9Smrg * 122822944501Smrg * \internal 122922944501Smrg * This function is a wrapper around the DRM_IOCTL_FREE_BUFS ioctl, passing 123022944501Smrg * the arguments in a drm_buf_free structure. 123122944501Smrg */ 12326260e5d5Smrgdrm_public int drmFreeBufs(int fd, int count, int *list) 123322944501Smrg{ 123422944501Smrg drm_buf_free_t request; 123522944501Smrg 1236424e9256Smrg memclear(request); 123722944501Smrg request.count = count; 123822944501Smrg request.list = list; 123922944501Smrg if (drmIoctl(fd, DRM_IOCTL_FREE_BUFS, &request)) 1240fe517fc9Smrg return -errno; 124122944501Smrg return 0; 124222944501Smrg} 124322944501Smrg 124422944501Smrg 124522944501Smrg/** 124622944501Smrg * Close the device. 124722944501Smrg * 124822944501Smrg * \param fd file descriptor. 124922944501Smrg * 125022944501Smrg * \internal 125122944501Smrg * This function closes the file descriptor. 125222944501Smrg */ 12536260e5d5Smrgdrm_public int drmClose(int fd) 125422944501Smrg{ 125522944501Smrg unsigned long key = drmGetKeyFromFd(fd); 125622944501Smrg drmHashEntry *entry = drmGetEntry(fd); 125722944501Smrg 125822944501Smrg drmHashDestroy(entry->tagTable); 125922944501Smrg entry->fd = 0; 126022944501Smrg entry->f = NULL; 126122944501Smrg entry->tagTable = NULL; 126222944501Smrg 126322944501Smrg drmHashDelete(drmHashTable, key); 126422944501Smrg drmFree(entry); 126522944501Smrg 126622944501Smrg return close(fd); 126722944501Smrg} 126822944501Smrg 126922944501Smrg 127022944501Smrg/** 127122944501Smrg * Map a region of memory. 127222944501Smrg * 127322944501Smrg * \param fd file descriptor. 127422944501Smrg * \param handle handle returned by drmAddMap(). 127522944501Smrg * \param size size in bytes. Must match the size used by drmAddMap(). 127622944501Smrg * \param address will contain the user-space virtual address where the mapping 127722944501Smrg * begins. 127822944501Smrg * 127922944501Smrg * \return zero on success, or a negative value on failure. 1280fe517fc9Smrg * 128122944501Smrg * \internal 128222944501Smrg * This function is a wrapper for mmap(). 128322944501Smrg */ 12846260e5d5Smrgdrm_public int drmMap(int fd, drm_handle_t handle, drmSize size, 12856260e5d5Smrg drmAddressPtr address) 128622944501Smrg{ 128722944501Smrg static unsigned long pagesize_mask = 0; 128822944501Smrg 128922944501Smrg if (fd < 0) 1290fe517fc9Smrg return -EINVAL; 129122944501Smrg 129222944501Smrg if (!pagesize_mask) 1293fe517fc9Smrg pagesize_mask = getpagesize() - 1; 129422944501Smrg 129522944501Smrg size = (size + pagesize_mask) & ~pagesize_mask; 129622944501Smrg 1297a884aba1Smrg *address = drm_mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, handle); 129822944501Smrg if (*address == MAP_FAILED) 1299fe517fc9Smrg return -errno; 130022944501Smrg return 0; 130122944501Smrg} 130222944501Smrg 130322944501Smrg 130422944501Smrg/** 130522944501Smrg * Unmap mappings obtained with drmMap(). 130622944501Smrg * 130722944501Smrg * \param address address as given by drmMap(). 130822944501Smrg * \param size size in bytes. Must match the size used by drmMap(). 1309fe517fc9Smrg * 131022944501Smrg * \return zero on success, or a negative value on failure. 131122944501Smrg * 131222944501Smrg * \internal 131322944501Smrg * This function is a wrapper for munmap(). 131422944501Smrg */ 13156260e5d5Smrgdrm_public int drmUnmap(drmAddress address, drmSize size) 131622944501Smrg{ 1317a884aba1Smrg return drm_munmap(address, size); 131822944501Smrg} 131922944501Smrg 13206260e5d5Smrgdrm_public drmBufInfoPtr drmGetBufInfo(int fd) 132122944501Smrg{ 132222944501Smrg drm_buf_info_t info; 132322944501Smrg drmBufInfoPtr retval; 132422944501Smrg int i; 132522944501Smrg 1326424e9256Smrg memclear(info); 132722944501Smrg 132822944501Smrg if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info)) 1329fe517fc9Smrg return NULL; 133022944501Smrg 133122944501Smrg if (info.count) { 1332fe517fc9Smrg if (!(info.list = drmMalloc(info.count * sizeof(*info.list)))) 1333fe517fc9Smrg return NULL; 1334fe517fc9Smrg 1335fe517fc9Smrg if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info)) { 1336fe517fc9Smrg drmFree(info.list); 1337fe517fc9Smrg return NULL; 1338fe517fc9Smrg } 1339fe517fc9Smrg 1340fe517fc9Smrg retval = drmMalloc(sizeof(*retval)); 1341fe517fc9Smrg retval->count = info.count; 1342fe517fc9Smrg retval->list = drmMalloc(info.count * sizeof(*retval->list)); 1343fe517fc9Smrg for (i = 0; i < info.count; i++) { 1344fe517fc9Smrg retval->list[i].count = info.list[i].count; 1345fe517fc9Smrg retval->list[i].size = info.list[i].size; 1346fe517fc9Smrg retval->list[i].low_mark = info.list[i].low_mark; 1347fe517fc9Smrg retval->list[i].high_mark = info.list[i].high_mark; 1348fe517fc9Smrg } 1349fe517fc9Smrg drmFree(info.list); 1350fe517fc9Smrg return retval; 135122944501Smrg } 135222944501Smrg return NULL; 135322944501Smrg} 135422944501Smrg 135522944501Smrg/** 135622944501Smrg * Map all DMA buffers into client-virtual space. 135722944501Smrg * 135822944501Smrg * \param fd file descriptor. 135922944501Smrg * 136022944501Smrg * \return a pointer to a ::drmBufMap structure. 136122944501Smrg * 136222944501Smrg * \note The client may not use these buffers until obtaining buffer indices 136322944501Smrg * with drmDMA(). 1364fe517fc9Smrg * 136522944501Smrg * \internal 136622944501Smrg * This function calls the DRM_IOCTL_MAP_BUFS ioctl and copies the returned 136722944501Smrg * information about the buffers in a drm_buf_map structure into the 136822944501Smrg * client-visible data structures. 1369fe517fc9Smrg */ 13706260e5d5Smrgdrm_public drmBufMapPtr drmMapBufs(int fd) 137122944501Smrg{ 137222944501Smrg drm_buf_map_t bufs; 137322944501Smrg drmBufMapPtr retval; 137422944501Smrg int i; 137522944501Smrg 1376424e9256Smrg memclear(bufs); 137722944501Smrg if (drmIoctl(fd, DRM_IOCTL_MAP_BUFS, &bufs)) 1378fe517fc9Smrg return NULL; 137922944501Smrg 138022944501Smrg if (!bufs.count) 1381fe517fc9Smrg return NULL; 138222944501Smrg 1383fe517fc9Smrg if (!(bufs.list = drmMalloc(bufs.count * sizeof(*bufs.list)))) 1384fe517fc9Smrg return NULL; 138522944501Smrg 1386fe517fc9Smrg if (drmIoctl(fd, DRM_IOCTL_MAP_BUFS, &bufs)) { 1387fe517fc9Smrg drmFree(bufs.list); 1388fe517fc9Smrg return NULL; 1389fe517fc9Smrg } 139022944501Smrg 1391fe517fc9Smrg retval = drmMalloc(sizeof(*retval)); 1392fe517fc9Smrg retval->count = bufs.count; 1393fe517fc9Smrg retval->list = drmMalloc(bufs.count * sizeof(*retval->list)); 1394fe517fc9Smrg for (i = 0; i < bufs.count; i++) { 1395fe517fc9Smrg retval->list[i].idx = bufs.list[i].idx; 1396fe517fc9Smrg retval->list[i].total = bufs.list[i].total; 1397fe517fc9Smrg retval->list[i].used = 0; 1398fe517fc9Smrg retval->list[i].address = bufs.list[i].address; 1399fe517fc9Smrg } 140022944501Smrg 1401fe517fc9Smrg drmFree(bufs.list); 1402fe517fc9Smrg return retval; 140322944501Smrg} 140422944501Smrg 140522944501Smrg 140622944501Smrg/** 140722944501Smrg * Unmap buffers allocated with drmMapBufs(). 140822944501Smrg * 140922944501Smrg * \return zero on success, or negative value on failure. 141022944501Smrg * 141122944501Smrg * \internal 141222944501Smrg * Calls munmap() for every buffer stored in \p bufs and frees the 141322944501Smrg * memory allocated by drmMapBufs(). 141422944501Smrg */ 14156260e5d5Smrgdrm_public int drmUnmapBufs(drmBufMapPtr bufs) 141622944501Smrg{ 141722944501Smrg int i; 141822944501Smrg 141922944501Smrg for (i = 0; i < bufs->count; i++) { 1420fe517fc9Smrg drm_munmap(bufs->list[i].address, bufs->list[i].total); 142122944501Smrg } 142222944501Smrg 142322944501Smrg drmFree(bufs->list); 142422944501Smrg drmFree(bufs); 142522944501Smrg return 0; 142622944501Smrg} 142722944501Smrg 142822944501Smrg 1429fe517fc9Smrg#define DRM_DMA_RETRY 16 143022944501Smrg 143122944501Smrg/** 143222944501Smrg * Reserve DMA buffers. 143322944501Smrg * 143422944501Smrg * \param fd file descriptor. 1435fe517fc9Smrg * \param request 1436fe517fc9Smrg * 143722944501Smrg * \return zero on success, or a negative value on failure. 143822944501Smrg * 143922944501Smrg * \internal 144022944501Smrg * Assemble the arguments into a drm_dma structure and keeps issuing the 144122944501Smrg * DRM_IOCTL_DMA ioctl until success or until maximum number of retries. 144222944501Smrg */ 14436260e5d5Smrgdrm_public int drmDMA(int fd, drmDMAReqPtr request) 144422944501Smrg{ 144522944501Smrg drm_dma_t dma; 144622944501Smrg int ret, i = 0; 144722944501Smrg 144822944501Smrg dma.context = request->context; 144922944501Smrg dma.send_count = request->send_count; 145022944501Smrg dma.send_indices = request->send_list; 145122944501Smrg dma.send_sizes = request->send_sizes; 145222944501Smrg dma.flags = request->flags; 145322944501Smrg dma.request_count = request->request_count; 145422944501Smrg dma.request_size = request->request_size; 145522944501Smrg dma.request_indices = request->request_list; 145622944501Smrg dma.request_sizes = request->request_sizes; 145722944501Smrg dma.granted_count = 0; 145822944501Smrg 145922944501Smrg do { 1460fe517fc9Smrg ret = ioctl( fd, DRM_IOCTL_DMA, &dma ); 146122944501Smrg } while ( ret && errno == EAGAIN && i++ < DRM_DMA_RETRY ); 146222944501Smrg 146322944501Smrg if ( ret == 0 ) { 1464fe517fc9Smrg request->granted_count = dma.granted_count; 1465fe517fc9Smrg return 0; 146622944501Smrg } else { 1467fe517fc9Smrg return -errno; 146822944501Smrg } 146922944501Smrg} 147022944501Smrg 147122944501Smrg 147222944501Smrg/** 147322944501Smrg * Obtain heavyweight hardware lock. 147422944501Smrg * 147522944501Smrg * \param fd file descriptor. 147622944501Smrg * \param context context. 1477bf6cc7dcSmrg * \param flags flags that determine the state of the hardware when the function 147822944501Smrg * returns. 1479fe517fc9Smrg * 148022944501Smrg * \return always zero. 1481fe517fc9Smrg * 148222944501Smrg * \internal 148322944501Smrg * This function translates the arguments into a drm_lock structure and issue 148422944501Smrg * the DRM_IOCTL_LOCK ioctl until the lock is successfully acquired. 148522944501Smrg */ 14866260e5d5Smrgdrm_public int drmGetLock(int fd, drm_context_t context, drmLockFlags flags) 148722944501Smrg{ 148822944501Smrg drm_lock_t lock; 148922944501Smrg 1490424e9256Smrg memclear(lock); 149122944501Smrg lock.context = context; 149222944501Smrg lock.flags = 0; 149322944501Smrg if (flags & DRM_LOCK_READY) lock.flags |= _DRM_LOCK_READY; 149422944501Smrg if (flags & DRM_LOCK_QUIESCENT) lock.flags |= _DRM_LOCK_QUIESCENT; 149522944501Smrg if (flags & DRM_LOCK_FLUSH) lock.flags |= _DRM_LOCK_FLUSH; 149622944501Smrg if (flags & DRM_LOCK_FLUSH_ALL) lock.flags |= _DRM_LOCK_FLUSH_ALL; 149722944501Smrg if (flags & DRM_HALT_ALL_QUEUES) lock.flags |= _DRM_HALT_ALL_QUEUES; 149822944501Smrg if (flags & DRM_HALT_CUR_QUEUES) lock.flags |= _DRM_HALT_CUR_QUEUES; 149922944501Smrg 150022944501Smrg while (drmIoctl(fd, DRM_IOCTL_LOCK, &lock)) 1501fe517fc9Smrg ; 150222944501Smrg return 0; 150322944501Smrg} 150422944501Smrg 150522944501Smrg/** 150622944501Smrg * Release the hardware lock. 150722944501Smrg * 150822944501Smrg * \param fd file descriptor. 150922944501Smrg * \param context context. 1510fe517fc9Smrg * 151122944501Smrg * \return zero on success, or a negative value on failure. 1512fe517fc9Smrg * 151322944501Smrg * \internal 151422944501Smrg * This function is a wrapper around the DRM_IOCTL_UNLOCK ioctl, passing the 151522944501Smrg * argument in a drm_lock structure. 151622944501Smrg */ 15176260e5d5Smrgdrm_public int drmUnlock(int fd, drm_context_t context) 151822944501Smrg{ 151922944501Smrg drm_lock_t lock; 152022944501Smrg 1521424e9256Smrg memclear(lock); 152222944501Smrg lock.context = context; 152322944501Smrg return drmIoctl(fd, DRM_IOCTL_UNLOCK, &lock); 152422944501Smrg} 152522944501Smrg 15266260e5d5Smrgdrm_public drm_context_t *drmGetReservedContextList(int fd, int *count) 152722944501Smrg{ 152822944501Smrg drm_ctx_res_t res; 152922944501Smrg drm_ctx_t *list; 153022944501Smrg drm_context_t * retval; 153122944501Smrg int i; 153222944501Smrg 1533424e9256Smrg memclear(res); 153422944501Smrg if (drmIoctl(fd, DRM_IOCTL_RES_CTX, &res)) 1535fe517fc9Smrg return NULL; 153622944501Smrg 153722944501Smrg if (!res.count) 1538fe517fc9Smrg return NULL; 153922944501Smrg 154022944501Smrg if (!(list = drmMalloc(res.count * sizeof(*list)))) 1541fe517fc9Smrg return NULL; 15420655efefSmrg if (!(retval = drmMalloc(res.count * sizeof(*retval)))) 15430655efefSmrg goto err_free_list; 154422944501Smrg 154522944501Smrg res.contexts = list; 154622944501Smrg if (drmIoctl(fd, DRM_IOCTL_RES_CTX, &res)) 15470655efefSmrg goto err_free_context; 154822944501Smrg 154922944501Smrg for (i = 0; i < res.count; i++) 1550fe517fc9Smrg retval[i] = list[i].handle; 155122944501Smrg drmFree(list); 155222944501Smrg 155322944501Smrg *count = res.count; 155422944501Smrg return retval; 15550655efefSmrg 15560655efefSmrgerr_free_list: 15570655efefSmrg drmFree(list); 15580655efefSmrgerr_free_context: 15590655efefSmrg drmFree(retval); 15600655efefSmrg return NULL; 156122944501Smrg} 156222944501Smrg 15636260e5d5Smrgdrm_public void drmFreeReservedContextList(drm_context_t *pt) 156422944501Smrg{ 156522944501Smrg drmFree(pt); 156622944501Smrg} 156722944501Smrg 156822944501Smrg/** 156922944501Smrg * Create context. 157022944501Smrg * 157122944501Smrg * Used by the X server during GLXContext initialization. This causes 157222944501Smrg * per-context kernel-level resources to be allocated. 157322944501Smrg * 157422944501Smrg * \param fd file descriptor. 157522944501Smrg * \param handle is set on success. To be used by the client when requesting DMA 157622944501Smrg * dispatch with drmDMA(). 1577fe517fc9Smrg * 157822944501Smrg * \return zero on success, or a negative value on failure. 1579fe517fc9Smrg * 158022944501Smrg * \note May only be called by root. 1581fe517fc9Smrg * 158222944501Smrg * \internal 158322944501Smrg * This function is a wrapper around the DRM_IOCTL_ADD_CTX ioctl, passing the 158422944501Smrg * argument in a drm_ctx structure. 158522944501Smrg */ 15866260e5d5Smrgdrm_public int drmCreateContext(int fd, drm_context_t *handle) 158722944501Smrg{ 158822944501Smrg drm_ctx_t ctx; 158922944501Smrg 1590424e9256Smrg memclear(ctx); 159122944501Smrg if (drmIoctl(fd, DRM_IOCTL_ADD_CTX, &ctx)) 1592fe517fc9Smrg return -errno; 159322944501Smrg *handle = ctx.handle; 159422944501Smrg return 0; 159522944501Smrg} 159622944501Smrg 15976260e5d5Smrgdrm_public int drmSwitchToContext(int fd, drm_context_t context) 159822944501Smrg{ 159922944501Smrg drm_ctx_t ctx; 160022944501Smrg 1601424e9256Smrg memclear(ctx); 160222944501Smrg ctx.handle = context; 160322944501Smrg if (drmIoctl(fd, DRM_IOCTL_SWITCH_CTX, &ctx)) 1604fe517fc9Smrg return -errno; 160522944501Smrg return 0; 160622944501Smrg} 160722944501Smrg 16086260e5d5Smrgdrm_public int drmSetContextFlags(int fd, drm_context_t context, 16096260e5d5Smrg drm_context_tFlags flags) 161022944501Smrg{ 161122944501Smrg drm_ctx_t ctx; 161222944501Smrg 161322944501Smrg /* 161422944501Smrg * Context preserving means that no context switches are done between DMA 161522944501Smrg * buffers from one context and the next. This is suitable for use in the 161622944501Smrg * X server (which promises to maintain hardware context), or in the 161722944501Smrg * client-side library when buffers are swapped on behalf of two threads. 161822944501Smrg */ 1619424e9256Smrg memclear(ctx); 162022944501Smrg ctx.handle = context; 162122944501Smrg if (flags & DRM_CONTEXT_PRESERVED) 1622fe517fc9Smrg ctx.flags |= _DRM_CONTEXT_PRESERVED; 162322944501Smrg if (flags & DRM_CONTEXT_2DONLY) 1624fe517fc9Smrg ctx.flags |= _DRM_CONTEXT_2DONLY; 162522944501Smrg if (drmIoctl(fd, DRM_IOCTL_MOD_CTX, &ctx)) 1626fe517fc9Smrg return -errno; 162722944501Smrg return 0; 162822944501Smrg} 162922944501Smrg 16306260e5d5Smrgdrm_public int drmGetContextFlags(int fd, drm_context_t context, 16316260e5d5Smrg drm_context_tFlagsPtr flags) 163222944501Smrg{ 163322944501Smrg drm_ctx_t ctx; 163422944501Smrg 1635424e9256Smrg memclear(ctx); 163622944501Smrg ctx.handle = context; 163722944501Smrg if (drmIoctl(fd, DRM_IOCTL_GET_CTX, &ctx)) 1638fe517fc9Smrg return -errno; 163922944501Smrg *flags = 0; 164022944501Smrg if (ctx.flags & _DRM_CONTEXT_PRESERVED) 1641fe517fc9Smrg *flags |= DRM_CONTEXT_PRESERVED; 164222944501Smrg if (ctx.flags & _DRM_CONTEXT_2DONLY) 1643fe517fc9Smrg *flags |= DRM_CONTEXT_2DONLY; 164422944501Smrg return 0; 164522944501Smrg} 164622944501Smrg 164722944501Smrg/** 164822944501Smrg * Destroy context. 164922944501Smrg * 165022944501Smrg * Free any kernel-level resources allocated with drmCreateContext() associated 165122944501Smrg * with the context. 1652fe517fc9Smrg * 165322944501Smrg * \param fd file descriptor. 165422944501Smrg * \param handle handle given by drmCreateContext(). 1655fe517fc9Smrg * 165622944501Smrg * \return zero on success, or a negative value on failure. 1657fe517fc9Smrg * 165822944501Smrg * \note May only be called by root. 1659fe517fc9Smrg * 166022944501Smrg * \internal 166122944501Smrg * This function is a wrapper around the DRM_IOCTL_RM_CTX ioctl, passing the 166222944501Smrg * argument in a drm_ctx structure. 166322944501Smrg */ 16646260e5d5Smrgdrm_public int drmDestroyContext(int fd, drm_context_t handle) 166522944501Smrg{ 166622944501Smrg drm_ctx_t ctx; 1667424e9256Smrg 1668424e9256Smrg memclear(ctx); 166922944501Smrg ctx.handle = handle; 167022944501Smrg if (drmIoctl(fd, DRM_IOCTL_RM_CTX, &ctx)) 1671fe517fc9Smrg return -errno; 167222944501Smrg return 0; 167322944501Smrg} 167422944501Smrg 16756260e5d5Smrgdrm_public int drmCreateDrawable(int fd, drm_drawable_t *handle) 167622944501Smrg{ 167722944501Smrg drm_draw_t draw; 1678424e9256Smrg 1679424e9256Smrg memclear(draw); 168022944501Smrg if (drmIoctl(fd, DRM_IOCTL_ADD_DRAW, &draw)) 1681fe517fc9Smrg return -errno; 168222944501Smrg *handle = draw.handle; 168322944501Smrg return 0; 168422944501Smrg} 168522944501Smrg 16866260e5d5Smrgdrm_public int drmDestroyDrawable(int fd, drm_drawable_t handle) 168722944501Smrg{ 168822944501Smrg drm_draw_t draw; 1689424e9256Smrg 1690424e9256Smrg memclear(draw); 169122944501Smrg draw.handle = handle; 169222944501Smrg if (drmIoctl(fd, DRM_IOCTL_RM_DRAW, &draw)) 1693fe517fc9Smrg return -errno; 169422944501Smrg return 0; 169522944501Smrg} 169622944501Smrg 16976260e5d5Smrgdrm_public int drmUpdateDrawableInfo(int fd, drm_drawable_t handle, 16986260e5d5Smrg drm_drawable_info_type_t type, 16996260e5d5Smrg unsigned int num, void *data) 170022944501Smrg{ 170122944501Smrg drm_update_draw_t update; 170222944501Smrg 1703424e9256Smrg memclear(update); 170422944501Smrg update.handle = handle; 170522944501Smrg update.type = type; 170622944501Smrg update.num = num; 170722944501Smrg update.data = (unsigned long long)(unsigned long)data; 170822944501Smrg 170922944501Smrg if (drmIoctl(fd, DRM_IOCTL_UPDATE_DRAW, &update)) 1710fe517fc9Smrg return -errno; 171122944501Smrg 171222944501Smrg return 0; 171322944501Smrg} 171422944501Smrg 17156260e5d5Smrgdrm_public int drmCrtcGetSequence(int fd, uint32_t crtcId, uint64_t *sequence, 17166260e5d5Smrg uint64_t *ns) 17172b90624aSmrg{ 17182b90624aSmrg struct drm_crtc_get_sequence get_seq; 17192b90624aSmrg int ret; 17202b90624aSmrg 17212b90624aSmrg memclear(get_seq); 17222b90624aSmrg get_seq.crtc_id = crtcId; 17232b90624aSmrg ret = drmIoctl(fd, DRM_IOCTL_CRTC_GET_SEQUENCE, &get_seq); 17242b90624aSmrg if (ret) 17252b90624aSmrg return ret; 17262b90624aSmrg 17272b90624aSmrg if (sequence) 17282b90624aSmrg *sequence = get_seq.sequence; 17292b90624aSmrg if (ns) 17302b90624aSmrg *ns = get_seq.sequence_ns; 17312b90624aSmrg return 0; 17322b90624aSmrg} 17332b90624aSmrg 17346260e5d5Smrgdrm_public int drmCrtcQueueSequence(int fd, uint32_t crtcId, uint32_t flags, 17356260e5d5Smrg uint64_t sequence, 17366260e5d5Smrg uint64_t *sequence_queued, 17376260e5d5Smrg uint64_t user_data) 17382b90624aSmrg{ 17392b90624aSmrg struct drm_crtc_queue_sequence queue_seq; 17402b90624aSmrg int ret; 17412b90624aSmrg 17422b90624aSmrg memclear(queue_seq); 17432b90624aSmrg queue_seq.crtc_id = crtcId; 17442b90624aSmrg queue_seq.flags = flags; 17452b90624aSmrg queue_seq.sequence = sequence; 17462b90624aSmrg queue_seq.user_data = user_data; 17472b90624aSmrg 17482b90624aSmrg ret = drmIoctl(fd, DRM_IOCTL_CRTC_QUEUE_SEQUENCE, &queue_seq); 17492b90624aSmrg if (ret == 0 && sequence_queued) 17502b90624aSmrg *sequence_queued = queue_seq.sequence; 17512b90624aSmrg 17522b90624aSmrg return ret; 17532b90624aSmrg} 17542b90624aSmrg 175522944501Smrg/** 175622944501Smrg * Acquire the AGP device. 175722944501Smrg * 175822944501Smrg * Must be called before any of the other AGP related calls. 175922944501Smrg * 176022944501Smrg * \param fd file descriptor. 1761fe517fc9Smrg * 176222944501Smrg * \return zero on success, or a negative value on failure. 1763fe517fc9Smrg * 176422944501Smrg * \internal 176522944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_ACQUIRE ioctl. 176622944501Smrg */ 17676260e5d5Smrgdrm_public int drmAgpAcquire(int fd) 176822944501Smrg{ 176922944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_ACQUIRE, NULL)) 1770fe517fc9Smrg return -errno; 177122944501Smrg return 0; 177222944501Smrg} 177322944501Smrg 177422944501Smrg 177522944501Smrg/** 177622944501Smrg * Release the AGP device. 177722944501Smrg * 177822944501Smrg * \param fd file descriptor. 1779fe517fc9Smrg * 178022944501Smrg * \return zero on success, or a negative value on failure. 1781fe517fc9Smrg * 178222944501Smrg * \internal 178322944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_RELEASE ioctl. 178422944501Smrg */ 17856260e5d5Smrgdrm_public int drmAgpRelease(int fd) 178622944501Smrg{ 178722944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_RELEASE, NULL)) 1788fe517fc9Smrg return -errno; 178922944501Smrg return 0; 179022944501Smrg} 179122944501Smrg 179222944501Smrg 179322944501Smrg/** 179422944501Smrg * Set the AGP mode. 179522944501Smrg * 179622944501Smrg * \param fd file descriptor. 179722944501Smrg * \param mode AGP mode. 1798fe517fc9Smrg * 179922944501Smrg * \return zero on success, or a negative value on failure. 1800fe517fc9Smrg * 180122944501Smrg * \internal 180222944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_ENABLE ioctl, passing the 180322944501Smrg * argument in a drm_agp_mode structure. 180422944501Smrg */ 18056260e5d5Smrgdrm_public int drmAgpEnable(int fd, unsigned long mode) 180622944501Smrg{ 180722944501Smrg drm_agp_mode_t m; 180822944501Smrg 1809424e9256Smrg memclear(m); 181022944501Smrg m.mode = mode; 181122944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_ENABLE, &m)) 1812fe517fc9Smrg return -errno; 181322944501Smrg return 0; 181422944501Smrg} 181522944501Smrg 181622944501Smrg 181722944501Smrg/** 181822944501Smrg * Allocate a chunk of AGP memory. 181922944501Smrg * 182022944501Smrg * \param fd file descriptor. 182122944501Smrg * \param size requested memory size in bytes. Will be rounded to page boundary. 182222944501Smrg * \param type type of memory to allocate. 182322944501Smrg * \param address if not zero, will be set to the physical address of the 182422944501Smrg * allocated memory. 182522944501Smrg * \param handle on success will be set to a handle of the allocated memory. 1826fe517fc9Smrg * 182722944501Smrg * \return zero on success, or a negative value on failure. 1828fe517fc9Smrg * 182922944501Smrg * \internal 183022944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_ALLOC ioctl, passing the 183122944501Smrg * arguments in a drm_agp_buffer structure. 183222944501Smrg */ 18336260e5d5Smrgdrm_public int drmAgpAlloc(int fd, unsigned long size, unsigned long type, 18346260e5d5Smrg unsigned long *address, drm_handle_t *handle) 183522944501Smrg{ 183622944501Smrg drm_agp_buffer_t b; 183722944501Smrg 1838424e9256Smrg memclear(b); 183922944501Smrg *handle = DRM_AGP_NO_HANDLE; 184022944501Smrg b.size = size; 184122944501Smrg b.type = type; 184222944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_ALLOC, &b)) 1843fe517fc9Smrg return -errno; 184422944501Smrg if (address != 0UL) 1845fe517fc9Smrg *address = b.physical; 184622944501Smrg *handle = b.handle; 184722944501Smrg return 0; 184822944501Smrg} 184922944501Smrg 185022944501Smrg 185122944501Smrg/** 185222944501Smrg * Free a chunk of AGP memory. 185322944501Smrg * 185422944501Smrg * \param fd file descriptor. 185522944501Smrg * \param handle handle to the allocated memory, as given by drmAgpAllocate(). 1856fe517fc9Smrg * 185722944501Smrg * \return zero on success, or a negative value on failure. 1858fe517fc9Smrg * 185922944501Smrg * \internal 186022944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_FREE ioctl, passing the 186122944501Smrg * argument in a drm_agp_buffer structure. 186222944501Smrg */ 18636260e5d5Smrgdrm_public int drmAgpFree(int fd, drm_handle_t handle) 186422944501Smrg{ 186522944501Smrg drm_agp_buffer_t b; 186622944501Smrg 1867424e9256Smrg memclear(b); 186822944501Smrg b.handle = handle; 186922944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_FREE, &b)) 1870fe517fc9Smrg return -errno; 187122944501Smrg return 0; 187222944501Smrg} 187322944501Smrg 187422944501Smrg 187522944501Smrg/** 187622944501Smrg * Bind a chunk of AGP memory. 187722944501Smrg * 187822944501Smrg * \param fd file descriptor. 187922944501Smrg * \param handle handle to the allocated memory, as given by drmAgpAllocate(). 188022944501Smrg * \param offset offset in bytes. It will round to page boundary. 1881fe517fc9Smrg * 188222944501Smrg * \return zero on success, or a negative value on failure. 1883fe517fc9Smrg * 188422944501Smrg * \internal 188522944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_BIND ioctl, passing the 188622944501Smrg * argument in a drm_agp_binding structure. 188722944501Smrg */ 18886260e5d5Smrgdrm_public int drmAgpBind(int fd, drm_handle_t handle, unsigned long offset) 188922944501Smrg{ 189022944501Smrg drm_agp_binding_t b; 189122944501Smrg 1892424e9256Smrg memclear(b); 189322944501Smrg b.handle = handle; 189422944501Smrg b.offset = offset; 189522944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_BIND, &b)) 1896fe517fc9Smrg return -errno; 189722944501Smrg return 0; 189822944501Smrg} 189922944501Smrg 190022944501Smrg 190122944501Smrg/** 190222944501Smrg * Unbind a chunk of AGP memory. 190322944501Smrg * 190422944501Smrg * \param fd file descriptor. 190522944501Smrg * \param handle handle to the allocated memory, as given by drmAgpAllocate(). 1906fe517fc9Smrg * 190722944501Smrg * \return zero on success, or a negative value on failure. 1908fe517fc9Smrg * 190922944501Smrg * \internal 191022944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_UNBIND ioctl, passing 191122944501Smrg * the argument in a drm_agp_binding structure. 191222944501Smrg */ 19136260e5d5Smrgdrm_public int drmAgpUnbind(int fd, drm_handle_t handle) 191422944501Smrg{ 191522944501Smrg drm_agp_binding_t b; 191622944501Smrg 1917424e9256Smrg memclear(b); 191822944501Smrg b.handle = handle; 191922944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_UNBIND, &b)) 1920fe517fc9Smrg return -errno; 192122944501Smrg return 0; 192222944501Smrg} 192322944501Smrg 192422944501Smrg 192522944501Smrg/** 192622944501Smrg * Get AGP driver major version number. 192722944501Smrg * 192822944501Smrg * \param fd file descriptor. 1929fe517fc9Smrg * 193022944501Smrg * \return major version number on success, or a negative value on failure.. 1931fe517fc9Smrg * 193222944501Smrg * \internal 193322944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the 193422944501Smrg * necessary information in a drm_agp_info structure. 193522944501Smrg */ 19366260e5d5Smrgdrm_public int drmAgpVersionMajor(int fd) 193722944501Smrg{ 193822944501Smrg drm_agp_info_t i; 193922944501Smrg 1940424e9256Smrg memclear(i); 1941424e9256Smrg 194222944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i)) 1943fe517fc9Smrg return -errno; 194422944501Smrg return i.agp_version_major; 194522944501Smrg} 194622944501Smrg 194722944501Smrg 194822944501Smrg/** 194922944501Smrg * Get AGP driver minor version number. 195022944501Smrg * 195122944501Smrg * \param fd file descriptor. 1952fe517fc9Smrg * 195322944501Smrg * \return minor version number on success, or a negative value on failure. 1954fe517fc9Smrg * 195522944501Smrg * \internal 195622944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the 195722944501Smrg * necessary information in a drm_agp_info structure. 195822944501Smrg */ 19596260e5d5Smrgdrm_public int drmAgpVersionMinor(int fd) 196022944501Smrg{ 196122944501Smrg drm_agp_info_t i; 196222944501Smrg 1963424e9256Smrg memclear(i); 1964424e9256Smrg 196522944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i)) 1966fe517fc9Smrg return -errno; 196722944501Smrg return i.agp_version_minor; 196822944501Smrg} 196922944501Smrg 197022944501Smrg 197122944501Smrg/** 197222944501Smrg * Get AGP mode. 197322944501Smrg * 197422944501Smrg * \param fd file descriptor. 1975fe517fc9Smrg * 197622944501Smrg * \return mode on success, or zero on failure. 1977fe517fc9Smrg * 197822944501Smrg * \internal 197922944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the 198022944501Smrg * necessary information in a drm_agp_info structure. 198122944501Smrg */ 19826260e5d5Smrgdrm_public unsigned long drmAgpGetMode(int fd) 198322944501Smrg{ 198422944501Smrg drm_agp_info_t i; 198522944501Smrg 1986424e9256Smrg memclear(i); 1987424e9256Smrg 198822944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i)) 1989fe517fc9Smrg return 0; 199022944501Smrg return i.mode; 199122944501Smrg} 199222944501Smrg 199322944501Smrg 199422944501Smrg/** 199522944501Smrg * Get AGP aperture base. 199622944501Smrg * 199722944501Smrg * \param fd file descriptor. 1998fe517fc9Smrg * 199922944501Smrg * \return aperture base on success, zero on failure. 2000fe517fc9Smrg * 200122944501Smrg * \internal 200222944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the 200322944501Smrg * necessary information in a drm_agp_info structure. 200422944501Smrg */ 20056260e5d5Smrgdrm_public unsigned long drmAgpBase(int fd) 200622944501Smrg{ 200722944501Smrg drm_agp_info_t i; 200822944501Smrg 2009424e9256Smrg memclear(i); 2010424e9256Smrg 201122944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i)) 2012fe517fc9Smrg return 0; 201322944501Smrg return i.aperture_base; 201422944501Smrg} 201522944501Smrg 201622944501Smrg 201722944501Smrg/** 201822944501Smrg * Get AGP aperture size. 201922944501Smrg * 202022944501Smrg * \param fd file descriptor. 2021fe517fc9Smrg * 202222944501Smrg * \return aperture size on success, zero on failure. 2023fe517fc9Smrg * 202422944501Smrg * \internal 202522944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the 202622944501Smrg * necessary information in a drm_agp_info structure. 202722944501Smrg */ 20286260e5d5Smrgdrm_public unsigned long drmAgpSize(int fd) 202922944501Smrg{ 203022944501Smrg drm_agp_info_t i; 203122944501Smrg 2032424e9256Smrg memclear(i); 2033424e9256Smrg 203422944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i)) 2035fe517fc9Smrg return 0; 203622944501Smrg return i.aperture_size; 203722944501Smrg} 203822944501Smrg 203922944501Smrg 204022944501Smrg/** 204122944501Smrg * Get used AGP memory. 204222944501Smrg * 204322944501Smrg * \param fd file descriptor. 2044fe517fc9Smrg * 204522944501Smrg * \return memory used on success, or zero on failure. 2046fe517fc9Smrg * 204722944501Smrg * \internal 204822944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the 204922944501Smrg * necessary information in a drm_agp_info structure. 205022944501Smrg */ 20516260e5d5Smrgdrm_public unsigned long drmAgpMemoryUsed(int fd) 205222944501Smrg{ 205322944501Smrg drm_agp_info_t i; 205422944501Smrg 2055424e9256Smrg memclear(i); 2056424e9256Smrg 205722944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i)) 2058fe517fc9Smrg return 0; 205922944501Smrg return i.memory_used; 206022944501Smrg} 206122944501Smrg 206222944501Smrg 206322944501Smrg/** 206422944501Smrg * Get available AGP memory. 206522944501Smrg * 206622944501Smrg * \param fd file descriptor. 2067fe517fc9Smrg * 206822944501Smrg * \return memory available on success, or zero on failure. 2069fe517fc9Smrg * 207022944501Smrg * \internal 207122944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the 207222944501Smrg * necessary information in a drm_agp_info structure. 207322944501Smrg */ 20746260e5d5Smrgdrm_public unsigned long drmAgpMemoryAvail(int fd) 207522944501Smrg{ 207622944501Smrg drm_agp_info_t i; 207722944501Smrg 2078424e9256Smrg memclear(i); 2079424e9256Smrg 208022944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i)) 2081fe517fc9Smrg return 0; 208222944501Smrg return i.memory_allowed; 208322944501Smrg} 208422944501Smrg 208522944501Smrg 208622944501Smrg/** 208722944501Smrg * Get hardware vendor ID. 208822944501Smrg * 208922944501Smrg * \param fd file descriptor. 2090fe517fc9Smrg * 209122944501Smrg * \return vendor ID on success, or zero on failure. 2092fe517fc9Smrg * 209322944501Smrg * \internal 209422944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the 209522944501Smrg * necessary information in a drm_agp_info structure. 209622944501Smrg */ 20976260e5d5Smrgdrm_public unsigned int drmAgpVendorId(int fd) 209822944501Smrg{ 209922944501Smrg drm_agp_info_t i; 210022944501Smrg 2101424e9256Smrg memclear(i); 2102424e9256Smrg 210322944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i)) 2104fe517fc9Smrg return 0; 210522944501Smrg return i.id_vendor; 210622944501Smrg} 210722944501Smrg 210822944501Smrg 210922944501Smrg/** 211022944501Smrg * Get hardware device ID. 211122944501Smrg * 211222944501Smrg * \param fd file descriptor. 2113fe517fc9Smrg * 211422944501Smrg * \return zero on success, or zero on failure. 2115fe517fc9Smrg * 211622944501Smrg * \internal 211722944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the 211822944501Smrg * necessary information in a drm_agp_info structure. 211922944501Smrg */ 21206260e5d5Smrgdrm_public unsigned int drmAgpDeviceId(int fd) 212122944501Smrg{ 212222944501Smrg drm_agp_info_t i; 212322944501Smrg 2124424e9256Smrg memclear(i); 2125424e9256Smrg 212622944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i)) 2127fe517fc9Smrg return 0; 212822944501Smrg return i.id_device; 212922944501Smrg} 213022944501Smrg 21316260e5d5Smrgdrm_public int drmScatterGatherAlloc(int fd, unsigned long size, 21326260e5d5Smrg drm_handle_t *handle) 213322944501Smrg{ 213422944501Smrg drm_scatter_gather_t sg; 213522944501Smrg 2136424e9256Smrg memclear(sg); 2137424e9256Smrg 213822944501Smrg *handle = 0; 213922944501Smrg sg.size = size; 214022944501Smrg if (drmIoctl(fd, DRM_IOCTL_SG_ALLOC, &sg)) 2141fe517fc9Smrg return -errno; 214222944501Smrg *handle = sg.handle; 214322944501Smrg return 0; 214422944501Smrg} 214522944501Smrg 21466260e5d5Smrgdrm_public int drmScatterGatherFree(int fd, drm_handle_t handle) 214722944501Smrg{ 214822944501Smrg drm_scatter_gather_t sg; 214922944501Smrg 2150424e9256Smrg memclear(sg); 215122944501Smrg sg.handle = handle; 215222944501Smrg if (drmIoctl(fd, DRM_IOCTL_SG_FREE, &sg)) 2153fe517fc9Smrg return -errno; 215422944501Smrg return 0; 215522944501Smrg} 215622944501Smrg 215722944501Smrg/** 215822944501Smrg * Wait for VBLANK. 215922944501Smrg * 216022944501Smrg * \param fd file descriptor. 216122944501Smrg * \param vbl pointer to a drmVBlank structure. 2162fe517fc9Smrg * 216322944501Smrg * \return zero on success, or a negative value on failure. 2164fe517fc9Smrg * 216522944501Smrg * \internal 216622944501Smrg * This function is a wrapper around the DRM_IOCTL_WAIT_VBLANK ioctl. 216722944501Smrg */ 21686260e5d5Smrgdrm_public int drmWaitVBlank(int fd, drmVBlankPtr vbl) 216922944501Smrg{ 217022944501Smrg struct timespec timeout, cur; 217122944501Smrg int ret; 217222944501Smrg 217322944501Smrg ret = clock_gettime(CLOCK_MONOTONIC, &timeout); 217422944501Smrg if (ret < 0) { 2175fe517fc9Smrg fprintf(stderr, "clock_gettime failed: %s\n", strerror(errno)); 2176fe517fc9Smrg goto out; 217722944501Smrg } 217822944501Smrg timeout.tv_sec++; 217922944501Smrg 218022944501Smrg do { 218122944501Smrg ret = ioctl(fd, DRM_IOCTL_WAIT_VBLANK, vbl); 218222944501Smrg vbl->request.type &= ~DRM_VBLANK_RELATIVE; 218322944501Smrg if (ret && errno == EINTR) { 2184fe517fc9Smrg clock_gettime(CLOCK_MONOTONIC, &cur); 2185fe517fc9Smrg /* Timeout after 1s */ 2186fe517fc9Smrg if (cur.tv_sec > timeout.tv_sec + 1 || 2187fe517fc9Smrg (cur.tv_sec == timeout.tv_sec && cur.tv_nsec >= 2188fe517fc9Smrg timeout.tv_nsec)) { 2189fe517fc9Smrg errno = EBUSY; 2190fe517fc9Smrg ret = -1; 2191fe517fc9Smrg break; 2192fe517fc9Smrg } 219322944501Smrg } 219422944501Smrg } while (ret && errno == EINTR); 219522944501Smrg 219622944501Smrgout: 219722944501Smrg return ret; 219822944501Smrg} 219922944501Smrg 22006260e5d5Smrgdrm_public int drmError(int err, const char *label) 220122944501Smrg{ 220222944501Smrg switch (err) { 220322944501Smrg case DRM_ERR_NO_DEVICE: 2204fe517fc9Smrg fprintf(stderr, "%s: no device\n", label); 2205fe517fc9Smrg break; 220622944501Smrg case DRM_ERR_NO_ACCESS: 2207fe517fc9Smrg fprintf(stderr, "%s: no access\n", label); 2208fe517fc9Smrg break; 220922944501Smrg case DRM_ERR_NOT_ROOT: 2210fe517fc9Smrg fprintf(stderr, "%s: not root\n", label); 2211fe517fc9Smrg break; 221222944501Smrg case DRM_ERR_INVALID: 2213fe517fc9Smrg fprintf(stderr, "%s: invalid args\n", label); 2214fe517fc9Smrg break; 221522944501Smrg default: 2216fe517fc9Smrg if (err < 0) 2217fe517fc9Smrg err = -err; 2218fe517fc9Smrg fprintf( stderr, "%s: error %d (%s)\n", label, err, strerror(err) ); 2219fe517fc9Smrg break; 222022944501Smrg } 222122944501Smrg 222222944501Smrg return 1; 222322944501Smrg} 222422944501Smrg 222522944501Smrg/** 222622944501Smrg * Install IRQ handler. 222722944501Smrg * 222822944501Smrg * \param fd file descriptor. 222922944501Smrg * \param irq IRQ number. 2230fe517fc9Smrg * 223122944501Smrg * \return zero on success, or a negative value on failure. 2232fe517fc9Smrg * 223322944501Smrg * \internal 223422944501Smrg * This function is a wrapper around the DRM_IOCTL_CONTROL ioctl, passing the 223522944501Smrg * argument in a drm_control structure. 223622944501Smrg */ 22376260e5d5Smrgdrm_public int drmCtlInstHandler(int fd, int irq) 223822944501Smrg{ 223922944501Smrg drm_control_t ctl; 224022944501Smrg 2241424e9256Smrg memclear(ctl); 224222944501Smrg ctl.func = DRM_INST_HANDLER; 224322944501Smrg ctl.irq = irq; 224422944501Smrg if (drmIoctl(fd, DRM_IOCTL_CONTROL, &ctl)) 2245fe517fc9Smrg return -errno; 224622944501Smrg return 0; 224722944501Smrg} 224822944501Smrg 224922944501Smrg 225022944501Smrg/** 225122944501Smrg * Uninstall IRQ handler. 225222944501Smrg * 225322944501Smrg * \param fd file descriptor. 2254fe517fc9Smrg * 225522944501Smrg * \return zero on success, or a negative value on failure. 2256fe517fc9Smrg * 225722944501Smrg * \internal 225822944501Smrg * This function is a wrapper around the DRM_IOCTL_CONTROL ioctl, passing the 225922944501Smrg * argument in a drm_control structure. 226022944501Smrg */ 22616260e5d5Smrgdrm_public int drmCtlUninstHandler(int fd) 226222944501Smrg{ 226322944501Smrg drm_control_t ctl; 226422944501Smrg 2265424e9256Smrg memclear(ctl); 226622944501Smrg ctl.func = DRM_UNINST_HANDLER; 226722944501Smrg ctl.irq = 0; 226822944501Smrg if (drmIoctl(fd, DRM_IOCTL_CONTROL, &ctl)) 2269fe517fc9Smrg return -errno; 227022944501Smrg return 0; 227122944501Smrg} 227222944501Smrg 22736260e5d5Smrgdrm_public int drmFinish(int fd, int context, drmLockFlags flags) 227422944501Smrg{ 227522944501Smrg drm_lock_t lock; 227622944501Smrg 2277424e9256Smrg memclear(lock); 227822944501Smrg lock.context = context; 227922944501Smrg if (flags & DRM_LOCK_READY) lock.flags |= _DRM_LOCK_READY; 228022944501Smrg if (flags & DRM_LOCK_QUIESCENT) lock.flags |= _DRM_LOCK_QUIESCENT; 228122944501Smrg if (flags & DRM_LOCK_FLUSH) lock.flags |= _DRM_LOCK_FLUSH; 228222944501Smrg if (flags & DRM_LOCK_FLUSH_ALL) lock.flags |= _DRM_LOCK_FLUSH_ALL; 228322944501Smrg if (flags & DRM_HALT_ALL_QUEUES) lock.flags |= _DRM_HALT_ALL_QUEUES; 228422944501Smrg if (flags & DRM_HALT_CUR_QUEUES) lock.flags |= _DRM_HALT_CUR_QUEUES; 228522944501Smrg if (drmIoctl(fd, DRM_IOCTL_FINISH, &lock)) 2286fe517fc9Smrg return -errno; 228722944501Smrg return 0; 228822944501Smrg} 228922944501Smrg 229022944501Smrg/** 229122944501Smrg * Get IRQ from bus ID. 229222944501Smrg * 229322944501Smrg * \param fd file descriptor. 229422944501Smrg * \param busnum bus number. 229522944501Smrg * \param devnum device number. 229622944501Smrg * \param funcnum function number. 2297fe517fc9Smrg * 229822944501Smrg * \return IRQ number on success, or a negative value on failure. 2299fe517fc9Smrg * 230022944501Smrg * \internal 230122944501Smrg * This function is a wrapper around the DRM_IOCTL_IRQ_BUSID ioctl, passing the 230222944501Smrg * arguments in a drm_irq_busid structure. 230322944501Smrg */ 23046260e5d5Smrgdrm_public int drmGetInterruptFromBusID(int fd, int busnum, int devnum, 23056260e5d5Smrg int funcnum) 230622944501Smrg{ 230722944501Smrg drm_irq_busid_t p; 230822944501Smrg 2309424e9256Smrg memclear(p); 231022944501Smrg p.busnum = busnum; 231122944501Smrg p.devnum = devnum; 231222944501Smrg p.funcnum = funcnum; 231322944501Smrg if (drmIoctl(fd, DRM_IOCTL_IRQ_BUSID, &p)) 2314fe517fc9Smrg return -errno; 231522944501Smrg return p.irq; 231622944501Smrg} 231722944501Smrg 23186260e5d5Smrgdrm_public int drmAddContextTag(int fd, drm_context_t context, void *tag) 231922944501Smrg{ 232022944501Smrg drmHashEntry *entry = drmGetEntry(fd); 232122944501Smrg 232222944501Smrg if (drmHashInsert(entry->tagTable, context, tag)) { 2323fe517fc9Smrg drmHashDelete(entry->tagTable, context); 2324fe517fc9Smrg drmHashInsert(entry->tagTable, context, tag); 232522944501Smrg } 232622944501Smrg return 0; 232722944501Smrg} 232822944501Smrg 23296260e5d5Smrgdrm_public int drmDelContextTag(int fd, drm_context_t context) 233022944501Smrg{ 233122944501Smrg drmHashEntry *entry = drmGetEntry(fd); 233222944501Smrg 233322944501Smrg return drmHashDelete(entry->tagTable, context); 233422944501Smrg} 233522944501Smrg 23366260e5d5Smrgdrm_public void *drmGetContextTag(int fd, drm_context_t context) 233722944501Smrg{ 233822944501Smrg drmHashEntry *entry = drmGetEntry(fd); 233922944501Smrg void *value; 234022944501Smrg 234122944501Smrg if (drmHashLookup(entry->tagTable, context, &value)) 2342fe517fc9Smrg return NULL; 234322944501Smrg 234422944501Smrg return value; 234522944501Smrg} 234622944501Smrg 23476260e5d5Smrgdrm_public int drmAddContextPrivateMapping(int fd, drm_context_t ctx_id, 23486260e5d5Smrg drm_handle_t handle) 234922944501Smrg{ 235022944501Smrg drm_ctx_priv_map_t map; 235122944501Smrg 2352424e9256Smrg memclear(map); 235322944501Smrg map.ctx_id = ctx_id; 235420131375Smrg map.handle = (void *)(uintptr_t)handle; 235522944501Smrg 235622944501Smrg if (drmIoctl(fd, DRM_IOCTL_SET_SAREA_CTX, &map)) 2357fe517fc9Smrg return -errno; 235822944501Smrg return 0; 235922944501Smrg} 236022944501Smrg 23616260e5d5Smrgdrm_public int drmGetContextPrivateMapping(int fd, drm_context_t ctx_id, 23626260e5d5Smrg drm_handle_t *handle) 236322944501Smrg{ 236422944501Smrg drm_ctx_priv_map_t map; 236522944501Smrg 2366424e9256Smrg memclear(map); 236722944501Smrg map.ctx_id = ctx_id; 236822944501Smrg 236922944501Smrg if (drmIoctl(fd, DRM_IOCTL_GET_SAREA_CTX, &map)) 2370fe517fc9Smrg return -errno; 237122944501Smrg if (handle) 2372fe517fc9Smrg *handle = (drm_handle_t)(uintptr_t)map.handle; 237322944501Smrg 237422944501Smrg return 0; 237522944501Smrg} 237622944501Smrg 23776260e5d5Smrgdrm_public int drmGetMap(int fd, int idx, drm_handle_t *offset, drmSize *size, 23786260e5d5Smrg drmMapType *type, drmMapFlags *flags, 23796260e5d5Smrg drm_handle_t *handle, int *mtrr) 238022944501Smrg{ 238122944501Smrg drm_map_t map; 238222944501Smrg 2383424e9256Smrg memclear(map); 238422944501Smrg map.offset = idx; 238522944501Smrg if (drmIoctl(fd, DRM_IOCTL_GET_MAP, &map)) 2386fe517fc9Smrg return -errno; 238722944501Smrg *offset = map.offset; 238822944501Smrg *size = map.size; 238922944501Smrg *type = map.type; 239022944501Smrg *flags = map.flags; 239122944501Smrg *handle = (unsigned long)map.handle; 239222944501Smrg *mtrr = map.mtrr; 239322944501Smrg return 0; 239422944501Smrg} 239522944501Smrg 23966260e5d5Smrgdrm_public int drmGetClient(int fd, int idx, int *auth, int *pid, int *uid, 23976260e5d5Smrg unsigned long *magic, unsigned long *iocs) 239822944501Smrg{ 239922944501Smrg drm_client_t client; 240022944501Smrg 2401424e9256Smrg memclear(client); 240222944501Smrg client.idx = idx; 240322944501Smrg if (drmIoctl(fd, DRM_IOCTL_GET_CLIENT, &client)) 2404fe517fc9Smrg return -errno; 240522944501Smrg *auth = client.auth; 240622944501Smrg *pid = client.pid; 240722944501Smrg *uid = client.uid; 240822944501Smrg *magic = client.magic; 240922944501Smrg *iocs = client.iocs; 241022944501Smrg return 0; 241122944501Smrg} 241222944501Smrg 24136260e5d5Smrgdrm_public int drmGetStats(int fd, drmStatsT *stats) 241422944501Smrg{ 241522944501Smrg drm_stats_t s; 2416424e9256Smrg unsigned i; 241722944501Smrg 2418424e9256Smrg memclear(s); 241922944501Smrg if (drmIoctl(fd, DRM_IOCTL_GET_STATS, &s)) 2420fe517fc9Smrg return -errno; 242122944501Smrg 242222944501Smrg stats->count = 0; 242322944501Smrg memset(stats, 0, sizeof(*stats)); 242422944501Smrg if (s.count > sizeof(stats->data)/sizeof(stats->data[0])) 2425fe517fc9Smrg return -1; 242622944501Smrg 242722944501Smrg#define SET_VALUE \ 242822944501Smrg stats->data[i].long_format = "%-20.20s"; \ 242922944501Smrg stats->data[i].rate_format = "%8.8s"; \ 243022944501Smrg stats->data[i].isvalue = 1; \ 243122944501Smrg stats->data[i].verbose = 0 243222944501Smrg 243322944501Smrg#define SET_COUNT \ 243422944501Smrg stats->data[i].long_format = "%-20.20s"; \ 243522944501Smrg stats->data[i].rate_format = "%5.5s"; \ 243622944501Smrg stats->data[i].isvalue = 0; \ 243722944501Smrg stats->data[i].mult_names = "kgm"; \ 243822944501Smrg stats->data[i].mult = 1000; \ 243922944501Smrg stats->data[i].verbose = 0 244022944501Smrg 244122944501Smrg#define SET_BYTE \ 244222944501Smrg stats->data[i].long_format = "%-20.20s"; \ 244322944501Smrg stats->data[i].rate_format = "%5.5s"; \ 244422944501Smrg stats->data[i].isvalue = 0; \ 244522944501Smrg stats->data[i].mult_names = "KGM"; \ 244622944501Smrg stats->data[i].mult = 1024; \ 244722944501Smrg stats->data[i].verbose = 0 244822944501Smrg 244922944501Smrg 245022944501Smrg stats->count = s.count; 245122944501Smrg for (i = 0; i < s.count; i++) { 2452fe517fc9Smrg stats->data[i].value = s.data[i].value; 2453fe517fc9Smrg switch (s.data[i].type) { 2454fe517fc9Smrg case _DRM_STAT_LOCK: 2455fe517fc9Smrg stats->data[i].long_name = "Lock"; 2456fe517fc9Smrg stats->data[i].rate_name = "Lock"; 2457fe517fc9Smrg SET_VALUE; 2458fe517fc9Smrg break; 2459fe517fc9Smrg case _DRM_STAT_OPENS: 2460fe517fc9Smrg stats->data[i].long_name = "Opens"; 2461fe517fc9Smrg stats->data[i].rate_name = "O"; 2462fe517fc9Smrg SET_COUNT; 2463fe517fc9Smrg stats->data[i].verbose = 1; 2464fe517fc9Smrg break; 2465fe517fc9Smrg case _DRM_STAT_CLOSES: 2466fe517fc9Smrg stats->data[i].long_name = "Closes"; 2467fe517fc9Smrg stats->data[i].rate_name = "Lock"; 2468fe517fc9Smrg SET_COUNT; 2469fe517fc9Smrg stats->data[i].verbose = 1; 2470fe517fc9Smrg break; 2471fe517fc9Smrg case _DRM_STAT_IOCTLS: 2472fe517fc9Smrg stats->data[i].long_name = "Ioctls"; 2473fe517fc9Smrg stats->data[i].rate_name = "Ioc/s"; 2474fe517fc9Smrg SET_COUNT; 2475fe517fc9Smrg break; 2476fe517fc9Smrg case _DRM_STAT_LOCKS: 2477fe517fc9Smrg stats->data[i].long_name = "Locks"; 2478fe517fc9Smrg stats->data[i].rate_name = "Lck/s"; 2479fe517fc9Smrg SET_COUNT; 2480fe517fc9Smrg break; 2481fe517fc9Smrg case _DRM_STAT_UNLOCKS: 2482fe517fc9Smrg stats->data[i].long_name = "Unlocks"; 2483fe517fc9Smrg stats->data[i].rate_name = "Unl/s"; 2484fe517fc9Smrg SET_COUNT; 2485fe517fc9Smrg break; 2486fe517fc9Smrg case _DRM_STAT_IRQ: 2487fe517fc9Smrg stats->data[i].long_name = "IRQs"; 2488fe517fc9Smrg stats->data[i].rate_name = "IRQ/s"; 2489fe517fc9Smrg SET_COUNT; 2490fe517fc9Smrg break; 2491fe517fc9Smrg case _DRM_STAT_PRIMARY: 2492fe517fc9Smrg stats->data[i].long_name = "Primary Bytes"; 2493fe517fc9Smrg stats->data[i].rate_name = "PB/s"; 2494fe517fc9Smrg SET_BYTE; 2495fe517fc9Smrg break; 2496fe517fc9Smrg case _DRM_STAT_SECONDARY: 2497fe517fc9Smrg stats->data[i].long_name = "Secondary Bytes"; 2498fe517fc9Smrg stats->data[i].rate_name = "SB/s"; 2499fe517fc9Smrg SET_BYTE; 2500fe517fc9Smrg break; 2501fe517fc9Smrg case _DRM_STAT_DMA: 2502fe517fc9Smrg stats->data[i].long_name = "DMA"; 2503fe517fc9Smrg stats->data[i].rate_name = "DMA/s"; 2504fe517fc9Smrg SET_COUNT; 2505fe517fc9Smrg break; 2506fe517fc9Smrg case _DRM_STAT_SPECIAL: 2507fe517fc9Smrg stats->data[i].long_name = "Special DMA"; 2508fe517fc9Smrg stats->data[i].rate_name = "dma/s"; 2509fe517fc9Smrg SET_COUNT; 2510fe517fc9Smrg break; 2511fe517fc9Smrg case _DRM_STAT_MISSED: 2512fe517fc9Smrg stats->data[i].long_name = "Miss"; 2513fe517fc9Smrg stats->data[i].rate_name = "Ms/s"; 2514fe517fc9Smrg SET_COUNT; 2515fe517fc9Smrg break; 2516fe517fc9Smrg case _DRM_STAT_VALUE: 2517fe517fc9Smrg stats->data[i].long_name = "Value"; 2518fe517fc9Smrg stats->data[i].rate_name = "Value"; 2519fe517fc9Smrg SET_VALUE; 2520fe517fc9Smrg break; 2521fe517fc9Smrg case _DRM_STAT_BYTE: 2522fe517fc9Smrg stats->data[i].long_name = "Bytes"; 2523fe517fc9Smrg stats->data[i].rate_name = "B/s"; 2524fe517fc9Smrg SET_BYTE; 2525fe517fc9Smrg break; 2526fe517fc9Smrg case _DRM_STAT_COUNT: 2527fe517fc9Smrg default: 2528fe517fc9Smrg stats->data[i].long_name = "Count"; 2529fe517fc9Smrg stats->data[i].rate_name = "Cnt/s"; 2530fe517fc9Smrg SET_COUNT; 2531fe517fc9Smrg break; 2532fe517fc9Smrg } 253322944501Smrg } 253422944501Smrg return 0; 253522944501Smrg} 253622944501Smrg 253722944501Smrg/** 253822944501Smrg * Issue a set-version ioctl. 253922944501Smrg * 254022944501Smrg * \param fd file descriptor. 2541fe517fc9Smrg * \param drmCommandIndex command index 254222944501Smrg * \param data source pointer of the data to be read and written. 254322944501Smrg * \param size size of the data to be read and written. 2544fe517fc9Smrg * 254522944501Smrg * \return zero on success, or a negative value on failure. 2546fe517fc9Smrg * 254722944501Smrg * \internal 2548fe517fc9Smrg * It issues a read-write ioctl given by 254922944501Smrg * \code DRM_COMMAND_BASE + drmCommandIndex \endcode. 255022944501Smrg */ 25516260e5d5Smrgdrm_public int drmSetInterfaceVersion(int fd, drmSetVersion *version) 255222944501Smrg{ 255322944501Smrg int retcode = 0; 255422944501Smrg drm_set_version_t sv; 255522944501Smrg 2556424e9256Smrg memclear(sv); 255722944501Smrg sv.drm_di_major = version->drm_di_major; 255822944501Smrg sv.drm_di_minor = version->drm_di_minor; 255922944501Smrg sv.drm_dd_major = version->drm_dd_major; 256022944501Smrg sv.drm_dd_minor = version->drm_dd_minor; 256122944501Smrg 256222944501Smrg if (drmIoctl(fd, DRM_IOCTL_SET_VERSION, &sv)) { 2563fe517fc9Smrg retcode = -errno; 256422944501Smrg } 256522944501Smrg 256622944501Smrg version->drm_di_major = sv.drm_di_major; 256722944501Smrg version->drm_di_minor = sv.drm_di_minor; 256822944501Smrg version->drm_dd_major = sv.drm_dd_major; 256922944501Smrg version->drm_dd_minor = sv.drm_dd_minor; 257022944501Smrg 257122944501Smrg return retcode; 257222944501Smrg} 257322944501Smrg 257422944501Smrg/** 257522944501Smrg * Send a device-specific command. 257622944501Smrg * 257722944501Smrg * \param fd file descriptor. 2578fe517fc9Smrg * \param drmCommandIndex command index 2579fe517fc9Smrg * 258022944501Smrg * \return zero on success, or a negative value on failure. 2581fe517fc9Smrg * 258222944501Smrg * \internal 2583fe517fc9Smrg * It issues a ioctl given by 258422944501Smrg * \code DRM_COMMAND_BASE + drmCommandIndex \endcode. 258522944501Smrg */ 25866260e5d5Smrgdrm_public int drmCommandNone(int fd, unsigned long drmCommandIndex) 258722944501Smrg{ 258822944501Smrg unsigned long request; 258922944501Smrg 259022944501Smrg request = DRM_IO( DRM_COMMAND_BASE + drmCommandIndex); 259122944501Smrg 2592424e9256Smrg if (drmIoctl(fd, request, NULL)) { 2593fe517fc9Smrg return -errno; 259422944501Smrg } 259522944501Smrg return 0; 259622944501Smrg} 259722944501Smrg 259822944501Smrg 259922944501Smrg/** 260022944501Smrg * Send a device-specific read command. 260122944501Smrg * 260222944501Smrg * \param fd file descriptor. 2603fe517fc9Smrg * \param drmCommandIndex command index 260422944501Smrg * \param data destination pointer of the data to be read. 260522944501Smrg * \param size size of the data to be read. 2606fe517fc9Smrg * 260722944501Smrg * \return zero on success, or a negative value on failure. 260822944501Smrg * 260922944501Smrg * \internal 2610fe517fc9Smrg * It issues a read ioctl given by 261122944501Smrg * \code DRM_COMMAND_BASE + drmCommandIndex \endcode. 261222944501Smrg */ 26136260e5d5Smrgdrm_public int drmCommandRead(int fd, unsigned long drmCommandIndex, 26146260e5d5Smrg void *data, unsigned long size) 261522944501Smrg{ 261622944501Smrg unsigned long request; 261722944501Smrg 2618fe517fc9Smrg request = DRM_IOC( DRM_IOC_READ, DRM_IOCTL_BASE, 2619fe517fc9Smrg DRM_COMMAND_BASE + drmCommandIndex, size); 262022944501Smrg 262122944501Smrg if (drmIoctl(fd, request, data)) { 2622fe517fc9Smrg return -errno; 262322944501Smrg } 262422944501Smrg return 0; 262522944501Smrg} 262622944501Smrg 262722944501Smrg 262822944501Smrg/** 262922944501Smrg * Send a device-specific write command. 263022944501Smrg * 263122944501Smrg * \param fd file descriptor. 2632fe517fc9Smrg * \param drmCommandIndex command index 263322944501Smrg * \param data source pointer of the data to be written. 263422944501Smrg * \param size size of the data to be written. 2635fe517fc9Smrg * 263622944501Smrg * \return zero on success, or a negative value on failure. 2637fe517fc9Smrg * 263822944501Smrg * \internal 2639fe517fc9Smrg * It issues a write ioctl given by 264022944501Smrg * \code DRM_COMMAND_BASE + drmCommandIndex \endcode. 264122944501Smrg */ 26426260e5d5Smrgdrm_public int drmCommandWrite(int fd, unsigned long drmCommandIndex, 26436260e5d5Smrg void *data, unsigned long size) 264422944501Smrg{ 264522944501Smrg unsigned long request; 264622944501Smrg 2647fe517fc9Smrg request = DRM_IOC( DRM_IOC_WRITE, DRM_IOCTL_BASE, 2648fe517fc9Smrg DRM_COMMAND_BASE + drmCommandIndex, size); 264922944501Smrg 265022944501Smrg if (drmIoctl(fd, request, data)) { 2651fe517fc9Smrg return -errno; 265222944501Smrg } 265322944501Smrg return 0; 265422944501Smrg} 265522944501Smrg 265622944501Smrg 265722944501Smrg/** 265822944501Smrg * Send a device-specific read-write command. 265922944501Smrg * 266022944501Smrg * \param fd file descriptor. 2661fe517fc9Smrg * \param drmCommandIndex command index 266222944501Smrg * \param data source pointer of the data to be read and written. 266322944501Smrg * \param size size of the data to be read and written. 2664fe517fc9Smrg * 266522944501Smrg * \return zero on success, or a negative value on failure. 2666fe517fc9Smrg * 266722944501Smrg * \internal 2668fe517fc9Smrg * It issues a read-write ioctl given by 266922944501Smrg * \code DRM_COMMAND_BASE + drmCommandIndex \endcode. 267022944501Smrg */ 26716260e5d5Smrgdrm_public int drmCommandWriteRead(int fd, unsigned long drmCommandIndex, 26726260e5d5Smrg void *data, unsigned long size) 267322944501Smrg{ 267422944501Smrg unsigned long request; 267522944501Smrg 2676fe517fc9Smrg request = DRM_IOC( DRM_IOC_READ|DRM_IOC_WRITE, DRM_IOCTL_BASE, 2677fe517fc9Smrg DRM_COMMAND_BASE + drmCommandIndex, size); 267822944501Smrg 267922944501Smrg if (drmIoctl(fd, request, data)) 2680fe517fc9Smrg return -errno; 268122944501Smrg return 0; 268222944501Smrg} 268322944501Smrg 268422944501Smrg#define DRM_MAX_FDS 16 268522944501Smrgstatic struct { 268622944501Smrg char *BusID; 268722944501Smrg int fd; 268822944501Smrg int refcount; 2689424e9256Smrg int type; 269022944501Smrg} connection[DRM_MAX_FDS]; 269122944501Smrg 269222944501Smrgstatic int nr_fds = 0; 269322944501Smrg 26946260e5d5Smrgdrm_public int drmOpenOnce(void *unused, const char *BusID, int *newlyopened) 2695424e9256Smrg{ 2696424e9256Smrg return drmOpenOnceWithType(BusID, newlyopened, DRM_NODE_PRIMARY); 2697424e9256Smrg} 2698424e9256Smrg 26996260e5d5Smrgdrm_public int drmOpenOnceWithType(const char *BusID, int *newlyopened, 27006260e5d5Smrg int type) 270122944501Smrg{ 270222944501Smrg int i; 270322944501Smrg int fd; 2704fe517fc9Smrg 270522944501Smrg for (i = 0; i < nr_fds; i++) 2706fe517fc9Smrg if ((strcmp(BusID, connection[i].BusID) == 0) && 2707fe517fc9Smrg (connection[i].type == type)) { 2708fe517fc9Smrg connection[i].refcount++; 2709fe517fc9Smrg *newlyopened = 0; 2710fe517fc9Smrg return connection[i].fd; 2711fe517fc9Smrg } 271222944501Smrg 2713424e9256Smrg fd = drmOpenWithType(NULL, BusID, type); 2714fe517fc9Smrg if (fd < 0 || nr_fds == DRM_MAX_FDS) 2715fe517fc9Smrg return fd; 2716fe517fc9Smrg 271722944501Smrg connection[nr_fds].BusID = strdup(BusID); 271822944501Smrg connection[nr_fds].fd = fd; 271922944501Smrg connection[nr_fds].refcount = 1; 2720424e9256Smrg connection[nr_fds].type = type; 272122944501Smrg *newlyopened = 1; 272222944501Smrg 272322944501Smrg if (0) 2724fe517fc9Smrg fprintf(stderr, "saved connection %d for %s %d\n", 2725fe517fc9Smrg nr_fds, connection[nr_fds].BusID, 2726fe517fc9Smrg strcmp(BusID, connection[nr_fds].BusID)); 272722944501Smrg 272822944501Smrg nr_fds++; 272922944501Smrg 273022944501Smrg return fd; 273122944501Smrg} 273222944501Smrg 27336260e5d5Smrgdrm_public void drmCloseOnce(int fd) 273422944501Smrg{ 273522944501Smrg int i; 273622944501Smrg 273722944501Smrg for (i = 0; i < nr_fds; i++) { 2738fe517fc9Smrg if (fd == connection[i].fd) { 2739fe517fc9Smrg if (--connection[i].refcount == 0) { 2740fe517fc9Smrg drmClose(connection[i].fd); 2741fe517fc9Smrg free(connection[i].BusID); 2742fe517fc9Smrg 2743fe517fc9Smrg if (i < --nr_fds) 2744fe517fc9Smrg connection[i] = connection[nr_fds]; 2745fe517fc9Smrg 2746fe517fc9Smrg return; 2747fe517fc9Smrg } 2748fe517fc9Smrg } 274922944501Smrg } 275022944501Smrg} 275122944501Smrg 27526260e5d5Smrgdrm_public int drmSetMaster(int fd) 275322944501Smrg{ 2754fe517fc9Smrg return drmIoctl(fd, DRM_IOCTL_SET_MASTER, NULL); 275522944501Smrg} 275622944501Smrg 27576260e5d5Smrgdrm_public int drmDropMaster(int fd) 275822944501Smrg{ 2759fe517fc9Smrg return drmIoctl(fd, DRM_IOCTL_DROP_MASTER, NULL); 276022944501Smrg} 276122944501Smrg 2762bf6cc7dcSmrgdrm_public int drmIsMaster(int fd) 2763bf6cc7dcSmrg{ 2764bf6cc7dcSmrg /* Detect master by attempting something that requires master. 2765bf6cc7dcSmrg * 2766bf6cc7dcSmrg * Authenticating magic tokens requires master and 0 is an 2767bf6cc7dcSmrg * internal kernel detail which we could use. Attempting this on 2768bf6cc7dcSmrg * a master fd would fail therefore fail with EINVAL because 0 2769bf6cc7dcSmrg * is invalid. 2770bf6cc7dcSmrg * 2771bf6cc7dcSmrg * A non-master fd will fail with EACCES, as the kernel checks 2772bf6cc7dcSmrg * for master before attempting to do anything else. 2773bf6cc7dcSmrg * 2774bf6cc7dcSmrg * Since we don't want to leak implementation details, use 2775bf6cc7dcSmrg * EACCES. 2776bf6cc7dcSmrg */ 2777bf6cc7dcSmrg return drmAuthMagic(fd, 0) != -EACCES; 2778bf6cc7dcSmrg} 2779bf6cc7dcSmrg 27806260e5d5Smrgdrm_public char *drmGetDeviceNameFromFd(int fd) 278122944501Smrg{ 278287bf8e7cSmrg#ifdef __FreeBSD__ 278387bf8e7cSmrg struct stat sbuf; 278487bf8e7cSmrg int maj, min; 278587bf8e7cSmrg int nodetype; 278687bf8e7cSmrg 278787bf8e7cSmrg if (fstat(fd, &sbuf)) 278887bf8e7cSmrg return NULL; 278987bf8e7cSmrg 279087bf8e7cSmrg maj = major(sbuf.st_rdev); 279187bf8e7cSmrg min = minor(sbuf.st_rdev); 279287bf8e7cSmrg nodetype = drmGetMinorType(maj, min); 279387bf8e7cSmrg return drmGetMinorNameForFD(fd, nodetype); 279487bf8e7cSmrg#else 2795fe517fc9Smrg char name[128]; 2796fe517fc9Smrg struct stat sbuf; 2797fe517fc9Smrg dev_t d; 2798fe517fc9Smrg int i; 279922944501Smrg 2800fe517fc9Smrg /* The whole drmOpen thing is a fiasco and we need to find a way 2801fe517fc9Smrg * back to just using open(2). For now, however, lets just make 2802fe517fc9Smrg * things worse with even more ad hoc directory walking code to 2803fe517fc9Smrg * discover the device file name. */ 280422944501Smrg 2805fe517fc9Smrg fstat(fd, &sbuf); 2806fe517fc9Smrg d = sbuf.st_rdev; 280722944501Smrg 2808fe517fc9Smrg for (i = 0; i < DRM_MAX_MINOR; i++) { 2809fe517fc9Smrg snprintf(name, sizeof name, DRM_DEV_NAME, DRM_DIR_NAME, i); 2810fe517fc9Smrg if (stat(name, &sbuf) == 0 && sbuf.st_rdev == d) 2811fe517fc9Smrg break; 2812fe517fc9Smrg } 2813fe517fc9Smrg if (i == DRM_MAX_MINOR) 2814fe517fc9Smrg return NULL; 281522944501Smrg 2816fe517fc9Smrg return strdup(name); 281787bf8e7cSmrg#endif 281822944501Smrg} 281920131375Smrg 28206260e5d5Smrgstatic bool drmNodeIsDRM(int maj, int min) 28216260e5d5Smrg{ 28226260e5d5Smrg#ifdef __linux__ 28236260e5d5Smrg char path[64]; 28246260e5d5Smrg struct stat sbuf; 28256260e5d5Smrg 28266260e5d5Smrg snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device/drm", 28276260e5d5Smrg maj, min); 28286260e5d5Smrg return stat(path, &sbuf) == 0; 282987bf8e7cSmrg#elif __FreeBSD__ 283087bf8e7cSmrg char name[SPECNAMELEN]; 283187bf8e7cSmrg 283287bf8e7cSmrg if (!devname_r(makedev(maj, min), S_IFCHR, name, sizeof(name))) 283387bf8e7cSmrg return 0; 283487bf8e7cSmrg /* Handle drm/ and dri/ as both are present in different FreeBSD version 283587bf8e7cSmrg * FreeBSD on amd64/i386/powerpc external kernel modules create node in 283687bf8e7cSmrg * in /dev/drm/ and links in /dev/dri while a WIP in kernel driver creates 283787bf8e7cSmrg * only device nodes in /dev/dri/ */ 283887bf8e7cSmrg return (!strncmp(name, "drm/", 4) || !strncmp(name, "dri/", 4)); 28396260e5d5Smrg#else 28406260e5d5Smrg return maj == DRM_MAJOR; 28416260e5d5Smrg#endif 28426260e5d5Smrg} 28436260e5d5Smrg 28446260e5d5Smrgdrm_public int drmGetNodeTypeFromFd(int fd) 2845424e9256Smrg{ 2846fe517fc9Smrg struct stat sbuf; 2847fe517fc9Smrg int maj, min, type; 2848424e9256Smrg 2849fe517fc9Smrg if (fstat(fd, &sbuf)) 2850fe517fc9Smrg return -1; 2851424e9256Smrg 2852fe517fc9Smrg maj = major(sbuf.st_rdev); 2853fe517fc9Smrg min = minor(sbuf.st_rdev); 2854424e9256Smrg 28556260e5d5Smrg if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode)) { 2856fe517fc9Smrg errno = EINVAL; 2857fe517fc9Smrg return -1; 2858fe517fc9Smrg } 2859424e9256Smrg 286087bf8e7cSmrg type = drmGetMinorType(maj, min); 2861fe517fc9Smrg if (type == -1) 2862fe517fc9Smrg errno = ENODEV; 2863fe517fc9Smrg return type; 2864424e9256Smrg} 2865424e9256Smrg 28666260e5d5Smrgdrm_public int drmPrimeHandleToFD(int fd, uint32_t handle, uint32_t flags, 28676260e5d5Smrg int *prime_fd) 286820131375Smrg{ 2869fe517fc9Smrg struct drm_prime_handle args; 2870fe517fc9Smrg int ret; 287120131375Smrg 2872fe517fc9Smrg memclear(args); 2873fe517fc9Smrg args.fd = -1; 2874fe517fc9Smrg args.handle = handle; 2875fe517fc9Smrg args.flags = flags; 2876fe517fc9Smrg ret = drmIoctl(fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &args); 2877fe517fc9Smrg if (ret) 2878fe517fc9Smrg return ret; 287920131375Smrg 2880fe517fc9Smrg *prime_fd = args.fd; 2881fe517fc9Smrg return 0; 288220131375Smrg} 288320131375Smrg 28846260e5d5Smrgdrm_public int drmPrimeFDToHandle(int fd, int prime_fd, uint32_t *handle) 288520131375Smrg{ 2886fe517fc9Smrg struct drm_prime_handle args; 2887fe517fc9Smrg int ret; 288820131375Smrg 2889fe517fc9Smrg memclear(args); 2890fe517fc9Smrg args.fd = prime_fd; 2891fe517fc9Smrg ret = drmIoctl(fd, DRM_IOCTL_PRIME_FD_TO_HANDLE, &args); 2892fe517fc9Smrg if (ret) 2893fe517fc9Smrg return ret; 289420131375Smrg 2895fe517fc9Smrg *handle = args.handle; 2896fe517fc9Smrg return 0; 289720131375Smrg} 2898424e9256Smrg 2899424e9256Smrgstatic char *drmGetMinorNameForFD(int fd, int type) 2900424e9256Smrg{ 2901424e9256Smrg#ifdef __linux__ 2902fe517fc9Smrg DIR *sysdir; 29036260e5d5Smrg struct dirent *ent; 2904fe517fc9Smrg struct stat sbuf; 2905fe517fc9Smrg const char *name = drmGetMinorName(type); 2906fe517fc9Smrg int len; 2907fe517fc9Smrg char dev_name[64], buf[64]; 2908fe517fc9Smrg int maj, min; 2909fe517fc9Smrg 2910fe517fc9Smrg if (!name) 2911fe517fc9Smrg return NULL; 2912424e9256Smrg 2913fe517fc9Smrg len = strlen(name); 2914424e9256Smrg 2915fe517fc9Smrg if (fstat(fd, &sbuf)) 2916fe517fc9Smrg return NULL; 2917424e9256Smrg 2918fe517fc9Smrg maj = major(sbuf.st_rdev); 2919fe517fc9Smrg min = minor(sbuf.st_rdev); 2920424e9256Smrg 29216260e5d5Smrg if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode)) 2922fe517fc9Smrg return NULL; 2923424e9256Smrg 2924fe517fc9Smrg snprintf(buf, sizeof(buf), "/sys/dev/char/%d:%d/device/drm", maj, min); 2925424e9256Smrg 2926fe517fc9Smrg sysdir = opendir(buf); 2927fe517fc9Smrg if (!sysdir) 2928fe517fc9Smrg return NULL; 2929424e9256Smrg 29306260e5d5Smrg while ((ent = readdir(sysdir))) { 2931fe517fc9Smrg if (strncmp(ent->d_name, name, len) == 0) { 2932fe517fc9Smrg snprintf(dev_name, sizeof(dev_name), DRM_DIR_NAME "/%s", 2933fe517fc9Smrg ent->d_name); 2934424e9256Smrg 2935fe517fc9Smrg closedir(sysdir); 2936fe517fc9Smrg return strdup(dev_name); 2937fe517fc9Smrg } 2938fe517fc9Smrg } 2939424e9256Smrg 2940fe517fc9Smrg closedir(sysdir); 29416260e5d5Smrg return NULL; 294287bf8e7cSmrg#elif __FreeBSD__ 294387bf8e7cSmrg struct stat sbuf; 294487bf8e7cSmrg char dname[SPECNAMELEN]; 294587bf8e7cSmrg const char *mname; 294687bf8e7cSmrg char name[SPECNAMELEN]; 294787bf8e7cSmrg int id, maj, min, nodetype, i; 294887bf8e7cSmrg 294987bf8e7cSmrg if (fstat(fd, &sbuf)) 295087bf8e7cSmrg return NULL; 295187bf8e7cSmrg 295287bf8e7cSmrg maj = major(sbuf.st_rdev); 295387bf8e7cSmrg min = minor(sbuf.st_rdev); 295487bf8e7cSmrg 295587bf8e7cSmrg if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode)) 295687bf8e7cSmrg return NULL; 295787bf8e7cSmrg 295887bf8e7cSmrg if (!devname_r(sbuf.st_rdev, S_IFCHR, dname, sizeof(dname))) 295987bf8e7cSmrg return NULL; 296087bf8e7cSmrg 296187bf8e7cSmrg /* Handle both /dev/drm and /dev/dri 296287bf8e7cSmrg * FreeBSD on amd64/i386/powerpc external kernel modules create node in 296387bf8e7cSmrg * in /dev/drm/ and links in /dev/dri while a WIP in kernel driver creates 296487bf8e7cSmrg * only device nodes in /dev/dri/ */ 296587bf8e7cSmrg 296687bf8e7cSmrg /* Get the node type represented by fd so we can deduce the target name */ 296787bf8e7cSmrg nodetype = drmGetMinorType(maj, min); 296887bf8e7cSmrg if (nodetype == -1) 296987bf8e7cSmrg return (NULL); 297087bf8e7cSmrg mname = drmGetMinorName(type); 297187bf8e7cSmrg 297287bf8e7cSmrg for (i = 0; i < SPECNAMELEN; i++) { 297387bf8e7cSmrg if (isalpha(dname[i]) == 0 && dname[i] != '/') 297487bf8e7cSmrg break; 297587bf8e7cSmrg } 297687bf8e7cSmrg if (dname[i] == '\0') 297787bf8e7cSmrg return (NULL); 297887bf8e7cSmrg 297987bf8e7cSmrg id = (int)strtol(&dname[i], NULL, 10); 298087bf8e7cSmrg id -= drmGetMinorBase(nodetype); 298187bf8e7cSmrg snprintf(name, sizeof(name), DRM_DIR_NAME "/%s%d", mname, 298287bf8e7cSmrg id + drmGetMinorBase(type)); 298387bf8e7cSmrg 298487bf8e7cSmrg return strdup(name); 2985fe517fc9Smrg#else 29862ee35494Smrg struct stat sbuf; 29872ee35494Smrg char buf[PATH_MAX + 1]; 298882025ec7Smrg const char *dev_name = drmGetDeviceName(type); 29892ee35494Smrg unsigned int maj, min; 299082025ec7Smrg int n; 29912ee35494Smrg 29922ee35494Smrg if (fstat(fd, &sbuf)) 29932ee35494Smrg return NULL; 29942ee35494Smrg 29952ee35494Smrg maj = major(sbuf.st_rdev); 29962ee35494Smrg min = minor(sbuf.st_rdev); 29972ee35494Smrg 29986260e5d5Smrg if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode)) 29992ee35494Smrg return NULL; 30002ee35494Smrg 300182025ec7Smrg if (!dev_name) 30022ee35494Smrg return NULL; 30032ee35494Smrg 300482025ec7Smrg n = snprintf(buf, sizeof(buf), dev_name, DRM_DIR_NAME, min); 30052ee35494Smrg if (n == -1 || n >= sizeof(buf)) 30062ee35494Smrg return NULL; 30072ee35494Smrg 30082ee35494Smrg return strdup(buf); 3009424e9256Smrg#endif 3010424e9256Smrg} 3011424e9256Smrg 30126260e5d5Smrgdrm_public char *drmGetPrimaryDeviceNameFromFd(int fd) 3013424e9256Smrg{ 3014fe517fc9Smrg return drmGetMinorNameForFD(fd, DRM_NODE_PRIMARY); 3015424e9256Smrg} 3016424e9256Smrg 30176260e5d5Smrgdrm_public char *drmGetRenderDeviceNameFromFd(int fd) 3018424e9256Smrg{ 3019fe517fc9Smrg return drmGetMinorNameForFD(fd, DRM_NODE_RENDER); 3020fe517fc9Smrg} 3021fe517fc9Smrg 30222ee35494Smrg#ifdef __linux__ 30232ee35494Smrgstatic char * DRM_PRINTFLIKE(2, 3) 30242ee35494Smrgsysfs_uevent_get(const char *path, const char *fmt, ...) 30252ee35494Smrg{ 30262ee35494Smrg char filename[PATH_MAX + 1], *key, *line = NULL, *value = NULL; 30272ee35494Smrg size_t size = 0, len; 30282ee35494Smrg ssize_t num; 30292ee35494Smrg va_list ap; 30302ee35494Smrg FILE *fp; 30312ee35494Smrg 30322ee35494Smrg va_start(ap, fmt); 30332ee35494Smrg num = vasprintf(&key, fmt, ap); 30342ee35494Smrg va_end(ap); 30352ee35494Smrg len = num; 30362ee35494Smrg 30372ee35494Smrg snprintf(filename, sizeof(filename), "%s/uevent", path); 30382ee35494Smrg 30392ee35494Smrg fp = fopen(filename, "r"); 30402ee35494Smrg if (!fp) { 30412ee35494Smrg free(key); 30422ee35494Smrg return NULL; 30432ee35494Smrg } 30442ee35494Smrg 30452ee35494Smrg while ((num = getline(&line, &size, fp)) >= 0) { 30462ee35494Smrg if ((strncmp(line, key, len) == 0) && (line[len] == '=')) { 30472ee35494Smrg char *start = line + len + 1, *end = line + num - 1; 30482ee35494Smrg 30492ee35494Smrg if (*end != '\n') 30502ee35494Smrg end++; 30512ee35494Smrg 30522ee35494Smrg value = strndup(start, end - start); 30532ee35494Smrg break; 30542ee35494Smrg } 30552ee35494Smrg } 30562ee35494Smrg 30572ee35494Smrg free(line); 30582ee35494Smrg fclose(fp); 30592ee35494Smrg 30602ee35494Smrg free(key); 30612ee35494Smrg 30622ee35494Smrg return value; 30632ee35494Smrg} 30642ee35494Smrg#endif 30652ee35494Smrg 30666260e5d5Smrg/* Little white lie to avoid major rework of the existing code */ 30676260e5d5Smrg#define DRM_BUS_VIRTIO 0x10 30686260e5d5Smrg 3069fe517fc9Smrg#ifdef __linux__ 307087bf8e7cSmrgstatic int get_subsystem_type(const char *device_path) 307187bf8e7cSmrg{ 307287bf8e7cSmrg char path[PATH_MAX + 1] = ""; 3073fe517fc9Smrg char link[PATH_MAX + 1] = ""; 3074fe517fc9Smrg char *name; 30754545e80cSmrg struct { 30764545e80cSmrg const char *name; 30774545e80cSmrg int bus_type; 30784545e80cSmrg } bus_types[] = { 30794545e80cSmrg { "/pci", DRM_BUS_PCI }, 30804545e80cSmrg { "/usb", DRM_BUS_USB }, 30814545e80cSmrg { "/platform", DRM_BUS_PLATFORM }, 30824545e80cSmrg { "/spi", DRM_BUS_PLATFORM }, 30834545e80cSmrg { "/host1x", DRM_BUS_HOST1X }, 30844545e80cSmrg { "/virtio", DRM_BUS_VIRTIO }, 30854545e80cSmrg }; 3086fe517fc9Smrg 308787bf8e7cSmrg strncpy(path, device_path, PATH_MAX); 308887bf8e7cSmrg strncat(path, "/subsystem", PATH_MAX); 3089fe517fc9Smrg 3090fe517fc9Smrg if (readlink(path, link, PATH_MAX) < 0) 3091fe517fc9Smrg return -errno; 3092fe517fc9Smrg 3093fe517fc9Smrg name = strrchr(link, '/'); 3094fe517fc9Smrg if (!name) 3095fe517fc9Smrg return -EINVAL; 3096fe517fc9Smrg 30974545e80cSmrg for (unsigned i = 0; i < ARRAY_SIZE(bus_types); i++) { 30984545e80cSmrg if (strncmp(name, bus_types[i].name, strlen(bus_types[i].name)) == 0) 30994545e80cSmrg return bus_types[i].bus_type; 31004545e80cSmrg } 31016260e5d5Smrg 3102fe517fc9Smrg return -EINVAL; 310387bf8e7cSmrg} 310487bf8e7cSmrg#endif 310587bf8e7cSmrg 310687bf8e7cSmrgstatic int drmParseSubsystemType(int maj, int min) 310787bf8e7cSmrg{ 310887bf8e7cSmrg#ifdef __linux__ 310987bf8e7cSmrg char path[PATH_MAX + 1] = ""; 311087bf8e7cSmrg char real_path[PATH_MAX + 1] = ""; 311187bf8e7cSmrg int subsystem_type; 311287bf8e7cSmrg 311387bf8e7cSmrg snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min); 311487bf8e7cSmrg 311587bf8e7cSmrg subsystem_type = get_subsystem_type(path); 311687bf8e7cSmrg /* Try to get the parent (underlying) device type */ 311787bf8e7cSmrg if (subsystem_type == DRM_BUS_VIRTIO) { 311887bf8e7cSmrg /* Assume virtio-pci on error */ 311987bf8e7cSmrg if (!realpath(path, real_path)) 312087bf8e7cSmrg return DRM_BUS_VIRTIO; 312187bf8e7cSmrg strncat(path, "/..", PATH_MAX); 312287bf8e7cSmrg subsystem_type = get_subsystem_type(path); 312387bf8e7cSmrg if (subsystem_type < 0) 312487bf8e7cSmrg return DRM_BUS_VIRTIO; 312587bf8e7cSmrg } 3126a970b457Sriastradh#elif defined(__NetBSD__) 3127a970b457Sriastradh int type, fd; 3128a970b457Sriastradh drmSetVersion sv; 3129a970b457Sriastradh char *buf; 3130a970b457Sriastradh unsigned domain, bus, dev; 3131a970b457Sriastradh int func; 3132a970b457Sriastradh int ret; 3133a970b457Sriastradh 3134a970b457Sriastradh /* Get the type of device we're looking for to pick the right pathname. */ 3135a970b457Sriastradh type = drmGetMinorType(min); 3136a970b457Sriastradh if (type == -1) 3137a970b457Sriastradh return -ENODEV; 3138a970b457Sriastradh 3139a970b457Sriastradh /* Open the device. Don't try to create it if it's not there. */ 3140a970b457Sriastradh fd = drmOpenMinor(min, 0, type); 3141a970b457Sriastradh if (fd < 0) 3142a970b457Sriastradh return -errno; 3143a970b457Sriastradh 3144a970b457Sriastradh /* 3145a970b457Sriastradh * Set the interface version to 1.4 or 1.1, which has the effect of 3146a970b457Sriastradh * populating the bus id for us. 3147a970b457Sriastradh */ 3148a970b457Sriastradh sv.drm_di_major = 1; 3149a970b457Sriastradh sv.drm_di_minor = 4; 3150a970b457Sriastradh sv.drm_dd_major = -1; 3151a970b457Sriastradh sv.drm_dd_minor = -1; 3152a970b457Sriastradh if (drmSetInterfaceVersion(fd, &sv)) { 3153a970b457Sriastradh sv.drm_di_major = 1; 3154a970b457Sriastradh sv.drm_di_minor = 1; 3155a970b457Sriastradh sv.drm_dd_major = -1; 3156a970b457Sriastradh sv.drm_dd_minor = -1; 3157a970b457Sriastradh if (drmSetInterfaceVersion(fd, &sv)) { 31585046d36bSriastradh /* 31595046d36bSriastradh * We're probably not the master. Hope the master already 31605046d36bSriastradh * set the version to >=1.1 so that we can get the busid. 31615046d36bSriastradh */ 3162a970b457Sriastradh } 3163a970b457Sriastradh } 3164a970b457Sriastradh 3165a970b457Sriastradh /* Get the bus id. */ 3166a970b457Sriastradh buf = drmGetBusid(fd); 3167a970b457Sriastradh 3168a970b457Sriastradh /* We're done with the device now. */ 3169a970b457Sriastradh (void)close(fd); 3170a970b457Sriastradh 3171a970b457Sriastradh /* If there is no bus id, fail. */ 3172a970b457Sriastradh if (buf == NULL) 3173a970b457Sriastradh return -ENODEV; 3174a970b457Sriastradh 3175a970b457Sriastradh /* Find a string we know about; otherwise -EINVAL. */ 3176a970b457Sriastradh ret = -EINVAL; 317748994cb0Sriastradh if (strncmp(buf, "pci:", 4) == 0) 3178a970b457Sriastradh ret = DRM_BUS_PCI; 3179a970b457Sriastradh 3180a970b457Sriastradh /* We're done with the bus id. */ 3181a970b457Sriastradh free(buf); 3182a970b457Sriastradh 3183a970b457Sriastradh /* Success or not, we're done. */ 3184a970b457Sriastradh return ret; 31854545e80cSmrg#elif defined(__OpenBSD__) || defined(__DragonFly__) 31862ee35494Smrg return DRM_BUS_PCI; 3187fe517fc9Smrg#else 3188fe517fc9Smrg#warning "Missing implementation of drmParseSubsystemType" 3189fe517fc9Smrg return -EINVAL; 3190fe517fc9Smrg#endif 3191fe517fc9Smrg} 3192fe517fc9Smrg 319387bf8e7cSmrg#ifdef __linux__ 31946260e5d5Smrgstatic void 31956260e5d5Smrgget_pci_path(int maj, int min, char *pci_path) 31966260e5d5Smrg{ 31976260e5d5Smrg char path[PATH_MAX + 1], *term; 31986260e5d5Smrg 31996260e5d5Smrg snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min); 32006260e5d5Smrg if (!realpath(path, pci_path)) { 32016260e5d5Smrg strcpy(pci_path, path); 32026260e5d5Smrg return; 32036260e5d5Smrg } 32046260e5d5Smrg 32056260e5d5Smrg term = strrchr(pci_path, '/'); 32066260e5d5Smrg if (term && strncmp(term, "/virtio", 7) == 0) 32076260e5d5Smrg *term = 0; 32086260e5d5Smrg} 320987bf8e7cSmrg#endif 321087bf8e7cSmrg 321187bf8e7cSmrg#ifdef __FreeBSD__ 321287bf8e7cSmrgstatic int get_sysctl_pci_bus_info(int maj, int min, drmPciBusInfoPtr info) 321387bf8e7cSmrg{ 321487bf8e7cSmrg char dname[SPECNAMELEN]; 321587bf8e7cSmrg char sysctl_name[16]; 321687bf8e7cSmrg char sysctl_val[256]; 321787bf8e7cSmrg size_t sysctl_len; 321887bf8e7cSmrg int id, type, nelem; 321987bf8e7cSmrg unsigned int rdev, majmin, domain, bus, dev, func; 322087bf8e7cSmrg 322187bf8e7cSmrg rdev = makedev(maj, min); 322287bf8e7cSmrg if (!devname_r(rdev, S_IFCHR, dname, sizeof(dname))) 322387bf8e7cSmrg return -EINVAL; 322487bf8e7cSmrg 322587bf8e7cSmrg if (sscanf(dname, "drm/%d\n", &id) != 1) 322687bf8e7cSmrg return -EINVAL; 322787bf8e7cSmrg type = drmGetMinorType(maj, min); 322887bf8e7cSmrg if (type == -1) 322987bf8e7cSmrg return -EINVAL; 323087bf8e7cSmrg 323187bf8e7cSmrg /* BUG: This above section is iffy, since it mandates that a driver will 323287bf8e7cSmrg * create both card and render node. 323387bf8e7cSmrg * If it does not, the next DRM device will create card#X and 323487bf8e7cSmrg * renderD#(128+X)-1. 323587bf8e7cSmrg * This is a possibility in FreeBSD but for now there is no good way for 323687bf8e7cSmrg * obtaining the info. 323787bf8e7cSmrg */ 323887bf8e7cSmrg switch (type) { 323987bf8e7cSmrg case DRM_NODE_PRIMARY: 324087bf8e7cSmrg break; 324187bf8e7cSmrg case DRM_NODE_CONTROL: 324287bf8e7cSmrg id -= 64; 324387bf8e7cSmrg break; 324487bf8e7cSmrg case DRM_NODE_RENDER: 324587bf8e7cSmrg id -= 128; 324687bf8e7cSmrg break; 324787bf8e7cSmrg } 324887bf8e7cSmrg if (id < 0) 324987bf8e7cSmrg return -EINVAL; 325087bf8e7cSmrg 325187bf8e7cSmrg if (snprintf(sysctl_name, sizeof(sysctl_name), "hw.dri.%d.busid", id) <= 0) 325287bf8e7cSmrg return -EINVAL; 325387bf8e7cSmrg sysctl_len = sizeof(sysctl_val); 325487bf8e7cSmrg if (sysctlbyname(sysctl_name, sysctl_val, &sysctl_len, NULL, 0)) 325587bf8e7cSmrg return -EINVAL; 325687bf8e7cSmrg 325787bf8e7cSmrg #define bus_fmt "pci:%04x:%02x:%02x.%u" 325887bf8e7cSmrg 325987bf8e7cSmrg nelem = sscanf(sysctl_val, bus_fmt, &domain, &bus, &dev, &func); 326087bf8e7cSmrg if (nelem != 4) 326187bf8e7cSmrg return -EINVAL; 326287bf8e7cSmrg info->domain = domain; 326387bf8e7cSmrg info->bus = bus; 326487bf8e7cSmrg info->dev = dev; 326587bf8e7cSmrg info->func = func; 326687bf8e7cSmrg 326787bf8e7cSmrg return 0; 326887bf8e7cSmrg} 326987bf8e7cSmrg#endif 32706260e5d5Smrg 3271fe517fc9Smrgstatic int drmParsePciBusInfo(int maj, int min, drmPciBusInfoPtr info) 3272fe517fc9Smrg{ 3273fe517fc9Smrg#ifdef __linux__ 32742ee35494Smrg unsigned int domain, bus, dev, func; 32756260e5d5Smrg char pci_path[PATH_MAX + 1], *value; 32762ee35494Smrg int num; 3277fe517fc9Smrg 32786260e5d5Smrg get_pci_path(maj, min, pci_path); 3279fe517fc9Smrg 32806260e5d5Smrg value = sysfs_uevent_get(pci_path, "PCI_SLOT_NAME"); 32812ee35494Smrg if (!value) 32822ee35494Smrg return -ENOENT; 3283fe517fc9Smrg 32842ee35494Smrg num = sscanf(value, "%04x:%02x:%02x.%1u", &domain, &bus, &dev, &func); 32852ee35494Smrg free(value); 3286fe517fc9Smrg 32872ee35494Smrg if (num != 4) 3288fe517fc9Smrg return -EINVAL; 3289fe517fc9Smrg 3290fe517fc9Smrg info->domain = domain; 3291fe517fc9Smrg info->bus = bus; 3292fe517fc9Smrg info->dev = dev; 3293fe517fc9Smrg info->func = func; 3294fe517fc9Smrg 3295a970b457Sriastradh return 0; 3296a970b457Sriastradh#elif defined(__NetBSD__) 3297a970b457Sriastradh int type, fd; 3298a970b457Sriastradh drmSetVersion sv; 3299a970b457Sriastradh char *buf; 3300a970b457Sriastradh unsigned domain, bus, dev; 3301a970b457Sriastradh int func; 3302a970b457Sriastradh int ret; 3303a970b457Sriastradh 3304a970b457Sriastradh /* Get the type of device we're looking for to pick the right pathname. */ 3305a970b457Sriastradh type = drmGetMinorType(min); 3306a970b457Sriastradh if (type == -1) 3307a970b457Sriastradh return -ENODEV; 3308a970b457Sriastradh 3309a970b457Sriastradh /* Open the device. Don't try to create it if it's not there. */ 3310a970b457Sriastradh fd = drmOpenMinor(min, 0, type); 3311a970b457Sriastradh if (fd < 0) 3312a970b457Sriastradh return -errno; 3313a970b457Sriastradh 3314a970b457Sriastradh /* 3315a970b457Sriastradh * Set the interface version to 1.4 or 1.1, which has the effect of 3316a970b457Sriastradh * populating the bus id for us. 3317a970b457Sriastradh */ 3318a970b457Sriastradh sv.drm_di_major = 1; 3319a970b457Sriastradh sv.drm_di_minor = 4; 3320a970b457Sriastradh sv.drm_dd_major = -1; 3321a970b457Sriastradh sv.drm_dd_minor = -1; 3322a970b457Sriastradh if (drmSetInterfaceVersion(fd, &sv)) { 3323a970b457Sriastradh sv.drm_di_major = 1; 3324a970b457Sriastradh sv.drm_di_minor = 1; 3325a970b457Sriastradh sv.drm_dd_major = -1; 3326a970b457Sriastradh sv.drm_dd_minor = -1; 3327a970b457Sriastradh if (drmSetInterfaceVersion(fd, &sv)) { 332806815bcbSmaya /* 332906815bcbSmaya * We're probably not the master. Hope the master already 333006815bcbSmaya * set the version to >=1.1 so that we can get the busid. 333106815bcbSmaya */ 3332a970b457Sriastradh } 3333a970b457Sriastradh } 3334a970b457Sriastradh 3335a970b457Sriastradh /* Get the bus id. */ 3336a970b457Sriastradh buf = drmGetBusid(fd); 3337a970b457Sriastradh 3338a970b457Sriastradh /* We're done with the device now. */ 3339a970b457Sriastradh (void)close(fd); 3340a970b457Sriastradh 3341a970b457Sriastradh /* If there is no bus id, fail. */ 3342a970b457Sriastradh if (buf == NULL) 3343a970b457Sriastradh return -ENODEV; 3344a970b457Sriastradh 3345a970b457Sriastradh /* Parse the bus id. */ 3346a970b457Sriastradh ret = sscanf(buf, "pci:%04x:%02x:%02x.%d", &domain, &bus, &dev, &func); 3347a970b457Sriastradh 3348a970b457Sriastradh /* We're done with the bus id. */ 3349a970b457Sriastradh free(buf); 3350a970b457Sriastradh 3351a970b457Sriastradh /* If scanf didn't return 4 -- domain, bus, dev, func -- then fail. */ 3352a970b457Sriastradh if (ret != 4) 3353a970b457Sriastradh return -ENODEV; 3354a970b457Sriastradh 3355a970b457Sriastradh /* Populate the results. */ 3356a970b457Sriastradh info->domain = domain; 3357a970b457Sriastradh info->bus = bus; 3358a970b457Sriastradh info->dev = dev; 3359a970b457Sriastradh info->func = func; 3360a970b457Sriastradh 3361a970b457Sriastradh /* Success! */ 33622ee35494Smrg return 0; 33634545e80cSmrg#elif defined(__OpenBSD__) || defined(__DragonFly__) 33642ee35494Smrg struct drm_pciinfo pinfo; 33652ee35494Smrg int fd, type; 33662ee35494Smrg 336787bf8e7cSmrg type = drmGetMinorType(maj, min); 33682ee35494Smrg if (type == -1) 33692ee35494Smrg return -ENODEV; 33702ee35494Smrg 33712ee35494Smrg fd = drmOpenMinor(min, 0, type); 33722ee35494Smrg if (fd < 0) 33732ee35494Smrg return -errno; 33742ee35494Smrg 33752ee35494Smrg if (drmIoctl(fd, DRM_IOCTL_GET_PCIINFO, &pinfo)) { 33762ee35494Smrg close(fd); 33772ee35494Smrg return -errno; 33782ee35494Smrg } 33792ee35494Smrg close(fd); 33802ee35494Smrg 33812ee35494Smrg info->domain = pinfo.domain; 33822ee35494Smrg info->bus = pinfo.bus; 33832ee35494Smrg info->dev = pinfo.dev; 33842ee35494Smrg info->func = pinfo.func; 33852ee35494Smrg 3386fe517fc9Smrg return 0; 338787bf8e7cSmrg#elif __FreeBSD__ 338887bf8e7cSmrg return get_sysctl_pci_bus_info(maj, min, info); 3389fe517fc9Smrg#else 3390fe517fc9Smrg#warning "Missing implementation of drmParsePciBusInfo" 3391fe517fc9Smrg return -EINVAL; 3392fe517fc9Smrg#endif 3393fe517fc9Smrg} 3394fe517fc9Smrg 33956260e5d5Smrgdrm_public int drmDevicesEqual(drmDevicePtr a, drmDevicePtr b) 3396fe517fc9Smrg{ 3397fe517fc9Smrg if (a == NULL || b == NULL) 33980655efefSmrg return 0; 3399fe517fc9Smrg 3400fe517fc9Smrg if (a->bustype != b->bustype) 34010655efefSmrg return 0; 3402fe517fc9Smrg 3403fe517fc9Smrg switch (a->bustype) { 3404fe517fc9Smrg case DRM_BUS_PCI: 34050655efefSmrg return memcmp(a->businfo.pci, b->businfo.pci, sizeof(drmPciBusInfo)) == 0; 34062ee35494Smrg 34072ee35494Smrg case DRM_BUS_USB: 34080655efefSmrg return memcmp(a->businfo.usb, b->businfo.usb, sizeof(drmUsbBusInfo)) == 0; 34092ee35494Smrg 34102ee35494Smrg case DRM_BUS_PLATFORM: 34110655efefSmrg return memcmp(a->businfo.platform, b->businfo.platform, sizeof(drmPlatformBusInfo)) == 0; 34122ee35494Smrg 34132ee35494Smrg case DRM_BUS_HOST1X: 34140655efefSmrg return memcmp(a->businfo.host1x, b->businfo.host1x, sizeof(drmHost1xBusInfo)) == 0; 34152ee35494Smrg 3416fe517fc9Smrg default: 3417fe517fc9Smrg break; 3418fe517fc9Smrg } 3419fe517fc9Smrg 34200655efefSmrg return 0; 3421fe517fc9Smrg} 3422fe517fc9Smrg 3423fe517fc9Smrgstatic int drmGetNodeType(const char *name) 3424fe517fc9Smrg{ 3425fe517fc9Smrg if (strncmp(name, DRM_CONTROL_MINOR_NAME, 3426fe517fc9Smrg sizeof(DRM_CONTROL_MINOR_NAME ) - 1) == 0) 3427fe517fc9Smrg return DRM_NODE_CONTROL; 3428fe517fc9Smrg 3429fe517fc9Smrg if (strncmp(name, DRM_RENDER_MINOR_NAME, 3430fe517fc9Smrg sizeof(DRM_RENDER_MINOR_NAME) - 1) == 0) 3431fe517fc9Smrg return DRM_NODE_RENDER; 3432fe517fc9Smrg 343382025ec7Smrg if (strncmp(name, DRM_PRIMARY_MINOR_NAME, 343482025ec7Smrg sizeof(DRM_PRIMARY_MINOR_NAME) - 1) == 0) 343582025ec7Smrg return DRM_NODE_PRIMARY; 343682025ec7Smrg 3437fe517fc9Smrg return -EINVAL; 3438fe517fc9Smrg} 3439fe517fc9Smrg 3440fe517fc9Smrgstatic int drmGetMaxNodeName(void) 3441fe517fc9Smrg{ 3442fe517fc9Smrg return sizeof(DRM_DIR_NAME) + 3443fe517fc9Smrg MAX3(sizeof(DRM_PRIMARY_MINOR_NAME), 3444fe517fc9Smrg sizeof(DRM_CONTROL_MINOR_NAME), 3445fe517fc9Smrg sizeof(DRM_RENDER_MINOR_NAME)) + 3446fe517fc9Smrg 3 /* length of the node number */; 3447fe517fc9Smrg} 3448fe517fc9Smrg 3449fe517fc9Smrg#ifdef __linux__ 34502ee35494Smrgstatic int parse_separate_sysfs_files(int maj, int min, 34512ee35494Smrg drmPciDeviceInfoPtr device, 34522ee35494Smrg bool ignore_revision) 34532ee35494Smrg{ 34542ee35494Smrg static const char *attrs[] = { 34552ee35494Smrg "revision", /* Older kernels are missing the file, so check for it first */ 34562ee35494Smrg "vendor", 34572ee35494Smrg "device", 34582ee35494Smrg "subsystem_vendor", 34592ee35494Smrg "subsystem_device", 34602ee35494Smrg }; 34616260e5d5Smrg char path[PATH_MAX + 1], pci_path[PATH_MAX + 1]; 34622ee35494Smrg unsigned int data[ARRAY_SIZE(attrs)]; 34632ee35494Smrg FILE *fp; 34642ee35494Smrg int ret; 34652ee35494Smrg 34666260e5d5Smrg get_pci_path(maj, min, pci_path); 34676260e5d5Smrg 34682ee35494Smrg for (unsigned i = ignore_revision ? 1 : 0; i < ARRAY_SIZE(attrs); i++) { 34696260e5d5Smrg snprintf(path, PATH_MAX, "%s/%s", pci_path, attrs[i]); 34702ee35494Smrg fp = fopen(path, "r"); 34712ee35494Smrg if (!fp) 34722ee35494Smrg return -errno; 34732ee35494Smrg 34742ee35494Smrg ret = fscanf(fp, "%x", &data[i]); 34752ee35494Smrg fclose(fp); 34762ee35494Smrg if (ret != 1) 34772ee35494Smrg return -errno; 34782ee35494Smrg 34792ee35494Smrg } 34802ee35494Smrg 34812ee35494Smrg device->revision_id = ignore_revision ? 0xff : data[0] & 0xff; 34822ee35494Smrg device->vendor_id = data[1] & 0xffff; 34832ee35494Smrg device->device_id = data[2] & 0xffff; 34842ee35494Smrg device->subvendor_id = data[3] & 0xffff; 34852ee35494Smrg device->subdevice_id = data[4] & 0xffff; 34862ee35494Smrg 34872ee35494Smrg return 0; 34882ee35494Smrg} 34892ee35494Smrg 34902ee35494Smrgstatic int parse_config_sysfs_file(int maj, int min, 34912ee35494Smrg drmPciDeviceInfoPtr device) 34922ee35494Smrg{ 34936260e5d5Smrg char path[PATH_MAX + 1], pci_path[PATH_MAX + 1]; 3494fe517fc9Smrg unsigned char config[64]; 3495fe517fc9Smrg int fd, ret; 3496fe517fc9Smrg 34976260e5d5Smrg get_pci_path(maj, min, pci_path); 34986260e5d5Smrg 34996260e5d5Smrg snprintf(path, PATH_MAX, "%s/config", pci_path); 3500fe517fc9Smrg fd = open(path, O_RDONLY); 3501fe517fc9Smrg if (fd < 0) 3502fe517fc9Smrg return -errno; 3503fe517fc9Smrg 3504fe517fc9Smrg ret = read(fd, config, sizeof(config)); 3505fe517fc9Smrg close(fd); 3506fe517fc9Smrg if (ret < 0) 3507fe517fc9Smrg return -errno; 3508fe517fc9Smrg 3509fe517fc9Smrg device->vendor_id = config[0] | (config[1] << 8); 3510fe517fc9Smrg device->device_id = config[2] | (config[3] << 8); 3511fe517fc9Smrg device->revision_id = config[8]; 3512fe517fc9Smrg device->subvendor_id = config[44] | (config[45] << 8); 3513fe517fc9Smrg device->subdevice_id = config[46] | (config[47] << 8); 3514fe517fc9Smrg 35152ee35494Smrg return 0; 35162ee35494Smrg} 35172ee35494Smrg#endif 35182ee35494Smrg 35192ee35494Smrgstatic int drmParsePciDeviceInfo(int maj, int min, 35202ee35494Smrg drmPciDeviceInfoPtr device, 35212ee35494Smrg uint32_t flags) 35222ee35494Smrg{ 35232ee35494Smrg#ifdef __linux__ 35242ee35494Smrg if (!(flags & DRM_DEVICE_GET_PCI_REVISION)) 35252ee35494Smrg return parse_separate_sysfs_files(maj, min, device, true); 35262ee35494Smrg 35272ee35494Smrg if (parse_separate_sysfs_files(maj, min, device, false)) 35282ee35494Smrg return parse_config_sysfs_file(maj, min, device); 35292ee35494Smrg 35302ee35494Smrg return 0; 3531a970b457Sriastradh#elif defined(__NetBSD__) 3532a970b457Sriastradh drmPciBusInfo businfo; 3533a970b457Sriastradh char fname[PATH_MAX]; 3534a970b457Sriastradh int pcifd; 3535a970b457Sriastradh pcireg_t id, class, subsys; 3536a970b457Sriastradh int ret; 3537a970b457Sriastradh 3538a970b457Sriastradh /* Find where on the bus the device lives. */ 3539a970b457Sriastradh ret = drmParsePciBusInfo(maj, min, &businfo); 3540a970b457Sriastradh if (ret) 3541a970b457Sriastradh return ret; 3542a970b457Sriastradh 3543a970b457Sriastradh /* Open the pciN device node to get at its config registers. */ 3544a970b457Sriastradh if (snprintf(fname, sizeof fname, "/dev/pci%u", businfo.domain) 3545a970b457Sriastradh >= sizeof fname) 3546a970b457Sriastradh return -ENODEV; 3547a970b457Sriastradh if ((pcifd = open(fname, O_RDONLY)) == -1) 3548a970b457Sriastradh return -errno; 3549a970b457Sriastradh 3550f8b67707Schristos ret = -1; 3551a970b457Sriastradh /* Read the id and class pci config registers. */ 3552a970b457Sriastradh if (pcibus_conf_read(pcifd, businfo.bus, businfo.dev, businfo.func, 3553a970b457Sriastradh PCI_ID_REG, &id) == -1) 3554f8b67707Schristos goto out; 3555a970b457Sriastradh if (pcibus_conf_read(pcifd, businfo.bus, businfo.dev, businfo.func, 3556a970b457Sriastradh PCI_CLASS_REG, &class) == -1) 3557f8b67707Schristos goto out; 3558a970b457Sriastradh if (pcibus_conf_read(pcifd, businfo.bus, businfo.dev, businfo.func, 3559a970b457Sriastradh PCI_SUBSYS_ID_REG, &subsys) == -1) 3560f8b67707Schristos goto out; 3561a970b457Sriastradh 3562f8b67707Schristos ret = 0; 3563a970b457Sriastradh device->vendor_id = PCI_VENDOR(id); 3564a970b457Sriastradh device->device_id = PCI_PRODUCT(id); 3565a970b457Sriastradh device->subvendor_id = PCI_SUBSYS_VENDOR(subsys); 3566a970b457Sriastradh device->subdevice_id = PCI_SUBSYS_ID(subsys); 3567a970b457Sriastradh device->revision_id = PCI_REVISION(class); 3568f8b67707Schristosout: 3569f8b67707Schristos if (ret == -1) 3570f8b67707Schristos ret = -errno; 3571f8b67707Schristos close(pcifd); 3572f8b67707Schristos return ret; 35734545e80cSmrg#elif defined(__OpenBSD__) || defined(__DragonFly__) 35742ee35494Smrg struct drm_pciinfo pinfo; 35752ee35494Smrg int fd, type; 35762ee35494Smrg 357787bf8e7cSmrg type = drmGetMinorType(maj, min); 35782ee35494Smrg if (type == -1) 35792ee35494Smrg return -ENODEV; 35802ee35494Smrg 35812ee35494Smrg fd = drmOpenMinor(min, 0, type); 35822ee35494Smrg if (fd < 0) 35832ee35494Smrg return -errno; 35842ee35494Smrg 35852ee35494Smrg if (drmIoctl(fd, DRM_IOCTL_GET_PCIINFO, &pinfo)) { 35862ee35494Smrg close(fd); 35872ee35494Smrg return -errno; 35882ee35494Smrg } 35892ee35494Smrg close(fd); 35902ee35494Smrg 35912ee35494Smrg device->vendor_id = pinfo.vendor_id; 35922ee35494Smrg device->device_id = pinfo.device_id; 35932ee35494Smrg device->revision_id = pinfo.revision_id; 35942ee35494Smrg device->subvendor_id = pinfo.subvendor_id; 35952ee35494Smrg device->subdevice_id = pinfo.subdevice_id; 35962ee35494Smrg 359787bf8e7cSmrg return 0; 359887bf8e7cSmrg#elif __FreeBSD__ 359987bf8e7cSmrg drmPciBusInfo info; 360087bf8e7cSmrg struct pci_conf_io pc; 360187bf8e7cSmrg struct pci_match_conf patterns[1]; 360287bf8e7cSmrg struct pci_conf results[1]; 360387bf8e7cSmrg int fd, error; 360487bf8e7cSmrg 360587bf8e7cSmrg if (get_sysctl_pci_bus_info(maj, min, &info) != 0) 360687bf8e7cSmrg return -EINVAL; 360787bf8e7cSmrg 360887bf8e7cSmrg fd = open("/dev/pci", O_RDONLY, 0); 360987bf8e7cSmrg if (fd < 0) 361087bf8e7cSmrg return -errno; 361187bf8e7cSmrg 361287bf8e7cSmrg bzero(&patterns, sizeof(patterns)); 361387bf8e7cSmrg patterns[0].pc_sel.pc_domain = info.domain; 361487bf8e7cSmrg patterns[0].pc_sel.pc_bus = info.bus; 361587bf8e7cSmrg patterns[0].pc_sel.pc_dev = info.dev; 361687bf8e7cSmrg patterns[0].pc_sel.pc_func = info.func; 361787bf8e7cSmrg patterns[0].flags = PCI_GETCONF_MATCH_DOMAIN | PCI_GETCONF_MATCH_BUS 361887bf8e7cSmrg | PCI_GETCONF_MATCH_DEV | PCI_GETCONF_MATCH_FUNC; 361987bf8e7cSmrg bzero(&pc, sizeof(struct pci_conf_io)); 362087bf8e7cSmrg pc.num_patterns = 1; 362187bf8e7cSmrg pc.pat_buf_len = sizeof(patterns); 362287bf8e7cSmrg pc.patterns = patterns; 362387bf8e7cSmrg pc.match_buf_len = sizeof(results); 362487bf8e7cSmrg pc.matches = results; 362587bf8e7cSmrg 362687bf8e7cSmrg if (ioctl(fd, PCIOCGETCONF, &pc) || pc.status == PCI_GETCONF_ERROR) { 362787bf8e7cSmrg error = errno; 362887bf8e7cSmrg close(fd); 362987bf8e7cSmrg return -error; 363087bf8e7cSmrg } 363187bf8e7cSmrg close(fd); 363287bf8e7cSmrg 363387bf8e7cSmrg device->vendor_id = results[0].pc_vendor; 363487bf8e7cSmrg device->device_id = results[0].pc_device; 363587bf8e7cSmrg device->subvendor_id = results[0].pc_subvendor; 363687bf8e7cSmrg device->subdevice_id = results[0].pc_subdevice; 363787bf8e7cSmrg device->revision_id = results[0].pc_revid; 363887bf8e7cSmrg 3639fe517fc9Smrg return 0; 3640fe517fc9Smrg#else 3641fe517fc9Smrg#warning "Missing implementation of drmParsePciDeviceInfo" 3642fe517fc9Smrg return -EINVAL; 3643fe517fc9Smrg#endif 3644fe517fc9Smrg} 3645fe517fc9Smrg 36462ee35494Smrgstatic void drmFreePlatformDevice(drmDevicePtr device) 36472ee35494Smrg{ 36482ee35494Smrg if (device->deviceinfo.platform) { 36492ee35494Smrg if (device->deviceinfo.platform->compatible) { 36502ee35494Smrg char **compatible = device->deviceinfo.platform->compatible; 36512ee35494Smrg 36522ee35494Smrg while (*compatible) { 36532ee35494Smrg free(*compatible); 36542ee35494Smrg compatible++; 36552ee35494Smrg } 36562ee35494Smrg 36572ee35494Smrg free(device->deviceinfo.platform->compatible); 36582ee35494Smrg } 36592ee35494Smrg } 36602ee35494Smrg} 36612ee35494Smrg 36622ee35494Smrgstatic void drmFreeHost1xDevice(drmDevicePtr device) 36632ee35494Smrg{ 36642ee35494Smrg if (device->deviceinfo.host1x) { 36652ee35494Smrg if (device->deviceinfo.host1x->compatible) { 36662ee35494Smrg char **compatible = device->deviceinfo.host1x->compatible; 36672ee35494Smrg 36682ee35494Smrg while (*compatible) { 36692ee35494Smrg free(*compatible); 36702ee35494Smrg compatible++; 36712ee35494Smrg } 36722ee35494Smrg 36732ee35494Smrg free(device->deviceinfo.host1x->compatible); 36742ee35494Smrg } 36752ee35494Smrg } 36762ee35494Smrg} 36772ee35494Smrg 36786260e5d5Smrgdrm_public void drmFreeDevice(drmDevicePtr *device) 3679fe517fc9Smrg{ 3680fe517fc9Smrg if (device == NULL) 3681fe517fc9Smrg return; 3682fe517fc9Smrg 36832ee35494Smrg if (*device) { 36842ee35494Smrg switch ((*device)->bustype) { 36852ee35494Smrg case DRM_BUS_PLATFORM: 36862ee35494Smrg drmFreePlatformDevice(*device); 36872ee35494Smrg break; 36882ee35494Smrg 36892ee35494Smrg case DRM_BUS_HOST1X: 36902ee35494Smrg drmFreeHost1xDevice(*device); 36912ee35494Smrg break; 36922ee35494Smrg } 36932ee35494Smrg } 36942ee35494Smrg 3695fe517fc9Smrg free(*device); 3696fe517fc9Smrg *device = NULL; 3697fe517fc9Smrg} 3698fe517fc9Smrg 36996260e5d5Smrgdrm_public void drmFreeDevices(drmDevicePtr devices[], int count) 3700fe517fc9Smrg{ 3701fe517fc9Smrg int i; 3702fe517fc9Smrg 3703fe517fc9Smrg if (devices == NULL) 3704fe517fc9Smrg return; 3705fe517fc9Smrg 3706fe517fc9Smrg for (i = 0; i < count; i++) 3707fe517fc9Smrg if (devices[i]) 3708fe517fc9Smrg drmFreeDevice(&devices[i]); 3709fe517fc9Smrg} 3710fe517fc9Smrg 37112ee35494Smrgstatic drmDevicePtr drmDeviceAlloc(unsigned int type, const char *node, 37122ee35494Smrg size_t bus_size, size_t device_size, 37132ee35494Smrg char **ptrp) 3714fe517fc9Smrg{ 37152ee35494Smrg size_t max_node_length, extra, size; 37162ee35494Smrg drmDevicePtr device; 37172ee35494Smrg unsigned int i; 37182ee35494Smrg char *ptr; 3719fe517fc9Smrg 37202ee35494Smrg max_node_length = ALIGN(drmGetMaxNodeName(), sizeof(void *)); 37212ee35494Smrg extra = DRM_NODE_MAX * (sizeof(void *) + max_node_length); 3722fe517fc9Smrg 37232ee35494Smrg size = sizeof(*device) + extra + bus_size + device_size; 3724fe517fc9Smrg 37252ee35494Smrg device = calloc(1, size); 37262ee35494Smrg if (!device) 37272ee35494Smrg return NULL; 37282ee35494Smrg 37292ee35494Smrg device->available_nodes = 1 << type; 3730fe517fc9Smrg 37312ee35494Smrg ptr = (char *)device + sizeof(*device); 37322ee35494Smrg device->nodes = (char **)ptr; 37332ee35494Smrg 37342ee35494Smrg ptr += DRM_NODE_MAX * sizeof(void *); 3735fe517fc9Smrg 3736fe517fc9Smrg for (i = 0; i < DRM_NODE_MAX; i++) { 37372ee35494Smrg device->nodes[i] = ptr; 37382ee35494Smrg ptr += max_node_length; 3739fe517fc9Smrg } 3740fe517fc9Smrg 37412ee35494Smrg memcpy(device->nodes[type], node, max_node_length); 37422ee35494Smrg 37432ee35494Smrg *ptrp = ptr; 37442ee35494Smrg 37452ee35494Smrg return device; 37462ee35494Smrg} 37472ee35494Smrg 37482ee35494Smrgstatic int drmProcessPciDevice(drmDevicePtr *device, 37492ee35494Smrg const char *node, int node_type, 37502ee35494Smrg int maj, int min, bool fetch_deviceinfo, 37512ee35494Smrg uint32_t flags) 37522ee35494Smrg{ 37532ee35494Smrg drmDevicePtr dev; 37542ee35494Smrg char *addr; 37552ee35494Smrg int ret; 37562ee35494Smrg 37572ee35494Smrg dev = drmDeviceAlloc(node_type, node, sizeof(drmPciBusInfo), 37582ee35494Smrg sizeof(drmPciDeviceInfo), &addr); 37592ee35494Smrg if (!dev) 37602ee35494Smrg return -ENOMEM; 37612ee35494Smrg 37622ee35494Smrg dev->bustype = DRM_BUS_PCI; 3763fe517fc9Smrg 37642ee35494Smrg dev->businfo.pci = (drmPciBusInfoPtr)addr; 37652ee35494Smrg 37662ee35494Smrg ret = drmParsePciBusInfo(maj, min, dev->businfo.pci); 3767fe517fc9Smrg if (ret) 3768fe517fc9Smrg goto free_device; 3769fe517fc9Smrg 3770fe517fc9Smrg // Fetch the device info if the user has requested it 3771fe517fc9Smrg if (fetch_deviceinfo) { 3772fe517fc9Smrg addr += sizeof(drmPciBusInfo); 37732ee35494Smrg dev->deviceinfo.pci = (drmPciDeviceInfoPtr)addr; 3774fe517fc9Smrg 37752ee35494Smrg ret = drmParsePciDeviceInfo(maj, min, dev->deviceinfo.pci, flags); 3776fe517fc9Smrg if (ret) 3777fe517fc9Smrg goto free_device; 3778fe517fc9Smrg } 37792ee35494Smrg 37802ee35494Smrg *device = dev; 37812ee35494Smrg 3782fe517fc9Smrg return 0; 3783fe517fc9Smrg 3784fe517fc9Smrgfree_device: 37852ee35494Smrg free(dev); 37862ee35494Smrg return ret; 37872ee35494Smrg} 37882ee35494Smrg 378987bf8e7cSmrg#ifdef __linux__ 379087bf8e7cSmrgstatic int drm_usb_dev_path(int maj, int min, char *path, size_t len) 379187bf8e7cSmrg{ 379287bf8e7cSmrg char *value, *tmp_path, *slash; 379387bf8e7cSmrg 379487bf8e7cSmrg snprintf(path, len, "/sys/dev/char/%d:%d/device", maj, min); 379587bf8e7cSmrg 379687bf8e7cSmrg value = sysfs_uevent_get(path, "DEVTYPE"); 379787bf8e7cSmrg if (!value) 379887bf8e7cSmrg return -ENOENT; 379987bf8e7cSmrg 380087bf8e7cSmrg if (strcmp(value, "usb_device") == 0) 380187bf8e7cSmrg return 0; 380287bf8e7cSmrg if (strcmp(value, "usb_interface") != 0) 380387bf8e7cSmrg return -ENOTSUP; 380487bf8e7cSmrg 380587bf8e7cSmrg /* The parent of a usb_interface is a usb_device */ 380687bf8e7cSmrg 380787bf8e7cSmrg tmp_path = realpath(path, NULL); 380887bf8e7cSmrg if (!tmp_path) 380987bf8e7cSmrg return -errno; 381087bf8e7cSmrg 381187bf8e7cSmrg slash = strrchr(tmp_path, '/'); 381287bf8e7cSmrg if (!slash) { 381387bf8e7cSmrg free(tmp_path); 381487bf8e7cSmrg return -EINVAL; 381587bf8e7cSmrg } 381687bf8e7cSmrg 381787bf8e7cSmrg *slash = '\0'; 381887bf8e7cSmrg 381987bf8e7cSmrg if (snprintf(path, len, "%s", tmp_path) >= (int)len) { 382087bf8e7cSmrg free(tmp_path); 382187bf8e7cSmrg return -EINVAL; 382287bf8e7cSmrg } 382387bf8e7cSmrg 382487bf8e7cSmrg free(tmp_path); 382587bf8e7cSmrg return 0; 382687bf8e7cSmrg} 382787bf8e7cSmrg#endif 382887bf8e7cSmrg 38292ee35494Smrgstatic int drmParseUsbBusInfo(int maj, int min, drmUsbBusInfoPtr info) 38302ee35494Smrg{ 38312ee35494Smrg#ifdef __linux__ 38322ee35494Smrg char path[PATH_MAX + 1], *value; 38332ee35494Smrg unsigned int bus, dev; 38342ee35494Smrg int ret; 38352ee35494Smrg 383687bf8e7cSmrg ret = drm_usb_dev_path(maj, min, path, sizeof(path)); 383787bf8e7cSmrg if (ret < 0) 383887bf8e7cSmrg return ret; 38392ee35494Smrg 38402ee35494Smrg value = sysfs_uevent_get(path, "BUSNUM"); 38412ee35494Smrg if (!value) 38422ee35494Smrg return -ENOENT; 38432ee35494Smrg 38442ee35494Smrg ret = sscanf(value, "%03u", &bus); 38452ee35494Smrg free(value); 38462ee35494Smrg 38472ee35494Smrg if (ret <= 0) 38482ee35494Smrg return -errno; 38492ee35494Smrg 38502ee35494Smrg value = sysfs_uevent_get(path, "DEVNUM"); 38512ee35494Smrg if (!value) 38522ee35494Smrg return -ENOENT; 38532ee35494Smrg 38542ee35494Smrg ret = sscanf(value, "%03u", &dev); 38552ee35494Smrg free(value); 38562ee35494Smrg 38572ee35494Smrg if (ret <= 0) 38582ee35494Smrg return -errno; 38592ee35494Smrg 38602ee35494Smrg info->bus = bus; 38612ee35494Smrg info->dev = dev; 38622ee35494Smrg 38632ee35494Smrg return 0; 38642ee35494Smrg#else 38652ee35494Smrg#warning "Missing implementation of drmParseUsbBusInfo" 38662ee35494Smrg return -EINVAL; 38672ee35494Smrg#endif 38682ee35494Smrg} 38692ee35494Smrg 38702ee35494Smrgstatic int drmParseUsbDeviceInfo(int maj, int min, drmUsbDeviceInfoPtr info) 38712ee35494Smrg{ 38722ee35494Smrg#ifdef __linux__ 38732ee35494Smrg char path[PATH_MAX + 1], *value; 38742ee35494Smrg unsigned int vendor, product; 38752ee35494Smrg int ret; 38762ee35494Smrg 387787bf8e7cSmrg ret = drm_usb_dev_path(maj, min, path, sizeof(path)); 387887bf8e7cSmrg if (ret < 0) 387987bf8e7cSmrg return ret; 38802ee35494Smrg 38812ee35494Smrg value = sysfs_uevent_get(path, "PRODUCT"); 38822ee35494Smrg if (!value) 38832ee35494Smrg return -ENOENT; 38842ee35494Smrg 38852ee35494Smrg ret = sscanf(value, "%x/%x", &vendor, &product); 38862ee35494Smrg free(value); 38872ee35494Smrg 38882ee35494Smrg if (ret <= 0) 38892ee35494Smrg return -errno; 38902ee35494Smrg 38912ee35494Smrg info->vendor = vendor; 38922ee35494Smrg info->product = product; 38932ee35494Smrg 38942ee35494Smrg return 0; 38952ee35494Smrg#else 38962ee35494Smrg#warning "Missing implementation of drmParseUsbDeviceInfo" 38972ee35494Smrg return -EINVAL; 38982ee35494Smrg#endif 38992ee35494Smrg} 39002ee35494Smrg 39012ee35494Smrgstatic int drmProcessUsbDevice(drmDevicePtr *device, const char *node, 39022ee35494Smrg int node_type, int maj, int min, 39032ee35494Smrg bool fetch_deviceinfo, uint32_t flags) 39042ee35494Smrg{ 39052ee35494Smrg drmDevicePtr dev; 39062ee35494Smrg char *ptr; 39072ee35494Smrg int ret; 39082ee35494Smrg 39092ee35494Smrg dev = drmDeviceAlloc(node_type, node, sizeof(drmUsbBusInfo), 39102ee35494Smrg sizeof(drmUsbDeviceInfo), &ptr); 39112ee35494Smrg if (!dev) 39122ee35494Smrg return -ENOMEM; 39132ee35494Smrg 39142ee35494Smrg dev->bustype = DRM_BUS_USB; 39152ee35494Smrg 39162ee35494Smrg dev->businfo.usb = (drmUsbBusInfoPtr)ptr; 39172ee35494Smrg 39182ee35494Smrg ret = drmParseUsbBusInfo(maj, min, dev->businfo.usb); 39192ee35494Smrg if (ret < 0) 39202ee35494Smrg goto free_device; 39212ee35494Smrg 39222ee35494Smrg if (fetch_deviceinfo) { 39232ee35494Smrg ptr += sizeof(drmUsbBusInfo); 39242ee35494Smrg dev->deviceinfo.usb = (drmUsbDeviceInfoPtr)ptr; 39252ee35494Smrg 39262ee35494Smrg ret = drmParseUsbDeviceInfo(maj, min, dev->deviceinfo.usb); 39272ee35494Smrg if (ret < 0) 39282ee35494Smrg goto free_device; 39292ee35494Smrg } 39302ee35494Smrg 39312ee35494Smrg *device = dev; 39322ee35494Smrg 39332ee35494Smrg return 0; 39342ee35494Smrg 39352ee35494Smrgfree_device: 39362ee35494Smrg free(dev); 39372ee35494Smrg return ret; 39382ee35494Smrg} 39392ee35494Smrg 3940bf6cc7dcSmrgstatic int drmParseOFBusInfo(int maj, int min, char *fullname) 39412ee35494Smrg{ 39422ee35494Smrg#ifdef __linux__ 3943bf6cc7dcSmrg char path[PATH_MAX + 1], *name, *tmp_name; 39442ee35494Smrg 39452ee35494Smrg snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min); 39462ee35494Smrg 39472ee35494Smrg name = sysfs_uevent_get(path, "OF_FULLNAME"); 3948bf6cc7dcSmrg tmp_name = name; 3949bf6cc7dcSmrg if (!name) { 3950bf6cc7dcSmrg /* If the device lacks OF data, pick the MODALIAS info */ 3951bf6cc7dcSmrg name = sysfs_uevent_get(path, "MODALIAS"); 3952bf6cc7dcSmrg if (!name) 3953bf6cc7dcSmrg return -ENOENT; 3954bf6cc7dcSmrg 3955bf6cc7dcSmrg /* .. and strip the MODALIAS=[platform,usb...]: part. */ 3956bf6cc7dcSmrg tmp_name = strrchr(name, ':'); 3957bf6cc7dcSmrg if (!tmp_name) { 3958bf6cc7dcSmrg free(name); 3959bf6cc7dcSmrg return -ENOENT; 3960bf6cc7dcSmrg } 3961bf6cc7dcSmrg tmp_name++; 3962bf6cc7dcSmrg } 39632ee35494Smrg 3964bf6cc7dcSmrg strncpy(fullname, tmp_name, DRM_PLATFORM_DEVICE_NAME_LEN); 3965bf6cc7dcSmrg fullname[DRM_PLATFORM_DEVICE_NAME_LEN - 1] = '\0'; 39662ee35494Smrg free(name); 39672ee35494Smrg 39682ee35494Smrg return 0; 39692ee35494Smrg#else 3970bf6cc7dcSmrg#warning "Missing implementation of drmParseOFBusInfo" 39712ee35494Smrg return -EINVAL; 39722ee35494Smrg#endif 39732ee35494Smrg} 39742ee35494Smrg 3975bf6cc7dcSmrgstatic int drmParseOFDeviceInfo(int maj, int min, char ***compatible) 39762ee35494Smrg{ 39772ee35494Smrg#ifdef __linux__ 3978bf6cc7dcSmrg char path[PATH_MAX + 1], *value, *tmp_name; 39792ee35494Smrg unsigned int count, i; 39802ee35494Smrg int err; 39812ee35494Smrg 39822ee35494Smrg snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min); 39832ee35494Smrg 39842ee35494Smrg value = sysfs_uevent_get(path, "OF_COMPATIBLE_N"); 3985bf6cc7dcSmrg if (value) { 3986bf6cc7dcSmrg sscanf(value, "%u", &count); 3987bf6cc7dcSmrg free(value); 3988bf6cc7dcSmrg } else { 3989bf6cc7dcSmrg /* Assume one entry if the device lack OF data */ 3990bf6cc7dcSmrg count = 1; 3991bf6cc7dcSmrg } 39922ee35494Smrg 3993bf6cc7dcSmrg *compatible = calloc(count + 1, sizeof(char *)); 3994bf6cc7dcSmrg if (!*compatible) 39952ee35494Smrg return -ENOMEM; 39962ee35494Smrg 39972ee35494Smrg for (i = 0; i < count; i++) { 39982ee35494Smrg value = sysfs_uevent_get(path, "OF_COMPATIBLE_%u", i); 3999bf6cc7dcSmrg tmp_name = value; 40002ee35494Smrg if (!value) { 4001bf6cc7dcSmrg /* If the device lacks OF data, pick the MODALIAS info */ 4002bf6cc7dcSmrg value = sysfs_uevent_get(path, "MODALIAS"); 4003bf6cc7dcSmrg if (!value) { 4004bf6cc7dcSmrg err = -ENOENT; 4005bf6cc7dcSmrg goto free; 4006bf6cc7dcSmrg } 4007bf6cc7dcSmrg 4008bf6cc7dcSmrg /* .. and strip the MODALIAS=[platform,usb...]: part. */ 4009bf6cc7dcSmrg tmp_name = strrchr(value, ':'); 4010bf6cc7dcSmrg if (!tmp_name) { 4011bf6cc7dcSmrg free(value); 4012bf6cc7dcSmrg return -ENOENT; 4013bf6cc7dcSmrg } 4014bf6cc7dcSmrg tmp_name = strdup(tmp_name + 1); 4015bf6cc7dcSmrg free(value); 40162ee35494Smrg } 40172ee35494Smrg 4018bf6cc7dcSmrg (*compatible)[i] = tmp_name; 40192ee35494Smrg } 40202ee35494Smrg 40212ee35494Smrg return 0; 40222ee35494Smrg 40232ee35494Smrgfree: 40242ee35494Smrg while (i--) 4025bf6cc7dcSmrg free((*compatible)[i]); 40262ee35494Smrg 4027bf6cc7dcSmrg free(*compatible); 40282ee35494Smrg return err; 40292ee35494Smrg#else 4030bf6cc7dcSmrg#warning "Missing implementation of drmParseOFDeviceInfo" 40312ee35494Smrg return -EINVAL; 40322ee35494Smrg#endif 40332ee35494Smrg} 40342ee35494Smrg 40352ee35494Smrgstatic int drmProcessPlatformDevice(drmDevicePtr *device, 40362ee35494Smrg const char *node, int node_type, 40372ee35494Smrg int maj, int min, bool fetch_deviceinfo, 40382ee35494Smrg uint32_t flags) 40392ee35494Smrg{ 40402ee35494Smrg drmDevicePtr dev; 40412ee35494Smrg char *ptr; 40422ee35494Smrg int ret; 40432ee35494Smrg 40442ee35494Smrg dev = drmDeviceAlloc(node_type, node, sizeof(drmPlatformBusInfo), 40452ee35494Smrg sizeof(drmPlatformDeviceInfo), &ptr); 40462ee35494Smrg if (!dev) 40472ee35494Smrg return -ENOMEM; 40482ee35494Smrg 40492ee35494Smrg dev->bustype = DRM_BUS_PLATFORM; 40502ee35494Smrg 40512ee35494Smrg dev->businfo.platform = (drmPlatformBusInfoPtr)ptr; 40522ee35494Smrg 4053bf6cc7dcSmrg ret = drmParseOFBusInfo(maj, min, dev->businfo.platform->fullname); 40542ee35494Smrg if (ret < 0) 40552ee35494Smrg goto free_device; 40562ee35494Smrg 40572ee35494Smrg if (fetch_deviceinfo) { 40582ee35494Smrg ptr += sizeof(drmPlatformBusInfo); 40592ee35494Smrg dev->deviceinfo.platform = (drmPlatformDeviceInfoPtr)ptr; 40602ee35494Smrg 4061bf6cc7dcSmrg ret = drmParseOFDeviceInfo(maj, min, &dev->deviceinfo.platform->compatible); 40622ee35494Smrg if (ret < 0) 40632ee35494Smrg goto free_device; 40642ee35494Smrg } 40652ee35494Smrg 40662ee35494Smrg *device = dev; 40672ee35494Smrg 40682ee35494Smrg return 0; 40692ee35494Smrg 40702ee35494Smrgfree_device: 40712ee35494Smrg free(dev); 40722ee35494Smrg return ret; 40732ee35494Smrg} 40742ee35494Smrg 40752ee35494Smrgstatic int drmProcessHost1xDevice(drmDevicePtr *device, 40762ee35494Smrg const char *node, int node_type, 40772ee35494Smrg int maj, int min, bool fetch_deviceinfo, 40782ee35494Smrg uint32_t flags) 40792ee35494Smrg{ 40802ee35494Smrg drmDevicePtr dev; 40812ee35494Smrg char *ptr; 40822ee35494Smrg int ret; 40832ee35494Smrg 40842ee35494Smrg dev = drmDeviceAlloc(node_type, node, sizeof(drmHost1xBusInfo), 40852ee35494Smrg sizeof(drmHost1xDeviceInfo), &ptr); 40862ee35494Smrg if (!dev) 40872ee35494Smrg return -ENOMEM; 40882ee35494Smrg 40892ee35494Smrg dev->bustype = DRM_BUS_HOST1X; 40902ee35494Smrg 40912ee35494Smrg dev->businfo.host1x = (drmHost1xBusInfoPtr)ptr; 40922ee35494Smrg 4093bf6cc7dcSmrg ret = drmParseOFBusInfo(maj, min, dev->businfo.host1x->fullname); 40942ee35494Smrg if (ret < 0) 40952ee35494Smrg goto free_device; 40962ee35494Smrg 40972ee35494Smrg if (fetch_deviceinfo) { 40982ee35494Smrg ptr += sizeof(drmHost1xBusInfo); 40992ee35494Smrg dev->deviceinfo.host1x = (drmHost1xDeviceInfoPtr)ptr; 41002ee35494Smrg 4101bf6cc7dcSmrg ret = drmParseOFDeviceInfo(maj, min, &dev->deviceinfo.host1x->compatible); 41022ee35494Smrg if (ret < 0) 41032ee35494Smrg goto free_device; 41042ee35494Smrg } 41052ee35494Smrg 41062ee35494Smrg *device = dev; 41072ee35494Smrg 41082ee35494Smrg return 0; 41092ee35494Smrg 41102ee35494Smrgfree_device: 41112ee35494Smrg free(dev); 4112fe517fc9Smrg return ret; 4113fe517fc9Smrg} 4114fe517fc9Smrg 41156260e5d5Smrgstatic int 41166260e5d5Smrgprocess_device(drmDevicePtr *device, const char *d_name, 41176260e5d5Smrg int req_subsystem_type, 41186260e5d5Smrg bool fetch_deviceinfo, uint32_t flags) 41196260e5d5Smrg{ 41206260e5d5Smrg struct stat sbuf; 41216260e5d5Smrg char node[PATH_MAX + 1]; 41226260e5d5Smrg int node_type, subsystem_type; 41236260e5d5Smrg unsigned int maj, min; 41246260e5d5Smrg 41256260e5d5Smrg node_type = drmGetNodeType(d_name); 41266260e5d5Smrg if (node_type < 0) 41276260e5d5Smrg return -1; 41286260e5d5Smrg 41296260e5d5Smrg snprintf(node, PATH_MAX, "%s/%s", DRM_DIR_NAME, d_name); 41306260e5d5Smrg if (stat(node, &sbuf)) 41316260e5d5Smrg return -1; 41326260e5d5Smrg 41336260e5d5Smrg maj = major(sbuf.st_rdev); 41346260e5d5Smrg min = minor(sbuf.st_rdev); 41356260e5d5Smrg 41366260e5d5Smrg if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode)) 41376260e5d5Smrg return -1; 41386260e5d5Smrg 41396260e5d5Smrg subsystem_type = drmParseSubsystemType(maj, min); 41406260e5d5Smrg if (req_subsystem_type != -1 && req_subsystem_type != subsystem_type) 41416260e5d5Smrg return -1; 41426260e5d5Smrg 41436260e5d5Smrg switch (subsystem_type) { 41446260e5d5Smrg case DRM_BUS_PCI: 41456260e5d5Smrg case DRM_BUS_VIRTIO: 41466260e5d5Smrg return drmProcessPciDevice(device, node, node_type, maj, min, 41476260e5d5Smrg fetch_deviceinfo, flags); 41486260e5d5Smrg case DRM_BUS_USB: 41496260e5d5Smrg return drmProcessUsbDevice(device, node, node_type, maj, min, 41506260e5d5Smrg fetch_deviceinfo, flags); 41516260e5d5Smrg case DRM_BUS_PLATFORM: 41526260e5d5Smrg return drmProcessPlatformDevice(device, node, node_type, maj, min, 41536260e5d5Smrg fetch_deviceinfo, flags); 41546260e5d5Smrg case DRM_BUS_HOST1X: 41556260e5d5Smrg return drmProcessHost1xDevice(device, node, node_type, maj, min, 41566260e5d5Smrg fetch_deviceinfo, flags); 41576260e5d5Smrg default: 41586260e5d5Smrg return -1; 41596260e5d5Smrg } 41606260e5d5Smrg} 41616260e5d5Smrg 4162fe517fc9Smrg/* Consider devices located on the same bus as duplicate and fold the respective 4163fe517fc9Smrg * entries into a single one. 4164fe517fc9Smrg * 4165fe517fc9Smrg * Note: this leaves "gaps" in the array, while preserving the length. 4166fe517fc9Smrg */ 4167fe517fc9Smrgstatic void drmFoldDuplicatedDevices(drmDevicePtr local_devices[], int count) 4168fe517fc9Smrg{ 4169fe517fc9Smrg int node_type, i, j; 4170fe517fc9Smrg 4171fe517fc9Smrg for (i = 0; i < count; i++) { 4172fe517fc9Smrg for (j = i + 1; j < count; j++) { 41730655efefSmrg if (drmDevicesEqual(local_devices[i], local_devices[j])) { 4174fe517fc9Smrg local_devices[i]->available_nodes |= local_devices[j]->available_nodes; 4175fe517fc9Smrg node_type = log2(local_devices[j]->available_nodes); 4176fe517fc9Smrg memcpy(local_devices[i]->nodes[node_type], 4177fe517fc9Smrg local_devices[j]->nodes[node_type], drmGetMaxNodeName()); 4178fe517fc9Smrg drmFreeDevice(&local_devices[j]); 4179fe517fc9Smrg } 4180fe517fc9Smrg } 4181fe517fc9Smrg } 4182fe517fc9Smrg} 4183fe517fc9Smrg 41842ee35494Smrg/* Check that the given flags are valid returning 0 on success */ 41852ee35494Smrgstatic int 41862ee35494Smrgdrm_device_validate_flags(uint32_t flags) 41872ee35494Smrg{ 41882ee35494Smrg return (flags & ~DRM_DEVICE_GET_PCI_REVISION); 41892ee35494Smrg} 41902ee35494Smrg 41916260e5d5Smrgstatic bool 41926260e5d5Smrgdrm_device_has_rdev(drmDevicePtr device, dev_t find_rdev) 41936260e5d5Smrg{ 41946260e5d5Smrg struct stat sbuf; 41956260e5d5Smrg 41966260e5d5Smrg for (int i = 0; i < DRM_NODE_MAX; i++) { 41976260e5d5Smrg if (device->available_nodes & 1 << i) { 41986260e5d5Smrg if (stat(device->nodes[i], &sbuf) == 0 && 41996260e5d5Smrg sbuf.st_rdev == find_rdev) 42006260e5d5Smrg return true; 42016260e5d5Smrg } 42026260e5d5Smrg } 42036260e5d5Smrg return false; 42046260e5d5Smrg} 42056260e5d5Smrg 42066260e5d5Smrg/* 42076260e5d5Smrg * The kernel drm core has a number of places that assume maximum of 42086260e5d5Smrg * 3x64 devices nodes. That's 64 for each of primary, control and 42096260e5d5Smrg * render nodes. Rounded it up to 256 for simplicity. 42106260e5d5Smrg */ 42116260e5d5Smrg#define MAX_DRM_NODES 256 42126260e5d5Smrg 4213fe517fc9Smrg/** 4214fe517fc9Smrg * Get information about the opened drm device 4215fe517fc9Smrg * 4216fe517fc9Smrg * \param fd file descriptor of the drm device 42172ee35494Smrg * \param flags feature/behaviour bitmask 4218fe517fc9Smrg * \param device the address of a drmDevicePtr where the information 4219fe517fc9Smrg * will be allocated in stored 4220fe517fc9Smrg * 4221fe517fc9Smrg * \return zero on success, negative error code otherwise. 42222ee35494Smrg * 42232ee35494Smrg * \note Unlike drmGetDevice it does not retrieve the pci device revision field 42242ee35494Smrg * unless the DRM_DEVICE_GET_PCI_REVISION \p flag is set. 4225fe517fc9Smrg */ 42266260e5d5Smrgdrm_public int drmGetDevice2(int fd, uint32_t flags, drmDevicePtr *device) 4227fe517fc9Smrg{ 42282ee35494Smrg#ifdef __OpenBSD__ 42292ee35494Smrg /* 42302ee35494Smrg * DRI device nodes on OpenBSD are not in their own directory, they reside 42312ee35494Smrg * in /dev along with a large number of statically generated /dev nodes. 42322ee35494Smrg * Avoid stat'ing all of /dev needlessly by implementing this custom path. 42332ee35494Smrg */ 42342ee35494Smrg drmDevicePtr d; 42352ee35494Smrg struct stat sbuf; 42362ee35494Smrg char node[PATH_MAX + 1]; 42372ee35494Smrg const char *dev_name; 42382ee35494Smrg int node_type, subsystem_type; 423982025ec7Smrg int maj, min, n, ret; 42402ee35494Smrg 42412ee35494Smrg if (fd == -1 || device == NULL) 42422ee35494Smrg return -EINVAL; 42432ee35494Smrg 42442ee35494Smrg if (fstat(fd, &sbuf)) 42452ee35494Smrg return -errno; 42462ee35494Smrg 42472ee35494Smrg maj = major(sbuf.st_rdev); 42482ee35494Smrg min = minor(sbuf.st_rdev); 42492ee35494Smrg 42506260e5d5Smrg if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode)) 42512ee35494Smrg return -EINVAL; 42522ee35494Smrg 425387bf8e7cSmrg node_type = drmGetMinorType(maj, min); 42542ee35494Smrg if (node_type == -1) 42552ee35494Smrg return -ENODEV; 42562ee35494Smrg 425782025ec7Smrg dev_name = drmGetDeviceName(node_type); 425882025ec7Smrg if (!dev_name) 42592ee35494Smrg return -EINVAL; 42602ee35494Smrg 426182025ec7Smrg n = snprintf(node, PATH_MAX, dev_name, DRM_DIR_NAME, min); 42622ee35494Smrg if (n == -1 || n >= PATH_MAX) 42632ee35494Smrg return -errno; 42642ee35494Smrg if (stat(node, &sbuf)) 42652ee35494Smrg return -EINVAL; 42662ee35494Smrg 42672ee35494Smrg subsystem_type = drmParseSubsystemType(maj, min); 42682ee35494Smrg if (subsystem_type != DRM_BUS_PCI) 42692ee35494Smrg return -ENODEV; 42702ee35494Smrg 42712ee35494Smrg ret = drmProcessPciDevice(&d, node, node_type, maj, min, true, flags); 42722ee35494Smrg if (ret) 42732ee35494Smrg return ret; 42742ee35494Smrg 42752ee35494Smrg *device = d; 42762ee35494Smrg 42772ee35494Smrg return 0; 42782ee35494Smrg#else 42796260e5d5Smrg drmDevicePtr local_devices[MAX_DRM_NODES]; 4280fe517fc9Smrg drmDevicePtr d; 4281fe517fc9Smrg DIR *sysdir; 4282fe517fc9Smrg struct dirent *dent; 4283fe517fc9Smrg struct stat sbuf; 42846260e5d5Smrg int subsystem_type; 4285fe517fc9Smrg int maj, min; 4286fe517fc9Smrg int ret, i, node_count; 4287fe517fc9Smrg dev_t find_rdev; 4288fe517fc9Smrg 42892ee35494Smrg if (drm_device_validate_flags(flags)) 42902ee35494Smrg return -EINVAL; 42912ee35494Smrg 4292fe517fc9Smrg if (fd == -1 || device == NULL) 4293fe517fc9Smrg return -EINVAL; 4294fe517fc9Smrg 4295fe517fc9Smrg if (fstat(fd, &sbuf)) 4296fe517fc9Smrg return -errno; 4297fe517fc9Smrg 4298fe517fc9Smrg find_rdev = sbuf.st_rdev; 4299fe517fc9Smrg maj = major(sbuf.st_rdev); 4300fe517fc9Smrg min = minor(sbuf.st_rdev); 4301fe517fc9Smrg 43026260e5d5Smrg if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode)) 4303fe517fc9Smrg return -EINVAL; 4304fe517fc9Smrg 4305fe517fc9Smrg subsystem_type = drmParseSubsystemType(maj, min); 43066260e5d5Smrg if (subsystem_type < 0) 43076260e5d5Smrg return subsystem_type; 4308fe517fc9Smrg 4309fe517fc9Smrg sysdir = opendir(DRM_DIR_NAME); 43106260e5d5Smrg if (!sysdir) 43116260e5d5Smrg return -errno; 4312fe517fc9Smrg 4313fe517fc9Smrg i = 0; 4314fe517fc9Smrg while ((dent = readdir(sysdir))) { 43156260e5d5Smrg ret = process_device(&d, dent->d_name, subsystem_type, true, flags); 43166260e5d5Smrg if (ret) 4317fe517fc9Smrg continue; 4318fe517fc9Smrg 43196260e5d5Smrg if (i >= MAX_DRM_NODES) { 43206260e5d5Smrg fprintf(stderr, "More than %d drm nodes detected. " 43216260e5d5Smrg "Please report a bug - that should not happen.\n" 43226260e5d5Smrg "Skipping extra nodes\n", MAX_DRM_NODES); 4323fe517fc9Smrg break; 4324fe517fc9Smrg } 43256260e5d5Smrg local_devices[i] = d; 4326fe517fc9Smrg i++; 4327fe517fc9Smrg } 4328fe517fc9Smrg node_count = i; 4329fe517fc9Smrg 4330fe517fc9Smrg drmFoldDuplicatedDevices(local_devices, node_count); 4331fe517fc9Smrg 43326260e5d5Smrg *device = NULL; 43336260e5d5Smrg 43346260e5d5Smrg for (i = 0; i < node_count; i++) { 43356260e5d5Smrg if (!local_devices[i]) 43366260e5d5Smrg continue; 43376260e5d5Smrg 43386260e5d5Smrg if (drm_device_has_rdev(local_devices[i], find_rdev)) 43396260e5d5Smrg *device = local_devices[i]; 43406260e5d5Smrg else 43416260e5d5Smrg drmFreeDevice(&local_devices[i]); 43426260e5d5Smrg } 4343fe517fc9Smrg 4344fe517fc9Smrg closedir(sysdir); 43452ee35494Smrg if (*device == NULL) 43462ee35494Smrg return -ENODEV; 4347fe517fc9Smrg return 0; 43482ee35494Smrg#endif 43492ee35494Smrg} 43502ee35494Smrg 43512ee35494Smrg/** 43522ee35494Smrg * Get information about the opened drm device 43532ee35494Smrg * 43542ee35494Smrg * \param fd file descriptor of the drm device 43552ee35494Smrg * \param device the address of a drmDevicePtr where the information 43562ee35494Smrg * will be allocated in stored 43572ee35494Smrg * 43582ee35494Smrg * \return zero on success, negative error code otherwise. 43592ee35494Smrg */ 43606260e5d5Smrgdrm_public int drmGetDevice(int fd, drmDevicePtr *device) 43612ee35494Smrg{ 43622ee35494Smrg return drmGetDevice2(fd, DRM_DEVICE_GET_PCI_REVISION, device); 4363fe517fc9Smrg} 4364fe517fc9Smrg 4365fe517fc9Smrg/** 4366fe517fc9Smrg * Get drm devices on the system 4367fe517fc9Smrg * 43682ee35494Smrg * \param flags feature/behaviour bitmask 4369fe517fc9Smrg * \param devices the array of devices with drmDevicePtr elements 4370fe517fc9Smrg * can be NULL to get the device number first 4371fe517fc9Smrg * \param max_devices the maximum number of devices for the array 4372fe517fc9Smrg * 4373fe517fc9Smrg * \return on error - negative error code, 4374fe517fc9Smrg * if devices is NULL - total number of devices available on the system, 4375fe517fc9Smrg * alternatively the number of devices stored in devices[], which is 4376fe517fc9Smrg * capped by the max_devices. 43772ee35494Smrg * 43782ee35494Smrg * \note Unlike drmGetDevices it does not retrieve the pci device revision field 43792ee35494Smrg * unless the DRM_DEVICE_GET_PCI_REVISION \p flag is set. 4380fe517fc9Smrg */ 43816260e5d5Smrgdrm_public int drmGetDevices2(uint32_t flags, drmDevicePtr devices[], 43826260e5d5Smrg int max_devices) 4383fe517fc9Smrg{ 43846260e5d5Smrg drmDevicePtr local_devices[MAX_DRM_NODES]; 4385fe517fc9Smrg drmDevicePtr device; 4386fe517fc9Smrg DIR *sysdir; 4387fe517fc9Smrg struct dirent *dent; 4388fe517fc9Smrg int ret, i, node_count, device_count; 4389fe517fc9Smrg 43902ee35494Smrg if (drm_device_validate_flags(flags)) 43912ee35494Smrg return -EINVAL; 43922ee35494Smrg 4393fe517fc9Smrg sysdir = opendir(DRM_DIR_NAME); 43946260e5d5Smrg if (!sysdir) 43956260e5d5Smrg return -errno; 4396fe517fc9Smrg 4397fe517fc9Smrg i = 0; 4398fe517fc9Smrg while ((dent = readdir(sysdir))) { 43996260e5d5Smrg ret = process_device(&device, dent->d_name, -1, devices != NULL, flags); 44006260e5d5Smrg if (ret) 4401fe517fc9Smrg continue; 4402fe517fc9Smrg 44036260e5d5Smrg if (i >= MAX_DRM_NODES) { 44046260e5d5Smrg fprintf(stderr, "More than %d drm nodes detected. " 44056260e5d5Smrg "Please report a bug - that should not happen.\n" 44066260e5d5Smrg "Skipping extra nodes\n", MAX_DRM_NODES); 44072ee35494Smrg break; 4408fe517fc9Smrg } 4409fe517fc9Smrg local_devices[i] = device; 4410fe517fc9Smrg i++; 4411fe517fc9Smrg } 4412fe517fc9Smrg node_count = i; 4413fe517fc9Smrg 4414fe517fc9Smrg drmFoldDuplicatedDevices(local_devices, node_count); 4415fe517fc9Smrg 4416fe517fc9Smrg device_count = 0; 4417fe517fc9Smrg for (i = 0; i < node_count; i++) { 4418fe517fc9Smrg if (!local_devices[i]) 4419fe517fc9Smrg continue; 4420fe517fc9Smrg 4421fe517fc9Smrg if ((devices != NULL) && (device_count < max_devices)) 4422fe517fc9Smrg devices[device_count] = local_devices[i]; 4423fe517fc9Smrg else 4424fe517fc9Smrg drmFreeDevice(&local_devices[i]); 4425fe517fc9Smrg 4426fe517fc9Smrg device_count++; 4427fe517fc9Smrg } 4428fe517fc9Smrg 4429fe517fc9Smrg closedir(sysdir); 4430fe517fc9Smrg return device_count; 4431424e9256Smrg} 44322ee35494Smrg 44332ee35494Smrg/** 44342ee35494Smrg * Get drm devices on the system 44352ee35494Smrg * 44362ee35494Smrg * \param devices the array of devices with drmDevicePtr elements 44372ee35494Smrg * can be NULL to get the device number first 44382ee35494Smrg * \param max_devices the maximum number of devices for the array 44392ee35494Smrg * 44402ee35494Smrg * \return on error - negative error code, 44412ee35494Smrg * if devices is NULL - total number of devices available on the system, 44422ee35494Smrg * alternatively the number of devices stored in devices[], which is 44432ee35494Smrg * capped by the max_devices. 44442ee35494Smrg */ 44456260e5d5Smrgdrm_public int drmGetDevices(drmDevicePtr devices[], int max_devices) 44462ee35494Smrg{ 44472ee35494Smrg return drmGetDevices2(DRM_DEVICE_GET_PCI_REVISION, devices, max_devices); 44482ee35494Smrg} 44492ee35494Smrg 44506260e5d5Smrgdrm_public char *drmGetDeviceNameFromFd2(int fd) 44512ee35494Smrg{ 44522ee35494Smrg#ifdef __linux__ 44532ee35494Smrg struct stat sbuf; 44542ee35494Smrg char path[PATH_MAX + 1], *value; 44552ee35494Smrg unsigned int maj, min; 44562ee35494Smrg 44572ee35494Smrg if (fstat(fd, &sbuf)) 44582ee35494Smrg return NULL; 44592ee35494Smrg 44602ee35494Smrg maj = major(sbuf.st_rdev); 44612ee35494Smrg min = minor(sbuf.st_rdev); 44622ee35494Smrg 44636260e5d5Smrg if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode)) 44642ee35494Smrg return NULL; 44652ee35494Smrg 44662ee35494Smrg snprintf(path, sizeof(path), "/sys/dev/char/%d:%d", maj, min); 44672ee35494Smrg 44682ee35494Smrg value = sysfs_uevent_get(path, "DEVNAME"); 44692ee35494Smrg if (!value) 44702ee35494Smrg return NULL; 44712ee35494Smrg 44722ee35494Smrg snprintf(path, sizeof(path), "/dev/%s", value); 44732ee35494Smrg free(value); 44742ee35494Smrg 44752ee35494Smrg return strdup(path); 447687bf8e7cSmrg#elif __FreeBSD__ 447787bf8e7cSmrg return drmGetDeviceNameFromFd(fd); 44782ee35494Smrg#else 44792ee35494Smrg struct stat sbuf; 44802ee35494Smrg char node[PATH_MAX + 1]; 44812ee35494Smrg const char *dev_name; 44822ee35494Smrg int node_type; 448382025ec7Smrg int maj, min, n; 44842ee35494Smrg 44852ee35494Smrg if (fstat(fd, &sbuf)) 44862ee35494Smrg return NULL; 44872ee35494Smrg 44882ee35494Smrg maj = major(sbuf.st_rdev); 44892ee35494Smrg min = minor(sbuf.st_rdev); 44902ee35494Smrg 44916260e5d5Smrg if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode)) 44922ee35494Smrg return NULL; 44932ee35494Smrg 449487bf8e7cSmrg node_type = drmGetMinorType(maj, min); 44952ee35494Smrg if (node_type == -1) 44962ee35494Smrg return NULL; 44972ee35494Smrg 449882025ec7Smrg dev_name = drmGetDeviceName(node_type); 449982025ec7Smrg if (!dev_name) 45002ee35494Smrg return NULL; 45012ee35494Smrg 450282025ec7Smrg n = snprintf(node, PATH_MAX, dev_name, DRM_DIR_NAME, min); 45032ee35494Smrg if (n == -1 || n >= PATH_MAX) 45042ee35494Smrg return NULL; 45052ee35494Smrg 45062ee35494Smrg return strdup(node); 45072ee35494Smrg#endif 45082ee35494Smrg} 45090655efefSmrg 45106260e5d5Smrgdrm_public int drmSyncobjCreate(int fd, uint32_t flags, uint32_t *handle) 45110655efefSmrg{ 45120655efefSmrg struct drm_syncobj_create args; 45130655efefSmrg int ret; 45140655efefSmrg 45150655efefSmrg memclear(args); 45160655efefSmrg args.flags = flags; 45170655efefSmrg args.handle = 0; 45180655efefSmrg ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_CREATE, &args); 45190655efefSmrg if (ret) 45202b90624aSmrg return ret; 45210655efefSmrg *handle = args.handle; 45220655efefSmrg return 0; 45230655efefSmrg} 45240655efefSmrg 45256260e5d5Smrgdrm_public int drmSyncobjDestroy(int fd, uint32_t handle) 45260655efefSmrg{ 45270655efefSmrg struct drm_syncobj_destroy args; 45280655efefSmrg 45290655efefSmrg memclear(args); 45300655efefSmrg args.handle = handle; 45310655efefSmrg return drmIoctl(fd, DRM_IOCTL_SYNCOBJ_DESTROY, &args); 45320655efefSmrg} 45330655efefSmrg 45346260e5d5Smrgdrm_public int drmSyncobjHandleToFD(int fd, uint32_t handle, int *obj_fd) 45350655efefSmrg{ 45360655efefSmrg struct drm_syncobj_handle args; 45370655efefSmrg int ret; 45380655efefSmrg 45390655efefSmrg memclear(args); 45400655efefSmrg args.fd = -1; 45410655efefSmrg args.handle = handle; 45420655efefSmrg ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD, &args); 45430655efefSmrg if (ret) 45442b90624aSmrg return ret; 45450655efefSmrg *obj_fd = args.fd; 45460655efefSmrg return 0; 45470655efefSmrg} 45480655efefSmrg 45496260e5d5Smrgdrm_public int drmSyncobjFDToHandle(int fd, int obj_fd, uint32_t *handle) 45500655efefSmrg{ 45510655efefSmrg struct drm_syncobj_handle args; 45520655efefSmrg int ret; 45530655efefSmrg 45540655efefSmrg memclear(args); 45550655efefSmrg args.fd = obj_fd; 45560655efefSmrg args.handle = 0; 45570655efefSmrg ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE, &args); 45580655efefSmrg if (ret) 45592b90624aSmrg return ret; 45600655efefSmrg *handle = args.handle; 45610655efefSmrg return 0; 45620655efefSmrg} 45630655efefSmrg 45646260e5d5Smrgdrm_public int drmSyncobjImportSyncFile(int fd, uint32_t handle, 45656260e5d5Smrg int sync_file_fd) 45660655efefSmrg{ 45670655efefSmrg struct drm_syncobj_handle args; 45680655efefSmrg 45690655efefSmrg memclear(args); 45700655efefSmrg args.fd = sync_file_fd; 45710655efefSmrg args.handle = handle; 45720655efefSmrg args.flags = DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_IMPORT_SYNC_FILE; 45730655efefSmrg return drmIoctl(fd, DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE, &args); 45740655efefSmrg} 45750655efefSmrg 45766260e5d5Smrgdrm_public int drmSyncobjExportSyncFile(int fd, uint32_t handle, 45776260e5d5Smrg int *sync_file_fd) 45780655efefSmrg{ 45790655efefSmrg struct drm_syncobj_handle args; 45800655efefSmrg int ret; 45810655efefSmrg 45820655efefSmrg memclear(args); 45830655efefSmrg args.fd = -1; 45840655efefSmrg args.handle = handle; 45850655efefSmrg args.flags = DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_EXPORT_SYNC_FILE; 45860655efefSmrg ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD, &args); 45870655efefSmrg if (ret) 45882b90624aSmrg return ret; 45890655efefSmrg *sync_file_fd = args.fd; 45900655efefSmrg return 0; 45910655efefSmrg} 45922b90624aSmrg 45936260e5d5Smrgdrm_public int drmSyncobjWait(int fd, uint32_t *handles, unsigned num_handles, 45946260e5d5Smrg int64_t timeout_nsec, unsigned flags, 45956260e5d5Smrg uint32_t *first_signaled) 45962b90624aSmrg{ 45972b90624aSmrg struct drm_syncobj_wait args; 45982b90624aSmrg int ret; 45992b90624aSmrg 46002b90624aSmrg memclear(args); 46012b90624aSmrg args.handles = (uintptr_t)handles; 46022b90624aSmrg args.timeout_nsec = timeout_nsec; 46032b90624aSmrg args.count_handles = num_handles; 46042b90624aSmrg args.flags = flags; 46052b90624aSmrg 46062b90624aSmrg ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_WAIT, &args); 46072b90624aSmrg if (ret < 0) 46082b90624aSmrg return -errno; 46092b90624aSmrg 46102b90624aSmrg if (first_signaled) 46112b90624aSmrg *first_signaled = args.first_signaled; 46122b90624aSmrg return ret; 46132b90624aSmrg} 46142b90624aSmrg 46156260e5d5Smrgdrm_public int drmSyncobjReset(int fd, const uint32_t *handles, 46166260e5d5Smrg uint32_t handle_count) 46172b90624aSmrg{ 46182b90624aSmrg struct drm_syncobj_array args; 46192b90624aSmrg int ret; 46202b90624aSmrg 46212b90624aSmrg memclear(args); 46222b90624aSmrg args.handles = (uintptr_t)handles; 46232b90624aSmrg args.count_handles = handle_count; 46242b90624aSmrg 46252b90624aSmrg ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_RESET, &args); 46262b90624aSmrg return ret; 46272b90624aSmrg} 46282b90624aSmrg 46296260e5d5Smrgdrm_public int drmSyncobjSignal(int fd, const uint32_t *handles, 46306260e5d5Smrg uint32_t handle_count) 46312b90624aSmrg{ 46322b90624aSmrg struct drm_syncobj_array args; 46332b90624aSmrg int ret; 46342b90624aSmrg 46352b90624aSmrg memclear(args); 46362b90624aSmrg args.handles = (uintptr_t)handles; 46372b90624aSmrg args.count_handles = handle_count; 46382b90624aSmrg 46392b90624aSmrg ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_SIGNAL, &args); 46402b90624aSmrg return ret; 46412b90624aSmrg} 4642bf6cc7dcSmrg 4643bf6cc7dcSmrgdrm_public int drmSyncobjTimelineSignal(int fd, const uint32_t *handles, 4644bf6cc7dcSmrg uint64_t *points, uint32_t handle_count) 4645bf6cc7dcSmrg{ 4646bf6cc7dcSmrg struct drm_syncobj_timeline_array args; 4647bf6cc7dcSmrg int ret; 4648bf6cc7dcSmrg 4649bf6cc7dcSmrg memclear(args); 4650bf6cc7dcSmrg args.handles = (uintptr_t)handles; 4651bf6cc7dcSmrg args.points = (uintptr_t)points; 4652bf6cc7dcSmrg args.count_handles = handle_count; 4653bf6cc7dcSmrg 4654bf6cc7dcSmrg ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_TIMELINE_SIGNAL, &args); 4655bf6cc7dcSmrg return ret; 4656bf6cc7dcSmrg} 4657bf6cc7dcSmrg 4658bf6cc7dcSmrgdrm_public int drmSyncobjTimelineWait(int fd, uint32_t *handles, uint64_t *points, 4659bf6cc7dcSmrg unsigned num_handles, 4660bf6cc7dcSmrg int64_t timeout_nsec, unsigned flags, 4661bf6cc7dcSmrg uint32_t *first_signaled) 4662bf6cc7dcSmrg{ 4663bf6cc7dcSmrg struct drm_syncobj_timeline_wait args; 4664bf6cc7dcSmrg int ret; 4665bf6cc7dcSmrg 4666bf6cc7dcSmrg memclear(args); 4667bf6cc7dcSmrg args.handles = (uintptr_t)handles; 4668bf6cc7dcSmrg args.points = (uintptr_t)points; 4669bf6cc7dcSmrg args.timeout_nsec = timeout_nsec; 4670bf6cc7dcSmrg args.count_handles = num_handles; 4671bf6cc7dcSmrg args.flags = flags; 4672bf6cc7dcSmrg 4673bf6cc7dcSmrg ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_TIMELINE_WAIT, &args); 4674bf6cc7dcSmrg if (ret < 0) 4675bf6cc7dcSmrg return -errno; 4676bf6cc7dcSmrg 4677bf6cc7dcSmrg if (first_signaled) 4678bf6cc7dcSmrg *first_signaled = args.first_signaled; 4679bf6cc7dcSmrg return ret; 4680bf6cc7dcSmrg} 4681bf6cc7dcSmrg 4682bf6cc7dcSmrg 4683bf6cc7dcSmrgdrm_public int drmSyncobjQuery(int fd, uint32_t *handles, uint64_t *points, 4684bf6cc7dcSmrg uint32_t handle_count) 4685bf6cc7dcSmrg{ 4686bf6cc7dcSmrg struct drm_syncobj_timeline_array args; 4687bf6cc7dcSmrg int ret; 4688bf6cc7dcSmrg 4689bf6cc7dcSmrg memclear(args); 4690bf6cc7dcSmrg args.handles = (uintptr_t)handles; 4691bf6cc7dcSmrg args.points = (uintptr_t)points; 4692bf6cc7dcSmrg args.count_handles = handle_count; 4693bf6cc7dcSmrg 4694bf6cc7dcSmrg ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_QUERY, &args); 4695bf6cc7dcSmrg if (ret) 4696bf6cc7dcSmrg return ret; 4697bf6cc7dcSmrg return 0; 4698bf6cc7dcSmrg} 4699bf6cc7dcSmrg 470087bf8e7cSmrgdrm_public int drmSyncobjQuery2(int fd, uint32_t *handles, uint64_t *points, 470187bf8e7cSmrg uint32_t handle_count, uint32_t flags) 470287bf8e7cSmrg{ 470387bf8e7cSmrg struct drm_syncobj_timeline_array args; 470487bf8e7cSmrg 470587bf8e7cSmrg memclear(args); 470687bf8e7cSmrg args.handles = (uintptr_t)handles; 470787bf8e7cSmrg args.points = (uintptr_t)points; 470887bf8e7cSmrg args.count_handles = handle_count; 470987bf8e7cSmrg args.flags = flags; 471087bf8e7cSmrg 471187bf8e7cSmrg return drmIoctl(fd, DRM_IOCTL_SYNCOBJ_QUERY, &args); 471287bf8e7cSmrg} 471387bf8e7cSmrg 471487bf8e7cSmrg 4715bf6cc7dcSmrgdrm_public int drmSyncobjTransfer(int fd, 4716bf6cc7dcSmrg uint32_t dst_handle, uint64_t dst_point, 4717bf6cc7dcSmrg uint32_t src_handle, uint64_t src_point, 4718bf6cc7dcSmrg uint32_t flags) 4719bf6cc7dcSmrg{ 4720bf6cc7dcSmrg struct drm_syncobj_transfer args; 4721bf6cc7dcSmrg int ret; 4722bf6cc7dcSmrg 4723bf6cc7dcSmrg memclear(args); 4724bf6cc7dcSmrg args.src_handle = src_handle; 4725bf6cc7dcSmrg args.dst_handle = dst_handle; 4726bf6cc7dcSmrg args.src_point = src_point; 4727bf6cc7dcSmrg args.dst_point = dst_point; 4728bf6cc7dcSmrg args.flags = flags; 4729bf6cc7dcSmrg 4730bf6cc7dcSmrg ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_TRANSFER, &args); 4731bf6cc7dcSmrg 4732bf6cc7dcSmrg return ret; 4733bf6cc7dcSmrg} 4734