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