xf86drm.c revision 2b90624a
122944501Smrg/** 2fe517fc9Smrg * \file xf86drm.c 322944501Smrg * User-level interface to DRM device 422944501Smrg * 522944501Smrg * \author Rickard E. (Rik) Faith <faith@valinux.com> 622944501Smrg * \author Kevin E. Martin <martin@valinux.com> 722944501Smrg */ 822944501Smrg 922944501Smrg/* 1022944501Smrg * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. 1122944501Smrg * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. 1222944501Smrg * All Rights Reserved. 1322944501Smrg * 1422944501Smrg * Permission is hereby granted, free of charge, to any person obtaining a 1522944501Smrg * copy of this software and associated documentation files (the "Software"), 1622944501Smrg * to deal in the Software without restriction, including without limitation 1722944501Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 1822944501Smrg * and/or sell copies of the Software, and to permit persons to whom the 1922944501Smrg * Software is furnished to do so, subject to the following conditions: 2022944501Smrg * 2122944501Smrg * The above copyright notice and this permission notice (including the next 2222944501Smrg * paragraph) shall be included in all copies or substantial portions of the 2322944501Smrg * Software. 2422944501Smrg * 2522944501Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 2622944501Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 2722944501Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 2822944501Smrg * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 2922944501Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 3022944501Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 3122944501Smrg * DEALINGS IN THE SOFTWARE. 3222944501Smrg */ 3322944501Smrg 3422944501Smrg#ifdef HAVE_CONFIG_H 3522944501Smrg# include <config.h> 3622944501Smrg#endif 3722944501Smrg#include <stdio.h> 3822944501Smrg#include <stdlib.h> 39fe517fc9Smrg#include <stdbool.h> 4022944501Smrg#include <unistd.h> 4122944501Smrg#include <string.h> 4222944501Smrg#include <strings.h> 4322944501Smrg#include <ctype.h> 44424e9256Smrg#include <dirent.h> 45424e9256Smrg#include <stddef.h> 4622944501Smrg#include <fcntl.h> 4722944501Smrg#include <errno.h> 48fe517fc9Smrg#include <limits.h> 4922944501Smrg#include <signal.h> 5022944501Smrg#include <time.h> 5122944501Smrg#include <sys/types.h> 5222944501Smrg#include <sys/stat.h> 5322944501Smrg#define stat_t struct stat 5422944501Smrg#include <sys/ioctl.h> 5522944501Smrg#include <sys/time.h> 5622944501Smrg#include <stdarg.h> 57fe517fc9Smrg#ifdef MAJOR_IN_MKDEV 58fe517fc9Smrg#include <sys/mkdev.h> 59424e9256Smrg#endif 60fe517fc9Smrg#ifdef MAJOR_IN_SYSMACROS 61fe517fc9Smrg#include <sys/sysmacros.h> 62fe517fc9Smrg#endif 63fe517fc9Smrg#include <math.h> 6422944501Smrg 652ee35494Smrg/* Not all systems have MAP_FAILED defined */ 662ee35494Smrg#ifndef MAP_FAILED 672ee35494Smrg#define MAP_FAILED ((void *)-1) 682ee35494Smrg#endif 6922944501Smrg 7022944501Smrg#include "xf86drm.h" 71424e9256Smrg#include "libdrm_macros.h" 7222944501Smrg 73fe517fc9Smrg#include "util_math.h" 74fe517fc9Smrg 75fe517fc9Smrg#ifdef __OpenBSD__ 76fe517fc9Smrg#define DRM_PRIMARY_MINOR_NAME "drm" 77fe517fc9Smrg#define DRM_CONTROL_MINOR_NAME "drmC" 78fe517fc9Smrg#define DRM_RENDER_MINOR_NAME "drmR" 79fe517fc9Smrg#else 80fe517fc9Smrg#define DRM_PRIMARY_MINOR_NAME "card" 81fe517fc9Smrg#define DRM_CONTROL_MINOR_NAME "controlD" 82fe517fc9Smrg#define DRM_RENDER_MINOR_NAME "renderD" 83fe517fc9Smrg#endif 84fe517fc9Smrg 8522944501Smrg#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) 8622944501Smrg#define DRM_MAJOR 145 8722944501Smrg#endif 8822944501Smrg 8922944501Smrg#ifdef __NetBSD__ 902e6867f6Smrg#undef DRM_MAJOR 912e6867f6Smrg#define DRM_MAJOR 180 9222944501Smrg#endif 9322944501Smrg 94fe517fc9Smrg#ifdef __OpenBSD__ 95fe517fc9Smrg#ifdef __i386__ 96fe517fc9Smrg#define DRM_MAJOR 88 97fe517fc9Smrg#else 98fe517fc9Smrg#define DRM_MAJOR 87 9922944501Smrg#endif 100fe517fc9Smrg#endif /* __OpenBSD__ */ 10122944501Smrg 102fe517fc9Smrg#ifndef DRM_MAJOR 103fe517fc9Smrg#define DRM_MAJOR 226 /* Linux */ 10422944501Smrg#endif 10522944501Smrg 1062ee35494Smrg#ifdef __OpenBSD__ 1072ee35494Smrgstruct drm_pciinfo { 1082ee35494Smrg uint16_t domain; 1092ee35494Smrg uint8_t bus; 1102ee35494Smrg uint8_t dev; 1112ee35494Smrg uint8_t func; 1122ee35494Smrg uint16_t vendor_id; 1132ee35494Smrg uint16_t device_id; 1142ee35494Smrg uint16_t subvendor_id; 1152ee35494Smrg uint16_t subdevice_id; 1162ee35494Smrg uint8_t revision_id; 1172ee35494Smrg}; 1182ee35494Smrg 1192ee35494Smrg#define DRM_IOCTL_GET_PCIINFO DRM_IOR(0x15, struct drm_pciinfo) 12011c53d23Schristos#endif 12111c53d23Schristos 12222944501Smrg#define DRM_MSG_VERBOSITY 3 12322944501Smrg 124424e9256Smrg#define memclear(s) memset(&s, 0, sizeof(s)) 12522944501Smrg 12622944501Smrgstatic drmServerInfoPtr drm_server_info; 12722944501Smrg 12822944501Smrgvoid drmSetServerInfo(drmServerInfoPtr info) 12922944501Smrg{ 13022944501Smrg drm_server_info = info; 13122944501Smrg} 13222944501Smrg 13322944501Smrg/** 13422944501Smrg * Output a message to stderr. 13522944501Smrg * 13622944501Smrg * \param format printf() like format string. 13722944501Smrg * 13822944501Smrg * \internal 13922944501Smrg * This function is a wrapper around vfprintf(). 14022944501Smrg */ 14122944501Smrg 142a7d7de1eSmrgstatic int DRM_PRINTFLIKE(1, 0) 143a7d7de1eSmrgdrmDebugPrint(const char *format, va_list ap) 14422944501Smrg{ 14522944501Smrg return vfprintf(stderr, format, ap); 14622944501Smrg} 14722944501Smrg 14822944501Smrgvoid 14922944501SmrgdrmMsg(const char *format, ...) 15022944501Smrg{ 151fe517fc9Smrg va_list ap; 15222944501Smrg const char *env; 153fe517fc9Smrg if (((env = getenv("LIBGL_DEBUG")) && strstr(env, "verbose")) || 154fe517fc9Smrg (drm_server_info && drm_server_info->debug_print)) 15522944501Smrg { 156fe517fc9Smrg va_start(ap, format); 157fe517fc9Smrg if (drm_server_info) { 158fe517fc9Smrg drm_server_info->debug_print(format,ap); 159fe517fc9Smrg } else { 160fe517fc9Smrg drmDebugPrint(format, ap); 161fe517fc9Smrg } 162fe517fc9Smrg va_end(ap); 16322944501Smrg } 16422944501Smrg} 16522944501Smrg 16622944501Smrgstatic void *drmHashTable = NULL; /* Context switch callbacks */ 16722944501Smrg 16822944501Smrgvoid *drmGetHashTable(void) 16922944501Smrg{ 17022944501Smrg return drmHashTable; 17122944501Smrg} 17222944501Smrg 17322944501Smrgvoid *drmMalloc(int size) 17422944501Smrg{ 175424e9256Smrg return calloc(1, size); 17622944501Smrg} 17722944501Smrg 17822944501Smrgvoid drmFree(void *pt) 17922944501Smrg{ 180424e9256Smrg free(pt); 18122944501Smrg} 18222944501Smrg 18322944501Smrg/** 18422944501Smrg * Call ioctl, restarting if it is interupted 18522944501Smrg */ 18622944501Smrgint 18722944501SmrgdrmIoctl(int fd, unsigned long request, void *arg) 18822944501Smrg{ 189fe517fc9Smrg int ret; 19022944501Smrg 19122944501Smrg do { 192fe517fc9Smrg ret = ioctl(fd, request, arg); 19322944501Smrg } while (ret == -1 && (errno == EINTR || errno == EAGAIN)); 19422944501Smrg return ret; 19522944501Smrg} 19622944501Smrg 19722944501Smrgstatic unsigned long drmGetKeyFromFd(int fd) 19822944501Smrg{ 19922944501Smrg stat_t st; 20022944501Smrg 20122944501Smrg st.st_rdev = 0; 20222944501Smrg fstat(fd, &st); 20322944501Smrg return st.st_rdev; 20422944501Smrg} 20522944501Smrg 20622944501SmrgdrmHashEntry *drmGetEntry(int fd) 20722944501Smrg{ 20822944501Smrg unsigned long key = drmGetKeyFromFd(fd); 20922944501Smrg void *value; 21022944501Smrg drmHashEntry *entry; 21122944501Smrg 21222944501Smrg if (!drmHashTable) 213fe517fc9Smrg drmHashTable = drmHashCreate(); 21422944501Smrg 21522944501Smrg if (drmHashLookup(drmHashTable, key, &value)) { 216fe517fc9Smrg entry = drmMalloc(sizeof(*entry)); 217fe517fc9Smrg entry->fd = fd; 218fe517fc9Smrg entry->f = NULL; 219fe517fc9Smrg entry->tagTable = drmHashCreate(); 220fe517fc9Smrg drmHashInsert(drmHashTable, key, entry); 22122944501Smrg } else { 222fe517fc9Smrg entry = value; 22322944501Smrg } 22422944501Smrg return entry; 22522944501Smrg} 22622944501Smrg 22722944501Smrg/** 22822944501Smrg * Compare two busid strings 22922944501Smrg * 23022944501Smrg * \param first 23122944501Smrg * \param second 23222944501Smrg * 23322944501Smrg * \return 1 if matched. 23422944501Smrg * 23522944501Smrg * \internal 23622944501Smrg * This function compares two bus ID strings. It understands the older 23722944501Smrg * PCI:b:d:f format and the newer pci:oooo:bb:dd.f format. In the format, o is 23822944501Smrg * domain, b is bus, d is device, f is function. 23922944501Smrg */ 2406d98c517Smrgstatic int drmMatchBusID(const char *id1, const char *id2, int pci_domain_ok) 24122944501Smrg{ 24222944501Smrg /* First, check if the IDs are exactly the same */ 24322944501Smrg if (strcasecmp(id1, id2) == 0) 244fe517fc9Smrg return 1; 24522944501Smrg 24622944501Smrg /* Try to match old/new-style PCI bus IDs. */ 24722944501Smrg if (strncasecmp(id1, "pci", 3) == 0) { 248fe517fc9Smrg unsigned int o1, b1, d1, f1; 249fe517fc9Smrg unsigned int o2, b2, d2, f2; 250fe517fc9Smrg int ret; 251fe517fc9Smrg 252fe517fc9Smrg ret = sscanf(id1, "pci:%04x:%02x:%02x.%u", &o1, &b1, &d1, &f1); 253fe517fc9Smrg if (ret != 4) { 254fe517fc9Smrg o1 = 0; 255fe517fc9Smrg ret = sscanf(id1, "PCI:%u:%u:%u", &b1, &d1, &f1); 256fe517fc9Smrg if (ret != 3) 257fe517fc9Smrg return 0; 258fe517fc9Smrg } 259fe517fc9Smrg 260fe517fc9Smrg ret = sscanf(id2, "pci:%04x:%02x:%02x.%u", &o2, &b2, &d2, &f2); 261fe517fc9Smrg if (ret != 4) { 262fe517fc9Smrg o2 = 0; 263fe517fc9Smrg ret = sscanf(id2, "PCI:%u:%u:%u", &b2, &d2, &f2); 264fe517fc9Smrg if (ret != 3) 265fe517fc9Smrg return 0; 266fe517fc9Smrg } 267fe517fc9Smrg 268fe517fc9Smrg /* If domains aren't properly supported by the kernel interface, 269fe517fc9Smrg * just ignore them, which sucks less than picking a totally random 270fe517fc9Smrg * card with "open by name" 271fe517fc9Smrg */ 272fe517fc9Smrg if (!pci_domain_ok) 273fe517fc9Smrg o1 = o2 = 0; 274fe517fc9Smrg 275fe517fc9Smrg if ((o1 != o2) || (b1 != b2) || (d1 != d2) || (f1 != f2)) 276fe517fc9Smrg return 0; 277fe517fc9Smrg else 278fe517fc9Smrg return 1; 27922944501Smrg } 28022944501Smrg return 0; 28122944501Smrg} 28222944501Smrg 28322944501Smrg/** 28422944501Smrg * Handles error checking for chown call. 28522944501Smrg * 28622944501Smrg * \param path to file. 28722944501Smrg * \param id of the new owner. 28822944501Smrg * \param id of the new group. 28922944501Smrg * 29022944501Smrg * \return zero if success or -1 if failure. 29122944501Smrg * 29222944501Smrg * \internal 29322944501Smrg * Checks for failure. If failure was caused by signal call chown again. 29422944501Smrg * If any other failure happened then it will output error mesage using 29522944501Smrg * drmMsg() call. 29622944501Smrg */ 297424e9256Smrg#if !defined(UDEV) 29822944501Smrgstatic int chown_check_return(const char *path, uid_t owner, gid_t group) 29922944501Smrg{ 300fe517fc9Smrg int rv; 30122944501Smrg 302fe517fc9Smrg do { 303fe517fc9Smrg rv = chown(path, owner, group); 304fe517fc9Smrg } while (rv != 0 && errno == EINTR); 30522944501Smrg 306fe517fc9Smrg if (rv == 0) 307fe517fc9Smrg return 0; 30822944501Smrg 309fe517fc9Smrg drmMsg("Failed to change owner or group for file %s! %d: %s\n", 310fe517fc9Smrg path, errno, strerror(errno)); 311fe517fc9Smrg return -1; 31222944501Smrg} 313424e9256Smrg#endif 31422944501Smrg 31522944501Smrg/** 31622944501Smrg * Open the DRM device, creating it if necessary. 31722944501Smrg * 31822944501Smrg * \param dev major and minor numbers of the device. 31922944501Smrg * \param minor minor number of the device. 320fe517fc9Smrg * 32122944501Smrg * \return a file descriptor on success, or a negative value on error. 32222944501Smrg * 32322944501Smrg * \internal 32422944501Smrg * Assembles the device name from \p minor and opens it, creating the device 32522944501Smrg * special file node with the major and minor numbers specified by \p dev and 32622944501Smrg * parent directory if necessary and was called by root. 32722944501Smrg */ 328424e9256Smrgstatic int drmOpenDevice(dev_t dev, int minor, int type) 32922944501Smrg{ 33022944501Smrg stat_t st; 331424e9256Smrg const char *dev_name; 33222944501Smrg char buf[64]; 33322944501Smrg int fd; 33422944501Smrg mode_t devmode = DRM_DEV_MODE, serv_mode; 335424e9256Smrg gid_t serv_group; 336424e9256Smrg#if !defined(UDEV) 33722944501Smrg int isroot = !geteuid(); 33822944501Smrg uid_t user = DRM_DEV_UID; 339424e9256Smrg gid_t group = DRM_DEV_GID; 340424e9256Smrg#endif 341424e9256Smrg 342424e9256Smrg switch (type) { 343424e9256Smrg case DRM_NODE_PRIMARY: 344fe517fc9Smrg dev_name = DRM_DEV_NAME; 345fe517fc9Smrg break; 346424e9256Smrg case DRM_NODE_CONTROL: 347fe517fc9Smrg dev_name = DRM_CONTROL_DEV_NAME; 348fe517fc9Smrg break; 349424e9256Smrg case DRM_NODE_RENDER: 350fe517fc9Smrg dev_name = DRM_RENDER_DEV_NAME; 351fe517fc9Smrg break; 352424e9256Smrg default: 353fe517fc9Smrg return -EINVAL; 354424e9256Smrg }; 355424e9256Smrg 356424e9256Smrg sprintf(buf, dev_name, DRM_DIR_NAME, minor); 35722944501Smrg drmMsg("drmOpenDevice: node name is %s\n", buf); 35822944501Smrg 359fe517fc9Smrg if (drm_server_info && drm_server_info->get_perms) { 360fe517fc9Smrg drm_server_info->get_perms(&serv_group, &serv_mode); 361fe517fc9Smrg devmode = serv_mode ? serv_mode : DRM_DEV_MODE; 362fe517fc9Smrg devmode &= ~(S_IXUSR|S_IXGRP|S_IXOTH); 36322944501Smrg } 36422944501Smrg 36522944501Smrg#if !defined(UDEV) 36622944501Smrg if (stat(DRM_DIR_NAME, &st)) { 367fe517fc9Smrg if (!isroot) 368fe517fc9Smrg return DRM_ERR_NOT_ROOT; 369fe517fc9Smrg mkdir(DRM_DIR_NAME, DRM_DEV_DIRMODE); 370fe517fc9Smrg chown_check_return(DRM_DIR_NAME, 0, 0); /* root:root */ 371fe517fc9Smrg chmod(DRM_DIR_NAME, DRM_DEV_DIRMODE); 37222944501Smrg } 37322944501Smrg 37422944501Smrg /* Check if the device node exists and create it if necessary. */ 37522944501Smrg if (stat(buf, &st)) { 376fe517fc9Smrg if (!isroot) 377fe517fc9Smrg return DRM_ERR_NOT_ROOT; 378fe517fc9Smrg remove(buf); 379fe517fc9Smrg mknod(buf, S_IFCHR | devmode, dev); 38022944501Smrg } 38122944501Smrg 382fe517fc9Smrg if (drm_server_info && drm_server_info->get_perms) { 383fe517fc9Smrg group = ((int)serv_group >= 0) ? serv_group : DRM_DEV_GID; 384fe517fc9Smrg chown_check_return(buf, user, group); 385fe517fc9Smrg chmod(buf, devmode); 38622944501Smrg } 38722944501Smrg#else 38822944501Smrg /* if we modprobed then wait for udev */ 38922944501Smrg { 390fe517fc9Smrg int udev_count = 0; 39122944501Smrgwait_for_udev: 39222944501Smrg if (stat(DRM_DIR_NAME, &st)) { 393fe517fc9Smrg usleep(20); 394fe517fc9Smrg udev_count++; 395fe517fc9Smrg 396fe517fc9Smrg if (udev_count == 50) 397fe517fc9Smrg return -1; 398fe517fc9Smrg goto wait_for_udev; 399fe517fc9Smrg } 400fe517fc9Smrg 401fe517fc9Smrg if (stat(buf, &st)) { 402fe517fc9Smrg usleep(20); 403fe517fc9Smrg udev_count++; 404fe517fc9Smrg 405fe517fc9Smrg if (udev_count == 50) 406fe517fc9Smrg return -1; 407fe517fc9Smrg goto wait_for_udev; 408fe517fc9Smrg } 40922944501Smrg } 41022944501Smrg#endif 41122944501Smrg 41222944501Smrg fd = open(buf, O_RDWR, 0); 41322944501Smrg drmMsg("drmOpenDevice: open result is %d, (%s)\n", 414fe517fc9Smrg fd, fd < 0 ? strerror(errno) : "OK"); 41522944501Smrg if (fd >= 0) 416fe517fc9Smrg return fd; 41722944501Smrg 4189ce4edccSmrg#if !defined(UDEV) 41922944501Smrg /* Check if the device node is not what we expect it to be, and recreate it 42022944501Smrg * and try again if so. 42122944501Smrg */ 42222944501Smrg if (st.st_rdev != dev) { 423fe517fc9Smrg if (!isroot) 424fe517fc9Smrg return DRM_ERR_NOT_ROOT; 425fe517fc9Smrg remove(buf); 426fe517fc9Smrg mknod(buf, S_IFCHR | devmode, dev); 427fe517fc9Smrg if (drm_server_info && drm_server_info->get_perms) { 428fe517fc9Smrg chown_check_return(buf, user, group); 429fe517fc9Smrg chmod(buf, devmode); 430fe517fc9Smrg } 43122944501Smrg } 43222944501Smrg fd = open(buf, O_RDWR, 0); 43322944501Smrg drmMsg("drmOpenDevice: open result is %d, (%s)\n", 434fe517fc9Smrg fd, fd < 0 ? strerror(errno) : "OK"); 43522944501Smrg if (fd >= 0) 436fe517fc9Smrg return fd; 43722944501Smrg 43822944501Smrg drmMsg("drmOpenDevice: Open failed\n"); 43922944501Smrg remove(buf); 4409ce4edccSmrg#endif 44122944501Smrg return -errno; 44222944501Smrg} 44322944501Smrg 44422944501Smrg 44522944501Smrg/** 44622944501Smrg * Open the DRM device 44722944501Smrg * 44822944501Smrg * \param minor device minor number. 44922944501Smrg * \param create allow to create the device if set. 45022944501Smrg * 45122944501Smrg * \return a file descriptor on success, or a negative value on error. 452fe517fc9Smrg * 45322944501Smrg * \internal 45422944501Smrg * Calls drmOpenDevice() if \p create is set, otherwise assembles the device 45522944501Smrg * name from \p minor and opens it. 45622944501Smrg */ 45722944501Smrgstatic int drmOpenMinor(int minor, int create, int type) 45822944501Smrg{ 45922944501Smrg int fd; 46022944501Smrg char buf[64]; 461424e9256Smrg const char *dev_name; 462fe517fc9Smrg 46322944501Smrg if (create) 464fe517fc9Smrg return drmOpenDevice(makedev(DRM_MAJOR, minor), minor, type); 465fe517fc9Smrg 466424e9256Smrg switch (type) { 467424e9256Smrg case DRM_NODE_PRIMARY: 468fe517fc9Smrg dev_name = DRM_DEV_NAME; 469fe517fc9Smrg break; 470424e9256Smrg case DRM_NODE_CONTROL: 471fe517fc9Smrg dev_name = DRM_CONTROL_DEV_NAME; 472fe517fc9Smrg break; 473424e9256Smrg case DRM_NODE_RENDER: 474fe517fc9Smrg dev_name = DRM_RENDER_DEV_NAME; 475fe517fc9Smrg break; 476424e9256Smrg default: 477fe517fc9Smrg return -EINVAL; 478424e9256Smrg }; 479424e9256Smrg 480424e9256Smrg sprintf(buf, dev_name, DRM_DIR_NAME, minor); 48122944501Smrg if ((fd = open(buf, O_RDWR, 0)) >= 0) 482fe517fc9Smrg return fd; 48322944501Smrg return -errno; 48422944501Smrg} 48522944501Smrg 48622944501Smrg 48722944501Smrg/** 48822944501Smrg * Determine whether the DRM kernel driver has been loaded. 489fe517fc9Smrg * 49022944501Smrg * \return 1 if the DRM driver is loaded, 0 otherwise. 49122944501Smrg * 492fe517fc9Smrg * \internal 49322944501Smrg * Determine the presence of the kernel driver by attempting to open the 0 49422944501Smrg * minor and get version information. For backward compatibility with older 49522944501Smrg * Linux implementations, /proc/dri is also checked. 49622944501Smrg */ 49722944501Smrgint drmAvailable(void) 49822944501Smrg{ 49922944501Smrg drmVersionPtr version; 50022944501Smrg int retval = 0; 50122944501Smrg int fd; 50222944501Smrg 503424e9256Smrg if ((fd = drmOpenMinor(0, 1, DRM_NODE_PRIMARY)) < 0) { 50422944501Smrg#ifdef __linux__ 505fe517fc9Smrg /* Try proc for backward Linux compatibility */ 506fe517fc9Smrg if (!access("/proc/dri/0", R_OK)) 507fe517fc9Smrg return 1; 50822944501Smrg#endif 509fe517fc9Smrg return 0; 51022944501Smrg } 511fe517fc9Smrg 51222944501Smrg if ((version = drmGetVersion(fd))) { 513fe517fc9Smrg retval = 1; 514fe517fc9Smrg drmFreeVersion(version); 51522944501Smrg } 51622944501Smrg close(fd); 51722944501Smrg 51822944501Smrg return retval; 51922944501Smrg} 52022944501Smrg 521424e9256Smrgstatic int drmGetMinorBase(int type) 522424e9256Smrg{ 523424e9256Smrg switch (type) { 524424e9256Smrg case DRM_NODE_PRIMARY: 525424e9256Smrg return 0; 526424e9256Smrg case DRM_NODE_CONTROL: 527424e9256Smrg return 64; 528424e9256Smrg case DRM_NODE_RENDER: 529424e9256Smrg return 128; 530424e9256Smrg default: 531424e9256Smrg return -1; 532424e9256Smrg }; 533424e9256Smrg} 534424e9256Smrg 535424e9256Smrgstatic int drmGetMinorType(int minor) 536424e9256Smrg{ 537424e9256Smrg int type = minor >> 6; 538424e9256Smrg 539424e9256Smrg if (minor < 0) 540424e9256Smrg return -1; 541424e9256Smrg 542424e9256Smrg switch (type) { 543424e9256Smrg case DRM_NODE_PRIMARY: 544424e9256Smrg case DRM_NODE_CONTROL: 545424e9256Smrg case DRM_NODE_RENDER: 546424e9256Smrg return type; 547424e9256Smrg default: 548424e9256Smrg return -1; 549424e9256Smrg } 550424e9256Smrg} 551424e9256Smrg 552424e9256Smrgstatic const char *drmGetMinorName(int type) 553424e9256Smrg{ 554424e9256Smrg switch (type) { 555424e9256Smrg case DRM_NODE_PRIMARY: 556fe517fc9Smrg return DRM_PRIMARY_MINOR_NAME; 557424e9256Smrg case DRM_NODE_CONTROL: 558fe517fc9Smrg return DRM_CONTROL_MINOR_NAME; 559424e9256Smrg case DRM_NODE_RENDER: 560fe517fc9Smrg return DRM_RENDER_MINOR_NAME; 561424e9256Smrg default: 562424e9256Smrg return NULL; 563424e9256Smrg } 564424e9256Smrg} 56522944501Smrg 56622944501Smrg/** 56722944501Smrg * Open the device by bus ID. 56822944501Smrg * 56922944501Smrg * \param busid bus ID. 570424e9256Smrg * \param type device node type. 57122944501Smrg * 57222944501Smrg * \return a file descriptor on success, or a negative value on error. 57322944501Smrg * 57422944501Smrg * \internal 57522944501Smrg * This function attempts to open every possible minor (up to DRM_MAX_MINOR), 57622944501Smrg * comparing the device bus ID with the one supplied. 57722944501Smrg * 57822944501Smrg * \sa drmOpenMinor() and drmGetBusid(). 57922944501Smrg */ 580424e9256Smrgstatic int drmOpenByBusid(const char *busid, int type) 58122944501Smrg{ 5826d98c517Smrg int i, pci_domain_ok = 1; 58322944501Smrg int fd; 58422944501Smrg const char *buf; 58522944501Smrg drmSetVersion sv; 586424e9256Smrg int base = drmGetMinorBase(type); 587424e9256Smrg 588424e9256Smrg if (base < 0) 589424e9256Smrg return -1; 59022944501Smrg 59122944501Smrg drmMsg("drmOpenByBusid: Searching for BusID %s\n", busid); 592424e9256Smrg for (i = base; i < base + DRM_MAX_MINOR; i++) { 593fe517fc9Smrg fd = drmOpenMinor(i, 1, type); 594fe517fc9Smrg drmMsg("drmOpenByBusid: drmOpenMinor returns %d\n", fd); 595fe517fc9Smrg if (fd >= 0) { 596fe517fc9Smrg /* We need to try for 1.4 first for proper PCI domain support 597fe517fc9Smrg * and if that fails, we know the kernel is busted 598fe517fc9Smrg */ 599fe517fc9Smrg sv.drm_di_major = 1; 600fe517fc9Smrg sv.drm_di_minor = 4; 601fe517fc9Smrg sv.drm_dd_major = -1; /* Don't care */ 602fe517fc9Smrg sv.drm_dd_minor = -1; /* Don't care */ 603fe517fc9Smrg if (drmSetInterfaceVersion(fd, &sv)) { 6046d98c517Smrg#ifndef __alpha__ 605fe517fc9Smrg pci_domain_ok = 0; 6066d98c517Smrg#endif 607fe517fc9Smrg sv.drm_di_major = 1; 608fe517fc9Smrg sv.drm_di_minor = 1; 609fe517fc9Smrg sv.drm_dd_major = -1; /* Don't care */ 610fe517fc9Smrg sv.drm_dd_minor = -1; /* Don't care */ 611fe517fc9Smrg drmMsg("drmOpenByBusid: Interface 1.4 failed, trying 1.1\n"); 612fe517fc9Smrg drmSetInterfaceVersion(fd, &sv); 613fe517fc9Smrg } 614fe517fc9Smrg buf = drmGetBusid(fd); 615fe517fc9Smrg drmMsg("drmOpenByBusid: drmGetBusid reports %s\n", buf); 616fe517fc9Smrg if (buf && drmMatchBusID(buf, busid, pci_domain_ok)) { 617fe517fc9Smrg drmFreeBusid(buf); 618fe517fc9Smrg return fd; 619fe517fc9Smrg } 620fe517fc9Smrg if (buf) 621fe517fc9Smrg drmFreeBusid(buf); 622fe517fc9Smrg close(fd); 623fe517fc9Smrg } 62422944501Smrg } 62522944501Smrg return -1; 62622944501Smrg} 62722944501Smrg 62822944501Smrg 62922944501Smrg/** 63022944501Smrg * Open the device by name. 63122944501Smrg * 63222944501Smrg * \param name driver name. 633424e9256Smrg * \param type the device node type. 634fe517fc9Smrg * 63522944501Smrg * \return a file descriptor on success, or a negative value on error. 636fe517fc9Smrg * 63722944501Smrg * \internal 63822944501Smrg * This function opens the first minor number that matches the driver name and 63922944501Smrg * isn't already in use. If it's in use it then it will already have a bus ID 64022944501Smrg * assigned. 641fe517fc9Smrg * 64222944501Smrg * \sa drmOpenMinor(), drmGetVersion() and drmGetBusid(). 64322944501Smrg */ 644424e9256Smrgstatic int drmOpenByName(const char *name, int type) 64522944501Smrg{ 64622944501Smrg int i; 64722944501Smrg int fd; 64822944501Smrg drmVersionPtr version; 64922944501Smrg char * id; 650424e9256Smrg int base = drmGetMinorBase(type); 651424e9256Smrg 652424e9256Smrg if (base < 0) 653424e9256Smrg return -1; 65422944501Smrg 65522944501Smrg /* 65622944501Smrg * Open the first minor number that matches the driver name and isn't 65722944501Smrg * already in use. If it's in use it will have a busid assigned already. 65822944501Smrg */ 659424e9256Smrg for (i = base; i < base + DRM_MAX_MINOR; i++) { 660fe517fc9Smrg if ((fd = drmOpenMinor(i, 1, type)) >= 0) { 661fe517fc9Smrg if ((version = drmGetVersion(fd))) { 662fe517fc9Smrg if (!strcmp(version->name, name)) { 663fe517fc9Smrg drmFreeVersion(version); 664fe517fc9Smrg id = drmGetBusid(fd); 665fe517fc9Smrg drmMsg("drmGetBusid returned '%s'\n", id ? id : "NULL"); 666fe517fc9Smrg if (!id || !*id) { 667fe517fc9Smrg if (id) 668fe517fc9Smrg drmFreeBusid(id); 669fe517fc9Smrg return fd; 670fe517fc9Smrg } else { 671fe517fc9Smrg drmFreeBusid(id); 672fe517fc9Smrg } 673fe517fc9Smrg } else { 674fe517fc9Smrg drmFreeVersion(version); 675fe517fc9Smrg } 676fe517fc9Smrg } 677fe517fc9Smrg close(fd); 678fe517fc9Smrg } 67922944501Smrg } 68022944501Smrg 68122944501Smrg#ifdef __linux__ 68222944501Smrg /* Backward-compatibility /proc support */ 68322944501Smrg for (i = 0; i < 8; i++) { 684fe517fc9Smrg char proc_name[64], buf[512]; 685fe517fc9Smrg char *driver, *pt, *devstring; 686fe517fc9Smrg int retcode; 687fe517fc9Smrg 688fe517fc9Smrg sprintf(proc_name, "/proc/dri/%d/name", i); 689fe517fc9Smrg if ((fd = open(proc_name, 0, 0)) >= 0) { 690fe517fc9Smrg retcode = read(fd, buf, sizeof(buf)-1); 691fe517fc9Smrg close(fd); 692fe517fc9Smrg if (retcode) { 693fe517fc9Smrg buf[retcode-1] = '\0'; 694fe517fc9Smrg for (driver = pt = buf; *pt && *pt != ' '; ++pt) 695fe517fc9Smrg ; 696fe517fc9Smrg if (*pt) { /* Device is next */ 697fe517fc9Smrg *pt = '\0'; 698fe517fc9Smrg if (!strcmp(driver, name)) { /* Match */ 699fe517fc9Smrg for (devstring = ++pt; *pt && *pt != ' '; ++pt) 700fe517fc9Smrg ; 701fe517fc9Smrg if (*pt) { /* Found busid */ 702fe517fc9Smrg return drmOpenByBusid(++pt, type); 703fe517fc9Smrg } else { /* No busid */ 704fe517fc9Smrg return drmOpenDevice(strtol(devstring, NULL, 0),i, type); 705fe517fc9Smrg } 706fe517fc9Smrg } 707fe517fc9Smrg } 708fe517fc9Smrg } 709fe517fc9Smrg } 71022944501Smrg } 71122944501Smrg#endif 71222944501Smrg 71322944501Smrg return -1; 71422944501Smrg} 71522944501Smrg 71622944501Smrg 71722944501Smrg/** 71822944501Smrg * Open the DRM device. 71922944501Smrg * 72022944501Smrg * Looks up the specified name and bus ID, and opens the device found. The 72122944501Smrg * entry in /dev/dri is created if necessary and if called by root. 72222944501Smrg * 72322944501Smrg * \param name driver name. Not referenced if bus ID is supplied. 72422944501Smrg * \param busid bus ID. Zero if not known. 725fe517fc9Smrg * 72622944501Smrg * \return a file descriptor on success, or a negative value on error. 727fe517fc9Smrg * 72822944501Smrg * \internal 72922944501Smrg * It calls drmOpenByBusid() if \p busid is specified or drmOpenByName() 73022944501Smrg * otherwise. 73122944501Smrg */ 73222944501Smrgint drmOpen(const char *name, const char *busid) 733424e9256Smrg{ 734424e9256Smrg return drmOpenWithType(name, busid, DRM_NODE_PRIMARY); 735424e9256Smrg} 736424e9256Smrg 737424e9256Smrg/** 738424e9256Smrg * Open the DRM device with specified type. 739424e9256Smrg * 740424e9256Smrg * Looks up the specified name and bus ID, and opens the device found. The 741424e9256Smrg * entry in /dev/dri is created if necessary and if called by root. 742424e9256Smrg * 743424e9256Smrg * \param name driver name. Not referenced if bus ID is supplied. 744424e9256Smrg * \param busid bus ID. Zero if not known. 745424e9256Smrg * \param type the device node type to open, PRIMARY, CONTROL or RENDER 746424e9256Smrg * 747424e9256Smrg * \return a file descriptor on success, or a negative value on error. 748424e9256Smrg * 749424e9256Smrg * \internal 750424e9256Smrg * It calls drmOpenByBusid() if \p busid is specified or drmOpenByName() 751424e9256Smrg * otherwise. 752424e9256Smrg */ 753424e9256Smrgint drmOpenWithType(const char *name, const char *busid, int type) 75422944501Smrg{ 755fe517fc9Smrg if (!drmAvailable() && name != NULL && drm_server_info && 756fe517fc9Smrg drm_server_info->load_module) { 757fe517fc9Smrg /* try to load the kernel module */ 758fe517fc9Smrg if (!drm_server_info->load_module(name)) { 759fe517fc9Smrg drmMsg("[drm] failed to load kernel module \"%s\"\n", name); 760fe517fc9Smrg return -1; 761fe517fc9Smrg } 76222944501Smrg } 76322944501Smrg 76422944501Smrg if (busid) { 765fe517fc9Smrg int fd = drmOpenByBusid(busid, type); 766fe517fc9Smrg if (fd >= 0) 767fe517fc9Smrg return fd; 76822944501Smrg } 769fe517fc9Smrg 77022944501Smrg if (name) 771fe517fc9Smrg return drmOpenByName(name, type); 77222944501Smrg 77322944501Smrg return -1; 77422944501Smrg} 77522944501Smrg 77622944501Smrgint drmOpenControl(int minor) 77722944501Smrg{ 77822944501Smrg return drmOpenMinor(minor, 0, DRM_NODE_CONTROL); 77922944501Smrg} 78022944501Smrg 781424e9256Smrgint drmOpenRender(int minor) 782424e9256Smrg{ 783424e9256Smrg return drmOpenMinor(minor, 0, DRM_NODE_RENDER); 784424e9256Smrg} 785424e9256Smrg 78622944501Smrg/** 78722944501Smrg * Free the version information returned by drmGetVersion(). 78822944501Smrg * 78922944501Smrg * \param v pointer to the version information. 79022944501Smrg * 79122944501Smrg * \internal 79222944501Smrg * It frees the memory pointed by \p %v as well as all the non-null strings 79322944501Smrg * pointers in it. 79422944501Smrg */ 79522944501Smrgvoid drmFreeVersion(drmVersionPtr v) 79622944501Smrg{ 79722944501Smrg if (!v) 798fe517fc9Smrg return; 79922944501Smrg drmFree(v->name); 80022944501Smrg drmFree(v->date); 80122944501Smrg drmFree(v->desc); 80222944501Smrg drmFree(v); 80322944501Smrg} 80422944501Smrg 80522944501Smrg 80622944501Smrg/** 80722944501Smrg * Free the non-public version information returned by the kernel. 80822944501Smrg * 80922944501Smrg * \param v pointer to the version information. 81022944501Smrg * 81122944501Smrg * \internal 81222944501Smrg * Used by drmGetVersion() to free the memory pointed by \p %v as well as all 81322944501Smrg * the non-null strings pointers in it. 81422944501Smrg */ 81522944501Smrgstatic void drmFreeKernelVersion(drm_version_t *v) 81622944501Smrg{ 81722944501Smrg if (!v) 818fe517fc9Smrg return; 81922944501Smrg drmFree(v->name); 82022944501Smrg drmFree(v->date); 82122944501Smrg drmFree(v->desc); 82222944501Smrg drmFree(v); 82322944501Smrg} 82422944501Smrg 82522944501Smrg 82622944501Smrg/** 82722944501Smrg * Copy version information. 828fe517fc9Smrg * 82922944501Smrg * \param d destination pointer. 83022944501Smrg * \param s source pointer. 831fe517fc9Smrg * 83222944501Smrg * \internal 83322944501Smrg * Used by drmGetVersion() to translate the information returned by the ioctl 83422944501Smrg * interface in a private structure into the public structure counterpart. 83522944501Smrg */ 83622944501Smrgstatic void drmCopyVersion(drmVersionPtr d, const drm_version_t *s) 83722944501Smrg{ 83822944501Smrg d->version_major = s->version_major; 83922944501Smrg d->version_minor = s->version_minor; 84022944501Smrg d->version_patchlevel = s->version_patchlevel; 84122944501Smrg d->name_len = s->name_len; 8429ce4edccSmrg d->name = strdup(s->name); 84322944501Smrg d->date_len = s->date_len; 8449ce4edccSmrg d->date = strdup(s->date); 84522944501Smrg d->desc_len = s->desc_len; 8469ce4edccSmrg d->desc = strdup(s->desc); 84722944501Smrg} 84822944501Smrg 84922944501Smrg 85022944501Smrg/** 85122944501Smrg * Query the driver version information. 85222944501Smrg * 85322944501Smrg * \param fd file descriptor. 854fe517fc9Smrg * 85522944501Smrg * \return pointer to a drmVersion structure which should be freed with 85622944501Smrg * drmFreeVersion(). 857fe517fc9Smrg * 85822944501Smrg * \note Similar information is available via /proc/dri. 859fe517fc9Smrg * 86022944501Smrg * \internal 86122944501Smrg * It gets the version information via successive DRM_IOCTL_VERSION ioctls, 86222944501Smrg * first with zeros to get the string lengths, and then the actually strings. 86322944501Smrg * It also null-terminates them since they might not be already. 86422944501Smrg */ 86522944501SmrgdrmVersionPtr drmGetVersion(int fd) 86622944501Smrg{ 86722944501Smrg drmVersionPtr retval; 86822944501Smrg drm_version_t *version = drmMalloc(sizeof(*version)); 86922944501Smrg 87022944501Smrg if (drmIoctl(fd, DRM_IOCTL_VERSION, version)) { 871fe517fc9Smrg drmFreeKernelVersion(version); 872fe517fc9Smrg return NULL; 87322944501Smrg } 87422944501Smrg 87522944501Smrg if (version->name_len) 876fe517fc9Smrg version->name = drmMalloc(version->name_len + 1); 87722944501Smrg if (version->date_len) 878fe517fc9Smrg version->date = drmMalloc(version->date_len + 1); 87922944501Smrg if (version->desc_len) 880fe517fc9Smrg version->desc = drmMalloc(version->desc_len + 1); 88122944501Smrg 88222944501Smrg if (drmIoctl(fd, DRM_IOCTL_VERSION, version)) { 883fe517fc9Smrg drmMsg("DRM_IOCTL_VERSION: %s\n", strerror(errno)); 884fe517fc9Smrg drmFreeKernelVersion(version); 885fe517fc9Smrg return NULL; 88622944501Smrg } 88722944501Smrg 88822944501Smrg /* The results might not be null-terminated strings, so terminate them. */ 88922944501Smrg if (version->name_len) version->name[version->name_len] = '\0'; 89022944501Smrg if (version->date_len) version->date[version->date_len] = '\0'; 89122944501Smrg if (version->desc_len) version->desc[version->desc_len] = '\0'; 89222944501Smrg 89322944501Smrg retval = drmMalloc(sizeof(*retval)); 89422944501Smrg drmCopyVersion(retval, version); 89522944501Smrg drmFreeKernelVersion(version); 89622944501Smrg return retval; 89722944501Smrg} 89822944501Smrg 89922944501Smrg 90022944501Smrg/** 90122944501Smrg * Get version information for the DRM user space library. 902fe517fc9Smrg * 90322944501Smrg * This version number is driver independent. 904fe517fc9Smrg * 90522944501Smrg * \param fd file descriptor. 90622944501Smrg * 90722944501Smrg * \return version information. 908fe517fc9Smrg * 90922944501Smrg * \internal 91022944501Smrg * This function allocates and fills a drm_version structure with a hard coded 91122944501Smrg * version number. 91222944501Smrg */ 91322944501SmrgdrmVersionPtr drmGetLibVersion(int fd) 91422944501Smrg{ 91522944501Smrg drm_version_t *version = drmMalloc(sizeof(*version)); 91622944501Smrg 91722944501Smrg /* Version history: 91822944501Smrg * NOTE THIS MUST NOT GO ABOVE VERSION 1.X due to drivers needing it 91922944501Smrg * revision 1.0.x = original DRM interface with no drmGetLibVersion 92022944501Smrg * entry point and many drm<Device> extensions 92122944501Smrg * revision 1.1.x = added drmCommand entry points for device extensions 92222944501Smrg * added drmGetLibVersion to identify libdrm.a version 92322944501Smrg * revision 1.2.x = added drmSetInterfaceVersion 92422944501Smrg * modified drmOpen to handle both busid and name 92522944501Smrg * revision 1.3.x = added server + memory manager 92622944501Smrg */ 92722944501Smrg version->version_major = 1; 92822944501Smrg version->version_minor = 3; 92922944501Smrg version->version_patchlevel = 0; 93022944501Smrg 93122944501Smrg return (drmVersionPtr)version; 93222944501Smrg} 93322944501Smrg 93420131375Smrgint drmGetCap(int fd, uint64_t capability, uint64_t *value) 93520131375Smrg{ 936fe517fc9Smrg struct drm_get_cap cap; 937fe517fc9Smrg int ret; 93820131375Smrg 939fe517fc9Smrg memclear(cap); 940fe517fc9Smrg cap.capability = capability; 941424e9256Smrg 942fe517fc9Smrg ret = drmIoctl(fd, DRM_IOCTL_GET_CAP, &cap); 943fe517fc9Smrg if (ret) 944fe517fc9Smrg return ret; 94520131375Smrg 946fe517fc9Smrg *value = cap.value; 947fe517fc9Smrg return 0; 94820131375Smrg} 94920131375Smrg 95020131375Smrgint drmSetClientCap(int fd, uint64_t capability, uint64_t value) 95120131375Smrg{ 952fe517fc9Smrg struct drm_set_client_cap cap; 953424e9256Smrg 954fe517fc9Smrg memclear(cap); 955fe517fc9Smrg cap.capability = capability; 956fe517fc9Smrg cap.value = value; 95720131375Smrg 958fe517fc9Smrg return drmIoctl(fd, DRM_IOCTL_SET_CLIENT_CAP, &cap); 95920131375Smrg} 96022944501Smrg 96122944501Smrg/** 96222944501Smrg * Free the bus ID information. 96322944501Smrg * 96422944501Smrg * \param busid bus ID information string as given by drmGetBusid(). 96522944501Smrg * 96622944501Smrg * \internal 96722944501Smrg * This function is just frees the memory pointed by \p busid. 96822944501Smrg */ 96922944501Smrgvoid drmFreeBusid(const char *busid) 97022944501Smrg{ 97122944501Smrg drmFree((void *)busid); 97222944501Smrg} 97322944501Smrg 97422944501Smrg 97522944501Smrg/** 97622944501Smrg * Get the bus ID of the device. 97722944501Smrg * 97822944501Smrg * \param fd file descriptor. 97922944501Smrg * 98022944501Smrg * \return bus ID string. 98122944501Smrg * 98222944501Smrg * \internal 98322944501Smrg * This function gets the bus ID via successive DRM_IOCTL_GET_UNIQUE ioctls to 98422944501Smrg * get the string length and data, passing the arguments in a drm_unique 98522944501Smrg * structure. 98622944501Smrg */ 98722944501Smrgchar *drmGetBusid(int fd) 98822944501Smrg{ 98922944501Smrg drm_unique_t u; 99022944501Smrg 991424e9256Smrg memclear(u); 99222944501Smrg 99322944501Smrg if (drmIoctl(fd, DRM_IOCTL_GET_UNIQUE, &u)) 994fe517fc9Smrg return NULL; 99522944501Smrg u.unique = drmMalloc(u.unique_len + 1); 9960655efefSmrg if (drmIoctl(fd, DRM_IOCTL_GET_UNIQUE, &u)) { 9970655efefSmrg drmFree(u.unique); 998fe517fc9Smrg return NULL; 9990655efefSmrg } 100022944501Smrg u.unique[u.unique_len] = '\0'; 100122944501Smrg 100222944501Smrg return u.unique; 100322944501Smrg} 100422944501Smrg 100522944501Smrg 100622944501Smrg/** 100722944501Smrg * Set the bus ID of the device. 100822944501Smrg * 100922944501Smrg * \param fd file descriptor. 101022944501Smrg * \param busid bus ID string. 101122944501Smrg * 101222944501Smrg * \return zero on success, negative on failure. 101322944501Smrg * 101422944501Smrg * \internal 101522944501Smrg * This function is a wrapper around the DRM_IOCTL_SET_UNIQUE ioctl, passing 101622944501Smrg * the arguments in a drm_unique structure. 101722944501Smrg */ 101822944501Smrgint drmSetBusid(int fd, const char *busid) 101922944501Smrg{ 102022944501Smrg drm_unique_t u; 102122944501Smrg 1022424e9256Smrg memclear(u); 102322944501Smrg u.unique = (char *)busid; 102422944501Smrg u.unique_len = strlen(busid); 102522944501Smrg 102622944501Smrg if (drmIoctl(fd, DRM_IOCTL_SET_UNIQUE, &u)) { 1027fe517fc9Smrg return -errno; 102822944501Smrg } 102922944501Smrg return 0; 103022944501Smrg} 103122944501Smrg 103222944501Smrgint drmGetMagic(int fd, drm_magic_t * magic) 103322944501Smrg{ 103422944501Smrg drm_auth_t auth; 103522944501Smrg 1036424e9256Smrg memclear(auth); 1037424e9256Smrg 103822944501Smrg *magic = 0; 103922944501Smrg if (drmIoctl(fd, DRM_IOCTL_GET_MAGIC, &auth)) 1040fe517fc9Smrg return -errno; 104122944501Smrg *magic = auth.magic; 104222944501Smrg return 0; 104322944501Smrg} 104422944501Smrg 104522944501Smrgint drmAuthMagic(int fd, drm_magic_t magic) 104622944501Smrg{ 104722944501Smrg drm_auth_t auth; 104822944501Smrg 1049424e9256Smrg memclear(auth); 105022944501Smrg auth.magic = magic; 105122944501Smrg if (drmIoctl(fd, DRM_IOCTL_AUTH_MAGIC, &auth)) 1052fe517fc9Smrg return -errno; 105322944501Smrg return 0; 105422944501Smrg} 105522944501Smrg 105622944501Smrg/** 105722944501Smrg * Specifies a range of memory that is available for mapping by a 105822944501Smrg * non-root process. 105922944501Smrg * 106022944501Smrg * \param fd file descriptor. 106122944501Smrg * \param offset usually the physical address. The actual meaning depends of 106222944501Smrg * the \p type parameter. See below. 106322944501Smrg * \param size of the memory in bytes. 106422944501Smrg * \param type type of the memory to be mapped. 106522944501Smrg * \param flags combination of several flags to modify the function actions. 106622944501Smrg * \param handle will be set to a value that may be used as the offset 106722944501Smrg * parameter for mmap(). 1068fe517fc9Smrg * 106922944501Smrg * \return zero on success or a negative value on error. 107022944501Smrg * 107122944501Smrg * \par Mapping the frame buffer 107222944501Smrg * For the frame buffer 107322944501Smrg * - \p offset will be the physical address of the start of the frame buffer, 107422944501Smrg * - \p size will be the size of the frame buffer in bytes, and 107522944501Smrg * - \p type will be DRM_FRAME_BUFFER. 107622944501Smrg * 107722944501Smrg * \par 107822944501Smrg * The area mapped will be uncached. If MTRR support is available in the 1079fe517fc9Smrg * kernel, the frame buffer area will be set to write combining. 108022944501Smrg * 108122944501Smrg * \par Mapping the MMIO register area 108222944501Smrg * For the MMIO register area, 108322944501Smrg * - \p offset will be the physical address of the start of the register area, 108422944501Smrg * - \p size will be the size of the register area bytes, and 108522944501Smrg * - \p type will be DRM_REGISTERS. 108622944501Smrg * \par 1087fe517fc9Smrg * The area mapped will be uncached. 1088fe517fc9Smrg * 108922944501Smrg * \par Mapping the SAREA 109022944501Smrg * For the SAREA, 109122944501Smrg * - \p offset will be ignored and should be set to zero, 109222944501Smrg * - \p size will be the desired size of the SAREA in bytes, 109322944501Smrg * - \p type will be DRM_SHM. 1094fe517fc9Smrg * 109522944501Smrg * \par 109622944501Smrg * A shared memory area of the requested size will be created and locked in 109722944501Smrg * kernel memory. This area may be mapped into client-space by using the handle 1098fe517fc9Smrg * returned. 1099fe517fc9Smrg * 110022944501Smrg * \note May only be called by root. 110122944501Smrg * 110222944501Smrg * \internal 110322944501Smrg * This function is a wrapper around the DRM_IOCTL_ADD_MAP ioctl, passing 110422944501Smrg * the arguments in a drm_map structure. 110522944501Smrg */ 110622944501Smrgint drmAddMap(int fd, drm_handle_t offset, drmSize size, drmMapType type, 1107fe517fc9Smrg drmMapFlags flags, drm_handle_t *handle) 110822944501Smrg{ 110922944501Smrg drm_map_t map; 111022944501Smrg 1111424e9256Smrg memclear(map); 111222944501Smrg map.offset = offset; 111322944501Smrg map.size = size; 111422944501Smrg map.type = type; 111522944501Smrg map.flags = flags; 111622944501Smrg if (drmIoctl(fd, DRM_IOCTL_ADD_MAP, &map)) 1117fe517fc9Smrg return -errno; 111822944501Smrg if (handle) 1119fe517fc9Smrg *handle = (drm_handle_t)(uintptr_t)map.handle; 112022944501Smrg return 0; 112122944501Smrg} 112222944501Smrg 112322944501Smrgint drmRmMap(int fd, drm_handle_t handle) 112422944501Smrg{ 112522944501Smrg drm_map_t map; 112622944501Smrg 1127424e9256Smrg memclear(map); 112820131375Smrg map.handle = (void *)(uintptr_t)handle; 112922944501Smrg 113022944501Smrg if(drmIoctl(fd, DRM_IOCTL_RM_MAP, &map)) 1131fe517fc9Smrg return -errno; 113222944501Smrg return 0; 113322944501Smrg} 113422944501Smrg 113522944501Smrg/** 113622944501Smrg * Make buffers available for DMA transfers. 1137fe517fc9Smrg * 113822944501Smrg * \param fd file descriptor. 113922944501Smrg * \param count number of buffers. 114022944501Smrg * \param size size of each buffer. 114122944501Smrg * \param flags buffer allocation flags. 1142fe517fc9Smrg * \param agp_offset offset in the AGP aperture 114322944501Smrg * 114422944501Smrg * \return number of buffers allocated, negative on error. 114522944501Smrg * 114622944501Smrg * \internal 114722944501Smrg * This function is a wrapper around DRM_IOCTL_ADD_BUFS ioctl. 114822944501Smrg * 114922944501Smrg * \sa drm_buf_desc. 115022944501Smrg */ 115122944501Smrgint drmAddBufs(int fd, int count, int size, drmBufDescFlags flags, 1152fe517fc9Smrg int agp_offset) 115322944501Smrg{ 115422944501Smrg drm_buf_desc_t request; 115522944501Smrg 1156424e9256Smrg memclear(request); 115722944501Smrg request.count = count; 115822944501Smrg request.size = size; 115922944501Smrg request.flags = flags; 116022944501Smrg request.agp_start = agp_offset; 116122944501Smrg 116222944501Smrg if (drmIoctl(fd, DRM_IOCTL_ADD_BUFS, &request)) 1163fe517fc9Smrg return -errno; 116422944501Smrg return request.count; 116522944501Smrg} 116622944501Smrg 116722944501Smrgint drmMarkBufs(int fd, double low, double high) 116822944501Smrg{ 116922944501Smrg drm_buf_info_t info; 117022944501Smrg int i; 117122944501Smrg 1172424e9256Smrg memclear(info); 117322944501Smrg 117422944501Smrg if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info)) 1175fe517fc9Smrg return -EINVAL; 117622944501Smrg 117722944501Smrg if (!info.count) 1178fe517fc9Smrg return -EINVAL; 117922944501Smrg 118022944501Smrg if (!(info.list = drmMalloc(info.count * sizeof(*info.list)))) 1181fe517fc9Smrg return -ENOMEM; 118222944501Smrg 118322944501Smrg if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info)) { 1184fe517fc9Smrg int retval = -errno; 1185fe517fc9Smrg drmFree(info.list); 1186fe517fc9Smrg return retval; 118722944501Smrg } 118822944501Smrg 118922944501Smrg for (i = 0; i < info.count; i++) { 1190fe517fc9Smrg info.list[i].low_mark = low * info.list[i].count; 1191fe517fc9Smrg info.list[i].high_mark = high * info.list[i].count; 1192fe517fc9Smrg if (drmIoctl(fd, DRM_IOCTL_MARK_BUFS, &info.list[i])) { 1193fe517fc9Smrg int retval = -errno; 1194fe517fc9Smrg drmFree(info.list); 1195fe517fc9Smrg return retval; 1196fe517fc9Smrg } 119722944501Smrg } 119822944501Smrg drmFree(info.list); 119922944501Smrg 120022944501Smrg return 0; 120122944501Smrg} 120222944501Smrg 120322944501Smrg/** 120422944501Smrg * Free buffers. 120522944501Smrg * 120622944501Smrg * \param fd file descriptor. 120722944501Smrg * \param count number of buffers to free. 120822944501Smrg * \param list list of buffers to be freed. 120922944501Smrg * 121022944501Smrg * \return zero on success, or a negative value on failure. 1211fe517fc9Smrg * 121222944501Smrg * \note This function is primarily used for debugging. 1213fe517fc9Smrg * 121422944501Smrg * \internal 121522944501Smrg * This function is a wrapper around the DRM_IOCTL_FREE_BUFS ioctl, passing 121622944501Smrg * the arguments in a drm_buf_free structure. 121722944501Smrg */ 121822944501Smrgint drmFreeBufs(int fd, int count, int *list) 121922944501Smrg{ 122022944501Smrg drm_buf_free_t request; 122122944501Smrg 1222424e9256Smrg memclear(request); 122322944501Smrg request.count = count; 122422944501Smrg request.list = list; 122522944501Smrg if (drmIoctl(fd, DRM_IOCTL_FREE_BUFS, &request)) 1226fe517fc9Smrg return -errno; 122722944501Smrg return 0; 122822944501Smrg} 122922944501Smrg 123022944501Smrg 123122944501Smrg/** 123222944501Smrg * Close the device. 123322944501Smrg * 123422944501Smrg * \param fd file descriptor. 123522944501Smrg * 123622944501Smrg * \internal 123722944501Smrg * This function closes the file descriptor. 123822944501Smrg */ 123922944501Smrgint drmClose(int fd) 124022944501Smrg{ 124122944501Smrg unsigned long key = drmGetKeyFromFd(fd); 124222944501Smrg drmHashEntry *entry = drmGetEntry(fd); 124322944501Smrg 124422944501Smrg drmHashDestroy(entry->tagTable); 124522944501Smrg entry->fd = 0; 124622944501Smrg entry->f = NULL; 124722944501Smrg entry->tagTable = NULL; 124822944501Smrg 124922944501Smrg drmHashDelete(drmHashTable, key); 125022944501Smrg drmFree(entry); 125122944501Smrg 125222944501Smrg return close(fd); 125322944501Smrg} 125422944501Smrg 125522944501Smrg 125622944501Smrg/** 125722944501Smrg * Map a region of memory. 125822944501Smrg * 125922944501Smrg * \param fd file descriptor. 126022944501Smrg * \param handle handle returned by drmAddMap(). 126122944501Smrg * \param size size in bytes. Must match the size used by drmAddMap(). 126222944501Smrg * \param address will contain the user-space virtual address where the mapping 126322944501Smrg * begins. 126422944501Smrg * 126522944501Smrg * \return zero on success, or a negative value on failure. 1266fe517fc9Smrg * 126722944501Smrg * \internal 126822944501Smrg * This function is a wrapper for mmap(). 126922944501Smrg */ 127022944501Smrgint drmMap(int fd, drm_handle_t handle, drmSize size, drmAddressPtr address) 127122944501Smrg{ 127222944501Smrg static unsigned long pagesize_mask = 0; 127322944501Smrg 127422944501Smrg if (fd < 0) 1275fe517fc9Smrg return -EINVAL; 127622944501Smrg 127722944501Smrg if (!pagesize_mask) 1278fe517fc9Smrg pagesize_mask = getpagesize() - 1; 127922944501Smrg 128022944501Smrg size = (size + pagesize_mask) & ~pagesize_mask; 128122944501Smrg 1282a884aba1Smrg *address = drm_mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, handle); 128322944501Smrg if (*address == MAP_FAILED) 1284fe517fc9Smrg return -errno; 128522944501Smrg return 0; 128622944501Smrg} 128722944501Smrg 128822944501Smrg 128922944501Smrg/** 129022944501Smrg * Unmap mappings obtained with drmMap(). 129122944501Smrg * 129222944501Smrg * \param address address as given by drmMap(). 129322944501Smrg * \param size size in bytes. Must match the size used by drmMap(). 1294fe517fc9Smrg * 129522944501Smrg * \return zero on success, or a negative value on failure. 129622944501Smrg * 129722944501Smrg * \internal 129822944501Smrg * This function is a wrapper for munmap(). 129922944501Smrg */ 130022944501Smrgint drmUnmap(drmAddress address, drmSize size) 130122944501Smrg{ 1302a884aba1Smrg return drm_munmap(address, size); 130322944501Smrg} 130422944501Smrg 130522944501SmrgdrmBufInfoPtr drmGetBufInfo(int fd) 130622944501Smrg{ 130722944501Smrg drm_buf_info_t info; 130822944501Smrg drmBufInfoPtr retval; 130922944501Smrg int i; 131022944501Smrg 1311424e9256Smrg memclear(info); 131222944501Smrg 131322944501Smrg if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info)) 1314fe517fc9Smrg return NULL; 131522944501Smrg 131622944501Smrg if (info.count) { 1317fe517fc9Smrg if (!(info.list = drmMalloc(info.count * sizeof(*info.list)))) 1318fe517fc9Smrg return NULL; 1319fe517fc9Smrg 1320fe517fc9Smrg if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info)) { 1321fe517fc9Smrg drmFree(info.list); 1322fe517fc9Smrg return NULL; 1323fe517fc9Smrg } 1324fe517fc9Smrg 1325fe517fc9Smrg retval = drmMalloc(sizeof(*retval)); 1326fe517fc9Smrg retval->count = info.count; 1327fe517fc9Smrg retval->list = drmMalloc(info.count * sizeof(*retval->list)); 1328fe517fc9Smrg for (i = 0; i < info.count; i++) { 1329fe517fc9Smrg retval->list[i].count = info.list[i].count; 1330fe517fc9Smrg retval->list[i].size = info.list[i].size; 1331fe517fc9Smrg retval->list[i].low_mark = info.list[i].low_mark; 1332fe517fc9Smrg retval->list[i].high_mark = info.list[i].high_mark; 1333fe517fc9Smrg } 1334fe517fc9Smrg drmFree(info.list); 1335fe517fc9Smrg return retval; 133622944501Smrg } 133722944501Smrg return NULL; 133822944501Smrg} 133922944501Smrg 134022944501Smrg/** 134122944501Smrg * Map all DMA buffers into client-virtual space. 134222944501Smrg * 134322944501Smrg * \param fd file descriptor. 134422944501Smrg * 134522944501Smrg * \return a pointer to a ::drmBufMap structure. 134622944501Smrg * 134722944501Smrg * \note The client may not use these buffers until obtaining buffer indices 134822944501Smrg * with drmDMA(). 1349fe517fc9Smrg * 135022944501Smrg * \internal 135122944501Smrg * This function calls the DRM_IOCTL_MAP_BUFS ioctl and copies the returned 135222944501Smrg * information about the buffers in a drm_buf_map structure into the 135322944501Smrg * client-visible data structures. 1354fe517fc9Smrg */ 135522944501SmrgdrmBufMapPtr drmMapBufs(int fd) 135622944501Smrg{ 135722944501Smrg drm_buf_map_t bufs; 135822944501Smrg drmBufMapPtr retval; 135922944501Smrg int i; 136022944501Smrg 1361424e9256Smrg memclear(bufs); 136222944501Smrg if (drmIoctl(fd, DRM_IOCTL_MAP_BUFS, &bufs)) 1363fe517fc9Smrg return NULL; 136422944501Smrg 136522944501Smrg if (!bufs.count) 1366fe517fc9Smrg return NULL; 136722944501Smrg 1368fe517fc9Smrg if (!(bufs.list = drmMalloc(bufs.count * sizeof(*bufs.list)))) 1369fe517fc9Smrg return NULL; 137022944501Smrg 1371fe517fc9Smrg if (drmIoctl(fd, DRM_IOCTL_MAP_BUFS, &bufs)) { 1372fe517fc9Smrg drmFree(bufs.list); 1373fe517fc9Smrg return NULL; 1374fe517fc9Smrg } 137522944501Smrg 1376fe517fc9Smrg retval = drmMalloc(sizeof(*retval)); 1377fe517fc9Smrg retval->count = bufs.count; 1378fe517fc9Smrg retval->list = drmMalloc(bufs.count * sizeof(*retval->list)); 1379fe517fc9Smrg for (i = 0; i < bufs.count; i++) { 1380fe517fc9Smrg retval->list[i].idx = bufs.list[i].idx; 1381fe517fc9Smrg retval->list[i].total = bufs.list[i].total; 1382fe517fc9Smrg retval->list[i].used = 0; 1383fe517fc9Smrg retval->list[i].address = bufs.list[i].address; 1384fe517fc9Smrg } 138522944501Smrg 1386fe517fc9Smrg drmFree(bufs.list); 1387fe517fc9Smrg return retval; 138822944501Smrg} 138922944501Smrg 139022944501Smrg 139122944501Smrg/** 139222944501Smrg * Unmap buffers allocated with drmMapBufs(). 139322944501Smrg * 139422944501Smrg * \return zero on success, or negative value on failure. 139522944501Smrg * 139622944501Smrg * \internal 139722944501Smrg * Calls munmap() for every buffer stored in \p bufs and frees the 139822944501Smrg * memory allocated by drmMapBufs(). 139922944501Smrg */ 140022944501Smrgint drmUnmapBufs(drmBufMapPtr bufs) 140122944501Smrg{ 140222944501Smrg int i; 140322944501Smrg 140422944501Smrg for (i = 0; i < bufs->count; i++) { 1405fe517fc9Smrg drm_munmap(bufs->list[i].address, bufs->list[i].total); 140622944501Smrg } 140722944501Smrg 140822944501Smrg drmFree(bufs->list); 140922944501Smrg drmFree(bufs); 141022944501Smrg return 0; 141122944501Smrg} 141222944501Smrg 141322944501Smrg 1414fe517fc9Smrg#define DRM_DMA_RETRY 16 141522944501Smrg 141622944501Smrg/** 141722944501Smrg * Reserve DMA buffers. 141822944501Smrg * 141922944501Smrg * \param fd file descriptor. 1420fe517fc9Smrg * \param request 1421fe517fc9Smrg * 142222944501Smrg * \return zero on success, or a negative value on failure. 142322944501Smrg * 142422944501Smrg * \internal 142522944501Smrg * Assemble the arguments into a drm_dma structure and keeps issuing the 142622944501Smrg * DRM_IOCTL_DMA ioctl until success or until maximum number of retries. 142722944501Smrg */ 142822944501Smrgint drmDMA(int fd, drmDMAReqPtr request) 142922944501Smrg{ 143022944501Smrg drm_dma_t dma; 143122944501Smrg int ret, i = 0; 143222944501Smrg 143322944501Smrg dma.context = request->context; 143422944501Smrg dma.send_count = request->send_count; 143522944501Smrg dma.send_indices = request->send_list; 143622944501Smrg dma.send_sizes = request->send_sizes; 143722944501Smrg dma.flags = request->flags; 143822944501Smrg dma.request_count = request->request_count; 143922944501Smrg dma.request_size = request->request_size; 144022944501Smrg dma.request_indices = request->request_list; 144122944501Smrg dma.request_sizes = request->request_sizes; 144222944501Smrg dma.granted_count = 0; 144322944501Smrg 144422944501Smrg do { 1445fe517fc9Smrg ret = ioctl( fd, DRM_IOCTL_DMA, &dma ); 144622944501Smrg } while ( ret && errno == EAGAIN && i++ < DRM_DMA_RETRY ); 144722944501Smrg 144822944501Smrg if ( ret == 0 ) { 1449fe517fc9Smrg request->granted_count = dma.granted_count; 1450fe517fc9Smrg return 0; 145122944501Smrg } else { 1452fe517fc9Smrg return -errno; 145322944501Smrg } 145422944501Smrg} 145522944501Smrg 145622944501Smrg 145722944501Smrg/** 145822944501Smrg * Obtain heavyweight hardware lock. 145922944501Smrg * 146022944501Smrg * \param fd file descriptor. 146122944501Smrg * \param context context. 146222944501Smrg * \param flags flags that determine the sate of the hardware when the function 146322944501Smrg * returns. 1464fe517fc9Smrg * 146522944501Smrg * \return always zero. 1466fe517fc9Smrg * 146722944501Smrg * \internal 146822944501Smrg * This function translates the arguments into a drm_lock structure and issue 146922944501Smrg * the DRM_IOCTL_LOCK ioctl until the lock is successfully acquired. 147022944501Smrg */ 147122944501Smrgint drmGetLock(int fd, drm_context_t context, drmLockFlags flags) 147222944501Smrg{ 147322944501Smrg drm_lock_t lock; 147422944501Smrg 1475424e9256Smrg memclear(lock); 147622944501Smrg lock.context = context; 147722944501Smrg lock.flags = 0; 147822944501Smrg if (flags & DRM_LOCK_READY) lock.flags |= _DRM_LOCK_READY; 147922944501Smrg if (flags & DRM_LOCK_QUIESCENT) lock.flags |= _DRM_LOCK_QUIESCENT; 148022944501Smrg if (flags & DRM_LOCK_FLUSH) lock.flags |= _DRM_LOCK_FLUSH; 148122944501Smrg if (flags & DRM_LOCK_FLUSH_ALL) lock.flags |= _DRM_LOCK_FLUSH_ALL; 148222944501Smrg if (flags & DRM_HALT_ALL_QUEUES) lock.flags |= _DRM_HALT_ALL_QUEUES; 148322944501Smrg if (flags & DRM_HALT_CUR_QUEUES) lock.flags |= _DRM_HALT_CUR_QUEUES; 148422944501Smrg 148522944501Smrg while (drmIoctl(fd, DRM_IOCTL_LOCK, &lock)) 1486fe517fc9Smrg ; 148722944501Smrg return 0; 148822944501Smrg} 148922944501Smrg 149022944501Smrg/** 149122944501Smrg * Release the hardware lock. 149222944501Smrg * 149322944501Smrg * \param fd file descriptor. 149422944501Smrg * \param context context. 1495fe517fc9Smrg * 149622944501Smrg * \return zero on success, or a negative value on failure. 1497fe517fc9Smrg * 149822944501Smrg * \internal 149922944501Smrg * This function is a wrapper around the DRM_IOCTL_UNLOCK ioctl, passing the 150022944501Smrg * argument in a drm_lock structure. 150122944501Smrg */ 150222944501Smrgint drmUnlock(int fd, drm_context_t context) 150322944501Smrg{ 150422944501Smrg drm_lock_t lock; 150522944501Smrg 1506424e9256Smrg memclear(lock); 150722944501Smrg lock.context = context; 150822944501Smrg return drmIoctl(fd, DRM_IOCTL_UNLOCK, &lock); 150922944501Smrg} 151022944501Smrg 151122944501Smrgdrm_context_t *drmGetReservedContextList(int fd, int *count) 151222944501Smrg{ 151322944501Smrg drm_ctx_res_t res; 151422944501Smrg drm_ctx_t *list; 151522944501Smrg drm_context_t * retval; 151622944501Smrg int i; 151722944501Smrg 1518424e9256Smrg memclear(res); 151922944501Smrg if (drmIoctl(fd, DRM_IOCTL_RES_CTX, &res)) 1520fe517fc9Smrg return NULL; 152122944501Smrg 152222944501Smrg if (!res.count) 1523fe517fc9Smrg return NULL; 152422944501Smrg 152522944501Smrg if (!(list = drmMalloc(res.count * sizeof(*list)))) 1526fe517fc9Smrg return NULL; 15270655efefSmrg if (!(retval = drmMalloc(res.count * sizeof(*retval)))) 15280655efefSmrg goto err_free_list; 152922944501Smrg 153022944501Smrg res.contexts = list; 153122944501Smrg if (drmIoctl(fd, DRM_IOCTL_RES_CTX, &res)) 15320655efefSmrg goto err_free_context; 153322944501Smrg 153422944501Smrg for (i = 0; i < res.count; i++) 1535fe517fc9Smrg retval[i] = list[i].handle; 153622944501Smrg drmFree(list); 153722944501Smrg 153822944501Smrg *count = res.count; 153922944501Smrg return retval; 15400655efefSmrg 15410655efefSmrgerr_free_list: 15420655efefSmrg drmFree(list); 15430655efefSmrgerr_free_context: 15440655efefSmrg drmFree(retval); 15450655efefSmrg return NULL; 154622944501Smrg} 154722944501Smrg 154822944501Smrgvoid drmFreeReservedContextList(drm_context_t *pt) 154922944501Smrg{ 155022944501Smrg drmFree(pt); 155122944501Smrg} 155222944501Smrg 155322944501Smrg/** 155422944501Smrg * Create context. 155522944501Smrg * 155622944501Smrg * Used by the X server during GLXContext initialization. This causes 155722944501Smrg * per-context kernel-level resources to be allocated. 155822944501Smrg * 155922944501Smrg * \param fd file descriptor. 156022944501Smrg * \param handle is set on success. To be used by the client when requesting DMA 156122944501Smrg * dispatch with drmDMA(). 1562fe517fc9Smrg * 156322944501Smrg * \return zero on success, or a negative value on failure. 1564fe517fc9Smrg * 156522944501Smrg * \note May only be called by root. 1566fe517fc9Smrg * 156722944501Smrg * \internal 156822944501Smrg * This function is a wrapper around the DRM_IOCTL_ADD_CTX ioctl, passing the 156922944501Smrg * argument in a drm_ctx structure. 157022944501Smrg */ 157122944501Smrgint drmCreateContext(int fd, drm_context_t *handle) 157222944501Smrg{ 157322944501Smrg drm_ctx_t ctx; 157422944501Smrg 1575424e9256Smrg memclear(ctx); 157622944501Smrg if (drmIoctl(fd, DRM_IOCTL_ADD_CTX, &ctx)) 1577fe517fc9Smrg return -errno; 157822944501Smrg *handle = ctx.handle; 157922944501Smrg return 0; 158022944501Smrg} 158122944501Smrg 158222944501Smrgint drmSwitchToContext(int fd, drm_context_t context) 158322944501Smrg{ 158422944501Smrg drm_ctx_t ctx; 158522944501Smrg 1586424e9256Smrg memclear(ctx); 158722944501Smrg ctx.handle = context; 158822944501Smrg if (drmIoctl(fd, DRM_IOCTL_SWITCH_CTX, &ctx)) 1589fe517fc9Smrg return -errno; 159022944501Smrg return 0; 159122944501Smrg} 159222944501Smrg 159322944501Smrgint drmSetContextFlags(int fd, drm_context_t context, drm_context_tFlags flags) 159422944501Smrg{ 159522944501Smrg drm_ctx_t ctx; 159622944501Smrg 159722944501Smrg /* 159822944501Smrg * Context preserving means that no context switches are done between DMA 159922944501Smrg * buffers from one context and the next. This is suitable for use in the 160022944501Smrg * X server (which promises to maintain hardware context), or in the 160122944501Smrg * client-side library when buffers are swapped on behalf of two threads. 160222944501Smrg */ 1603424e9256Smrg memclear(ctx); 160422944501Smrg ctx.handle = context; 160522944501Smrg if (flags & DRM_CONTEXT_PRESERVED) 1606fe517fc9Smrg ctx.flags |= _DRM_CONTEXT_PRESERVED; 160722944501Smrg if (flags & DRM_CONTEXT_2DONLY) 1608fe517fc9Smrg ctx.flags |= _DRM_CONTEXT_2DONLY; 160922944501Smrg if (drmIoctl(fd, DRM_IOCTL_MOD_CTX, &ctx)) 1610fe517fc9Smrg return -errno; 161122944501Smrg return 0; 161222944501Smrg} 161322944501Smrg 161422944501Smrgint drmGetContextFlags(int fd, drm_context_t context, 161522944501Smrg drm_context_tFlagsPtr flags) 161622944501Smrg{ 161722944501Smrg drm_ctx_t ctx; 161822944501Smrg 1619424e9256Smrg memclear(ctx); 162022944501Smrg ctx.handle = context; 162122944501Smrg if (drmIoctl(fd, DRM_IOCTL_GET_CTX, &ctx)) 1622fe517fc9Smrg return -errno; 162322944501Smrg *flags = 0; 162422944501Smrg if (ctx.flags & _DRM_CONTEXT_PRESERVED) 1625fe517fc9Smrg *flags |= DRM_CONTEXT_PRESERVED; 162622944501Smrg if (ctx.flags & _DRM_CONTEXT_2DONLY) 1627fe517fc9Smrg *flags |= DRM_CONTEXT_2DONLY; 162822944501Smrg return 0; 162922944501Smrg} 163022944501Smrg 163122944501Smrg/** 163222944501Smrg * Destroy context. 163322944501Smrg * 163422944501Smrg * Free any kernel-level resources allocated with drmCreateContext() associated 163522944501Smrg * with the context. 1636fe517fc9Smrg * 163722944501Smrg * \param fd file descriptor. 163822944501Smrg * \param handle handle given by drmCreateContext(). 1639fe517fc9Smrg * 164022944501Smrg * \return zero on success, or a negative value on failure. 1641fe517fc9Smrg * 164222944501Smrg * \note May only be called by root. 1643fe517fc9Smrg * 164422944501Smrg * \internal 164522944501Smrg * This function is a wrapper around the DRM_IOCTL_RM_CTX ioctl, passing the 164622944501Smrg * argument in a drm_ctx structure. 164722944501Smrg */ 164822944501Smrgint drmDestroyContext(int fd, drm_context_t handle) 164922944501Smrg{ 165022944501Smrg drm_ctx_t ctx; 1651424e9256Smrg 1652424e9256Smrg memclear(ctx); 165322944501Smrg ctx.handle = handle; 165422944501Smrg if (drmIoctl(fd, DRM_IOCTL_RM_CTX, &ctx)) 1655fe517fc9Smrg return -errno; 165622944501Smrg return 0; 165722944501Smrg} 165822944501Smrg 165922944501Smrgint drmCreateDrawable(int fd, drm_drawable_t *handle) 166022944501Smrg{ 166122944501Smrg drm_draw_t draw; 1662424e9256Smrg 1663424e9256Smrg memclear(draw); 166422944501Smrg if (drmIoctl(fd, DRM_IOCTL_ADD_DRAW, &draw)) 1665fe517fc9Smrg return -errno; 166622944501Smrg *handle = draw.handle; 166722944501Smrg return 0; 166822944501Smrg} 166922944501Smrg 167022944501Smrgint drmDestroyDrawable(int fd, drm_drawable_t handle) 167122944501Smrg{ 167222944501Smrg drm_draw_t draw; 1673424e9256Smrg 1674424e9256Smrg memclear(draw); 167522944501Smrg draw.handle = handle; 167622944501Smrg if (drmIoctl(fd, DRM_IOCTL_RM_DRAW, &draw)) 1677fe517fc9Smrg return -errno; 167822944501Smrg return 0; 167922944501Smrg} 168022944501Smrg 168122944501Smrgint drmUpdateDrawableInfo(int fd, drm_drawable_t handle, 1682fe517fc9Smrg drm_drawable_info_type_t type, unsigned int num, 1683fe517fc9Smrg void *data) 168422944501Smrg{ 168522944501Smrg drm_update_draw_t update; 168622944501Smrg 1687424e9256Smrg memclear(update); 168822944501Smrg update.handle = handle; 168922944501Smrg update.type = type; 169022944501Smrg update.num = num; 169122944501Smrg update.data = (unsigned long long)(unsigned long)data; 169222944501Smrg 169322944501Smrg if (drmIoctl(fd, DRM_IOCTL_UPDATE_DRAW, &update)) 1694fe517fc9Smrg return -errno; 169522944501Smrg 169622944501Smrg return 0; 169722944501Smrg} 169822944501Smrg 16992b90624aSmrgint drmCrtcGetSequence(int fd, uint32_t crtcId, uint64_t *sequence, uint64_t *ns) 17002b90624aSmrg{ 17012b90624aSmrg struct drm_crtc_get_sequence get_seq; 17022b90624aSmrg int ret; 17032b90624aSmrg 17042b90624aSmrg memclear(get_seq); 17052b90624aSmrg get_seq.crtc_id = crtcId; 17062b90624aSmrg ret = drmIoctl(fd, DRM_IOCTL_CRTC_GET_SEQUENCE, &get_seq); 17072b90624aSmrg if (ret) 17082b90624aSmrg return ret; 17092b90624aSmrg 17102b90624aSmrg if (sequence) 17112b90624aSmrg *sequence = get_seq.sequence; 17122b90624aSmrg if (ns) 17132b90624aSmrg *ns = get_seq.sequence_ns; 17142b90624aSmrg return 0; 17152b90624aSmrg} 17162b90624aSmrg 17172b90624aSmrgint drmCrtcQueueSequence(int fd, uint32_t crtcId, uint32_t flags, uint64_t sequence, 17182b90624aSmrg uint64_t *sequence_queued, uint64_t user_data) 17192b90624aSmrg{ 17202b90624aSmrg struct drm_crtc_queue_sequence queue_seq; 17212b90624aSmrg int ret; 17222b90624aSmrg 17232b90624aSmrg memclear(queue_seq); 17242b90624aSmrg queue_seq.crtc_id = crtcId; 17252b90624aSmrg queue_seq.flags = flags; 17262b90624aSmrg queue_seq.sequence = sequence; 17272b90624aSmrg queue_seq.user_data = user_data; 17282b90624aSmrg 17292b90624aSmrg ret = drmIoctl(fd, DRM_IOCTL_CRTC_QUEUE_SEQUENCE, &queue_seq); 17302b90624aSmrg if (ret == 0 && sequence_queued) 17312b90624aSmrg *sequence_queued = queue_seq.sequence; 17322b90624aSmrg 17332b90624aSmrg return ret; 17342b90624aSmrg} 17352b90624aSmrg 173622944501Smrg/** 173722944501Smrg * Acquire the AGP device. 173822944501Smrg * 173922944501Smrg * Must be called before any of the other AGP related calls. 174022944501Smrg * 174122944501Smrg * \param fd file descriptor. 1742fe517fc9Smrg * 174322944501Smrg * \return zero on success, or a negative value on failure. 1744fe517fc9Smrg * 174522944501Smrg * \internal 174622944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_ACQUIRE ioctl. 174722944501Smrg */ 174822944501Smrgint drmAgpAcquire(int fd) 174922944501Smrg{ 175022944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_ACQUIRE, NULL)) 1751fe517fc9Smrg return -errno; 175222944501Smrg return 0; 175322944501Smrg} 175422944501Smrg 175522944501Smrg 175622944501Smrg/** 175722944501Smrg * Release the AGP device. 175822944501Smrg * 175922944501Smrg * \param fd file descriptor. 1760fe517fc9Smrg * 176122944501Smrg * \return zero on success, or a negative value on failure. 1762fe517fc9Smrg * 176322944501Smrg * \internal 176422944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_RELEASE ioctl. 176522944501Smrg */ 176622944501Smrgint drmAgpRelease(int fd) 176722944501Smrg{ 176822944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_RELEASE, NULL)) 1769fe517fc9Smrg return -errno; 177022944501Smrg return 0; 177122944501Smrg} 177222944501Smrg 177322944501Smrg 177422944501Smrg/** 177522944501Smrg * Set the AGP mode. 177622944501Smrg * 177722944501Smrg * \param fd file descriptor. 177822944501Smrg * \param mode AGP mode. 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_ENABLE ioctl, passing the 178422944501Smrg * argument in a drm_agp_mode structure. 178522944501Smrg */ 178622944501Smrgint drmAgpEnable(int fd, unsigned long mode) 178722944501Smrg{ 178822944501Smrg drm_agp_mode_t m; 178922944501Smrg 1790424e9256Smrg memclear(m); 179122944501Smrg m.mode = mode; 179222944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_ENABLE, &m)) 1793fe517fc9Smrg return -errno; 179422944501Smrg return 0; 179522944501Smrg} 179622944501Smrg 179722944501Smrg 179822944501Smrg/** 179922944501Smrg * Allocate a chunk of AGP memory. 180022944501Smrg * 180122944501Smrg * \param fd file descriptor. 180222944501Smrg * \param size requested memory size in bytes. Will be rounded to page boundary. 180322944501Smrg * \param type type of memory to allocate. 180422944501Smrg * \param address if not zero, will be set to the physical address of the 180522944501Smrg * allocated memory. 180622944501Smrg * \param handle on success will be set to a handle of the allocated memory. 1807fe517fc9Smrg * 180822944501Smrg * \return zero on success, or a negative value on failure. 1809fe517fc9Smrg * 181022944501Smrg * \internal 181122944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_ALLOC ioctl, passing the 181222944501Smrg * arguments in a drm_agp_buffer structure. 181322944501Smrg */ 181422944501Smrgint drmAgpAlloc(int fd, unsigned long size, unsigned long type, 1815fe517fc9Smrg unsigned long *address, drm_handle_t *handle) 181622944501Smrg{ 181722944501Smrg drm_agp_buffer_t b; 181822944501Smrg 1819424e9256Smrg memclear(b); 182022944501Smrg *handle = DRM_AGP_NO_HANDLE; 182122944501Smrg b.size = size; 182222944501Smrg b.type = type; 182322944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_ALLOC, &b)) 1824fe517fc9Smrg return -errno; 182522944501Smrg if (address != 0UL) 1826fe517fc9Smrg *address = b.physical; 182722944501Smrg *handle = b.handle; 182822944501Smrg return 0; 182922944501Smrg} 183022944501Smrg 183122944501Smrg 183222944501Smrg/** 183322944501Smrg * Free a chunk of AGP memory. 183422944501Smrg * 183522944501Smrg * \param fd file descriptor. 183622944501Smrg * \param handle handle to the allocated memory, as given by drmAgpAllocate(). 1837fe517fc9Smrg * 183822944501Smrg * \return zero on success, or a negative value on failure. 1839fe517fc9Smrg * 184022944501Smrg * \internal 184122944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_FREE ioctl, passing the 184222944501Smrg * argument in a drm_agp_buffer structure. 184322944501Smrg */ 184422944501Smrgint drmAgpFree(int fd, drm_handle_t handle) 184522944501Smrg{ 184622944501Smrg drm_agp_buffer_t b; 184722944501Smrg 1848424e9256Smrg memclear(b); 184922944501Smrg b.handle = handle; 185022944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_FREE, &b)) 1851fe517fc9Smrg return -errno; 185222944501Smrg return 0; 185322944501Smrg} 185422944501Smrg 185522944501Smrg 185622944501Smrg/** 185722944501Smrg * Bind a chunk of AGP memory. 185822944501Smrg * 185922944501Smrg * \param fd file descriptor. 186022944501Smrg * \param handle handle to the allocated memory, as given by drmAgpAllocate(). 186122944501Smrg * \param offset offset in bytes. It will round to page boundary. 1862fe517fc9Smrg * 186322944501Smrg * \return zero on success, or a negative value on failure. 1864fe517fc9Smrg * 186522944501Smrg * \internal 186622944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_BIND ioctl, passing the 186722944501Smrg * argument in a drm_agp_binding structure. 186822944501Smrg */ 186922944501Smrgint drmAgpBind(int fd, drm_handle_t handle, unsigned long offset) 187022944501Smrg{ 187122944501Smrg drm_agp_binding_t b; 187222944501Smrg 1873424e9256Smrg memclear(b); 187422944501Smrg b.handle = handle; 187522944501Smrg b.offset = offset; 187622944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_BIND, &b)) 1877fe517fc9Smrg return -errno; 187822944501Smrg return 0; 187922944501Smrg} 188022944501Smrg 188122944501Smrg 188222944501Smrg/** 188322944501Smrg * Unbind a chunk of AGP memory. 188422944501Smrg * 188522944501Smrg * \param fd file descriptor. 188622944501Smrg * \param handle handle to the allocated memory, as given by drmAgpAllocate(). 1887fe517fc9Smrg * 188822944501Smrg * \return zero on success, or a negative value on failure. 1889fe517fc9Smrg * 189022944501Smrg * \internal 189122944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_UNBIND ioctl, passing 189222944501Smrg * the argument in a drm_agp_binding structure. 189322944501Smrg */ 189422944501Smrgint drmAgpUnbind(int fd, drm_handle_t handle) 189522944501Smrg{ 189622944501Smrg drm_agp_binding_t b; 189722944501Smrg 1898424e9256Smrg memclear(b); 189922944501Smrg b.handle = handle; 190022944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_UNBIND, &b)) 1901fe517fc9Smrg return -errno; 190222944501Smrg return 0; 190322944501Smrg} 190422944501Smrg 190522944501Smrg 190622944501Smrg/** 190722944501Smrg * Get AGP driver major version number. 190822944501Smrg * 190922944501Smrg * \param fd file descriptor. 1910fe517fc9Smrg * 191122944501Smrg * \return major version number on success, or a negative value on failure.. 1912fe517fc9Smrg * 191322944501Smrg * \internal 191422944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the 191522944501Smrg * necessary information in a drm_agp_info structure. 191622944501Smrg */ 191722944501Smrgint drmAgpVersionMajor(int fd) 191822944501Smrg{ 191922944501Smrg drm_agp_info_t i; 192022944501Smrg 1921424e9256Smrg memclear(i); 1922424e9256Smrg 192322944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i)) 1924fe517fc9Smrg return -errno; 192522944501Smrg return i.agp_version_major; 192622944501Smrg} 192722944501Smrg 192822944501Smrg 192922944501Smrg/** 193022944501Smrg * Get AGP driver minor version number. 193122944501Smrg * 193222944501Smrg * \param fd file descriptor. 1933fe517fc9Smrg * 193422944501Smrg * \return minor version number on success, or a negative value on failure. 1935fe517fc9Smrg * 193622944501Smrg * \internal 193722944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the 193822944501Smrg * necessary information in a drm_agp_info structure. 193922944501Smrg */ 194022944501Smrgint drmAgpVersionMinor(int fd) 194122944501Smrg{ 194222944501Smrg drm_agp_info_t i; 194322944501Smrg 1944424e9256Smrg memclear(i); 1945424e9256Smrg 194622944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i)) 1947fe517fc9Smrg return -errno; 194822944501Smrg return i.agp_version_minor; 194922944501Smrg} 195022944501Smrg 195122944501Smrg 195222944501Smrg/** 195322944501Smrg * Get AGP mode. 195422944501Smrg * 195522944501Smrg * \param fd file descriptor. 1956fe517fc9Smrg * 195722944501Smrg * \return mode on success, or zero on failure. 1958fe517fc9Smrg * 195922944501Smrg * \internal 196022944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the 196122944501Smrg * necessary information in a drm_agp_info structure. 196222944501Smrg */ 196322944501Smrgunsigned long drmAgpGetMode(int fd) 196422944501Smrg{ 196522944501Smrg drm_agp_info_t i; 196622944501Smrg 1967424e9256Smrg memclear(i); 1968424e9256Smrg 196922944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i)) 1970fe517fc9Smrg return 0; 197122944501Smrg return i.mode; 197222944501Smrg} 197322944501Smrg 197422944501Smrg 197522944501Smrg/** 197622944501Smrg * Get AGP aperture base. 197722944501Smrg * 197822944501Smrg * \param fd file descriptor. 1979fe517fc9Smrg * 198022944501Smrg * \return aperture base on success, zero on failure. 1981fe517fc9Smrg * 198222944501Smrg * \internal 198322944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the 198422944501Smrg * necessary information in a drm_agp_info structure. 198522944501Smrg */ 198622944501Smrgunsigned long drmAgpBase(int fd) 198722944501Smrg{ 198822944501Smrg drm_agp_info_t i; 198922944501Smrg 1990424e9256Smrg memclear(i); 1991424e9256Smrg 199222944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i)) 1993fe517fc9Smrg return 0; 199422944501Smrg return i.aperture_base; 199522944501Smrg} 199622944501Smrg 199722944501Smrg 199822944501Smrg/** 199922944501Smrg * Get AGP aperture size. 200022944501Smrg * 200122944501Smrg * \param fd file descriptor. 2002fe517fc9Smrg * 200322944501Smrg * \return aperture size on success, zero on failure. 2004fe517fc9Smrg * 200522944501Smrg * \internal 200622944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the 200722944501Smrg * necessary information in a drm_agp_info structure. 200822944501Smrg */ 200922944501Smrgunsigned long drmAgpSize(int fd) 201022944501Smrg{ 201122944501Smrg drm_agp_info_t i; 201222944501Smrg 2013424e9256Smrg memclear(i); 2014424e9256Smrg 201522944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i)) 2016fe517fc9Smrg return 0; 201722944501Smrg return i.aperture_size; 201822944501Smrg} 201922944501Smrg 202022944501Smrg 202122944501Smrg/** 202222944501Smrg * Get used AGP memory. 202322944501Smrg * 202422944501Smrg * \param fd file descriptor. 2025fe517fc9Smrg * 202622944501Smrg * \return memory used on success, or zero on failure. 2027fe517fc9Smrg * 202822944501Smrg * \internal 202922944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the 203022944501Smrg * necessary information in a drm_agp_info structure. 203122944501Smrg */ 203222944501Smrgunsigned long drmAgpMemoryUsed(int fd) 203322944501Smrg{ 203422944501Smrg drm_agp_info_t i; 203522944501Smrg 2036424e9256Smrg memclear(i); 2037424e9256Smrg 203822944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i)) 2039fe517fc9Smrg return 0; 204022944501Smrg return i.memory_used; 204122944501Smrg} 204222944501Smrg 204322944501Smrg 204422944501Smrg/** 204522944501Smrg * Get available AGP memory. 204622944501Smrg * 204722944501Smrg * \param fd file descriptor. 2048fe517fc9Smrg * 204922944501Smrg * \return memory available on success, or zero on failure. 2050fe517fc9Smrg * 205122944501Smrg * \internal 205222944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the 205322944501Smrg * necessary information in a drm_agp_info structure. 205422944501Smrg */ 205522944501Smrgunsigned long drmAgpMemoryAvail(int fd) 205622944501Smrg{ 205722944501Smrg drm_agp_info_t i; 205822944501Smrg 2059424e9256Smrg memclear(i); 2060424e9256Smrg 206122944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i)) 2062fe517fc9Smrg return 0; 206322944501Smrg return i.memory_allowed; 206422944501Smrg} 206522944501Smrg 206622944501Smrg 206722944501Smrg/** 206822944501Smrg * Get hardware vendor ID. 206922944501Smrg * 207022944501Smrg * \param fd file descriptor. 2071fe517fc9Smrg * 207222944501Smrg * \return vendor ID on success, or zero on failure. 2073fe517fc9Smrg * 207422944501Smrg * \internal 207522944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the 207622944501Smrg * necessary information in a drm_agp_info structure. 207722944501Smrg */ 207822944501Smrgunsigned int drmAgpVendorId(int fd) 207922944501Smrg{ 208022944501Smrg drm_agp_info_t i; 208122944501Smrg 2082424e9256Smrg memclear(i); 2083424e9256Smrg 208422944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i)) 2085fe517fc9Smrg return 0; 208622944501Smrg return i.id_vendor; 208722944501Smrg} 208822944501Smrg 208922944501Smrg 209022944501Smrg/** 209122944501Smrg * Get hardware device ID. 209222944501Smrg * 209322944501Smrg * \param fd file descriptor. 2094fe517fc9Smrg * 209522944501Smrg * \return zero on success, or zero on failure. 2096fe517fc9Smrg * 209722944501Smrg * \internal 209822944501Smrg * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the 209922944501Smrg * necessary information in a drm_agp_info structure. 210022944501Smrg */ 210122944501Smrgunsigned int drmAgpDeviceId(int fd) 210222944501Smrg{ 210322944501Smrg drm_agp_info_t i; 210422944501Smrg 2105424e9256Smrg memclear(i); 2106424e9256Smrg 210722944501Smrg if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i)) 2108fe517fc9Smrg return 0; 210922944501Smrg return i.id_device; 211022944501Smrg} 211122944501Smrg 211222944501Smrgint drmScatterGatherAlloc(int fd, unsigned long size, drm_handle_t *handle) 211322944501Smrg{ 211422944501Smrg drm_scatter_gather_t sg; 211522944501Smrg 2116424e9256Smrg memclear(sg); 2117424e9256Smrg 211822944501Smrg *handle = 0; 211922944501Smrg sg.size = size; 212022944501Smrg if (drmIoctl(fd, DRM_IOCTL_SG_ALLOC, &sg)) 2121fe517fc9Smrg return -errno; 212222944501Smrg *handle = sg.handle; 212322944501Smrg return 0; 212422944501Smrg} 212522944501Smrg 212622944501Smrgint drmScatterGatherFree(int fd, drm_handle_t handle) 212722944501Smrg{ 212822944501Smrg drm_scatter_gather_t sg; 212922944501Smrg 2130424e9256Smrg memclear(sg); 213122944501Smrg sg.handle = handle; 213222944501Smrg if (drmIoctl(fd, DRM_IOCTL_SG_FREE, &sg)) 2133fe517fc9Smrg return -errno; 213422944501Smrg return 0; 213522944501Smrg} 213622944501Smrg 213722944501Smrg/** 213822944501Smrg * Wait for VBLANK. 213922944501Smrg * 214022944501Smrg * \param fd file descriptor. 214122944501Smrg * \param vbl pointer to a drmVBlank structure. 2142fe517fc9Smrg * 214322944501Smrg * \return zero on success, or a negative value on failure. 2144fe517fc9Smrg * 214522944501Smrg * \internal 214622944501Smrg * This function is a wrapper around the DRM_IOCTL_WAIT_VBLANK ioctl. 214722944501Smrg */ 214822944501Smrgint drmWaitVBlank(int fd, drmVBlankPtr vbl) 214922944501Smrg{ 215022944501Smrg struct timespec timeout, cur; 215122944501Smrg int ret; 215222944501Smrg 215322944501Smrg ret = clock_gettime(CLOCK_MONOTONIC, &timeout); 215422944501Smrg if (ret < 0) { 2155fe517fc9Smrg fprintf(stderr, "clock_gettime failed: %s\n", strerror(errno)); 2156fe517fc9Smrg goto out; 215722944501Smrg } 215822944501Smrg timeout.tv_sec++; 215922944501Smrg 216022944501Smrg do { 216122944501Smrg ret = ioctl(fd, DRM_IOCTL_WAIT_VBLANK, vbl); 216222944501Smrg vbl->request.type &= ~DRM_VBLANK_RELATIVE; 216322944501Smrg if (ret && errno == EINTR) { 2164fe517fc9Smrg clock_gettime(CLOCK_MONOTONIC, &cur); 2165fe517fc9Smrg /* Timeout after 1s */ 2166fe517fc9Smrg if (cur.tv_sec > timeout.tv_sec + 1 || 2167fe517fc9Smrg (cur.tv_sec == timeout.tv_sec && cur.tv_nsec >= 2168fe517fc9Smrg timeout.tv_nsec)) { 2169fe517fc9Smrg errno = EBUSY; 2170fe517fc9Smrg ret = -1; 2171fe517fc9Smrg break; 2172fe517fc9Smrg } 217322944501Smrg } 217422944501Smrg } while (ret && errno == EINTR); 217522944501Smrg 217622944501Smrgout: 217722944501Smrg return ret; 217822944501Smrg} 217922944501Smrg 218022944501Smrgint drmError(int err, const char *label) 218122944501Smrg{ 218222944501Smrg switch (err) { 218322944501Smrg case DRM_ERR_NO_DEVICE: 2184fe517fc9Smrg fprintf(stderr, "%s: no device\n", label); 2185fe517fc9Smrg break; 218622944501Smrg case DRM_ERR_NO_ACCESS: 2187fe517fc9Smrg fprintf(stderr, "%s: no access\n", label); 2188fe517fc9Smrg break; 218922944501Smrg case DRM_ERR_NOT_ROOT: 2190fe517fc9Smrg fprintf(stderr, "%s: not root\n", label); 2191fe517fc9Smrg break; 219222944501Smrg case DRM_ERR_INVALID: 2193fe517fc9Smrg fprintf(stderr, "%s: invalid args\n", label); 2194fe517fc9Smrg break; 219522944501Smrg default: 2196fe517fc9Smrg if (err < 0) 2197fe517fc9Smrg err = -err; 2198fe517fc9Smrg fprintf( stderr, "%s: error %d (%s)\n", label, err, strerror(err) ); 2199fe517fc9Smrg break; 220022944501Smrg } 220122944501Smrg 220222944501Smrg return 1; 220322944501Smrg} 220422944501Smrg 220522944501Smrg/** 220622944501Smrg * Install IRQ handler. 220722944501Smrg * 220822944501Smrg * \param fd file descriptor. 220922944501Smrg * \param irq IRQ number. 2210fe517fc9Smrg * 221122944501Smrg * \return zero on success, or a negative value on failure. 2212fe517fc9Smrg * 221322944501Smrg * \internal 221422944501Smrg * This function is a wrapper around the DRM_IOCTL_CONTROL ioctl, passing the 221522944501Smrg * argument in a drm_control structure. 221622944501Smrg */ 221722944501Smrgint drmCtlInstHandler(int fd, int irq) 221822944501Smrg{ 221922944501Smrg drm_control_t ctl; 222022944501Smrg 2221424e9256Smrg memclear(ctl); 222222944501Smrg ctl.func = DRM_INST_HANDLER; 222322944501Smrg ctl.irq = irq; 222422944501Smrg if (drmIoctl(fd, DRM_IOCTL_CONTROL, &ctl)) 2225fe517fc9Smrg return -errno; 222622944501Smrg return 0; 222722944501Smrg} 222822944501Smrg 222922944501Smrg 223022944501Smrg/** 223122944501Smrg * Uninstall IRQ handler. 223222944501Smrg * 223322944501Smrg * \param fd file descriptor. 2234fe517fc9Smrg * 223522944501Smrg * \return zero on success, or a negative value on failure. 2236fe517fc9Smrg * 223722944501Smrg * \internal 223822944501Smrg * This function is a wrapper around the DRM_IOCTL_CONTROL ioctl, passing the 223922944501Smrg * argument in a drm_control structure. 224022944501Smrg */ 224122944501Smrgint drmCtlUninstHandler(int fd) 224222944501Smrg{ 224322944501Smrg drm_control_t ctl; 224422944501Smrg 2245424e9256Smrg memclear(ctl); 224622944501Smrg ctl.func = DRM_UNINST_HANDLER; 224722944501Smrg ctl.irq = 0; 224822944501Smrg if (drmIoctl(fd, DRM_IOCTL_CONTROL, &ctl)) 2249fe517fc9Smrg return -errno; 225022944501Smrg return 0; 225122944501Smrg} 225222944501Smrg 225322944501Smrgint drmFinish(int fd, int context, drmLockFlags flags) 225422944501Smrg{ 225522944501Smrg drm_lock_t lock; 225622944501Smrg 2257424e9256Smrg memclear(lock); 225822944501Smrg lock.context = context; 225922944501Smrg if (flags & DRM_LOCK_READY) lock.flags |= _DRM_LOCK_READY; 226022944501Smrg if (flags & DRM_LOCK_QUIESCENT) lock.flags |= _DRM_LOCK_QUIESCENT; 226122944501Smrg if (flags & DRM_LOCK_FLUSH) lock.flags |= _DRM_LOCK_FLUSH; 226222944501Smrg if (flags & DRM_LOCK_FLUSH_ALL) lock.flags |= _DRM_LOCK_FLUSH_ALL; 226322944501Smrg if (flags & DRM_HALT_ALL_QUEUES) lock.flags |= _DRM_HALT_ALL_QUEUES; 226422944501Smrg if (flags & DRM_HALT_CUR_QUEUES) lock.flags |= _DRM_HALT_CUR_QUEUES; 226522944501Smrg if (drmIoctl(fd, DRM_IOCTL_FINISH, &lock)) 2266fe517fc9Smrg return -errno; 226722944501Smrg return 0; 226822944501Smrg} 226922944501Smrg 227022944501Smrg/** 227122944501Smrg * Get IRQ from bus ID. 227222944501Smrg * 227322944501Smrg * \param fd file descriptor. 227422944501Smrg * \param busnum bus number. 227522944501Smrg * \param devnum device number. 227622944501Smrg * \param funcnum function number. 2277fe517fc9Smrg * 227822944501Smrg * \return IRQ number on success, or a negative value on failure. 2279fe517fc9Smrg * 228022944501Smrg * \internal 228122944501Smrg * This function is a wrapper around the DRM_IOCTL_IRQ_BUSID ioctl, passing the 228222944501Smrg * arguments in a drm_irq_busid structure. 228322944501Smrg */ 228422944501Smrgint drmGetInterruptFromBusID(int fd, int busnum, int devnum, int funcnum) 228522944501Smrg{ 228622944501Smrg drm_irq_busid_t p; 228722944501Smrg 2288424e9256Smrg memclear(p); 228922944501Smrg p.busnum = busnum; 229022944501Smrg p.devnum = devnum; 229122944501Smrg p.funcnum = funcnum; 229222944501Smrg if (drmIoctl(fd, DRM_IOCTL_IRQ_BUSID, &p)) 2293fe517fc9Smrg return -errno; 229422944501Smrg return p.irq; 229522944501Smrg} 229622944501Smrg 229722944501Smrgint drmAddContextTag(int fd, drm_context_t context, void *tag) 229822944501Smrg{ 229922944501Smrg drmHashEntry *entry = drmGetEntry(fd); 230022944501Smrg 230122944501Smrg if (drmHashInsert(entry->tagTable, context, tag)) { 2302fe517fc9Smrg drmHashDelete(entry->tagTable, context); 2303fe517fc9Smrg drmHashInsert(entry->tagTable, context, tag); 230422944501Smrg } 230522944501Smrg return 0; 230622944501Smrg} 230722944501Smrg 230822944501Smrgint drmDelContextTag(int fd, drm_context_t context) 230922944501Smrg{ 231022944501Smrg drmHashEntry *entry = drmGetEntry(fd); 231122944501Smrg 231222944501Smrg return drmHashDelete(entry->tagTable, context); 231322944501Smrg} 231422944501Smrg 231522944501Smrgvoid *drmGetContextTag(int fd, drm_context_t context) 231622944501Smrg{ 231722944501Smrg drmHashEntry *entry = drmGetEntry(fd); 231822944501Smrg void *value; 231922944501Smrg 232022944501Smrg if (drmHashLookup(entry->tagTable, context, &value)) 2321fe517fc9Smrg return NULL; 232222944501Smrg 232322944501Smrg return value; 232422944501Smrg} 232522944501Smrg 232622944501Smrgint drmAddContextPrivateMapping(int fd, drm_context_t ctx_id, 232722944501Smrg drm_handle_t handle) 232822944501Smrg{ 232922944501Smrg drm_ctx_priv_map_t map; 233022944501Smrg 2331424e9256Smrg memclear(map); 233222944501Smrg map.ctx_id = ctx_id; 233320131375Smrg map.handle = (void *)(uintptr_t)handle; 233422944501Smrg 233522944501Smrg if (drmIoctl(fd, DRM_IOCTL_SET_SAREA_CTX, &map)) 2336fe517fc9Smrg return -errno; 233722944501Smrg return 0; 233822944501Smrg} 233922944501Smrg 234022944501Smrgint drmGetContextPrivateMapping(int fd, drm_context_t ctx_id, 234122944501Smrg drm_handle_t *handle) 234222944501Smrg{ 234322944501Smrg drm_ctx_priv_map_t map; 234422944501Smrg 2345424e9256Smrg memclear(map); 234622944501Smrg map.ctx_id = ctx_id; 234722944501Smrg 234822944501Smrg if (drmIoctl(fd, DRM_IOCTL_GET_SAREA_CTX, &map)) 2349fe517fc9Smrg return -errno; 235022944501Smrg if (handle) 2351fe517fc9Smrg *handle = (drm_handle_t)(uintptr_t)map.handle; 235222944501Smrg 235322944501Smrg return 0; 235422944501Smrg} 235522944501Smrg 235622944501Smrgint drmGetMap(int fd, int idx, drm_handle_t *offset, drmSize *size, 2357fe517fc9Smrg drmMapType *type, drmMapFlags *flags, drm_handle_t *handle, 2358fe517fc9Smrg int *mtrr) 235922944501Smrg{ 236022944501Smrg drm_map_t map; 236122944501Smrg 2362424e9256Smrg memclear(map); 236322944501Smrg map.offset = idx; 236422944501Smrg if (drmIoctl(fd, DRM_IOCTL_GET_MAP, &map)) 2365fe517fc9Smrg return -errno; 236622944501Smrg *offset = map.offset; 236722944501Smrg *size = map.size; 236822944501Smrg *type = map.type; 236922944501Smrg *flags = map.flags; 237022944501Smrg *handle = (unsigned long)map.handle; 237122944501Smrg *mtrr = map.mtrr; 237222944501Smrg return 0; 237322944501Smrg} 237422944501Smrg 237522944501Smrgint drmGetClient(int fd, int idx, int *auth, int *pid, int *uid, 2376fe517fc9Smrg unsigned long *magic, unsigned long *iocs) 237722944501Smrg{ 237822944501Smrg drm_client_t client; 237922944501Smrg 2380424e9256Smrg memclear(client); 238122944501Smrg client.idx = idx; 238222944501Smrg if (drmIoctl(fd, DRM_IOCTL_GET_CLIENT, &client)) 2383fe517fc9Smrg return -errno; 238422944501Smrg *auth = client.auth; 238522944501Smrg *pid = client.pid; 238622944501Smrg *uid = client.uid; 238722944501Smrg *magic = client.magic; 238822944501Smrg *iocs = client.iocs; 238922944501Smrg return 0; 239022944501Smrg} 239122944501Smrg 239222944501Smrgint drmGetStats(int fd, drmStatsT *stats) 239322944501Smrg{ 239422944501Smrg drm_stats_t s; 2395424e9256Smrg unsigned i; 239622944501Smrg 2397424e9256Smrg memclear(s); 239822944501Smrg if (drmIoctl(fd, DRM_IOCTL_GET_STATS, &s)) 2399fe517fc9Smrg return -errno; 240022944501Smrg 240122944501Smrg stats->count = 0; 240222944501Smrg memset(stats, 0, sizeof(*stats)); 240322944501Smrg if (s.count > sizeof(stats->data)/sizeof(stats->data[0])) 2404fe517fc9Smrg return -1; 240522944501Smrg 240622944501Smrg#define SET_VALUE \ 240722944501Smrg stats->data[i].long_format = "%-20.20s"; \ 240822944501Smrg stats->data[i].rate_format = "%8.8s"; \ 240922944501Smrg stats->data[i].isvalue = 1; \ 241022944501Smrg stats->data[i].verbose = 0 241122944501Smrg 241222944501Smrg#define SET_COUNT \ 241322944501Smrg stats->data[i].long_format = "%-20.20s"; \ 241422944501Smrg stats->data[i].rate_format = "%5.5s"; \ 241522944501Smrg stats->data[i].isvalue = 0; \ 241622944501Smrg stats->data[i].mult_names = "kgm"; \ 241722944501Smrg stats->data[i].mult = 1000; \ 241822944501Smrg stats->data[i].verbose = 0 241922944501Smrg 242022944501Smrg#define SET_BYTE \ 242122944501Smrg stats->data[i].long_format = "%-20.20s"; \ 242222944501Smrg stats->data[i].rate_format = "%5.5s"; \ 242322944501Smrg stats->data[i].isvalue = 0; \ 242422944501Smrg stats->data[i].mult_names = "KGM"; \ 242522944501Smrg stats->data[i].mult = 1024; \ 242622944501Smrg stats->data[i].verbose = 0 242722944501Smrg 242822944501Smrg 242922944501Smrg stats->count = s.count; 243022944501Smrg for (i = 0; i < s.count; i++) { 2431fe517fc9Smrg stats->data[i].value = s.data[i].value; 2432fe517fc9Smrg switch (s.data[i].type) { 2433fe517fc9Smrg case _DRM_STAT_LOCK: 2434fe517fc9Smrg stats->data[i].long_name = "Lock"; 2435fe517fc9Smrg stats->data[i].rate_name = "Lock"; 2436fe517fc9Smrg SET_VALUE; 2437fe517fc9Smrg break; 2438fe517fc9Smrg case _DRM_STAT_OPENS: 2439fe517fc9Smrg stats->data[i].long_name = "Opens"; 2440fe517fc9Smrg stats->data[i].rate_name = "O"; 2441fe517fc9Smrg SET_COUNT; 2442fe517fc9Smrg stats->data[i].verbose = 1; 2443fe517fc9Smrg break; 2444fe517fc9Smrg case _DRM_STAT_CLOSES: 2445fe517fc9Smrg stats->data[i].long_name = "Closes"; 2446fe517fc9Smrg stats->data[i].rate_name = "Lock"; 2447fe517fc9Smrg SET_COUNT; 2448fe517fc9Smrg stats->data[i].verbose = 1; 2449fe517fc9Smrg break; 2450fe517fc9Smrg case _DRM_STAT_IOCTLS: 2451fe517fc9Smrg stats->data[i].long_name = "Ioctls"; 2452fe517fc9Smrg stats->data[i].rate_name = "Ioc/s"; 2453fe517fc9Smrg SET_COUNT; 2454fe517fc9Smrg break; 2455fe517fc9Smrg case _DRM_STAT_LOCKS: 2456fe517fc9Smrg stats->data[i].long_name = "Locks"; 2457fe517fc9Smrg stats->data[i].rate_name = "Lck/s"; 2458fe517fc9Smrg SET_COUNT; 2459fe517fc9Smrg break; 2460fe517fc9Smrg case _DRM_STAT_UNLOCKS: 2461fe517fc9Smrg stats->data[i].long_name = "Unlocks"; 2462fe517fc9Smrg stats->data[i].rate_name = "Unl/s"; 2463fe517fc9Smrg SET_COUNT; 2464fe517fc9Smrg break; 2465fe517fc9Smrg case _DRM_STAT_IRQ: 2466fe517fc9Smrg stats->data[i].long_name = "IRQs"; 2467fe517fc9Smrg stats->data[i].rate_name = "IRQ/s"; 2468fe517fc9Smrg SET_COUNT; 2469fe517fc9Smrg break; 2470fe517fc9Smrg case _DRM_STAT_PRIMARY: 2471fe517fc9Smrg stats->data[i].long_name = "Primary Bytes"; 2472fe517fc9Smrg stats->data[i].rate_name = "PB/s"; 2473fe517fc9Smrg SET_BYTE; 2474fe517fc9Smrg break; 2475fe517fc9Smrg case _DRM_STAT_SECONDARY: 2476fe517fc9Smrg stats->data[i].long_name = "Secondary Bytes"; 2477fe517fc9Smrg stats->data[i].rate_name = "SB/s"; 2478fe517fc9Smrg SET_BYTE; 2479fe517fc9Smrg break; 2480fe517fc9Smrg case _DRM_STAT_DMA: 2481fe517fc9Smrg stats->data[i].long_name = "DMA"; 2482fe517fc9Smrg stats->data[i].rate_name = "DMA/s"; 2483fe517fc9Smrg SET_COUNT; 2484fe517fc9Smrg break; 2485fe517fc9Smrg case _DRM_STAT_SPECIAL: 2486fe517fc9Smrg stats->data[i].long_name = "Special DMA"; 2487fe517fc9Smrg stats->data[i].rate_name = "dma/s"; 2488fe517fc9Smrg SET_COUNT; 2489fe517fc9Smrg break; 2490fe517fc9Smrg case _DRM_STAT_MISSED: 2491fe517fc9Smrg stats->data[i].long_name = "Miss"; 2492fe517fc9Smrg stats->data[i].rate_name = "Ms/s"; 2493fe517fc9Smrg SET_COUNT; 2494fe517fc9Smrg break; 2495fe517fc9Smrg case _DRM_STAT_VALUE: 2496fe517fc9Smrg stats->data[i].long_name = "Value"; 2497fe517fc9Smrg stats->data[i].rate_name = "Value"; 2498fe517fc9Smrg SET_VALUE; 2499fe517fc9Smrg break; 2500fe517fc9Smrg case _DRM_STAT_BYTE: 2501fe517fc9Smrg stats->data[i].long_name = "Bytes"; 2502fe517fc9Smrg stats->data[i].rate_name = "B/s"; 2503fe517fc9Smrg SET_BYTE; 2504fe517fc9Smrg break; 2505fe517fc9Smrg case _DRM_STAT_COUNT: 2506fe517fc9Smrg default: 2507fe517fc9Smrg stats->data[i].long_name = "Count"; 2508fe517fc9Smrg stats->data[i].rate_name = "Cnt/s"; 2509fe517fc9Smrg SET_COUNT; 2510fe517fc9Smrg break; 2511fe517fc9Smrg } 251222944501Smrg } 251322944501Smrg return 0; 251422944501Smrg} 251522944501Smrg 251622944501Smrg/** 251722944501Smrg * Issue a set-version ioctl. 251822944501Smrg * 251922944501Smrg * \param fd file descriptor. 2520fe517fc9Smrg * \param drmCommandIndex command index 252122944501Smrg * \param data source pointer of the data to be read and written. 252222944501Smrg * \param size size of the data to be read and written. 2523fe517fc9Smrg * 252422944501Smrg * \return zero on success, or a negative value on failure. 2525fe517fc9Smrg * 252622944501Smrg * \internal 2527fe517fc9Smrg * It issues a read-write ioctl given by 252822944501Smrg * \code DRM_COMMAND_BASE + drmCommandIndex \endcode. 252922944501Smrg */ 253022944501Smrgint drmSetInterfaceVersion(int fd, drmSetVersion *version) 253122944501Smrg{ 253222944501Smrg int retcode = 0; 253322944501Smrg drm_set_version_t sv; 253422944501Smrg 2535424e9256Smrg memclear(sv); 253622944501Smrg sv.drm_di_major = version->drm_di_major; 253722944501Smrg sv.drm_di_minor = version->drm_di_minor; 253822944501Smrg sv.drm_dd_major = version->drm_dd_major; 253922944501Smrg sv.drm_dd_minor = version->drm_dd_minor; 254022944501Smrg 254122944501Smrg if (drmIoctl(fd, DRM_IOCTL_SET_VERSION, &sv)) { 2542fe517fc9Smrg retcode = -errno; 254322944501Smrg } 254422944501Smrg 254522944501Smrg version->drm_di_major = sv.drm_di_major; 254622944501Smrg version->drm_di_minor = sv.drm_di_minor; 254722944501Smrg version->drm_dd_major = sv.drm_dd_major; 254822944501Smrg version->drm_dd_minor = sv.drm_dd_minor; 254922944501Smrg 255022944501Smrg return retcode; 255122944501Smrg} 255222944501Smrg 255322944501Smrg/** 255422944501Smrg * Send a device-specific command. 255522944501Smrg * 255622944501Smrg * \param fd file descriptor. 2557fe517fc9Smrg * \param drmCommandIndex command index 2558fe517fc9Smrg * 255922944501Smrg * \return zero on success, or a negative value on failure. 2560fe517fc9Smrg * 256122944501Smrg * \internal 2562fe517fc9Smrg * It issues a ioctl given by 256322944501Smrg * \code DRM_COMMAND_BASE + drmCommandIndex \endcode. 256422944501Smrg */ 256522944501Smrgint drmCommandNone(int fd, unsigned long drmCommandIndex) 256622944501Smrg{ 256722944501Smrg unsigned long request; 256822944501Smrg 256922944501Smrg request = DRM_IO( DRM_COMMAND_BASE + drmCommandIndex); 257022944501Smrg 2571424e9256Smrg if (drmIoctl(fd, request, NULL)) { 2572fe517fc9Smrg return -errno; 257322944501Smrg } 257422944501Smrg return 0; 257522944501Smrg} 257622944501Smrg 257722944501Smrg 257822944501Smrg/** 257922944501Smrg * Send a device-specific read command. 258022944501Smrg * 258122944501Smrg * \param fd file descriptor. 2582fe517fc9Smrg * \param drmCommandIndex command index 258322944501Smrg * \param data destination pointer of the data to be read. 258422944501Smrg * \param size size of the data to be read. 2585fe517fc9Smrg * 258622944501Smrg * \return zero on success, or a negative value on failure. 258722944501Smrg * 258822944501Smrg * \internal 2589fe517fc9Smrg * It issues a read ioctl given by 259022944501Smrg * \code DRM_COMMAND_BASE + drmCommandIndex \endcode. 259122944501Smrg */ 259222944501Smrgint drmCommandRead(int fd, unsigned long drmCommandIndex, void *data, 259322944501Smrg unsigned long size) 259422944501Smrg{ 259522944501Smrg unsigned long request; 259622944501Smrg 2597fe517fc9Smrg request = DRM_IOC( DRM_IOC_READ, DRM_IOCTL_BASE, 2598fe517fc9Smrg DRM_COMMAND_BASE + drmCommandIndex, size); 259922944501Smrg 260022944501Smrg if (drmIoctl(fd, request, data)) { 2601fe517fc9Smrg return -errno; 260222944501Smrg } 260322944501Smrg return 0; 260422944501Smrg} 260522944501Smrg 260622944501Smrg 260722944501Smrg/** 260822944501Smrg * Send a device-specific write command. 260922944501Smrg * 261022944501Smrg * \param fd file descriptor. 2611fe517fc9Smrg * \param drmCommandIndex command index 261222944501Smrg * \param data source pointer of the data to be written. 261322944501Smrg * \param size size of the data to be written. 2614fe517fc9Smrg * 261522944501Smrg * \return zero on success, or a negative value on failure. 2616fe517fc9Smrg * 261722944501Smrg * \internal 2618fe517fc9Smrg * It issues a write ioctl given by 261922944501Smrg * \code DRM_COMMAND_BASE + drmCommandIndex \endcode. 262022944501Smrg */ 262122944501Smrgint drmCommandWrite(int fd, unsigned long drmCommandIndex, void *data, 262222944501Smrg unsigned long size) 262322944501Smrg{ 262422944501Smrg unsigned long request; 262522944501Smrg 2626fe517fc9Smrg request = DRM_IOC( DRM_IOC_WRITE, DRM_IOCTL_BASE, 2627fe517fc9Smrg DRM_COMMAND_BASE + drmCommandIndex, size); 262822944501Smrg 262922944501Smrg if (drmIoctl(fd, request, data)) { 2630fe517fc9Smrg return -errno; 263122944501Smrg } 263222944501Smrg return 0; 263322944501Smrg} 263422944501Smrg 263522944501Smrg 263622944501Smrg/** 263722944501Smrg * Send a device-specific read-write command. 263822944501Smrg * 263922944501Smrg * \param fd file descriptor. 2640fe517fc9Smrg * \param drmCommandIndex command index 264122944501Smrg * \param data source pointer of the data to be read and written. 264222944501Smrg * \param size size of the data to be read and written. 2643fe517fc9Smrg * 264422944501Smrg * \return zero on success, or a negative value on failure. 2645fe517fc9Smrg * 264622944501Smrg * \internal 2647fe517fc9Smrg * It issues a read-write ioctl given by 264822944501Smrg * \code DRM_COMMAND_BASE + drmCommandIndex \endcode. 264922944501Smrg */ 265022944501Smrgint drmCommandWriteRead(int fd, unsigned long drmCommandIndex, void *data, 265122944501Smrg unsigned long size) 265222944501Smrg{ 265322944501Smrg unsigned long request; 265422944501Smrg 2655fe517fc9Smrg request = DRM_IOC( DRM_IOC_READ|DRM_IOC_WRITE, DRM_IOCTL_BASE, 2656fe517fc9Smrg DRM_COMMAND_BASE + drmCommandIndex, size); 265722944501Smrg 265822944501Smrg if (drmIoctl(fd, request, data)) 2659fe517fc9Smrg return -errno; 266022944501Smrg return 0; 266122944501Smrg} 266222944501Smrg 266322944501Smrg#define DRM_MAX_FDS 16 266422944501Smrgstatic struct { 266522944501Smrg char *BusID; 266622944501Smrg int fd; 266722944501Smrg int refcount; 2668424e9256Smrg int type; 266922944501Smrg} connection[DRM_MAX_FDS]; 267022944501Smrg 267122944501Smrgstatic int nr_fds = 0; 267222944501Smrg 2673fe517fc9Smrgint drmOpenOnce(void *unused, 2674fe517fc9Smrg const char *BusID, 2675fe517fc9Smrg int *newlyopened) 2676424e9256Smrg{ 2677424e9256Smrg return drmOpenOnceWithType(BusID, newlyopened, DRM_NODE_PRIMARY); 2678424e9256Smrg} 2679424e9256Smrg 2680424e9256Smrgint drmOpenOnceWithType(const char *BusID, int *newlyopened, int type) 268122944501Smrg{ 268222944501Smrg int i; 268322944501Smrg int fd; 2684fe517fc9Smrg 268522944501Smrg for (i = 0; i < nr_fds; i++) 2686fe517fc9Smrg if ((strcmp(BusID, connection[i].BusID) == 0) && 2687fe517fc9Smrg (connection[i].type == type)) { 2688fe517fc9Smrg connection[i].refcount++; 2689fe517fc9Smrg *newlyopened = 0; 2690fe517fc9Smrg return connection[i].fd; 2691fe517fc9Smrg } 269222944501Smrg 2693424e9256Smrg fd = drmOpenWithType(NULL, BusID, type); 2694fe517fc9Smrg if (fd < 0 || nr_fds == DRM_MAX_FDS) 2695fe517fc9Smrg return fd; 2696fe517fc9Smrg 269722944501Smrg connection[nr_fds].BusID = strdup(BusID); 269822944501Smrg connection[nr_fds].fd = fd; 269922944501Smrg connection[nr_fds].refcount = 1; 2700424e9256Smrg connection[nr_fds].type = type; 270122944501Smrg *newlyopened = 1; 270222944501Smrg 270322944501Smrg if (0) 2704fe517fc9Smrg fprintf(stderr, "saved connection %d for %s %d\n", 2705fe517fc9Smrg nr_fds, connection[nr_fds].BusID, 2706fe517fc9Smrg strcmp(BusID, connection[nr_fds].BusID)); 270722944501Smrg 270822944501Smrg nr_fds++; 270922944501Smrg 271022944501Smrg return fd; 271122944501Smrg} 271222944501Smrg 271322944501Smrgvoid drmCloseOnce(int fd) 271422944501Smrg{ 271522944501Smrg int i; 271622944501Smrg 271722944501Smrg for (i = 0; i < nr_fds; i++) { 2718fe517fc9Smrg if (fd == connection[i].fd) { 2719fe517fc9Smrg if (--connection[i].refcount == 0) { 2720fe517fc9Smrg drmClose(connection[i].fd); 2721fe517fc9Smrg free(connection[i].BusID); 2722fe517fc9Smrg 2723fe517fc9Smrg if (i < --nr_fds) 2724fe517fc9Smrg connection[i] = connection[nr_fds]; 2725fe517fc9Smrg 2726fe517fc9Smrg return; 2727fe517fc9Smrg } 2728fe517fc9Smrg } 272922944501Smrg } 273022944501Smrg} 273122944501Smrg 273222944501Smrgint drmSetMaster(int fd) 273322944501Smrg{ 2734fe517fc9Smrg return drmIoctl(fd, DRM_IOCTL_SET_MASTER, NULL); 273522944501Smrg} 273622944501Smrg 273722944501Smrgint drmDropMaster(int fd) 273822944501Smrg{ 2739fe517fc9Smrg return drmIoctl(fd, DRM_IOCTL_DROP_MASTER, NULL); 274022944501Smrg} 274122944501Smrg 274222944501Smrgchar *drmGetDeviceNameFromFd(int fd) 274322944501Smrg{ 2744fe517fc9Smrg char name[128]; 2745fe517fc9Smrg struct stat sbuf; 2746fe517fc9Smrg dev_t d; 2747fe517fc9Smrg int i; 274822944501Smrg 2749fe517fc9Smrg /* The whole drmOpen thing is a fiasco and we need to find a way 2750fe517fc9Smrg * back to just using open(2). For now, however, lets just make 2751fe517fc9Smrg * things worse with even more ad hoc directory walking code to 2752fe517fc9Smrg * discover the device file name. */ 275322944501Smrg 2754fe517fc9Smrg fstat(fd, &sbuf); 2755fe517fc9Smrg d = sbuf.st_rdev; 275622944501Smrg 2757fe517fc9Smrg for (i = 0; i < DRM_MAX_MINOR; i++) { 2758fe517fc9Smrg snprintf(name, sizeof name, DRM_DEV_NAME, DRM_DIR_NAME, i); 2759fe517fc9Smrg if (stat(name, &sbuf) == 0 && sbuf.st_rdev == d) 2760fe517fc9Smrg break; 2761fe517fc9Smrg } 2762fe517fc9Smrg if (i == DRM_MAX_MINOR) 2763fe517fc9Smrg return NULL; 276422944501Smrg 2765fe517fc9Smrg return strdup(name); 276622944501Smrg} 276720131375Smrg 2768424e9256Smrgint drmGetNodeTypeFromFd(int fd) 2769424e9256Smrg{ 2770fe517fc9Smrg struct stat sbuf; 2771fe517fc9Smrg int maj, min, type; 2772424e9256Smrg 2773fe517fc9Smrg if (fstat(fd, &sbuf)) 2774fe517fc9Smrg return -1; 2775424e9256Smrg 2776fe517fc9Smrg maj = major(sbuf.st_rdev); 2777fe517fc9Smrg min = minor(sbuf.st_rdev); 2778424e9256Smrg 2779fe517fc9Smrg if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode)) { 2780fe517fc9Smrg errno = EINVAL; 2781fe517fc9Smrg return -1; 2782fe517fc9Smrg } 2783424e9256Smrg 2784fe517fc9Smrg type = drmGetMinorType(min); 2785fe517fc9Smrg if (type == -1) 2786fe517fc9Smrg errno = ENODEV; 2787fe517fc9Smrg return type; 2788424e9256Smrg} 2789424e9256Smrg 279020131375Smrgint drmPrimeHandleToFD(int fd, uint32_t handle, uint32_t flags, int *prime_fd) 279120131375Smrg{ 2792fe517fc9Smrg struct drm_prime_handle args; 2793fe517fc9Smrg int ret; 279420131375Smrg 2795fe517fc9Smrg memclear(args); 2796fe517fc9Smrg args.fd = -1; 2797fe517fc9Smrg args.handle = handle; 2798fe517fc9Smrg args.flags = flags; 2799fe517fc9Smrg ret = drmIoctl(fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &args); 2800fe517fc9Smrg if (ret) 2801fe517fc9Smrg return ret; 280220131375Smrg 2803fe517fc9Smrg *prime_fd = args.fd; 2804fe517fc9Smrg return 0; 280520131375Smrg} 280620131375Smrg 280720131375Smrgint drmPrimeFDToHandle(int fd, int prime_fd, uint32_t *handle) 280820131375Smrg{ 2809fe517fc9Smrg struct drm_prime_handle args; 2810fe517fc9Smrg int ret; 281120131375Smrg 2812fe517fc9Smrg memclear(args); 2813fe517fc9Smrg args.fd = prime_fd; 2814fe517fc9Smrg ret = drmIoctl(fd, DRM_IOCTL_PRIME_FD_TO_HANDLE, &args); 2815fe517fc9Smrg if (ret) 2816fe517fc9Smrg return ret; 281720131375Smrg 2818fe517fc9Smrg *handle = args.handle; 2819fe517fc9Smrg return 0; 282020131375Smrg} 2821424e9256Smrg 2822424e9256Smrgstatic char *drmGetMinorNameForFD(int fd, int type) 2823424e9256Smrg{ 2824424e9256Smrg#ifdef __linux__ 2825fe517fc9Smrg DIR *sysdir; 2826fe517fc9Smrg struct dirent *pent, *ent; 2827fe517fc9Smrg struct stat sbuf; 2828fe517fc9Smrg const char *name = drmGetMinorName(type); 2829fe517fc9Smrg int len; 2830fe517fc9Smrg char dev_name[64], buf[64]; 2831fe517fc9Smrg long name_max; 2832fe517fc9Smrg int maj, min; 2833fe517fc9Smrg 2834fe517fc9Smrg if (!name) 2835fe517fc9Smrg return NULL; 2836424e9256Smrg 2837fe517fc9Smrg len = strlen(name); 2838424e9256Smrg 2839fe517fc9Smrg if (fstat(fd, &sbuf)) 2840fe517fc9Smrg return NULL; 2841424e9256Smrg 2842fe517fc9Smrg maj = major(sbuf.st_rdev); 2843fe517fc9Smrg min = minor(sbuf.st_rdev); 2844424e9256Smrg 2845fe517fc9Smrg if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode)) 2846fe517fc9Smrg return NULL; 2847424e9256Smrg 2848fe517fc9Smrg snprintf(buf, sizeof(buf), "/sys/dev/char/%d:%d/device/drm", maj, min); 2849424e9256Smrg 2850fe517fc9Smrg sysdir = opendir(buf); 2851fe517fc9Smrg if (!sysdir) 2852fe517fc9Smrg return NULL; 2853424e9256Smrg 2854fe517fc9Smrg name_max = fpathconf(dirfd(sysdir), _PC_NAME_MAX); 2855fe517fc9Smrg if (name_max == -1) 2856fe517fc9Smrg goto out_close_dir; 2857424e9256Smrg 2858fe517fc9Smrg pent = malloc(offsetof(struct dirent, d_name) + name_max + 1); 2859fe517fc9Smrg if (pent == NULL) 2860fe517fc9Smrg goto out_close_dir; 2861424e9256Smrg 2862fe517fc9Smrg while (readdir_r(sysdir, pent, &ent) == 0 && ent != NULL) { 2863fe517fc9Smrg if (strncmp(ent->d_name, name, len) == 0) { 2864fe517fc9Smrg snprintf(dev_name, sizeof(dev_name), DRM_DIR_NAME "/%s", 2865fe517fc9Smrg ent->d_name); 2866424e9256Smrg 2867fe517fc9Smrg free(pent); 2868fe517fc9Smrg closedir(sysdir); 2869424e9256Smrg 2870fe517fc9Smrg return strdup(dev_name); 2871fe517fc9Smrg } 2872fe517fc9Smrg } 2873424e9256Smrg 2874fe517fc9Smrg free(pent); 2875424e9256Smrg 2876424e9256Smrgout_close_dir: 2877fe517fc9Smrg closedir(sysdir); 2878fe517fc9Smrg#else 28792ee35494Smrg struct stat sbuf; 28802ee35494Smrg char buf[PATH_MAX + 1]; 28812ee35494Smrg const char *dev_name; 28822ee35494Smrg unsigned int maj, min; 28832ee35494Smrg int n, base; 28842ee35494Smrg 28852ee35494Smrg if (fstat(fd, &sbuf)) 28862ee35494Smrg return NULL; 28872ee35494Smrg 28882ee35494Smrg maj = major(sbuf.st_rdev); 28892ee35494Smrg min = minor(sbuf.st_rdev); 28902ee35494Smrg 28912ee35494Smrg if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode)) 28922ee35494Smrg return NULL; 28932ee35494Smrg 28942ee35494Smrg switch (type) { 28952ee35494Smrg case DRM_NODE_PRIMARY: 28962ee35494Smrg dev_name = DRM_DEV_NAME; 28972ee35494Smrg break; 28982ee35494Smrg case DRM_NODE_CONTROL: 28992ee35494Smrg dev_name = DRM_CONTROL_DEV_NAME; 29002ee35494Smrg break; 29012ee35494Smrg case DRM_NODE_RENDER: 29022ee35494Smrg dev_name = DRM_RENDER_DEV_NAME; 29032ee35494Smrg break; 29042ee35494Smrg default: 29052ee35494Smrg return NULL; 29062ee35494Smrg }; 29072ee35494Smrg 29082ee35494Smrg base = drmGetMinorBase(type); 29092ee35494Smrg if (base < 0) 29102ee35494Smrg return NULL; 29112ee35494Smrg 29122ee35494Smrg n = snprintf(buf, sizeof(buf), dev_name, DRM_DIR_NAME, min - base); 29132ee35494Smrg if (n == -1 || n >= sizeof(buf)) 29142ee35494Smrg return NULL; 29152ee35494Smrg 29162ee35494Smrg return strdup(buf); 2917424e9256Smrg#endif 2918fe517fc9Smrg return NULL; 2919424e9256Smrg} 2920424e9256Smrg 2921424e9256Smrgchar *drmGetPrimaryDeviceNameFromFd(int fd) 2922424e9256Smrg{ 2923fe517fc9Smrg return drmGetMinorNameForFD(fd, DRM_NODE_PRIMARY); 2924424e9256Smrg} 2925424e9256Smrg 2926424e9256Smrgchar *drmGetRenderDeviceNameFromFd(int fd) 2927424e9256Smrg{ 2928fe517fc9Smrg return drmGetMinorNameForFD(fd, DRM_NODE_RENDER); 2929fe517fc9Smrg} 2930fe517fc9Smrg 29312ee35494Smrg#ifdef __linux__ 29322ee35494Smrgstatic char * DRM_PRINTFLIKE(2, 3) 29332ee35494Smrgsysfs_uevent_get(const char *path, const char *fmt, ...) 29342ee35494Smrg{ 29352ee35494Smrg char filename[PATH_MAX + 1], *key, *line = NULL, *value = NULL; 29362ee35494Smrg size_t size = 0, len; 29372ee35494Smrg ssize_t num; 29382ee35494Smrg va_list ap; 29392ee35494Smrg FILE *fp; 29402ee35494Smrg 29412ee35494Smrg va_start(ap, fmt); 29422ee35494Smrg num = vasprintf(&key, fmt, ap); 29432ee35494Smrg va_end(ap); 29442ee35494Smrg len = num; 29452ee35494Smrg 29462ee35494Smrg snprintf(filename, sizeof(filename), "%s/uevent", path); 29472ee35494Smrg 29482ee35494Smrg fp = fopen(filename, "r"); 29492ee35494Smrg if (!fp) { 29502ee35494Smrg free(key); 29512ee35494Smrg return NULL; 29522ee35494Smrg } 29532ee35494Smrg 29542ee35494Smrg while ((num = getline(&line, &size, fp)) >= 0) { 29552ee35494Smrg if ((strncmp(line, key, len) == 0) && (line[len] == '=')) { 29562ee35494Smrg char *start = line + len + 1, *end = line + num - 1; 29572ee35494Smrg 29582ee35494Smrg if (*end != '\n') 29592ee35494Smrg end++; 29602ee35494Smrg 29612ee35494Smrg value = strndup(start, end - start); 29622ee35494Smrg break; 29632ee35494Smrg } 29642ee35494Smrg } 29652ee35494Smrg 29662ee35494Smrg free(line); 29672ee35494Smrg fclose(fp); 29682ee35494Smrg 29692ee35494Smrg free(key); 29702ee35494Smrg 29712ee35494Smrg return value; 29722ee35494Smrg} 29732ee35494Smrg#endif 29742ee35494Smrg 2975fe517fc9Smrgstatic int drmParseSubsystemType(int maj, int min) 2976fe517fc9Smrg{ 2977fe517fc9Smrg#ifdef __linux__ 2978fe517fc9Smrg char path[PATH_MAX + 1]; 2979fe517fc9Smrg char link[PATH_MAX + 1] = ""; 2980fe517fc9Smrg char *name; 2981fe517fc9Smrg 2982fe517fc9Smrg snprintf(path, PATH_MAX, "/sys/dev/char/%d:%d/device/subsystem", 2983fe517fc9Smrg maj, min); 2984fe517fc9Smrg 2985fe517fc9Smrg if (readlink(path, link, PATH_MAX) < 0) 2986fe517fc9Smrg return -errno; 2987fe517fc9Smrg 2988fe517fc9Smrg name = strrchr(link, '/'); 2989fe517fc9Smrg if (!name) 2990fe517fc9Smrg return -EINVAL; 2991fe517fc9Smrg 2992fe517fc9Smrg if (strncmp(name, "/pci", 4) == 0) 2993fe517fc9Smrg return DRM_BUS_PCI; 2994fe517fc9Smrg 29952ee35494Smrg if (strncmp(name, "/usb", 4) == 0) 29962ee35494Smrg return DRM_BUS_USB; 29972ee35494Smrg 29982ee35494Smrg if (strncmp(name, "/platform", 9) == 0) 29992ee35494Smrg return DRM_BUS_PLATFORM; 30002ee35494Smrg 30012ee35494Smrg if (strncmp(name, "/host1x", 7) == 0) 30022ee35494Smrg return DRM_BUS_HOST1X; 30032ee35494Smrg 3004fe517fc9Smrg return -EINVAL; 30052ee35494Smrg#elif defined(__OpenBSD__) 30062ee35494Smrg return DRM_BUS_PCI; 3007fe517fc9Smrg#else 3008fe517fc9Smrg#warning "Missing implementation of drmParseSubsystemType" 3009fe517fc9Smrg return -EINVAL; 3010fe517fc9Smrg#endif 3011fe517fc9Smrg} 3012fe517fc9Smrg 3013fe517fc9Smrgstatic int drmParsePciBusInfo(int maj, int min, drmPciBusInfoPtr info) 3014fe517fc9Smrg{ 3015fe517fc9Smrg#ifdef __linux__ 30162ee35494Smrg unsigned int domain, bus, dev, func; 30172ee35494Smrg char path[PATH_MAX + 1], *value; 30182ee35494Smrg int num; 3019fe517fc9Smrg 30202ee35494Smrg snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min); 3021fe517fc9Smrg 30222ee35494Smrg value = sysfs_uevent_get(path, "PCI_SLOT_NAME"); 30232ee35494Smrg if (!value) 30242ee35494Smrg return -ENOENT; 3025fe517fc9Smrg 30262ee35494Smrg num = sscanf(value, "%04x:%02x:%02x.%1u", &domain, &bus, &dev, &func); 30272ee35494Smrg free(value); 3028fe517fc9Smrg 30292ee35494Smrg if (num != 4) 3030fe517fc9Smrg return -EINVAL; 3031fe517fc9Smrg 3032fe517fc9Smrg info->domain = domain; 3033fe517fc9Smrg info->bus = bus; 3034fe517fc9Smrg info->dev = dev; 3035fe517fc9Smrg info->func = func; 3036fe517fc9Smrg 30372ee35494Smrg return 0; 30382ee35494Smrg#elif defined(__OpenBSD__) 30392ee35494Smrg struct drm_pciinfo pinfo; 30402ee35494Smrg int fd, type; 30412ee35494Smrg 30422ee35494Smrg type = drmGetMinorType(min); 30432ee35494Smrg if (type == -1) 30442ee35494Smrg return -ENODEV; 30452ee35494Smrg 30462ee35494Smrg fd = drmOpenMinor(min, 0, type); 30472ee35494Smrg if (fd < 0) 30482ee35494Smrg return -errno; 30492ee35494Smrg 30502ee35494Smrg if (drmIoctl(fd, DRM_IOCTL_GET_PCIINFO, &pinfo)) { 30512ee35494Smrg close(fd); 30522ee35494Smrg return -errno; 30532ee35494Smrg } 30542ee35494Smrg close(fd); 30552ee35494Smrg 30562ee35494Smrg info->domain = pinfo.domain; 30572ee35494Smrg info->bus = pinfo.bus; 30582ee35494Smrg info->dev = pinfo.dev; 30592ee35494Smrg info->func = pinfo.func; 30602ee35494Smrg 3061fe517fc9Smrg return 0; 3062fe517fc9Smrg#else 3063fe517fc9Smrg#warning "Missing implementation of drmParsePciBusInfo" 3064fe517fc9Smrg return -EINVAL; 3065fe517fc9Smrg#endif 3066fe517fc9Smrg} 3067fe517fc9Smrg 30680655efefSmrgint drmDevicesEqual(drmDevicePtr a, drmDevicePtr b) 3069fe517fc9Smrg{ 3070fe517fc9Smrg if (a == NULL || b == NULL) 30710655efefSmrg return 0; 3072fe517fc9Smrg 3073fe517fc9Smrg if (a->bustype != b->bustype) 30740655efefSmrg return 0; 3075fe517fc9Smrg 3076fe517fc9Smrg switch (a->bustype) { 3077fe517fc9Smrg case DRM_BUS_PCI: 30780655efefSmrg return memcmp(a->businfo.pci, b->businfo.pci, sizeof(drmPciBusInfo)) == 0; 30792ee35494Smrg 30802ee35494Smrg case DRM_BUS_USB: 30810655efefSmrg return memcmp(a->businfo.usb, b->businfo.usb, sizeof(drmUsbBusInfo)) == 0; 30822ee35494Smrg 30832ee35494Smrg case DRM_BUS_PLATFORM: 30840655efefSmrg return memcmp(a->businfo.platform, b->businfo.platform, sizeof(drmPlatformBusInfo)) == 0; 30852ee35494Smrg 30862ee35494Smrg case DRM_BUS_HOST1X: 30870655efefSmrg return memcmp(a->businfo.host1x, b->businfo.host1x, sizeof(drmHost1xBusInfo)) == 0; 30882ee35494Smrg 3089fe517fc9Smrg default: 3090fe517fc9Smrg break; 3091fe517fc9Smrg } 3092fe517fc9Smrg 30930655efefSmrg return 0; 3094fe517fc9Smrg} 3095fe517fc9Smrg 3096fe517fc9Smrgstatic int drmGetNodeType(const char *name) 3097fe517fc9Smrg{ 3098fe517fc9Smrg if (strncmp(name, DRM_PRIMARY_MINOR_NAME, 3099fe517fc9Smrg sizeof(DRM_PRIMARY_MINOR_NAME) - 1) == 0) 3100fe517fc9Smrg return DRM_NODE_PRIMARY; 3101fe517fc9Smrg 3102fe517fc9Smrg if (strncmp(name, DRM_CONTROL_MINOR_NAME, 3103fe517fc9Smrg sizeof(DRM_CONTROL_MINOR_NAME ) - 1) == 0) 3104fe517fc9Smrg return DRM_NODE_CONTROL; 3105fe517fc9Smrg 3106fe517fc9Smrg if (strncmp(name, DRM_RENDER_MINOR_NAME, 3107fe517fc9Smrg sizeof(DRM_RENDER_MINOR_NAME) - 1) == 0) 3108fe517fc9Smrg return DRM_NODE_RENDER; 3109fe517fc9Smrg 3110fe517fc9Smrg return -EINVAL; 3111fe517fc9Smrg} 3112fe517fc9Smrg 3113fe517fc9Smrgstatic int drmGetMaxNodeName(void) 3114fe517fc9Smrg{ 3115fe517fc9Smrg return sizeof(DRM_DIR_NAME) + 3116fe517fc9Smrg MAX3(sizeof(DRM_PRIMARY_MINOR_NAME), 3117fe517fc9Smrg sizeof(DRM_CONTROL_MINOR_NAME), 3118fe517fc9Smrg sizeof(DRM_RENDER_MINOR_NAME)) + 3119fe517fc9Smrg 3 /* length of the node number */; 3120fe517fc9Smrg} 3121fe517fc9Smrg 3122fe517fc9Smrg#ifdef __linux__ 31232ee35494Smrgstatic int parse_separate_sysfs_files(int maj, int min, 31242ee35494Smrg drmPciDeviceInfoPtr device, 31252ee35494Smrg bool ignore_revision) 31262ee35494Smrg{ 31272ee35494Smrg#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) 31282ee35494Smrg static const char *attrs[] = { 31292ee35494Smrg "revision", /* Older kernels are missing the file, so check for it first */ 31302ee35494Smrg "vendor", 31312ee35494Smrg "device", 31322ee35494Smrg "subsystem_vendor", 31332ee35494Smrg "subsystem_device", 31342ee35494Smrg }; 31352ee35494Smrg char path[PATH_MAX + 1]; 31362ee35494Smrg unsigned int data[ARRAY_SIZE(attrs)]; 31372ee35494Smrg FILE *fp; 31382ee35494Smrg int ret; 31392ee35494Smrg 31402ee35494Smrg for (unsigned i = ignore_revision ? 1 : 0; i < ARRAY_SIZE(attrs); i++) { 31412ee35494Smrg snprintf(path, PATH_MAX, "/sys/dev/char/%d:%d/device/%s", maj, min, 31422ee35494Smrg attrs[i]); 31432ee35494Smrg fp = fopen(path, "r"); 31442ee35494Smrg if (!fp) 31452ee35494Smrg return -errno; 31462ee35494Smrg 31472ee35494Smrg ret = fscanf(fp, "%x", &data[i]); 31482ee35494Smrg fclose(fp); 31492ee35494Smrg if (ret != 1) 31502ee35494Smrg return -errno; 31512ee35494Smrg 31522ee35494Smrg } 31532ee35494Smrg 31542ee35494Smrg device->revision_id = ignore_revision ? 0xff : data[0] & 0xff; 31552ee35494Smrg device->vendor_id = data[1] & 0xffff; 31562ee35494Smrg device->device_id = data[2] & 0xffff; 31572ee35494Smrg device->subvendor_id = data[3] & 0xffff; 31582ee35494Smrg device->subdevice_id = data[4] & 0xffff; 31592ee35494Smrg 31602ee35494Smrg return 0; 31612ee35494Smrg} 31622ee35494Smrg 31632ee35494Smrgstatic int parse_config_sysfs_file(int maj, int min, 31642ee35494Smrg drmPciDeviceInfoPtr device) 31652ee35494Smrg{ 3166fe517fc9Smrg char path[PATH_MAX + 1]; 3167fe517fc9Smrg unsigned char config[64]; 3168fe517fc9Smrg int fd, ret; 3169fe517fc9Smrg 31702ee35494Smrg snprintf(path, PATH_MAX, "/sys/dev/char/%d:%d/device/config", maj, min); 3171fe517fc9Smrg fd = open(path, O_RDONLY); 3172fe517fc9Smrg if (fd < 0) 3173fe517fc9Smrg return -errno; 3174fe517fc9Smrg 3175fe517fc9Smrg ret = read(fd, config, sizeof(config)); 3176fe517fc9Smrg close(fd); 3177fe517fc9Smrg if (ret < 0) 3178fe517fc9Smrg return -errno; 3179fe517fc9Smrg 3180fe517fc9Smrg device->vendor_id = config[0] | (config[1] << 8); 3181fe517fc9Smrg device->device_id = config[2] | (config[3] << 8); 3182fe517fc9Smrg device->revision_id = config[8]; 3183fe517fc9Smrg device->subvendor_id = config[44] | (config[45] << 8); 3184fe517fc9Smrg device->subdevice_id = config[46] | (config[47] << 8); 3185fe517fc9Smrg 31862ee35494Smrg return 0; 31872ee35494Smrg} 31882ee35494Smrg#endif 31892ee35494Smrg 31902ee35494Smrgstatic int drmParsePciDeviceInfo(int maj, int min, 31912ee35494Smrg drmPciDeviceInfoPtr device, 31922ee35494Smrg uint32_t flags) 31932ee35494Smrg{ 31942ee35494Smrg#ifdef __linux__ 31952ee35494Smrg if (!(flags & DRM_DEVICE_GET_PCI_REVISION)) 31962ee35494Smrg return parse_separate_sysfs_files(maj, min, device, true); 31972ee35494Smrg 31982ee35494Smrg if (parse_separate_sysfs_files(maj, min, device, false)) 31992ee35494Smrg return parse_config_sysfs_file(maj, min, device); 32002ee35494Smrg 32012ee35494Smrg return 0; 32022ee35494Smrg#elif defined(__OpenBSD__) 32032ee35494Smrg struct drm_pciinfo pinfo; 32042ee35494Smrg int fd, type; 32052ee35494Smrg 32062ee35494Smrg type = drmGetMinorType(min); 32072ee35494Smrg if (type == -1) 32082ee35494Smrg return -ENODEV; 32092ee35494Smrg 32102ee35494Smrg fd = drmOpenMinor(min, 0, type); 32112ee35494Smrg if (fd < 0) 32122ee35494Smrg return -errno; 32132ee35494Smrg 32142ee35494Smrg if (drmIoctl(fd, DRM_IOCTL_GET_PCIINFO, &pinfo)) { 32152ee35494Smrg close(fd); 32162ee35494Smrg return -errno; 32172ee35494Smrg } 32182ee35494Smrg close(fd); 32192ee35494Smrg 32202ee35494Smrg device->vendor_id = pinfo.vendor_id; 32212ee35494Smrg device->device_id = pinfo.device_id; 32222ee35494Smrg device->revision_id = pinfo.revision_id; 32232ee35494Smrg device->subvendor_id = pinfo.subvendor_id; 32242ee35494Smrg device->subdevice_id = pinfo.subdevice_id; 32252ee35494Smrg 3226fe517fc9Smrg return 0; 3227fe517fc9Smrg#else 3228fe517fc9Smrg#warning "Missing implementation of drmParsePciDeviceInfo" 3229fe517fc9Smrg return -EINVAL; 3230fe517fc9Smrg#endif 3231fe517fc9Smrg} 3232fe517fc9Smrg 32332ee35494Smrgstatic void drmFreePlatformDevice(drmDevicePtr device) 32342ee35494Smrg{ 32352ee35494Smrg if (device->deviceinfo.platform) { 32362ee35494Smrg if (device->deviceinfo.platform->compatible) { 32372ee35494Smrg char **compatible = device->deviceinfo.platform->compatible; 32382ee35494Smrg 32392ee35494Smrg while (*compatible) { 32402ee35494Smrg free(*compatible); 32412ee35494Smrg compatible++; 32422ee35494Smrg } 32432ee35494Smrg 32442ee35494Smrg free(device->deviceinfo.platform->compatible); 32452ee35494Smrg } 32462ee35494Smrg } 32472ee35494Smrg} 32482ee35494Smrg 32492ee35494Smrgstatic void drmFreeHost1xDevice(drmDevicePtr device) 32502ee35494Smrg{ 32512ee35494Smrg if (device->deviceinfo.host1x) { 32522ee35494Smrg if (device->deviceinfo.host1x->compatible) { 32532ee35494Smrg char **compatible = device->deviceinfo.host1x->compatible; 32542ee35494Smrg 32552ee35494Smrg while (*compatible) { 32562ee35494Smrg free(*compatible); 32572ee35494Smrg compatible++; 32582ee35494Smrg } 32592ee35494Smrg 32602ee35494Smrg free(device->deviceinfo.host1x->compatible); 32612ee35494Smrg } 32622ee35494Smrg } 32632ee35494Smrg} 32642ee35494Smrg 3265fe517fc9Smrgvoid drmFreeDevice(drmDevicePtr *device) 3266fe517fc9Smrg{ 3267fe517fc9Smrg if (device == NULL) 3268fe517fc9Smrg return; 3269fe517fc9Smrg 32702ee35494Smrg if (*device) { 32712ee35494Smrg switch ((*device)->bustype) { 32722ee35494Smrg case DRM_BUS_PLATFORM: 32732ee35494Smrg drmFreePlatformDevice(*device); 32742ee35494Smrg break; 32752ee35494Smrg 32762ee35494Smrg case DRM_BUS_HOST1X: 32772ee35494Smrg drmFreeHost1xDevice(*device); 32782ee35494Smrg break; 32792ee35494Smrg } 32802ee35494Smrg } 32812ee35494Smrg 3282fe517fc9Smrg free(*device); 3283fe517fc9Smrg *device = NULL; 3284fe517fc9Smrg} 3285fe517fc9Smrg 3286fe517fc9Smrgvoid drmFreeDevices(drmDevicePtr devices[], int count) 3287fe517fc9Smrg{ 3288fe517fc9Smrg int i; 3289fe517fc9Smrg 3290fe517fc9Smrg if (devices == NULL) 3291fe517fc9Smrg return; 3292fe517fc9Smrg 3293fe517fc9Smrg for (i = 0; i < count; i++) 3294fe517fc9Smrg if (devices[i]) 3295fe517fc9Smrg drmFreeDevice(&devices[i]); 3296fe517fc9Smrg} 3297fe517fc9Smrg 32982ee35494Smrgstatic drmDevicePtr drmDeviceAlloc(unsigned int type, const char *node, 32992ee35494Smrg size_t bus_size, size_t device_size, 33002ee35494Smrg char **ptrp) 3301fe517fc9Smrg{ 33022ee35494Smrg size_t max_node_length, extra, size; 33032ee35494Smrg drmDevicePtr device; 33042ee35494Smrg unsigned int i; 33052ee35494Smrg char *ptr; 3306fe517fc9Smrg 33072ee35494Smrg max_node_length = ALIGN(drmGetMaxNodeName(), sizeof(void *)); 33082ee35494Smrg extra = DRM_NODE_MAX * (sizeof(void *) + max_node_length); 3309fe517fc9Smrg 33102ee35494Smrg size = sizeof(*device) + extra + bus_size + device_size; 3311fe517fc9Smrg 33122ee35494Smrg device = calloc(1, size); 33132ee35494Smrg if (!device) 33142ee35494Smrg return NULL; 33152ee35494Smrg 33162ee35494Smrg device->available_nodes = 1 << type; 3317fe517fc9Smrg 33182ee35494Smrg ptr = (char *)device + sizeof(*device); 33192ee35494Smrg device->nodes = (char **)ptr; 33202ee35494Smrg 33212ee35494Smrg ptr += DRM_NODE_MAX * sizeof(void *); 3322fe517fc9Smrg 3323fe517fc9Smrg for (i = 0; i < DRM_NODE_MAX; i++) { 33242ee35494Smrg device->nodes[i] = ptr; 33252ee35494Smrg ptr += max_node_length; 3326fe517fc9Smrg } 3327fe517fc9Smrg 33282ee35494Smrg memcpy(device->nodes[type], node, max_node_length); 33292ee35494Smrg 33302ee35494Smrg *ptrp = ptr; 33312ee35494Smrg 33322ee35494Smrg return device; 33332ee35494Smrg} 33342ee35494Smrg 33352ee35494Smrgstatic int drmProcessPciDevice(drmDevicePtr *device, 33362ee35494Smrg const char *node, int node_type, 33372ee35494Smrg int maj, int min, bool fetch_deviceinfo, 33382ee35494Smrg uint32_t flags) 33392ee35494Smrg{ 33402ee35494Smrg drmDevicePtr dev; 33412ee35494Smrg char *addr; 33422ee35494Smrg int ret; 33432ee35494Smrg 33442ee35494Smrg dev = drmDeviceAlloc(node_type, node, sizeof(drmPciBusInfo), 33452ee35494Smrg sizeof(drmPciDeviceInfo), &addr); 33462ee35494Smrg if (!dev) 33472ee35494Smrg return -ENOMEM; 33482ee35494Smrg 33492ee35494Smrg dev->bustype = DRM_BUS_PCI; 3350fe517fc9Smrg 33512ee35494Smrg dev->businfo.pci = (drmPciBusInfoPtr)addr; 33522ee35494Smrg 33532ee35494Smrg ret = drmParsePciBusInfo(maj, min, dev->businfo.pci); 3354fe517fc9Smrg if (ret) 3355fe517fc9Smrg goto free_device; 3356fe517fc9Smrg 3357fe517fc9Smrg // Fetch the device info if the user has requested it 3358fe517fc9Smrg if (fetch_deviceinfo) { 3359fe517fc9Smrg addr += sizeof(drmPciBusInfo); 33602ee35494Smrg dev->deviceinfo.pci = (drmPciDeviceInfoPtr)addr; 3361fe517fc9Smrg 33622ee35494Smrg ret = drmParsePciDeviceInfo(maj, min, dev->deviceinfo.pci, flags); 3363fe517fc9Smrg if (ret) 3364fe517fc9Smrg goto free_device; 3365fe517fc9Smrg } 33662ee35494Smrg 33672ee35494Smrg *device = dev; 33682ee35494Smrg 3369fe517fc9Smrg return 0; 3370fe517fc9Smrg 3371fe517fc9Smrgfree_device: 33722ee35494Smrg free(dev); 33732ee35494Smrg return ret; 33742ee35494Smrg} 33752ee35494Smrg 33762ee35494Smrgstatic int drmParseUsbBusInfo(int maj, int min, drmUsbBusInfoPtr info) 33772ee35494Smrg{ 33782ee35494Smrg#ifdef __linux__ 33792ee35494Smrg char path[PATH_MAX + 1], *value; 33802ee35494Smrg unsigned int bus, dev; 33812ee35494Smrg int ret; 33822ee35494Smrg 33832ee35494Smrg snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min); 33842ee35494Smrg 33852ee35494Smrg value = sysfs_uevent_get(path, "BUSNUM"); 33862ee35494Smrg if (!value) 33872ee35494Smrg return -ENOENT; 33882ee35494Smrg 33892ee35494Smrg ret = sscanf(value, "%03u", &bus); 33902ee35494Smrg free(value); 33912ee35494Smrg 33922ee35494Smrg if (ret <= 0) 33932ee35494Smrg return -errno; 33942ee35494Smrg 33952ee35494Smrg value = sysfs_uevent_get(path, "DEVNUM"); 33962ee35494Smrg if (!value) 33972ee35494Smrg return -ENOENT; 33982ee35494Smrg 33992ee35494Smrg ret = sscanf(value, "%03u", &dev); 34002ee35494Smrg free(value); 34012ee35494Smrg 34022ee35494Smrg if (ret <= 0) 34032ee35494Smrg return -errno; 34042ee35494Smrg 34052ee35494Smrg info->bus = bus; 34062ee35494Smrg info->dev = dev; 34072ee35494Smrg 34082ee35494Smrg return 0; 34092ee35494Smrg#else 34102ee35494Smrg#warning "Missing implementation of drmParseUsbBusInfo" 34112ee35494Smrg return -EINVAL; 34122ee35494Smrg#endif 34132ee35494Smrg} 34142ee35494Smrg 34152ee35494Smrgstatic int drmParseUsbDeviceInfo(int maj, int min, drmUsbDeviceInfoPtr info) 34162ee35494Smrg{ 34172ee35494Smrg#ifdef __linux__ 34182ee35494Smrg char path[PATH_MAX + 1], *value; 34192ee35494Smrg unsigned int vendor, product; 34202ee35494Smrg int ret; 34212ee35494Smrg 34222ee35494Smrg snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min); 34232ee35494Smrg 34242ee35494Smrg value = sysfs_uevent_get(path, "PRODUCT"); 34252ee35494Smrg if (!value) 34262ee35494Smrg return -ENOENT; 34272ee35494Smrg 34282ee35494Smrg ret = sscanf(value, "%x/%x", &vendor, &product); 34292ee35494Smrg free(value); 34302ee35494Smrg 34312ee35494Smrg if (ret <= 0) 34322ee35494Smrg return -errno; 34332ee35494Smrg 34342ee35494Smrg info->vendor = vendor; 34352ee35494Smrg info->product = product; 34362ee35494Smrg 34372ee35494Smrg return 0; 34382ee35494Smrg#else 34392ee35494Smrg#warning "Missing implementation of drmParseUsbDeviceInfo" 34402ee35494Smrg return -EINVAL; 34412ee35494Smrg#endif 34422ee35494Smrg} 34432ee35494Smrg 34442ee35494Smrgstatic int drmProcessUsbDevice(drmDevicePtr *device, const char *node, 34452ee35494Smrg int node_type, int maj, int min, 34462ee35494Smrg bool fetch_deviceinfo, uint32_t flags) 34472ee35494Smrg{ 34482ee35494Smrg drmDevicePtr dev; 34492ee35494Smrg char *ptr; 34502ee35494Smrg int ret; 34512ee35494Smrg 34522ee35494Smrg dev = drmDeviceAlloc(node_type, node, sizeof(drmUsbBusInfo), 34532ee35494Smrg sizeof(drmUsbDeviceInfo), &ptr); 34542ee35494Smrg if (!dev) 34552ee35494Smrg return -ENOMEM; 34562ee35494Smrg 34572ee35494Smrg dev->bustype = DRM_BUS_USB; 34582ee35494Smrg 34592ee35494Smrg dev->businfo.usb = (drmUsbBusInfoPtr)ptr; 34602ee35494Smrg 34612ee35494Smrg ret = drmParseUsbBusInfo(maj, min, dev->businfo.usb); 34622ee35494Smrg if (ret < 0) 34632ee35494Smrg goto free_device; 34642ee35494Smrg 34652ee35494Smrg if (fetch_deviceinfo) { 34662ee35494Smrg ptr += sizeof(drmUsbBusInfo); 34672ee35494Smrg dev->deviceinfo.usb = (drmUsbDeviceInfoPtr)ptr; 34682ee35494Smrg 34692ee35494Smrg ret = drmParseUsbDeviceInfo(maj, min, dev->deviceinfo.usb); 34702ee35494Smrg if (ret < 0) 34712ee35494Smrg goto free_device; 34722ee35494Smrg } 34732ee35494Smrg 34742ee35494Smrg *device = dev; 34752ee35494Smrg 34762ee35494Smrg return 0; 34772ee35494Smrg 34782ee35494Smrgfree_device: 34792ee35494Smrg free(dev); 34802ee35494Smrg return ret; 34812ee35494Smrg} 34822ee35494Smrg 34832ee35494Smrgstatic int drmParsePlatformBusInfo(int maj, int min, drmPlatformBusInfoPtr info) 34842ee35494Smrg{ 34852ee35494Smrg#ifdef __linux__ 34862ee35494Smrg char path[PATH_MAX + 1], *name; 34872ee35494Smrg 34882ee35494Smrg snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min); 34892ee35494Smrg 34902ee35494Smrg name = sysfs_uevent_get(path, "OF_FULLNAME"); 34912ee35494Smrg if (!name) 34922ee35494Smrg return -ENOENT; 34932ee35494Smrg 34942ee35494Smrg strncpy(info->fullname, name, DRM_PLATFORM_DEVICE_NAME_LEN); 34952ee35494Smrg info->fullname[DRM_PLATFORM_DEVICE_NAME_LEN - 1] = '\0'; 34962ee35494Smrg free(name); 34972ee35494Smrg 34982ee35494Smrg return 0; 34992ee35494Smrg#else 35002ee35494Smrg#warning "Missing implementation of drmParsePlatformBusInfo" 35012ee35494Smrg return -EINVAL; 35022ee35494Smrg#endif 35032ee35494Smrg} 35042ee35494Smrg 35052ee35494Smrgstatic int drmParsePlatformDeviceInfo(int maj, int min, 35062ee35494Smrg drmPlatformDeviceInfoPtr info) 35072ee35494Smrg{ 35082ee35494Smrg#ifdef __linux__ 35092ee35494Smrg char path[PATH_MAX + 1], *value; 35102ee35494Smrg unsigned int count, i; 35112ee35494Smrg int err; 35122ee35494Smrg 35132ee35494Smrg snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min); 35142ee35494Smrg 35152ee35494Smrg value = sysfs_uevent_get(path, "OF_COMPATIBLE_N"); 35162ee35494Smrg if (!value) 35172ee35494Smrg return -ENOENT; 35182ee35494Smrg 35192ee35494Smrg sscanf(value, "%u", &count); 35202ee35494Smrg free(value); 35212ee35494Smrg 35222ee35494Smrg info->compatible = calloc(count + 1, sizeof(*info->compatible)); 35232ee35494Smrg if (!info->compatible) 35242ee35494Smrg return -ENOMEM; 35252ee35494Smrg 35262ee35494Smrg for (i = 0; i < count; i++) { 35272ee35494Smrg value = sysfs_uevent_get(path, "OF_COMPATIBLE_%u", i); 35282ee35494Smrg if (!value) { 35292ee35494Smrg err = -ENOENT; 35302ee35494Smrg goto free; 35312ee35494Smrg } 35322ee35494Smrg 35332ee35494Smrg info->compatible[i] = value; 35342ee35494Smrg } 35352ee35494Smrg 35362ee35494Smrg return 0; 35372ee35494Smrg 35382ee35494Smrgfree: 35392ee35494Smrg while (i--) 35402ee35494Smrg free(info->compatible[i]); 35412ee35494Smrg 35422ee35494Smrg free(info->compatible); 35432ee35494Smrg return err; 35442ee35494Smrg#else 35452ee35494Smrg#warning "Missing implementation of drmParsePlatformDeviceInfo" 35462ee35494Smrg return -EINVAL; 35472ee35494Smrg#endif 35482ee35494Smrg} 35492ee35494Smrg 35502ee35494Smrgstatic int drmProcessPlatformDevice(drmDevicePtr *device, 35512ee35494Smrg const char *node, int node_type, 35522ee35494Smrg int maj, int min, bool fetch_deviceinfo, 35532ee35494Smrg uint32_t flags) 35542ee35494Smrg{ 35552ee35494Smrg drmDevicePtr dev; 35562ee35494Smrg char *ptr; 35572ee35494Smrg int ret; 35582ee35494Smrg 35592ee35494Smrg dev = drmDeviceAlloc(node_type, node, sizeof(drmPlatformBusInfo), 35602ee35494Smrg sizeof(drmPlatformDeviceInfo), &ptr); 35612ee35494Smrg if (!dev) 35622ee35494Smrg return -ENOMEM; 35632ee35494Smrg 35642ee35494Smrg dev->bustype = DRM_BUS_PLATFORM; 35652ee35494Smrg 35662ee35494Smrg dev->businfo.platform = (drmPlatformBusInfoPtr)ptr; 35672ee35494Smrg 35682ee35494Smrg ret = drmParsePlatformBusInfo(maj, min, dev->businfo.platform); 35692ee35494Smrg if (ret < 0) 35702ee35494Smrg goto free_device; 35712ee35494Smrg 35722ee35494Smrg if (fetch_deviceinfo) { 35732ee35494Smrg ptr += sizeof(drmPlatformBusInfo); 35742ee35494Smrg dev->deviceinfo.platform = (drmPlatformDeviceInfoPtr)ptr; 35752ee35494Smrg 35762ee35494Smrg ret = drmParsePlatformDeviceInfo(maj, min, dev->deviceinfo.platform); 35772ee35494Smrg if (ret < 0) 35782ee35494Smrg goto free_device; 35792ee35494Smrg } 35802ee35494Smrg 35812ee35494Smrg *device = dev; 35822ee35494Smrg 35832ee35494Smrg return 0; 35842ee35494Smrg 35852ee35494Smrgfree_device: 35862ee35494Smrg free(dev); 35872ee35494Smrg return ret; 35882ee35494Smrg} 35892ee35494Smrg 35902ee35494Smrgstatic int drmParseHost1xBusInfo(int maj, int min, drmHost1xBusInfoPtr info) 35912ee35494Smrg{ 35922ee35494Smrg#ifdef __linux__ 35932ee35494Smrg char path[PATH_MAX + 1], *name; 35942ee35494Smrg 35952ee35494Smrg snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min); 35962ee35494Smrg 35972ee35494Smrg name = sysfs_uevent_get(path, "OF_FULLNAME"); 35982ee35494Smrg if (!name) 35992ee35494Smrg return -ENOENT; 36002ee35494Smrg 36012ee35494Smrg strncpy(info->fullname, name, DRM_HOST1X_DEVICE_NAME_LEN); 36022ee35494Smrg info->fullname[DRM_HOST1X_DEVICE_NAME_LEN - 1] = '\0'; 36032ee35494Smrg free(name); 36042ee35494Smrg 36052ee35494Smrg return 0; 36062ee35494Smrg#else 36072ee35494Smrg#warning "Missing implementation of drmParseHost1xBusInfo" 36082ee35494Smrg return -EINVAL; 36092ee35494Smrg#endif 36102ee35494Smrg} 36112ee35494Smrg 36122ee35494Smrgstatic int drmParseHost1xDeviceInfo(int maj, int min, 36132ee35494Smrg drmHost1xDeviceInfoPtr info) 36142ee35494Smrg{ 36152ee35494Smrg#ifdef __linux__ 36162ee35494Smrg char path[PATH_MAX + 1], *value; 36172ee35494Smrg unsigned int count, i; 36182ee35494Smrg int err; 36192ee35494Smrg 36202ee35494Smrg snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min); 36212ee35494Smrg 36222ee35494Smrg value = sysfs_uevent_get(path, "OF_COMPATIBLE_N"); 36232ee35494Smrg if (!value) 36242ee35494Smrg return -ENOENT; 36252ee35494Smrg 36262ee35494Smrg sscanf(value, "%u", &count); 36272ee35494Smrg free(value); 36282ee35494Smrg 36292ee35494Smrg info->compatible = calloc(count + 1, sizeof(*info->compatible)); 36302ee35494Smrg if (!info->compatible) 36312ee35494Smrg return -ENOMEM; 36322ee35494Smrg 36332ee35494Smrg for (i = 0; i < count; i++) { 36342ee35494Smrg value = sysfs_uevent_get(path, "OF_COMPATIBLE_%u", i); 36352ee35494Smrg if (!value) { 36362ee35494Smrg err = -ENOENT; 36372ee35494Smrg goto free; 36382ee35494Smrg } 36392ee35494Smrg 36402ee35494Smrg info->compatible[i] = value; 36412ee35494Smrg } 36422ee35494Smrg 36432ee35494Smrg return 0; 36442ee35494Smrg 36452ee35494Smrgfree: 36462ee35494Smrg while (i--) 36472ee35494Smrg free(info->compatible[i]); 36482ee35494Smrg 36492ee35494Smrg free(info->compatible); 36502ee35494Smrg return err; 36512ee35494Smrg#else 36522ee35494Smrg#warning "Missing implementation of drmParseHost1xDeviceInfo" 36532ee35494Smrg return -EINVAL; 36542ee35494Smrg#endif 36552ee35494Smrg} 36562ee35494Smrg 36572ee35494Smrgstatic int drmProcessHost1xDevice(drmDevicePtr *device, 36582ee35494Smrg const char *node, int node_type, 36592ee35494Smrg int maj, int min, bool fetch_deviceinfo, 36602ee35494Smrg uint32_t flags) 36612ee35494Smrg{ 36622ee35494Smrg drmDevicePtr dev; 36632ee35494Smrg char *ptr; 36642ee35494Smrg int ret; 36652ee35494Smrg 36662ee35494Smrg dev = drmDeviceAlloc(node_type, node, sizeof(drmHost1xBusInfo), 36672ee35494Smrg sizeof(drmHost1xDeviceInfo), &ptr); 36682ee35494Smrg if (!dev) 36692ee35494Smrg return -ENOMEM; 36702ee35494Smrg 36712ee35494Smrg dev->bustype = DRM_BUS_HOST1X; 36722ee35494Smrg 36732ee35494Smrg dev->businfo.host1x = (drmHost1xBusInfoPtr)ptr; 36742ee35494Smrg 36752ee35494Smrg ret = drmParseHost1xBusInfo(maj, min, dev->businfo.host1x); 36762ee35494Smrg if (ret < 0) 36772ee35494Smrg goto free_device; 36782ee35494Smrg 36792ee35494Smrg if (fetch_deviceinfo) { 36802ee35494Smrg ptr += sizeof(drmHost1xBusInfo); 36812ee35494Smrg dev->deviceinfo.host1x = (drmHost1xDeviceInfoPtr)ptr; 36822ee35494Smrg 36832ee35494Smrg ret = drmParseHost1xDeviceInfo(maj, min, dev->deviceinfo.host1x); 36842ee35494Smrg if (ret < 0) 36852ee35494Smrg goto free_device; 36862ee35494Smrg } 36872ee35494Smrg 36882ee35494Smrg *device = dev; 36892ee35494Smrg 36902ee35494Smrg return 0; 36912ee35494Smrg 36922ee35494Smrgfree_device: 36932ee35494Smrg free(dev); 3694fe517fc9Smrg return ret; 3695fe517fc9Smrg} 3696fe517fc9Smrg 3697fe517fc9Smrg/* Consider devices located on the same bus as duplicate and fold the respective 3698fe517fc9Smrg * entries into a single one. 3699fe517fc9Smrg * 3700fe517fc9Smrg * Note: this leaves "gaps" in the array, while preserving the length. 3701fe517fc9Smrg */ 3702fe517fc9Smrgstatic void drmFoldDuplicatedDevices(drmDevicePtr local_devices[], int count) 3703fe517fc9Smrg{ 3704fe517fc9Smrg int node_type, i, j; 3705fe517fc9Smrg 3706fe517fc9Smrg for (i = 0; i < count; i++) { 3707fe517fc9Smrg for (j = i + 1; j < count; j++) { 37080655efefSmrg if (drmDevicesEqual(local_devices[i], local_devices[j])) { 3709fe517fc9Smrg local_devices[i]->available_nodes |= local_devices[j]->available_nodes; 3710fe517fc9Smrg node_type = log2(local_devices[j]->available_nodes); 3711fe517fc9Smrg memcpy(local_devices[i]->nodes[node_type], 3712fe517fc9Smrg local_devices[j]->nodes[node_type], drmGetMaxNodeName()); 3713fe517fc9Smrg drmFreeDevice(&local_devices[j]); 3714fe517fc9Smrg } 3715fe517fc9Smrg } 3716fe517fc9Smrg } 3717fe517fc9Smrg} 3718fe517fc9Smrg 37192ee35494Smrg/* Check that the given flags are valid returning 0 on success */ 37202ee35494Smrgstatic int 37212ee35494Smrgdrm_device_validate_flags(uint32_t flags) 37222ee35494Smrg{ 37232ee35494Smrg return (flags & ~DRM_DEVICE_GET_PCI_REVISION); 37242ee35494Smrg} 37252ee35494Smrg 3726fe517fc9Smrg/** 3727fe517fc9Smrg * Get information about the opened drm device 3728fe517fc9Smrg * 3729fe517fc9Smrg * \param fd file descriptor of the drm device 37302ee35494Smrg * \param flags feature/behaviour bitmask 3731fe517fc9Smrg * \param device the address of a drmDevicePtr where the information 3732fe517fc9Smrg * will be allocated in stored 3733fe517fc9Smrg * 3734fe517fc9Smrg * \return zero on success, negative error code otherwise. 37352ee35494Smrg * 37362ee35494Smrg * \note Unlike drmGetDevice it does not retrieve the pci device revision field 37372ee35494Smrg * unless the DRM_DEVICE_GET_PCI_REVISION \p flag is set. 3738fe517fc9Smrg */ 37392ee35494Smrgint drmGetDevice2(int fd, uint32_t flags, drmDevicePtr *device) 3740fe517fc9Smrg{ 37412ee35494Smrg#ifdef __OpenBSD__ 37422ee35494Smrg /* 37432ee35494Smrg * DRI device nodes on OpenBSD are not in their own directory, they reside 37442ee35494Smrg * in /dev along with a large number of statically generated /dev nodes. 37452ee35494Smrg * Avoid stat'ing all of /dev needlessly by implementing this custom path. 37462ee35494Smrg */ 37472ee35494Smrg drmDevicePtr d; 37482ee35494Smrg struct stat sbuf; 37492ee35494Smrg char node[PATH_MAX + 1]; 37502ee35494Smrg const char *dev_name; 37512ee35494Smrg int node_type, subsystem_type; 37522ee35494Smrg int maj, min, n, ret, base; 37532ee35494Smrg 37542ee35494Smrg if (fd == -1 || device == NULL) 37552ee35494Smrg return -EINVAL; 37562ee35494Smrg 37572ee35494Smrg if (fstat(fd, &sbuf)) 37582ee35494Smrg return -errno; 37592ee35494Smrg 37602ee35494Smrg maj = major(sbuf.st_rdev); 37612ee35494Smrg min = minor(sbuf.st_rdev); 37622ee35494Smrg 37632ee35494Smrg if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode)) 37642ee35494Smrg return -EINVAL; 37652ee35494Smrg 37662ee35494Smrg node_type = drmGetMinorType(min); 37672ee35494Smrg if (node_type == -1) 37682ee35494Smrg return -ENODEV; 37692ee35494Smrg 37702ee35494Smrg switch (node_type) { 37712ee35494Smrg case DRM_NODE_PRIMARY: 37722ee35494Smrg dev_name = DRM_DEV_NAME; 37732ee35494Smrg break; 37742ee35494Smrg case DRM_NODE_CONTROL: 37752ee35494Smrg dev_name = DRM_CONTROL_DEV_NAME; 37762ee35494Smrg break; 37772ee35494Smrg case DRM_NODE_RENDER: 37782ee35494Smrg dev_name = DRM_RENDER_DEV_NAME; 37792ee35494Smrg break; 37802ee35494Smrg default: 37812ee35494Smrg return -EINVAL; 37822ee35494Smrg }; 37832ee35494Smrg 37842ee35494Smrg base = drmGetMinorBase(node_type); 37852ee35494Smrg if (base < 0) 37862ee35494Smrg return -EINVAL; 37872ee35494Smrg 37882ee35494Smrg n = snprintf(node, PATH_MAX, dev_name, DRM_DIR_NAME, min - base); 37892ee35494Smrg if (n == -1 || n >= PATH_MAX) 37902ee35494Smrg return -errno; 37912ee35494Smrg if (stat(node, &sbuf)) 37922ee35494Smrg return -EINVAL; 37932ee35494Smrg 37942ee35494Smrg subsystem_type = drmParseSubsystemType(maj, min); 37952ee35494Smrg if (subsystem_type != DRM_BUS_PCI) 37962ee35494Smrg return -ENODEV; 37972ee35494Smrg 37982ee35494Smrg ret = drmProcessPciDevice(&d, node, node_type, maj, min, true, flags); 37992ee35494Smrg if (ret) 38002ee35494Smrg return ret; 38012ee35494Smrg 38022ee35494Smrg *device = d; 38032ee35494Smrg 38042ee35494Smrg return 0; 38052ee35494Smrg#else 3806fe517fc9Smrg drmDevicePtr *local_devices; 3807fe517fc9Smrg drmDevicePtr d; 3808fe517fc9Smrg DIR *sysdir; 3809fe517fc9Smrg struct dirent *dent; 3810fe517fc9Smrg struct stat sbuf; 3811fe517fc9Smrg char node[PATH_MAX + 1]; 3812fe517fc9Smrg int node_type, subsystem_type; 3813fe517fc9Smrg int maj, min; 3814fe517fc9Smrg int ret, i, node_count; 3815fe517fc9Smrg int max_count = 16; 3816fe517fc9Smrg dev_t find_rdev; 3817fe517fc9Smrg 38182ee35494Smrg if (drm_device_validate_flags(flags)) 38192ee35494Smrg return -EINVAL; 38202ee35494Smrg 3821fe517fc9Smrg if (fd == -1 || device == NULL) 3822fe517fc9Smrg return -EINVAL; 3823fe517fc9Smrg 3824fe517fc9Smrg if (fstat(fd, &sbuf)) 3825fe517fc9Smrg return -errno; 3826fe517fc9Smrg 3827fe517fc9Smrg find_rdev = sbuf.st_rdev; 3828fe517fc9Smrg maj = major(sbuf.st_rdev); 3829fe517fc9Smrg min = minor(sbuf.st_rdev); 3830fe517fc9Smrg 3831fe517fc9Smrg if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode)) 3832fe517fc9Smrg return -EINVAL; 3833fe517fc9Smrg 3834fe517fc9Smrg subsystem_type = drmParseSubsystemType(maj, min); 3835fe517fc9Smrg 3836fe517fc9Smrg local_devices = calloc(max_count, sizeof(drmDevicePtr)); 3837fe517fc9Smrg if (local_devices == NULL) 3838fe517fc9Smrg return -ENOMEM; 3839fe517fc9Smrg 3840fe517fc9Smrg sysdir = opendir(DRM_DIR_NAME); 3841fe517fc9Smrg if (!sysdir) { 3842fe517fc9Smrg ret = -errno; 3843fe517fc9Smrg goto free_locals; 3844fe517fc9Smrg } 3845fe517fc9Smrg 3846fe517fc9Smrg i = 0; 3847fe517fc9Smrg while ((dent = readdir(sysdir))) { 3848fe517fc9Smrg node_type = drmGetNodeType(dent->d_name); 3849fe517fc9Smrg if (node_type < 0) 3850fe517fc9Smrg continue; 3851fe517fc9Smrg 3852fe517fc9Smrg snprintf(node, PATH_MAX, "%s/%s", DRM_DIR_NAME, dent->d_name); 3853fe517fc9Smrg if (stat(node, &sbuf)) 3854fe517fc9Smrg continue; 3855fe517fc9Smrg 3856fe517fc9Smrg maj = major(sbuf.st_rdev); 3857fe517fc9Smrg min = minor(sbuf.st_rdev); 3858fe517fc9Smrg 3859fe517fc9Smrg if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode)) 3860fe517fc9Smrg continue; 3861fe517fc9Smrg 3862fe517fc9Smrg if (drmParseSubsystemType(maj, min) != subsystem_type) 3863fe517fc9Smrg continue; 3864fe517fc9Smrg 3865fe517fc9Smrg switch (subsystem_type) { 3866fe517fc9Smrg case DRM_BUS_PCI: 38672ee35494Smrg ret = drmProcessPciDevice(&d, node, node_type, maj, min, true, flags); 3868fe517fc9Smrg if (ret) 38692ee35494Smrg continue; 38702ee35494Smrg 38712ee35494Smrg break; 38722ee35494Smrg 38732ee35494Smrg case DRM_BUS_USB: 38742ee35494Smrg ret = drmProcessUsbDevice(&d, node, node_type, maj, min, true, flags); 38752ee35494Smrg if (ret) 38762ee35494Smrg continue; 38772ee35494Smrg 38782ee35494Smrg break; 38792ee35494Smrg 38802ee35494Smrg case DRM_BUS_PLATFORM: 38812ee35494Smrg ret = drmProcessPlatformDevice(&d, node, node_type, maj, min, true, flags); 38822ee35494Smrg if (ret) 38832ee35494Smrg continue; 38842ee35494Smrg 38852ee35494Smrg break; 38862ee35494Smrg 38872ee35494Smrg case DRM_BUS_HOST1X: 38882ee35494Smrg ret = drmProcessHost1xDevice(&d, node, node_type, maj, min, true, flags); 38892ee35494Smrg if (ret) 38902ee35494Smrg continue; 3891fe517fc9Smrg 3892fe517fc9Smrg break; 38932ee35494Smrg 3894fe517fc9Smrg default: 3895fe517fc9Smrg continue; 3896fe517fc9Smrg } 3897fe517fc9Smrg 3898fe517fc9Smrg if (i >= max_count) { 3899fe517fc9Smrg drmDevicePtr *temp; 3900fe517fc9Smrg 3901fe517fc9Smrg max_count += 16; 3902fe517fc9Smrg temp = realloc(local_devices, max_count * sizeof(drmDevicePtr)); 3903fe517fc9Smrg if (!temp) 3904fe517fc9Smrg goto free_devices; 3905fe517fc9Smrg local_devices = temp; 3906fe517fc9Smrg } 3907fe517fc9Smrg 3908fe517fc9Smrg /* store target at local_devices[0] for ease to use below */ 3909fe517fc9Smrg if (find_rdev == sbuf.st_rdev && i) { 3910fe517fc9Smrg local_devices[i] = local_devices[0]; 3911fe517fc9Smrg local_devices[0] = d; 3912fe517fc9Smrg } 3913fe517fc9Smrg else 3914fe517fc9Smrg local_devices[i] = d; 3915fe517fc9Smrg i++; 3916fe517fc9Smrg } 3917fe517fc9Smrg node_count = i; 3918fe517fc9Smrg 3919fe517fc9Smrg drmFoldDuplicatedDevices(local_devices, node_count); 3920fe517fc9Smrg 3921fe517fc9Smrg *device = local_devices[0]; 3922fe517fc9Smrg drmFreeDevices(&local_devices[1], node_count - 1); 3923fe517fc9Smrg 3924fe517fc9Smrg closedir(sysdir); 3925fe517fc9Smrg free(local_devices); 39262ee35494Smrg if (*device == NULL) 39272ee35494Smrg return -ENODEV; 3928fe517fc9Smrg return 0; 3929fe517fc9Smrg 3930fe517fc9Smrgfree_devices: 3931fe517fc9Smrg drmFreeDevices(local_devices, i); 3932fe517fc9Smrg closedir(sysdir); 3933fe517fc9Smrg 3934fe517fc9Smrgfree_locals: 3935fe517fc9Smrg free(local_devices); 3936fe517fc9Smrg return ret; 39372ee35494Smrg#endif 39382ee35494Smrg} 39392ee35494Smrg 39402ee35494Smrg/** 39412ee35494Smrg * Get information about the opened drm device 39422ee35494Smrg * 39432ee35494Smrg * \param fd file descriptor of the drm device 39442ee35494Smrg * \param device the address of a drmDevicePtr where the information 39452ee35494Smrg * will be allocated in stored 39462ee35494Smrg * 39472ee35494Smrg * \return zero on success, negative error code otherwise. 39482ee35494Smrg */ 39492ee35494Smrgint drmGetDevice(int fd, drmDevicePtr *device) 39502ee35494Smrg{ 39512ee35494Smrg return drmGetDevice2(fd, DRM_DEVICE_GET_PCI_REVISION, device); 3952fe517fc9Smrg} 3953fe517fc9Smrg 3954fe517fc9Smrg/** 3955fe517fc9Smrg * Get drm devices on the system 3956fe517fc9Smrg * 39572ee35494Smrg * \param flags feature/behaviour bitmask 3958fe517fc9Smrg * \param devices the array of devices with drmDevicePtr elements 3959fe517fc9Smrg * can be NULL to get the device number first 3960fe517fc9Smrg * \param max_devices the maximum number of devices for the array 3961fe517fc9Smrg * 3962fe517fc9Smrg * \return on error - negative error code, 3963fe517fc9Smrg * if devices is NULL - total number of devices available on the system, 3964fe517fc9Smrg * alternatively the number of devices stored in devices[], which is 3965fe517fc9Smrg * capped by the max_devices. 39662ee35494Smrg * 39672ee35494Smrg * \note Unlike drmGetDevices it does not retrieve the pci device revision field 39682ee35494Smrg * unless the DRM_DEVICE_GET_PCI_REVISION \p flag is set. 3969fe517fc9Smrg */ 39702ee35494Smrgint drmGetDevices2(uint32_t flags, drmDevicePtr devices[], int max_devices) 3971fe517fc9Smrg{ 3972fe517fc9Smrg drmDevicePtr *local_devices; 3973fe517fc9Smrg drmDevicePtr device; 3974fe517fc9Smrg DIR *sysdir; 3975fe517fc9Smrg struct dirent *dent; 3976fe517fc9Smrg struct stat sbuf; 3977fe517fc9Smrg char node[PATH_MAX + 1]; 3978fe517fc9Smrg int node_type, subsystem_type; 3979fe517fc9Smrg int maj, min; 3980fe517fc9Smrg int ret, i, node_count, device_count; 3981fe517fc9Smrg int max_count = 16; 3982fe517fc9Smrg 39832ee35494Smrg if (drm_device_validate_flags(flags)) 39842ee35494Smrg return -EINVAL; 39852ee35494Smrg 3986fe517fc9Smrg local_devices = calloc(max_count, sizeof(drmDevicePtr)); 3987fe517fc9Smrg if (local_devices == NULL) 3988fe517fc9Smrg return -ENOMEM; 3989fe517fc9Smrg 3990fe517fc9Smrg sysdir = opendir(DRM_DIR_NAME); 3991fe517fc9Smrg if (!sysdir) { 3992fe517fc9Smrg ret = -errno; 3993fe517fc9Smrg goto free_locals; 3994fe517fc9Smrg } 3995fe517fc9Smrg 3996fe517fc9Smrg i = 0; 3997fe517fc9Smrg while ((dent = readdir(sysdir))) { 3998fe517fc9Smrg node_type = drmGetNodeType(dent->d_name); 3999fe517fc9Smrg if (node_type < 0) 4000fe517fc9Smrg continue; 4001fe517fc9Smrg 4002fe517fc9Smrg snprintf(node, PATH_MAX, "%s/%s", DRM_DIR_NAME, dent->d_name); 4003fe517fc9Smrg if (stat(node, &sbuf)) 4004fe517fc9Smrg continue; 4005fe517fc9Smrg 4006fe517fc9Smrg maj = major(sbuf.st_rdev); 4007fe517fc9Smrg min = minor(sbuf.st_rdev); 4008fe517fc9Smrg 4009fe517fc9Smrg if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode)) 4010fe517fc9Smrg continue; 4011fe517fc9Smrg 4012fe517fc9Smrg subsystem_type = drmParseSubsystemType(maj, min); 4013fe517fc9Smrg 4014fe517fc9Smrg if (subsystem_type < 0) 4015fe517fc9Smrg continue; 4016fe517fc9Smrg 4017fe517fc9Smrg switch (subsystem_type) { 4018fe517fc9Smrg case DRM_BUS_PCI: 40192ee35494Smrg ret = drmProcessPciDevice(&device, node, node_type, 40202ee35494Smrg maj, min, devices != NULL, flags); 40212ee35494Smrg if (ret) 40222ee35494Smrg continue; 40232ee35494Smrg 40242ee35494Smrg break; 40252ee35494Smrg 40262ee35494Smrg case DRM_BUS_USB: 40272ee35494Smrg ret = drmProcessUsbDevice(&device, node, node_type, maj, min, 40282ee35494Smrg devices != NULL, flags); 4029fe517fc9Smrg if (ret) 40300655efefSmrg continue; 4031fe517fc9Smrg 4032fe517fc9Smrg break; 40332ee35494Smrg 40342ee35494Smrg case DRM_BUS_PLATFORM: 40352ee35494Smrg ret = drmProcessPlatformDevice(&device, node, node_type, maj, min, 40362ee35494Smrg devices != NULL, flags); 40372ee35494Smrg if (ret) 40380655efefSmrg continue; 40392ee35494Smrg 40402ee35494Smrg break; 40412ee35494Smrg 40422ee35494Smrg case DRM_BUS_HOST1X: 40432ee35494Smrg ret = drmProcessHost1xDevice(&device, node, node_type, maj, min, 40442ee35494Smrg devices != NULL, flags); 40452ee35494Smrg if (ret) 40460655efefSmrg continue; 40472ee35494Smrg 40482ee35494Smrg break; 40492ee35494Smrg 4050fe517fc9Smrg default: 4051fe517fc9Smrg continue; 4052fe517fc9Smrg } 4053fe517fc9Smrg 4054fe517fc9Smrg if (i >= max_count) { 4055fe517fc9Smrg drmDevicePtr *temp; 4056fe517fc9Smrg 4057fe517fc9Smrg max_count += 16; 4058fe517fc9Smrg temp = realloc(local_devices, max_count * sizeof(drmDevicePtr)); 4059fe517fc9Smrg if (!temp) 4060fe517fc9Smrg goto free_devices; 4061fe517fc9Smrg local_devices = temp; 4062fe517fc9Smrg } 4063fe517fc9Smrg 4064fe517fc9Smrg local_devices[i] = device; 4065fe517fc9Smrg i++; 4066fe517fc9Smrg } 4067fe517fc9Smrg node_count = i; 4068fe517fc9Smrg 4069fe517fc9Smrg drmFoldDuplicatedDevices(local_devices, node_count); 4070fe517fc9Smrg 4071fe517fc9Smrg device_count = 0; 4072fe517fc9Smrg for (i = 0; i < node_count; i++) { 4073fe517fc9Smrg if (!local_devices[i]) 4074fe517fc9Smrg continue; 4075fe517fc9Smrg 4076fe517fc9Smrg if ((devices != NULL) && (device_count < max_devices)) 4077fe517fc9Smrg devices[device_count] = local_devices[i]; 4078fe517fc9Smrg else 4079fe517fc9Smrg drmFreeDevice(&local_devices[i]); 4080fe517fc9Smrg 4081fe517fc9Smrg device_count++; 4082fe517fc9Smrg } 4083fe517fc9Smrg 4084fe517fc9Smrg closedir(sysdir); 4085fe517fc9Smrg free(local_devices); 4086fe517fc9Smrg return device_count; 4087fe517fc9Smrg 4088fe517fc9Smrgfree_devices: 4089fe517fc9Smrg drmFreeDevices(local_devices, i); 4090fe517fc9Smrg closedir(sysdir); 4091fe517fc9Smrg 4092fe517fc9Smrgfree_locals: 4093fe517fc9Smrg free(local_devices); 4094fe517fc9Smrg return ret; 4095424e9256Smrg} 40962ee35494Smrg 40972ee35494Smrg/** 40982ee35494Smrg * Get drm devices on the system 40992ee35494Smrg * 41002ee35494Smrg * \param devices the array of devices with drmDevicePtr elements 41012ee35494Smrg * can be NULL to get the device number first 41022ee35494Smrg * \param max_devices the maximum number of devices for the array 41032ee35494Smrg * 41042ee35494Smrg * \return on error - negative error code, 41052ee35494Smrg * if devices is NULL - total number of devices available on the system, 41062ee35494Smrg * alternatively the number of devices stored in devices[], which is 41072ee35494Smrg * capped by the max_devices. 41082ee35494Smrg */ 41092ee35494Smrgint drmGetDevices(drmDevicePtr devices[], int max_devices) 41102ee35494Smrg{ 41112ee35494Smrg return drmGetDevices2(DRM_DEVICE_GET_PCI_REVISION, devices, max_devices); 41122ee35494Smrg} 41132ee35494Smrg 41142ee35494Smrgchar *drmGetDeviceNameFromFd2(int fd) 41152ee35494Smrg{ 41162ee35494Smrg#ifdef __linux__ 41172ee35494Smrg struct stat sbuf; 41182ee35494Smrg char path[PATH_MAX + 1], *value; 41192ee35494Smrg unsigned int maj, min; 41202ee35494Smrg 41212ee35494Smrg if (fstat(fd, &sbuf)) 41222ee35494Smrg return NULL; 41232ee35494Smrg 41242ee35494Smrg maj = major(sbuf.st_rdev); 41252ee35494Smrg min = minor(sbuf.st_rdev); 41262ee35494Smrg 41272ee35494Smrg if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode)) 41282ee35494Smrg return NULL; 41292ee35494Smrg 41302ee35494Smrg snprintf(path, sizeof(path), "/sys/dev/char/%d:%d", maj, min); 41312ee35494Smrg 41322ee35494Smrg value = sysfs_uevent_get(path, "DEVNAME"); 41332ee35494Smrg if (!value) 41342ee35494Smrg return NULL; 41352ee35494Smrg 41362ee35494Smrg snprintf(path, sizeof(path), "/dev/%s", value); 41372ee35494Smrg free(value); 41382ee35494Smrg 41392ee35494Smrg return strdup(path); 41402ee35494Smrg#else 41412ee35494Smrg struct stat sbuf; 41422ee35494Smrg char node[PATH_MAX + 1]; 41432ee35494Smrg const char *dev_name; 41442ee35494Smrg int node_type; 41452ee35494Smrg int maj, min, n, base; 41462ee35494Smrg 41472ee35494Smrg if (fstat(fd, &sbuf)) 41482ee35494Smrg return NULL; 41492ee35494Smrg 41502ee35494Smrg maj = major(sbuf.st_rdev); 41512ee35494Smrg min = minor(sbuf.st_rdev); 41522ee35494Smrg 41532ee35494Smrg if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode)) 41542ee35494Smrg return NULL; 41552ee35494Smrg 41562ee35494Smrg node_type = drmGetMinorType(min); 41572ee35494Smrg if (node_type == -1) 41582ee35494Smrg return NULL; 41592ee35494Smrg 41602ee35494Smrg switch (node_type) { 41612ee35494Smrg case DRM_NODE_PRIMARY: 41622ee35494Smrg dev_name = DRM_DEV_NAME; 41632ee35494Smrg break; 41642ee35494Smrg case DRM_NODE_CONTROL: 41652ee35494Smrg dev_name = DRM_CONTROL_DEV_NAME; 41662ee35494Smrg break; 41672ee35494Smrg case DRM_NODE_RENDER: 41682ee35494Smrg dev_name = DRM_RENDER_DEV_NAME; 41692ee35494Smrg break; 41702ee35494Smrg default: 41712ee35494Smrg return NULL; 41722ee35494Smrg }; 41732ee35494Smrg 41742ee35494Smrg base = drmGetMinorBase(node_type); 41752ee35494Smrg if (base < 0) 41762ee35494Smrg return NULL; 41772ee35494Smrg 41782ee35494Smrg n = snprintf(node, PATH_MAX, dev_name, DRM_DIR_NAME, min - base); 41792ee35494Smrg if (n == -1 || n >= PATH_MAX) 41802ee35494Smrg return NULL; 41812ee35494Smrg 41822ee35494Smrg return strdup(node); 41832ee35494Smrg#endif 41842ee35494Smrg} 41850655efefSmrg 41860655efefSmrgint drmSyncobjCreate(int fd, uint32_t flags, uint32_t *handle) 41870655efefSmrg{ 41880655efefSmrg struct drm_syncobj_create args; 41890655efefSmrg int ret; 41900655efefSmrg 41910655efefSmrg memclear(args); 41920655efefSmrg args.flags = flags; 41930655efefSmrg args.handle = 0; 41940655efefSmrg ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_CREATE, &args); 41950655efefSmrg if (ret) 41962b90624aSmrg return ret; 41970655efefSmrg *handle = args.handle; 41980655efefSmrg return 0; 41990655efefSmrg} 42000655efefSmrg 42010655efefSmrgint drmSyncobjDestroy(int fd, uint32_t handle) 42020655efefSmrg{ 42030655efefSmrg struct drm_syncobj_destroy args; 42040655efefSmrg 42050655efefSmrg memclear(args); 42060655efefSmrg args.handle = handle; 42070655efefSmrg return drmIoctl(fd, DRM_IOCTL_SYNCOBJ_DESTROY, &args); 42080655efefSmrg} 42090655efefSmrg 42100655efefSmrgint drmSyncobjHandleToFD(int fd, uint32_t handle, int *obj_fd) 42110655efefSmrg{ 42120655efefSmrg struct drm_syncobj_handle args; 42130655efefSmrg int ret; 42140655efefSmrg 42150655efefSmrg memclear(args); 42160655efefSmrg args.fd = -1; 42170655efefSmrg args.handle = handle; 42180655efefSmrg ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD, &args); 42190655efefSmrg if (ret) 42202b90624aSmrg return ret; 42210655efefSmrg *obj_fd = args.fd; 42220655efefSmrg return 0; 42230655efefSmrg} 42240655efefSmrg 42250655efefSmrgint drmSyncobjFDToHandle(int fd, int obj_fd, uint32_t *handle) 42260655efefSmrg{ 42270655efefSmrg struct drm_syncobj_handle args; 42280655efefSmrg int ret; 42290655efefSmrg 42300655efefSmrg memclear(args); 42310655efefSmrg args.fd = obj_fd; 42320655efefSmrg args.handle = 0; 42330655efefSmrg ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE, &args); 42340655efefSmrg if (ret) 42352b90624aSmrg return ret; 42360655efefSmrg *handle = args.handle; 42370655efefSmrg return 0; 42380655efefSmrg} 42390655efefSmrg 42400655efefSmrgint drmSyncobjImportSyncFile(int fd, uint32_t handle, int sync_file_fd) 42410655efefSmrg{ 42420655efefSmrg struct drm_syncobj_handle args; 42430655efefSmrg 42440655efefSmrg memclear(args); 42450655efefSmrg args.fd = sync_file_fd; 42460655efefSmrg args.handle = handle; 42470655efefSmrg args.flags = DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_IMPORT_SYNC_FILE; 42480655efefSmrg return drmIoctl(fd, DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE, &args); 42490655efefSmrg} 42500655efefSmrg 42510655efefSmrgint drmSyncobjExportSyncFile(int fd, uint32_t handle, int *sync_file_fd) 42520655efefSmrg{ 42530655efefSmrg struct drm_syncobj_handle args; 42540655efefSmrg int ret; 42550655efefSmrg 42560655efefSmrg memclear(args); 42570655efefSmrg args.fd = -1; 42580655efefSmrg args.handle = handle; 42590655efefSmrg args.flags = DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_EXPORT_SYNC_FILE; 42600655efefSmrg ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD, &args); 42610655efefSmrg if (ret) 42622b90624aSmrg return ret; 42630655efefSmrg *sync_file_fd = args.fd; 42640655efefSmrg return 0; 42650655efefSmrg} 42662b90624aSmrg 42672b90624aSmrgint drmSyncobjWait(int fd, uint32_t *handles, unsigned num_handles, 42682b90624aSmrg int64_t timeout_nsec, unsigned flags, 42692b90624aSmrg uint32_t *first_signaled) 42702b90624aSmrg{ 42712b90624aSmrg struct drm_syncobj_wait args; 42722b90624aSmrg int ret; 42732b90624aSmrg 42742b90624aSmrg memclear(args); 42752b90624aSmrg args.handles = (uintptr_t)handles; 42762b90624aSmrg args.timeout_nsec = timeout_nsec; 42772b90624aSmrg args.count_handles = num_handles; 42782b90624aSmrg args.flags = flags; 42792b90624aSmrg 42802b90624aSmrg ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_WAIT, &args); 42812b90624aSmrg if (ret < 0) 42822b90624aSmrg return -errno; 42832b90624aSmrg 42842b90624aSmrg if (first_signaled) 42852b90624aSmrg *first_signaled = args.first_signaled; 42862b90624aSmrg return ret; 42872b90624aSmrg} 42882b90624aSmrg 42892b90624aSmrgint drmSyncobjReset(int fd, const uint32_t *handles, uint32_t handle_count) 42902b90624aSmrg{ 42912b90624aSmrg struct drm_syncobj_array args; 42922b90624aSmrg int ret; 42932b90624aSmrg 42942b90624aSmrg memclear(args); 42952b90624aSmrg args.handles = (uintptr_t)handles; 42962b90624aSmrg args.count_handles = handle_count; 42972b90624aSmrg 42982b90624aSmrg ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_RESET, &args); 42992b90624aSmrg return ret; 43002b90624aSmrg} 43012b90624aSmrg 43022b90624aSmrgint drmSyncobjSignal(int fd, const uint32_t *handles, uint32_t handle_count) 43032b90624aSmrg{ 43042b90624aSmrg struct drm_syncobj_array args; 43052b90624aSmrg int ret; 43062b90624aSmrg 43072b90624aSmrg memclear(args); 43082b90624aSmrg args.handles = (uintptr_t)handles; 43092b90624aSmrg args.count_handles = handle_count; 43102b90624aSmrg 43112b90624aSmrg ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_SIGNAL, &args); 43122b90624aSmrg return ret; 43132b90624aSmrg} 4314