blob: c4a2b424599da85278d2284c9727c2aa37cfa1a0 [file] [log] [blame]
Jose Fonsecad2443b22003-05-27 00:37:33 +00001/**
Jan Vesely50d3c852016-06-30 14:22:52 -04002 * \file xf86drm.c
Jose Fonsecad2443b22003-05-27 00:37:33 +00003 * User-level interface to DRM device
Daryll Straussb3a57661999-12-05 01:19:48 +00004 *
Jose Fonsecad2443b22003-05-27 00:37:33 +00005 * \author Rickard E. (Rik) Faith <faith@valinux.com>
6 * \author Kevin E. Martin <martin@valinux.com>
7 */
8
9/*
Brian Paul569da5a2000-06-08 14:38:22 +000010 * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
11 * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
Daryll Straussb3a57661999-12-05 01:19:48 +000012 * All Rights Reserved.
13 *
14 * Permission is hereby granted, free of charge, to any person obtaining a
15 * copy of this software and associated documentation files (the "Software"),
16 * to deal in the Software without restriction, including without limitation
17 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
18 * and/or sell copies of the Software, and to permit persons to whom the
19 * Software is furnished to do so, subject to the following conditions:
Gareth Hughes36047532001-02-15 08:12:14 +000020 *
Daryll Straussb3a57661999-12-05 01:19:48 +000021 * The above copyright notice and this permission notice (including the next
22 * paragraph) shall be included in all copies or substantial portions of the
23 * Software.
Gareth Hughes36047532001-02-15 08:12:14 +000024 *
Daryll Straussb3a57661999-12-05 01:19:48 +000025 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
28 * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
29 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
30 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
31 * DEALINGS IN THE SOFTWARE.
Daryll Straussb3a57661999-12-05 01:19:48 +000032 */
33
Dave Airlie79038752006-11-08 15:08:09 +110034#include <stdio.h>
35#include <stdlib.h>
Emil Velikovfae59d72015-09-09 17:54:34 +010036#include <stdbool.h>
Dave Airlie79038752006-11-08 15:08:09 +110037#include <unistd.h>
38#include <string.h>
Ian Romanick015efd12009-07-06 09:23:59 -070039#include <strings.h>
Dave Airlie79038752006-11-08 15:08:09 +110040#include <ctype.h>
Emil Velikov0ca03a42015-03-07 00:58:39 +000041#include <dirent.h>
42#include <stddef.h>
Dave Airlie79038752006-11-08 15:08:09 +110043#include <fcntl.h>
44#include <errno.h>
Felix Janda4031dc12015-09-26 08:08:43 +020045#include <limits.h>
Dave Airlie79038752006-11-08 15:08:09 +110046#include <signal.h>
Jesse Barnesf4f76a62009-01-07 10:18:08 -080047#include <time.h>
Dave Airlie79038752006-11-08 15:08:09 +110048#include <sys/types.h>
49#include <sys/stat.h>
50#define stat_t struct stat
51#include <sys/ioctl.h>
Dave Airlie79038752006-11-08 15:08:09 +110052#include <sys/time.h>
53#include <stdarg.h>
Mike Frysinger8c8d5dd2016-06-21 12:18:15 -040054#ifdef MAJOR_IN_MKDEV
55#include <sys/mkdev.h>
56#endif
57#ifdef MAJOR_IN_SYSMACROS
58#include <sys/sysmacros.h>
Alan Coopersmith0e1135d2015-03-07 11:44:32 -080059#endif
Emil Velikovb556ea12015-08-17 11:09:06 +080060#include <math.h>
Daryll Straussb3a57661999-12-05 01:19:48 +000061
Eric Anholt9b28c5a2018-11-15 17:48:53 -080062#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
63
Daryll Straussb3a57661999-12-05 01:19:48 +000064/* Not all systems have MAP_FAILED defined */
65#ifndef MAP_FAILED
66#define MAP_FAILED ((void *)-1)
67#endif
68
Daryll Straussb3a57661999-12-05 01:19:48 +000069#include "xf86drm.h"
Emil Velikov42465fe2015-04-05 15:51:59 +010070#include "libdrm_macros.h"
Daryll Straussb3a57661999-12-05 01:19:48 +000071
Emil Velikov5f68d312015-09-07 13:54:32 +010072#include "util_math.h"
73
Jonathan Grayfc083322015-07-21 03:12:56 +100074#ifdef __OpenBSD__
Jan Vesely50d3c852016-06-30 14:22:52 -040075#define DRM_PRIMARY_MINOR_NAME "drm"
76#define DRM_CONTROL_MINOR_NAME "drmC"
77#define DRM_RENDER_MINOR_NAME "drmR"
Jonathan Grayfc083322015-07-21 03:12:56 +100078#else
Jan Vesely50d3c852016-06-30 14:22:52 -040079#define DRM_PRIMARY_MINOR_NAME "card"
80#define DRM_CONTROL_MINOR_NAME "controlD"
81#define DRM_RENDER_MINOR_NAME "renderD"
Jonathan Grayfc083322015-07-21 03:12:56 +100082#endif
83
Hasso Tepper27c37852008-04-07 15:27:43 +030084#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
Eric Anholtcfa778a2003-02-21 23:23:09 +000085#define DRM_MAJOR 145
Rik Faith88dbee52001-02-28 09:27:44 +000086#endif
87
Eric Anholtcfa778a2003-02-21 23:23:09 +000088#ifdef __NetBSD__
89#define DRM_MAJOR 34
90#endif
91
Jonathan Gray66c3afb2015-07-21 03:12:10 +100092#ifdef __OpenBSD__
93#ifdef __i386__
94#define DRM_MAJOR 88
95#else
96#define DRM_MAJOR 87
97#endif
98#endif /* __OpenBSD__ */
Alan Hourihaneb0a92852003-09-24 14:39:25 +000099
Eric Anholtcfa778a2003-02-21 23:23:09 +0000100#ifndef DRM_MAJOR
Jan Vesely50d3c852016-06-30 14:22:52 -0400101#define DRM_MAJOR 226 /* Linux */
Rik Faith88dbee52001-02-28 09:27:44 +0000102#endif
103
François Tigeot8f2e0922018-12-12 20:48:36 +0100104#if defined(__OpenBSD__) || defined(__DragonFly__)
Jonathan Grayc0ef1d02016-12-01 15:18:41 +1100105struct drm_pciinfo {
106 uint16_t domain;
107 uint8_t bus;
108 uint8_t dev;
109 uint8_t func;
110 uint16_t vendor_id;
111 uint16_t device_id;
112 uint16_t subvendor_id;
113 uint16_t subdevice_id;
114 uint8_t revision_id;
115};
116
117#define DRM_IOCTL_GET_PCIINFO DRM_IOR(0x15, struct drm_pciinfo)
118#endif
119
David Dawes56bd9c22001-07-30 19:59:39 +0000120#define DRM_MSG_VERBOSITY 3
121
Daniel Vetterfd387942015-02-11 12:41:04 +0100122#define memclear(s) memset(&s, 0, sizeof(s))
123
Dave Airlie79038752006-11-08 15:08:09 +1100124static drmServerInfoPtr drm_server_info;
125
Lucas De Marchi26f9ce52018-09-13 15:42:26 -0700126drm_public void drmSetServerInfo(drmServerInfoPtr info)
Dave Airlie79038752006-11-08 15:08:09 +1100127{
Brianccd7b6e2007-05-29 14:54:00 -0600128 drm_server_info = info;
Dave Airlie79038752006-11-08 15:08:09 +1100129}
130
Jose Fonsecad2443b22003-05-27 00:37:33 +0000131/**
132 * Output a message to stderr.
133 *
134 * \param format printf() like format string.
135 *
136 * \internal
137 * This function is a wrapper around vfprintf().
138 */
Dave Airlie79038752006-11-08 15:08:09 +1100139
Thierry Reding44b08c02014-01-22 12:06:51 +0100140static int DRM_PRINTFLIKE(1, 0)
141drmDebugPrint(const char *format, va_list ap)
Dave Airlie79038752006-11-08 15:08:09 +1100142{
Brianccd7b6e2007-05-29 14:54:00 -0600143 return vfprintf(stderr, format, ap);
Dave Airlie79038752006-11-08 15:08:09 +1100144}
145
Lucas De Marchi26f9ce52018-09-13 15:42:26 -0700146drm_public void
David Dawes56bd9c22001-07-30 19:59:39 +0000147drmMsg(const char *format, ...)
148{
Jan Vesely50d3c852016-06-30 14:22:52 -0400149 va_list ap;
David Dawes56bd9c22001-07-30 19:59:39 +0000150 const char *env;
Rob Clarkeb7c2d52015-09-04 08:08:02 -0400151 if (((env = getenv("LIBGL_DEBUG")) && strstr(env, "verbose")) ||
152 (drm_server_info && drm_server_info->debug_print))
David Dawes56bd9c22001-07-30 19:59:39 +0000153 {
Jan Vesely50d3c852016-06-30 14:22:52 -0400154 va_start(ap, format);
155 if (drm_server_info) {
156 drm_server_info->debug_print(format,ap);
157 } else {
158 drmDebugPrint(format, ap);
159 }
160 va_end(ap);
David Dawes56bd9c22001-07-30 19:59:39 +0000161 }
162}
163
Daryll Straussb3a57661999-12-05 01:19:48 +0000164static void *drmHashTable = NULL; /* Context switch callbacks */
165
Lucas De Marchi26f9ce52018-09-13 15:42:26 -0700166drm_public void *drmGetHashTable(void)
Dave Airlie79038752006-11-08 15:08:09 +1100167{
Brianccd7b6e2007-05-29 14:54:00 -0600168 return drmHashTable;
Dave Airlie79038752006-11-08 15:08:09 +1100169}
Daryll Straussb3a57661999-12-05 01:19:48 +0000170
Lucas De Marchi26f9ce52018-09-13 15:42:26 -0700171drm_public void *drmMalloc(int size)
Daryll Straussb3a57661999-12-05 01:19:48 +0000172{
Emil Velikovd0e592d2015-04-28 13:33:46 +0100173 return calloc(1, size);
Daryll Straussb3a57661999-12-05 01:19:48 +0000174}
175
Lucas De Marchi26f9ce52018-09-13 15:42:26 -0700176drm_public void drmFree(void *pt)
Daryll Straussb3a57661999-12-05 01:19:48 +0000177{
Emil Velikovd0e592d2015-04-28 13:33:46 +0100178 free(pt);
Daryll Straussb3a57661999-12-05 01:19:48 +0000179}
180
Keith Packard8b9ab102008-06-13 16:03:22 -0700181/**
182 * Call ioctl, restarting if it is interupted
183 */
Lucas De Marchi26f9ce52018-09-13 15:42:26 -0700184drm_public int
Coleman Kane41b83a92008-08-18 17:08:21 -0400185drmIoctl(int fd, unsigned long request, void *arg)
Keith Packard8b9ab102008-06-13 16:03:22 -0700186{
Jan Vesely50d3c852016-06-30 14:22:52 -0400187 int ret;
Keith Packard8b9ab102008-06-13 16:03:22 -0700188
189 do {
Jan Vesely50d3c852016-06-30 14:22:52 -0400190 ret = ioctl(fd, request, arg);
Keith Packard8b9ab102008-06-13 16:03:22 -0700191 } while (ret == -1 && (errno == EINTR || errno == EAGAIN));
192 return ret;
193}
Daryll Straussb3a57661999-12-05 01:19:48 +0000194
Daryll Straussb3a57661999-12-05 01:19:48 +0000195static unsigned long drmGetKeyFromFd(int fd)
196{
David Dawesfcc21062001-03-30 17:16:20 +0000197 stat_t st;
Daryll Straussb3a57661999-12-05 01:19:48 +0000198
199 st.st_rdev = 0;
200 fstat(fd, &st);
201 return st.st_rdev;
202}
203
Lucas De Marchi26f9ce52018-09-13 15:42:26 -0700204drm_public drmHashEntry *drmGetEntry(int fd)
Daryll Straussb3a57661999-12-05 01:19:48 +0000205{
206 unsigned long key = drmGetKeyFromFd(fd);
207 void *value;
208 drmHashEntry *entry;
209
Brianccd7b6e2007-05-29 14:54:00 -0600210 if (!drmHashTable)
Jan Vesely50d3c852016-06-30 14:22:52 -0400211 drmHashTable = drmHashCreate();
Daryll Straussb3a57661999-12-05 01:19:48 +0000212
213 if (drmHashLookup(drmHashTable, key, &value)) {
Jan Vesely50d3c852016-06-30 14:22:52 -0400214 entry = drmMalloc(sizeof(*entry));
215 entry->fd = fd;
216 entry->f = NULL;
217 entry->tagTable = drmHashCreate();
218 drmHashInsert(drmHashTable, key, entry);
Daryll Straussb3a57661999-12-05 01:19:48 +0000219 } else {
Jan Vesely50d3c852016-06-30 14:22:52 -0400220 entry = value;
Daryll Straussb3a57661999-12-05 01:19:48 +0000221 }
222 return entry;
223}
224
Jose Fonsecad2443b22003-05-27 00:37:33 +0000225/**
Eric Anholt06cb1322003-10-23 02:23:31 +0000226 * Compare two busid strings
227 *
228 * \param first
229 * \param second
230 *
231 * \return 1 if matched.
232 *
233 * \internal
234 * This function compares two bus ID strings. It understands the older
235 * PCI:b:d:f format and the newer pci:oooo:bb:dd.f format. In the format, o is
236 * domain, b is bus, d is device, f is function.
237 */
Benjamin Herrenschmidtb04515c2010-08-06 13:55:11 +1000238static int drmMatchBusID(const char *id1, const char *id2, int pci_domain_ok)
Eric Anholt06cb1322003-10-23 02:23:31 +0000239{
240 /* First, check if the IDs are exactly the same */
241 if (strcasecmp(id1, id2) == 0)
Jan Vesely50d3c852016-06-30 14:22:52 -0400242 return 1;
Eric Anholt06cb1322003-10-23 02:23:31 +0000243
244 /* Try to match old/new-style PCI bus IDs. */
245 if (strncasecmp(id1, "pci", 3) == 0) {
Jan Vesely50d3c852016-06-30 14:22:52 -0400246 unsigned int o1, b1, d1, f1;
247 unsigned int o2, b2, d2, f2;
248 int ret;
Eric Anholt06cb1322003-10-23 02:23:31 +0000249
Jan Vesely50d3c852016-06-30 14:22:52 -0400250 ret = sscanf(id1, "pci:%04x:%02x:%02x.%u", &o1, &b1, &d1, &f1);
251 if (ret != 4) {
252 o1 = 0;
253 ret = sscanf(id1, "PCI:%u:%u:%u", &b1, &d1, &f1);
254 if (ret != 3)
255 return 0;
256 }
Eric Anholt06cb1322003-10-23 02:23:31 +0000257
Jan Vesely50d3c852016-06-30 14:22:52 -0400258 ret = sscanf(id2, "pci:%04x:%02x:%02x.%u", &o2, &b2, &d2, &f2);
259 if (ret != 4) {
260 o2 = 0;
261 ret = sscanf(id2, "PCI:%u:%u:%u", &b2, &d2, &f2);
262 if (ret != 3)
263 return 0;
264 }
Eric Anholt06cb1322003-10-23 02:23:31 +0000265
Jan Vesely50d3c852016-06-30 14:22:52 -0400266 /* If domains aren't properly supported by the kernel interface,
267 * just ignore them, which sucks less than picking a totally random
268 * card with "open by name"
269 */
270 if (!pci_domain_ok)
271 o1 = o2 = 0;
Benjamin Herrenschmidtb04515c2010-08-06 13:55:11 +1000272
Jan Vesely50d3c852016-06-30 14:22:52 -0400273 if ((o1 != o2) || (b1 != b2) || (d1 != d2) || (f1 != f2))
274 return 0;
275 else
276 return 1;
Eric Anholt06cb1322003-10-23 02:23:31 +0000277 }
278 return 0;
279}
280
281/**
Pauli Nieminenc5a5bbb2009-07-06 23:37:20 +0300282 * Handles error checking for chown call.
283 *
284 * \param path to file.
285 * \param id of the new owner.
286 * \param id of the new group.
287 *
288 * \return zero if success or -1 if failure.
289 *
290 * \internal
291 * Checks for failure. If failure was caused by signal call chown again.
292 * If any other failure happened then it will output error mesage using
293 * drmMsg() call.
294 */
Eric Engestrom07585202018-03-16 17:04:50 +0000295#if !UDEV
Pauli Nieminenc5a5bbb2009-07-06 23:37:20 +0300296static int chown_check_return(const char *path, uid_t owner, gid_t group)
297{
Jan Vesely50d3c852016-06-30 14:22:52 -0400298 int rv;
Pauli Nieminenc5a5bbb2009-07-06 23:37:20 +0300299
Jan Vesely50d3c852016-06-30 14:22:52 -0400300 do {
301 rv = chown(path, owner, group);
302 } while (rv != 0 && errno == EINTR);
Pauli Nieminenc5a5bbb2009-07-06 23:37:20 +0300303
Jan Vesely50d3c852016-06-30 14:22:52 -0400304 if (rv == 0)
305 return 0;
Pauli Nieminenc5a5bbb2009-07-06 23:37:20 +0300306
Jan Vesely50d3c852016-06-30 14:22:52 -0400307 drmMsg("Failed to change owner or group for file %s! %d: %s\n",
308 path, errno, strerror(errno));
309 return -1;
Pauli Nieminenc5a5bbb2009-07-06 23:37:20 +0300310}
Jan Vesely6fc0e4b2015-02-27 12:54:34 -0500311#endif
Pauli Nieminenc5a5bbb2009-07-06 23:37:20 +0300312
313/**
Jose Fonsecad2443b22003-05-27 00:37:33 +0000314 * Open the DRM device, creating it if necessary.
315 *
316 * \param dev major and minor numbers of the device.
317 * \param minor minor number of the device.
Jan Vesely50d3c852016-06-30 14:22:52 -0400318 *
Jose Fonsecad2443b22003-05-27 00:37:33 +0000319 * \return a file descriptor on success, or a negative value on error.
320 *
321 * \internal
322 * Assembles the device name from \p minor and opens it, creating the device
323 * special file node with the major and minor numbers specified by \p dev and
324 * parent directory if necessary and was called by root.
325 */
Jan Veselyde8532d2014-11-30 12:53:18 -0500326static int drmOpenDevice(dev_t dev, int minor, int type)
Daryll Straussb3a57661999-12-05 01:19:48 +0000327{
David Dawes9c775d02001-05-14 14:49:58 +0000328 stat_t st;
Frank Binns0c5aaee2015-01-14 14:07:51 +0000329 const char *dev_name;
Rik Faith88dbee52001-02-28 09:27:44 +0000330 char buf[64];
331 int fd;
Dave Airlie79038752006-11-08 15:08:09 +1100332 mode_t devmode = DRM_DEV_MODE, serv_mode;
Jan Vesely0706c142015-02-27 12:47:46 -0500333 gid_t serv_group;
Eric Engestrom07585202018-03-16 17:04:50 +0000334#if !UDEV
Rik Faith88dbee52001-02-28 09:27:44 +0000335 int isroot = !geteuid();
Rik Faith88dbee52001-02-28 09:27:44 +0000336 uid_t user = DRM_DEV_UID;
Jan Vesely0706c142015-02-27 12:47:46 -0500337 gid_t group = DRM_DEV_GID;
338#endif
339
Frank Binns0c5aaee2015-01-14 14:07:51 +0000340 switch (type) {
341 case DRM_NODE_PRIMARY:
Jan Vesely50d3c852016-06-30 14:22:52 -0400342 dev_name = DRM_DEV_NAME;
343 break;
Frank Binns0c5aaee2015-01-14 14:07:51 +0000344 case DRM_NODE_CONTROL:
Jan Vesely50d3c852016-06-30 14:22:52 -0400345 dev_name = DRM_CONTROL_DEV_NAME;
346 break;
Frank Binns0c5aaee2015-01-14 14:07:51 +0000347 case DRM_NODE_RENDER:
Jan Vesely50d3c852016-06-30 14:22:52 -0400348 dev_name = DRM_RENDER_DEV_NAME;
349 break;
Frank Binns0c5aaee2015-01-14 14:07:51 +0000350 default:
Jan Vesely50d3c852016-06-30 14:22:52 -0400351 return -EINVAL;
Frank Binns0c5aaee2015-01-14 14:07:51 +0000352 };
353
354 sprintf(buf, dev_name, DRM_DIR_NAME, minor);
Eric Anholt06cb1322003-10-23 02:23:31 +0000355 drmMsg("drmOpenDevice: node name is %s\n", buf);
David Dawes56bd9c22001-07-30 19:59:39 +0000356
Rob Clarkeb7c2d52015-09-04 08:08:02 -0400357 if (drm_server_info && drm_server_info->get_perms) {
Jan Vesely50d3c852016-06-30 14:22:52 -0400358 drm_server_info->get_perms(&serv_group, &serv_mode);
359 devmode = serv_mode ? serv_mode : DRM_DEV_MODE;
360 devmode &= ~(S_IXUSR|S_IXGRP|S_IXOTH);
Dave Airlie79038752006-11-08 15:08:09 +1100361 }
Brian Paul569da5a2000-06-08 14:38:22 +0000362
Eric Engestrom07585202018-03-16 17:04:50 +0000363#if !UDEV
Rik Faith88dbee52001-02-28 09:27:44 +0000364 if (stat(DRM_DIR_NAME, &st)) {
Jan Vesely50d3c852016-06-30 14:22:52 -0400365 if (!isroot)
366 return DRM_ERR_NOT_ROOT;
367 mkdir(DRM_DIR_NAME, DRM_DEV_DIRMODE);
368 chown_check_return(DRM_DIR_NAME, 0, 0); /* root:root */
369 chmod(DRM_DIR_NAME, DRM_DEV_DIRMODE);
Brian Paul569da5a2000-06-08 14:38:22 +0000370 }
Daryll Straussb3a57661999-12-05 01:19:48 +0000371
Eric Anholt06cb1322003-10-23 02:23:31 +0000372 /* Check if the device node exists and create it if necessary. */
Eric Anholtd2f2b422002-08-08 21:23:46 +0000373 if (stat(buf, &st)) {
Jan Vesely50d3c852016-06-30 14:22:52 -0400374 if (!isroot)
375 return DRM_ERR_NOT_ROOT;
376 remove(buf);
377 mknod(buf, S_IFCHR | devmode, dev);
Daryll Straussb3a57661999-12-05 01:19:48 +0000378 }
Dave Airlie79038752006-11-08 15:08:09 +1100379
Rob Clarkeb7c2d52015-09-04 08:08:02 -0400380 if (drm_server_info && drm_server_info->get_perms) {
Jan Vesely50d3c852016-06-30 14:22:52 -0400381 group = ((int)serv_group >= 0) ? serv_group : DRM_DEV_GID;
382 chown_check_return(buf, user, group);
383 chmod(buf, devmode);
Dave Airlie79038752006-11-08 15:08:09 +1100384 }
Dave Airlie9101a022008-08-24 16:54:43 +1000385#else
386 /* if we modprobed then wait for udev */
387 {
Jan Vesely50d3c852016-06-30 14:22:52 -0400388 int udev_count = 0;
Dave Airlie9101a022008-08-24 16:54:43 +1000389wait_for_udev:
390 if (stat(DRM_DIR_NAME, &st)) {
Jan Vesely50d3c852016-06-30 14:22:52 -0400391 usleep(20);
392 udev_count++;
Dave Airlie9101a022008-08-24 16:54:43 +1000393
Jan Vesely50d3c852016-06-30 14:22:52 -0400394 if (udev_count == 50)
395 return -1;
396 goto wait_for_udev;
397 }
Dave Airlie9101a022008-08-24 16:54:43 +1000398
Jan Vesely50d3c852016-06-30 14:22:52 -0400399 if (stat(buf, &st)) {
400 usleep(20);
401 udev_count++;
Dave Airlie9101a022008-08-24 16:54:43 +1000402
Jan Vesely50d3c852016-06-30 14:22:52 -0400403 if (udev_count == 50)
404 return -1;
405 goto wait_for_udev;
406 }
Dave Airlie9101a022008-08-24 16:54:43 +1000407 }
408#endif
Rik Faith88dbee52001-02-28 09:27:44 +0000409
Michel Dänzer35615692018-05-18 11:16:51 +0200410 fd = open(buf, O_RDWR | O_CLOEXEC, 0);
David Dawes56bd9c22001-07-30 19:59:39 +0000411 drmMsg("drmOpenDevice: open result is %d, (%s)\n",
Jan Vesely50d3c852016-06-30 14:22:52 -0400412 fd, fd < 0 ? strerror(errno) : "OK");
Brianccd7b6e2007-05-29 14:54:00 -0600413 if (fd >= 0)
Jan Vesely50d3c852016-06-30 14:22:52 -0400414 return fd;
Eric Anholtd2f2b422002-08-08 21:23:46 +0000415
Eric Engestrom07585202018-03-16 17:04:50 +0000416#if !UDEV
Eric Anholt06cb1322003-10-23 02:23:31 +0000417 /* Check if the device node is not what we expect it to be, and recreate it
418 * and try again if so.
419 */
Eric Anholtd2f2b422002-08-08 21:23:46 +0000420 if (st.st_rdev != dev) {
Jan Vesely50d3c852016-06-30 14:22:52 -0400421 if (!isroot)
422 return DRM_ERR_NOT_ROOT;
423 remove(buf);
424 mknod(buf, S_IFCHR | devmode, dev);
425 if (drm_server_info && drm_server_info->get_perms) {
426 chown_check_return(buf, user, group);
427 chmod(buf, devmode);
428 }
Eric Anholtd2f2b422002-08-08 21:23:46 +0000429 }
Michel Dänzer35615692018-05-18 11:16:51 +0200430 fd = open(buf, O_RDWR | O_CLOEXEC, 0);
Eric Anholtd2f2b422002-08-08 21:23:46 +0000431 drmMsg("drmOpenDevice: open result is %d, (%s)\n",
Jan Vesely50d3c852016-06-30 14:22:52 -0400432 fd, fd < 0 ? strerror(errno) : "OK");
Brianccd7b6e2007-05-29 14:54:00 -0600433 if (fd >= 0)
Jan Vesely50d3c852016-06-30 14:22:52 -0400434 return fd;
Eric Anholtd2f2b422002-08-08 21:23:46 +0000435
David Dawes56bd9c22001-07-30 19:59:39 +0000436 drmMsg("drmOpenDevice: Open failed\n");
Rik Faith88dbee52001-02-28 09:27:44 +0000437 remove(buf);
Dave Airlie39e5e982010-12-07 14:26:09 +1000438#endif
Rik Faith88dbee52001-02-28 09:27:44 +0000439 return -errno;
Daryll Straussb3a57661999-12-05 01:19:48 +0000440}
441
Jose Fonsecad2443b22003-05-27 00:37:33 +0000442
443/**
444 * Open the DRM device
445 *
446 * \param minor device minor number.
447 * \param create allow to create the device if set.
448 *
449 * \return a file descriptor on success, or a negative value on error.
Jan Vesely50d3c852016-06-30 14:22:52 -0400450 *
Jose Fonsecad2443b22003-05-27 00:37:33 +0000451 * \internal
452 * Calls drmOpenDevice() if \p create is set, otherwise assembles the device
453 * name from \p minor and opens it.
454 */
Jesse Barnes731cd552008-12-17 10:09:49 -0800455static int drmOpenMinor(int minor, int create, int type)
Rik Faith88dbee52001-02-28 09:27:44 +0000456{
457 int fd;
458 char buf[64];
Frank Binns0c5aaee2015-01-14 14:07:51 +0000459 const char *dev_name;
Jan Vesely50d3c852016-06-30 14:22:52 -0400460
Brianccd7b6e2007-05-29 14:54:00 -0600461 if (create)
Jan Vesely50d3c852016-06-30 14:22:52 -0400462 return drmOpenDevice(makedev(DRM_MAJOR, minor), minor, type);
463
Frank Binns0c5aaee2015-01-14 14:07:51 +0000464 switch (type) {
465 case DRM_NODE_PRIMARY:
Jan Vesely50d3c852016-06-30 14:22:52 -0400466 dev_name = DRM_DEV_NAME;
467 break;
Frank Binns0c5aaee2015-01-14 14:07:51 +0000468 case DRM_NODE_CONTROL:
Jan Vesely50d3c852016-06-30 14:22:52 -0400469 dev_name = DRM_CONTROL_DEV_NAME;
470 break;
Frank Binns0c5aaee2015-01-14 14:07:51 +0000471 case DRM_NODE_RENDER:
Jan Vesely50d3c852016-06-30 14:22:52 -0400472 dev_name = DRM_RENDER_DEV_NAME;
473 break;
Frank Binns0c5aaee2015-01-14 14:07:51 +0000474 default:
Jan Vesely50d3c852016-06-30 14:22:52 -0400475 return -EINVAL;
Frank Binns0c5aaee2015-01-14 14:07:51 +0000476 };
477
478 sprintf(buf, dev_name, DRM_DIR_NAME, minor);
Michel Dänzer35615692018-05-18 11:16:51 +0200479 if ((fd = open(buf, O_RDWR | O_CLOEXEC, 0)) >= 0)
Jan Vesely50d3c852016-06-30 14:22:52 -0400480 return fd;
Rik Faith88dbee52001-02-28 09:27:44 +0000481 return -errno;
482}
483
Brian Paul569da5a2000-06-08 14:38:22 +0000484
Jose Fonsecad2443b22003-05-27 00:37:33 +0000485/**
486 * Determine whether the DRM kernel driver has been loaded.
Jan Vesely50d3c852016-06-30 14:22:52 -0400487 *
Jose Fonsecad2443b22003-05-27 00:37:33 +0000488 * \return 1 if the DRM driver is loaded, 0 otherwise.
489 *
Jan Vesely50d3c852016-06-30 14:22:52 -0400490 * \internal
Jose Fonsecad2443b22003-05-27 00:37:33 +0000491 * Determine the presence of the kernel driver by attempting to open the 0
492 * minor and get version information. For backward compatibility with older
493 * Linux implementations, /proc/dri is also checked.
494 */
Lucas De Marchi26f9ce52018-09-13 15:42:26 -0700495drm_public int drmAvailable(void)
Brian Paul569da5a2000-06-08 14:38:22 +0000496{
Brian Paul569da5a2000-06-08 14:38:22 +0000497 drmVersionPtr version;
498 int retval = 0;
499 int fd;
Gareth Hughes36047532001-02-15 08:12:14 +0000500
Frank Binnsad8bbfd2015-01-14 14:07:50 +0000501 if ((fd = drmOpenMinor(0, 1, DRM_NODE_PRIMARY)) < 0) {
Alan Hourihaneb0a92852003-09-24 14:39:25 +0000502#ifdef __linux__
Jan Vesely50d3c852016-06-30 14:22:52 -0400503 /* Try proc for backward Linux compatibility */
504 if (!access("/proc/dri/0", R_OK))
505 return 1;
Alan Hourihaneb0a92852003-09-24 14:39:25 +0000506#endif
Jan Vesely50d3c852016-06-30 14:22:52 -0400507 return 0;
Brian Paul569da5a2000-06-08 14:38:22 +0000508 }
Jan Vesely50d3c852016-06-30 14:22:52 -0400509
Rik Faith88dbee52001-02-28 09:27:44 +0000510 if ((version = drmGetVersion(fd))) {
Jan Vesely50d3c852016-06-30 14:22:52 -0400511 retval = 1;
512 drmFreeVersion(version);
Rik Faith88dbee52001-02-28 09:27:44 +0000513 }
514 close(fd);
Brian Paul569da5a2000-06-08 14:38:22 +0000515
516 return retval;
517}
518
Jammy Zhouf1adc4b2015-02-11 12:40:51 +0800519static int drmGetMinorBase(int type)
520{
521 switch (type) {
522 case DRM_NODE_PRIMARY:
523 return 0;
524 case DRM_NODE_CONTROL:
525 return 64;
526 case DRM_NODE_RENDER:
527 return 128;
528 default:
529 return -1;
530 };
531}
Jose Fonsecad2443b22003-05-27 00:37:33 +0000532
Frank Binns1f735782015-02-13 10:51:15 +0000533static int drmGetMinorType(int minor)
534{
535 int type = minor >> 6;
536
537 if (minor < 0)
538 return -1;
539
540 switch (type) {
541 case DRM_NODE_PRIMARY:
542 case DRM_NODE_CONTROL:
543 case DRM_NODE_RENDER:
544 return type;
545 default:
546 return -1;
547 }
548}
549
Emil Velikov0ca03a42015-03-07 00:58:39 +0000550static const char *drmGetMinorName(int type)
551{
552 switch (type) {
553 case DRM_NODE_PRIMARY:
Jonathan Grayfc083322015-07-21 03:12:56 +1000554 return DRM_PRIMARY_MINOR_NAME;
Emil Velikov0ca03a42015-03-07 00:58:39 +0000555 case DRM_NODE_CONTROL:
Jonathan Grayfc083322015-07-21 03:12:56 +1000556 return DRM_CONTROL_MINOR_NAME;
Emil Velikov0ca03a42015-03-07 00:58:39 +0000557 case DRM_NODE_RENDER:
Jonathan Grayfc083322015-07-21 03:12:56 +1000558 return DRM_RENDER_MINOR_NAME;
Emil Velikov0ca03a42015-03-07 00:58:39 +0000559 default:
560 return NULL;
561 }
562}
563
Jose Fonsecad2443b22003-05-27 00:37:33 +0000564/**
565 * Open the device by bus ID.
566 *
567 * \param busid bus ID.
Jammy Zhouf1adc4b2015-02-11 12:40:51 +0800568 * \param type device node type.
Jose Fonsecad2443b22003-05-27 00:37:33 +0000569 *
570 * \return a file descriptor on success, or a negative value on error.
571 *
572 * \internal
573 * This function attempts to open every possible minor (up to DRM_MAX_MINOR),
574 * comparing the device bus ID with the one supplied.
575 *
576 * \sa drmOpenMinor() and drmGetBusid().
577 */
Jammy Zhouf1adc4b2015-02-11 12:40:51 +0800578static int drmOpenByBusid(const char *busid, int type)
Daryll Strausse1dba5c1999-12-07 03:37:16 +0000579{
Benjamin Herrenschmidtb04515c2010-08-06 13:55:11 +1000580 int i, pci_domain_ok = 1;
Rik Faith88dbee52001-02-28 09:27:44 +0000581 int fd;
582 const char *buf;
Eric Anholt06cb1322003-10-23 02:23:31 +0000583 drmSetVersion sv;
Jammy Zhouf1adc4b2015-02-11 12:40:51 +0800584 int base = drmGetMinorBase(type);
585
586 if (base < 0)
587 return -1;
Eric Anholt06cb1322003-10-23 02:23:31 +0000588
589 drmMsg("drmOpenByBusid: Searching for BusID %s\n", busid);
Jammy Zhouf1adc4b2015-02-11 12:40:51 +0800590 for (i = base; i < base + DRM_MAX_MINOR; i++) {
Jan Vesely50d3c852016-06-30 14:22:52 -0400591 fd = drmOpenMinor(i, 1, type);
592 drmMsg("drmOpenByBusid: drmOpenMinor returns %d\n", fd);
593 if (fd >= 0) {
594 /* We need to try for 1.4 first for proper PCI domain support
595 * and if that fails, we know the kernel is busted
596 */
597 sv.drm_di_major = 1;
598 sv.drm_di_minor = 4;
599 sv.drm_dd_major = -1; /* Don't care */
600 sv.drm_dd_minor = -1; /* Don't care */
601 if (drmSetInterfaceVersion(fd, &sv)) {
Benjamin Herrenschmidtb04515c2010-08-06 13:55:11 +1000602#ifndef __alpha__
Jan Vesely50d3c852016-06-30 14:22:52 -0400603 pci_domain_ok = 0;
Benjamin Herrenschmidtb04515c2010-08-06 13:55:11 +1000604#endif
Jan Vesely50d3c852016-06-30 14:22:52 -0400605 sv.drm_di_major = 1;
606 sv.drm_di_minor = 1;
607 sv.drm_dd_major = -1; /* Don't care */
608 sv.drm_dd_minor = -1; /* Don't care */
609 drmMsg("drmOpenByBusid: Interface 1.4 failed, trying 1.1\n");
610 drmSetInterfaceVersion(fd, &sv);
611 }
612 buf = drmGetBusid(fd);
613 drmMsg("drmOpenByBusid: drmGetBusid reports %s\n", buf);
614 if (buf && drmMatchBusID(buf, busid, pci_domain_ok)) {
615 drmFreeBusid(buf);
616 return fd;
617 }
618 if (buf)
619 drmFreeBusid(buf);
620 close(fd);
621 }
Daryll Strausse1dba5c1999-12-07 03:37:16 +0000622 }
623 return -1;
624}
625
Jose Fonsecad2443b22003-05-27 00:37:33 +0000626
627/**
628 * Open the device by name.
629 *
630 * \param name driver name.
Jammy Zhouf1adc4b2015-02-11 12:40:51 +0800631 * \param type the device node type.
Jan Vesely50d3c852016-06-30 14:22:52 -0400632 *
Jose Fonsecad2443b22003-05-27 00:37:33 +0000633 * \return a file descriptor on success, or a negative value on error.
Jan Vesely50d3c852016-06-30 14:22:52 -0400634 *
Jose Fonsecad2443b22003-05-27 00:37:33 +0000635 * \internal
636 * This function opens the first minor number that matches the driver name and
637 * isn't already in use. If it's in use it then it will already have a bus ID
638 * assigned.
Jan Vesely50d3c852016-06-30 14:22:52 -0400639 *
Jose Fonsecad2443b22003-05-27 00:37:33 +0000640 * \sa drmOpenMinor(), drmGetVersion() and drmGetBusid().
641 */
Jammy Zhouf1adc4b2015-02-11 12:40:51 +0800642static int drmOpenByName(const char *name, int type)
Daryll Straussb3a57661999-12-05 01:19:48 +0000643{
Rik Faith88dbee52001-02-28 09:27:44 +0000644 int i;
645 int fd;
646 drmVersionPtr version;
David Dawes56bd9c22001-07-30 19:59:39 +0000647 char * id;
Jammy Zhouf1adc4b2015-02-11 12:40:51 +0800648 int base = drmGetMinorBase(type);
649
650 if (base < 0)
651 return -1;
Dave Airliedb85ed22008-02-13 12:20:02 +1000652
David Dawes56bd9c22001-07-30 19:59:39 +0000653 /*
654 * Open the first minor number that matches the driver name and isn't
655 * already in use. If it's in use it will have a busid assigned already.
656 */
Jammy Zhouf1adc4b2015-02-11 12:40:51 +0800657 for (i = base; i < base + DRM_MAX_MINOR; i++) {
Jan Vesely50d3c852016-06-30 14:22:52 -0400658 if ((fd = drmOpenMinor(i, 1, type)) >= 0) {
659 if ((version = drmGetVersion(fd))) {
660 if (!strcmp(version->name, name)) {
661 drmFreeVersion(version);
662 id = drmGetBusid(fd);
663 drmMsg("drmGetBusid returned '%s'\n", id ? id : "NULL");
664 if (!id || !*id) {
665 if (id)
666 drmFreeBusid(id);
667 return fd;
668 } else {
669 drmFreeBusid(id);
670 }
671 } else {
672 drmFreeVersion(version);
673 }
674 }
675 close(fd);
676 }
Rik Faith88dbee52001-02-28 09:27:44 +0000677 }
678
679#ifdef __linux__
Adam Jackson22e41ef2006-02-20 23:09:00 +0000680 /* Backward-compatibility /proc support */
Daryll Straussb6a28bf1999-12-05 23:10:37 +0000681 for (i = 0; i < 8; i++) {
Jan Vesely50d3c852016-06-30 14:22:52 -0400682 char proc_name[64], buf[512];
683 char *driver, *pt, *devstring;
684 int retcode;
685
686 sprintf(proc_name, "/proc/dri/%d/name", i);
687 if ((fd = open(proc_name, 0, 0)) >= 0) {
688 retcode = read(fd, buf, sizeof(buf)-1);
689 close(fd);
690 if (retcode) {
691 buf[retcode-1] = '\0';
692 for (driver = pt = buf; *pt && *pt != ' '; ++pt)
693 ;
694 if (*pt) { /* Device is next */
695 *pt = '\0';
696 if (!strcmp(driver, name)) { /* Match */
697 for (devstring = ++pt; *pt && *pt != ' '; ++pt)
698 ;
699 if (*pt) { /* Found busid */
700 return drmOpenByBusid(++pt, type);
701 } else { /* No busid */
702 return drmOpenDevice(strtol(devstring, NULL, 0),i, type);
703 }
704 }
705 }
706 }
707 }
Daryll Straussb6a28bf1999-12-05 23:10:37 +0000708 }
Rik Faith88dbee52001-02-28 09:27:44 +0000709#endif
710
Daryll Straussb6a28bf1999-12-05 23:10:37 +0000711 return -1;
712}
713
Daryll Straussb6a28bf1999-12-05 23:10:37 +0000714
Jose Fonsecad2443b22003-05-27 00:37:33 +0000715/**
716 * Open the DRM device.
717 *
718 * Looks up the specified name and bus ID, and opens the device found. The
719 * entry in /dev/dri is created if necessary and if called by root.
720 *
721 * \param name driver name. Not referenced if bus ID is supplied.
722 * \param busid bus ID. Zero if not known.
Jan Vesely50d3c852016-06-30 14:22:52 -0400723 *
Jose Fonsecad2443b22003-05-27 00:37:33 +0000724 * \return a file descriptor on success, or a negative value on error.
Jan Vesely50d3c852016-06-30 14:22:52 -0400725 *
Jose Fonsecad2443b22003-05-27 00:37:33 +0000726 * \internal
727 * It calls drmOpenByBusid() if \p busid is specified or drmOpenByName()
728 * otherwise.
729 */
Lucas De Marchi26f9ce52018-09-13 15:42:26 -0700730drm_public int drmOpen(const char *name, const char *busid)
Daryll Straussb3a57661999-12-05 01:19:48 +0000731{
Jammy Zhouf1adc4b2015-02-11 12:40:51 +0800732 return drmOpenWithType(name, busid, DRM_NODE_PRIMARY);
733}
734
735/**
736 * Open the DRM device with specified type.
737 *
738 * Looks up the specified name and bus ID, and opens the device found. The
739 * entry in /dev/dri is created if necessary and if called by root.
740 *
741 * \param name driver name. Not referenced if bus ID is supplied.
742 * \param busid bus ID. Zero if not known.
743 * \param type the device node type to open, PRIMARY, CONTROL or RENDER
744 *
745 * \return a file descriptor on success, or a negative value on error.
746 *
747 * \internal
748 * It calls drmOpenByBusid() if \p busid is specified or drmOpenByName()
749 * otherwise.
750 */
Lucas De Marchi26f9ce52018-09-13 15:42:26 -0700751drm_public int drmOpenWithType(const char *name, const char *busid, int type)
Jammy Zhouf1adc4b2015-02-11 12:40:51 +0800752{
Rob Clarkeb7c2d52015-09-04 08:08:02 -0400753 if (!drmAvailable() && name != NULL && drm_server_info &&
754 drm_server_info->load_module) {
Jan Vesely50d3c852016-06-30 14:22:52 -0400755 /* try to load the kernel module */
756 if (!drm_server_info->load_module(name)) {
757 drmMsg("[drm] failed to load kernel module \"%s\"\n", name);
758 return -1;
759 }
Eric Anholt06cb1322003-10-23 02:23:31 +0000760 }
Daryll Straussb6a28bf1999-12-05 23:10:37 +0000761
Eric Anholt06cb1322003-10-23 02:23:31 +0000762 if (busid) {
Jan Vesely50d3c852016-06-30 14:22:52 -0400763 int fd = drmOpenByBusid(busid, type);
764 if (fd >= 0)
765 return fd;
Eric Anholt06cb1322003-10-23 02:23:31 +0000766 }
Jan Vesely50d3c852016-06-30 14:22:52 -0400767
Eric Anholt06cb1322003-10-23 02:23:31 +0000768 if (name)
Jan Vesely50d3c852016-06-30 14:22:52 -0400769 return drmOpenByName(name, type);
Adam Jackson22e41ef2006-02-20 23:09:00 +0000770
Eric Anholt06cb1322003-10-23 02:23:31 +0000771 return -1;
Daryll Straussb3a57661999-12-05 01:19:48 +0000772}
773
Lucas De Marchi26f9ce52018-09-13 15:42:26 -0700774drm_public int drmOpenControl(int minor)
Jesse Barnes731cd552008-12-17 10:09:49 -0800775{
776 return drmOpenMinor(minor, 0, DRM_NODE_CONTROL);
777}
Jose Fonsecad2443b22003-05-27 00:37:33 +0000778
Lucas De Marchi26f9ce52018-09-13 15:42:26 -0700779drm_public int drmOpenRender(int minor)
Frank Binns0c5aaee2015-01-14 14:07:51 +0000780{
781 return drmOpenMinor(minor, 0, DRM_NODE_RENDER);
782}
783
Jose Fonsecad2443b22003-05-27 00:37:33 +0000784/**
785 * Free the version information returned by drmGetVersion().
786 *
787 * \param v pointer to the version information.
788 *
789 * \internal
790 * It frees the memory pointed by \p %v as well as all the non-null strings
791 * pointers in it.
792 */
Lucas De Marchi26f9ce52018-09-13 15:42:26 -0700793drm_public void drmFreeVersion(drmVersionPtr v)
Daryll Straussb3a57661999-12-05 01:19:48 +0000794{
Brianccd7b6e2007-05-29 14:54:00 -0600795 if (!v)
Jan Vesely50d3c852016-06-30 14:22:52 -0400796 return;
Jakob Bornecrantz9d8ba2d2007-02-25 10:48:26 +1100797 drmFree(v->name);
798 drmFree(v->date);
799 drmFree(v->desc);
Daryll Straussb3a57661999-12-05 01:19:48 +0000800 drmFree(v);
801}
802
Jose Fonsecad2443b22003-05-27 00:37:33 +0000803
804/**
805 * Free the non-public version information returned by the kernel.
806 *
807 * \param v pointer to the version information.
808 *
809 * \internal
810 * Used by drmGetVersion() to free the memory pointed by \p %v as well as all
811 * the non-null strings pointers in it.
812 */
Daryll Straussb3a57661999-12-05 01:19:48 +0000813static void drmFreeKernelVersion(drm_version_t *v)
814{
Brianccd7b6e2007-05-29 14:54:00 -0600815 if (!v)
Jan Vesely50d3c852016-06-30 14:22:52 -0400816 return;
Jakob Bornecrantz9d8ba2d2007-02-25 10:48:26 +1100817 drmFree(v->name);
818 drmFree(v->date);
819 drmFree(v->desc);
Daryll Straussb3a57661999-12-05 01:19:48 +0000820 drmFree(v);
821}
822
Jose Fonsecad2443b22003-05-27 00:37:33 +0000823
824/**
825 * Copy version information.
Jan Vesely50d3c852016-06-30 14:22:52 -0400826 *
Jose Fonsecad2443b22003-05-27 00:37:33 +0000827 * \param d destination pointer.
828 * \param s source pointer.
Jan Vesely50d3c852016-06-30 14:22:52 -0400829 *
Jose Fonsecad2443b22003-05-27 00:37:33 +0000830 * \internal
831 * Used by drmGetVersion() to translate the information returned by the ioctl
832 * interface in a private structure into the public structure counterpart.
833 */
Brian Paul569da5a2000-06-08 14:38:22 +0000834static void drmCopyVersion(drmVersionPtr d, const drm_version_t *s)
Daryll Straussb3a57661999-12-05 01:19:48 +0000835{
836 d->version_major = s->version_major;
837 d->version_minor = s->version_minor;
838 d->version_patchlevel = s->version_patchlevel;
839 d->name_len = s->name_len;
Adam Jackson0a1ff352010-10-27 18:44:53 -0400840 d->name = strdup(s->name);
Daryll Straussb3a57661999-12-05 01:19:48 +0000841 d->date_len = s->date_len;
Adam Jackson0a1ff352010-10-27 18:44:53 -0400842 d->date = strdup(s->date);
Daryll Straussb3a57661999-12-05 01:19:48 +0000843 d->desc_len = s->desc_len;
Adam Jackson0a1ff352010-10-27 18:44:53 -0400844 d->desc = strdup(s->desc);
Daryll Straussb3a57661999-12-05 01:19:48 +0000845}
846
Daryll Straussb3a57661999-12-05 01:19:48 +0000847
Jose Fonsecad2443b22003-05-27 00:37:33 +0000848/**
849 * Query the driver version information.
850 *
851 * \param fd file descriptor.
Jan Vesely50d3c852016-06-30 14:22:52 -0400852 *
Jose Fonsecad2443b22003-05-27 00:37:33 +0000853 * \return pointer to a drmVersion structure which should be freed with
854 * drmFreeVersion().
Jan Vesely50d3c852016-06-30 14:22:52 -0400855 *
Jose Fonsecad2443b22003-05-27 00:37:33 +0000856 * \note Similar information is available via /proc/dri.
Jan Vesely50d3c852016-06-30 14:22:52 -0400857 *
Jose Fonsecad2443b22003-05-27 00:37:33 +0000858 * \internal
859 * It gets the version information via successive DRM_IOCTL_VERSION ioctls,
860 * first with zeros to get the string lengths, and then the actually strings.
861 * It also null-terminates them since they might not be already.
862 */
Lucas De Marchi26f9ce52018-09-13 15:42:26 -0700863drm_public drmVersionPtr drmGetVersion(int fd)
Daryll Straussb3a57661999-12-05 01:19:48 +0000864{
865 drmVersionPtr retval;
866 drm_version_t *version = drmMalloc(sizeof(*version));
867
Keith Packard8b9ab102008-06-13 16:03:22 -0700868 if (drmIoctl(fd, DRM_IOCTL_VERSION, version)) {
Jan Vesely50d3c852016-06-30 14:22:52 -0400869 drmFreeKernelVersion(version);
870 return NULL;
Daryll Straussb3a57661999-12-05 01:19:48 +0000871 }
872
Daryll Straussb3a57661999-12-05 01:19:48 +0000873 if (version->name_len)
Jan Vesely50d3c852016-06-30 14:22:52 -0400874 version->name = drmMalloc(version->name_len + 1);
Daryll Straussb3a57661999-12-05 01:19:48 +0000875 if (version->date_len)
Jan Vesely50d3c852016-06-30 14:22:52 -0400876 version->date = drmMalloc(version->date_len + 1);
Daryll Straussb3a57661999-12-05 01:19:48 +0000877 if (version->desc_len)
Jan Vesely50d3c852016-06-30 14:22:52 -0400878 version->desc = drmMalloc(version->desc_len + 1);
Gareth Hughes36047532001-02-15 08:12:14 +0000879
Keith Packard8b9ab102008-06-13 16:03:22 -0700880 if (drmIoctl(fd, DRM_IOCTL_VERSION, version)) {
Jan Vesely50d3c852016-06-30 14:22:52 -0400881 drmMsg("DRM_IOCTL_VERSION: %s\n", strerror(errno));
882 drmFreeKernelVersion(version);
883 return NULL;
Daryll Straussb3a57661999-12-05 01:19:48 +0000884 }
885
Adam Jackson22e41ef2006-02-20 23:09:00 +0000886 /* The results might not be null-terminated strings, so terminate them. */
Daryll Straussb3a57661999-12-05 01:19:48 +0000887 if (version->name_len) version->name[version->name_len] = '\0';
888 if (version->date_len) version->date[version->date_len] = '\0';
889 if (version->desc_len) version->desc[version->desc_len] = '\0';
890
Daryll Straussb3a57661999-12-05 01:19:48 +0000891 retval = drmMalloc(sizeof(*retval));
892 drmCopyVersion(retval, version);
893 drmFreeKernelVersion(version);
894 return retval;
895}
896
Jens Owen3903e5a2002-04-09 21:54:56 +0000897
Jose Fonsecad2443b22003-05-27 00:37:33 +0000898/**
899 * Get version information for the DRM user space library.
Jan Vesely50d3c852016-06-30 14:22:52 -0400900 *
Jose Fonsecad2443b22003-05-27 00:37:33 +0000901 * This version number is driver independent.
Jan Vesely50d3c852016-06-30 14:22:52 -0400902 *
Jose Fonsecad2443b22003-05-27 00:37:33 +0000903 * \param fd file descriptor.
904 *
905 * \return version information.
Jan Vesely50d3c852016-06-30 14:22:52 -0400906 *
Jose Fonsecad2443b22003-05-27 00:37:33 +0000907 * \internal
908 * This function allocates and fills a drm_version structure with a hard coded
909 * version number.
910 */
Lucas De Marchi26f9ce52018-09-13 15:42:26 -0700911drm_public drmVersionPtr drmGetLibVersion(int fd)
Jens Owen3903e5a2002-04-09 21:54:56 +0000912{
913 drm_version_t *version = drmMalloc(sizeof(*version));
914
915 /* Version history:
Dave Airlie79038752006-11-08 15:08:09 +1100916 * NOTE THIS MUST NOT GO ABOVE VERSION 1.X due to drivers needing it
Jens Owen3903e5a2002-04-09 21:54:56 +0000917 * revision 1.0.x = original DRM interface with no drmGetLibVersion
918 * entry point and many drm<Device> extensions
919 * revision 1.1.x = added drmCommand entry points for device extensions
920 * added drmGetLibVersion to identify libdrm.a version
Eric Anholt06cb1322003-10-23 02:23:31 +0000921 * revision 1.2.x = added drmSetInterfaceVersion
922 * modified drmOpen to handle both busid and name
Dave Airlie79038752006-11-08 15:08:09 +1100923 * revision 1.3.x = added server + memory manager
Jens Owen3903e5a2002-04-09 21:54:56 +0000924 */
Dave Airlie79038752006-11-08 15:08:09 +1100925 version->version_major = 1;
926 version->version_minor = 3;
Jens Owen3903e5a2002-04-09 21:54:56 +0000927 version->version_patchlevel = 0;
928
929 return (drmVersionPtr)version;
930}
931
Lucas De Marchi26f9ce52018-09-13 15:42:26 -0700932drm_public int drmGetCap(int fd, uint64_t capability, uint64_t *value)
Ben Skeggs5c6c6912011-02-21 11:27:19 +1000933{
Jan Vesely50d3c852016-06-30 14:22:52 -0400934 struct drm_get_cap cap;
935 int ret;
Ben Skeggs5c6c6912011-02-21 11:27:19 +1000936
Jan Vesely50d3c852016-06-30 14:22:52 -0400937 memclear(cap);
938 cap.capability = capability;
Daniel Vetterfd387942015-02-11 12:41:04 +0100939
Jan Vesely50d3c852016-06-30 14:22:52 -0400940 ret = drmIoctl(fd, DRM_IOCTL_GET_CAP, &cap);
941 if (ret)
942 return ret;
Ben Skeggs5c6c6912011-02-21 11:27:19 +1000943
Jan Vesely50d3c852016-06-30 14:22:52 -0400944 *value = cap.value;
945 return 0;
Ben Skeggs5c6c6912011-02-21 11:27:19 +1000946}
Jose Fonsecad2443b22003-05-27 00:37:33 +0000947
Lucas De Marchi26f9ce52018-09-13 15:42:26 -0700948drm_public int drmSetClientCap(int fd, uint64_t capability, uint64_t value)
Damien Lespiauddbbdb12013-09-03 15:34:41 +0100949{
Jan Vesely50d3c852016-06-30 14:22:52 -0400950 struct drm_set_client_cap cap;
Daniel Vetterfd387942015-02-11 12:41:04 +0100951
Jan Vesely50d3c852016-06-30 14:22:52 -0400952 memclear(cap);
953 cap.capability = capability;
954 cap.value = value;
Damien Lespiauddbbdb12013-09-03 15:34:41 +0100955
Jan Vesely50d3c852016-06-30 14:22:52 -0400956 return drmIoctl(fd, DRM_IOCTL_SET_CLIENT_CAP, &cap);
Damien Lespiauddbbdb12013-09-03 15:34:41 +0100957}
958
Jose Fonsecad2443b22003-05-27 00:37:33 +0000959/**
960 * Free the bus ID information.
961 *
962 * \param busid bus ID information string as given by drmGetBusid().
963 *
964 * \internal
965 * This function is just frees the memory pointed by \p busid.
966 */
Lucas De Marchi26f9ce52018-09-13 15:42:26 -0700967drm_public void drmFreeBusid(const char *busid)
Daryll Straussb3a57661999-12-05 01:19:48 +0000968{
Daryll Straussb6a28bf1999-12-05 23:10:37 +0000969 drmFree((void *)busid);
Daryll Straussb3a57661999-12-05 01:19:48 +0000970}
971
Jose Fonsecad2443b22003-05-27 00:37:33 +0000972
973/**
974 * Get the bus ID of the device.
975 *
976 * \param fd file descriptor.
977 *
978 * \return bus ID string.
979 *
980 * \internal
981 * This function gets the bus ID via successive DRM_IOCTL_GET_UNIQUE ioctls to
982 * get the string length and data, passing the arguments in a drm_unique
983 * structure.
984 */
Lucas De Marchi26f9ce52018-09-13 15:42:26 -0700985drm_public char *drmGetBusid(int fd)
Daryll Straussb3a57661999-12-05 01:19:48 +0000986{
Daryll Straussb6a28bf1999-12-05 23:10:37 +0000987 drm_unique_t u;
988
Daniel Vetterfd387942015-02-11 12:41:04 +0100989 memclear(u);
Daryll Straussb6a28bf1999-12-05 23:10:37 +0000990
Keith Packard8b9ab102008-06-13 16:03:22 -0700991 if (drmIoctl(fd, DRM_IOCTL_GET_UNIQUE, &u))
Jan Vesely50d3c852016-06-30 14:22:52 -0400992 return NULL;
Daryll Straussb6a28bf1999-12-05 23:10:37 +0000993 u.unique = drmMalloc(u.unique_len + 1);
Seung-Woo Kim7b806e82017-03-27 11:09:29 +0900994 if (drmIoctl(fd, DRM_IOCTL_GET_UNIQUE, &u)) {
995 drmFree(u.unique);
Jan Vesely50d3c852016-06-30 14:22:52 -0400996 return NULL;
Seung-Woo Kim7b806e82017-03-27 11:09:29 +0900997 }
Daryll Straussb6a28bf1999-12-05 23:10:37 +0000998 u.unique[u.unique_len] = '\0';
Eric Anholt06cb1322003-10-23 02:23:31 +0000999
Daryll Straussb6a28bf1999-12-05 23:10:37 +00001000 return u.unique;
Daryll Straussb3a57661999-12-05 01:19:48 +00001001}
1002
Jose Fonsecad2443b22003-05-27 00:37:33 +00001003
1004/**
1005 * Set the bus ID of the device.
1006 *
1007 * \param fd file descriptor.
1008 * \param busid bus ID string.
1009 *
1010 * \return zero on success, negative on failure.
1011 *
1012 * \internal
1013 * This function is a wrapper around the DRM_IOCTL_SET_UNIQUE ioctl, passing
1014 * the arguments in a drm_unique structure.
1015 */
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07001016drm_public int drmSetBusid(int fd, const char *busid)
Daryll Straussb3a57661999-12-05 01:19:48 +00001017{
Daryll Straussb6a28bf1999-12-05 23:10:37 +00001018 drm_unique_t u;
Daryll Straussb3a57661999-12-05 01:19:48 +00001019
Daniel Vetterfd387942015-02-11 12:41:04 +01001020 memclear(u);
Daryll Straussb6a28bf1999-12-05 23:10:37 +00001021 u.unique = (char *)busid;
1022 u.unique_len = strlen(busid);
Daryll Straussb3a57661999-12-05 01:19:48 +00001023
Keith Packard8b9ab102008-06-13 16:03:22 -07001024 if (drmIoctl(fd, DRM_IOCTL_SET_UNIQUE, &u)) {
Jan Vesely50d3c852016-06-30 14:22:52 -04001025 return -errno;
David Dawes56bd9c22001-07-30 19:59:39 +00001026 }
Daryll Straussb3a57661999-12-05 01:19:48 +00001027 return 0;
1028}
1029
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07001030drm_public int drmGetMagic(int fd, drm_magic_t * magic)
Daryll Straussb3a57661999-12-05 01:19:48 +00001031{
1032 drm_auth_t auth;
1033
Daniel Vetterfd387942015-02-11 12:41:04 +01001034 memclear(auth);
1035
Daryll Straussb3a57661999-12-05 01:19:48 +00001036 *magic = 0;
Keith Packard8b9ab102008-06-13 16:03:22 -07001037 if (drmIoctl(fd, DRM_IOCTL_GET_MAGIC, &auth))
Jan Vesely50d3c852016-06-30 14:22:52 -04001038 return -errno;
Daryll Straussb3a57661999-12-05 01:19:48 +00001039 *magic = auth.magic;
1040 return 0;
1041}
1042
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07001043drm_public int drmAuthMagic(int fd, drm_magic_t magic)
Daryll Straussb3a57661999-12-05 01:19:48 +00001044{
1045 drm_auth_t auth;
1046
Daniel Vetterfd387942015-02-11 12:41:04 +01001047 memclear(auth);
Daryll Straussb3a57661999-12-05 01:19:48 +00001048 auth.magic = magic;
Keith Packard8b9ab102008-06-13 16:03:22 -07001049 if (drmIoctl(fd, DRM_IOCTL_AUTH_MAGIC, &auth))
Jan Vesely50d3c852016-06-30 14:22:52 -04001050 return -errno;
Daryll Straussb3a57661999-12-05 01:19:48 +00001051 return 0;
1052}
1053
Jose Fonsecad2443b22003-05-27 00:37:33 +00001054/**
1055 * Specifies a range of memory that is available for mapping by a
1056 * non-root process.
1057 *
1058 * \param fd file descriptor.
1059 * \param offset usually the physical address. The actual meaning depends of
1060 * the \p type parameter. See below.
1061 * \param size of the memory in bytes.
1062 * \param type type of the memory to be mapped.
1063 * \param flags combination of several flags to modify the function actions.
1064 * \param handle will be set to a value that may be used as the offset
1065 * parameter for mmap().
Jan Vesely50d3c852016-06-30 14:22:52 -04001066 *
Jose Fonsecad2443b22003-05-27 00:37:33 +00001067 * \return zero on success or a negative value on error.
1068 *
1069 * \par Mapping the frame buffer
1070 * For the frame buffer
1071 * - \p offset will be the physical address of the start of the frame buffer,
1072 * - \p size will be the size of the frame buffer in bytes, and
1073 * - \p type will be DRM_FRAME_BUFFER.
1074 *
1075 * \par
1076 * The area mapped will be uncached. If MTRR support is available in the
Jan Vesely50d3c852016-06-30 14:22:52 -04001077 * kernel, the frame buffer area will be set to write combining.
Jose Fonsecad2443b22003-05-27 00:37:33 +00001078 *
1079 * \par Mapping the MMIO register area
1080 * For the MMIO register area,
1081 * - \p offset will be the physical address of the start of the register area,
1082 * - \p size will be the size of the register area bytes, and
1083 * - \p type will be DRM_REGISTERS.
1084 * \par
Jan Vesely50d3c852016-06-30 14:22:52 -04001085 * The area mapped will be uncached.
1086 *
Jose Fonsecad2443b22003-05-27 00:37:33 +00001087 * \par Mapping the SAREA
1088 * For the SAREA,
1089 * - \p offset will be ignored and should be set to zero,
1090 * - \p size will be the desired size of the SAREA in bytes,
1091 * - \p type will be DRM_SHM.
Jan Vesely50d3c852016-06-30 14:22:52 -04001092 *
Jose Fonsecad2443b22003-05-27 00:37:33 +00001093 * \par
1094 * A shared memory area of the requested size will be created and locked in
1095 * kernel memory. This area may be mapped into client-space by using the handle
Jan Vesely50d3c852016-06-30 14:22:52 -04001096 * returned.
1097 *
Jose Fonsecad2443b22003-05-27 00:37:33 +00001098 * \note May only be called by root.
1099 *
1100 * \internal
1101 * This function is a wrapper around the DRM_IOCTL_ADD_MAP ioctl, passing
1102 * the arguments in a drm_map structure.
1103 */
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07001104drm_public int drmAddMap(int fd, drm_handle_t offset, drmSize size, drmMapType type,
1105 drmMapFlags flags, drm_handle_t *handle)
Daryll Straussb3a57661999-12-05 01:19:48 +00001106{
1107 drm_map_t map;
1108
Daniel Vetterfd387942015-02-11 12:41:04 +01001109 memclear(map);
Daryll Straussb3a57661999-12-05 01:19:48 +00001110 map.offset = offset;
1111 map.size = size;
Daryll Straussb3a57661999-12-05 01:19:48 +00001112 map.type = type;
1113 map.flags = flags;
Keith Packard8b9ab102008-06-13 16:03:22 -07001114 if (drmIoctl(fd, DRM_IOCTL_ADD_MAP, &map))
Jan Vesely50d3c852016-06-30 14:22:52 -04001115 return -errno;
Brianccd7b6e2007-05-29 14:54:00 -06001116 if (handle)
Jan Vesely50d3c852016-06-30 14:22:52 -04001117 *handle = (drm_handle_t)(uintptr_t)map.handle;
Daryll Straussb3a57661999-12-05 01:19:48 +00001118 return 0;
1119}
1120
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07001121drm_public int drmRmMap(int fd, drm_handle_t handle)
Kevin E Martin74e19a42001-03-14 22:22:50 +00001122{
1123 drm_map_t map;
1124
Daniel Vetterfd387942015-02-11 12:41:04 +01001125 memclear(map);
Jeremy Huddleston961bf9b2011-11-01 14:42:13 -07001126 map.handle = (void *)(uintptr_t)handle;
Kevin E Martin74e19a42001-03-14 22:22:50 +00001127
Keith Packard8b9ab102008-06-13 16:03:22 -07001128 if(drmIoctl(fd, DRM_IOCTL_RM_MAP, &map))
Jan Vesely50d3c852016-06-30 14:22:52 -04001129 return -errno;
Kevin E Martin74e19a42001-03-14 22:22:50 +00001130 return 0;
1131}
1132
Jose Fonsecad2443b22003-05-27 00:37:33 +00001133/**
1134 * Make buffers available for DMA transfers.
Jan Vesely50d3c852016-06-30 14:22:52 -04001135 *
Jose Fonsecad2443b22003-05-27 00:37:33 +00001136 * \param fd file descriptor.
1137 * \param count number of buffers.
1138 * \param size size of each buffer.
1139 * \param flags buffer allocation flags.
Jan Vesely50d3c852016-06-30 14:22:52 -04001140 * \param agp_offset offset in the AGP aperture
Jose Fonsecad2443b22003-05-27 00:37:33 +00001141 *
1142 * \return number of buffers allocated, negative on error.
1143 *
1144 * \internal
1145 * This function is a wrapper around DRM_IOCTL_ADD_BUFS ioctl.
1146 *
1147 * \sa drm_buf_desc.
1148 */
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07001149drm_public int drmAddBufs(int fd, int count, int size, drmBufDescFlags flags,
1150 int agp_offset)
Daryll Straussb3a57661999-12-05 01:19:48 +00001151{
1152 drm_buf_desc_t request;
Gareth Hughes36047532001-02-15 08:12:14 +00001153
Daniel Vetterfd387942015-02-11 12:41:04 +01001154 memclear(request);
Daryll Straussb3a57661999-12-05 01:19:48 +00001155 request.count = count;
1156 request.size = size;
Daryll Straussb3a57661999-12-05 01:19:48 +00001157 request.flags = flags;
Jeff Hartmannba1b1ae2000-04-04 22:08:14 +00001158 request.agp_start = agp_offset;
Gareth Hughes36047532001-02-15 08:12:14 +00001159
Keith Packard8b9ab102008-06-13 16:03:22 -07001160 if (drmIoctl(fd, DRM_IOCTL_ADD_BUFS, &request))
Jan Vesely50d3c852016-06-30 14:22:52 -04001161 return -errno;
Daryll Straussb3a57661999-12-05 01:19:48 +00001162 return request.count;
1163}
1164
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07001165drm_public int drmMarkBufs(int fd, double low, double high)
Daryll Straussb3a57661999-12-05 01:19:48 +00001166{
1167 drm_buf_info_t info;
1168 int i;
1169
Daniel Vetterfd387942015-02-11 12:41:04 +01001170 memclear(info);
Daryll Straussb3a57661999-12-05 01:19:48 +00001171
Keith Packard8b9ab102008-06-13 16:03:22 -07001172 if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info))
Jan Vesely50d3c852016-06-30 14:22:52 -04001173 return -EINVAL;
Daryll Straussb3a57661999-12-05 01:19:48 +00001174
Brianccd7b6e2007-05-29 14:54:00 -06001175 if (!info.count)
Jan Vesely50d3c852016-06-30 14:22:52 -04001176 return -EINVAL;
Gareth Hughes36047532001-02-15 08:12:14 +00001177
Daryll Straussb3a57661999-12-05 01:19:48 +00001178 if (!(info.list = drmMalloc(info.count * sizeof(*info.list))))
Jan Vesely50d3c852016-06-30 14:22:52 -04001179 return -ENOMEM;
Gareth Hughes36047532001-02-15 08:12:14 +00001180
Keith Packard8b9ab102008-06-13 16:03:22 -07001181 if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info)) {
Jan Vesely50d3c852016-06-30 14:22:52 -04001182 int retval = -errno;
1183 drmFree(info.list);
1184 return retval;
Daryll Straussb3a57661999-12-05 01:19:48 +00001185 }
Gareth Hughes36047532001-02-15 08:12:14 +00001186
Daryll Straussb3a57661999-12-05 01:19:48 +00001187 for (i = 0; i < info.count; i++) {
Jan Vesely50d3c852016-06-30 14:22:52 -04001188 info.list[i].low_mark = low * info.list[i].count;
1189 info.list[i].high_mark = high * info.list[i].count;
1190 if (drmIoctl(fd, DRM_IOCTL_MARK_BUFS, &info.list[i])) {
1191 int retval = -errno;
1192 drmFree(info.list);
1193 return retval;
1194 }
Daryll Straussb3a57661999-12-05 01:19:48 +00001195 }
1196 drmFree(info.list);
Gareth Hughes36047532001-02-15 08:12:14 +00001197
Daryll Straussb3a57661999-12-05 01:19:48 +00001198 return 0;
1199}
1200
Jose Fonsecad2443b22003-05-27 00:37:33 +00001201/**
1202 * Free buffers.
1203 *
1204 * \param fd file descriptor.
1205 * \param count number of buffers to free.
1206 * \param list list of buffers to be freed.
1207 *
1208 * \return zero on success, or a negative value on failure.
Jan Vesely50d3c852016-06-30 14:22:52 -04001209 *
Jose Fonsecad2443b22003-05-27 00:37:33 +00001210 * \note This function is primarily used for debugging.
Jan Vesely50d3c852016-06-30 14:22:52 -04001211 *
Jose Fonsecad2443b22003-05-27 00:37:33 +00001212 * \internal
1213 * This function is a wrapper around the DRM_IOCTL_FREE_BUFS ioctl, passing
1214 * the arguments in a drm_buf_free structure.
1215 */
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07001216drm_public int drmFreeBufs(int fd, int count, int *list)
Daryll Straussb3a57661999-12-05 01:19:48 +00001217{
1218 drm_buf_free_t request;
1219
Daniel Vetterfd387942015-02-11 12:41:04 +01001220 memclear(request);
Daryll Straussb3a57661999-12-05 01:19:48 +00001221 request.count = count;
1222 request.list = list;
Keith Packard8b9ab102008-06-13 16:03:22 -07001223 if (drmIoctl(fd, DRM_IOCTL_FREE_BUFS, &request))
Jan Vesely50d3c852016-06-30 14:22:52 -04001224 return -errno;
Daryll Straussb3a57661999-12-05 01:19:48 +00001225 return 0;
1226}
1227
Jose Fonsecad2443b22003-05-27 00:37:33 +00001228
1229/**
1230 * Close the device.
1231 *
1232 * \param fd file descriptor.
1233 *
1234 * \internal
1235 * This function closes the file descriptor.
1236 */
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07001237drm_public int drmClose(int fd)
Daryll Straussb3a57661999-12-05 01:19:48 +00001238{
1239 unsigned long key = drmGetKeyFromFd(fd);
1240 drmHashEntry *entry = drmGetEntry(fd);
1241
1242 drmHashDestroy(entry->tagTable);
1243 entry->fd = 0;
1244 entry->f = NULL;
1245 entry->tagTable = NULL;
1246
1247 drmHashDelete(drmHashTable, key);
1248 drmFree(entry);
1249
1250 return close(fd);
1251}
1252
Jose Fonsecad2443b22003-05-27 00:37:33 +00001253
1254/**
1255 * Map a region of memory.
1256 *
1257 * \param fd file descriptor.
1258 * \param handle handle returned by drmAddMap().
1259 * \param size size in bytes. Must match the size used by drmAddMap().
1260 * \param address will contain the user-space virtual address where the mapping
1261 * begins.
1262 *
1263 * \return zero on success, or a negative value on failure.
Jan Vesely50d3c852016-06-30 14:22:52 -04001264 *
Jose Fonsecad2443b22003-05-27 00:37:33 +00001265 * \internal
1266 * This function is a wrapper for mmap().
1267 */
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07001268drm_public int drmMap(int fd, drm_handle_t handle, drmSize size,
1269 drmAddressPtr address)
Daryll Straussb3a57661999-12-05 01:19:48 +00001270{
Alan Hourihanec7558d82000-09-24 09:34:10 +00001271 static unsigned long pagesize_mask = 0;
1272
Brianccd7b6e2007-05-29 14:54:00 -06001273 if (fd < 0)
Jan Vesely50d3c852016-06-30 14:22:52 -04001274 return -EINVAL;
Alan Hourihanec7558d82000-09-24 09:34:10 +00001275
1276 if (!pagesize_mask)
Jan Vesely50d3c852016-06-30 14:22:52 -04001277 pagesize_mask = getpagesize() - 1;
Alan Hourihanec7558d82000-09-24 09:34:10 +00001278
1279 size = (size + pagesize_mask) & ~pagesize_mask;
1280
Emil Velikovfaf51d52014-09-07 20:03:05 +01001281 *address = drm_mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, handle);
Brianccd7b6e2007-05-29 14:54:00 -06001282 if (*address == MAP_FAILED)
Jan Vesely50d3c852016-06-30 14:22:52 -04001283 return -errno;
Daryll Straussb3a57661999-12-05 01:19:48 +00001284 return 0;
1285}
1286
Jose Fonsecad2443b22003-05-27 00:37:33 +00001287
1288/**
1289 * Unmap mappings obtained with drmMap().
1290 *
1291 * \param address address as given by drmMap().
1292 * \param size size in bytes. Must match the size used by drmMap().
Jan Vesely50d3c852016-06-30 14:22:52 -04001293 *
Jose Fonsecad2443b22003-05-27 00:37:33 +00001294 * \return zero on success, or a negative value on failure.
1295 *
1296 * \internal
Adam Jackson22e41ef2006-02-20 23:09:00 +00001297 * This function is a wrapper for munmap().
Jose Fonsecad2443b22003-05-27 00:37:33 +00001298 */
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07001299drm_public int drmUnmap(drmAddress address, drmSize size)
Daryll Straussb3a57661999-12-05 01:19:48 +00001300{
Emil Velikovfaf51d52014-09-07 20:03:05 +01001301 return drm_munmap(address, size);
Daryll Straussb3a57661999-12-05 01:19:48 +00001302}
1303
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07001304drm_public drmBufInfoPtr drmGetBufInfo(int fd)
Daryll Straussb3a57661999-12-05 01:19:48 +00001305{
1306 drm_buf_info_t info;
1307 drmBufInfoPtr retval;
1308 int i;
1309
Daniel Vetterfd387942015-02-11 12:41:04 +01001310 memclear(info);
Daryll Straussb3a57661999-12-05 01:19:48 +00001311
Keith Packard8b9ab102008-06-13 16:03:22 -07001312 if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info))
Jan Vesely50d3c852016-06-30 14:22:52 -04001313 return NULL;
Daryll Straussb3a57661999-12-05 01:19:48 +00001314
1315 if (info.count) {
Jan Vesely50d3c852016-06-30 14:22:52 -04001316 if (!(info.list = drmMalloc(info.count * sizeof(*info.list))))
1317 return NULL;
Gareth Hughes36047532001-02-15 08:12:14 +00001318
Jan Vesely50d3c852016-06-30 14:22:52 -04001319 if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info)) {
1320 drmFree(info.list);
1321 return NULL;
1322 }
Adam Jackson22e41ef2006-02-20 23:09:00 +00001323
Jan Vesely50d3c852016-06-30 14:22:52 -04001324 retval = drmMalloc(sizeof(*retval));
1325 retval->count = info.count;
1326 retval->list = drmMalloc(info.count * sizeof(*retval->list));
1327 for (i = 0; i < info.count; i++) {
1328 retval->list[i].count = info.list[i].count;
1329 retval->list[i].size = info.list[i].size;
1330 retval->list[i].low_mark = info.list[i].low_mark;
1331 retval->list[i].high_mark = info.list[i].high_mark;
1332 }
1333 drmFree(info.list);
1334 return retval;
Daryll Straussb3a57661999-12-05 01:19:48 +00001335 }
1336 return NULL;
1337}
1338
Jose Fonsecad2443b22003-05-27 00:37:33 +00001339/**
1340 * Map all DMA buffers into client-virtual space.
1341 *
1342 * \param fd file descriptor.
1343 *
1344 * \return a pointer to a ::drmBufMap structure.
1345 *
1346 * \note The client may not use these buffers until obtaining buffer indices
1347 * with drmDMA().
Jan Vesely50d3c852016-06-30 14:22:52 -04001348 *
Jose Fonsecad2443b22003-05-27 00:37:33 +00001349 * \internal
1350 * This function calls the DRM_IOCTL_MAP_BUFS ioctl and copies the returned
1351 * information about the buffers in a drm_buf_map structure into the
1352 * client-visible data structures.
Jan Vesely50d3c852016-06-30 14:22:52 -04001353 */
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07001354drm_public drmBufMapPtr drmMapBufs(int fd)
Daryll Straussb3a57661999-12-05 01:19:48 +00001355{
1356 drm_buf_map_t bufs;
1357 drmBufMapPtr retval;
1358 int i;
Gareth Hughes36047532001-02-15 08:12:14 +00001359
Daniel Vetterfd387942015-02-11 12:41:04 +01001360 memclear(bufs);
Keith Packard8b9ab102008-06-13 16:03:22 -07001361 if (drmIoctl(fd, DRM_IOCTL_MAP_BUFS, &bufs))
Jan Vesely50d3c852016-06-30 14:22:52 -04001362 return NULL;
Daryll Straussb3a57661999-12-05 01:19:48 +00001363
Brianccd7b6e2007-05-29 14:54:00 -06001364 if (!bufs.count)
Jan Vesely50d3c852016-06-30 14:22:52 -04001365 return NULL;
Jon Smirl8696e712004-07-07 04:36:36 +00001366
Jan Vesely50d3c852016-06-30 14:22:52 -04001367 if (!(bufs.list = drmMalloc(bufs.count * sizeof(*bufs.list))))
1368 return NULL;
Daryll Straussb3a57661999-12-05 01:19:48 +00001369
Jan Vesely50d3c852016-06-30 14:22:52 -04001370 if (drmIoctl(fd, DRM_IOCTL_MAP_BUFS, &bufs)) {
1371 drmFree(bufs.list);
1372 return NULL;
1373 }
Adam Jackson22e41ef2006-02-20 23:09:00 +00001374
Jan Vesely50d3c852016-06-30 14:22:52 -04001375 retval = drmMalloc(sizeof(*retval));
1376 retval->count = bufs.count;
1377 retval->list = drmMalloc(bufs.count * sizeof(*retval->list));
1378 for (i = 0; i < bufs.count; i++) {
1379 retval->list[i].idx = bufs.list[i].idx;
1380 retval->list[i].total = bufs.list[i].total;
1381 retval->list[i].used = 0;
1382 retval->list[i].address = bufs.list[i].address;
1383 }
Jon Smirl8696e712004-07-07 04:36:36 +00001384
Jan Vesely50d3c852016-06-30 14:22:52 -04001385 drmFree(bufs.list);
1386 return retval;
Daryll Straussb3a57661999-12-05 01:19:48 +00001387}
1388
Jose Fonsecad2443b22003-05-27 00:37:33 +00001389
1390/**
1391 * Unmap buffers allocated with drmMapBufs().
1392 *
1393 * \return zero on success, or negative value on failure.
1394 *
1395 * \internal
Jon Smirl8696e712004-07-07 04:36:36 +00001396 * Calls munmap() for every buffer stored in \p bufs and frees the
1397 * memory allocated by drmMapBufs().
Jose Fonsecad2443b22003-05-27 00:37:33 +00001398 */
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07001399drm_public int drmUnmapBufs(drmBufMapPtr bufs)
Daryll Straussb3a57661999-12-05 01:19:48 +00001400{
1401 int i;
Gareth Hughes36047532001-02-15 08:12:14 +00001402
Daryll Straussb3a57661999-12-05 01:19:48 +00001403 for (i = 0; i < bufs->count; i++) {
Jan Vesely50d3c852016-06-30 14:22:52 -04001404 drm_munmap(bufs->list[i].address, bufs->list[i].total);
Daryll Straussb3a57661999-12-05 01:19:48 +00001405 }
Jon Smirl8696e712004-07-07 04:36:36 +00001406
1407 drmFree(bufs->list);
1408 drmFree(bufs);
Daryll Straussb3a57661999-12-05 01:19:48 +00001409 return 0;
1410}
1411
Jose Fonsecad2443b22003-05-27 00:37:33 +00001412
Jan Vesely50d3c852016-06-30 14:22:52 -04001413#define DRM_DMA_RETRY 16
Gareth Hughes36047532001-02-15 08:12:14 +00001414
Jose Fonsecad2443b22003-05-27 00:37:33 +00001415/**
1416 * Reserve DMA buffers.
1417 *
1418 * \param fd file descriptor.
Jan Vesely50d3c852016-06-30 14:22:52 -04001419 * \param request
1420 *
Jose Fonsecad2443b22003-05-27 00:37:33 +00001421 * \return zero on success, or a negative value on failure.
1422 *
1423 * \internal
1424 * Assemble the arguments into a drm_dma structure and keeps issuing the
1425 * DRM_IOCTL_DMA ioctl until success or until maximum number of retries.
1426 */
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07001427drm_public int drmDMA(int fd, drmDMAReqPtr request)
Daryll Straussb3a57661999-12-05 01:19:48 +00001428{
1429 drm_dma_t dma;
Gareth Hughes36047532001-02-15 08:12:14 +00001430 int ret, i = 0;
Daryll Straussb3a57661999-12-05 01:19:48 +00001431
Daryll Straussb3a57661999-12-05 01:19:48 +00001432 dma.context = request->context;
1433 dma.send_count = request->send_count;
1434 dma.send_indices = request->send_list;
1435 dma.send_sizes = request->send_sizes;
1436 dma.flags = request->flags;
1437 dma.request_count = request->request_count;
1438 dma.request_size = request->request_size;
1439 dma.request_indices = request->request_list;
1440 dma.request_sizes = request->request_sizes;
Jon Smirl8696e712004-07-07 04:36:36 +00001441 dma.granted_count = 0;
Gareth Hughes36047532001-02-15 08:12:14 +00001442
1443 do {
Jan Vesely50d3c852016-06-30 14:22:52 -04001444 ret = ioctl( fd, DRM_IOCTL_DMA, &dma );
Gareth Hughes36047532001-02-15 08:12:14 +00001445 } while ( ret && errno == EAGAIN && i++ < DRM_DMA_RETRY );
1446
1447 if ( ret == 0 ) {
Jan Vesely50d3c852016-06-30 14:22:52 -04001448 request->granted_count = dma.granted_count;
1449 return 0;
Gareth Hughes36047532001-02-15 08:12:14 +00001450 } else {
Jan Vesely50d3c852016-06-30 14:22:52 -04001451 return -errno;
Gareth Hughes36047532001-02-15 08:12:14 +00001452 }
Daryll Straussb3a57661999-12-05 01:19:48 +00001453}
1454
Jose Fonsecad2443b22003-05-27 00:37:33 +00001455
1456/**
1457 * Obtain heavyweight hardware lock.
1458 *
1459 * \param fd file descriptor.
1460 * \param context context.
1461 * \param flags flags that determine the sate of the hardware when the function
1462 * returns.
Jan Vesely50d3c852016-06-30 14:22:52 -04001463 *
Jose Fonsecad2443b22003-05-27 00:37:33 +00001464 * \return always zero.
Jan Vesely50d3c852016-06-30 14:22:52 -04001465 *
Jose Fonsecad2443b22003-05-27 00:37:33 +00001466 * \internal
1467 * This function translates the arguments into a drm_lock structure and issue
1468 * the DRM_IOCTL_LOCK ioctl until the lock is successfully acquired.
1469 */
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07001470drm_public int drmGetLock(int fd, drm_context_t context, drmLockFlags flags)
Daryll Straussb3a57661999-12-05 01:19:48 +00001471{
1472 drm_lock_t lock;
1473
Daniel Vetterfd387942015-02-11 12:41:04 +01001474 memclear(lock);
Daryll Straussb3a57661999-12-05 01:19:48 +00001475 lock.context = context;
1476 lock.flags = 0;
1477 if (flags & DRM_LOCK_READY) lock.flags |= _DRM_LOCK_READY;
1478 if (flags & DRM_LOCK_QUIESCENT) lock.flags |= _DRM_LOCK_QUIESCENT;
1479 if (flags & DRM_LOCK_FLUSH) lock.flags |= _DRM_LOCK_FLUSH;
1480 if (flags & DRM_LOCK_FLUSH_ALL) lock.flags |= _DRM_LOCK_FLUSH_ALL;
1481 if (flags & DRM_HALT_ALL_QUEUES) lock.flags |= _DRM_HALT_ALL_QUEUES;
1482 if (flags & DRM_HALT_CUR_QUEUES) lock.flags |= _DRM_HALT_CUR_QUEUES;
Gareth Hughes36047532001-02-15 08:12:14 +00001483
Keith Packard8b9ab102008-06-13 16:03:22 -07001484 while (drmIoctl(fd, DRM_IOCTL_LOCK, &lock))
Jan Vesely50d3c852016-06-30 14:22:52 -04001485 ;
Daryll Straussb3a57661999-12-05 01:19:48 +00001486 return 0;
1487}
1488
Jose Fonsecad2443b22003-05-27 00:37:33 +00001489/**
1490 * Release the hardware lock.
1491 *
1492 * \param fd file descriptor.
1493 * \param context context.
Jan Vesely50d3c852016-06-30 14:22:52 -04001494 *
Jose Fonsecad2443b22003-05-27 00:37:33 +00001495 * \return zero on success, or a negative value on failure.
Jan Vesely50d3c852016-06-30 14:22:52 -04001496 *
Jose Fonsecad2443b22003-05-27 00:37:33 +00001497 * \internal
1498 * This function is a wrapper around the DRM_IOCTL_UNLOCK ioctl, passing the
1499 * argument in a drm_lock structure.
1500 */
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07001501drm_public int drmUnlock(int fd, drm_context_t context)
Daryll Straussb3a57661999-12-05 01:19:48 +00001502{
1503 drm_lock_t lock;
1504
Daniel Vetterfd387942015-02-11 12:41:04 +01001505 memclear(lock);
Daryll Straussb3a57661999-12-05 01:19:48 +00001506 lock.context = context;
Keith Packard8b9ab102008-06-13 16:03:22 -07001507 return drmIoctl(fd, DRM_IOCTL_UNLOCK, &lock);
Daryll Straussb3a57661999-12-05 01:19:48 +00001508}
1509
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07001510drm_public drm_context_t *drmGetReservedContextList(int fd, int *count)
Daryll Straussb3a57661999-12-05 01:19:48 +00001511{
1512 drm_ctx_res_t res;
1513 drm_ctx_t *list;
Jon Smirl8696e712004-07-07 04:36:36 +00001514 drm_context_t * retval;
Daryll Straussb3a57661999-12-05 01:19:48 +00001515 int i;
1516
Daniel Vetterfd387942015-02-11 12:41:04 +01001517 memclear(res);
Keith Packard8b9ab102008-06-13 16:03:22 -07001518 if (drmIoctl(fd, DRM_IOCTL_RES_CTX, &res))
Jan Vesely50d3c852016-06-30 14:22:52 -04001519 return NULL;
Daryll Straussb3a57661999-12-05 01:19:48 +00001520
Brianccd7b6e2007-05-29 14:54:00 -06001521 if (!res.count)
Jan Vesely50d3c852016-06-30 14:22:52 -04001522 return NULL;
Daryll Straussb3a57661999-12-05 01:19:48 +00001523
Brianccd7b6e2007-05-29 14:54:00 -06001524 if (!(list = drmMalloc(res.count * sizeof(*list))))
Jan Vesely50d3c852016-06-30 14:22:52 -04001525 return NULL;
Seung-Woo Kim7b806e82017-03-27 11:09:29 +09001526 if (!(retval = drmMalloc(res.count * sizeof(*retval))))
1527 goto err_free_list;
Daryll Straussb3a57661999-12-05 01:19:48 +00001528
1529 res.contexts = list;
Keith Packard8b9ab102008-06-13 16:03:22 -07001530 if (drmIoctl(fd, DRM_IOCTL_RES_CTX, &res))
Seung-Woo Kim7b806e82017-03-27 11:09:29 +09001531 goto err_free_context;
Daryll Straussb3a57661999-12-05 01:19:48 +00001532
Brianccd7b6e2007-05-29 14:54:00 -06001533 for (i = 0; i < res.count; i++)
Jan Vesely50d3c852016-06-30 14:22:52 -04001534 retval[i] = list[i].handle;
Daryll Straussb3a57661999-12-05 01:19:48 +00001535 drmFree(list);
1536
1537 *count = res.count;
1538 return retval;
Seung-Woo Kim7b806e82017-03-27 11:09:29 +09001539
1540err_free_list:
1541 drmFree(list);
1542err_free_context:
1543 drmFree(retval);
1544 return NULL;
Daryll Straussb3a57661999-12-05 01:19:48 +00001545}
1546
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07001547drm_public void drmFreeReservedContextList(drm_context_t *pt)
Daryll Straussb3a57661999-12-05 01:19:48 +00001548{
1549 drmFree(pt);
1550}
1551
Jose Fonsecad2443b22003-05-27 00:37:33 +00001552/**
1553 * Create context.
1554 *
1555 * Used by the X server during GLXContext initialization. This causes
1556 * per-context kernel-level resources to be allocated.
1557 *
1558 * \param fd file descriptor.
1559 * \param handle is set on success. To be used by the client when requesting DMA
1560 * dispatch with drmDMA().
Jan Vesely50d3c852016-06-30 14:22:52 -04001561 *
Jose Fonsecad2443b22003-05-27 00:37:33 +00001562 * \return zero on success, or a negative value on failure.
Jan Vesely50d3c852016-06-30 14:22:52 -04001563 *
Jose Fonsecad2443b22003-05-27 00:37:33 +00001564 * \note May only be called by root.
Jan Vesely50d3c852016-06-30 14:22:52 -04001565 *
Jose Fonsecad2443b22003-05-27 00:37:33 +00001566 * \internal
1567 * This function is a wrapper around the DRM_IOCTL_ADD_CTX ioctl, passing the
1568 * argument in a drm_ctx structure.
1569 */
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07001570drm_public int drmCreateContext(int fd, drm_context_t *handle)
Daryll Straussb3a57661999-12-05 01:19:48 +00001571{
1572 drm_ctx_t ctx;
1573
Daniel Vetterfd387942015-02-11 12:41:04 +01001574 memclear(ctx);
Keith Packard8b9ab102008-06-13 16:03:22 -07001575 if (drmIoctl(fd, DRM_IOCTL_ADD_CTX, &ctx))
Jan Vesely50d3c852016-06-30 14:22:52 -04001576 return -errno;
Daryll Straussb3a57661999-12-05 01:19:48 +00001577 *handle = ctx.handle;
1578 return 0;
1579}
1580
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07001581drm_public int drmSwitchToContext(int fd, drm_context_t context)
Daryll Straussb3a57661999-12-05 01:19:48 +00001582{
1583 drm_ctx_t ctx;
1584
Daniel Vetterfd387942015-02-11 12:41:04 +01001585 memclear(ctx);
Daryll Straussb3a57661999-12-05 01:19:48 +00001586 ctx.handle = context;
Keith Packard8b9ab102008-06-13 16:03:22 -07001587 if (drmIoctl(fd, DRM_IOCTL_SWITCH_CTX, &ctx))
Jan Vesely50d3c852016-06-30 14:22:52 -04001588 return -errno;
Daryll Straussb3a57661999-12-05 01:19:48 +00001589 return 0;
1590}
1591
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07001592drm_public int drmSetContextFlags(int fd, drm_context_t context,
1593 drm_context_tFlags flags)
Daryll Straussb3a57661999-12-05 01:19:48 +00001594{
1595 drm_ctx_t ctx;
1596
Adam Jackson22e41ef2006-02-20 23:09:00 +00001597 /*
1598 * Context preserving means that no context switches are done between DMA
1599 * buffers from one context and the next. This is suitable for use in the
1600 * X server (which promises to maintain hardware context), or in the
1601 * client-side library when buffers are swapped on behalf of two threads.
1602 */
Daniel Vetterfd387942015-02-11 12:41:04 +01001603 memclear(ctx);
Daryll Straussb3a57661999-12-05 01:19:48 +00001604 ctx.handle = context;
Brianccd7b6e2007-05-29 14:54:00 -06001605 if (flags & DRM_CONTEXT_PRESERVED)
Jan Vesely50d3c852016-06-30 14:22:52 -04001606 ctx.flags |= _DRM_CONTEXT_PRESERVED;
Brianccd7b6e2007-05-29 14:54:00 -06001607 if (flags & DRM_CONTEXT_2DONLY)
Jan Vesely50d3c852016-06-30 14:22:52 -04001608 ctx.flags |= _DRM_CONTEXT_2DONLY;
Keith Packard8b9ab102008-06-13 16:03:22 -07001609 if (drmIoctl(fd, DRM_IOCTL_MOD_CTX, &ctx))
Jan Vesely50d3c852016-06-30 14:22:52 -04001610 return -errno;
Daryll Straussb3a57661999-12-05 01:19:48 +00001611 return 0;
1612}
1613
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07001614drm_public int drmGetContextFlags(int fd, drm_context_t context,
1615 drm_context_tFlagsPtr flags)
Daryll Straussb3a57661999-12-05 01:19:48 +00001616{
1617 drm_ctx_t ctx;
1618
Daniel Vetterfd387942015-02-11 12:41:04 +01001619 memclear(ctx);
Daryll Straussb3a57661999-12-05 01:19:48 +00001620 ctx.handle = context;
Keith Packard8b9ab102008-06-13 16:03:22 -07001621 if (drmIoctl(fd, DRM_IOCTL_GET_CTX, &ctx))
Jan Vesely50d3c852016-06-30 14:22:52 -04001622 return -errno;
Daryll Straussb3a57661999-12-05 01:19:48 +00001623 *flags = 0;
Brianccd7b6e2007-05-29 14:54:00 -06001624 if (ctx.flags & _DRM_CONTEXT_PRESERVED)
Jan Vesely50d3c852016-06-30 14:22:52 -04001625 *flags |= DRM_CONTEXT_PRESERVED;
Brianccd7b6e2007-05-29 14:54:00 -06001626 if (ctx.flags & _DRM_CONTEXT_2DONLY)
Jan Vesely50d3c852016-06-30 14:22:52 -04001627 *flags |= DRM_CONTEXT_2DONLY;
Daryll Straussb3a57661999-12-05 01:19:48 +00001628 return 0;
1629}
Gareth Hughes36047532001-02-15 08:12:14 +00001630
Jose Fonsecad2443b22003-05-27 00:37:33 +00001631/**
1632 * Destroy context.
1633 *
1634 * Free any kernel-level resources allocated with drmCreateContext() associated
1635 * with the context.
Jan Vesely50d3c852016-06-30 14:22:52 -04001636 *
Jose Fonsecad2443b22003-05-27 00:37:33 +00001637 * \param fd file descriptor.
1638 * \param handle handle given by drmCreateContext().
Jan Vesely50d3c852016-06-30 14:22:52 -04001639 *
Jose Fonsecad2443b22003-05-27 00:37:33 +00001640 * \return zero on success, or a negative value on failure.
Jan Vesely50d3c852016-06-30 14:22:52 -04001641 *
Jose Fonsecad2443b22003-05-27 00:37:33 +00001642 * \note May only be called by root.
Jan Vesely50d3c852016-06-30 14:22:52 -04001643 *
Jose Fonsecad2443b22003-05-27 00:37:33 +00001644 * \internal
1645 * This function is a wrapper around the DRM_IOCTL_RM_CTX ioctl, passing the
1646 * argument in a drm_ctx structure.
1647 */
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07001648drm_public int drmDestroyContext(int fd, drm_context_t handle)
Daryll Straussb3a57661999-12-05 01:19:48 +00001649{
1650 drm_ctx_t ctx;
Daniel Vetterfd387942015-02-11 12:41:04 +01001651
1652 memclear(ctx);
Daryll Straussb3a57661999-12-05 01:19:48 +00001653 ctx.handle = handle;
Keith Packard8b9ab102008-06-13 16:03:22 -07001654 if (drmIoctl(fd, DRM_IOCTL_RM_CTX, &ctx))
Jan Vesely50d3c852016-06-30 14:22:52 -04001655 return -errno;
Daryll Straussb3a57661999-12-05 01:19:48 +00001656 return 0;
1657}
1658
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07001659drm_public int drmCreateDrawable(int fd, drm_drawable_t *handle)
Daryll Straussb3a57661999-12-05 01:19:48 +00001660{
1661 drm_draw_t draw;
Daniel Vetterfd387942015-02-11 12:41:04 +01001662
1663 memclear(draw);
Keith Packard8b9ab102008-06-13 16:03:22 -07001664 if (drmIoctl(fd, DRM_IOCTL_ADD_DRAW, &draw))
Jan Vesely50d3c852016-06-30 14:22:52 -04001665 return -errno;
Daryll Straussb3a57661999-12-05 01:19:48 +00001666 *handle = draw.handle;
1667 return 0;
1668}
1669
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07001670drm_public int drmDestroyDrawable(int fd, drm_drawable_t handle)
Daryll Straussb3a57661999-12-05 01:19:48 +00001671{
1672 drm_draw_t draw;
Daniel Vetterfd387942015-02-11 12:41:04 +01001673
1674 memclear(draw);
Daryll Straussb3a57661999-12-05 01:19:48 +00001675 draw.handle = handle;
Keith Packard8b9ab102008-06-13 16:03:22 -07001676 if (drmIoctl(fd, DRM_IOCTL_RM_DRAW, &draw))
Jan Vesely50d3c852016-06-30 14:22:52 -04001677 return -errno;
Daryll Straussb3a57661999-12-05 01:19:48 +00001678 return 0;
1679}
1680
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07001681drm_public int drmUpdateDrawableInfo(int fd, drm_drawable_t handle,
1682 drm_drawable_info_type_t type,
1683 unsigned int num, void *data)
Michel Dänzer9810ec22006-08-22 16:40:07 +02001684{
1685 drm_update_draw_t update;
1686
Daniel Vetterfd387942015-02-11 12:41:04 +01001687 memclear(update);
Michel Dänzer9810ec22006-08-22 16:40:07 +02001688 update.handle = handle;
1689 update.type = type;
1690 update.num = num;
1691 update.data = (unsigned long long)(unsigned long)data;
1692
Keith Packard8b9ab102008-06-13 16:03:22 -07001693 if (drmIoctl(fd, DRM_IOCTL_UPDATE_DRAW, &update))
Jan Vesely50d3c852016-06-30 14:22:52 -04001694 return -errno;
Michel Dänzer9810ec22006-08-22 16:40:07 +02001695
1696 return 0;
1697}
1698
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07001699drm_public int drmCrtcGetSequence(int fd, uint32_t crtcId, uint64_t *sequence,
1700 uint64_t *ns)
Keith Packardd4331dd2017-07-01 00:43:15 -07001701{
1702 struct drm_crtc_get_sequence get_seq;
1703 int ret;
1704
1705 memclear(get_seq);
1706 get_seq.crtc_id = crtcId;
1707 ret = drmIoctl(fd, DRM_IOCTL_CRTC_GET_SEQUENCE, &get_seq);
1708 if (ret)
1709 return ret;
1710
1711 if (sequence)
1712 *sequence = get_seq.sequence;
1713 if (ns)
1714 *ns = get_seq.sequence_ns;
1715 return 0;
1716}
1717
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07001718drm_public int drmCrtcQueueSequence(int fd, uint32_t crtcId, uint32_t flags,
1719 uint64_t sequence,
1720 uint64_t *sequence_queued,
1721 uint64_t user_data)
Keith Packardd4331dd2017-07-01 00:43:15 -07001722{
1723 struct drm_crtc_queue_sequence queue_seq;
1724 int ret;
1725
1726 memclear(queue_seq);
1727 queue_seq.crtc_id = crtcId;
1728 queue_seq.flags = flags;
1729 queue_seq.sequence = sequence;
1730 queue_seq.user_data = user_data;
1731
1732 ret = drmIoctl(fd, DRM_IOCTL_CRTC_QUEUE_SEQUENCE, &queue_seq);
1733 if (ret == 0 && sequence_queued)
1734 *sequence_queued = queue_seq.sequence;
1735
1736 return ret;
1737}
1738
Jose Fonsecad2443b22003-05-27 00:37:33 +00001739/**
1740 * Acquire the AGP device.
1741 *
1742 * Must be called before any of the other AGP related calls.
1743 *
1744 * \param fd file descriptor.
Jan Vesely50d3c852016-06-30 14:22:52 -04001745 *
Jose Fonsecad2443b22003-05-27 00:37:33 +00001746 * \return zero on success, or a negative value on failure.
Jan Vesely50d3c852016-06-30 14:22:52 -04001747 *
Jose Fonsecad2443b22003-05-27 00:37:33 +00001748 * \internal
1749 * This function is a wrapper around the DRM_IOCTL_AGP_ACQUIRE ioctl.
1750 */
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07001751drm_public int drmAgpAcquire(int fd)
Jeff Hartmannba1b1ae2000-04-04 22:08:14 +00001752{
Keith Packard8b9ab102008-06-13 16:03:22 -07001753 if (drmIoctl(fd, DRM_IOCTL_AGP_ACQUIRE, NULL))
Jan Vesely50d3c852016-06-30 14:22:52 -04001754 return -errno;
Jeff Hartmannba1b1ae2000-04-04 22:08:14 +00001755 return 0;
1756}
1757
Jose Fonsecad2443b22003-05-27 00:37:33 +00001758
1759/**
1760 * Release the AGP device.
1761 *
1762 * \param fd file descriptor.
Jan Vesely50d3c852016-06-30 14:22:52 -04001763 *
Jose Fonsecad2443b22003-05-27 00:37:33 +00001764 * \return zero on success, or a negative value on failure.
Jan Vesely50d3c852016-06-30 14:22:52 -04001765 *
Jose Fonsecad2443b22003-05-27 00:37:33 +00001766 * \internal
1767 * This function is a wrapper around the DRM_IOCTL_AGP_RELEASE ioctl.
1768 */
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07001769drm_public int drmAgpRelease(int fd)
Jeff Hartmannba1b1ae2000-04-04 22:08:14 +00001770{
Keith Packard8b9ab102008-06-13 16:03:22 -07001771 if (drmIoctl(fd, DRM_IOCTL_AGP_RELEASE, NULL))
Jan Vesely50d3c852016-06-30 14:22:52 -04001772 return -errno;
Jeff Hartmannba1b1ae2000-04-04 22:08:14 +00001773 return 0;
1774}
1775
Jose Fonsecad2443b22003-05-27 00:37:33 +00001776
1777/**
1778 * Set the AGP mode.
1779 *
1780 * \param fd file descriptor.
1781 * \param mode AGP mode.
Jan Vesely50d3c852016-06-30 14:22:52 -04001782 *
Jose Fonsecad2443b22003-05-27 00:37:33 +00001783 * \return zero on success, or a negative value on failure.
Jan Vesely50d3c852016-06-30 14:22:52 -04001784 *
Jose Fonsecad2443b22003-05-27 00:37:33 +00001785 * \internal
1786 * This function is a wrapper around the DRM_IOCTL_AGP_ENABLE ioctl, passing the
1787 * argument in a drm_agp_mode structure.
1788 */
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07001789drm_public int drmAgpEnable(int fd, unsigned long mode)
Jeff Hartmannba1b1ae2000-04-04 22:08:14 +00001790{
1791 drm_agp_mode_t m;
1792
Connor Behan14900552015-03-24 13:53:51 -04001793 memclear(m);
Jeff Hartmannba1b1ae2000-04-04 22:08:14 +00001794 m.mode = mode;
Keith Packard8b9ab102008-06-13 16:03:22 -07001795 if (drmIoctl(fd, DRM_IOCTL_AGP_ENABLE, &m))
Jan Vesely50d3c852016-06-30 14:22:52 -04001796 return -errno;
Jeff Hartmannba1b1ae2000-04-04 22:08:14 +00001797 return 0;
1798}
1799
Jose Fonsecad2443b22003-05-27 00:37:33 +00001800
1801/**
1802 * Allocate a chunk of AGP memory.
1803 *
1804 * \param fd file descriptor.
1805 * \param size requested memory size in bytes. Will be rounded to page boundary.
1806 * \param type type of memory to allocate.
1807 * \param address if not zero, will be set to the physical address of the
1808 * allocated memory.
1809 * \param handle on success will be set to a handle of the allocated memory.
Jan Vesely50d3c852016-06-30 14:22:52 -04001810 *
Jose Fonsecad2443b22003-05-27 00:37:33 +00001811 * \return zero on success, or a negative value on failure.
Jan Vesely50d3c852016-06-30 14:22:52 -04001812 *
Jose Fonsecad2443b22003-05-27 00:37:33 +00001813 * \internal
1814 * This function is a wrapper around the DRM_IOCTL_AGP_ALLOC ioctl, passing the
1815 * arguments in a drm_agp_buffer structure.
1816 */
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07001817drm_public int drmAgpAlloc(int fd, unsigned long size, unsigned long type,
1818 unsigned long *address, drm_handle_t *handle)
Jeff Hartmannba1b1ae2000-04-04 22:08:14 +00001819{
1820 drm_agp_buffer_t b;
Alan Hourihaneb0a92852003-09-24 14:39:25 +00001821
Daniel Vetterfd387942015-02-11 12:41:04 +01001822 memclear(b);
Alan Hourihaneb0a92852003-09-24 14:39:25 +00001823 *handle = DRM_AGP_NO_HANDLE;
Jeff Hartmannba1b1ae2000-04-04 22:08:14 +00001824 b.size = size;
Jeff Hartmannba1b1ae2000-04-04 22:08:14 +00001825 b.type = type;
Keith Packard8b9ab102008-06-13 16:03:22 -07001826 if (drmIoctl(fd, DRM_IOCTL_AGP_ALLOC, &b))
Jan Vesely50d3c852016-06-30 14:22:52 -04001827 return -errno;
Brianccd7b6e2007-05-29 14:54:00 -06001828 if (address != 0UL)
Jan Vesely50d3c852016-06-30 14:22:52 -04001829 *address = b.physical;
Jeff Hartmannba1b1ae2000-04-04 22:08:14 +00001830 *handle = b.handle;
1831 return 0;
1832}
1833
Jose Fonsecad2443b22003-05-27 00:37:33 +00001834
1835/**
1836 * Free a chunk of AGP memory.
1837 *
1838 * \param fd file descriptor.
1839 * \param handle handle to the allocated memory, as given by drmAgpAllocate().
Jan Vesely50d3c852016-06-30 14:22:52 -04001840 *
Jose Fonsecad2443b22003-05-27 00:37:33 +00001841 * \return zero on success, or a negative value on failure.
Jan Vesely50d3c852016-06-30 14:22:52 -04001842 *
Jose Fonsecad2443b22003-05-27 00:37:33 +00001843 * \internal
1844 * This function is a wrapper around the DRM_IOCTL_AGP_FREE ioctl, passing the
1845 * argument in a drm_agp_buffer structure.
1846 */
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07001847drm_public int drmAgpFree(int fd, drm_handle_t handle)
Jeff Hartmannba1b1ae2000-04-04 22:08:14 +00001848{
1849 drm_agp_buffer_t b;
1850
Daniel Vetterfd387942015-02-11 12:41:04 +01001851 memclear(b);
Jeff Hartmannba1b1ae2000-04-04 22:08:14 +00001852 b.handle = handle;
Keith Packard8b9ab102008-06-13 16:03:22 -07001853 if (drmIoctl(fd, DRM_IOCTL_AGP_FREE, &b))
Jan Vesely50d3c852016-06-30 14:22:52 -04001854 return -errno;
Jeff Hartmannba1b1ae2000-04-04 22:08:14 +00001855 return 0;
1856}
1857
Jose Fonsecad2443b22003-05-27 00:37:33 +00001858
1859/**
1860 * Bind a chunk of AGP memory.
1861 *
1862 * \param fd file descriptor.
1863 * \param handle handle to the allocated memory, as given by drmAgpAllocate().
1864 * \param offset offset in bytes. It will round to page boundary.
Jan Vesely50d3c852016-06-30 14:22:52 -04001865 *
Jose Fonsecad2443b22003-05-27 00:37:33 +00001866 * \return zero on success, or a negative value on failure.
Jan Vesely50d3c852016-06-30 14:22:52 -04001867 *
Jose Fonsecad2443b22003-05-27 00:37:33 +00001868 * \internal
1869 * This function is a wrapper around the DRM_IOCTL_AGP_BIND ioctl, passing the
1870 * argument in a drm_agp_binding structure.
1871 */
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07001872drm_public int drmAgpBind(int fd, drm_handle_t handle, unsigned long offset)
Jeff Hartmannba1b1ae2000-04-04 22:08:14 +00001873{
1874 drm_agp_binding_t b;
1875
Daniel Vetterfd387942015-02-11 12:41:04 +01001876 memclear(b);
Jeff Hartmannba1b1ae2000-04-04 22:08:14 +00001877 b.handle = handle;
1878 b.offset = offset;
Keith Packard8b9ab102008-06-13 16:03:22 -07001879 if (drmIoctl(fd, DRM_IOCTL_AGP_BIND, &b))
Jan Vesely50d3c852016-06-30 14:22:52 -04001880 return -errno;
Jeff Hartmannba1b1ae2000-04-04 22:08:14 +00001881 return 0;
1882}
1883
Jose Fonsecad2443b22003-05-27 00:37:33 +00001884
1885/**
1886 * Unbind a chunk of AGP memory.
1887 *
1888 * \param fd file descriptor.
1889 * \param handle handle to the allocated memory, as given by drmAgpAllocate().
Jan Vesely50d3c852016-06-30 14:22:52 -04001890 *
Jose Fonsecad2443b22003-05-27 00:37:33 +00001891 * \return zero on success, or a negative value on failure.
Jan Vesely50d3c852016-06-30 14:22:52 -04001892 *
Jose Fonsecad2443b22003-05-27 00:37:33 +00001893 * \internal
1894 * This function is a wrapper around the DRM_IOCTL_AGP_UNBIND ioctl, passing
1895 * the argument in a drm_agp_binding structure.
1896 */
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07001897drm_public int drmAgpUnbind(int fd, drm_handle_t handle)
Jeff Hartmannba1b1ae2000-04-04 22:08:14 +00001898{
1899 drm_agp_binding_t b;
1900
Daniel Vetterfd387942015-02-11 12:41:04 +01001901 memclear(b);
Jeff Hartmannba1b1ae2000-04-04 22:08:14 +00001902 b.handle = handle;
Keith Packard8b9ab102008-06-13 16:03:22 -07001903 if (drmIoctl(fd, DRM_IOCTL_AGP_UNBIND, &b))
Jan Vesely50d3c852016-06-30 14:22:52 -04001904 return -errno;
Jeff Hartmannba1b1ae2000-04-04 22:08:14 +00001905 return 0;
1906}
1907
Jose Fonsecad2443b22003-05-27 00:37:33 +00001908
1909/**
1910 * Get AGP driver major version number.
1911 *
1912 * \param fd file descriptor.
Jan Vesely50d3c852016-06-30 14:22:52 -04001913 *
Jose Fonsecad2443b22003-05-27 00:37:33 +00001914 * \return major version number on success, or a negative value on failure..
Jan Vesely50d3c852016-06-30 14:22:52 -04001915 *
Jose Fonsecad2443b22003-05-27 00:37:33 +00001916 * \internal
1917 * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
1918 * necessary information in a drm_agp_info structure.
1919 */
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07001920drm_public int drmAgpVersionMajor(int fd)
Jeff Hartmannba1b1ae2000-04-04 22:08:14 +00001921{
1922 drm_agp_info_t i;
1923
Daniel Vetterfd387942015-02-11 12:41:04 +01001924 memclear(i);
1925
Keith Packard8b9ab102008-06-13 16:03:22 -07001926 if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
Jan Vesely50d3c852016-06-30 14:22:52 -04001927 return -errno;
Jeff Hartmannba1b1ae2000-04-04 22:08:14 +00001928 return i.agp_version_major;
1929}
1930
Jose Fonsecad2443b22003-05-27 00:37:33 +00001931
1932/**
1933 * Get AGP driver minor version number.
1934 *
1935 * \param fd file descriptor.
Jan Vesely50d3c852016-06-30 14:22:52 -04001936 *
Jose Fonsecad2443b22003-05-27 00:37:33 +00001937 * \return minor version number on success, or a negative value on failure.
Jan Vesely50d3c852016-06-30 14:22:52 -04001938 *
Jose Fonsecad2443b22003-05-27 00:37:33 +00001939 * \internal
1940 * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
1941 * necessary information in a drm_agp_info structure.
1942 */
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07001943drm_public int drmAgpVersionMinor(int fd)
Jeff Hartmannba1b1ae2000-04-04 22:08:14 +00001944{
1945 drm_agp_info_t i;
1946
Daniel Vetterfd387942015-02-11 12:41:04 +01001947 memclear(i);
1948
Keith Packard8b9ab102008-06-13 16:03:22 -07001949 if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
Jan Vesely50d3c852016-06-30 14:22:52 -04001950 return -errno;
Jeff Hartmannba1b1ae2000-04-04 22:08:14 +00001951 return i.agp_version_minor;
1952}
1953
Jose Fonsecad2443b22003-05-27 00:37:33 +00001954
1955/**
1956 * Get AGP mode.
1957 *
1958 * \param fd file descriptor.
Jan Vesely50d3c852016-06-30 14:22:52 -04001959 *
Jose Fonsecad2443b22003-05-27 00:37:33 +00001960 * \return mode on success, or zero on failure.
Jan Vesely50d3c852016-06-30 14:22:52 -04001961 *
Jose Fonsecad2443b22003-05-27 00:37:33 +00001962 * \internal
1963 * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
1964 * necessary information in a drm_agp_info structure.
1965 */
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07001966drm_public unsigned long drmAgpGetMode(int fd)
Jeff Hartmannba1b1ae2000-04-04 22:08:14 +00001967{
1968 drm_agp_info_t i;
1969
Daniel Vetterfd387942015-02-11 12:41:04 +01001970 memclear(i);
1971
Keith Packard8b9ab102008-06-13 16:03:22 -07001972 if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
Jan Vesely50d3c852016-06-30 14:22:52 -04001973 return 0;
Jeff Hartmannba1b1ae2000-04-04 22:08:14 +00001974 return i.mode;
1975}
1976
Jose Fonsecad2443b22003-05-27 00:37:33 +00001977
1978/**
1979 * Get AGP aperture base.
1980 *
1981 * \param fd file descriptor.
Jan Vesely50d3c852016-06-30 14:22:52 -04001982 *
Jose Fonsecad2443b22003-05-27 00:37:33 +00001983 * \return aperture base on success, zero on failure.
Jan Vesely50d3c852016-06-30 14:22:52 -04001984 *
Jose Fonsecad2443b22003-05-27 00:37:33 +00001985 * \internal
1986 * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
1987 * necessary information in a drm_agp_info structure.
1988 */
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07001989drm_public unsigned long drmAgpBase(int fd)
Jeff Hartmannba1b1ae2000-04-04 22:08:14 +00001990{
1991 drm_agp_info_t i;
1992
Daniel Vetterfd387942015-02-11 12:41:04 +01001993 memclear(i);
1994
Keith Packard8b9ab102008-06-13 16:03:22 -07001995 if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
Jan Vesely50d3c852016-06-30 14:22:52 -04001996 return 0;
Jeff Hartmannba1b1ae2000-04-04 22:08:14 +00001997 return i.aperture_base;
1998}
1999
Jose Fonsecad2443b22003-05-27 00:37:33 +00002000
2001/**
2002 * Get AGP aperture size.
2003 *
2004 * \param fd file descriptor.
Jan Vesely50d3c852016-06-30 14:22:52 -04002005 *
Jose Fonsecad2443b22003-05-27 00:37:33 +00002006 * \return aperture size on success, zero on failure.
Jan Vesely50d3c852016-06-30 14:22:52 -04002007 *
Jose Fonsecad2443b22003-05-27 00:37:33 +00002008 * \internal
2009 * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
2010 * necessary information in a drm_agp_info structure.
2011 */
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07002012drm_public unsigned long drmAgpSize(int fd)
Jeff Hartmannba1b1ae2000-04-04 22:08:14 +00002013{
2014 drm_agp_info_t i;
2015
Daniel Vetterfd387942015-02-11 12:41:04 +01002016 memclear(i);
2017
Keith Packard8b9ab102008-06-13 16:03:22 -07002018 if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
Jan Vesely50d3c852016-06-30 14:22:52 -04002019 return 0;
Jeff Hartmannba1b1ae2000-04-04 22:08:14 +00002020 return i.aperture_size;
2021}
2022
Jose Fonsecad2443b22003-05-27 00:37:33 +00002023
2024/**
2025 * Get used AGP memory.
2026 *
2027 * \param fd file descriptor.
Jan Vesely50d3c852016-06-30 14:22:52 -04002028 *
Jose Fonsecad2443b22003-05-27 00:37:33 +00002029 * \return memory used on success, or zero on failure.
Jan Vesely50d3c852016-06-30 14:22:52 -04002030 *
Jose Fonsecad2443b22003-05-27 00:37:33 +00002031 * \internal
2032 * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
2033 * necessary information in a drm_agp_info structure.
2034 */
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07002035drm_public unsigned long drmAgpMemoryUsed(int fd)
Jeff Hartmannba1b1ae2000-04-04 22:08:14 +00002036{
2037 drm_agp_info_t i;
2038
Daniel Vetterfd387942015-02-11 12:41:04 +01002039 memclear(i);
2040
Keith Packard8b9ab102008-06-13 16:03:22 -07002041 if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
Jan Vesely50d3c852016-06-30 14:22:52 -04002042 return 0;
Jeff Hartmannba1b1ae2000-04-04 22:08:14 +00002043 return i.memory_used;
2044}
2045
Jose Fonsecad2443b22003-05-27 00:37:33 +00002046
2047/**
2048 * Get available AGP memory.
2049 *
2050 * \param fd file descriptor.
Jan Vesely50d3c852016-06-30 14:22:52 -04002051 *
Jose Fonsecad2443b22003-05-27 00:37:33 +00002052 * \return memory available on success, or zero on failure.
Jan Vesely50d3c852016-06-30 14:22:52 -04002053 *
Jose Fonsecad2443b22003-05-27 00:37:33 +00002054 * \internal
2055 * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
2056 * necessary information in a drm_agp_info structure.
2057 */
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07002058drm_public unsigned long drmAgpMemoryAvail(int fd)
Jeff Hartmannba1b1ae2000-04-04 22:08:14 +00002059{
2060 drm_agp_info_t i;
2061
Daniel Vetterfd387942015-02-11 12:41:04 +01002062 memclear(i);
2063
Keith Packard8b9ab102008-06-13 16:03:22 -07002064 if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
Jan Vesely50d3c852016-06-30 14:22:52 -04002065 return 0;
Jeff Hartmannba1b1ae2000-04-04 22:08:14 +00002066 return i.memory_allowed;
2067}
2068
Jose Fonsecad2443b22003-05-27 00:37:33 +00002069
2070/**
2071 * Get hardware vendor ID.
2072 *
2073 * \param fd file descriptor.
Jan Vesely50d3c852016-06-30 14:22:52 -04002074 *
Jose Fonsecad2443b22003-05-27 00:37:33 +00002075 * \return vendor ID on success, or zero on failure.
Jan Vesely50d3c852016-06-30 14:22:52 -04002076 *
Jose Fonsecad2443b22003-05-27 00:37:33 +00002077 * \internal
2078 * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
2079 * necessary information in a drm_agp_info structure.
2080 */
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07002081drm_public unsigned int drmAgpVendorId(int fd)
Jeff Hartmannba1b1ae2000-04-04 22:08:14 +00002082{
2083 drm_agp_info_t i;
2084
Daniel Vetterfd387942015-02-11 12:41:04 +01002085 memclear(i);
2086
Keith Packard8b9ab102008-06-13 16:03:22 -07002087 if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
Jan Vesely50d3c852016-06-30 14:22:52 -04002088 return 0;
Jeff Hartmannba1b1ae2000-04-04 22:08:14 +00002089 return i.id_vendor;
2090}
2091
Jose Fonsecad2443b22003-05-27 00:37:33 +00002092
2093/**
2094 * Get hardware device ID.
2095 *
2096 * \param fd file descriptor.
Jan Vesely50d3c852016-06-30 14:22:52 -04002097 *
Jose Fonsecad2443b22003-05-27 00:37:33 +00002098 * \return zero on success, or zero on failure.
Jan Vesely50d3c852016-06-30 14:22:52 -04002099 *
Jose Fonsecad2443b22003-05-27 00:37:33 +00002100 * \internal
2101 * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
2102 * necessary information in a drm_agp_info structure.
2103 */
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07002104drm_public unsigned int drmAgpDeviceId(int fd)
Jeff Hartmannba1b1ae2000-04-04 22:08:14 +00002105{
2106 drm_agp_info_t i;
2107
Daniel Vetterfd387942015-02-11 12:41:04 +01002108 memclear(i);
2109
Keith Packard8b9ab102008-06-13 16:03:22 -07002110 if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
Jan Vesely50d3c852016-06-30 14:22:52 -04002111 return 0;
Jeff Hartmannba1b1ae2000-04-04 22:08:14 +00002112 return i.id_device;
2113}
2114
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07002115drm_public int drmScatterGatherAlloc(int fd, unsigned long size,
2116 drm_handle_t *handle)
Kevin E Martin5d6ddbc2001-04-05 22:16:12 +00002117{
2118 drm_scatter_gather_t sg;
2119
Daniel Vetterfd387942015-02-11 12:41:04 +01002120 memclear(sg);
2121
Kevin E Martin5d6ddbc2001-04-05 22:16:12 +00002122 *handle = 0;
2123 sg.size = size;
Keith Packard8b9ab102008-06-13 16:03:22 -07002124 if (drmIoctl(fd, DRM_IOCTL_SG_ALLOC, &sg))
Jan Vesely50d3c852016-06-30 14:22:52 -04002125 return -errno;
Kevin E Martin5d6ddbc2001-04-05 22:16:12 +00002126 *handle = sg.handle;
2127 return 0;
2128}
2129
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07002130drm_public int drmScatterGatherFree(int fd, drm_handle_t handle)
Kevin E Martin5d6ddbc2001-04-05 22:16:12 +00002131{
2132 drm_scatter_gather_t sg;
2133
Daniel Vetterfd387942015-02-11 12:41:04 +01002134 memclear(sg);
Kevin E Martin5d6ddbc2001-04-05 22:16:12 +00002135 sg.handle = handle;
Keith Packard8b9ab102008-06-13 16:03:22 -07002136 if (drmIoctl(fd, DRM_IOCTL_SG_FREE, &sg))
Jan Vesely50d3c852016-06-30 14:22:52 -04002137 return -errno;
Kevin E Martin5d6ddbc2001-04-05 22:16:12 +00002138 return 0;
2139}
2140
Jose Fonsecad2443b22003-05-27 00:37:33 +00002141/**
2142 * Wait for VBLANK.
2143 *
2144 * \param fd file descriptor.
2145 * \param vbl pointer to a drmVBlank structure.
Jan Vesely50d3c852016-06-30 14:22:52 -04002146 *
Jose Fonsecad2443b22003-05-27 00:37:33 +00002147 * \return zero on success, or a negative value on failure.
Jan Vesely50d3c852016-06-30 14:22:52 -04002148 *
Jose Fonsecad2443b22003-05-27 00:37:33 +00002149 * \internal
2150 * This function is a wrapper around the DRM_IOCTL_WAIT_VBLANK ioctl.
2151 */
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07002152drm_public int drmWaitVBlank(int fd, drmVBlankPtr vbl)
Michel Daenzer55acd0d2002-09-25 17:18:19 +00002153{
Jesse Barnesf4f76a62009-01-07 10:18:08 -08002154 struct timespec timeout, cur;
Michel Daenzer55acd0d2002-09-25 17:18:19 +00002155 int ret;
2156
Jesse Barnesf4f76a62009-01-07 10:18:08 -08002157 ret = clock_gettime(CLOCK_MONOTONIC, &timeout);
2158 if (ret < 0) {
Jan Vesely50d3c852016-06-30 14:22:52 -04002159 fprintf(stderr, "clock_gettime failed: %s\n", strerror(errno));
2160 goto out;
Jesse Barnesf4f76a62009-01-07 10:18:08 -08002161 }
2162 timeout.tv_sec++;
2163
Michel Daenzer55acd0d2002-09-25 17:18:19 +00002164 do {
Jesse Barnesf4f76a62009-01-07 10:18:08 -08002165 ret = ioctl(fd, DRM_IOCTL_WAIT_VBLANK, vbl);
Michel Daenzerc7d471b2003-02-02 03:06:47 +00002166 vbl->request.type &= ~DRM_VBLANK_RELATIVE;
Jesse Barnesca370772009-01-07 10:48:26 -08002167 if (ret && errno == EINTR) {
Jan Vesely50d3c852016-06-30 14:22:52 -04002168 clock_gettime(CLOCK_MONOTONIC, &cur);
2169 /* Timeout after 1s */
2170 if (cur.tv_sec > timeout.tv_sec + 1 ||
2171 (cur.tv_sec == timeout.tv_sec && cur.tv_nsec >=
2172 timeout.tv_nsec)) {
2173 errno = EBUSY;
2174 ret = -1;
2175 break;
2176 }
Jesse Barnesf4f76a62009-01-07 10:18:08 -08002177 }
Michel Daenzer55acd0d2002-09-25 17:18:19 +00002178 } while (ret && errno == EINTR);
2179
Jesse Barnesf4f76a62009-01-07 10:18:08 -08002180out:
Michel Daenzer55acd0d2002-09-25 17:18:19 +00002181 return ret;
2182}
2183
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07002184drm_public int drmError(int err, const char *label)
Daryll Straussb3a57661999-12-05 01:19:48 +00002185{
2186 switch (err) {
Brianccd7b6e2007-05-29 14:54:00 -06002187 case DRM_ERR_NO_DEVICE:
Jan Vesely50d3c852016-06-30 14:22:52 -04002188 fprintf(stderr, "%s: no device\n", label);
2189 break;
Brianccd7b6e2007-05-29 14:54:00 -06002190 case DRM_ERR_NO_ACCESS:
Jan Vesely50d3c852016-06-30 14:22:52 -04002191 fprintf(stderr, "%s: no access\n", label);
2192 break;
Brianccd7b6e2007-05-29 14:54:00 -06002193 case DRM_ERR_NOT_ROOT:
Jan Vesely50d3c852016-06-30 14:22:52 -04002194 fprintf(stderr, "%s: not root\n", label);
2195 break;
Brianccd7b6e2007-05-29 14:54:00 -06002196 case DRM_ERR_INVALID:
Jan Vesely50d3c852016-06-30 14:22:52 -04002197 fprintf(stderr, "%s: invalid args\n", label);
2198 break;
Daryll Straussb3a57661999-12-05 01:19:48 +00002199 default:
Jan Vesely50d3c852016-06-30 14:22:52 -04002200 if (err < 0)
2201 err = -err;
2202 fprintf( stderr, "%s: error %d (%s)\n", label, err, strerror(err) );
2203 break;
Daryll Straussb3a57661999-12-05 01:19:48 +00002204 }
2205
2206 return 1;
2207}
2208
Jose Fonsecad2443b22003-05-27 00:37:33 +00002209/**
2210 * Install IRQ handler.
2211 *
2212 * \param fd file descriptor.
2213 * \param irq IRQ number.
Jan Vesely50d3c852016-06-30 14:22:52 -04002214 *
Jose Fonsecad2443b22003-05-27 00:37:33 +00002215 * \return zero on success, or a negative value on failure.
Jan Vesely50d3c852016-06-30 14:22:52 -04002216 *
Jose Fonsecad2443b22003-05-27 00:37:33 +00002217 * \internal
2218 * This function is a wrapper around the DRM_IOCTL_CONTROL ioctl, passing the
2219 * argument in a drm_control structure.
2220 */
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07002221drm_public int drmCtlInstHandler(int fd, int irq)
Daryll Straussb3a57661999-12-05 01:19:48 +00002222{
2223 drm_control_t ctl;
2224
Daniel Vetterfd387942015-02-11 12:41:04 +01002225 memclear(ctl);
Daryll Straussb3a57661999-12-05 01:19:48 +00002226 ctl.func = DRM_INST_HANDLER;
Daryll Straussb3a57661999-12-05 01:19:48 +00002227 ctl.irq = irq;
Keith Packard8b9ab102008-06-13 16:03:22 -07002228 if (drmIoctl(fd, DRM_IOCTL_CONTROL, &ctl))
Jan Vesely50d3c852016-06-30 14:22:52 -04002229 return -errno;
Daryll Straussb3a57661999-12-05 01:19:48 +00002230 return 0;
2231}
2232
Jose Fonsecad2443b22003-05-27 00:37:33 +00002233
2234/**
2235 * Uninstall IRQ handler.
2236 *
2237 * \param fd file descriptor.
Jan Vesely50d3c852016-06-30 14:22:52 -04002238 *
Jose Fonsecad2443b22003-05-27 00:37:33 +00002239 * \return zero on success, or a negative value on failure.
Jan Vesely50d3c852016-06-30 14:22:52 -04002240 *
Jose Fonsecad2443b22003-05-27 00:37:33 +00002241 * \internal
2242 * This function is a wrapper around the DRM_IOCTL_CONTROL ioctl, passing the
2243 * argument in a drm_control structure.
2244 */
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07002245drm_public int drmCtlUninstHandler(int fd)
Daryll Straussb3a57661999-12-05 01:19:48 +00002246{
2247 drm_control_t ctl;
2248
Daniel Vetterfd387942015-02-11 12:41:04 +01002249 memclear(ctl);
Daryll Straussb3a57661999-12-05 01:19:48 +00002250 ctl.func = DRM_UNINST_HANDLER;
Daryll Straussb3a57661999-12-05 01:19:48 +00002251 ctl.irq = 0;
Keith Packard8b9ab102008-06-13 16:03:22 -07002252 if (drmIoctl(fd, DRM_IOCTL_CONTROL, &ctl))
Jan Vesely50d3c852016-06-30 14:22:52 -04002253 return -errno;
Daryll Straussb3a57661999-12-05 01:19:48 +00002254 return 0;
2255}
2256
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07002257drm_public int drmFinish(int fd, int context, drmLockFlags flags)
Daryll Straussb3a57661999-12-05 01:19:48 +00002258{
2259 drm_lock_t lock;
2260
Daniel Vetterfd387942015-02-11 12:41:04 +01002261 memclear(lock);
Daryll Straussb3a57661999-12-05 01:19:48 +00002262 lock.context = context;
Daryll Straussb3a57661999-12-05 01:19:48 +00002263 if (flags & DRM_LOCK_READY) lock.flags |= _DRM_LOCK_READY;
2264 if (flags & DRM_LOCK_QUIESCENT) lock.flags |= _DRM_LOCK_QUIESCENT;
2265 if (flags & DRM_LOCK_FLUSH) lock.flags |= _DRM_LOCK_FLUSH;
2266 if (flags & DRM_LOCK_FLUSH_ALL) lock.flags |= _DRM_LOCK_FLUSH_ALL;
2267 if (flags & DRM_HALT_ALL_QUEUES) lock.flags |= _DRM_HALT_ALL_QUEUES;
2268 if (flags & DRM_HALT_CUR_QUEUES) lock.flags |= _DRM_HALT_CUR_QUEUES;
Keith Packard8b9ab102008-06-13 16:03:22 -07002269 if (drmIoctl(fd, DRM_IOCTL_FINISH, &lock))
Jan Vesely50d3c852016-06-30 14:22:52 -04002270 return -errno;
Daryll Straussb3a57661999-12-05 01:19:48 +00002271 return 0;
2272}
2273
Jose Fonsecad2443b22003-05-27 00:37:33 +00002274/**
2275 * Get IRQ from bus ID.
2276 *
2277 * \param fd file descriptor.
2278 * \param busnum bus number.
2279 * \param devnum device number.
2280 * \param funcnum function number.
Jan Vesely50d3c852016-06-30 14:22:52 -04002281 *
Jose Fonsecad2443b22003-05-27 00:37:33 +00002282 * \return IRQ number on success, or a negative value on failure.
Jan Vesely50d3c852016-06-30 14:22:52 -04002283 *
Jose Fonsecad2443b22003-05-27 00:37:33 +00002284 * \internal
2285 * This function is a wrapper around the DRM_IOCTL_IRQ_BUSID ioctl, passing the
2286 * arguments in a drm_irq_busid structure.
2287 */
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07002288drm_public int drmGetInterruptFromBusID(int fd, int busnum, int devnum,
2289 int funcnum)
Daryll Straussb3a57661999-12-05 01:19:48 +00002290{
2291 drm_irq_busid_t p;
2292
Daniel Vetterfd387942015-02-11 12:41:04 +01002293 memclear(p);
Daryll Straussb3a57661999-12-05 01:19:48 +00002294 p.busnum = busnum;
2295 p.devnum = devnum;
2296 p.funcnum = funcnum;
Keith Packard8b9ab102008-06-13 16:03:22 -07002297 if (drmIoctl(fd, DRM_IOCTL_IRQ_BUSID, &p))
Jan Vesely50d3c852016-06-30 14:22:52 -04002298 return -errno;
Daryll Straussb3a57661999-12-05 01:19:48 +00002299 return p.irq;
2300}
2301
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07002302drm_public int drmAddContextTag(int fd, drm_context_t context, void *tag)
Daryll Straussb3a57661999-12-05 01:19:48 +00002303{
2304 drmHashEntry *entry = drmGetEntry(fd);
2305
2306 if (drmHashInsert(entry->tagTable, context, tag)) {
Jan Vesely50d3c852016-06-30 14:22:52 -04002307 drmHashDelete(entry->tagTable, context);
2308 drmHashInsert(entry->tagTable, context, tag);
Daryll Straussb3a57661999-12-05 01:19:48 +00002309 }
2310 return 0;
2311}
2312
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07002313drm_public int drmDelContextTag(int fd, drm_context_t context)
Daryll Straussb3a57661999-12-05 01:19:48 +00002314{
2315 drmHashEntry *entry = drmGetEntry(fd);
2316
2317 return drmHashDelete(entry->tagTable, context);
2318}
2319
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07002320drm_public void *drmGetContextTag(int fd, drm_context_t context)
Daryll Straussb3a57661999-12-05 01:19:48 +00002321{
2322 drmHashEntry *entry = drmGetEntry(fd);
2323 void *value;
Gareth Hughes36047532001-02-15 08:12:14 +00002324
Brianccd7b6e2007-05-29 14:54:00 -06002325 if (drmHashLookup(entry->tagTable, context, &value))
Jan Vesely50d3c852016-06-30 14:22:52 -04002326 return NULL;
Daryll Straussb3a57661999-12-05 01:19:48 +00002327
2328 return value;
2329}
2330
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07002331drm_public int drmAddContextPrivateMapping(int fd, drm_context_t ctx_id,
2332 drm_handle_t handle)
Kevin E Martin74e19a42001-03-14 22:22:50 +00002333{
2334 drm_ctx_priv_map_t map;
2335
Daniel Vetterfd387942015-02-11 12:41:04 +01002336 memclear(map);
Kevin E Martin74e19a42001-03-14 22:22:50 +00002337 map.ctx_id = ctx_id;
Jeremy Huddleston961bf9b2011-11-01 14:42:13 -07002338 map.handle = (void *)(uintptr_t)handle;
Kevin E Martin74e19a42001-03-14 22:22:50 +00002339
Keith Packard8b9ab102008-06-13 16:03:22 -07002340 if (drmIoctl(fd, DRM_IOCTL_SET_SAREA_CTX, &map))
Jan Vesely50d3c852016-06-30 14:22:52 -04002341 return -errno;
Kevin E Martin74e19a42001-03-14 22:22:50 +00002342 return 0;
2343}
2344
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07002345drm_public int drmGetContextPrivateMapping(int fd, drm_context_t ctx_id,
2346 drm_handle_t *handle)
Kevin E Martin74e19a42001-03-14 22:22:50 +00002347{
2348 drm_ctx_priv_map_t map;
2349
Daniel Vetterfd387942015-02-11 12:41:04 +01002350 memclear(map);
Kevin E Martin74e19a42001-03-14 22:22:50 +00002351 map.ctx_id = ctx_id;
2352
Keith Packard8b9ab102008-06-13 16:03:22 -07002353 if (drmIoctl(fd, DRM_IOCTL_GET_SAREA_CTX, &map))
Jan Vesely50d3c852016-06-30 14:22:52 -04002354 return -errno;
Brianccd7b6e2007-05-29 14:54:00 -06002355 if (handle)
Jan Vesely50d3c852016-06-30 14:22:52 -04002356 *handle = (drm_handle_t)(uintptr_t)map.handle;
Kevin E Martin74e19a42001-03-14 22:22:50 +00002357
2358 return 0;
2359}
2360
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07002361drm_public int drmGetMap(int fd, int idx, drm_handle_t *offset, drmSize *size,
2362 drmMapType *type, drmMapFlags *flags,
2363 drm_handle_t *handle, int *mtrr)
Rik Faith88dbee52001-02-28 09:27:44 +00002364{
2365 drm_map_t map;
2366
Daniel Vetterfd387942015-02-11 12:41:04 +01002367 memclear(map);
Rik Faith88dbee52001-02-28 09:27:44 +00002368 map.offset = idx;
Keith Packard8b9ab102008-06-13 16:03:22 -07002369 if (drmIoctl(fd, DRM_IOCTL_GET_MAP, &map))
Jan Vesely50d3c852016-06-30 14:22:52 -04002370 return -errno;
Rik Faith88dbee52001-02-28 09:27:44 +00002371 *offset = map.offset;
2372 *size = map.size;
2373 *type = map.type;
2374 *flags = map.flags;
2375 *handle = (unsigned long)map.handle;
2376 *mtrr = map.mtrr;
2377 return 0;
2378}
2379
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07002380drm_public int drmGetClient(int fd, int idx, int *auth, int *pid, int *uid,
2381 unsigned long *magic, unsigned long *iocs)
Rik Faith88dbee52001-02-28 09:27:44 +00002382{
2383 drm_client_t client;
2384
Daniel Vetterfd387942015-02-11 12:41:04 +01002385 memclear(client);
Rik Faith88dbee52001-02-28 09:27:44 +00002386 client.idx = idx;
Keith Packard8b9ab102008-06-13 16:03:22 -07002387 if (drmIoctl(fd, DRM_IOCTL_GET_CLIENT, &client))
Jan Vesely50d3c852016-06-30 14:22:52 -04002388 return -errno;
Rik Faith88dbee52001-02-28 09:27:44 +00002389 *auth = client.auth;
2390 *pid = client.pid;
2391 *uid = client.uid;
2392 *magic = client.magic;
2393 *iocs = client.iocs;
2394 return 0;
2395}
2396
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07002397drm_public int drmGetStats(int fd, drmStatsT *stats)
Rik Faith88dbee52001-02-28 09:27:44 +00002398{
2399 drm_stats_t s;
Jan Veselyde8532d2014-11-30 12:53:18 -05002400 unsigned i;
Rik Faith88dbee52001-02-28 09:27:44 +00002401
Daniel Vetterfd387942015-02-11 12:41:04 +01002402 memclear(s);
Keith Packard8b9ab102008-06-13 16:03:22 -07002403 if (drmIoctl(fd, DRM_IOCTL_GET_STATS, &s))
Jan Vesely50d3c852016-06-30 14:22:52 -04002404 return -errno;
Rik Faith88dbee52001-02-28 09:27:44 +00002405
2406 stats->count = 0;
2407 memset(stats, 0, sizeof(*stats));
2408 if (s.count > sizeof(stats->data)/sizeof(stats->data[0]))
Jan Vesely50d3c852016-06-30 14:22:52 -04002409 return -1;
Rik Faith88dbee52001-02-28 09:27:44 +00002410
2411#define SET_VALUE \
2412 stats->data[i].long_format = "%-20.20s"; \
2413 stats->data[i].rate_format = "%8.8s"; \
2414 stats->data[i].isvalue = 1; \
2415 stats->data[i].verbose = 0
2416
2417#define SET_COUNT \
2418 stats->data[i].long_format = "%-20.20s"; \
2419 stats->data[i].rate_format = "%5.5s"; \
2420 stats->data[i].isvalue = 0; \
2421 stats->data[i].mult_names = "kgm"; \
2422 stats->data[i].mult = 1000; \
2423 stats->data[i].verbose = 0
2424
2425#define SET_BYTE \
2426 stats->data[i].long_format = "%-20.20s"; \
2427 stats->data[i].rate_format = "%5.5s"; \
2428 stats->data[i].isvalue = 0; \
2429 stats->data[i].mult_names = "KGM"; \
2430 stats->data[i].mult = 1024; \
2431 stats->data[i].verbose = 0
2432
2433
2434 stats->count = s.count;
2435 for (i = 0; i < s.count; i++) {
Jan Vesely50d3c852016-06-30 14:22:52 -04002436 stats->data[i].value = s.data[i].value;
2437 switch (s.data[i].type) {
2438 case _DRM_STAT_LOCK:
2439 stats->data[i].long_name = "Lock";
2440 stats->data[i].rate_name = "Lock";
2441 SET_VALUE;
2442 break;
2443 case _DRM_STAT_OPENS:
2444 stats->data[i].long_name = "Opens";
2445 stats->data[i].rate_name = "O";
2446 SET_COUNT;
2447 stats->data[i].verbose = 1;
2448 break;
2449 case _DRM_STAT_CLOSES:
2450 stats->data[i].long_name = "Closes";
2451 stats->data[i].rate_name = "Lock";
2452 SET_COUNT;
2453 stats->data[i].verbose = 1;
2454 break;
2455 case _DRM_STAT_IOCTLS:
2456 stats->data[i].long_name = "Ioctls";
2457 stats->data[i].rate_name = "Ioc/s";
2458 SET_COUNT;
2459 break;
2460 case _DRM_STAT_LOCKS:
2461 stats->data[i].long_name = "Locks";
2462 stats->data[i].rate_name = "Lck/s";
2463 SET_COUNT;
2464 break;
2465 case _DRM_STAT_UNLOCKS:
2466 stats->data[i].long_name = "Unlocks";
2467 stats->data[i].rate_name = "Unl/s";
2468 SET_COUNT;
2469 break;
2470 case _DRM_STAT_IRQ:
2471 stats->data[i].long_name = "IRQs";
2472 stats->data[i].rate_name = "IRQ/s";
2473 SET_COUNT;
2474 break;
2475 case _DRM_STAT_PRIMARY:
2476 stats->data[i].long_name = "Primary Bytes";
2477 stats->data[i].rate_name = "PB/s";
2478 SET_BYTE;
2479 break;
2480 case _DRM_STAT_SECONDARY:
2481 stats->data[i].long_name = "Secondary Bytes";
2482 stats->data[i].rate_name = "SB/s";
2483 SET_BYTE;
2484 break;
2485 case _DRM_STAT_DMA:
2486 stats->data[i].long_name = "DMA";
2487 stats->data[i].rate_name = "DMA/s";
2488 SET_COUNT;
2489 break;
2490 case _DRM_STAT_SPECIAL:
2491 stats->data[i].long_name = "Special DMA";
2492 stats->data[i].rate_name = "dma/s";
2493 SET_COUNT;
2494 break;
2495 case _DRM_STAT_MISSED:
2496 stats->data[i].long_name = "Miss";
2497 stats->data[i].rate_name = "Ms/s";
2498 SET_COUNT;
2499 break;
2500 case _DRM_STAT_VALUE:
2501 stats->data[i].long_name = "Value";
2502 stats->data[i].rate_name = "Value";
2503 SET_VALUE;
2504 break;
2505 case _DRM_STAT_BYTE:
2506 stats->data[i].long_name = "Bytes";
2507 stats->data[i].rate_name = "B/s";
2508 SET_BYTE;
2509 break;
2510 case _DRM_STAT_COUNT:
2511 default:
2512 stats->data[i].long_name = "Count";
2513 stats->data[i].rate_name = "Cnt/s";
2514 SET_COUNT;
2515 break;
2516 }
Rik Faith88dbee52001-02-28 09:27:44 +00002517 }
2518 return 0;
2519}
2520
Jose Fonsecad2443b22003-05-27 00:37:33 +00002521/**
Eric Anholt06cb1322003-10-23 02:23:31 +00002522 * Issue a set-version ioctl.
2523 *
2524 * \param fd file descriptor.
Jan Vesely50d3c852016-06-30 14:22:52 -04002525 * \param drmCommandIndex command index
Eric Anholt06cb1322003-10-23 02:23:31 +00002526 * \param data source pointer of the data to be read and written.
2527 * \param size size of the data to be read and written.
Jan Vesely50d3c852016-06-30 14:22:52 -04002528 *
Eric Anholt06cb1322003-10-23 02:23:31 +00002529 * \return zero on success, or a negative value on failure.
Jan Vesely50d3c852016-06-30 14:22:52 -04002530 *
Eric Anholt06cb1322003-10-23 02:23:31 +00002531 * \internal
Jan Vesely50d3c852016-06-30 14:22:52 -04002532 * It issues a read-write ioctl given by
Eric Anholt06cb1322003-10-23 02:23:31 +00002533 * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
2534 */
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07002535drm_public int drmSetInterfaceVersion(int fd, drmSetVersion *version)
Eric Anholt06cb1322003-10-23 02:23:31 +00002536{
2537 int retcode = 0;
2538 drm_set_version_t sv;
2539
Daniel Vetterfd387942015-02-11 12:41:04 +01002540 memclear(sv);
Eric Anholt06cb1322003-10-23 02:23:31 +00002541 sv.drm_di_major = version->drm_di_major;
2542 sv.drm_di_minor = version->drm_di_minor;
2543 sv.drm_dd_major = version->drm_dd_major;
2544 sv.drm_dd_minor = version->drm_dd_minor;
2545
Keith Packard8b9ab102008-06-13 16:03:22 -07002546 if (drmIoctl(fd, DRM_IOCTL_SET_VERSION, &sv)) {
Jan Vesely50d3c852016-06-30 14:22:52 -04002547 retcode = -errno;
Eric Anholt06cb1322003-10-23 02:23:31 +00002548 }
2549
2550 version->drm_di_major = sv.drm_di_major;
2551 version->drm_di_minor = sv.drm_di_minor;
2552 version->drm_dd_major = sv.drm_dd_major;
2553 version->drm_dd_minor = sv.drm_dd_minor;
2554
2555 return retcode;
2556}
2557
2558/**
Jose Fonsecad2443b22003-05-27 00:37:33 +00002559 * Send a device-specific command.
2560 *
2561 * \param fd file descriptor.
Jan Vesely50d3c852016-06-30 14:22:52 -04002562 * \param drmCommandIndex command index
2563 *
Jose Fonsecad2443b22003-05-27 00:37:33 +00002564 * \return zero on success, or a negative value on failure.
Jan Vesely50d3c852016-06-30 14:22:52 -04002565 *
Jose Fonsecad2443b22003-05-27 00:37:33 +00002566 * \internal
Jan Vesely50d3c852016-06-30 14:22:52 -04002567 * It issues a ioctl given by
Jose Fonsecad2443b22003-05-27 00:37:33 +00002568 * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
2569 */
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07002570drm_public int drmCommandNone(int fd, unsigned long drmCommandIndex)
Jens Owen3903e5a2002-04-09 21:54:56 +00002571{
Jens Owen3903e5a2002-04-09 21:54:56 +00002572 unsigned long request;
2573
2574 request = DRM_IO( DRM_COMMAND_BASE + drmCommandIndex);
2575
Daniel Vetterfd387942015-02-11 12:41:04 +01002576 if (drmIoctl(fd, request, NULL)) {
Jan Vesely50d3c852016-06-30 14:22:52 -04002577 return -errno;
Jens Owen3903e5a2002-04-09 21:54:56 +00002578 }
2579 return 0;
2580}
2581
Jose Fonsecad2443b22003-05-27 00:37:33 +00002582
2583/**
2584 * Send a device-specific read command.
2585 *
2586 * \param fd file descriptor.
Jan Vesely50d3c852016-06-30 14:22:52 -04002587 * \param drmCommandIndex command index
Jose Fonsecad2443b22003-05-27 00:37:33 +00002588 * \param data destination pointer of the data to be read.
2589 * \param size size of the data to be read.
Jan Vesely50d3c852016-06-30 14:22:52 -04002590 *
Jose Fonsecad2443b22003-05-27 00:37:33 +00002591 * \return zero on success, or a negative value on failure.
2592 *
2593 * \internal
Jan Vesely50d3c852016-06-30 14:22:52 -04002594 * It issues a read ioctl given by
Jose Fonsecad2443b22003-05-27 00:37:33 +00002595 * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
2596 */
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07002597drm_public int drmCommandRead(int fd, unsigned long drmCommandIndex,
2598 void *data, unsigned long size)
Jens Owen3903e5a2002-04-09 21:54:56 +00002599{
2600 unsigned long request;
2601
Jan Vesely50d3c852016-06-30 14:22:52 -04002602 request = DRM_IOC( DRM_IOC_READ, DRM_IOCTL_BASE,
2603 DRM_COMMAND_BASE + drmCommandIndex, size);
Jens Owen3903e5a2002-04-09 21:54:56 +00002604
Keith Packard8b9ab102008-06-13 16:03:22 -07002605 if (drmIoctl(fd, request, data)) {
Jan Vesely50d3c852016-06-30 14:22:52 -04002606 return -errno;
Jens Owen3903e5a2002-04-09 21:54:56 +00002607 }
2608 return 0;
2609}
2610
Jose Fonsecad2443b22003-05-27 00:37:33 +00002611
2612/**
2613 * Send a device-specific write command.
2614 *
2615 * \param fd file descriptor.
Jan Vesely50d3c852016-06-30 14:22:52 -04002616 * \param drmCommandIndex command index
Jose Fonsecad2443b22003-05-27 00:37:33 +00002617 * \param data source pointer of the data to be written.
2618 * \param size size of the data to be written.
Jan Vesely50d3c852016-06-30 14:22:52 -04002619 *
Jose Fonsecad2443b22003-05-27 00:37:33 +00002620 * \return zero on success, or a negative value on failure.
Jan Vesely50d3c852016-06-30 14:22:52 -04002621 *
Jose Fonsecad2443b22003-05-27 00:37:33 +00002622 * \internal
Jan Vesely50d3c852016-06-30 14:22:52 -04002623 * It issues a write ioctl given by
Jose Fonsecad2443b22003-05-27 00:37:33 +00002624 * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
2625 */
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07002626drm_public int drmCommandWrite(int fd, unsigned long drmCommandIndex,
2627 void *data, unsigned long size)
Jens Owen3903e5a2002-04-09 21:54:56 +00002628{
2629 unsigned long request;
2630
Jan Vesely50d3c852016-06-30 14:22:52 -04002631 request = DRM_IOC( DRM_IOC_WRITE, DRM_IOCTL_BASE,
2632 DRM_COMMAND_BASE + drmCommandIndex, size);
Jens Owen3903e5a2002-04-09 21:54:56 +00002633
Keith Packard8b9ab102008-06-13 16:03:22 -07002634 if (drmIoctl(fd, request, data)) {
Jan Vesely50d3c852016-06-30 14:22:52 -04002635 return -errno;
Jens Owen3903e5a2002-04-09 21:54:56 +00002636 }
2637 return 0;
2638}
2639
Jose Fonsecad2443b22003-05-27 00:37:33 +00002640
2641/**
2642 * Send a device-specific read-write command.
2643 *
2644 * \param fd file descriptor.
Jan Vesely50d3c852016-06-30 14:22:52 -04002645 * \param drmCommandIndex command index
Jose Fonsecad2443b22003-05-27 00:37:33 +00002646 * \param data source pointer of the data to be read and written.
2647 * \param size size of the data to be read and written.
Jan Vesely50d3c852016-06-30 14:22:52 -04002648 *
Jose Fonsecad2443b22003-05-27 00:37:33 +00002649 * \return zero on success, or a negative value on failure.
Jan Vesely50d3c852016-06-30 14:22:52 -04002650 *
Jose Fonsecad2443b22003-05-27 00:37:33 +00002651 * \internal
Jan Vesely50d3c852016-06-30 14:22:52 -04002652 * It issues a read-write ioctl given by
Jose Fonsecad2443b22003-05-27 00:37:33 +00002653 * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
2654 */
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07002655drm_public int drmCommandWriteRead(int fd, unsigned long drmCommandIndex,
2656 void *data, unsigned long size)
Jens Owen3903e5a2002-04-09 21:54:56 +00002657{
2658 unsigned long request;
2659
Jan Vesely50d3c852016-06-30 14:22:52 -04002660 request = DRM_IOC( DRM_IOC_READ|DRM_IOC_WRITE, DRM_IOCTL_BASE,
2661 DRM_COMMAND_BASE + drmCommandIndex, size);
Jens Owen3903e5a2002-04-09 21:54:56 +00002662
Keith Packard8b9ab102008-06-13 16:03:22 -07002663 if (drmIoctl(fd, request, data))
Jan Vesely50d3c852016-06-30 14:22:52 -04002664 return -errno;
Jens Owen3903e5a2002-04-09 21:54:56 +00002665 return 0;
2666}
Thomas Hellstrom166da932006-08-21 21:02:08 +02002667
Dave Airlied51e1bb2006-11-09 08:55:58 +11002668#define DRM_MAX_FDS 16
2669static struct {
Brianccd7b6e2007-05-29 14:54:00 -06002670 char *BusID;
2671 int fd;
2672 int refcount;
Jammy Zhoudbc8b112015-02-02 18:06:27 +08002673 int type;
Dave Airlied51e1bb2006-11-09 08:55:58 +11002674} connection[DRM_MAX_FDS];
2675
2676static int nr_fds = 0;
2677
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07002678drm_public int drmOpenOnce(void *unused, const char *BusID, int *newlyopened)
Dave Airlied51e1bb2006-11-09 08:55:58 +11002679{
Jammy Zhoudbc8b112015-02-02 18:06:27 +08002680 return drmOpenOnceWithType(BusID, newlyopened, DRM_NODE_PRIMARY);
2681}
2682
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07002683drm_public int drmOpenOnceWithType(const char *BusID, int *newlyopened,
2684 int type)
Jammy Zhoudbc8b112015-02-02 18:06:27 +08002685{
Brianccd7b6e2007-05-29 14:54:00 -06002686 int i;
2687 int fd;
Jan Vesely50d3c852016-06-30 14:22:52 -04002688
Brianccd7b6e2007-05-29 14:54:00 -06002689 for (i = 0; i < nr_fds; i++)
Jan Vesely50d3c852016-06-30 14:22:52 -04002690 if ((strcmp(BusID, connection[i].BusID) == 0) &&
2691 (connection[i].type == type)) {
2692 connection[i].refcount++;
2693 *newlyopened = 0;
2694 return connection[i].fd;
2695 }
Dave Airlied51e1bb2006-11-09 08:55:58 +11002696
Jammy Zhoudbc8b112015-02-02 18:06:27 +08002697 fd = drmOpenWithType(NULL, BusID, type);
Emil Velikovc1cd3d92015-07-14 15:05:18 +01002698 if (fd < 0 || nr_fds == DRM_MAX_FDS)
Jan Vesely50d3c852016-06-30 14:22:52 -04002699 return fd;
2700
Brianccd7b6e2007-05-29 14:54:00 -06002701 connection[nr_fds].BusID = strdup(BusID);
2702 connection[nr_fds].fd = fd;
2703 connection[nr_fds].refcount = 1;
Jammy Zhoudbc8b112015-02-02 18:06:27 +08002704 connection[nr_fds].type = type;
Brianccd7b6e2007-05-29 14:54:00 -06002705 *newlyopened = 1;
Dave Airlied51e1bb2006-11-09 08:55:58 +11002706
Brianccd7b6e2007-05-29 14:54:00 -06002707 if (0)
Jan Vesely50d3c852016-06-30 14:22:52 -04002708 fprintf(stderr, "saved connection %d for %s %d\n",
2709 nr_fds, connection[nr_fds].BusID,
2710 strcmp(BusID, connection[nr_fds].BusID));
Dave Airlied51e1bb2006-11-09 08:55:58 +11002711
Brianccd7b6e2007-05-29 14:54:00 -06002712 nr_fds++;
Dave Airlied51e1bb2006-11-09 08:55:58 +11002713
Brianccd7b6e2007-05-29 14:54:00 -06002714 return fd;
Dave Airlied51e1bb2006-11-09 08:55:58 +11002715}
2716
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07002717drm_public void drmCloseOnce(int fd)
Dave Airlied51e1bb2006-11-09 08:55:58 +11002718{
Brianccd7b6e2007-05-29 14:54:00 -06002719 int i;
Dave Airlied51e1bb2006-11-09 08:55:58 +11002720
Brianccd7b6e2007-05-29 14:54:00 -06002721 for (i = 0; i < nr_fds; i++) {
Jan Vesely50d3c852016-06-30 14:22:52 -04002722 if (fd == connection[i].fd) {
2723 if (--connection[i].refcount == 0) {
2724 drmClose(connection[i].fd);
2725 free(connection[i].BusID);
Dave Airlied51e1bb2006-11-09 08:55:58 +11002726
Jan Vesely50d3c852016-06-30 14:22:52 -04002727 if (i < --nr_fds)
2728 connection[i] = connection[nr_fds];
2729
2730 return;
2731 }
2732 }
Brianccd7b6e2007-05-29 14:54:00 -06002733 }
Dave Airlied51e1bb2006-11-09 08:55:58 +11002734}
Jesse Barnes731cd552008-12-17 10:09:49 -08002735
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07002736drm_public int drmSetMaster(int fd)
Jesse Barnes731cd552008-12-17 10:09:49 -08002737{
Jan Vesely50d3c852016-06-30 14:22:52 -04002738 return drmIoctl(fd, DRM_IOCTL_SET_MASTER, NULL);
Jesse Barnes731cd552008-12-17 10:09:49 -08002739}
2740
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07002741drm_public int drmDropMaster(int fd)
Jesse Barnes731cd552008-12-17 10:09:49 -08002742{
Jan Vesely50d3c852016-06-30 14:22:52 -04002743 return drmIoctl(fd, DRM_IOCTL_DROP_MASTER, NULL);
Jesse Barnes731cd552008-12-17 10:09:49 -08002744}
Kristian Høgsberg22d46662009-11-23 20:51:34 -05002745
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07002746drm_public char *drmGetDeviceNameFromFd(int fd)
Kristian Høgsberg22d46662009-11-23 20:51:34 -05002747{
Jan Vesely50d3c852016-06-30 14:22:52 -04002748 char name[128];
2749 struct stat sbuf;
2750 dev_t d;
2751 int i;
Kristian Høgsberg22d46662009-11-23 20:51:34 -05002752
Jan Vesely50d3c852016-06-30 14:22:52 -04002753 /* The whole drmOpen thing is a fiasco and we need to find a way
2754 * back to just using open(2). For now, however, lets just make
2755 * things worse with even more ad hoc directory walking code to
2756 * discover the device file name. */
Kristian Høgsberg22d46662009-11-23 20:51:34 -05002757
Jan Vesely50d3c852016-06-30 14:22:52 -04002758 fstat(fd, &sbuf);
2759 d = sbuf.st_rdev;
Kristian Høgsberg22d46662009-11-23 20:51:34 -05002760
Jan Vesely50d3c852016-06-30 14:22:52 -04002761 for (i = 0; i < DRM_MAX_MINOR; i++) {
2762 snprintf(name, sizeof name, DRM_DEV_NAME, DRM_DIR_NAME, i);
2763 if (stat(name, &sbuf) == 0 && sbuf.st_rdev == d)
2764 break;
2765 }
2766 if (i == DRM_MAX_MINOR)
2767 return NULL;
Kristian Høgsberg22d46662009-11-23 20:51:34 -05002768
Jan Vesely50d3c852016-06-30 14:22:52 -04002769 return strdup(name);
Kristian Høgsberg22d46662009-11-23 20:51:34 -05002770}
Dave Airliecc0a1452012-07-14 09:52:17 +00002771
Thomas Hellstromf8392582018-08-31 13:47:05 +02002772static bool drmNodeIsDRM(int maj, int min)
2773{
2774#ifdef __linux__
2775 char path[64];
2776 struct stat sbuf;
2777
2778 snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device/drm",
2779 maj, min);
2780 return stat(path, &sbuf) == 0;
2781#else
2782 return maj == DRM_MAJOR;
2783#endif
2784}
2785
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07002786drm_public int drmGetNodeTypeFromFd(int fd)
Frank Binns1f735782015-02-13 10:51:15 +00002787{
Jan Vesely50d3c852016-06-30 14:22:52 -04002788 struct stat sbuf;
2789 int maj, min, type;
Frank Binns1f735782015-02-13 10:51:15 +00002790
Jan Vesely50d3c852016-06-30 14:22:52 -04002791 if (fstat(fd, &sbuf))
2792 return -1;
Frank Binns1f735782015-02-13 10:51:15 +00002793
Jan Vesely50d3c852016-06-30 14:22:52 -04002794 maj = major(sbuf.st_rdev);
2795 min = minor(sbuf.st_rdev);
Frank Binns1f735782015-02-13 10:51:15 +00002796
Thomas Hellstromf8392582018-08-31 13:47:05 +02002797 if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode)) {
Jan Vesely50d3c852016-06-30 14:22:52 -04002798 errno = EINVAL;
2799 return -1;
2800 }
Frank Binns1f735782015-02-13 10:51:15 +00002801
Jan Vesely50d3c852016-06-30 14:22:52 -04002802 type = drmGetMinorType(min);
2803 if (type == -1)
2804 errno = ENODEV;
2805 return type;
Frank Binns1f735782015-02-13 10:51:15 +00002806}
2807
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07002808drm_public int drmPrimeHandleToFD(int fd, uint32_t handle, uint32_t flags,
2809 int *prime_fd)
Dave Airliecc0a1452012-07-14 09:52:17 +00002810{
Jan Vesely50d3c852016-06-30 14:22:52 -04002811 struct drm_prime_handle args;
2812 int ret;
Dave Airliecc0a1452012-07-14 09:52:17 +00002813
Jan Vesely50d3c852016-06-30 14:22:52 -04002814 memclear(args);
2815 args.fd = -1;
2816 args.handle = handle;
2817 args.flags = flags;
2818 ret = drmIoctl(fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &args);
2819 if (ret)
2820 return ret;
Dave Airliecc0a1452012-07-14 09:52:17 +00002821
Jan Vesely50d3c852016-06-30 14:22:52 -04002822 *prime_fd = args.fd;
2823 return 0;
Dave Airliecc0a1452012-07-14 09:52:17 +00002824}
2825
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07002826drm_public int drmPrimeFDToHandle(int fd, int prime_fd, uint32_t *handle)
Dave Airliecc0a1452012-07-14 09:52:17 +00002827{
Jan Vesely50d3c852016-06-30 14:22:52 -04002828 struct drm_prime_handle args;
2829 int ret;
Dave Airliecc0a1452012-07-14 09:52:17 +00002830
Jan Vesely50d3c852016-06-30 14:22:52 -04002831 memclear(args);
2832 args.fd = prime_fd;
2833 ret = drmIoctl(fd, DRM_IOCTL_PRIME_FD_TO_HANDLE, &args);
2834 if (ret)
2835 return ret;
Dave Airliecc0a1452012-07-14 09:52:17 +00002836
Jan Vesely50d3c852016-06-30 14:22:52 -04002837 *handle = args.handle;
2838 return 0;
Dave Airliecc0a1452012-07-14 09:52:17 +00002839}
2840
Emil Velikov0ca03a42015-03-07 00:58:39 +00002841static char *drmGetMinorNameForFD(int fd, int type)
2842{
2843#ifdef __linux__
Jan Vesely50d3c852016-06-30 14:22:52 -04002844 DIR *sysdir;
John Stultzbb45ce42018-03-20 17:48:23 +00002845 struct dirent *ent;
Jan Vesely50d3c852016-06-30 14:22:52 -04002846 struct stat sbuf;
2847 const char *name = drmGetMinorName(type);
2848 int len;
2849 char dev_name[64], buf[64];
Jan Vesely50d3c852016-06-30 14:22:52 -04002850 int maj, min;
Emil Velikov0ca03a42015-03-07 00:58:39 +00002851
Jan Vesely50d3c852016-06-30 14:22:52 -04002852 if (!name)
2853 return NULL;
Emil Velikov0ca03a42015-03-07 00:58:39 +00002854
Jan Vesely50d3c852016-06-30 14:22:52 -04002855 len = strlen(name);
Emil Velikov0ca03a42015-03-07 00:58:39 +00002856
Jan Vesely50d3c852016-06-30 14:22:52 -04002857 if (fstat(fd, &sbuf))
2858 return NULL;
Emil Velikov0ca03a42015-03-07 00:58:39 +00002859
Jan Vesely50d3c852016-06-30 14:22:52 -04002860 maj = major(sbuf.st_rdev);
2861 min = minor(sbuf.st_rdev);
Emil Velikov0ca03a42015-03-07 00:58:39 +00002862
Thomas Hellstromf8392582018-08-31 13:47:05 +02002863 if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode))
Jan Vesely50d3c852016-06-30 14:22:52 -04002864 return NULL;
Emil Velikov0ca03a42015-03-07 00:58:39 +00002865
Jan Vesely50d3c852016-06-30 14:22:52 -04002866 snprintf(buf, sizeof(buf), "/sys/dev/char/%d:%d/device/drm", maj, min);
Emil Velikov0ca03a42015-03-07 00:58:39 +00002867
Jan Vesely50d3c852016-06-30 14:22:52 -04002868 sysdir = opendir(buf);
2869 if (!sysdir)
2870 return NULL;
Emil Velikov0ca03a42015-03-07 00:58:39 +00002871
John Stultzbb45ce42018-03-20 17:48:23 +00002872 while ((ent = readdir(sysdir))) {
Jan Vesely50d3c852016-06-30 14:22:52 -04002873 if (strncmp(ent->d_name, name, len) == 0) {
2874 snprintf(dev_name, sizeof(dev_name), DRM_DIR_NAME "/%s",
2875 ent->d_name);
Mathias Tillman5c42b5e2015-08-24 11:56:13 +08002876
Jan Vesely50d3c852016-06-30 14:22:52 -04002877 closedir(sysdir);
Jan Vesely50d3c852016-06-30 14:22:52 -04002878 return strdup(dev_name);
2879 }
2880 }
Kevin Strasserf34b6942018-05-18 12:48:17 -07002881
2882 closedir(sysdir);
John Stultzbb45ce42018-03-20 17:48:23 +00002883 return NULL;
Emil Velikov8415a002015-09-07 18:29:05 +01002884#else
Jonathan Grayf1890112016-12-01 15:18:39 +11002885 struct stat sbuf;
2886 char buf[PATH_MAX + 1];
2887 const char *dev_name;
2888 unsigned int maj, min;
Jonathan Grayd5cf3f92016-12-17 16:09:51 +11002889 int n, base;
Jonathan Grayf1890112016-12-01 15:18:39 +11002890
2891 if (fstat(fd, &sbuf))
2892 return NULL;
2893
2894 maj = major(sbuf.st_rdev);
2895 min = minor(sbuf.st_rdev);
2896
Thomas Hellstromf8392582018-08-31 13:47:05 +02002897 if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode))
Jonathan Grayf1890112016-12-01 15:18:39 +11002898 return NULL;
2899
2900 switch (type) {
2901 case DRM_NODE_PRIMARY:
2902 dev_name = DRM_DEV_NAME;
2903 break;
2904 case DRM_NODE_CONTROL:
2905 dev_name = DRM_CONTROL_DEV_NAME;
2906 break;
2907 case DRM_NODE_RENDER:
2908 dev_name = DRM_RENDER_DEV_NAME;
2909 break;
2910 default:
2911 return NULL;
2912 };
2913
Jonathan Grayd5cf3f92016-12-17 16:09:51 +11002914 base = drmGetMinorBase(type);
2915 if (base < 0)
2916 return NULL;
2917
2918 n = snprintf(buf, sizeof(buf), dev_name, DRM_DIR_NAME, min - base);
Jonathan Grayf1890112016-12-01 15:18:39 +11002919 if (n == -1 || n >= sizeof(buf))
2920 return NULL;
2921
2922 return strdup(buf);
Emil Velikov0ca03a42015-03-07 00:58:39 +00002923#endif
Emil Velikov0ca03a42015-03-07 00:58:39 +00002924}
2925
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07002926drm_public char *drmGetPrimaryDeviceNameFromFd(int fd)
Emil Velikov0ca03a42015-03-07 00:58:39 +00002927{
Jan Vesely50d3c852016-06-30 14:22:52 -04002928 return drmGetMinorNameForFD(fd, DRM_NODE_PRIMARY);
Emil Velikov0ca03a42015-03-07 00:58:39 +00002929}
2930
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07002931drm_public char *drmGetRenderDeviceNameFromFd(int fd)
Emil Velikov0ca03a42015-03-07 00:58:39 +00002932{
Jan Vesely50d3c852016-06-30 14:22:52 -04002933 return drmGetMinorNameForFD(fd, DRM_NODE_RENDER);
Emil Velikov0ca03a42015-03-07 00:58:39 +00002934}
Emil Velikovb556ea12015-08-17 11:09:06 +08002935
Thierry Redingf8484cc2016-12-22 00:39:36 +01002936#ifdef __linux__
2937static char * DRM_PRINTFLIKE(2, 3)
2938sysfs_uevent_get(const char *path, const char *fmt, ...)
2939{
2940 char filename[PATH_MAX + 1], *key, *line = NULL, *value = NULL;
2941 size_t size = 0, len;
2942 ssize_t num;
2943 va_list ap;
2944 FILE *fp;
2945
2946 va_start(ap, fmt);
2947 num = vasprintf(&key, fmt, ap);
2948 va_end(ap);
2949 len = num;
2950
2951 snprintf(filename, sizeof(filename), "%s/uevent", path);
2952
2953 fp = fopen(filename, "r");
2954 if (!fp) {
2955 free(key);
2956 return NULL;
2957 }
2958
2959 while ((num = getline(&line, &size, fp)) >= 0) {
2960 if ((strncmp(line, key, len) == 0) && (line[len] == '=')) {
2961 char *start = line + len + 1, *end = line + num - 1;
2962
2963 if (*end != '\n')
2964 end++;
2965
2966 value = strndup(start, end - start);
2967 break;
2968 }
2969 }
2970
2971 free(line);
2972 fclose(fp);
2973
2974 free(key);
2975
2976 return value;
2977}
2978#endif
2979
Emil Velikov39885802018-05-15 17:37:49 +01002980/* Little white lie to avoid major rework of the existing code */
2981#define DRM_BUS_VIRTIO 0x10
2982
Emil Velikova250fce2015-09-07 12:54:27 +01002983static int drmParseSubsystemType(int maj, int min)
Emil Velikovb556ea12015-08-17 11:09:06 +08002984{
Emil Velikov291b2bb2015-09-07 18:26:34 +01002985#ifdef __linux__
Emil Velikova250fce2015-09-07 12:54:27 +01002986 char path[PATH_MAX + 1];
Emil Velikovb556ea12015-08-17 11:09:06 +08002987 char link[PATH_MAX + 1] = "";
2988 char *name;
Eric Anholt9b28c5a2018-11-15 17:48:53 -08002989 struct {
2990 const char *name;
2991 int bus_type;
2992 } bus_types[] = {
2993 { "/pci", DRM_BUS_PCI },
2994 { "/usb", DRM_BUS_USB },
2995 { "/platform", DRM_BUS_PLATFORM },
Eric Anholt89700ab2018-11-15 17:52:19 -08002996 { "/spi", DRM_BUS_PLATFORM },
Eric Anholt9b28c5a2018-11-15 17:48:53 -08002997 { "/host1x", DRM_BUS_HOST1X },
2998 { "/virtio", DRM_BUS_VIRTIO },
2999 };
Emil Velikovb556ea12015-08-17 11:09:06 +08003000
Emil Velikova250fce2015-09-07 12:54:27 +01003001 snprintf(path, PATH_MAX, "/sys/dev/char/%d:%d/device/subsystem",
3002 maj, min);
3003
3004 if (readlink(path, link, PATH_MAX) < 0)
3005 return -errno;
Emil Velikovb556ea12015-08-17 11:09:06 +08003006
3007 name = strrchr(link, '/');
3008 if (!name)
3009 return -EINVAL;
3010
Eric Anholt9b28c5a2018-11-15 17:48:53 -08003011 for (unsigned i = 0; i < ARRAY_SIZE(bus_types); i++) {
3012 if (strncmp(name, bus_types[i].name, strlen(bus_types[i].name)) == 0)
3013 return bus_types[i].bus_type;
3014 }
Emil Velikov39885802018-05-15 17:37:49 +01003015
Emil Velikovb556ea12015-08-17 11:09:06 +08003016 return -EINVAL;
François Tigeot200e9e92018-12-12 20:48:35 +01003017#elif defined(__OpenBSD__) || defined(__DragonFly__)
Thierry Redinge17cad12016-12-21 18:00:52 +01003018 return DRM_BUS_PCI;
Emil Velikov291b2bb2015-09-07 18:26:34 +01003019#else
3020#warning "Missing implementation of drmParseSubsystemType"
3021 return -EINVAL;
3022#endif
Emil Velikovb556ea12015-08-17 11:09:06 +08003023}
3024
Eric Engestrom56499532018-09-05 13:23:59 +01003025static void
Eric Engestrom9030a0f2018-09-05 13:29:08 +01003026get_pci_path(int maj, int min, char *pci_path)
Emil Velikova0290012018-05-15 17:29:44 +01003027{
Emil Velikov39885802018-05-15 17:37:49 +01003028 char path[PATH_MAX + 1], *term;
Emil Velikova0290012018-05-15 17:29:44 +01003029
3030 snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min);
Eric Engestrom9030a0f2018-09-05 13:29:08 +01003031 if (!realpath(path, pci_path)) {
3032 strcpy(pci_path, path);
Eric Engestrom56499532018-09-05 13:23:59 +01003033 return;
3034 }
Emil Velikova0290012018-05-15 17:29:44 +01003035
Eric Engestrom9030a0f2018-09-05 13:29:08 +01003036 term = strrchr(pci_path, '/');
Emil Velikov39885802018-05-15 17:37:49 +01003037 if (term && strncmp(term, "/virtio", 7) == 0)
3038 *term = 0;
Emil Velikovbcb9d972018-08-23 10:49:54 +01003039}
3040
Emil Velikov536e0de2015-09-07 12:37:57 +01003041static int drmParsePciBusInfo(int maj, int min, drmPciBusInfoPtr info)
Emil Velikovb556ea12015-08-17 11:09:06 +08003042{
Emil Velikov291b2bb2015-09-07 18:26:34 +01003043#ifdef __linux__
Thierry Reding5403cb32017-01-18 08:29:23 +01003044 unsigned int domain, bus, dev, func;
Eric Engestrom9030a0f2018-09-05 13:29:08 +01003045 char pci_path[PATH_MAX + 1], *value;
Thierry Reding5403cb32017-01-18 08:29:23 +01003046 int num;
Emil Velikovb556ea12015-08-17 11:09:06 +08003047
Eric Engestrom9030a0f2018-09-05 13:29:08 +01003048 get_pci_path(maj, min, pci_path);
Emil Velikov536e0de2015-09-07 12:37:57 +01003049
Eric Engestrom9030a0f2018-09-05 13:29:08 +01003050 value = sysfs_uevent_get(pci_path, "PCI_SLOT_NAME");
Thierry Reding5403cb32017-01-18 08:29:23 +01003051 if (!value)
3052 return -ENOENT;
Emil Velikov536e0de2015-09-07 12:37:57 +01003053
Thierry Reding5403cb32017-01-18 08:29:23 +01003054 num = sscanf(value, "%04x:%02x:%02x.%1u", &domain, &bus, &dev, &func);
3055 free(value);
3056
3057 if (num != 4)
Emil Velikovb556ea12015-08-17 11:09:06 +08003058 return -EINVAL;
3059
Emil Velikovb556ea12015-08-17 11:09:06 +08003060 info->domain = domain;
3061 info->bus = bus;
3062 info->dev = dev;
3063 info->func = func;
3064
3065 return 0;
François Tigeot8f2e0922018-12-12 20:48:36 +01003066#elif defined(__OpenBSD__) || defined(__DragonFly__)
Jonathan Grayfd190562016-12-01 15:18:42 +11003067 struct drm_pciinfo pinfo;
3068 int fd, type;
3069
3070 type = drmGetMinorType(min);
3071 if (type == -1)
3072 return -ENODEV;
3073
3074 fd = drmOpenMinor(min, 0, type);
3075 if (fd < 0)
3076 return -errno;
3077
3078 if (drmIoctl(fd, DRM_IOCTL_GET_PCIINFO, &pinfo)) {
3079 close(fd);
3080 return -errno;
3081 }
3082 close(fd);
3083
3084 info->domain = pinfo.domain;
3085 info->bus = pinfo.bus;
3086 info->dev = pinfo.dev;
3087 info->func = pinfo.func;
3088
3089 return 0;
Emil Velikov291b2bb2015-09-07 18:26:34 +01003090#else
3091#warning "Missing implementation of drmParsePciBusInfo"
3092 return -EINVAL;
3093#endif
Emil Velikovb556ea12015-08-17 11:09:06 +08003094}
3095
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07003096drm_public int drmDevicesEqual(drmDevicePtr a, drmDevicePtr b)
Emil Velikovb556ea12015-08-17 11:09:06 +08003097{
Emil Velikovbc2aca92015-09-07 13:51:54 +01003098 if (a == NULL || b == NULL)
Adam Jackson7c27cd72017-05-04 10:48:56 -04003099 return 0;
Emil Velikovbc2aca92015-09-07 13:51:54 +01003100
Emil Velikovb556ea12015-08-17 11:09:06 +08003101 if (a->bustype != b->bustype)
Adam Jackson7c27cd72017-05-04 10:48:56 -04003102 return 0;
Emil Velikovb556ea12015-08-17 11:09:06 +08003103
3104 switch (a->bustype) {
3105 case DRM_BUS_PCI:
Adam Jackson7c27cd72017-05-04 10:48:56 -04003106 return memcmp(a->businfo.pci, b->businfo.pci, sizeof(drmPciBusInfo)) == 0;
Thierry Redingf8484cc2016-12-22 00:39:36 +01003107
3108 case DRM_BUS_USB:
Adam Jackson7c27cd72017-05-04 10:48:56 -04003109 return memcmp(a->businfo.usb, b->businfo.usb, sizeof(drmUsbBusInfo)) == 0;
Thierry Redingf8484cc2016-12-22 00:39:36 +01003110
Thierry Reding7b1f37f2016-12-21 17:59:04 +01003111 case DRM_BUS_PLATFORM:
Adam Jackson7c27cd72017-05-04 10:48:56 -04003112 return memcmp(a->businfo.platform, b->businfo.platform, sizeof(drmPlatformBusInfo)) == 0;
Thierry Reding7b1f37f2016-12-21 17:59:04 +01003113
3114 case DRM_BUS_HOST1X:
Adam Jackson7c27cd72017-05-04 10:48:56 -04003115 return memcmp(a->businfo.host1x, b->businfo.host1x, sizeof(drmHost1xBusInfo)) == 0;
Thierry Reding7b1f37f2016-12-21 17:59:04 +01003116
Emil Velikovb556ea12015-08-17 11:09:06 +08003117 default:
3118 break;
3119 }
3120
Adam Jackson7c27cd72017-05-04 10:48:56 -04003121 return 0;
Emil Velikovb556ea12015-08-17 11:09:06 +08003122}
3123
3124static int drmGetNodeType(const char *name)
3125{
3126 if (strncmp(name, DRM_PRIMARY_MINOR_NAME,
3127 sizeof(DRM_PRIMARY_MINOR_NAME) - 1) == 0)
3128 return DRM_NODE_PRIMARY;
3129
3130 if (strncmp(name, DRM_CONTROL_MINOR_NAME,
3131 sizeof(DRM_CONTROL_MINOR_NAME ) - 1) == 0)
3132 return DRM_NODE_CONTROL;
3133
3134 if (strncmp(name, DRM_RENDER_MINOR_NAME,
3135 sizeof(DRM_RENDER_MINOR_NAME) - 1) == 0)
3136 return DRM_NODE_RENDER;
3137
3138 return -EINVAL;
3139}
3140
Emil Velikov5f68d312015-09-07 13:54:32 +01003141static int drmGetMaxNodeName(void)
3142{
3143 return sizeof(DRM_DIR_NAME) +
3144 MAX3(sizeof(DRM_PRIMARY_MINOR_NAME),
3145 sizeof(DRM_CONTROL_MINOR_NAME),
3146 sizeof(DRM_RENDER_MINOR_NAME)) +
Eric Engestromce975072016-04-03 19:48:12 +01003147 3 /* length of the node number */;
Emil Velikov5f68d312015-09-07 13:54:32 +01003148}
3149
Emil Velikov291b2bb2015-09-07 18:26:34 +01003150#ifdef __linux__
Emil Velikovaae3f312016-11-01 18:04:06 +00003151static int parse_separate_sysfs_files(int maj, int min,
Emil Velikov11687bf2016-11-30 17:24:21 +00003152 drmPciDeviceInfoPtr device,
3153 bool ignore_revision)
Emil Velikovaae3f312016-11-01 18:04:06 +00003154{
Emil Velikovaae3f312016-11-01 18:04:06 +00003155 static const char *attrs[] = {
3156 "revision", /* Older kernels are missing the file, so check for it first */
3157 "vendor",
3158 "device",
3159 "subsystem_vendor",
3160 "subsystem_device",
3161 };
Eric Engestrom9030a0f2018-09-05 13:29:08 +01003162 char path[PATH_MAX + 1], pci_path[PATH_MAX + 1];
Emil Velikovaae3f312016-11-01 18:04:06 +00003163 unsigned int data[ARRAY_SIZE(attrs)];
3164 FILE *fp;
3165 int ret;
3166
Eric Engestrom9030a0f2018-09-05 13:29:08 +01003167 get_pci_path(maj, min, pci_path);
Emil Velikova0290012018-05-15 17:29:44 +01003168
Emil Velikov11687bf2016-11-30 17:24:21 +00003169 for (unsigned i = ignore_revision ? 1 : 0; i < ARRAY_SIZE(attrs); i++) {
Eric Engestrom9030a0f2018-09-05 13:29:08 +01003170 snprintf(path, PATH_MAX, "%s/%s", pci_path, attrs[i]);
Emil Velikovaae3f312016-11-01 18:04:06 +00003171 fp = fopen(path, "r");
3172 if (!fp)
3173 return -errno;
3174
3175 ret = fscanf(fp, "%x", &data[i]);
3176 fclose(fp);
3177 if (ret != 1)
3178 return -errno;
3179
3180 }
3181
Emil Velikov11687bf2016-11-30 17:24:21 +00003182 device->revision_id = ignore_revision ? 0xff : data[0] & 0xff;
Emil Velikovaae3f312016-11-01 18:04:06 +00003183 device->vendor_id = data[1] & 0xffff;
3184 device->device_id = data[2] & 0xffff;
3185 device->subvendor_id = data[3] & 0xffff;
3186 device->subdevice_id = data[4] & 0xffff;
3187
3188 return 0;
3189}
3190
3191static int parse_config_sysfs_file(int maj, int min,
3192 drmPciDeviceInfoPtr device)
3193{
Eric Engestrom9030a0f2018-09-05 13:29:08 +01003194 char path[PATH_MAX + 1], pci_path[PATH_MAX + 1];
Emil Velikovef5192e2015-09-07 12:47:47 +01003195 unsigned char config[64];
3196 int fd, ret;
3197
Eric Engestrom9030a0f2018-09-05 13:29:08 +01003198 get_pci_path(maj, min, pci_path);
Emil Velikova0290012018-05-15 17:29:44 +01003199
Eric Engestrom9030a0f2018-09-05 13:29:08 +01003200 snprintf(path, PATH_MAX, "%s/config", pci_path);
Emil Velikovef5192e2015-09-07 12:47:47 +01003201 fd = open(path, O_RDONLY);
3202 if (fd < 0)
3203 return -errno;
3204
3205 ret = read(fd, config, sizeof(config));
3206 close(fd);
3207 if (ret < 0)
3208 return -errno;
Emil Velikovb556ea12015-08-17 11:09:06 +08003209
3210 device->vendor_id = config[0] | (config[1] << 8);
3211 device->device_id = config[2] | (config[3] << 8);
3212 device->revision_id = config[8];
3213 device->subvendor_id = config[44] | (config[45] << 8);
3214 device->subdevice_id = config[46] | (config[47] << 8);
3215
3216 return 0;
Emil Velikovaae3f312016-11-01 18:04:06 +00003217}
3218#endif
3219
3220static int drmParsePciDeviceInfo(int maj, int min,
3221 drmPciDeviceInfoPtr device,
3222 uint32_t flags)
3223{
3224#ifdef __linux__
Emil Velikov11687bf2016-11-30 17:24:21 +00003225 if (!(flags & DRM_DEVICE_GET_PCI_REVISION))
3226 return parse_separate_sysfs_files(maj, min, device, true);
3227
3228 if (parse_separate_sysfs_files(maj, min, device, false))
Emil Velikovaae3f312016-11-01 18:04:06 +00003229 return parse_config_sysfs_file(maj, min, device);
3230
3231 return 0;
François Tigeot8f2e0922018-12-12 20:48:36 +01003232#elif defined(__OpenBSD__) || defined(__DragonFly__)
Jonathan Grayc0ef1d02016-12-01 15:18:41 +11003233 struct drm_pciinfo pinfo;
3234 int fd, type;
3235
3236 type = drmGetMinorType(min);
3237 if (type == -1)
3238 return -ENODEV;
3239
3240 fd = drmOpenMinor(min, 0, type);
3241 if (fd < 0)
3242 return -errno;
3243
3244 if (drmIoctl(fd, DRM_IOCTL_GET_PCIINFO, &pinfo)) {
3245 close(fd);
3246 return -errno;
3247 }
3248 close(fd);
3249
3250 device->vendor_id = pinfo.vendor_id;
3251 device->device_id = pinfo.device_id;
3252 device->revision_id = pinfo.revision_id;
3253 device->subvendor_id = pinfo.subvendor_id;
3254 device->subdevice_id = pinfo.subdevice_id;
3255
3256 return 0;
Emil Velikov291b2bb2015-09-07 18:26:34 +01003257#else
3258#warning "Missing implementation of drmParsePciDeviceInfo"
3259 return -EINVAL;
3260#endif
Emil Velikovb556ea12015-08-17 11:09:06 +08003261}
3262
Thierry Reding7b1f37f2016-12-21 17:59:04 +01003263static void drmFreePlatformDevice(drmDevicePtr device)
3264{
3265 if (device->deviceinfo.platform) {
3266 if (device->deviceinfo.platform->compatible) {
3267 char **compatible = device->deviceinfo.platform->compatible;
3268
3269 while (*compatible) {
3270 free(*compatible);
3271 compatible++;
3272 }
3273
3274 free(device->deviceinfo.platform->compatible);
3275 }
3276 }
3277}
3278
3279static void drmFreeHost1xDevice(drmDevicePtr device)
3280{
3281 if (device->deviceinfo.host1x) {
3282 if (device->deviceinfo.host1x->compatible) {
3283 char **compatible = device->deviceinfo.host1x->compatible;
3284
3285 while (*compatible) {
3286 free(*compatible);
3287 compatible++;
3288 }
3289
3290 free(device->deviceinfo.host1x->compatible);
3291 }
3292 }
3293}
3294
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07003295drm_public void drmFreeDevice(drmDevicePtr *device)
Emil Velikovb556ea12015-08-17 11:09:06 +08003296{
Emil Velikovb556ea12015-08-17 11:09:06 +08003297 if (device == NULL)
3298 return;
3299
Thierry Reding7b1f37f2016-12-21 17:59:04 +01003300 if (*device) {
3301 switch ((*device)->bustype) {
3302 case DRM_BUS_PLATFORM:
3303 drmFreePlatformDevice(*device);
3304 break;
3305
3306 case DRM_BUS_HOST1X:
3307 drmFreeHost1xDevice(*device);
3308 break;
3309 }
3310 }
3311
Emil Velikov5f68d312015-09-07 13:54:32 +01003312 free(*device);
3313 *device = NULL;
Emil Velikovb556ea12015-08-17 11:09:06 +08003314}
3315
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07003316drm_public void drmFreeDevices(drmDevicePtr devices[], int count)
Emil Velikovb556ea12015-08-17 11:09:06 +08003317{
3318 int i;
3319
3320 if (devices == NULL)
3321 return;
3322
Qiang Yu6c056ee2016-07-14 17:10:56 +08003323 for (i = 0; i < count; i++)
3324 if (devices[i])
3325 drmFreeDevice(&devices[i]);
Emil Velikovb556ea12015-08-17 11:09:06 +08003326}
3327
Thierry Reding2e57bba2016-12-21 17:54:48 +01003328static drmDevicePtr drmDeviceAlloc(unsigned int type, const char *node,
3329 size_t bus_size, size_t device_size,
3330 char **ptrp)
3331{
3332 size_t max_node_length, extra, size;
3333 drmDevicePtr device;
3334 unsigned int i;
3335 char *ptr;
3336
3337 max_node_length = ALIGN(drmGetMaxNodeName(), sizeof(void *));
3338 extra = DRM_NODE_MAX * (sizeof(void *) + max_node_length);
3339
3340 size = sizeof(*device) + extra + bus_size + device_size;
3341
3342 device = calloc(1, size);
3343 if (!device)
3344 return NULL;
3345
3346 device->available_nodes = 1 << type;
3347
3348 ptr = (char *)device + sizeof(*device);
3349 device->nodes = (char **)ptr;
3350
3351 ptr += DRM_NODE_MAX * sizeof(void *);
3352
3353 for (i = 0; i < DRM_NODE_MAX; i++) {
3354 device->nodes[i] = ptr;
3355 ptr += max_node_length;
3356 }
3357
3358 memcpy(device->nodes[type], node, max_node_length);
3359
3360 *ptrp = ptr;
3361
3362 return device;
3363}
3364
Emil Velikovb40a65d2016-11-30 16:41:27 +00003365static int drmProcessPciDevice(drmDevicePtr *device,
Emil Velikovfae59d72015-09-09 17:54:34 +01003366 const char *node, int node_type,
Emil Velikov138d2312016-11-30 17:13:51 +00003367 int maj, int min, bool fetch_deviceinfo,
3368 uint32_t flags)
Emil Velikovfae59d72015-09-09 17:54:34 +01003369{
Thierry Reding2e57bba2016-12-21 17:54:48 +01003370 drmDevicePtr dev;
Michel Dänzer30455232015-10-14 12:48:52 +09003371 char *addr;
Thierry Reding2e57bba2016-12-21 17:54:48 +01003372 int ret;
Emil Velikovfae59d72015-09-09 17:54:34 +01003373
Thierry Reding2e57bba2016-12-21 17:54:48 +01003374 dev = drmDeviceAlloc(node_type, node, sizeof(drmPciBusInfo),
3375 sizeof(drmPciDeviceInfo), &addr);
3376 if (!dev)
Emil Velikovfae59d72015-09-09 17:54:34 +01003377 return -ENOMEM;
3378
Thierry Reding2e57bba2016-12-21 17:54:48 +01003379 dev->bustype = DRM_BUS_PCI;
Jan Vesely50d3c852016-06-30 14:22:52 -04003380
Thierry Reding2e57bba2016-12-21 17:54:48 +01003381 dev->businfo.pci = (drmPciBusInfoPtr)addr;
Emil Velikovfae59d72015-09-09 17:54:34 +01003382
Thierry Reding2e57bba2016-12-21 17:54:48 +01003383 ret = drmParsePciBusInfo(maj, min, dev->businfo.pci);
Emil Velikovfae59d72015-09-09 17:54:34 +01003384 if (ret)
3385 goto free_device;
3386
3387 // Fetch the device info if the user has requested it
3388 if (fetch_deviceinfo) {
3389 addr += sizeof(drmPciBusInfo);
Thierry Reding2e57bba2016-12-21 17:54:48 +01003390 dev->deviceinfo.pci = (drmPciDeviceInfoPtr)addr;
Emil Velikovfae59d72015-09-09 17:54:34 +01003391
Thierry Reding2e57bba2016-12-21 17:54:48 +01003392 ret = drmParsePciDeviceInfo(maj, min, dev->deviceinfo.pci, flags);
Emil Velikovfae59d72015-09-09 17:54:34 +01003393 if (ret)
3394 goto free_device;
3395 }
Thierry Reding2e57bba2016-12-21 17:54:48 +01003396
3397 *device = dev;
3398
Emil Velikovfae59d72015-09-09 17:54:34 +01003399 return 0;
3400
3401free_device:
Thierry Reding2e57bba2016-12-21 17:54:48 +01003402 free(dev);
Emil Velikovfae59d72015-09-09 17:54:34 +01003403 return ret;
3404}
3405
Thierry Redingf8484cc2016-12-22 00:39:36 +01003406static int drmParseUsbBusInfo(int maj, int min, drmUsbBusInfoPtr info)
3407{
3408#ifdef __linux__
3409 char path[PATH_MAX + 1], *value;
3410 unsigned int bus, dev;
3411 int ret;
3412
3413 snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min);
3414
3415 value = sysfs_uevent_get(path, "BUSNUM");
3416 if (!value)
3417 return -ENOENT;
3418
3419 ret = sscanf(value, "%03u", &bus);
3420 free(value);
3421
3422 if (ret <= 0)
3423 return -errno;
3424
3425 value = sysfs_uevent_get(path, "DEVNUM");
3426 if (!value)
3427 return -ENOENT;
3428
3429 ret = sscanf(value, "%03u", &dev);
3430 free(value);
3431
3432 if (ret <= 0)
3433 return -errno;
3434
3435 info->bus = bus;
3436 info->dev = dev;
3437
3438 return 0;
3439#else
3440#warning "Missing implementation of drmParseUsbBusInfo"
3441 return -EINVAL;
3442#endif
3443}
3444
3445static int drmParseUsbDeviceInfo(int maj, int min, drmUsbDeviceInfoPtr info)
3446{
3447#ifdef __linux__
3448 char path[PATH_MAX + 1], *value;
3449 unsigned int vendor, product;
3450 int ret;
3451
3452 snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min);
3453
3454 value = sysfs_uevent_get(path, "PRODUCT");
3455 if (!value)
3456 return -ENOENT;
3457
3458 ret = sscanf(value, "%x/%x", &vendor, &product);
3459 free(value);
3460
3461 if (ret <= 0)
3462 return -errno;
3463
3464 info->vendor = vendor;
3465 info->product = product;
3466
3467 return 0;
3468#else
3469#warning "Missing implementation of drmParseUsbDeviceInfo"
3470 return -EINVAL;
3471#endif
3472}
3473
3474static int drmProcessUsbDevice(drmDevicePtr *device, const char *node,
3475 int node_type, int maj, int min,
3476 bool fetch_deviceinfo, uint32_t flags)
3477{
3478 drmDevicePtr dev;
3479 char *ptr;
3480 int ret;
3481
3482 dev = drmDeviceAlloc(node_type, node, sizeof(drmUsbBusInfo),
3483 sizeof(drmUsbDeviceInfo), &ptr);
3484 if (!dev)
3485 return -ENOMEM;
3486
3487 dev->bustype = DRM_BUS_USB;
3488
3489 dev->businfo.usb = (drmUsbBusInfoPtr)ptr;
3490
3491 ret = drmParseUsbBusInfo(maj, min, dev->businfo.usb);
3492 if (ret < 0)
3493 goto free_device;
3494
3495 if (fetch_deviceinfo) {
3496 ptr += sizeof(drmUsbBusInfo);
3497 dev->deviceinfo.usb = (drmUsbDeviceInfoPtr)ptr;
3498
3499 ret = drmParseUsbDeviceInfo(maj, min, dev->deviceinfo.usb);
3500 if (ret < 0)
3501 goto free_device;
3502 }
3503
3504 *device = dev;
3505
3506 return 0;
3507
3508free_device:
3509 free(dev);
3510 return ret;
3511}
3512
Thierry Reding7b1f37f2016-12-21 17:59:04 +01003513static int drmParsePlatformBusInfo(int maj, int min, drmPlatformBusInfoPtr info)
3514{
3515#ifdef __linux__
3516 char path[PATH_MAX + 1], *name;
3517
3518 snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min);
3519
3520 name = sysfs_uevent_get(path, "OF_FULLNAME");
3521 if (!name)
3522 return -ENOENT;
3523
3524 strncpy(info->fullname, name, DRM_PLATFORM_DEVICE_NAME_LEN);
3525 info->fullname[DRM_PLATFORM_DEVICE_NAME_LEN - 1] = '\0';
3526 free(name);
3527
3528 return 0;
3529#else
3530#warning "Missing implementation of drmParsePlatformBusInfo"
3531 return -EINVAL;
3532#endif
3533}
3534
3535static int drmParsePlatformDeviceInfo(int maj, int min,
3536 drmPlatformDeviceInfoPtr info)
3537{
3538#ifdef __linux__
3539 char path[PATH_MAX + 1], *value;
3540 unsigned int count, i;
3541 int err;
3542
3543 snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min);
3544
3545 value = sysfs_uevent_get(path, "OF_COMPATIBLE_N");
3546 if (!value)
3547 return -ENOENT;
3548
3549 sscanf(value, "%u", &count);
3550 free(value);
3551
3552 info->compatible = calloc(count + 1, sizeof(*info->compatible));
3553 if (!info->compatible)
3554 return -ENOMEM;
3555
3556 for (i = 0; i < count; i++) {
3557 value = sysfs_uevent_get(path, "OF_COMPATIBLE_%u", i);
3558 if (!value) {
3559 err = -ENOENT;
3560 goto free;
3561 }
3562
3563 info->compatible[i] = value;
3564 }
3565
3566 return 0;
3567
3568free:
3569 while (i--)
3570 free(info->compatible[i]);
3571
3572 free(info->compatible);
3573 return err;
3574#else
3575#warning "Missing implementation of drmParsePlatformDeviceInfo"
3576 return -EINVAL;
3577#endif
3578}
3579
3580static int drmProcessPlatformDevice(drmDevicePtr *device,
3581 const char *node, int node_type,
3582 int maj, int min, bool fetch_deviceinfo,
3583 uint32_t flags)
3584{
3585 drmDevicePtr dev;
3586 char *ptr;
3587 int ret;
3588
3589 dev = drmDeviceAlloc(node_type, node, sizeof(drmPlatformBusInfo),
3590 sizeof(drmPlatformDeviceInfo), &ptr);
3591 if (!dev)
3592 return -ENOMEM;
3593
3594 dev->bustype = DRM_BUS_PLATFORM;
3595
3596 dev->businfo.platform = (drmPlatformBusInfoPtr)ptr;
3597
3598 ret = drmParsePlatformBusInfo(maj, min, dev->businfo.platform);
3599 if (ret < 0)
3600 goto free_device;
3601
3602 if (fetch_deviceinfo) {
3603 ptr += sizeof(drmPlatformBusInfo);
3604 dev->deviceinfo.platform = (drmPlatformDeviceInfoPtr)ptr;
3605
3606 ret = drmParsePlatformDeviceInfo(maj, min, dev->deviceinfo.platform);
3607 if (ret < 0)
3608 goto free_device;
3609 }
3610
3611 *device = dev;
3612
3613 return 0;
3614
3615free_device:
3616 free(dev);
3617 return ret;
3618}
3619
3620static int drmParseHost1xBusInfo(int maj, int min, drmHost1xBusInfoPtr info)
3621{
3622#ifdef __linux__
3623 char path[PATH_MAX + 1], *name;
3624
3625 snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min);
3626
3627 name = sysfs_uevent_get(path, "OF_FULLNAME");
3628 if (!name)
3629 return -ENOENT;
3630
3631 strncpy(info->fullname, name, DRM_HOST1X_DEVICE_NAME_LEN);
3632 info->fullname[DRM_HOST1X_DEVICE_NAME_LEN - 1] = '\0';
3633 free(name);
3634
3635 return 0;
3636#else
3637#warning "Missing implementation of drmParseHost1xBusInfo"
3638 return -EINVAL;
3639#endif
3640}
3641
3642static int drmParseHost1xDeviceInfo(int maj, int min,
3643 drmHost1xDeviceInfoPtr info)
3644{
3645#ifdef __linux__
3646 char path[PATH_MAX + 1], *value;
3647 unsigned int count, i;
3648 int err;
3649
3650 snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min);
3651
3652 value = sysfs_uevent_get(path, "OF_COMPATIBLE_N");
3653 if (!value)
3654 return -ENOENT;
3655
3656 sscanf(value, "%u", &count);
3657 free(value);
3658
3659 info->compatible = calloc(count + 1, sizeof(*info->compatible));
3660 if (!info->compatible)
3661 return -ENOMEM;
3662
3663 for (i = 0; i < count; i++) {
3664 value = sysfs_uevent_get(path, "OF_COMPATIBLE_%u", i);
3665 if (!value) {
3666 err = -ENOENT;
3667 goto free;
3668 }
3669
3670 info->compatible[i] = value;
3671 }
3672
3673 return 0;
3674
3675free:
3676 while (i--)
3677 free(info->compatible[i]);
3678
3679 free(info->compatible);
3680 return err;
3681#else
3682#warning "Missing implementation of drmParseHost1xDeviceInfo"
3683 return -EINVAL;
3684#endif
3685}
3686
3687static int drmProcessHost1xDevice(drmDevicePtr *device,
3688 const char *node, int node_type,
3689 int maj, int min, bool fetch_deviceinfo,
3690 uint32_t flags)
3691{
3692 drmDevicePtr dev;
3693 char *ptr;
3694 int ret;
3695
3696 dev = drmDeviceAlloc(node_type, node, sizeof(drmHost1xBusInfo),
3697 sizeof(drmHost1xDeviceInfo), &ptr);
3698 if (!dev)
3699 return -ENOMEM;
3700
3701 dev->bustype = DRM_BUS_HOST1X;
3702
3703 dev->businfo.host1x = (drmHost1xBusInfoPtr)ptr;
3704
3705 ret = drmParseHost1xBusInfo(maj, min, dev->businfo.host1x);
3706 if (ret < 0)
3707 goto free_device;
3708
3709 if (fetch_deviceinfo) {
3710 ptr += sizeof(drmHost1xBusInfo);
3711 dev->deviceinfo.host1x = (drmHost1xDeviceInfoPtr)ptr;
3712
3713 ret = drmParseHost1xDeviceInfo(maj, min, dev->deviceinfo.host1x);
3714 if (ret < 0)
3715 goto free_device;
3716 }
3717
3718 *device = dev;
3719
3720 return 0;
3721
3722free_device:
3723 free(dev);
3724 return ret;
3725}
3726
Emil Velikovf808fee2018-05-15 15:02:52 +01003727static int
3728process_device(drmDevicePtr *device, const char *d_name,
3729 int req_subsystem_type,
3730 bool fetch_deviceinfo, uint32_t flags)
3731{
3732 struct stat sbuf;
3733 char node[PATH_MAX + 1];
3734 int node_type, subsystem_type;
3735 unsigned int maj, min;
3736
3737 node_type = drmGetNodeType(d_name);
3738 if (node_type < 0)
3739 return -1;
3740
3741 snprintf(node, PATH_MAX, "%s/%s", DRM_DIR_NAME, d_name);
3742 if (stat(node, &sbuf))
3743 return -1;
3744
3745 maj = major(sbuf.st_rdev);
3746 min = minor(sbuf.st_rdev);
3747
Thomas Hellstromf8392582018-08-31 13:47:05 +02003748 if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode))
Emil Velikovf808fee2018-05-15 15:02:52 +01003749 return -1;
3750
3751 subsystem_type = drmParseSubsystemType(maj, min);
3752 if (req_subsystem_type != -1 && req_subsystem_type != subsystem_type)
3753 return -1;
3754
3755 switch (subsystem_type) {
3756 case DRM_BUS_PCI:
Emil Velikov39885802018-05-15 17:37:49 +01003757 case DRM_BUS_VIRTIO:
Emil Velikovf808fee2018-05-15 15:02:52 +01003758 return drmProcessPciDevice(device, node, node_type, maj, min,
3759 fetch_deviceinfo, flags);
3760 case DRM_BUS_USB:
3761 return drmProcessUsbDevice(device, node, node_type, maj, min,
3762 fetch_deviceinfo, flags);
3763 case DRM_BUS_PLATFORM:
3764 return drmProcessPlatformDevice(device, node, node_type, maj, min,
3765 fetch_deviceinfo, flags);
3766 case DRM_BUS_HOST1X:
3767 return drmProcessHost1xDevice(device, node, node_type, maj, min,
3768 fetch_deviceinfo, flags);
3769 default:
3770 return -1;
3771 }
3772}
3773
Qiang Yu3c208932016-07-14 17:10:55 +08003774/* Consider devices located on the same bus as duplicate and fold the respective
3775 * entries into a single one.
3776 *
3777 * Note: this leaves "gaps" in the array, while preserving the length.
3778 */
Emil Velikovfae59d72015-09-09 17:54:34 +01003779static void drmFoldDuplicatedDevices(drmDevicePtr local_devices[], int count)
3780{
3781 int node_type, i, j;
3782
3783 for (i = 0; i < count; i++) {
3784 for (j = i + 1; j < count; j++) {
Adam Jacksona2fa2e02017-05-04 15:57:14 -04003785 if (drmDevicesEqual(local_devices[i], local_devices[j])) {
Emil Velikovfae59d72015-09-09 17:54:34 +01003786 local_devices[i]->available_nodes |= local_devices[j]->available_nodes;
3787 node_type = log2(local_devices[j]->available_nodes);
3788 memcpy(local_devices[i]->nodes[node_type],
3789 local_devices[j]->nodes[node_type], drmGetMaxNodeName());
3790 drmFreeDevice(&local_devices[j]);
3791 }
3792 }
3793 }
3794}
3795
Emil Velikov11687bf2016-11-30 17:24:21 +00003796/* Check that the given flags are valid returning 0 on success */
3797static int
3798drm_device_validate_flags(uint32_t flags)
3799{
3800 return (flags & ~DRM_DEVICE_GET_PCI_REVISION);
3801}
3802
Emil Velikov56e72d32018-06-21 16:06:35 +01003803static bool
3804drm_device_has_rdev(drmDevicePtr device, dev_t find_rdev)
3805{
3806 struct stat sbuf;
3807
3808 for (int i = 0; i < DRM_NODE_MAX; i++) {
3809 if (device->available_nodes & 1 << i) {
3810 if (stat(device->nodes[i], &sbuf) == 0 &&
3811 sbuf.st_rdev == find_rdev)
3812 return true;
3813 }
3814 }
3815 return false;
3816}
3817
Emil Velikov95b262f2018-05-15 16:32:10 +01003818/*
3819 * The kernel drm core has a number of places that assume maximum of
3820 * 3x64 devices nodes. That's 64 for each of primary, control and
3821 * render nodes. Rounded it up to 256 for simplicity.
3822 */
3823#define MAX_DRM_NODES 256
3824
Emil Velikovb556ea12015-08-17 11:09:06 +08003825/**
Emil Velikovccedf662015-09-09 16:02:18 +01003826 * Get information about the opened drm device
3827 *
3828 * \param fd file descriptor of the drm device
Emil Velikov11687bf2016-11-30 17:24:21 +00003829 * \param flags feature/behaviour bitmask
Emil Velikovccedf662015-09-09 16:02:18 +01003830 * \param device the address of a drmDevicePtr where the information
3831 * will be allocated in stored
3832 *
3833 * \return zero on success, negative error code otherwise.
Emil Velikov11687bf2016-11-30 17:24:21 +00003834 *
3835 * \note Unlike drmGetDevice it does not retrieve the pci device revision field
3836 * unless the DRM_DEVICE_GET_PCI_REVISION \p flag is set.
Emil Velikovccedf662015-09-09 16:02:18 +01003837 */
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07003838drm_public int drmGetDevice2(int fd, uint32_t flags, drmDevicePtr *device)
Emil Velikovccedf662015-09-09 16:02:18 +01003839{
Jonathan Gray08257922016-12-01 15:18:43 +11003840#ifdef __OpenBSD__
3841 /*
3842 * DRI device nodes on OpenBSD are not in their own directory, they reside
3843 * in /dev along with a large number of statically generated /dev nodes.
3844 * Avoid stat'ing all of /dev needlessly by implementing this custom path.
3845 */
3846 drmDevicePtr d;
3847 struct stat sbuf;
3848 char node[PATH_MAX + 1];
3849 const char *dev_name;
3850 int node_type, subsystem_type;
Jonathan Grayd5cf3f92016-12-17 16:09:51 +11003851 int maj, min, n, ret, base;
Jonathan Gray08257922016-12-01 15:18:43 +11003852
3853 if (fd == -1 || device == NULL)
3854 return -EINVAL;
3855
3856 if (fstat(fd, &sbuf))
3857 return -errno;
3858
3859 maj = major(sbuf.st_rdev);
3860 min = minor(sbuf.st_rdev);
3861
Thomas Hellstromf8392582018-08-31 13:47:05 +02003862 if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode))
Jonathan Gray08257922016-12-01 15:18:43 +11003863 return -EINVAL;
3864
3865 node_type = drmGetMinorType(min);
3866 if (node_type == -1)
3867 return -ENODEV;
3868
3869 switch (node_type) {
3870 case DRM_NODE_PRIMARY:
3871 dev_name = DRM_DEV_NAME;
3872 break;
3873 case DRM_NODE_CONTROL:
3874 dev_name = DRM_CONTROL_DEV_NAME;
3875 break;
3876 case DRM_NODE_RENDER:
3877 dev_name = DRM_RENDER_DEV_NAME;
3878 break;
3879 default:
3880 return -EINVAL;
3881 };
3882
Jonathan Grayd5cf3f92016-12-17 16:09:51 +11003883 base = drmGetMinorBase(node_type);
3884 if (base < 0)
3885 return -EINVAL;
3886
3887 n = snprintf(node, PATH_MAX, dev_name, DRM_DIR_NAME, min - base);
Jonathan Gray08257922016-12-01 15:18:43 +11003888 if (n == -1 || n >= PATH_MAX)
3889 return -errno;
3890 if (stat(node, &sbuf))
3891 return -EINVAL;
3892
3893 subsystem_type = drmParseSubsystemType(maj, min);
3894 if (subsystem_type != DRM_BUS_PCI)
3895 return -ENODEV;
3896
3897 ret = drmProcessPciDevice(&d, node, node_type, maj, min, true, flags);
3898 if (ret)
3899 return ret;
3900
3901 *device = d;
3902
3903 return 0;
3904#else
Emil Velikov95b262f2018-05-15 16:32:10 +01003905 drmDevicePtr local_devices[MAX_DRM_NODES];
Emil Velikovccedf662015-09-09 16:02:18 +01003906 drmDevicePtr d;
3907 DIR *sysdir;
3908 struct dirent *dent;
3909 struct stat sbuf;
Emil Velikovf808fee2018-05-15 15:02:52 +01003910 int subsystem_type;
Emil Velikovccedf662015-09-09 16:02:18 +01003911 int maj, min;
3912 int ret, i, node_count;
Qiang Yu3c208932016-07-14 17:10:55 +08003913 dev_t find_rdev;
Emil Velikov11687bf2016-11-30 17:24:21 +00003914
3915 if (drm_device_validate_flags(flags))
3916 return -EINVAL;
Emil Velikovccedf662015-09-09 16:02:18 +01003917
3918 if (fd == -1 || device == NULL)
3919 return -EINVAL;
3920
3921 if (fstat(fd, &sbuf))
3922 return -errno;
3923
Qiang Yu3c208932016-07-14 17:10:55 +08003924 find_rdev = sbuf.st_rdev;
Emil Velikovccedf662015-09-09 16:02:18 +01003925 maj = major(sbuf.st_rdev);
3926 min = minor(sbuf.st_rdev);
3927
Thomas Hellstromf8392582018-08-31 13:47:05 +02003928 if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode))
Emil Velikovccedf662015-09-09 16:02:18 +01003929 return -EINVAL;
3930
3931 subsystem_type = drmParseSubsystemType(maj, min);
Emil Velikov7f52a0e2018-05-15 16:43:58 +01003932 if (subsystem_type < 0)
3933 return subsystem_type;
Emil Velikovccedf662015-09-09 16:02:18 +01003934
Emil Velikovccedf662015-09-09 16:02:18 +01003935 sysdir = opendir(DRM_DIR_NAME);
Emil Velikov95b262f2018-05-15 16:32:10 +01003936 if (!sysdir)
3937 return -errno;
Emil Velikovccedf662015-09-09 16:02:18 +01003938
3939 i = 0;
3940 while ((dent = readdir(sysdir))) {
Emil Velikovf808fee2018-05-15 15:02:52 +01003941 ret = process_device(&d, dent->d_name, subsystem_type, true, flags);
3942 if (ret)
Emil Velikovccedf662015-09-09 16:02:18 +01003943 continue;
3944
Emil Velikov95b262f2018-05-15 16:32:10 +01003945 if (i >= MAX_DRM_NODES) {
3946 fprintf(stderr, "More than %d drm nodes detected. "
3947 "Please report a bug - that should not happen.\n"
3948 "Skipping extra nodes\n", MAX_DRM_NODES);
3949 break;
Emil Velikovccedf662015-09-09 16:02:18 +01003950 }
Emil Velikov56e72d32018-06-21 16:06:35 +01003951 local_devices[i] = d;
Emil Velikovccedf662015-09-09 16:02:18 +01003952 i++;
3953 }
3954 node_count = i;
3955
Emil Velikovccedf662015-09-09 16:02:18 +01003956 drmFoldDuplicatedDevices(local_devices, node_count);
3957
Mariusz Ceier4519db22018-07-29 10:20:14 +02003958 *device = NULL;
3959
Emil Velikov56e72d32018-06-21 16:06:35 +01003960 for (i = 0; i < node_count; i++) {
3961 if (!local_devices[i])
3962 continue;
3963
3964 if (drm_device_has_rdev(local_devices[i], find_rdev))
3965 *device = local_devices[i];
3966 else
3967 drmFreeDevice(&local_devices[i]);
3968 }
Emil Velikovccedf662015-09-09 16:02:18 +01003969
Emil Velikovccedf662015-09-09 16:02:18 +01003970 closedir(sysdir);
Rob Herring677cd972016-10-21 10:07:59 -07003971 if (*device == NULL)
Thierry Redinge17cad12016-12-21 18:00:52 +01003972 return -ENODEV;
Emil Velikovccedf662015-09-09 16:02:18 +01003973 return 0;
Jonathan Gray08257922016-12-01 15:18:43 +11003974#endif
Emil Velikovccedf662015-09-09 16:02:18 +01003975}
3976
3977/**
Emil Velikov11687bf2016-11-30 17:24:21 +00003978 * Get information about the opened drm device
3979 *
3980 * \param fd file descriptor of the drm device
3981 * \param device the address of a drmDevicePtr where the information
3982 * will be allocated in stored
3983 *
3984 * \return zero on success, negative error code otherwise.
3985 */
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07003986drm_public int drmGetDevice(int fd, drmDevicePtr *device)
Emil Velikov11687bf2016-11-30 17:24:21 +00003987{
3988 return drmGetDevice2(fd, DRM_DEVICE_GET_PCI_REVISION, device);
3989}
3990
3991/**
Emil Velikovb556ea12015-08-17 11:09:06 +08003992 * Get drm devices on the system
3993 *
Emil Velikov11687bf2016-11-30 17:24:21 +00003994 * \param flags feature/behaviour bitmask
Emil Velikovb556ea12015-08-17 11:09:06 +08003995 * \param devices the array of devices with drmDevicePtr elements
3996 * can be NULL to get the device number first
3997 * \param max_devices the maximum number of devices for the array
3998 *
3999 * \return on error - negative error code,
4000 * if devices is NULL - total number of devices available on the system,
4001 * alternatively the number of devices stored in devices[], which is
4002 * capped by the max_devices.
Emil Velikov11687bf2016-11-30 17:24:21 +00004003 *
4004 * \note Unlike drmGetDevices it does not retrieve the pci device revision field
4005 * unless the DRM_DEVICE_GET_PCI_REVISION \p flag is set.
Emil Velikovb556ea12015-08-17 11:09:06 +08004006 */
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07004007drm_public int drmGetDevices2(uint32_t flags, drmDevicePtr devices[],
4008 int max_devices)
Emil Velikovb556ea12015-08-17 11:09:06 +08004009{
Emil Velikov95b262f2018-05-15 16:32:10 +01004010 drmDevicePtr local_devices[MAX_DRM_NODES];
Emil Velikov5f68d312015-09-07 13:54:32 +01004011 drmDevicePtr device;
4012 DIR *sysdir;
4013 struct dirent *dent;
Emil Velikovfae59d72015-09-09 17:54:34 +01004014 int ret, i, node_count, device_count;
Emil Velikov11687bf2016-11-30 17:24:21 +00004015
4016 if (drm_device_validate_flags(flags))
4017 return -EINVAL;
Emil Velikovb556ea12015-08-17 11:09:06 +08004018
Emil Velikovb556ea12015-08-17 11:09:06 +08004019 sysdir = opendir(DRM_DIR_NAME);
Emil Velikov95b262f2018-05-15 16:32:10 +01004020 if (!sysdir)
4021 return -errno;
Emil Velikovb556ea12015-08-17 11:09:06 +08004022
Emil Velikov5f68d312015-09-07 13:54:32 +01004023 i = 0;
Emil Velikovb556ea12015-08-17 11:09:06 +08004024 while ((dent = readdir(sysdir))) {
Emil Velikovf808fee2018-05-15 15:02:52 +01004025 ret = process_device(&device, dent->d_name, -1, devices != NULL, flags);
4026 if (ret)
Emil Velikovb556ea12015-08-17 11:09:06 +08004027 continue;
4028
Emil Velikov95b262f2018-05-15 16:32:10 +01004029 if (i >= MAX_DRM_NODES) {
4030 fprintf(stderr, "More than %d drm nodes detected. "
4031 "Please report a bug - that should not happen.\n"
4032 "Skipping extra nodes\n", MAX_DRM_NODES);
4033 break;
Emil Velikov5f68d312015-09-07 13:54:32 +01004034 }
Emil Velikov5f68d312015-09-07 13:54:32 +01004035 local_devices[i] = device;
Emil Velikovb556ea12015-08-17 11:09:06 +08004036 i++;
4037 }
Emil Velikovb556ea12015-08-17 11:09:06 +08004038 node_count = i;
4039
Emil Velikovfae59d72015-09-09 17:54:34 +01004040 drmFoldDuplicatedDevices(local_devices, node_count);
Emil Velikovb556ea12015-08-17 11:09:06 +08004041
Emil Velikov5f68d312015-09-07 13:54:32 +01004042 device_count = 0;
Qiang Yu70b64072016-06-06 12:29:16 -04004043 for (i = 0; i < node_count; i++) {
Jan Vesely50d3c852016-06-30 14:22:52 -04004044 if (!local_devices[i])
4045 continue;
Qiang Yu70b64072016-06-06 12:29:16 -04004046
Emil Velikov5f68d312015-09-07 13:54:32 +01004047 if ((devices != NULL) && (device_count < max_devices))
4048 devices[device_count] = local_devices[i];
4049 else
4050 drmFreeDevice(&local_devices[i]);
4051
4052 device_count++;
Emil Velikovb556ea12015-08-17 11:09:06 +08004053 }
4054
Emil Velikovb556ea12015-08-17 11:09:06 +08004055 closedir(sysdir);
Emil Velikov5f68d312015-09-07 13:54:32 +01004056 return device_count;
Emil Velikovb556ea12015-08-17 11:09:06 +08004057}
Emil Velikov37d790f2016-11-10 17:26:50 +00004058
Emil Velikov11687bf2016-11-30 17:24:21 +00004059/**
4060 * Get drm devices on the system
4061 *
4062 * \param devices the array of devices with drmDevicePtr elements
4063 * can be NULL to get the device number first
4064 * \param max_devices the maximum number of devices for the array
4065 *
4066 * \return on error - negative error code,
4067 * if devices is NULL - total number of devices available on the system,
4068 * alternatively the number of devices stored in devices[], which is
4069 * capped by the max_devices.
4070 */
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07004071drm_public int drmGetDevices(drmDevicePtr devices[], int max_devices)
Emil Velikov11687bf2016-11-30 17:24:21 +00004072{
4073 return drmGetDevices2(DRM_DEVICE_GET_PCI_REVISION, devices, max_devices);
4074}
4075
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07004076drm_public char *drmGetDeviceNameFromFd2(int fd)
Emil Velikov37d790f2016-11-10 17:26:50 +00004077{
4078#ifdef __linux__
4079 struct stat sbuf;
Thierry Reding5403cb32017-01-18 08:29:23 +01004080 char path[PATH_MAX + 1], *value;
Emil Velikov37d790f2016-11-10 17:26:50 +00004081 unsigned int maj, min;
Emil Velikov37d790f2016-11-10 17:26:50 +00004082
4083 if (fstat(fd, &sbuf))
4084 return NULL;
4085
4086 maj = major(sbuf.st_rdev);
4087 min = minor(sbuf.st_rdev);
4088
Thomas Hellstromf8392582018-08-31 13:47:05 +02004089 if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode))
Emil Velikov37d790f2016-11-10 17:26:50 +00004090 return NULL;
4091
Thierry Reding5403cb32017-01-18 08:29:23 +01004092 snprintf(path, sizeof(path), "/sys/dev/char/%d:%d", maj, min);
4093
4094 value = sysfs_uevent_get(path, "DEVNAME");
4095 if (!value)
Emil Velikov37d790f2016-11-10 17:26:50 +00004096 return NULL;
4097
Thierry Reding5403cb32017-01-18 08:29:23 +01004098 snprintf(path, sizeof(path), "/dev/%s", value);
4099 free(value);
Emil Velikov37d790f2016-11-10 17:26:50 +00004100
Thierry Reding5403cb32017-01-18 08:29:23 +01004101 return strdup(path);
Emil Velikov37d790f2016-11-10 17:26:50 +00004102#else
Jonathan Graye2e766d2016-12-17 16:09:52 +11004103 struct stat sbuf;
4104 char node[PATH_MAX + 1];
4105 const char *dev_name;
4106 int node_type;
4107 int maj, min, n, base;
4108
4109 if (fstat(fd, &sbuf))
4110 return NULL;
4111
4112 maj = major(sbuf.st_rdev);
4113 min = minor(sbuf.st_rdev);
4114
Thomas Hellstromf8392582018-08-31 13:47:05 +02004115 if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode))
Jonathan Graye2e766d2016-12-17 16:09:52 +11004116 return NULL;
4117
4118 node_type = drmGetMinorType(min);
4119 if (node_type == -1)
4120 return NULL;
4121
4122 switch (node_type) {
4123 case DRM_NODE_PRIMARY:
4124 dev_name = DRM_DEV_NAME;
4125 break;
4126 case DRM_NODE_CONTROL:
4127 dev_name = DRM_CONTROL_DEV_NAME;
4128 break;
4129 case DRM_NODE_RENDER:
4130 dev_name = DRM_RENDER_DEV_NAME;
4131 break;
4132 default:
4133 return NULL;
4134 };
4135
4136 base = drmGetMinorBase(node_type);
4137 if (base < 0)
4138 return NULL;
4139
4140 n = snprintf(node, PATH_MAX, dev_name, DRM_DIR_NAME, min - base);
4141 if (n == -1 || n >= PATH_MAX)
4142 return NULL;
4143
4144 return strdup(node);
Emil Velikov37d790f2016-11-10 17:26:50 +00004145#endif
4146}
Dave Airliefc492272017-06-17 11:01:01 +10004147
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07004148drm_public int drmSyncobjCreate(int fd, uint32_t flags, uint32_t *handle)
Dave Airliefc492272017-06-17 11:01:01 +10004149{
4150 struct drm_syncobj_create args;
4151 int ret;
4152
4153 memclear(args);
4154 args.flags = flags;
4155 args.handle = 0;
4156 ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_CREATE, &args);
4157 if (ret)
Dave Airlie61ff9772017-10-25 07:43:56 +01004158 return ret;
Dave Airliefc492272017-06-17 11:01:01 +10004159 *handle = args.handle;
4160 return 0;
4161}
4162
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07004163drm_public int drmSyncobjDestroy(int fd, uint32_t handle)
Dave Airliefc492272017-06-17 11:01:01 +10004164{
4165 struct drm_syncobj_destroy args;
4166
4167 memclear(args);
4168 args.handle = handle;
4169 return drmIoctl(fd, DRM_IOCTL_SYNCOBJ_DESTROY, &args);
4170}
4171
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07004172drm_public int drmSyncobjHandleToFD(int fd, uint32_t handle, int *obj_fd)
Dave Airliefc492272017-06-17 11:01:01 +10004173{
4174 struct drm_syncobj_handle args;
4175 int ret;
4176
4177 memclear(args);
4178 args.fd = -1;
4179 args.handle = handle;
4180 ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD, &args);
4181 if (ret)
Dave Airlie61ff9772017-10-25 07:43:56 +01004182 return ret;
Dave Airliefc492272017-06-17 11:01:01 +10004183 *obj_fd = args.fd;
4184 return 0;
4185}
4186
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07004187drm_public int drmSyncobjFDToHandle(int fd, int obj_fd, uint32_t *handle)
Dave Airliefc492272017-06-17 11:01:01 +10004188{
4189 struct drm_syncobj_handle args;
4190 int ret;
4191
4192 memclear(args);
4193 args.fd = obj_fd;
4194 args.handle = 0;
4195 ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE, &args);
4196 if (ret)
Dave Airlie61ff9772017-10-25 07:43:56 +01004197 return ret;
Dave Airliefc492272017-06-17 11:01:01 +10004198 *handle = args.handle;
4199 return 0;
4200}
4201
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07004202drm_public int drmSyncobjImportSyncFile(int fd, uint32_t handle,
4203 int sync_file_fd)
Dave Airliefc492272017-06-17 11:01:01 +10004204{
4205 struct drm_syncobj_handle args;
4206
4207 memclear(args);
4208 args.fd = sync_file_fd;
4209 args.handle = handle;
4210 args.flags = DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_IMPORT_SYNC_FILE;
4211 return drmIoctl(fd, DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE, &args);
4212}
4213
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07004214drm_public int drmSyncobjExportSyncFile(int fd, uint32_t handle,
4215 int *sync_file_fd)
Dave Airliefc492272017-06-17 11:01:01 +10004216{
4217 struct drm_syncobj_handle args;
4218 int ret;
4219
4220 memclear(args);
4221 args.fd = -1;
4222 args.handle = handle;
4223 args.flags = DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_EXPORT_SYNC_FILE;
4224 ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD, &args);
4225 if (ret)
Dave Airlie61ff9772017-10-25 07:43:56 +01004226 return ret;
Dave Airliefc492272017-06-17 11:01:01 +10004227 *sync_file_fd = args.fd;
4228 return 0;
4229}
Marek Olšák2048a9e2017-09-11 21:57:32 +02004230
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07004231drm_public int drmSyncobjWait(int fd, uint32_t *handles, unsigned num_handles,
4232 int64_t timeout_nsec, unsigned flags,
4233 uint32_t *first_signaled)
Marek Olšák2048a9e2017-09-11 21:57:32 +02004234{
Dave Airlie61ff9772017-10-25 07:43:56 +01004235 struct drm_syncobj_wait args;
4236 int ret;
Marek Olšák2048a9e2017-09-11 21:57:32 +02004237
Dave Airlie61ff9772017-10-25 07:43:56 +01004238 memclear(args);
Bas Nieuwenhuizenb1e63d92018-02-06 11:21:35 +01004239 args.handles = (uintptr_t)handles;
Dave Airlie61ff9772017-10-25 07:43:56 +01004240 args.timeout_nsec = timeout_nsec;
4241 args.count_handles = num_handles;
4242 args.flags = flags;
Marek Olšák2048a9e2017-09-11 21:57:32 +02004243
Dave Airlie61ff9772017-10-25 07:43:56 +01004244 ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_WAIT, &args);
4245 if (ret < 0)
Chunming Zhoubde3b9b2018-02-07 11:22:32 +08004246 return -errno;
Marek Olšák2048a9e2017-09-11 21:57:32 +02004247
Dave Airlie61ff9772017-10-25 07:43:56 +01004248 if (first_signaled)
4249 *first_signaled = args.first_signaled;
4250 return ret;
Marek Olšák2048a9e2017-09-11 21:57:32 +02004251}
Bas Nieuwenhuizen1abcced2017-12-17 00:27:09 +01004252
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07004253drm_public int drmSyncobjReset(int fd, const uint32_t *handles,
4254 uint32_t handle_count)
Bas Nieuwenhuizen1abcced2017-12-17 00:27:09 +01004255{
4256 struct drm_syncobj_array args;
4257 int ret;
4258
4259 memclear(args);
4260 args.handles = (uintptr_t)handles;
4261 args.count_handles = handle_count;
4262
4263 ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_RESET, &args);
4264 return ret;
4265}
4266
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07004267drm_public int drmSyncobjSignal(int fd, const uint32_t *handles,
4268 uint32_t handle_count)
Bas Nieuwenhuizen1abcced2017-12-17 00:27:09 +01004269{
4270 struct drm_syncobj_array args;
4271 int ret;
4272
4273 memclear(args);
4274 args.handles = (uintptr_t)handles;
4275 args.count_handles = handle_count;
4276
4277 ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_SIGNAL, &args);
4278 return ret;
4279}