blob: 155c5a8a89a3d4877ad056abf925517a5fd96e8d [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/**
Eric Engestrom360292c2018-12-19 14:55:45 +0000182 * Call ioctl, restarting if it is interrupted
Keith Packard8b9ab102008-06-13 16:03:22 -0700183 */
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.
Eric Engestrom360292c2018-12-19 14:55:45 +0000292 * If any other failure happened then it will output error message using
Pauli Nieminenc5a5bbb2009-07-06 23:37:20 +0300293 * 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{
Prabhanjan Kandula225d73f2019-04-24 10:08:39 -0700753 if (name != NULL && drm_server_info &&
754 drm_server_info->load_module && !drmAvailable()) {
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.
Eric Engestrom360292c2018-12-19 14:55:45 +00001461 * \param flags flags that determine the state of the hardware when the function
Jose Fonsecad2443b22003-05-27 00:37:33 +00001462 * 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
Eric Engestromeba66092019-02-08 14:46:07 +00002746drm_public int drmIsMaster(int fd)
Christopher James Halse Rogers17dfe3a2019-01-23 15:38:45 +11002747{
2748 /* Detect master by attempting something that requires master.
2749 *
2750 * Authenticating magic tokens requires master and 0 is an
2751 * internal kernel detail which we could use. Attempting this on
2752 * a master fd would fail therefore fail with EINVAL because 0
2753 * is invalid.
2754 *
2755 * A non-master fd will fail with EACCES, as the kernel checks
2756 * for master before attempting to do anything else.
2757 *
2758 * Since we don't want to leak implementation details, use
2759 * EACCES.
2760 */
2761 return drmAuthMagic(fd, 0) != -EACCES;
2762}
2763
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07002764drm_public char *drmGetDeviceNameFromFd(int fd)
Kristian Høgsberg22d46662009-11-23 20:51:34 -05002765{
Jan Vesely50d3c852016-06-30 14:22:52 -04002766 char name[128];
2767 struct stat sbuf;
2768 dev_t d;
2769 int i;
Kristian Høgsberg22d46662009-11-23 20:51:34 -05002770
Jan Vesely50d3c852016-06-30 14:22:52 -04002771 /* The whole drmOpen thing is a fiasco and we need to find a way
2772 * back to just using open(2). For now, however, lets just make
2773 * things worse with even more ad hoc directory walking code to
2774 * discover the device file name. */
Kristian Høgsberg22d46662009-11-23 20:51:34 -05002775
Jan Vesely50d3c852016-06-30 14:22:52 -04002776 fstat(fd, &sbuf);
2777 d = sbuf.st_rdev;
Kristian Høgsberg22d46662009-11-23 20:51:34 -05002778
Jan Vesely50d3c852016-06-30 14:22:52 -04002779 for (i = 0; i < DRM_MAX_MINOR; i++) {
2780 snprintf(name, sizeof name, DRM_DEV_NAME, DRM_DIR_NAME, i);
2781 if (stat(name, &sbuf) == 0 && sbuf.st_rdev == d)
2782 break;
2783 }
2784 if (i == DRM_MAX_MINOR)
2785 return NULL;
Kristian Høgsberg22d46662009-11-23 20:51:34 -05002786
Jan Vesely50d3c852016-06-30 14:22:52 -04002787 return strdup(name);
Kristian Høgsberg22d46662009-11-23 20:51:34 -05002788}
Dave Airliecc0a1452012-07-14 09:52:17 +00002789
Thomas Hellstromf8392582018-08-31 13:47:05 +02002790static bool drmNodeIsDRM(int maj, int min)
2791{
2792#ifdef __linux__
2793 char path[64];
2794 struct stat sbuf;
2795
2796 snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device/drm",
2797 maj, min);
2798 return stat(path, &sbuf) == 0;
2799#else
2800 return maj == DRM_MAJOR;
2801#endif
2802}
2803
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07002804drm_public int drmGetNodeTypeFromFd(int fd)
Frank Binns1f735782015-02-13 10:51:15 +00002805{
Jan Vesely50d3c852016-06-30 14:22:52 -04002806 struct stat sbuf;
2807 int maj, min, type;
Frank Binns1f735782015-02-13 10:51:15 +00002808
Jan Vesely50d3c852016-06-30 14:22:52 -04002809 if (fstat(fd, &sbuf))
2810 return -1;
Frank Binns1f735782015-02-13 10:51:15 +00002811
Jan Vesely50d3c852016-06-30 14:22:52 -04002812 maj = major(sbuf.st_rdev);
2813 min = minor(sbuf.st_rdev);
Frank Binns1f735782015-02-13 10:51:15 +00002814
Thomas Hellstromf8392582018-08-31 13:47:05 +02002815 if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode)) {
Jan Vesely50d3c852016-06-30 14:22:52 -04002816 errno = EINVAL;
2817 return -1;
2818 }
Frank Binns1f735782015-02-13 10:51:15 +00002819
Jan Vesely50d3c852016-06-30 14:22:52 -04002820 type = drmGetMinorType(min);
2821 if (type == -1)
2822 errno = ENODEV;
2823 return type;
Frank Binns1f735782015-02-13 10:51:15 +00002824}
2825
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07002826drm_public int drmPrimeHandleToFD(int fd, uint32_t handle, uint32_t flags,
2827 int *prime_fd)
Dave Airliecc0a1452012-07-14 09:52:17 +00002828{
Jan Vesely50d3c852016-06-30 14:22:52 -04002829 struct drm_prime_handle args;
2830 int ret;
Dave Airliecc0a1452012-07-14 09:52:17 +00002831
Jan Vesely50d3c852016-06-30 14:22:52 -04002832 memclear(args);
2833 args.fd = -1;
2834 args.handle = handle;
2835 args.flags = flags;
2836 ret = drmIoctl(fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &args);
2837 if (ret)
2838 return ret;
Dave Airliecc0a1452012-07-14 09:52:17 +00002839
Jan Vesely50d3c852016-06-30 14:22:52 -04002840 *prime_fd = args.fd;
2841 return 0;
Dave Airliecc0a1452012-07-14 09:52:17 +00002842}
2843
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07002844drm_public int drmPrimeFDToHandle(int fd, int prime_fd, uint32_t *handle)
Dave Airliecc0a1452012-07-14 09:52:17 +00002845{
Jan Vesely50d3c852016-06-30 14:22:52 -04002846 struct drm_prime_handle args;
2847 int ret;
Dave Airliecc0a1452012-07-14 09:52:17 +00002848
Jan Vesely50d3c852016-06-30 14:22:52 -04002849 memclear(args);
2850 args.fd = prime_fd;
2851 ret = drmIoctl(fd, DRM_IOCTL_PRIME_FD_TO_HANDLE, &args);
2852 if (ret)
2853 return ret;
Dave Airliecc0a1452012-07-14 09:52:17 +00002854
Jan Vesely50d3c852016-06-30 14:22:52 -04002855 *handle = args.handle;
2856 return 0;
Dave Airliecc0a1452012-07-14 09:52:17 +00002857}
2858
Emil Velikov0ca03a42015-03-07 00:58:39 +00002859static char *drmGetMinorNameForFD(int fd, int type)
2860{
2861#ifdef __linux__
Jan Vesely50d3c852016-06-30 14:22:52 -04002862 DIR *sysdir;
John Stultzbb45ce42018-03-20 17:48:23 +00002863 struct dirent *ent;
Jan Vesely50d3c852016-06-30 14:22:52 -04002864 struct stat sbuf;
2865 const char *name = drmGetMinorName(type);
2866 int len;
2867 char dev_name[64], buf[64];
Jan Vesely50d3c852016-06-30 14:22:52 -04002868 int maj, min;
Emil Velikov0ca03a42015-03-07 00:58:39 +00002869
Jan Vesely50d3c852016-06-30 14:22:52 -04002870 if (!name)
2871 return NULL;
Emil Velikov0ca03a42015-03-07 00:58:39 +00002872
Jan Vesely50d3c852016-06-30 14:22:52 -04002873 len = strlen(name);
Emil Velikov0ca03a42015-03-07 00:58:39 +00002874
Jan Vesely50d3c852016-06-30 14:22:52 -04002875 if (fstat(fd, &sbuf))
2876 return NULL;
Emil Velikov0ca03a42015-03-07 00:58:39 +00002877
Jan Vesely50d3c852016-06-30 14:22:52 -04002878 maj = major(sbuf.st_rdev);
2879 min = minor(sbuf.st_rdev);
Emil Velikov0ca03a42015-03-07 00:58:39 +00002880
Thomas Hellstromf8392582018-08-31 13:47:05 +02002881 if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode))
Jan Vesely50d3c852016-06-30 14:22:52 -04002882 return NULL;
Emil Velikov0ca03a42015-03-07 00:58:39 +00002883
Jan Vesely50d3c852016-06-30 14:22:52 -04002884 snprintf(buf, sizeof(buf), "/sys/dev/char/%d:%d/device/drm", maj, min);
Emil Velikov0ca03a42015-03-07 00:58:39 +00002885
Jan Vesely50d3c852016-06-30 14:22:52 -04002886 sysdir = opendir(buf);
2887 if (!sysdir)
2888 return NULL;
Emil Velikov0ca03a42015-03-07 00:58:39 +00002889
John Stultzbb45ce42018-03-20 17:48:23 +00002890 while ((ent = readdir(sysdir))) {
Jan Vesely50d3c852016-06-30 14:22:52 -04002891 if (strncmp(ent->d_name, name, len) == 0) {
2892 snprintf(dev_name, sizeof(dev_name), DRM_DIR_NAME "/%s",
2893 ent->d_name);
Mathias Tillman5c42b5e2015-08-24 11:56:13 +08002894
Jan Vesely50d3c852016-06-30 14:22:52 -04002895 closedir(sysdir);
Jan Vesely50d3c852016-06-30 14:22:52 -04002896 return strdup(dev_name);
2897 }
2898 }
Kevin Strasserf34b6942018-05-18 12:48:17 -07002899
2900 closedir(sysdir);
John Stultzbb45ce42018-03-20 17:48:23 +00002901 return NULL;
Emil Velikov8415a002015-09-07 18:29:05 +01002902#else
Jonathan Grayf1890112016-12-01 15:18:39 +11002903 struct stat sbuf;
2904 char buf[PATH_MAX + 1];
2905 const char *dev_name;
2906 unsigned int maj, min;
Jonathan Grayd5cf3f92016-12-17 16:09:51 +11002907 int n, base;
Jonathan Grayf1890112016-12-01 15:18:39 +11002908
2909 if (fstat(fd, &sbuf))
2910 return NULL;
2911
2912 maj = major(sbuf.st_rdev);
2913 min = minor(sbuf.st_rdev);
2914
Thomas Hellstromf8392582018-08-31 13:47:05 +02002915 if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode))
Jonathan Grayf1890112016-12-01 15:18:39 +11002916 return NULL;
2917
2918 switch (type) {
2919 case DRM_NODE_PRIMARY:
2920 dev_name = DRM_DEV_NAME;
2921 break;
2922 case DRM_NODE_CONTROL:
2923 dev_name = DRM_CONTROL_DEV_NAME;
2924 break;
2925 case DRM_NODE_RENDER:
2926 dev_name = DRM_RENDER_DEV_NAME;
2927 break;
2928 default:
2929 return NULL;
2930 };
2931
Jonathan Grayd5cf3f92016-12-17 16:09:51 +11002932 base = drmGetMinorBase(type);
2933 if (base < 0)
2934 return NULL;
2935
2936 n = snprintf(buf, sizeof(buf), dev_name, DRM_DIR_NAME, min - base);
Jonathan Grayf1890112016-12-01 15:18:39 +11002937 if (n == -1 || n >= sizeof(buf))
2938 return NULL;
2939
2940 return strdup(buf);
Emil Velikov0ca03a42015-03-07 00:58:39 +00002941#endif
Emil Velikov0ca03a42015-03-07 00:58:39 +00002942}
2943
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07002944drm_public char *drmGetPrimaryDeviceNameFromFd(int fd)
Emil Velikov0ca03a42015-03-07 00:58:39 +00002945{
Jan Vesely50d3c852016-06-30 14:22:52 -04002946 return drmGetMinorNameForFD(fd, DRM_NODE_PRIMARY);
Emil Velikov0ca03a42015-03-07 00:58:39 +00002947}
2948
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07002949drm_public char *drmGetRenderDeviceNameFromFd(int fd)
Emil Velikov0ca03a42015-03-07 00:58:39 +00002950{
Jan Vesely50d3c852016-06-30 14:22:52 -04002951 return drmGetMinorNameForFD(fd, DRM_NODE_RENDER);
Emil Velikov0ca03a42015-03-07 00:58:39 +00002952}
Emil Velikovb556ea12015-08-17 11:09:06 +08002953
Thierry Redingf8484cc2016-12-22 00:39:36 +01002954#ifdef __linux__
2955static char * DRM_PRINTFLIKE(2, 3)
2956sysfs_uevent_get(const char *path, const char *fmt, ...)
2957{
2958 char filename[PATH_MAX + 1], *key, *line = NULL, *value = NULL;
2959 size_t size = 0, len;
2960 ssize_t num;
2961 va_list ap;
2962 FILE *fp;
2963
2964 va_start(ap, fmt);
2965 num = vasprintf(&key, fmt, ap);
2966 va_end(ap);
2967 len = num;
2968
2969 snprintf(filename, sizeof(filename), "%s/uevent", path);
2970
2971 fp = fopen(filename, "r");
2972 if (!fp) {
2973 free(key);
2974 return NULL;
2975 }
2976
2977 while ((num = getline(&line, &size, fp)) >= 0) {
2978 if ((strncmp(line, key, len) == 0) && (line[len] == '=')) {
2979 char *start = line + len + 1, *end = line + num - 1;
2980
2981 if (*end != '\n')
2982 end++;
2983
2984 value = strndup(start, end - start);
2985 break;
2986 }
2987 }
2988
2989 free(line);
2990 fclose(fp);
2991
2992 free(key);
2993
2994 return value;
2995}
2996#endif
2997
Emil Velikov39885802018-05-15 17:37:49 +01002998/* Little white lie to avoid major rework of the existing code */
2999#define DRM_BUS_VIRTIO 0x10
3000
Emil Velikov291b2bb2015-09-07 18:26:34 +01003001#ifdef __linux__
Vasyl Vavrychukf900a0f2020-01-29 03:54:56 +01003002static int get_subsystem_type(const char *device_path)
3003{
3004 char path[PATH_MAX + 1] = "";
Emil Velikovb556ea12015-08-17 11:09:06 +08003005 char link[PATH_MAX + 1] = "";
3006 char *name;
Eric Anholt9b28c5a2018-11-15 17:48:53 -08003007 struct {
3008 const char *name;
3009 int bus_type;
3010 } bus_types[] = {
3011 { "/pci", DRM_BUS_PCI },
3012 { "/usb", DRM_BUS_USB },
3013 { "/platform", DRM_BUS_PLATFORM },
Eric Anholt89700ab2018-11-15 17:52:19 -08003014 { "/spi", DRM_BUS_PLATFORM },
Eric Anholt9b28c5a2018-11-15 17:48:53 -08003015 { "/host1x", DRM_BUS_HOST1X },
3016 { "/virtio", DRM_BUS_VIRTIO },
3017 };
Emil Velikovb556ea12015-08-17 11:09:06 +08003018
Vasyl Vavrychukf900a0f2020-01-29 03:54:56 +01003019 strncpy(path, device_path, PATH_MAX);
3020 strncat(path, "/subsystem", PATH_MAX);
Emil Velikova250fce2015-09-07 12:54:27 +01003021
3022 if (readlink(path, link, PATH_MAX) < 0)
3023 return -errno;
Emil Velikovb556ea12015-08-17 11:09:06 +08003024
3025 name = strrchr(link, '/');
3026 if (!name)
3027 return -EINVAL;
3028
Eric Anholt9b28c5a2018-11-15 17:48:53 -08003029 for (unsigned i = 0; i < ARRAY_SIZE(bus_types); i++) {
3030 if (strncmp(name, bus_types[i].name, strlen(bus_types[i].name)) == 0)
3031 return bus_types[i].bus_type;
3032 }
Emil Velikov39885802018-05-15 17:37:49 +01003033
Emil Velikovb556ea12015-08-17 11:09:06 +08003034 return -EINVAL;
Vasyl Vavrychukf900a0f2020-01-29 03:54:56 +01003035}
3036#endif
3037
3038static int drmParseSubsystemType(int maj, int min)
3039{
3040#ifdef __linux__
3041 char path[PATH_MAX + 1] = "";
Vasyl Vavrychuk271ab542020-01-29 16:08:41 +01003042 char real_path[PATH_MAX + 1] = "";
3043 int subsystem_type;
Vasyl Vavrychukf900a0f2020-01-29 03:54:56 +01003044
Vasyl Vavrychuk271ab542020-01-29 16:08:41 +01003045 snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min);
3046 if (!realpath(path, real_path))
3047 return -errno;
3048 snprintf(path, sizeof(path), "%s", real_path);
Vasyl Vavrychukf900a0f2020-01-29 03:54:56 +01003049
Vasyl Vavrychuk271ab542020-01-29 16:08:41 +01003050 subsystem_type = get_subsystem_type(path);
3051 if (subsystem_type == DRM_BUS_VIRTIO) {
3052 strncat(path, "/..", PATH_MAX);
3053 subsystem_type = get_subsystem_type(path);
3054 }
3055 return subsystem_type;
François Tigeot200e9e92018-12-12 20:48:35 +01003056#elif defined(__OpenBSD__) || defined(__DragonFly__)
Thierry Redinge17cad12016-12-21 18:00:52 +01003057 return DRM_BUS_PCI;
Emil Velikov291b2bb2015-09-07 18:26:34 +01003058#else
3059#warning "Missing implementation of drmParseSubsystemType"
3060 return -EINVAL;
3061#endif
Emil Velikovb556ea12015-08-17 11:09:06 +08003062}
3063
Eric Engestrom56499532018-09-05 13:23:59 +01003064static void
Eric Engestrom9030a0f2018-09-05 13:29:08 +01003065get_pci_path(int maj, int min, char *pci_path)
Emil Velikova0290012018-05-15 17:29:44 +01003066{
Emil Velikov39885802018-05-15 17:37:49 +01003067 char path[PATH_MAX + 1], *term;
Emil Velikova0290012018-05-15 17:29:44 +01003068
3069 snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min);
Eric Engestrom9030a0f2018-09-05 13:29:08 +01003070 if (!realpath(path, pci_path)) {
3071 strcpy(pci_path, path);
Eric Engestrom56499532018-09-05 13:23:59 +01003072 return;
3073 }
Emil Velikova0290012018-05-15 17:29:44 +01003074
Eric Engestrom9030a0f2018-09-05 13:29:08 +01003075 term = strrchr(pci_path, '/');
Emil Velikov39885802018-05-15 17:37:49 +01003076 if (term && strncmp(term, "/virtio", 7) == 0)
3077 *term = 0;
Emil Velikovbcb9d972018-08-23 10:49:54 +01003078}
3079
Emil Velikov536e0de2015-09-07 12:37:57 +01003080static int drmParsePciBusInfo(int maj, int min, drmPciBusInfoPtr info)
Emil Velikovb556ea12015-08-17 11:09:06 +08003081{
Emil Velikov291b2bb2015-09-07 18:26:34 +01003082#ifdef __linux__
Thierry Reding5403cb32017-01-18 08:29:23 +01003083 unsigned int domain, bus, dev, func;
Eric Engestrom9030a0f2018-09-05 13:29:08 +01003084 char pci_path[PATH_MAX + 1], *value;
Thierry Reding5403cb32017-01-18 08:29:23 +01003085 int num;
Emil Velikovb556ea12015-08-17 11:09:06 +08003086
Eric Engestrom9030a0f2018-09-05 13:29:08 +01003087 get_pci_path(maj, min, pci_path);
Emil Velikov536e0de2015-09-07 12:37:57 +01003088
Eric Engestrom9030a0f2018-09-05 13:29:08 +01003089 value = sysfs_uevent_get(pci_path, "PCI_SLOT_NAME");
Thierry Reding5403cb32017-01-18 08:29:23 +01003090 if (!value)
3091 return -ENOENT;
Emil Velikov536e0de2015-09-07 12:37:57 +01003092
Thierry Reding5403cb32017-01-18 08:29:23 +01003093 num = sscanf(value, "%04x:%02x:%02x.%1u", &domain, &bus, &dev, &func);
3094 free(value);
3095
3096 if (num != 4)
Emil Velikovb556ea12015-08-17 11:09:06 +08003097 return -EINVAL;
3098
Emil Velikovb556ea12015-08-17 11:09:06 +08003099 info->domain = domain;
3100 info->bus = bus;
3101 info->dev = dev;
3102 info->func = func;
3103
3104 return 0;
François Tigeot8f2e0922018-12-12 20:48:36 +01003105#elif defined(__OpenBSD__) || defined(__DragonFly__)
Jonathan Grayfd190562016-12-01 15:18:42 +11003106 struct drm_pciinfo pinfo;
3107 int fd, type;
3108
3109 type = drmGetMinorType(min);
3110 if (type == -1)
3111 return -ENODEV;
3112
3113 fd = drmOpenMinor(min, 0, type);
3114 if (fd < 0)
3115 return -errno;
3116
3117 if (drmIoctl(fd, DRM_IOCTL_GET_PCIINFO, &pinfo)) {
3118 close(fd);
3119 return -errno;
3120 }
3121 close(fd);
3122
3123 info->domain = pinfo.domain;
3124 info->bus = pinfo.bus;
3125 info->dev = pinfo.dev;
3126 info->func = pinfo.func;
3127
3128 return 0;
Emil Velikov291b2bb2015-09-07 18:26:34 +01003129#else
3130#warning "Missing implementation of drmParsePciBusInfo"
3131 return -EINVAL;
3132#endif
Emil Velikovb556ea12015-08-17 11:09:06 +08003133}
3134
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07003135drm_public int drmDevicesEqual(drmDevicePtr a, drmDevicePtr b)
Emil Velikovb556ea12015-08-17 11:09:06 +08003136{
Emil Velikovbc2aca92015-09-07 13:51:54 +01003137 if (a == NULL || b == NULL)
Adam Jackson7c27cd72017-05-04 10:48:56 -04003138 return 0;
Emil Velikovbc2aca92015-09-07 13:51:54 +01003139
Emil Velikovb556ea12015-08-17 11:09:06 +08003140 if (a->bustype != b->bustype)
Adam Jackson7c27cd72017-05-04 10:48:56 -04003141 return 0;
Emil Velikovb556ea12015-08-17 11:09:06 +08003142
3143 switch (a->bustype) {
3144 case DRM_BUS_PCI:
Adam Jackson7c27cd72017-05-04 10:48:56 -04003145 return memcmp(a->businfo.pci, b->businfo.pci, sizeof(drmPciBusInfo)) == 0;
Thierry Redingf8484cc2016-12-22 00:39:36 +01003146
3147 case DRM_BUS_USB:
Adam Jackson7c27cd72017-05-04 10:48:56 -04003148 return memcmp(a->businfo.usb, b->businfo.usb, sizeof(drmUsbBusInfo)) == 0;
Thierry Redingf8484cc2016-12-22 00:39:36 +01003149
Thierry Reding7b1f37f2016-12-21 17:59:04 +01003150 case DRM_BUS_PLATFORM:
Adam Jackson7c27cd72017-05-04 10:48:56 -04003151 return memcmp(a->businfo.platform, b->businfo.platform, sizeof(drmPlatformBusInfo)) == 0;
Thierry Reding7b1f37f2016-12-21 17:59:04 +01003152
3153 case DRM_BUS_HOST1X:
Adam Jackson7c27cd72017-05-04 10:48:56 -04003154 return memcmp(a->businfo.host1x, b->businfo.host1x, sizeof(drmHost1xBusInfo)) == 0;
Thierry Reding7b1f37f2016-12-21 17:59:04 +01003155
Emil Velikovb556ea12015-08-17 11:09:06 +08003156 default:
3157 break;
3158 }
3159
Adam Jackson7c27cd72017-05-04 10:48:56 -04003160 return 0;
Emil Velikovb556ea12015-08-17 11:09:06 +08003161}
3162
3163static int drmGetNodeType(const char *name)
3164{
3165 if (strncmp(name, DRM_PRIMARY_MINOR_NAME,
3166 sizeof(DRM_PRIMARY_MINOR_NAME) - 1) == 0)
3167 return DRM_NODE_PRIMARY;
3168
3169 if (strncmp(name, DRM_CONTROL_MINOR_NAME,
3170 sizeof(DRM_CONTROL_MINOR_NAME ) - 1) == 0)
3171 return DRM_NODE_CONTROL;
3172
3173 if (strncmp(name, DRM_RENDER_MINOR_NAME,
3174 sizeof(DRM_RENDER_MINOR_NAME) - 1) == 0)
3175 return DRM_NODE_RENDER;
3176
3177 return -EINVAL;
3178}
3179
Emil Velikov5f68d312015-09-07 13:54:32 +01003180static int drmGetMaxNodeName(void)
3181{
3182 return sizeof(DRM_DIR_NAME) +
3183 MAX3(sizeof(DRM_PRIMARY_MINOR_NAME),
3184 sizeof(DRM_CONTROL_MINOR_NAME),
3185 sizeof(DRM_RENDER_MINOR_NAME)) +
Eric Engestromce975072016-04-03 19:48:12 +01003186 3 /* length of the node number */;
Emil Velikov5f68d312015-09-07 13:54:32 +01003187}
3188
Emil Velikov291b2bb2015-09-07 18:26:34 +01003189#ifdef __linux__
Emil Velikovaae3f312016-11-01 18:04:06 +00003190static int parse_separate_sysfs_files(int maj, int min,
Emil Velikov11687bf2016-11-30 17:24:21 +00003191 drmPciDeviceInfoPtr device,
3192 bool ignore_revision)
Emil Velikovaae3f312016-11-01 18:04:06 +00003193{
Emil Velikovaae3f312016-11-01 18:04:06 +00003194 static const char *attrs[] = {
3195 "revision", /* Older kernels are missing the file, so check for it first */
3196 "vendor",
3197 "device",
3198 "subsystem_vendor",
3199 "subsystem_device",
3200 };
Eric Engestrom9030a0f2018-09-05 13:29:08 +01003201 char path[PATH_MAX + 1], pci_path[PATH_MAX + 1];
Emil Velikovaae3f312016-11-01 18:04:06 +00003202 unsigned int data[ARRAY_SIZE(attrs)];
3203 FILE *fp;
3204 int ret;
3205
Eric Engestrom9030a0f2018-09-05 13:29:08 +01003206 get_pci_path(maj, min, pci_path);
Emil Velikova0290012018-05-15 17:29:44 +01003207
Emil Velikov11687bf2016-11-30 17:24:21 +00003208 for (unsigned i = ignore_revision ? 1 : 0; i < ARRAY_SIZE(attrs); i++) {
Eric Engestrom9030a0f2018-09-05 13:29:08 +01003209 snprintf(path, PATH_MAX, "%s/%s", pci_path, attrs[i]);
Emil Velikovaae3f312016-11-01 18:04:06 +00003210 fp = fopen(path, "r");
3211 if (!fp)
3212 return -errno;
3213
3214 ret = fscanf(fp, "%x", &data[i]);
3215 fclose(fp);
3216 if (ret != 1)
3217 return -errno;
3218
3219 }
3220
Emil Velikov11687bf2016-11-30 17:24:21 +00003221 device->revision_id = ignore_revision ? 0xff : data[0] & 0xff;
Emil Velikovaae3f312016-11-01 18:04:06 +00003222 device->vendor_id = data[1] & 0xffff;
3223 device->device_id = data[2] & 0xffff;
3224 device->subvendor_id = data[3] & 0xffff;
3225 device->subdevice_id = data[4] & 0xffff;
3226
3227 return 0;
3228}
3229
3230static int parse_config_sysfs_file(int maj, int min,
3231 drmPciDeviceInfoPtr device)
3232{
Eric Engestrom9030a0f2018-09-05 13:29:08 +01003233 char path[PATH_MAX + 1], pci_path[PATH_MAX + 1];
Emil Velikovef5192e2015-09-07 12:47:47 +01003234 unsigned char config[64];
3235 int fd, ret;
3236
Eric Engestrom9030a0f2018-09-05 13:29:08 +01003237 get_pci_path(maj, min, pci_path);
Emil Velikova0290012018-05-15 17:29:44 +01003238
Eric Engestrom9030a0f2018-09-05 13:29:08 +01003239 snprintf(path, PATH_MAX, "%s/config", pci_path);
Emil Velikovef5192e2015-09-07 12:47:47 +01003240 fd = open(path, O_RDONLY);
3241 if (fd < 0)
3242 return -errno;
3243
3244 ret = read(fd, config, sizeof(config));
3245 close(fd);
3246 if (ret < 0)
3247 return -errno;
Emil Velikovb556ea12015-08-17 11:09:06 +08003248
3249 device->vendor_id = config[0] | (config[1] << 8);
3250 device->device_id = config[2] | (config[3] << 8);
3251 device->revision_id = config[8];
3252 device->subvendor_id = config[44] | (config[45] << 8);
3253 device->subdevice_id = config[46] | (config[47] << 8);
3254
3255 return 0;
Emil Velikovaae3f312016-11-01 18:04:06 +00003256}
3257#endif
3258
3259static int drmParsePciDeviceInfo(int maj, int min,
3260 drmPciDeviceInfoPtr device,
3261 uint32_t flags)
3262{
3263#ifdef __linux__
Emil Velikov11687bf2016-11-30 17:24:21 +00003264 if (!(flags & DRM_DEVICE_GET_PCI_REVISION))
3265 return parse_separate_sysfs_files(maj, min, device, true);
3266
3267 if (parse_separate_sysfs_files(maj, min, device, false))
Emil Velikovaae3f312016-11-01 18:04:06 +00003268 return parse_config_sysfs_file(maj, min, device);
3269
3270 return 0;
François Tigeot8f2e0922018-12-12 20:48:36 +01003271#elif defined(__OpenBSD__) || defined(__DragonFly__)
Jonathan Grayc0ef1d02016-12-01 15:18:41 +11003272 struct drm_pciinfo pinfo;
3273 int fd, type;
3274
3275 type = drmGetMinorType(min);
3276 if (type == -1)
3277 return -ENODEV;
3278
3279 fd = drmOpenMinor(min, 0, type);
3280 if (fd < 0)
3281 return -errno;
3282
3283 if (drmIoctl(fd, DRM_IOCTL_GET_PCIINFO, &pinfo)) {
3284 close(fd);
3285 return -errno;
3286 }
3287 close(fd);
3288
3289 device->vendor_id = pinfo.vendor_id;
3290 device->device_id = pinfo.device_id;
3291 device->revision_id = pinfo.revision_id;
3292 device->subvendor_id = pinfo.subvendor_id;
3293 device->subdevice_id = pinfo.subdevice_id;
3294
3295 return 0;
Emil Velikov291b2bb2015-09-07 18:26:34 +01003296#else
3297#warning "Missing implementation of drmParsePciDeviceInfo"
3298 return -EINVAL;
3299#endif
Emil Velikovb556ea12015-08-17 11:09:06 +08003300}
3301
Thierry Reding7b1f37f2016-12-21 17:59:04 +01003302static void drmFreePlatformDevice(drmDevicePtr device)
3303{
3304 if (device->deviceinfo.platform) {
3305 if (device->deviceinfo.platform->compatible) {
3306 char **compatible = device->deviceinfo.platform->compatible;
3307
3308 while (*compatible) {
3309 free(*compatible);
3310 compatible++;
3311 }
3312
3313 free(device->deviceinfo.platform->compatible);
3314 }
3315 }
3316}
3317
3318static void drmFreeHost1xDevice(drmDevicePtr device)
3319{
3320 if (device->deviceinfo.host1x) {
3321 if (device->deviceinfo.host1x->compatible) {
3322 char **compatible = device->deviceinfo.host1x->compatible;
3323
3324 while (*compatible) {
3325 free(*compatible);
3326 compatible++;
3327 }
3328
3329 free(device->deviceinfo.host1x->compatible);
3330 }
3331 }
3332}
3333
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07003334drm_public void drmFreeDevice(drmDevicePtr *device)
Emil Velikovb556ea12015-08-17 11:09:06 +08003335{
Emil Velikovb556ea12015-08-17 11:09:06 +08003336 if (device == NULL)
3337 return;
3338
Thierry Reding7b1f37f2016-12-21 17:59:04 +01003339 if (*device) {
3340 switch ((*device)->bustype) {
3341 case DRM_BUS_PLATFORM:
3342 drmFreePlatformDevice(*device);
3343 break;
3344
3345 case DRM_BUS_HOST1X:
3346 drmFreeHost1xDevice(*device);
3347 break;
3348 }
3349 }
3350
Emil Velikov5f68d312015-09-07 13:54:32 +01003351 free(*device);
3352 *device = NULL;
Emil Velikovb556ea12015-08-17 11:09:06 +08003353}
3354
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07003355drm_public void drmFreeDevices(drmDevicePtr devices[], int count)
Emil Velikovb556ea12015-08-17 11:09:06 +08003356{
3357 int i;
3358
3359 if (devices == NULL)
3360 return;
3361
Qiang Yu6c056ee2016-07-14 17:10:56 +08003362 for (i = 0; i < count; i++)
3363 if (devices[i])
3364 drmFreeDevice(&devices[i]);
Emil Velikovb556ea12015-08-17 11:09:06 +08003365}
3366
Thierry Reding2e57bba2016-12-21 17:54:48 +01003367static drmDevicePtr drmDeviceAlloc(unsigned int type, const char *node,
3368 size_t bus_size, size_t device_size,
3369 char **ptrp)
3370{
3371 size_t max_node_length, extra, size;
3372 drmDevicePtr device;
3373 unsigned int i;
3374 char *ptr;
3375
3376 max_node_length = ALIGN(drmGetMaxNodeName(), sizeof(void *));
3377 extra = DRM_NODE_MAX * (sizeof(void *) + max_node_length);
3378
3379 size = sizeof(*device) + extra + bus_size + device_size;
3380
3381 device = calloc(1, size);
3382 if (!device)
3383 return NULL;
3384
3385 device->available_nodes = 1 << type;
3386
3387 ptr = (char *)device + sizeof(*device);
3388 device->nodes = (char **)ptr;
3389
3390 ptr += DRM_NODE_MAX * sizeof(void *);
3391
3392 for (i = 0; i < DRM_NODE_MAX; i++) {
3393 device->nodes[i] = ptr;
3394 ptr += max_node_length;
3395 }
3396
3397 memcpy(device->nodes[type], node, max_node_length);
3398
3399 *ptrp = ptr;
3400
3401 return device;
3402}
3403
Emil Velikovb40a65d2016-11-30 16:41:27 +00003404static int drmProcessPciDevice(drmDevicePtr *device,
Emil Velikovfae59d72015-09-09 17:54:34 +01003405 const char *node, int node_type,
Emil Velikov138d2312016-11-30 17:13:51 +00003406 int maj, int min, bool fetch_deviceinfo,
3407 uint32_t flags)
Emil Velikovfae59d72015-09-09 17:54:34 +01003408{
Thierry Reding2e57bba2016-12-21 17:54:48 +01003409 drmDevicePtr dev;
Michel Dänzer30455232015-10-14 12:48:52 +09003410 char *addr;
Thierry Reding2e57bba2016-12-21 17:54:48 +01003411 int ret;
Emil Velikovfae59d72015-09-09 17:54:34 +01003412
Thierry Reding2e57bba2016-12-21 17:54:48 +01003413 dev = drmDeviceAlloc(node_type, node, sizeof(drmPciBusInfo),
3414 sizeof(drmPciDeviceInfo), &addr);
3415 if (!dev)
Emil Velikovfae59d72015-09-09 17:54:34 +01003416 return -ENOMEM;
3417
Thierry Reding2e57bba2016-12-21 17:54:48 +01003418 dev->bustype = DRM_BUS_PCI;
Jan Vesely50d3c852016-06-30 14:22:52 -04003419
Thierry Reding2e57bba2016-12-21 17:54:48 +01003420 dev->businfo.pci = (drmPciBusInfoPtr)addr;
Emil Velikovfae59d72015-09-09 17:54:34 +01003421
Thierry Reding2e57bba2016-12-21 17:54:48 +01003422 ret = drmParsePciBusInfo(maj, min, dev->businfo.pci);
Emil Velikovfae59d72015-09-09 17:54:34 +01003423 if (ret)
3424 goto free_device;
3425
3426 // Fetch the device info if the user has requested it
3427 if (fetch_deviceinfo) {
3428 addr += sizeof(drmPciBusInfo);
Thierry Reding2e57bba2016-12-21 17:54:48 +01003429 dev->deviceinfo.pci = (drmPciDeviceInfoPtr)addr;
Emil Velikovfae59d72015-09-09 17:54:34 +01003430
Thierry Reding2e57bba2016-12-21 17:54:48 +01003431 ret = drmParsePciDeviceInfo(maj, min, dev->deviceinfo.pci, flags);
Emil Velikovfae59d72015-09-09 17:54:34 +01003432 if (ret)
3433 goto free_device;
3434 }
Thierry Reding2e57bba2016-12-21 17:54:48 +01003435
3436 *device = dev;
3437
Emil Velikovfae59d72015-09-09 17:54:34 +01003438 return 0;
3439
3440free_device:
Thierry Reding2e57bba2016-12-21 17:54:48 +01003441 free(dev);
Emil Velikovfae59d72015-09-09 17:54:34 +01003442 return ret;
3443}
3444
Thierry Redingf8484cc2016-12-22 00:39:36 +01003445static int drmParseUsbBusInfo(int maj, int min, drmUsbBusInfoPtr info)
3446{
3447#ifdef __linux__
3448 char path[PATH_MAX + 1], *value;
3449 unsigned int bus, dev;
3450 int ret;
3451
3452 snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min);
3453
3454 value = sysfs_uevent_get(path, "BUSNUM");
3455 if (!value)
3456 return -ENOENT;
3457
3458 ret = sscanf(value, "%03u", &bus);
3459 free(value);
3460
3461 if (ret <= 0)
3462 return -errno;
3463
3464 value = sysfs_uevent_get(path, "DEVNUM");
3465 if (!value)
3466 return -ENOENT;
3467
3468 ret = sscanf(value, "%03u", &dev);
3469 free(value);
3470
3471 if (ret <= 0)
3472 return -errno;
3473
3474 info->bus = bus;
3475 info->dev = dev;
3476
3477 return 0;
3478#else
3479#warning "Missing implementation of drmParseUsbBusInfo"
3480 return -EINVAL;
3481#endif
3482}
3483
3484static int drmParseUsbDeviceInfo(int maj, int min, drmUsbDeviceInfoPtr info)
3485{
3486#ifdef __linux__
3487 char path[PATH_MAX + 1], *value;
3488 unsigned int vendor, product;
3489 int ret;
3490
3491 snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min);
3492
3493 value = sysfs_uevent_get(path, "PRODUCT");
3494 if (!value)
3495 return -ENOENT;
3496
3497 ret = sscanf(value, "%x/%x", &vendor, &product);
3498 free(value);
3499
3500 if (ret <= 0)
3501 return -errno;
3502
3503 info->vendor = vendor;
3504 info->product = product;
3505
3506 return 0;
3507#else
3508#warning "Missing implementation of drmParseUsbDeviceInfo"
3509 return -EINVAL;
3510#endif
3511}
3512
3513static int drmProcessUsbDevice(drmDevicePtr *device, const char *node,
3514 int node_type, int maj, int min,
3515 bool fetch_deviceinfo, uint32_t flags)
3516{
3517 drmDevicePtr dev;
3518 char *ptr;
3519 int ret;
3520
3521 dev = drmDeviceAlloc(node_type, node, sizeof(drmUsbBusInfo),
3522 sizeof(drmUsbDeviceInfo), &ptr);
3523 if (!dev)
3524 return -ENOMEM;
3525
3526 dev->bustype = DRM_BUS_USB;
3527
3528 dev->businfo.usb = (drmUsbBusInfoPtr)ptr;
3529
3530 ret = drmParseUsbBusInfo(maj, min, dev->businfo.usb);
3531 if (ret < 0)
3532 goto free_device;
3533
3534 if (fetch_deviceinfo) {
3535 ptr += sizeof(drmUsbBusInfo);
3536 dev->deviceinfo.usb = (drmUsbDeviceInfoPtr)ptr;
3537
3538 ret = drmParseUsbDeviceInfo(maj, min, dev->deviceinfo.usb);
3539 if (ret < 0)
3540 goto free_device;
3541 }
3542
3543 *device = dev;
3544
3545 return 0;
3546
3547free_device:
3548 free(dev);
3549 return ret;
3550}
3551
Emil Velikovee798b92019-01-23 10:39:12 +00003552static int drmParseOFBusInfo(int maj, int min, char *fullname)
Thierry Reding7b1f37f2016-12-21 17:59:04 +01003553{
3554#ifdef __linux__
Emil Velikov3df8a7f2019-01-23 09:44:07 +00003555 char path[PATH_MAX + 1], *name, *tmp_name;
Thierry Reding7b1f37f2016-12-21 17:59:04 +01003556
3557 snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min);
3558
3559 name = sysfs_uevent_get(path, "OF_FULLNAME");
Emil Velikov3df8a7f2019-01-23 09:44:07 +00003560 tmp_name = name;
3561 if (!name) {
3562 /* If the device lacks OF data, pick the MODALIAS info */
3563 name = sysfs_uevent_get(path, "MODALIAS");
3564 if (!name)
3565 return -ENOENT;
Thierry Reding7b1f37f2016-12-21 17:59:04 +01003566
Emil Velikov3df8a7f2019-01-23 09:44:07 +00003567 /* .. and strip the MODALIAS=[platform,usb...]: part. */
3568 tmp_name = strrchr(name, ':');
3569 if (!tmp_name) {
3570 free(name);
3571 return -ENOENT;
3572 }
3573 tmp_name++;
3574 }
3575
Emil Velikovee798b92019-01-23 10:39:12 +00003576 strncpy(fullname, tmp_name, DRM_PLATFORM_DEVICE_NAME_LEN);
3577 fullname[DRM_PLATFORM_DEVICE_NAME_LEN - 1] = '\0';
Thierry Reding7b1f37f2016-12-21 17:59:04 +01003578 free(name);
3579
3580 return 0;
3581#else
Emil Velikovee798b92019-01-23 10:39:12 +00003582#warning "Missing implementation of drmParseOFBusInfo"
Thierry Reding7b1f37f2016-12-21 17:59:04 +01003583 return -EINVAL;
3584#endif
3585}
3586
Emil Velikovee798b92019-01-23 10:39:12 +00003587static int drmParseOFDeviceInfo(int maj, int min, char ***compatible)
Thierry Reding7b1f37f2016-12-21 17:59:04 +01003588{
3589#ifdef __linux__
Emil Velikov3df8a7f2019-01-23 09:44:07 +00003590 char path[PATH_MAX + 1], *value, *tmp_name;
Thierry Reding7b1f37f2016-12-21 17:59:04 +01003591 unsigned int count, i;
3592 int err;
3593
3594 snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min);
3595
3596 value = sysfs_uevent_get(path, "OF_COMPATIBLE_N");
Emil Velikov3df8a7f2019-01-23 09:44:07 +00003597 if (value) {
3598 sscanf(value, "%u", &count);
3599 free(value);
3600 } else {
3601 /* Assume one entry if the device lack OF data */
3602 count = 1;
3603 }
Thierry Reding7b1f37f2016-12-21 17:59:04 +01003604
Emil Velikovee798b92019-01-23 10:39:12 +00003605 *compatible = calloc(count + 1, sizeof(char *));
3606 if (!*compatible)
Thierry Reding7b1f37f2016-12-21 17:59:04 +01003607 return -ENOMEM;
3608
3609 for (i = 0; i < count; i++) {
3610 value = sysfs_uevent_get(path, "OF_COMPATIBLE_%u", i);
Emil Velikov3df8a7f2019-01-23 09:44:07 +00003611 tmp_name = value;
Thierry Reding7b1f37f2016-12-21 17:59:04 +01003612 if (!value) {
Emil Velikov3df8a7f2019-01-23 09:44:07 +00003613 /* If the device lacks OF data, pick the MODALIAS info */
3614 value = sysfs_uevent_get(path, "MODALIAS");
3615 if (!value) {
3616 err = -ENOENT;
3617 goto free;
3618 }
3619
3620 /* .. and strip the MODALIAS=[platform,usb...]: part. */
3621 tmp_name = strrchr(value, ':');
3622 if (!tmp_name) {
3623 free(value);
3624 return -ENOENT;
3625 }
3626 tmp_name = strdup(tmp_name + 1);
3627 free(value);
Thierry Reding7b1f37f2016-12-21 17:59:04 +01003628 }
3629
Andreas Baierl4735ca72019-03-11 16:04:08 +01003630 (*compatible)[i] = tmp_name;
Thierry Reding7b1f37f2016-12-21 17:59:04 +01003631 }
3632
3633 return 0;
3634
3635free:
3636 while (i--)
Andreas Baierl4735ca72019-03-11 16:04:08 +01003637 free((*compatible)[i]);
Thierry Reding7b1f37f2016-12-21 17:59:04 +01003638
Emil Velikovee798b92019-01-23 10:39:12 +00003639 free(*compatible);
Thierry Reding7b1f37f2016-12-21 17:59:04 +01003640 return err;
3641#else
Emil Velikovee798b92019-01-23 10:39:12 +00003642#warning "Missing implementation of drmParseOFDeviceInfo"
Thierry Reding7b1f37f2016-12-21 17:59:04 +01003643 return -EINVAL;
3644#endif
3645}
3646
3647static int drmProcessPlatformDevice(drmDevicePtr *device,
3648 const char *node, int node_type,
3649 int maj, int min, bool fetch_deviceinfo,
3650 uint32_t flags)
3651{
3652 drmDevicePtr dev;
3653 char *ptr;
3654 int ret;
3655
3656 dev = drmDeviceAlloc(node_type, node, sizeof(drmPlatformBusInfo),
3657 sizeof(drmPlatformDeviceInfo), &ptr);
3658 if (!dev)
3659 return -ENOMEM;
3660
3661 dev->bustype = DRM_BUS_PLATFORM;
3662
3663 dev->businfo.platform = (drmPlatformBusInfoPtr)ptr;
3664
Emil Velikovee798b92019-01-23 10:39:12 +00003665 ret = drmParseOFBusInfo(maj, min, dev->businfo.platform->fullname);
Thierry Reding7b1f37f2016-12-21 17:59:04 +01003666 if (ret < 0)
3667 goto free_device;
3668
3669 if (fetch_deviceinfo) {
3670 ptr += sizeof(drmPlatformBusInfo);
3671 dev->deviceinfo.platform = (drmPlatformDeviceInfoPtr)ptr;
3672
Emil Velikovee798b92019-01-23 10:39:12 +00003673 ret = drmParseOFDeviceInfo(maj, min, &dev->deviceinfo.platform->compatible);
Thierry Reding7b1f37f2016-12-21 17:59:04 +01003674 if (ret < 0)
3675 goto free_device;
3676 }
3677
3678 *device = dev;
3679
3680 return 0;
3681
3682free_device:
3683 free(dev);
3684 return ret;
3685}
3686
Thierry Reding7b1f37f2016-12-21 17:59:04 +01003687static 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
Emil Velikovee798b92019-01-23 10:39:12 +00003705 ret = drmParseOFBusInfo(maj, min, dev->businfo.host1x->fullname);
Thierry Reding7b1f37f2016-12-21 17:59:04 +01003706 if (ret < 0)
3707 goto free_device;
3708
3709 if (fetch_deviceinfo) {
3710 ptr += sizeof(drmHost1xBusInfo);
3711 dev->deviceinfo.host1x = (drmHost1xDeviceInfoPtr)ptr;
3712
Emil Velikovee798b92019-01-23 10:39:12 +00003713 ret = drmParseOFDeviceInfo(maj, min, &dev->deviceinfo.host1x->compatible);
Thierry Reding7b1f37f2016-12-21 17:59:04 +01003714 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:
3757 return drmProcessPciDevice(device, node, node_type, maj, min,
3758 fetch_deviceinfo, flags);
3759 case DRM_BUS_USB:
3760 return drmProcessUsbDevice(device, node, node_type, maj, min,
3761 fetch_deviceinfo, flags);
3762 case DRM_BUS_PLATFORM:
3763 return drmProcessPlatformDevice(device, node, node_type, maj, min,
3764 fetch_deviceinfo, flags);
3765 case DRM_BUS_HOST1X:
3766 return drmProcessHost1xDevice(device, node, node_type, maj, min,
3767 fetch_deviceinfo, flags);
3768 default:
3769 return -1;
3770 }
3771}
3772
Qiang Yu3c208932016-07-14 17:10:55 +08003773/* Consider devices located on the same bus as duplicate and fold the respective
3774 * entries into a single one.
3775 *
3776 * Note: this leaves "gaps" in the array, while preserving the length.
3777 */
Emil Velikovfae59d72015-09-09 17:54:34 +01003778static void drmFoldDuplicatedDevices(drmDevicePtr local_devices[], int count)
3779{
3780 int node_type, i, j;
3781
3782 for (i = 0; i < count; i++) {
3783 for (j = i + 1; j < count; j++) {
Adam Jacksona2fa2e02017-05-04 15:57:14 -04003784 if (drmDevicesEqual(local_devices[i], local_devices[j])) {
Emil Velikovfae59d72015-09-09 17:54:34 +01003785 local_devices[i]->available_nodes |= local_devices[j]->available_nodes;
3786 node_type = log2(local_devices[j]->available_nodes);
3787 memcpy(local_devices[i]->nodes[node_type],
3788 local_devices[j]->nodes[node_type], drmGetMaxNodeName());
3789 drmFreeDevice(&local_devices[j]);
3790 }
3791 }
3792 }
3793}
3794
Emil Velikov11687bf2016-11-30 17:24:21 +00003795/* Check that the given flags are valid returning 0 on success */
3796static int
3797drm_device_validate_flags(uint32_t flags)
3798{
3799 return (flags & ~DRM_DEVICE_GET_PCI_REVISION);
3800}
3801
Emil Velikov56e72d32018-06-21 16:06:35 +01003802static bool
3803drm_device_has_rdev(drmDevicePtr device, dev_t find_rdev)
3804{
3805 struct stat sbuf;
3806
3807 for (int i = 0; i < DRM_NODE_MAX; i++) {
3808 if (device->available_nodes & 1 << i) {
3809 if (stat(device->nodes[i], &sbuf) == 0 &&
3810 sbuf.st_rdev == find_rdev)
3811 return true;
3812 }
3813 }
3814 return false;
3815}
3816
Emil Velikov95b262f2018-05-15 16:32:10 +01003817/*
3818 * The kernel drm core has a number of places that assume maximum of
3819 * 3x64 devices nodes. That's 64 for each of primary, control and
3820 * render nodes. Rounded it up to 256 for simplicity.
3821 */
3822#define MAX_DRM_NODES 256
3823
Emil Velikovb556ea12015-08-17 11:09:06 +08003824/**
Emil Velikovccedf662015-09-09 16:02:18 +01003825 * Get information about the opened drm device
3826 *
3827 * \param fd file descriptor of the drm device
Emil Velikov11687bf2016-11-30 17:24:21 +00003828 * \param flags feature/behaviour bitmask
Emil Velikovccedf662015-09-09 16:02:18 +01003829 * \param device the address of a drmDevicePtr where the information
3830 * will be allocated in stored
3831 *
3832 * \return zero on success, negative error code otherwise.
Emil Velikov11687bf2016-11-30 17:24:21 +00003833 *
3834 * \note Unlike drmGetDevice it does not retrieve the pci device revision field
3835 * unless the DRM_DEVICE_GET_PCI_REVISION \p flag is set.
Emil Velikovccedf662015-09-09 16:02:18 +01003836 */
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07003837drm_public int drmGetDevice2(int fd, uint32_t flags, drmDevicePtr *device)
Emil Velikovccedf662015-09-09 16:02:18 +01003838{
Jonathan Gray08257922016-12-01 15:18:43 +11003839#ifdef __OpenBSD__
3840 /*
3841 * DRI device nodes on OpenBSD are not in their own directory, they reside
3842 * in /dev along with a large number of statically generated /dev nodes.
3843 * Avoid stat'ing all of /dev needlessly by implementing this custom path.
3844 */
3845 drmDevicePtr d;
3846 struct stat sbuf;
3847 char node[PATH_MAX + 1];
3848 const char *dev_name;
3849 int node_type, subsystem_type;
Jonathan Grayd5cf3f92016-12-17 16:09:51 +11003850 int maj, min, n, ret, base;
Jonathan Gray08257922016-12-01 15:18:43 +11003851
3852 if (fd == -1 || device == NULL)
3853 return -EINVAL;
3854
3855 if (fstat(fd, &sbuf))
3856 return -errno;
3857
3858 maj = major(sbuf.st_rdev);
3859 min = minor(sbuf.st_rdev);
3860
Thomas Hellstromf8392582018-08-31 13:47:05 +02003861 if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode))
Jonathan Gray08257922016-12-01 15:18:43 +11003862 return -EINVAL;
3863
3864 node_type = drmGetMinorType(min);
3865 if (node_type == -1)
3866 return -ENODEV;
3867
3868 switch (node_type) {
3869 case DRM_NODE_PRIMARY:
3870 dev_name = DRM_DEV_NAME;
3871 break;
3872 case DRM_NODE_CONTROL:
3873 dev_name = DRM_CONTROL_DEV_NAME;
3874 break;
3875 case DRM_NODE_RENDER:
3876 dev_name = DRM_RENDER_DEV_NAME;
3877 break;
3878 default:
3879 return -EINVAL;
3880 };
3881
Jonathan Grayd5cf3f92016-12-17 16:09:51 +11003882 base = drmGetMinorBase(node_type);
3883 if (base < 0)
3884 return -EINVAL;
3885
3886 n = snprintf(node, PATH_MAX, dev_name, DRM_DIR_NAME, min - base);
Jonathan Gray08257922016-12-01 15:18:43 +11003887 if (n == -1 || n >= PATH_MAX)
3888 return -errno;
3889 if (stat(node, &sbuf))
3890 return -EINVAL;
3891
3892 subsystem_type = drmParseSubsystemType(maj, min);
3893 if (subsystem_type != DRM_BUS_PCI)
3894 return -ENODEV;
3895
3896 ret = drmProcessPciDevice(&d, node, node_type, maj, min, true, flags);
3897 if (ret)
3898 return ret;
3899
3900 *device = d;
3901
3902 return 0;
3903#else
Emil Velikov95b262f2018-05-15 16:32:10 +01003904 drmDevicePtr local_devices[MAX_DRM_NODES];
Emil Velikovccedf662015-09-09 16:02:18 +01003905 drmDevicePtr d;
3906 DIR *sysdir;
3907 struct dirent *dent;
3908 struct stat sbuf;
Emil Velikovf808fee2018-05-15 15:02:52 +01003909 int subsystem_type;
Emil Velikovccedf662015-09-09 16:02:18 +01003910 int maj, min;
3911 int ret, i, node_count;
Qiang Yu3c208932016-07-14 17:10:55 +08003912 dev_t find_rdev;
Emil Velikov11687bf2016-11-30 17:24:21 +00003913
3914 if (drm_device_validate_flags(flags))
3915 return -EINVAL;
Emil Velikovccedf662015-09-09 16:02:18 +01003916
3917 if (fd == -1 || device == NULL)
3918 return -EINVAL;
3919
3920 if (fstat(fd, &sbuf))
3921 return -errno;
3922
Qiang Yu3c208932016-07-14 17:10:55 +08003923 find_rdev = sbuf.st_rdev;
Emil Velikovccedf662015-09-09 16:02:18 +01003924 maj = major(sbuf.st_rdev);
3925 min = minor(sbuf.st_rdev);
3926
Thomas Hellstromf8392582018-08-31 13:47:05 +02003927 if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode))
Emil Velikovccedf662015-09-09 16:02:18 +01003928 return -EINVAL;
3929
3930 subsystem_type = drmParseSubsystemType(maj, min);
Emil Velikov7f52a0e2018-05-15 16:43:58 +01003931 if (subsystem_type < 0)
3932 return subsystem_type;
Emil Velikovccedf662015-09-09 16:02:18 +01003933
Emil Velikovccedf662015-09-09 16:02:18 +01003934 sysdir = opendir(DRM_DIR_NAME);
Emil Velikov95b262f2018-05-15 16:32:10 +01003935 if (!sysdir)
3936 return -errno;
Emil Velikovccedf662015-09-09 16:02:18 +01003937
3938 i = 0;
3939 while ((dent = readdir(sysdir))) {
Emil Velikovf808fee2018-05-15 15:02:52 +01003940 ret = process_device(&d, dent->d_name, subsystem_type, true, flags);
3941 if (ret)
Emil Velikovccedf662015-09-09 16:02:18 +01003942 continue;
3943
Emil Velikov95b262f2018-05-15 16:32:10 +01003944 if (i >= MAX_DRM_NODES) {
3945 fprintf(stderr, "More than %d drm nodes detected. "
3946 "Please report a bug - that should not happen.\n"
3947 "Skipping extra nodes\n", MAX_DRM_NODES);
3948 break;
Emil Velikovccedf662015-09-09 16:02:18 +01003949 }
Emil Velikov56e72d32018-06-21 16:06:35 +01003950 local_devices[i] = d;
Emil Velikovccedf662015-09-09 16:02:18 +01003951 i++;
3952 }
3953 node_count = i;
3954
Emil Velikovccedf662015-09-09 16:02:18 +01003955 drmFoldDuplicatedDevices(local_devices, node_count);
3956
Mariusz Ceier4519db22018-07-29 10:20:14 +02003957 *device = NULL;
3958
Emil Velikov56e72d32018-06-21 16:06:35 +01003959 for (i = 0; i < node_count; i++) {
3960 if (!local_devices[i])
3961 continue;
3962
3963 if (drm_device_has_rdev(local_devices[i], find_rdev))
3964 *device = local_devices[i];
3965 else
3966 drmFreeDevice(&local_devices[i]);
3967 }
Emil Velikovccedf662015-09-09 16:02:18 +01003968
Emil Velikovccedf662015-09-09 16:02:18 +01003969 closedir(sysdir);
Rob Herring677cd972016-10-21 10:07:59 -07003970 if (*device == NULL)
Thierry Redinge17cad12016-12-21 18:00:52 +01003971 return -ENODEV;
Emil Velikovccedf662015-09-09 16:02:18 +01003972 return 0;
Jonathan Gray08257922016-12-01 15:18:43 +11003973#endif
Emil Velikovccedf662015-09-09 16:02:18 +01003974}
3975
3976/**
Emil Velikov11687bf2016-11-30 17:24:21 +00003977 * Get information about the opened drm device
3978 *
3979 * \param fd file descriptor of the drm device
3980 * \param device the address of a drmDevicePtr where the information
3981 * will be allocated in stored
3982 *
3983 * \return zero on success, negative error code otherwise.
3984 */
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07003985drm_public int drmGetDevice(int fd, drmDevicePtr *device)
Emil Velikov11687bf2016-11-30 17:24:21 +00003986{
3987 return drmGetDevice2(fd, DRM_DEVICE_GET_PCI_REVISION, device);
3988}
3989
3990/**
Emil Velikovb556ea12015-08-17 11:09:06 +08003991 * Get drm devices on the system
3992 *
Emil Velikov11687bf2016-11-30 17:24:21 +00003993 * \param flags feature/behaviour bitmask
Emil Velikovb556ea12015-08-17 11:09:06 +08003994 * \param devices the array of devices with drmDevicePtr elements
3995 * can be NULL to get the device number first
3996 * \param max_devices the maximum number of devices for the array
3997 *
3998 * \return on error - negative error code,
3999 * if devices is NULL - total number of devices available on the system,
4000 * alternatively the number of devices stored in devices[], which is
4001 * capped by the max_devices.
Emil Velikov11687bf2016-11-30 17:24:21 +00004002 *
4003 * \note Unlike drmGetDevices it does not retrieve the pci device revision field
4004 * unless the DRM_DEVICE_GET_PCI_REVISION \p flag is set.
Emil Velikovb556ea12015-08-17 11:09:06 +08004005 */
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07004006drm_public int drmGetDevices2(uint32_t flags, drmDevicePtr devices[],
4007 int max_devices)
Emil Velikovb556ea12015-08-17 11:09:06 +08004008{
Emil Velikov95b262f2018-05-15 16:32:10 +01004009 drmDevicePtr local_devices[MAX_DRM_NODES];
Emil Velikov5f68d312015-09-07 13:54:32 +01004010 drmDevicePtr device;
4011 DIR *sysdir;
4012 struct dirent *dent;
Emil Velikovfae59d72015-09-09 17:54:34 +01004013 int ret, i, node_count, device_count;
Emil Velikov11687bf2016-11-30 17:24:21 +00004014
4015 if (drm_device_validate_flags(flags))
4016 return -EINVAL;
Emil Velikovb556ea12015-08-17 11:09:06 +08004017
Emil Velikovb556ea12015-08-17 11:09:06 +08004018 sysdir = opendir(DRM_DIR_NAME);
Emil Velikov95b262f2018-05-15 16:32:10 +01004019 if (!sysdir)
4020 return -errno;
Emil Velikovb556ea12015-08-17 11:09:06 +08004021
Emil Velikov5f68d312015-09-07 13:54:32 +01004022 i = 0;
Emil Velikovb556ea12015-08-17 11:09:06 +08004023 while ((dent = readdir(sysdir))) {
Emil Velikovf808fee2018-05-15 15:02:52 +01004024 ret = process_device(&device, dent->d_name, -1, devices != NULL, flags);
4025 if (ret)
Emil Velikovb556ea12015-08-17 11:09:06 +08004026 continue;
4027
Emil Velikov95b262f2018-05-15 16:32:10 +01004028 if (i >= MAX_DRM_NODES) {
4029 fprintf(stderr, "More than %d drm nodes detected. "
4030 "Please report a bug - that should not happen.\n"
4031 "Skipping extra nodes\n", MAX_DRM_NODES);
4032 break;
Emil Velikov5f68d312015-09-07 13:54:32 +01004033 }
Emil Velikov5f68d312015-09-07 13:54:32 +01004034 local_devices[i] = device;
Emil Velikovb556ea12015-08-17 11:09:06 +08004035 i++;
4036 }
Emil Velikovb556ea12015-08-17 11:09:06 +08004037 node_count = i;
4038
Emil Velikovfae59d72015-09-09 17:54:34 +01004039 drmFoldDuplicatedDevices(local_devices, node_count);
Emil Velikovb556ea12015-08-17 11:09:06 +08004040
Emil Velikov5f68d312015-09-07 13:54:32 +01004041 device_count = 0;
Qiang Yu70b64072016-06-06 12:29:16 -04004042 for (i = 0; i < node_count; i++) {
Jan Vesely50d3c852016-06-30 14:22:52 -04004043 if (!local_devices[i])
4044 continue;
Qiang Yu70b64072016-06-06 12:29:16 -04004045
Emil Velikov5f68d312015-09-07 13:54:32 +01004046 if ((devices != NULL) && (device_count < max_devices))
4047 devices[device_count] = local_devices[i];
4048 else
4049 drmFreeDevice(&local_devices[i]);
4050
4051 device_count++;
Emil Velikovb556ea12015-08-17 11:09:06 +08004052 }
4053
Emil Velikovb556ea12015-08-17 11:09:06 +08004054 closedir(sysdir);
Emil Velikov5f68d312015-09-07 13:54:32 +01004055 return device_count;
Emil Velikovb556ea12015-08-17 11:09:06 +08004056}
Emil Velikov37d790f2016-11-10 17:26:50 +00004057
Emil Velikov11687bf2016-11-30 17:24:21 +00004058/**
4059 * Get drm devices on the system
4060 *
4061 * \param devices the array of devices with drmDevicePtr elements
4062 * can be NULL to get the device number first
4063 * \param max_devices the maximum number of devices for the array
4064 *
4065 * \return on error - negative error code,
4066 * if devices is NULL - total number of devices available on the system,
4067 * alternatively the number of devices stored in devices[], which is
4068 * capped by the max_devices.
4069 */
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07004070drm_public int drmGetDevices(drmDevicePtr devices[], int max_devices)
Emil Velikov11687bf2016-11-30 17:24:21 +00004071{
4072 return drmGetDevices2(DRM_DEVICE_GET_PCI_REVISION, devices, max_devices);
4073}
4074
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07004075drm_public char *drmGetDeviceNameFromFd2(int fd)
Emil Velikov37d790f2016-11-10 17:26:50 +00004076{
4077#ifdef __linux__
4078 struct stat sbuf;
Thierry Reding5403cb32017-01-18 08:29:23 +01004079 char path[PATH_MAX + 1], *value;
Emil Velikov37d790f2016-11-10 17:26:50 +00004080 unsigned int maj, min;
Emil Velikov37d790f2016-11-10 17:26:50 +00004081
4082 if (fstat(fd, &sbuf))
4083 return NULL;
4084
4085 maj = major(sbuf.st_rdev);
4086 min = minor(sbuf.st_rdev);
4087
Thomas Hellstromf8392582018-08-31 13:47:05 +02004088 if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode))
Emil Velikov37d790f2016-11-10 17:26:50 +00004089 return NULL;
4090
Thierry Reding5403cb32017-01-18 08:29:23 +01004091 snprintf(path, sizeof(path), "/sys/dev/char/%d:%d", maj, min);
4092
4093 value = sysfs_uevent_get(path, "DEVNAME");
4094 if (!value)
Emil Velikov37d790f2016-11-10 17:26:50 +00004095 return NULL;
4096
Thierry Reding5403cb32017-01-18 08:29:23 +01004097 snprintf(path, sizeof(path), "/dev/%s", value);
4098 free(value);
Emil Velikov37d790f2016-11-10 17:26:50 +00004099
Thierry Reding5403cb32017-01-18 08:29:23 +01004100 return strdup(path);
Emil Velikov37d790f2016-11-10 17:26:50 +00004101#else
Jonathan Graye2e766d2016-12-17 16:09:52 +11004102 struct stat sbuf;
4103 char node[PATH_MAX + 1];
4104 const char *dev_name;
4105 int node_type;
4106 int maj, min, n, base;
4107
4108 if (fstat(fd, &sbuf))
4109 return NULL;
4110
4111 maj = major(sbuf.st_rdev);
4112 min = minor(sbuf.st_rdev);
4113
Thomas Hellstromf8392582018-08-31 13:47:05 +02004114 if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode))
Jonathan Graye2e766d2016-12-17 16:09:52 +11004115 return NULL;
4116
4117 node_type = drmGetMinorType(min);
4118 if (node_type == -1)
4119 return NULL;
4120
4121 switch (node_type) {
4122 case DRM_NODE_PRIMARY:
4123 dev_name = DRM_DEV_NAME;
4124 break;
4125 case DRM_NODE_CONTROL:
4126 dev_name = DRM_CONTROL_DEV_NAME;
4127 break;
4128 case DRM_NODE_RENDER:
4129 dev_name = DRM_RENDER_DEV_NAME;
4130 break;
4131 default:
4132 return NULL;
4133 };
4134
4135 base = drmGetMinorBase(node_type);
4136 if (base < 0)
4137 return NULL;
4138
4139 n = snprintf(node, PATH_MAX, dev_name, DRM_DIR_NAME, min - base);
4140 if (n == -1 || n >= PATH_MAX)
4141 return NULL;
4142
4143 return strdup(node);
Emil Velikov37d790f2016-11-10 17:26:50 +00004144#endif
4145}
Dave Airliefc492272017-06-17 11:01:01 +10004146
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07004147drm_public int drmSyncobjCreate(int fd, uint32_t flags, uint32_t *handle)
Dave Airliefc492272017-06-17 11:01:01 +10004148{
4149 struct drm_syncobj_create args;
4150 int ret;
4151
4152 memclear(args);
4153 args.flags = flags;
4154 args.handle = 0;
4155 ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_CREATE, &args);
4156 if (ret)
Dave Airlie61ff9772017-10-25 07:43:56 +01004157 return ret;
Dave Airliefc492272017-06-17 11:01:01 +10004158 *handle = args.handle;
4159 return 0;
4160}
4161
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07004162drm_public int drmSyncobjDestroy(int fd, uint32_t handle)
Dave Airliefc492272017-06-17 11:01:01 +10004163{
4164 struct drm_syncobj_destroy args;
4165
4166 memclear(args);
4167 args.handle = handle;
4168 return drmIoctl(fd, DRM_IOCTL_SYNCOBJ_DESTROY, &args);
4169}
4170
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07004171drm_public int drmSyncobjHandleToFD(int fd, uint32_t handle, int *obj_fd)
Dave Airliefc492272017-06-17 11:01:01 +10004172{
4173 struct drm_syncobj_handle args;
4174 int ret;
4175
4176 memclear(args);
4177 args.fd = -1;
4178 args.handle = handle;
4179 ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD, &args);
4180 if (ret)
Dave Airlie61ff9772017-10-25 07:43:56 +01004181 return ret;
Dave Airliefc492272017-06-17 11:01:01 +10004182 *obj_fd = args.fd;
4183 return 0;
4184}
4185
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07004186drm_public int drmSyncobjFDToHandle(int fd, int obj_fd, uint32_t *handle)
Dave Airliefc492272017-06-17 11:01:01 +10004187{
4188 struct drm_syncobj_handle args;
4189 int ret;
4190
4191 memclear(args);
4192 args.fd = obj_fd;
4193 args.handle = 0;
4194 ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE, &args);
4195 if (ret)
Dave Airlie61ff9772017-10-25 07:43:56 +01004196 return ret;
Dave Airliefc492272017-06-17 11:01:01 +10004197 *handle = args.handle;
4198 return 0;
4199}
4200
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07004201drm_public int drmSyncobjImportSyncFile(int fd, uint32_t handle,
4202 int sync_file_fd)
Dave Airliefc492272017-06-17 11:01:01 +10004203{
4204 struct drm_syncobj_handle args;
4205
4206 memclear(args);
4207 args.fd = sync_file_fd;
4208 args.handle = handle;
4209 args.flags = DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_IMPORT_SYNC_FILE;
4210 return drmIoctl(fd, DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE, &args);
4211}
4212
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07004213drm_public int drmSyncobjExportSyncFile(int fd, uint32_t handle,
4214 int *sync_file_fd)
Dave Airliefc492272017-06-17 11:01:01 +10004215{
4216 struct drm_syncobj_handle args;
4217 int ret;
4218
4219 memclear(args);
4220 args.fd = -1;
4221 args.handle = handle;
4222 args.flags = DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_EXPORT_SYNC_FILE;
4223 ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD, &args);
4224 if (ret)
Dave Airlie61ff9772017-10-25 07:43:56 +01004225 return ret;
Dave Airliefc492272017-06-17 11:01:01 +10004226 *sync_file_fd = args.fd;
4227 return 0;
4228}
Marek Olšák2048a9e2017-09-11 21:57:32 +02004229
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07004230drm_public int drmSyncobjWait(int fd, uint32_t *handles, unsigned num_handles,
4231 int64_t timeout_nsec, unsigned flags,
4232 uint32_t *first_signaled)
Marek Olšák2048a9e2017-09-11 21:57:32 +02004233{
Dave Airlie61ff9772017-10-25 07:43:56 +01004234 struct drm_syncobj_wait args;
4235 int ret;
Marek Olšák2048a9e2017-09-11 21:57:32 +02004236
Dave Airlie61ff9772017-10-25 07:43:56 +01004237 memclear(args);
Bas Nieuwenhuizenb1e63d92018-02-06 11:21:35 +01004238 args.handles = (uintptr_t)handles;
Dave Airlie61ff9772017-10-25 07:43:56 +01004239 args.timeout_nsec = timeout_nsec;
4240 args.count_handles = num_handles;
4241 args.flags = flags;
Marek Olšák2048a9e2017-09-11 21:57:32 +02004242
Dave Airlie61ff9772017-10-25 07:43:56 +01004243 ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_WAIT, &args);
4244 if (ret < 0)
Chunming Zhoubde3b9b2018-02-07 11:22:32 +08004245 return -errno;
Marek Olšák2048a9e2017-09-11 21:57:32 +02004246
Dave Airlie61ff9772017-10-25 07:43:56 +01004247 if (first_signaled)
4248 *first_signaled = args.first_signaled;
4249 return ret;
Marek Olšák2048a9e2017-09-11 21:57:32 +02004250}
Bas Nieuwenhuizen1abcced2017-12-17 00:27:09 +01004251
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07004252drm_public int drmSyncobjReset(int fd, const uint32_t *handles,
4253 uint32_t handle_count)
Bas Nieuwenhuizen1abcced2017-12-17 00:27:09 +01004254{
4255 struct drm_syncobj_array args;
4256 int ret;
4257
4258 memclear(args);
4259 args.handles = (uintptr_t)handles;
4260 args.count_handles = handle_count;
4261
4262 ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_RESET, &args);
4263 return ret;
4264}
4265
Lucas De Marchi26f9ce52018-09-13 15:42:26 -07004266drm_public int drmSyncobjSignal(int fd, const uint32_t *handles,
4267 uint32_t handle_count)
Bas Nieuwenhuizen1abcced2017-12-17 00:27:09 +01004268{
4269 struct drm_syncobj_array args;
4270 int ret;
4271
4272 memclear(args);
4273 args.handles = (uintptr_t)handles;
4274 args.count_handles = handle_count;
4275
4276 ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_SIGNAL, &args);
4277 return ret;
4278}
Chunming Zhouec6ae512019-05-16 16:07:09 +08004279
Chunming Zhou12712eb2019-05-16 16:07:11 +08004280drm_public int drmSyncobjTimelineSignal(int fd, const uint32_t *handles,
4281 uint64_t *points, uint32_t handle_count)
4282{
4283 struct drm_syncobj_timeline_array args;
4284 int ret;
4285
4286 memclear(args);
4287 args.handles = (uintptr_t)handles;
4288 args.points = (uintptr_t)points;
4289 args.count_handles = handle_count;
4290
4291 ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_TIMELINE_SIGNAL, &args);
4292 return ret;
4293}
4294
Chunming Zhouec6ae512019-05-16 16:07:09 +08004295drm_public int drmSyncobjTimelineWait(int fd, uint32_t *handles, uint64_t *points,
4296 unsigned num_handles,
4297 int64_t timeout_nsec, unsigned flags,
4298 uint32_t *first_signaled)
4299{
4300 struct drm_syncobj_timeline_wait args;
4301 int ret;
4302
4303 memclear(args);
4304 args.handles = (uintptr_t)handles;
4305 args.points = (uintptr_t)points;
4306 args.timeout_nsec = timeout_nsec;
4307 args.count_handles = num_handles;
4308 args.flags = flags;
4309
4310 ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_TIMELINE_WAIT, &args);
4311 if (ret < 0)
4312 return -errno;
4313
4314 if (first_signaled)
4315 *first_signaled = args.first_signaled;
4316 return ret;
4317}
4318
4319
4320drm_public int drmSyncobjQuery(int fd, uint32_t *handles, uint64_t *points,
4321 uint32_t handle_count)
4322{
4323 struct drm_syncobj_timeline_array args;
4324 int ret;
4325
4326 memclear(args);
4327 args.handles = (uintptr_t)handles;
4328 args.points = (uintptr_t)points;
4329 args.count_handles = handle_count;
4330
4331 ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_QUERY, &args);
4332 if (ret)
4333 return ret;
4334 return 0;
4335}
4336
Chunming Zhou12712eb2019-05-16 16:07:11 +08004337drm_public int drmSyncobjTransfer(int fd,
4338 uint32_t dst_handle, uint64_t dst_point,
4339 uint32_t src_handle, uint64_t src_point,
4340 uint32_t flags)
4341{
4342 struct drm_syncobj_transfer args;
4343 int ret;
Chunming Zhouec6ae512019-05-16 16:07:09 +08004344
Chunming Zhou12712eb2019-05-16 16:07:11 +08004345 memclear(args);
4346 args.src_handle = src_handle;
4347 args.dst_handle = dst_handle;
4348 args.src_point = src_point;
4349 args.dst_point = dst_point;
4350 args.flags = flags;
4351
4352 ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_TRANSFER, &args);
4353
4354 return ret;
4355}