blob: 7e28b4f7b1c87a8ea5f25c29f4a2fbf47ed9e4de [file] [log] [blame]
Jose Fonsecad2443b22003-05-27 00:37:33 +00001/**
2 * \file xf86drm.c
3 * 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#ifdef HAVE_CONFIG_H
35# include <config.h>
Daryll Straussb3a57661999-12-05 01:19:48 +000036#endif
Dave Airlie79038752006-11-08 15:08:09 +110037#include <stdio.h>
38#include <stdlib.h>
Emil Velikovfae59d72015-09-09 17:54:34 +010039#include <stdbool.h>
Dave Airlie79038752006-11-08 15:08:09 +110040#include <unistd.h>
41#include <string.h>
Ian Romanick015efd12009-07-06 09:23:59 -070042#include <strings.h>
Dave Airlie79038752006-11-08 15:08:09 +110043#include <ctype.h>
Emil Velikov0ca03a42015-03-07 00:58:39 +000044#include <dirent.h>
45#include <stddef.h>
Dave Airlie79038752006-11-08 15:08:09 +110046#include <fcntl.h>
47#include <errno.h>
Felix Janda4031dc12015-09-26 08:08:43 +020048#include <limits.h>
Dave Airlie79038752006-11-08 15:08:09 +110049#include <signal.h>
Jesse Barnesf4f76a62009-01-07 10:18:08 -080050#include <time.h>
Dave Airlie79038752006-11-08 15:08:09 +110051#include <sys/types.h>
52#include <sys/stat.h>
53#define stat_t struct stat
54#include <sys/ioctl.h>
Dave Airlie79038752006-11-08 15:08:09 +110055#include <sys/time.h>
56#include <stdarg.h>
Alan Coopersmith0e1135d2015-03-07 11:44:32 -080057#ifdef HAVE_SYS_MKDEV_H
58# include <sys/mkdev.h> /* defines major(), minor(), and makedev() on Solaris */
59#endif
Emil Velikovb556ea12015-08-17 11:09:06 +080060#include <math.h>
Daryll Straussb3a57661999-12-05 01:19:48 +000061
62/* Not all systems have MAP_FAILED defined */
63#ifndef MAP_FAILED
64#define MAP_FAILED ((void *)-1)
65#endif
66
Daryll Straussb3a57661999-12-05 01:19:48 +000067#include "xf86drm.h"
Emil Velikov42465fe2015-04-05 15:51:59 +010068#include "libdrm_macros.h"
Daryll Straussb3a57661999-12-05 01:19:48 +000069
Emil Velikov5f68d312015-09-07 13:54:32 +010070#include "util_math.h"
71
Jonathan Grayfc083322015-07-21 03:12:56 +100072#ifdef __OpenBSD__
73#define DRM_PRIMARY_MINOR_NAME "drm"
74#define DRM_CONTROL_MINOR_NAME "drmC"
75#define DRM_RENDER_MINOR_NAME "drmR"
76#else
77#define DRM_PRIMARY_MINOR_NAME "card"
78#define DRM_CONTROL_MINOR_NAME "controlD"
79#define DRM_RENDER_MINOR_NAME "renderD"
80#endif
81
Hasso Tepper27c37852008-04-07 15:27:43 +030082#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
Eric Anholtcfa778a2003-02-21 23:23:09 +000083#define DRM_MAJOR 145
Rik Faith88dbee52001-02-28 09:27:44 +000084#endif
85
Eric Anholtcfa778a2003-02-21 23:23:09 +000086#ifdef __NetBSD__
87#define DRM_MAJOR 34
88#endif
89
Jonathan Gray66c3afb2015-07-21 03:12:10 +100090#ifdef __OpenBSD__
91#ifdef __i386__
92#define DRM_MAJOR 88
93#else
94#define DRM_MAJOR 87
95#endif
96#endif /* __OpenBSD__ */
Alan Hourihaneb0a92852003-09-24 14:39:25 +000097
Eric Anholtcfa778a2003-02-21 23:23:09 +000098#ifndef DRM_MAJOR
99#define DRM_MAJOR 226 /* Linux */
Rik Faith88dbee52001-02-28 09:27:44 +0000100#endif
101
David Dawes56bd9c22001-07-30 19:59:39 +0000102#define DRM_MSG_VERBOSITY 3
103
Daniel Vetterfd387942015-02-11 12:41:04 +0100104#define memclear(s) memset(&s, 0, sizeof(s))
105
Dave Airlie79038752006-11-08 15:08:09 +1100106static drmServerInfoPtr drm_server_info;
107
108void drmSetServerInfo(drmServerInfoPtr info)
109{
Brianccd7b6e2007-05-29 14:54:00 -0600110 drm_server_info = info;
Dave Airlie79038752006-11-08 15:08:09 +1100111}
112
Jose Fonsecad2443b22003-05-27 00:37:33 +0000113/**
114 * Output a message to stderr.
115 *
116 * \param format printf() like format string.
117 *
118 * \internal
119 * This function is a wrapper around vfprintf().
120 */
Dave Airlie79038752006-11-08 15:08:09 +1100121
Thierry Reding44b08c02014-01-22 12:06:51 +0100122static int DRM_PRINTFLIKE(1, 0)
123drmDebugPrint(const char *format, va_list ap)
Dave Airlie79038752006-11-08 15:08:09 +1100124{
Brianccd7b6e2007-05-29 14:54:00 -0600125 return vfprintf(stderr, format, ap);
Dave Airlie79038752006-11-08 15:08:09 +1100126}
127
Eric Anholtc4857422008-06-03 10:20:49 -0700128void
David Dawes56bd9c22001-07-30 19:59:39 +0000129drmMsg(const char *format, ...)
130{
131 va_list ap;
David Dawes56bd9c22001-07-30 19:59:39 +0000132 const char *env;
Rob Clarkeb7c2d52015-09-04 08:08:02 -0400133 if (((env = getenv("LIBGL_DEBUG")) && strstr(env, "verbose")) ||
134 (drm_server_info && drm_server_info->debug_print))
David Dawes56bd9c22001-07-30 19:59:39 +0000135 {
136 va_start(ap, format);
Dave Airlie79038752006-11-08 15:08:09 +1100137 if (drm_server_info) {
138 drm_server_info->debug_print(format,ap);
139 } else {
Jan Veselycfbe9c92015-03-18 14:17:26 -0400140 drmDebugPrint(format, ap);
Dave Airlie79038752006-11-08 15:08:09 +1100141 }
David Dawes56bd9c22001-07-30 19:59:39 +0000142 va_end(ap);
143 }
144}
145
Daryll Straussb3a57661999-12-05 01:19:48 +0000146static void *drmHashTable = NULL; /* Context switch callbacks */
147
Dave Airlie79038752006-11-08 15:08:09 +1100148void *drmGetHashTable(void)
149{
Brianccd7b6e2007-05-29 14:54:00 -0600150 return drmHashTable;
Dave Airlie79038752006-11-08 15:08:09 +1100151}
Daryll Straussb3a57661999-12-05 01:19:48 +0000152
153void *drmMalloc(int size)
154{
Emil Velikovd0e592d2015-04-28 13:33:46 +0100155 return calloc(1, size);
Daryll Straussb3a57661999-12-05 01:19:48 +0000156}
157
158void drmFree(void *pt)
159{
Emil Velikovd0e592d2015-04-28 13:33:46 +0100160 free(pt);
Daryll Straussb3a57661999-12-05 01:19:48 +0000161}
162
Keith Packard8b9ab102008-06-13 16:03:22 -0700163/**
164 * Call ioctl, restarting if it is interupted
165 */
Jesse Barnes731cd552008-12-17 10:09:49 -0800166int
Coleman Kane41b83a92008-08-18 17:08:21 -0400167drmIoctl(int fd, unsigned long request, void *arg)
Keith Packard8b9ab102008-06-13 16:03:22 -0700168{
169 int ret;
170
171 do {
172 ret = ioctl(fd, request, arg);
173 } while (ret == -1 && (errno == EINTR || errno == EAGAIN));
174 return ret;
175}
Daryll Straussb3a57661999-12-05 01:19:48 +0000176
Daryll Straussb3a57661999-12-05 01:19:48 +0000177static unsigned long drmGetKeyFromFd(int fd)
178{
David Dawesfcc21062001-03-30 17:16:20 +0000179 stat_t st;
Daryll Straussb3a57661999-12-05 01:19:48 +0000180
181 st.st_rdev = 0;
182 fstat(fd, &st);
183 return st.st_rdev;
184}
185
Dave Airlie79038752006-11-08 15:08:09 +1100186drmHashEntry *drmGetEntry(int fd)
Daryll Straussb3a57661999-12-05 01:19:48 +0000187{
188 unsigned long key = drmGetKeyFromFd(fd);
189 void *value;
190 drmHashEntry *entry;
191
Brianccd7b6e2007-05-29 14:54:00 -0600192 if (!drmHashTable)
193 drmHashTable = drmHashCreate();
Daryll Straussb3a57661999-12-05 01:19:48 +0000194
195 if (drmHashLookup(drmHashTable, key, &value)) {
196 entry = drmMalloc(sizeof(*entry));
197 entry->fd = fd;
198 entry->f = NULL;
199 entry->tagTable = drmHashCreate();
200 drmHashInsert(drmHashTable, key, entry);
201 } else {
202 entry = value;
203 }
204 return entry;
205}
206
Jose Fonsecad2443b22003-05-27 00:37:33 +0000207/**
Eric Anholt06cb1322003-10-23 02:23:31 +0000208 * Compare two busid strings
209 *
210 * \param first
211 * \param second
212 *
213 * \return 1 if matched.
214 *
215 * \internal
216 * This function compares two bus ID strings. It understands the older
217 * PCI:b:d:f format and the newer pci:oooo:bb:dd.f format. In the format, o is
218 * domain, b is bus, d is device, f is function.
219 */
Benjamin Herrenschmidtb04515c2010-08-06 13:55:11 +1000220static int drmMatchBusID(const char *id1, const char *id2, int pci_domain_ok)
Eric Anholt06cb1322003-10-23 02:23:31 +0000221{
222 /* First, check if the IDs are exactly the same */
223 if (strcasecmp(id1, id2) == 0)
224 return 1;
225
226 /* Try to match old/new-style PCI bus IDs. */
227 if (strncasecmp(id1, "pci", 3) == 0) {
Pauli Nieminen90ae0f22009-07-04 02:18:51 +0300228 unsigned int o1, b1, d1, f1;
229 unsigned int o2, b2, d2, f2;
Eric Anholt06cb1322003-10-23 02:23:31 +0000230 int ret;
231
Pauli Nieminen90ae0f22009-07-04 02:18:51 +0300232 ret = sscanf(id1, "pci:%04x:%02x:%02x.%u", &o1, &b1, &d1, &f1);
Eric Anholt06cb1322003-10-23 02:23:31 +0000233 if (ret != 4) {
234 o1 = 0;
Pauli Nieminen90ae0f22009-07-04 02:18:51 +0300235 ret = sscanf(id1, "PCI:%u:%u:%u", &b1, &d1, &f1);
Eric Anholt06cb1322003-10-23 02:23:31 +0000236 if (ret != 3)
237 return 0;
238 }
239
Pauli Nieminen90ae0f22009-07-04 02:18:51 +0300240 ret = sscanf(id2, "pci:%04x:%02x:%02x.%u", &o2, &b2, &d2, &f2);
Eric Anholt06cb1322003-10-23 02:23:31 +0000241 if (ret != 4) {
242 o2 = 0;
Pauli Nieminen90ae0f22009-07-04 02:18:51 +0300243 ret = sscanf(id2, "PCI:%u:%u:%u", &b2, &d2, &f2);
Eric Anholt06cb1322003-10-23 02:23:31 +0000244 if (ret != 3)
245 return 0;
246 }
247
Benjamin Herrenschmidtb04515c2010-08-06 13:55:11 +1000248 /* If domains aren't properly supported by the kernel interface,
249 * just ignore them, which sucks less than picking a totally random
250 * card with "open by name"
251 */
252 if (!pci_domain_ok)
253 o1 = o2 = 0;
254
Eric Anholt06cb1322003-10-23 02:23:31 +0000255 if ((o1 != o2) || (b1 != b2) || (d1 != d2) || (f1 != f2))
256 return 0;
257 else
258 return 1;
259 }
260 return 0;
261}
262
263/**
Pauli Nieminenc5a5bbb2009-07-06 23:37:20 +0300264 * Handles error checking for chown call.
265 *
266 * \param path to file.
267 * \param id of the new owner.
268 * \param id of the new group.
269 *
270 * \return zero if success or -1 if failure.
271 *
272 * \internal
273 * Checks for failure. If failure was caused by signal call chown again.
274 * If any other failure happened then it will output error mesage using
275 * drmMsg() call.
276 */
Jan Vesely6fc0e4b2015-02-27 12:54:34 -0500277#if !defined(UDEV)
Pauli Nieminenc5a5bbb2009-07-06 23:37:20 +0300278static int chown_check_return(const char *path, uid_t owner, gid_t group)
279{
280 int rv;
281
282 do {
283 rv = chown(path, owner, group);
284 } while (rv != 0 && errno == EINTR);
285
286 if (rv == 0)
287 return 0;
288
289 drmMsg("Failed to change owner or group for file %s! %d: %s\n",
290 path, errno, strerror(errno));
291 return -1;
292}
Jan Vesely6fc0e4b2015-02-27 12:54:34 -0500293#endif
Pauli Nieminenc5a5bbb2009-07-06 23:37:20 +0300294
295/**
Jose Fonsecad2443b22003-05-27 00:37:33 +0000296 * Open the DRM device, creating it if necessary.
297 *
298 * \param dev major and minor numbers of the device.
299 * \param minor minor number of the device.
300 *
301 * \return a file descriptor on success, or a negative value on error.
302 *
303 * \internal
304 * Assembles the device name from \p minor and opens it, creating the device
305 * special file node with the major and minor numbers specified by \p dev and
306 * parent directory if necessary and was called by root.
307 */
Jan Veselyde8532d2014-11-30 12:53:18 -0500308static int drmOpenDevice(dev_t dev, int minor, int type)
Daryll Straussb3a57661999-12-05 01:19:48 +0000309{
David Dawes9c775d02001-05-14 14:49:58 +0000310 stat_t st;
Frank Binns0c5aaee2015-01-14 14:07:51 +0000311 const char *dev_name;
Rik Faith88dbee52001-02-28 09:27:44 +0000312 char buf[64];
313 int fd;
Dave Airlie79038752006-11-08 15:08:09 +1100314 mode_t devmode = DRM_DEV_MODE, serv_mode;
Jan Vesely0706c142015-02-27 12:47:46 -0500315 gid_t serv_group;
316#if !defined(UDEV)
Rik Faith88dbee52001-02-28 09:27:44 +0000317 int isroot = !geteuid();
Rik Faith88dbee52001-02-28 09:27:44 +0000318 uid_t user = DRM_DEV_UID;
Jan Vesely0706c142015-02-27 12:47:46 -0500319 gid_t group = DRM_DEV_GID;
320#endif
321
Frank Binns0c5aaee2015-01-14 14:07:51 +0000322 switch (type) {
323 case DRM_NODE_PRIMARY:
324 dev_name = DRM_DEV_NAME;
325 break;
326 case DRM_NODE_CONTROL:
327 dev_name = DRM_CONTROL_DEV_NAME;
328 break;
329 case DRM_NODE_RENDER:
330 dev_name = DRM_RENDER_DEV_NAME;
331 break;
332 default:
333 return -EINVAL;
334 };
335
336 sprintf(buf, dev_name, DRM_DIR_NAME, minor);
Eric Anholt06cb1322003-10-23 02:23:31 +0000337 drmMsg("drmOpenDevice: node name is %s\n", buf);
David Dawes56bd9c22001-07-30 19:59:39 +0000338
Rob Clarkeb7c2d52015-09-04 08:08:02 -0400339 if (drm_server_info && drm_server_info->get_perms) {
Brianccd7b6e2007-05-29 14:54:00 -0600340 drm_server_info->get_perms(&serv_group, &serv_mode);
341 devmode = serv_mode ? serv_mode : DRM_DEV_MODE;
342 devmode &= ~(S_IXUSR|S_IXGRP|S_IXOTH);
Dave Airlie79038752006-11-08 15:08:09 +1100343 }
Brian Paul569da5a2000-06-08 14:38:22 +0000344
Dave Airlie9101a022008-08-24 16:54:43 +1000345#if !defined(UDEV)
Rik Faith88dbee52001-02-28 09:27:44 +0000346 if (stat(DRM_DIR_NAME, &st)) {
Brianccd7b6e2007-05-29 14:54:00 -0600347 if (!isroot)
348 return DRM_ERR_NOT_ROOT;
Alan Hourihaneb3a20ce2002-10-22 23:38:53 +0000349 mkdir(DRM_DIR_NAME, DRM_DEV_DIRMODE);
Pauli Nieminenc5a5bbb2009-07-06 23:37:20 +0300350 chown_check_return(DRM_DIR_NAME, 0, 0); /* root:root */
Alan Hourihaneb3a20ce2002-10-22 23:38:53 +0000351 chmod(DRM_DIR_NAME, DRM_DEV_DIRMODE);
Brian Paul569da5a2000-06-08 14:38:22 +0000352 }
Daryll Straussb3a57661999-12-05 01:19:48 +0000353
Eric Anholt06cb1322003-10-23 02:23:31 +0000354 /* Check if the device node exists and create it if necessary. */
Eric Anholtd2f2b422002-08-08 21:23:46 +0000355 if (stat(buf, &st)) {
Brianccd7b6e2007-05-29 14:54:00 -0600356 if (!isroot)
357 return DRM_ERR_NOT_ROOT;
Rik Faith88dbee52001-02-28 09:27:44 +0000358 remove(buf);
359 mknod(buf, S_IFCHR | devmode, dev);
Daryll Straussb3a57661999-12-05 01:19:48 +0000360 }
Dave Airlie79038752006-11-08 15:08:09 +1100361
Rob Clarkeb7c2d52015-09-04 08:08:02 -0400362 if (drm_server_info && drm_server_info->get_perms) {
Jammy Zhou454b1492015-04-27 10:29:55 +0800363 group = ((int)serv_group >= 0) ? serv_group : DRM_DEV_GID;
Pauli Nieminenc5a5bbb2009-07-06 23:37:20 +0300364 chown_check_return(buf, user, group);
Brianccd7b6e2007-05-29 14:54:00 -0600365 chmod(buf, devmode);
Dave Airlie79038752006-11-08 15:08:09 +1100366 }
Dave Airlie9101a022008-08-24 16:54:43 +1000367#else
368 /* if we modprobed then wait for udev */
369 {
370 int udev_count = 0;
371wait_for_udev:
372 if (stat(DRM_DIR_NAME, &st)) {
373 usleep(20);
374 udev_count++;
375
376 if (udev_count == 50)
377 return -1;
378 goto wait_for_udev;
379 }
380
381 if (stat(buf, &st)) {
382 usleep(20);
383 udev_count++;
384
385 if (udev_count == 50)
386 return -1;
387 goto wait_for_udev;
388 }
389 }
390#endif
Rik Faith88dbee52001-02-28 09:27:44 +0000391
David Dawes56bd9c22001-07-30 19:59:39 +0000392 fd = open(buf, O_RDWR, 0);
393 drmMsg("drmOpenDevice: open result is %d, (%s)\n",
394 fd, fd < 0 ? strerror(errno) : "OK");
Brianccd7b6e2007-05-29 14:54:00 -0600395 if (fd >= 0)
396 return fd;
Eric Anholtd2f2b422002-08-08 21:23:46 +0000397
Dave Airlie39e5e982010-12-07 14:26:09 +1000398#if !defined(UDEV)
Eric Anholt06cb1322003-10-23 02:23:31 +0000399 /* Check if the device node is not what we expect it to be, and recreate it
400 * and try again if so.
401 */
Eric Anholtd2f2b422002-08-08 21:23:46 +0000402 if (st.st_rdev != dev) {
Brianccd7b6e2007-05-29 14:54:00 -0600403 if (!isroot)
404 return DRM_ERR_NOT_ROOT;
Eric Anholtd2f2b422002-08-08 21:23:46 +0000405 remove(buf);
406 mknod(buf, S_IFCHR | devmode, dev);
Rob Clarkeb7c2d52015-09-04 08:08:02 -0400407 if (drm_server_info && drm_server_info->get_perms) {
Pauli Nieminenc5a5bbb2009-07-06 23:37:20 +0300408 chown_check_return(buf, user, group);
Brianccd7b6e2007-05-29 14:54:00 -0600409 chmod(buf, devmode);
Dave Airlie79038752006-11-08 15:08:09 +1100410 }
Eric Anholtd2f2b422002-08-08 21:23:46 +0000411 }
412 fd = open(buf, O_RDWR, 0);
413 drmMsg("drmOpenDevice: open result is %d, (%s)\n",
414 fd, fd < 0 ? strerror(errno) : "OK");
Brianccd7b6e2007-05-29 14:54:00 -0600415 if (fd >= 0)
416 return fd;
Eric Anholtd2f2b422002-08-08 21:23:46 +0000417
David Dawes56bd9c22001-07-30 19:59:39 +0000418 drmMsg("drmOpenDevice: Open failed\n");
Rik Faith88dbee52001-02-28 09:27:44 +0000419 remove(buf);
Dave Airlie39e5e982010-12-07 14:26:09 +1000420#endif
Rik Faith88dbee52001-02-28 09:27:44 +0000421 return -errno;
Daryll Straussb3a57661999-12-05 01:19:48 +0000422}
423
Jose Fonsecad2443b22003-05-27 00:37:33 +0000424
425/**
426 * Open the DRM device
427 *
428 * \param minor device minor number.
429 * \param create allow to create the device if set.
430 *
431 * \return a file descriptor on success, or a negative value on error.
432 *
433 * \internal
434 * Calls drmOpenDevice() if \p create is set, otherwise assembles the device
435 * name from \p minor and opens it.
436 */
Jesse Barnes731cd552008-12-17 10:09:49 -0800437static int drmOpenMinor(int minor, int create, int type)
Rik Faith88dbee52001-02-28 09:27:44 +0000438{
439 int fd;
440 char buf[64];
Frank Binns0c5aaee2015-01-14 14:07:51 +0000441 const char *dev_name;
Dave Airliedb85ed22008-02-13 12:20:02 +1000442
Brianccd7b6e2007-05-29 14:54:00 -0600443 if (create)
Jesse Barnes731cd552008-12-17 10:09:49 -0800444 return drmOpenDevice(makedev(DRM_MAJOR, minor), minor, type);
Rik Faith88dbee52001-02-28 09:27:44 +0000445
Frank Binns0c5aaee2015-01-14 14:07:51 +0000446 switch (type) {
447 case DRM_NODE_PRIMARY:
448 dev_name = DRM_DEV_NAME;
449 break;
450 case DRM_NODE_CONTROL:
451 dev_name = DRM_CONTROL_DEV_NAME;
452 break;
453 case DRM_NODE_RENDER:
454 dev_name = DRM_RENDER_DEV_NAME;
455 break;
456 default:
457 return -EINVAL;
458 };
459
460 sprintf(buf, dev_name, DRM_DIR_NAME, minor);
Brianccd7b6e2007-05-29 14:54:00 -0600461 if ((fd = open(buf, O_RDWR, 0)) >= 0)
462 return fd;
Rik Faith88dbee52001-02-28 09:27:44 +0000463 return -errno;
464}
465
Brian Paul569da5a2000-06-08 14:38:22 +0000466
Jose Fonsecad2443b22003-05-27 00:37:33 +0000467/**
468 * Determine whether the DRM kernel driver has been loaded.
469 *
470 * \return 1 if the DRM driver is loaded, 0 otherwise.
471 *
472 * \internal
473 * Determine the presence of the kernel driver by attempting to open the 0
474 * minor and get version information. For backward compatibility with older
475 * Linux implementations, /proc/dri is also checked.
476 */
Brian Paul569da5a2000-06-08 14:38:22 +0000477int drmAvailable(void)
478{
Brian Paul569da5a2000-06-08 14:38:22 +0000479 drmVersionPtr version;
480 int retval = 0;
481 int fd;
Gareth Hughes36047532001-02-15 08:12:14 +0000482
Frank Binnsad8bbfd2015-01-14 14:07:50 +0000483 if ((fd = drmOpenMinor(0, 1, DRM_NODE_PRIMARY)) < 0) {
Alan Hourihaneb0a92852003-09-24 14:39:25 +0000484#ifdef __linux__
Adam Jackson22e41ef2006-02-20 23:09:00 +0000485 /* Try proc for backward Linux compatibility */
Brianccd7b6e2007-05-29 14:54:00 -0600486 if (!access("/proc/dri/0", R_OK))
487 return 1;
Alan Hourihaneb0a92852003-09-24 14:39:25 +0000488#endif
Rik Faith88dbee52001-02-28 09:27:44 +0000489 return 0;
Brian Paul569da5a2000-06-08 14:38:22 +0000490 }
Rik Faith88dbee52001-02-28 09:27:44 +0000491
492 if ((version = drmGetVersion(fd))) {
493 retval = 1;
494 drmFreeVersion(version);
495 }
496 close(fd);
Brian Paul569da5a2000-06-08 14:38:22 +0000497
498 return retval;
499}
500
Jammy Zhouf1adc4b2015-02-11 12:40:51 +0800501static int drmGetMinorBase(int type)
502{
503 switch (type) {
504 case DRM_NODE_PRIMARY:
505 return 0;
506 case DRM_NODE_CONTROL:
507 return 64;
508 case DRM_NODE_RENDER:
509 return 128;
510 default:
511 return -1;
512 };
513}
Jose Fonsecad2443b22003-05-27 00:37:33 +0000514
Frank Binns1f735782015-02-13 10:51:15 +0000515static int drmGetMinorType(int minor)
516{
517 int type = minor >> 6;
518
519 if (minor < 0)
520 return -1;
521
522 switch (type) {
523 case DRM_NODE_PRIMARY:
524 case DRM_NODE_CONTROL:
525 case DRM_NODE_RENDER:
526 return type;
527 default:
528 return -1;
529 }
530}
531
Emil Velikov0ca03a42015-03-07 00:58:39 +0000532static const char *drmGetMinorName(int type)
533{
534 switch (type) {
535 case DRM_NODE_PRIMARY:
Jonathan Grayfc083322015-07-21 03:12:56 +1000536 return DRM_PRIMARY_MINOR_NAME;
Emil Velikov0ca03a42015-03-07 00:58:39 +0000537 case DRM_NODE_CONTROL:
Jonathan Grayfc083322015-07-21 03:12:56 +1000538 return DRM_CONTROL_MINOR_NAME;
Emil Velikov0ca03a42015-03-07 00:58:39 +0000539 case DRM_NODE_RENDER:
Jonathan Grayfc083322015-07-21 03:12:56 +1000540 return DRM_RENDER_MINOR_NAME;
Emil Velikov0ca03a42015-03-07 00:58:39 +0000541 default:
542 return NULL;
543 }
544}
545
Jose Fonsecad2443b22003-05-27 00:37:33 +0000546/**
547 * Open the device by bus ID.
548 *
549 * \param busid bus ID.
Jammy Zhouf1adc4b2015-02-11 12:40:51 +0800550 * \param type device node type.
Jose Fonsecad2443b22003-05-27 00:37:33 +0000551 *
552 * \return a file descriptor on success, or a negative value on error.
553 *
554 * \internal
555 * This function attempts to open every possible minor (up to DRM_MAX_MINOR),
556 * comparing the device bus ID with the one supplied.
557 *
558 * \sa drmOpenMinor() and drmGetBusid().
559 */
Jammy Zhouf1adc4b2015-02-11 12:40:51 +0800560static int drmOpenByBusid(const char *busid, int type)
Daryll Strausse1dba5c1999-12-07 03:37:16 +0000561{
Benjamin Herrenschmidtb04515c2010-08-06 13:55:11 +1000562 int i, pci_domain_ok = 1;
Rik Faith88dbee52001-02-28 09:27:44 +0000563 int fd;
564 const char *buf;
Eric Anholt06cb1322003-10-23 02:23:31 +0000565 drmSetVersion sv;
Jammy Zhouf1adc4b2015-02-11 12:40:51 +0800566 int base = drmGetMinorBase(type);
567
568 if (base < 0)
569 return -1;
Eric Anholt06cb1322003-10-23 02:23:31 +0000570
571 drmMsg("drmOpenByBusid: Searching for BusID %s\n", busid);
Jammy Zhouf1adc4b2015-02-11 12:40:51 +0800572 for (i = base; i < base + DRM_MAX_MINOR; i++) {
573 fd = drmOpenMinor(i, 1, type);
David Dawes56bd9c22001-07-30 19:59:39 +0000574 drmMsg("drmOpenByBusid: drmOpenMinor returns %d\n", fd);
575 if (fd >= 0) {
Benjamin Herrenschmidtb04515c2010-08-06 13:55:11 +1000576 /* We need to try for 1.4 first for proper PCI domain support
577 * and if that fails, we know the kernel is busted
578 */
Eric Anholt06cb1322003-10-23 02:23:31 +0000579 sv.drm_di_major = 1;
Benjamin Herrenschmidtb04515c2010-08-06 13:55:11 +1000580 sv.drm_di_minor = 4;
Eric Anholt06cb1322003-10-23 02:23:31 +0000581 sv.drm_dd_major = -1; /* Don't care */
Eric Anholt26462b92005-12-31 11:48:12 +0000582 sv.drm_dd_minor = -1; /* Don't care */
Benjamin Herrenschmidtb04515c2010-08-06 13:55:11 +1000583 if (drmSetInterfaceVersion(fd, &sv)) {
584#ifndef __alpha__
585 pci_domain_ok = 0;
586#endif
587 sv.drm_di_major = 1;
588 sv.drm_di_minor = 1;
589 sv.drm_dd_major = -1; /* Don't care */
590 sv.drm_dd_minor = -1; /* Don't care */
Thierry Reding303ff262014-04-08 22:33:04 +0200591 drmMsg("drmOpenByBusid: Interface 1.4 failed, trying 1.1\n");
Benjamin Herrenschmidtb04515c2010-08-06 13:55:11 +1000592 drmSetInterfaceVersion(fd, &sv);
593 }
Daryll Strausse1dba5c1999-12-07 03:37:16 +0000594 buf = drmGetBusid(fd);
David Dawes56bd9c22001-07-30 19:59:39 +0000595 drmMsg("drmOpenByBusid: drmGetBusid reports %s\n", buf);
Benjamin Herrenschmidtb04515c2010-08-06 13:55:11 +1000596 if (buf && drmMatchBusID(buf, busid, pci_domain_ok)) {
Rik Faith88dbee52001-02-28 09:27:44 +0000597 drmFreeBusid(buf);
598 return fd;
Daryll Strausse1dba5c1999-12-07 03:37:16 +0000599 }
Brianccd7b6e2007-05-29 14:54:00 -0600600 if (buf)
601 drmFreeBusid(buf);
Daryll Strausse1dba5c1999-12-07 03:37:16 +0000602 close(fd);
603 }
604 }
605 return -1;
606}
607
Jose Fonsecad2443b22003-05-27 00:37:33 +0000608
609/**
610 * Open the device by name.
611 *
612 * \param name driver name.
Jammy Zhouf1adc4b2015-02-11 12:40:51 +0800613 * \param type the device node type.
Jose Fonsecad2443b22003-05-27 00:37:33 +0000614 *
615 * \return a file descriptor on success, or a negative value on error.
616 *
617 * \internal
618 * This function opens the first minor number that matches the driver name and
619 * isn't already in use. If it's in use it then it will already have a bus ID
620 * assigned.
621 *
622 * \sa drmOpenMinor(), drmGetVersion() and drmGetBusid().
623 */
Jammy Zhouf1adc4b2015-02-11 12:40:51 +0800624static int drmOpenByName(const char *name, int type)
Daryll Straussb3a57661999-12-05 01:19:48 +0000625{
Rik Faith88dbee52001-02-28 09:27:44 +0000626 int i;
627 int fd;
628 drmVersionPtr version;
David Dawes56bd9c22001-07-30 19:59:39 +0000629 char * id;
Jammy Zhouf1adc4b2015-02-11 12:40:51 +0800630 int base = drmGetMinorBase(type);
631
632 if (base < 0)
633 return -1;
Dave Airliedb85ed22008-02-13 12:20:02 +1000634
David Dawes56bd9c22001-07-30 19:59:39 +0000635 /*
636 * Open the first minor number that matches the driver name and isn't
637 * already in use. If it's in use it will have a busid assigned already.
638 */
Jammy Zhouf1adc4b2015-02-11 12:40:51 +0800639 for (i = base; i < base + DRM_MAX_MINOR; i++) {
640 if ((fd = drmOpenMinor(i, 1, type)) >= 0) {
Rik Faith88dbee52001-02-28 09:27:44 +0000641 if ((version = drmGetVersion(fd))) {
642 if (!strcmp(version->name, name)) {
643 drmFreeVersion(version);
David Dawes56bd9c22001-07-30 19:59:39 +0000644 id = drmGetBusid(fd);
645 drmMsg("drmGetBusid returned '%s'\n", id ? id : "NULL");
646 if (!id || !*id) {
Adam Jackson22e41ef2006-02-20 23:09:00 +0000647 if (id)
David Dawes56bd9c22001-07-30 19:59:39 +0000648 drmFreeBusid(id);
David Dawes56bd9c22001-07-30 19:59:39 +0000649 return fd;
650 } else {
651 drmFreeBusid(id);
652 }
653 } else {
654 drmFreeVersion(version);
Rik Faith88dbee52001-02-28 09:27:44 +0000655 }
Rik Faith88dbee52001-02-28 09:27:44 +0000656 }
David Dawes56bd9c22001-07-30 19:59:39 +0000657 close(fd);
Rik Faith88dbee52001-02-28 09:27:44 +0000658 }
659 }
660
661#ifdef __linux__
Adam Jackson22e41ef2006-02-20 23:09:00 +0000662 /* Backward-compatibility /proc support */
Daryll Straussb6a28bf1999-12-05 23:10:37 +0000663 for (i = 0; i < 8; i++) {
Rik Faith88dbee52001-02-28 09:27:44 +0000664 char proc_name[64], buf[512];
665 char *driver, *pt, *devstring;
666 int retcode;
667
Daryll Strauss0371c291999-12-18 18:34:59 +0000668 sprintf(proc_name, "/proc/dri/%d/name", i);
Daryll Straussb6a28bf1999-12-05 23:10:37 +0000669 if ((fd = open(proc_name, 0, 0)) >= 0) {
670 retcode = read(fd, buf, sizeof(buf)-1);
671 close(fd);
672 if (retcode) {
673 buf[retcode-1] = '\0';
674 for (driver = pt = buf; *pt && *pt != ' '; ++pt)
675 ;
Adam Jackson22e41ef2006-02-20 23:09:00 +0000676 if (*pt) { /* Device is next */
Daryll Straussb6a28bf1999-12-05 23:10:37 +0000677 *pt = '\0';
678 if (!strcmp(driver, name)) { /* Match */
679 for (devstring = ++pt; *pt && *pt != ' '; ++pt)
680 ;
681 if (*pt) { /* Found busid */
Jammy Zhouf1adc4b2015-02-11 12:40:51 +0800682 return drmOpenByBusid(++pt, type);
Adam Jackson22e41ef2006-02-20 23:09:00 +0000683 } else { /* No busid */
Jammy Zhouf1adc4b2015-02-11 12:40:51 +0800684 return drmOpenDevice(strtol(devstring, NULL, 0),i, type);
Daryll Straussb6a28bf1999-12-05 23:10:37 +0000685 }
686 }
687 }
688 }
Brian Paul569da5a2000-06-08 14:38:22 +0000689 }
Daryll Straussb6a28bf1999-12-05 23:10:37 +0000690 }
Rik Faith88dbee52001-02-28 09:27:44 +0000691#endif
692
Daryll Straussb6a28bf1999-12-05 23:10:37 +0000693 return -1;
694}
695
Daryll Straussb6a28bf1999-12-05 23:10:37 +0000696
Jose Fonsecad2443b22003-05-27 00:37:33 +0000697/**
698 * Open the DRM device.
699 *
700 * Looks up the specified name and bus ID, and opens the device found. The
701 * entry in /dev/dri is created if necessary and if called by root.
702 *
703 * \param name driver name. Not referenced if bus ID is supplied.
704 * \param busid bus ID. Zero if not known.
705 *
706 * \return a file descriptor on success, or a negative value on error.
707 *
708 * \internal
709 * It calls drmOpenByBusid() if \p busid is specified or drmOpenByName()
710 * otherwise.
711 */
Daryll Straussb6a28bf1999-12-05 23:10:37 +0000712int drmOpen(const char *name, const char *busid)
Daryll Straussb3a57661999-12-05 01:19:48 +0000713{
Jammy Zhouf1adc4b2015-02-11 12:40:51 +0800714 return drmOpenWithType(name, busid, DRM_NODE_PRIMARY);
715}
716
717/**
718 * Open the DRM device with specified type.
719 *
720 * Looks up the specified name and bus ID, and opens the device found. The
721 * entry in /dev/dri is created if necessary and if called by root.
722 *
723 * \param name driver name. Not referenced if bus ID is supplied.
724 * \param busid bus ID. Zero if not known.
725 * \param type the device node type to open, PRIMARY, CONTROL or RENDER
726 *
727 * \return a file descriptor on success, or a negative value on error.
728 *
729 * \internal
730 * It calls drmOpenByBusid() if \p busid is specified or drmOpenByName()
731 * otherwise.
732 */
733int drmOpenWithType(const char *name, const char *busid, int type)
734{
Rob Clarkeb7c2d52015-09-04 08:08:02 -0400735 if (!drmAvailable() && name != NULL && drm_server_info &&
736 drm_server_info->load_module) {
Jammy Zhouf1adc4b2015-02-11 12:40:51 +0800737 /* try to load the kernel module */
Dave Airlie79038752006-11-08 15:08:09 +1100738 if (!drm_server_info->load_module(name)) {
Brianccd7b6e2007-05-29 14:54:00 -0600739 drmMsg("[drm] failed to load kernel module \"%s\"\n", name);
Eric Anholt06cb1322003-10-23 02:23:31 +0000740 return -1;
741 }
742 }
Daryll Straussb6a28bf1999-12-05 23:10:37 +0000743
Eric Anholt06cb1322003-10-23 02:23:31 +0000744 if (busid) {
Jammy Zhouf1adc4b2015-02-11 12:40:51 +0800745 int fd = drmOpenByBusid(busid, type);
Eric Anholt06cb1322003-10-23 02:23:31 +0000746 if (fd >= 0)
747 return fd;
748 }
Adam Jackson22e41ef2006-02-20 23:09:00 +0000749
Eric Anholt06cb1322003-10-23 02:23:31 +0000750 if (name)
Jammy Zhouf1adc4b2015-02-11 12:40:51 +0800751 return drmOpenByName(name, type);
Adam Jackson22e41ef2006-02-20 23:09:00 +0000752
Eric Anholt06cb1322003-10-23 02:23:31 +0000753 return -1;
Daryll Straussb3a57661999-12-05 01:19:48 +0000754}
755
Jesse Barnes731cd552008-12-17 10:09:49 -0800756int drmOpenControl(int minor)
757{
758 return drmOpenMinor(minor, 0, DRM_NODE_CONTROL);
759}
Jose Fonsecad2443b22003-05-27 00:37:33 +0000760
Frank Binns0c5aaee2015-01-14 14:07:51 +0000761int drmOpenRender(int minor)
762{
763 return drmOpenMinor(minor, 0, DRM_NODE_RENDER);
764}
765
Jose Fonsecad2443b22003-05-27 00:37:33 +0000766/**
767 * Free the version information returned by drmGetVersion().
768 *
769 * \param v pointer to the version information.
770 *
771 * \internal
772 * It frees the memory pointed by \p %v as well as all the non-null strings
773 * pointers in it.
774 */
Daryll Straussb3a57661999-12-05 01:19:48 +0000775void drmFreeVersion(drmVersionPtr v)
776{
Brianccd7b6e2007-05-29 14:54:00 -0600777 if (!v)
778 return;
Jakob Bornecrantz9d8ba2d2007-02-25 10:48:26 +1100779 drmFree(v->name);
780 drmFree(v->date);
781 drmFree(v->desc);
Daryll Straussb3a57661999-12-05 01:19:48 +0000782 drmFree(v);
783}
784
Jose Fonsecad2443b22003-05-27 00:37:33 +0000785
786/**
787 * Free the non-public version information returned by the kernel.
788 *
789 * \param v pointer to the version information.
790 *
791 * \internal
792 * Used by drmGetVersion() to free the memory pointed by \p %v as well as all
793 * the non-null strings pointers in it.
794 */
Daryll Straussb3a57661999-12-05 01:19:48 +0000795static void drmFreeKernelVersion(drm_version_t *v)
796{
Brianccd7b6e2007-05-29 14:54:00 -0600797 if (!v)
798 return;
Jakob Bornecrantz9d8ba2d2007-02-25 10:48:26 +1100799 drmFree(v->name);
800 drmFree(v->date);
801 drmFree(v->desc);
Daryll Straussb3a57661999-12-05 01:19:48 +0000802 drmFree(v);
803}
804
Jose Fonsecad2443b22003-05-27 00:37:33 +0000805
806/**
807 * Copy version information.
808 *
809 * \param d destination pointer.
810 * \param s source pointer.
811 *
812 * \internal
813 * Used by drmGetVersion() to translate the information returned by the ioctl
814 * interface in a private structure into the public structure counterpart.
815 */
Brian Paul569da5a2000-06-08 14:38:22 +0000816static void drmCopyVersion(drmVersionPtr d, const drm_version_t *s)
Daryll Straussb3a57661999-12-05 01:19:48 +0000817{
818 d->version_major = s->version_major;
819 d->version_minor = s->version_minor;
820 d->version_patchlevel = s->version_patchlevel;
821 d->name_len = s->name_len;
Adam Jackson0a1ff352010-10-27 18:44:53 -0400822 d->name = strdup(s->name);
Daryll Straussb3a57661999-12-05 01:19:48 +0000823 d->date_len = s->date_len;
Adam Jackson0a1ff352010-10-27 18:44:53 -0400824 d->date = strdup(s->date);
Daryll Straussb3a57661999-12-05 01:19:48 +0000825 d->desc_len = s->desc_len;
Adam Jackson0a1ff352010-10-27 18:44:53 -0400826 d->desc = strdup(s->desc);
Daryll Straussb3a57661999-12-05 01:19:48 +0000827}
828
Daryll Straussb3a57661999-12-05 01:19:48 +0000829
Jose Fonsecad2443b22003-05-27 00:37:33 +0000830/**
831 * Query the driver version information.
832 *
833 * \param fd file descriptor.
834 *
835 * \return pointer to a drmVersion structure which should be freed with
836 * drmFreeVersion().
837 *
838 * \note Similar information is available via /proc/dri.
839 *
840 * \internal
841 * It gets the version information via successive DRM_IOCTL_VERSION ioctls,
842 * first with zeros to get the string lengths, and then the actually strings.
843 * It also null-terminates them since they might not be already.
844 */
Daryll Straussb3a57661999-12-05 01:19:48 +0000845drmVersionPtr drmGetVersion(int fd)
846{
847 drmVersionPtr retval;
848 drm_version_t *version = drmMalloc(sizeof(*version));
849
Daniel Vetter95f23cf2015-02-11 17:25:30 +0100850 memclear(*version);
Gareth Hughes36047532001-02-15 08:12:14 +0000851
Keith Packard8b9ab102008-06-13 16:03:22 -0700852 if (drmIoctl(fd, DRM_IOCTL_VERSION, version)) {
Daryll Straussb3a57661999-12-05 01:19:48 +0000853 drmFreeKernelVersion(version);
854 return NULL;
855 }
856
Daryll Straussb3a57661999-12-05 01:19:48 +0000857 if (version->name_len)
858 version->name = drmMalloc(version->name_len + 1);
859 if (version->date_len)
860 version->date = drmMalloc(version->date_len + 1);
861 if (version->desc_len)
862 version->desc = drmMalloc(version->desc_len + 1);
Gareth Hughes36047532001-02-15 08:12:14 +0000863
Keith Packard8b9ab102008-06-13 16:03:22 -0700864 if (drmIoctl(fd, DRM_IOCTL_VERSION, version)) {
Alan Hourihaneb0a92852003-09-24 14:39:25 +0000865 drmMsg("DRM_IOCTL_VERSION: %s\n", strerror(errno));
Daryll Straussb3a57661999-12-05 01:19:48 +0000866 drmFreeKernelVersion(version);
867 return NULL;
868 }
869
Adam Jackson22e41ef2006-02-20 23:09:00 +0000870 /* The results might not be null-terminated strings, so terminate them. */
Daryll Straussb3a57661999-12-05 01:19:48 +0000871 if (version->name_len) version->name[version->name_len] = '\0';
872 if (version->date_len) version->date[version->date_len] = '\0';
873 if (version->desc_len) version->desc[version->desc_len] = '\0';
874
Daryll Straussb3a57661999-12-05 01:19:48 +0000875 retval = drmMalloc(sizeof(*retval));
876 drmCopyVersion(retval, version);
877 drmFreeKernelVersion(version);
878 return retval;
879}
880
Jens Owen3903e5a2002-04-09 21:54:56 +0000881
Jose Fonsecad2443b22003-05-27 00:37:33 +0000882/**
883 * Get version information for the DRM user space library.
884 *
885 * This version number is driver independent.
886 *
887 * \param fd file descriptor.
888 *
889 * \return version information.
890 *
891 * \internal
892 * This function allocates and fills a drm_version structure with a hard coded
893 * version number.
894 */
Jens Owen3903e5a2002-04-09 21:54:56 +0000895drmVersionPtr drmGetLibVersion(int fd)
896{
897 drm_version_t *version = drmMalloc(sizeof(*version));
898
899 /* Version history:
Dave Airlie79038752006-11-08 15:08:09 +1100900 * NOTE THIS MUST NOT GO ABOVE VERSION 1.X due to drivers needing it
Jens Owen3903e5a2002-04-09 21:54:56 +0000901 * revision 1.0.x = original DRM interface with no drmGetLibVersion
902 * entry point and many drm<Device> extensions
903 * revision 1.1.x = added drmCommand entry points for device extensions
904 * added drmGetLibVersion to identify libdrm.a version
Eric Anholt06cb1322003-10-23 02:23:31 +0000905 * revision 1.2.x = added drmSetInterfaceVersion
906 * modified drmOpen to handle both busid and name
Dave Airlie79038752006-11-08 15:08:09 +1100907 * revision 1.3.x = added server + memory manager
Jens Owen3903e5a2002-04-09 21:54:56 +0000908 */
Dave Airlie79038752006-11-08 15:08:09 +1100909 version->version_major = 1;
910 version->version_minor = 3;
Jens Owen3903e5a2002-04-09 21:54:56 +0000911 version->version_patchlevel = 0;
912
913 return (drmVersionPtr)version;
914}
915
Ben Skeggs5c6c6912011-02-21 11:27:19 +1000916int drmGetCap(int fd, uint64_t capability, uint64_t *value)
917{
Daniel Vetterfd387942015-02-11 12:41:04 +0100918 struct drm_get_cap cap;
Ben Skeggs5c6c6912011-02-21 11:27:19 +1000919 int ret;
920
Daniel Vetterfd387942015-02-11 12:41:04 +0100921 memclear(cap);
922 cap.capability = capability;
923
Ben Skeggs5c6c6912011-02-21 11:27:19 +1000924 ret = drmIoctl(fd, DRM_IOCTL_GET_CAP, &cap);
925 if (ret)
926 return ret;
927
928 *value = cap.value;
Dave Airlie3b04c732011-03-04 15:48:31 +1000929 return 0;
Ben Skeggs5c6c6912011-02-21 11:27:19 +1000930}
Jose Fonsecad2443b22003-05-27 00:37:33 +0000931
Damien Lespiauddbbdb12013-09-03 15:34:41 +0100932int drmSetClientCap(int fd, uint64_t capability, uint64_t value)
933{
Daniel Vetterfd387942015-02-11 12:41:04 +0100934 struct drm_set_client_cap cap;
935
936 memclear(cap);
937 cap.capability = capability;
938 cap.value = value;
Damien Lespiauddbbdb12013-09-03 15:34:41 +0100939
940 return drmIoctl(fd, DRM_IOCTL_SET_CLIENT_CAP, &cap);
941}
942
Jose Fonsecad2443b22003-05-27 00:37:33 +0000943/**
944 * Free the bus ID information.
945 *
946 * \param busid bus ID information string as given by drmGetBusid().
947 *
948 * \internal
949 * This function is just frees the memory pointed by \p busid.
950 */
Daryll Straussb6a28bf1999-12-05 23:10:37 +0000951void drmFreeBusid(const char *busid)
Daryll Straussb3a57661999-12-05 01:19:48 +0000952{
Daryll Straussb6a28bf1999-12-05 23:10:37 +0000953 drmFree((void *)busid);
Daryll Straussb3a57661999-12-05 01:19:48 +0000954}
955
Jose Fonsecad2443b22003-05-27 00:37:33 +0000956
957/**
958 * Get the bus ID of the device.
959 *
960 * \param fd file descriptor.
961 *
962 * \return bus ID string.
963 *
964 * \internal
965 * This function gets the bus ID via successive DRM_IOCTL_GET_UNIQUE ioctls to
966 * get the string length and data, passing the arguments in a drm_unique
967 * structure.
968 */
Daryll Straussb6a28bf1999-12-05 23:10:37 +0000969char *drmGetBusid(int fd)
Daryll Straussb3a57661999-12-05 01:19:48 +0000970{
Daryll Straussb6a28bf1999-12-05 23:10:37 +0000971 drm_unique_t u;
972
Daniel Vetterfd387942015-02-11 12:41:04 +0100973 memclear(u);
Daryll Straussb6a28bf1999-12-05 23:10:37 +0000974
Keith Packard8b9ab102008-06-13 16:03:22 -0700975 if (drmIoctl(fd, DRM_IOCTL_GET_UNIQUE, &u))
Brianccd7b6e2007-05-29 14:54:00 -0600976 return NULL;
Daryll Straussb6a28bf1999-12-05 23:10:37 +0000977 u.unique = drmMalloc(u.unique_len + 1);
Keith Packard8b9ab102008-06-13 16:03:22 -0700978 if (drmIoctl(fd, DRM_IOCTL_GET_UNIQUE, &u))
Brianccd7b6e2007-05-29 14:54:00 -0600979 return NULL;
Daryll Straussb6a28bf1999-12-05 23:10:37 +0000980 u.unique[u.unique_len] = '\0';
Eric Anholt06cb1322003-10-23 02:23:31 +0000981
Daryll Straussb6a28bf1999-12-05 23:10:37 +0000982 return u.unique;
Daryll Straussb3a57661999-12-05 01:19:48 +0000983}
984
Jose Fonsecad2443b22003-05-27 00:37:33 +0000985
986/**
987 * Set the bus ID of the device.
988 *
989 * \param fd file descriptor.
990 * \param busid bus ID string.
991 *
992 * \return zero on success, negative on failure.
993 *
994 * \internal
995 * This function is a wrapper around the DRM_IOCTL_SET_UNIQUE ioctl, passing
996 * the arguments in a drm_unique structure.
997 */
Daryll Straussb6a28bf1999-12-05 23:10:37 +0000998int drmSetBusid(int fd, const char *busid)
Daryll Straussb3a57661999-12-05 01:19:48 +0000999{
Daryll Straussb6a28bf1999-12-05 23:10:37 +00001000 drm_unique_t u;
Daryll Straussb3a57661999-12-05 01:19:48 +00001001
Daniel Vetterfd387942015-02-11 12:41:04 +01001002 memclear(u);
Daryll Straussb6a28bf1999-12-05 23:10:37 +00001003 u.unique = (char *)busid;
1004 u.unique_len = strlen(busid);
Daryll Straussb3a57661999-12-05 01:19:48 +00001005
Keith Packard8b9ab102008-06-13 16:03:22 -07001006 if (drmIoctl(fd, DRM_IOCTL_SET_UNIQUE, &u)) {
David Dawes56bd9c22001-07-30 19:59:39 +00001007 return -errno;
1008 }
Daryll Straussb3a57661999-12-05 01:19:48 +00001009 return 0;
1010}
1011
Jon Smirl8696e712004-07-07 04:36:36 +00001012int drmGetMagic(int fd, drm_magic_t * magic)
Daryll Straussb3a57661999-12-05 01:19:48 +00001013{
1014 drm_auth_t auth;
1015
Daniel Vetterfd387942015-02-11 12:41:04 +01001016 memclear(auth);
1017
Daryll Straussb3a57661999-12-05 01:19:48 +00001018 *magic = 0;
Keith Packard8b9ab102008-06-13 16:03:22 -07001019 if (drmIoctl(fd, DRM_IOCTL_GET_MAGIC, &auth))
Brianccd7b6e2007-05-29 14:54:00 -06001020 return -errno;
Daryll Straussb3a57661999-12-05 01:19:48 +00001021 *magic = auth.magic;
1022 return 0;
1023}
1024
Jon Smirl8696e712004-07-07 04:36:36 +00001025int drmAuthMagic(int fd, drm_magic_t magic)
Daryll Straussb3a57661999-12-05 01:19:48 +00001026{
1027 drm_auth_t auth;
1028
Daniel Vetterfd387942015-02-11 12:41:04 +01001029 memclear(auth);
Daryll Straussb3a57661999-12-05 01:19:48 +00001030 auth.magic = magic;
Keith Packard8b9ab102008-06-13 16:03:22 -07001031 if (drmIoctl(fd, DRM_IOCTL_AUTH_MAGIC, &auth))
Brianccd7b6e2007-05-29 14:54:00 -06001032 return -errno;
Daryll Straussb3a57661999-12-05 01:19:48 +00001033 return 0;
1034}
1035
Jose Fonsecad2443b22003-05-27 00:37:33 +00001036/**
1037 * Specifies a range of memory that is available for mapping by a
1038 * non-root process.
1039 *
1040 * \param fd file descriptor.
1041 * \param offset usually the physical address. The actual meaning depends of
1042 * the \p type parameter. See below.
1043 * \param size of the memory in bytes.
1044 * \param type type of the memory to be mapped.
1045 * \param flags combination of several flags to modify the function actions.
1046 * \param handle will be set to a value that may be used as the offset
1047 * parameter for mmap().
1048 *
1049 * \return zero on success or a negative value on error.
1050 *
1051 * \par Mapping the frame buffer
1052 * For the frame buffer
1053 * - \p offset will be the physical address of the start of the frame buffer,
1054 * - \p size will be the size of the frame buffer in bytes, and
1055 * - \p type will be DRM_FRAME_BUFFER.
1056 *
1057 * \par
1058 * The area mapped will be uncached. If MTRR support is available in the
1059 * kernel, the frame buffer area will be set to write combining.
1060 *
1061 * \par Mapping the MMIO register area
1062 * For the MMIO register area,
1063 * - \p offset will be the physical address of the start of the register area,
1064 * - \p size will be the size of the register area bytes, and
1065 * - \p type will be DRM_REGISTERS.
1066 * \par
1067 * The area mapped will be uncached.
1068 *
1069 * \par Mapping the SAREA
1070 * For the SAREA,
1071 * - \p offset will be ignored and should be set to zero,
1072 * - \p size will be the desired size of the SAREA in bytes,
1073 * - \p type will be DRM_SHM.
1074 *
1075 * \par
1076 * A shared memory area of the requested size will be created and locked in
1077 * kernel memory. This area may be mapped into client-space by using the handle
1078 * returned.
1079 *
1080 * \note May only be called by root.
1081 *
1082 * \internal
1083 * This function is a wrapper around the DRM_IOCTL_ADD_MAP ioctl, passing
1084 * the arguments in a drm_map structure.
1085 */
Adam Jackson22e41ef2006-02-20 23:09:00 +00001086int drmAddMap(int fd, drm_handle_t offset, drmSize size, drmMapType type,
1087 drmMapFlags flags, drm_handle_t *handle)
Daryll Straussb3a57661999-12-05 01:19:48 +00001088{
1089 drm_map_t map;
1090
Daniel Vetterfd387942015-02-11 12:41:04 +01001091 memclear(map);
Daryll Straussb3a57661999-12-05 01:19:48 +00001092 map.offset = offset;
1093 map.size = size;
Daryll Straussb3a57661999-12-05 01:19:48 +00001094 map.type = type;
1095 map.flags = flags;
Keith Packard8b9ab102008-06-13 16:03:22 -07001096 if (drmIoctl(fd, DRM_IOCTL_ADD_MAP, &map))
Brianccd7b6e2007-05-29 14:54:00 -06001097 return -errno;
1098 if (handle)
Jeremy Huddleston961bf9b2011-11-01 14:42:13 -07001099 *handle = (drm_handle_t)(uintptr_t)map.handle;
Daryll Straussb3a57661999-12-05 01:19:48 +00001100 return 0;
1101}
1102
Jon Smirl8696e712004-07-07 04:36:36 +00001103int drmRmMap(int fd, drm_handle_t handle)
Kevin E Martin74e19a42001-03-14 22:22:50 +00001104{
1105 drm_map_t map;
1106
Daniel Vetterfd387942015-02-11 12:41:04 +01001107 memclear(map);
Jeremy Huddleston961bf9b2011-11-01 14:42:13 -07001108 map.handle = (void *)(uintptr_t)handle;
Kevin E Martin74e19a42001-03-14 22:22:50 +00001109
Keith Packard8b9ab102008-06-13 16:03:22 -07001110 if(drmIoctl(fd, DRM_IOCTL_RM_MAP, &map))
Brianccd7b6e2007-05-29 14:54:00 -06001111 return -errno;
Kevin E Martin74e19a42001-03-14 22:22:50 +00001112 return 0;
1113}
1114
Jose Fonsecad2443b22003-05-27 00:37:33 +00001115/**
1116 * Make buffers available for DMA transfers.
1117 *
1118 * \param fd file descriptor.
1119 * \param count number of buffers.
1120 * \param size size of each buffer.
1121 * \param flags buffer allocation flags.
1122 * \param agp_offset offset in the AGP aperture
1123 *
1124 * \return number of buffers allocated, negative on error.
1125 *
1126 * \internal
1127 * This function is a wrapper around DRM_IOCTL_ADD_BUFS ioctl.
1128 *
1129 * \sa drm_buf_desc.
1130 */
Jeff Hartmannba1b1ae2000-04-04 22:08:14 +00001131int drmAddBufs(int fd, int count, int size, drmBufDescFlags flags,
1132 int agp_offset)
Daryll Straussb3a57661999-12-05 01:19:48 +00001133{
1134 drm_buf_desc_t request;
Gareth Hughes36047532001-02-15 08:12:14 +00001135
Daniel Vetterfd387942015-02-11 12:41:04 +01001136 memclear(request);
Daryll Straussb3a57661999-12-05 01:19:48 +00001137 request.count = count;
1138 request.size = size;
Daryll Straussb3a57661999-12-05 01:19:48 +00001139 request.flags = flags;
Jeff Hartmannba1b1ae2000-04-04 22:08:14 +00001140 request.agp_start = agp_offset;
Gareth Hughes36047532001-02-15 08:12:14 +00001141
Keith Packard8b9ab102008-06-13 16:03:22 -07001142 if (drmIoctl(fd, DRM_IOCTL_ADD_BUFS, &request))
Brianccd7b6e2007-05-29 14:54:00 -06001143 return -errno;
Daryll Straussb3a57661999-12-05 01:19:48 +00001144 return request.count;
1145}
1146
1147int drmMarkBufs(int fd, double low, double high)
1148{
1149 drm_buf_info_t info;
1150 int i;
1151
Daniel Vetterfd387942015-02-11 12:41:04 +01001152 memclear(info);
Daryll Straussb3a57661999-12-05 01:19:48 +00001153
Keith Packard8b9ab102008-06-13 16:03:22 -07001154 if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info))
Brianccd7b6e2007-05-29 14:54:00 -06001155 return -EINVAL;
Daryll Straussb3a57661999-12-05 01:19:48 +00001156
Brianccd7b6e2007-05-29 14:54:00 -06001157 if (!info.count)
1158 return -EINVAL;
Gareth Hughes36047532001-02-15 08:12:14 +00001159
Daryll Straussb3a57661999-12-05 01:19:48 +00001160 if (!(info.list = drmMalloc(info.count * sizeof(*info.list))))
1161 return -ENOMEM;
Gareth Hughes36047532001-02-15 08:12:14 +00001162
Keith Packard8b9ab102008-06-13 16:03:22 -07001163 if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info)) {
Daryll Straussb3a57661999-12-05 01:19:48 +00001164 int retval = -errno;
1165 drmFree(info.list);
1166 return retval;
1167 }
Gareth Hughes36047532001-02-15 08:12:14 +00001168
Daryll Straussb3a57661999-12-05 01:19:48 +00001169 for (i = 0; i < info.count; i++) {
1170 info.list[i].low_mark = low * info.list[i].count;
1171 info.list[i].high_mark = high * info.list[i].count;
Keith Packard8b9ab102008-06-13 16:03:22 -07001172 if (drmIoctl(fd, DRM_IOCTL_MARK_BUFS, &info.list[i])) {
Daryll Straussb3a57661999-12-05 01:19:48 +00001173 int retval = -errno;
1174 drmFree(info.list);
1175 return retval;
1176 }
1177 }
1178 drmFree(info.list);
Gareth Hughes36047532001-02-15 08:12:14 +00001179
Daryll Straussb3a57661999-12-05 01:19:48 +00001180 return 0;
1181}
1182
Jose Fonsecad2443b22003-05-27 00:37:33 +00001183/**
1184 * Free buffers.
1185 *
1186 * \param fd file descriptor.
1187 * \param count number of buffers to free.
1188 * \param list list of buffers to be freed.
1189 *
1190 * \return zero on success, or a negative value on failure.
1191 *
1192 * \note This function is primarily used for debugging.
1193 *
1194 * \internal
1195 * This function is a wrapper around the DRM_IOCTL_FREE_BUFS ioctl, passing
1196 * the arguments in a drm_buf_free structure.
1197 */
Daryll Straussb3a57661999-12-05 01:19:48 +00001198int drmFreeBufs(int fd, int count, int *list)
1199{
1200 drm_buf_free_t request;
1201
Daniel Vetterfd387942015-02-11 12:41:04 +01001202 memclear(request);
Daryll Straussb3a57661999-12-05 01:19:48 +00001203 request.count = count;
1204 request.list = list;
Keith Packard8b9ab102008-06-13 16:03:22 -07001205 if (drmIoctl(fd, DRM_IOCTL_FREE_BUFS, &request))
Brianccd7b6e2007-05-29 14:54:00 -06001206 return -errno;
Daryll Straussb3a57661999-12-05 01:19:48 +00001207 return 0;
1208}
1209
Jose Fonsecad2443b22003-05-27 00:37:33 +00001210
1211/**
1212 * Close the device.
1213 *
1214 * \param fd file descriptor.
1215 *
1216 * \internal
1217 * This function closes the file descriptor.
1218 */
Daryll Straussb6a28bf1999-12-05 23:10:37 +00001219int drmClose(int fd)
Daryll Straussb3a57661999-12-05 01:19:48 +00001220{
1221 unsigned long key = drmGetKeyFromFd(fd);
1222 drmHashEntry *entry = drmGetEntry(fd);
1223
1224 drmHashDestroy(entry->tagTable);
1225 entry->fd = 0;
1226 entry->f = NULL;
1227 entry->tagTable = NULL;
1228
1229 drmHashDelete(drmHashTable, key);
1230 drmFree(entry);
1231
1232 return close(fd);
1233}
1234
Jose Fonsecad2443b22003-05-27 00:37:33 +00001235
1236/**
1237 * Map a region of memory.
1238 *
1239 * \param fd file descriptor.
1240 * \param handle handle returned by drmAddMap().
1241 * \param size size in bytes. Must match the size used by drmAddMap().
1242 * \param address will contain the user-space virtual address where the mapping
1243 * begins.
1244 *
1245 * \return zero on success, or a negative value on failure.
1246 *
1247 * \internal
1248 * This function is a wrapper for mmap().
1249 */
Adam Jackson22e41ef2006-02-20 23:09:00 +00001250int drmMap(int fd, drm_handle_t handle, drmSize size, drmAddressPtr address)
Daryll Straussb3a57661999-12-05 01:19:48 +00001251{
Alan Hourihanec7558d82000-09-24 09:34:10 +00001252 static unsigned long pagesize_mask = 0;
1253
Brianccd7b6e2007-05-29 14:54:00 -06001254 if (fd < 0)
1255 return -EINVAL;
Alan Hourihanec7558d82000-09-24 09:34:10 +00001256
1257 if (!pagesize_mask)
1258 pagesize_mask = getpagesize() - 1;
1259
1260 size = (size + pagesize_mask) & ~pagesize_mask;
1261
Emil Velikovfaf51d52014-09-07 20:03:05 +01001262 *address = drm_mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, handle);
Brianccd7b6e2007-05-29 14:54:00 -06001263 if (*address == MAP_FAILED)
1264 return -errno;
Daryll Straussb3a57661999-12-05 01:19:48 +00001265 return 0;
1266}
1267
Jose Fonsecad2443b22003-05-27 00:37:33 +00001268
1269/**
1270 * Unmap mappings obtained with drmMap().
1271 *
1272 * \param address address as given by drmMap().
1273 * \param size size in bytes. Must match the size used by drmMap().
1274 *
1275 * \return zero on success, or a negative value on failure.
1276 *
1277 * \internal
Adam Jackson22e41ef2006-02-20 23:09:00 +00001278 * This function is a wrapper for munmap().
Jose Fonsecad2443b22003-05-27 00:37:33 +00001279 */
Daryll Straussb3a57661999-12-05 01:19:48 +00001280int drmUnmap(drmAddress address, drmSize size)
1281{
Emil Velikovfaf51d52014-09-07 20:03:05 +01001282 return drm_munmap(address, size);
Daryll Straussb3a57661999-12-05 01:19:48 +00001283}
1284
1285drmBufInfoPtr drmGetBufInfo(int fd)
1286{
1287 drm_buf_info_t info;
1288 drmBufInfoPtr retval;
1289 int i;
1290
Daniel Vetterfd387942015-02-11 12:41:04 +01001291 memclear(info);
Daryll Straussb3a57661999-12-05 01:19:48 +00001292
Keith Packard8b9ab102008-06-13 16:03:22 -07001293 if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info))
Brianccd7b6e2007-05-29 14:54:00 -06001294 return NULL;
Daryll Straussb3a57661999-12-05 01:19:48 +00001295
1296 if (info.count) {
1297 if (!(info.list = drmMalloc(info.count * sizeof(*info.list))))
1298 return NULL;
Gareth Hughes36047532001-02-15 08:12:14 +00001299
Keith Packard8b9ab102008-06-13 16:03:22 -07001300 if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info)) {
Daryll Straussb3a57661999-12-05 01:19:48 +00001301 drmFree(info.list);
1302 return NULL;
1303 }
Adam Jackson22e41ef2006-02-20 23:09:00 +00001304
Daryll Straussb3a57661999-12-05 01:19:48 +00001305 retval = drmMalloc(sizeof(*retval));
1306 retval->count = info.count;
1307 retval->list = drmMalloc(info.count * sizeof(*retval->list));
1308 for (i = 0; i < info.count; i++) {
1309 retval->list[i].count = info.list[i].count;
1310 retval->list[i].size = info.list[i].size;
1311 retval->list[i].low_mark = info.list[i].low_mark;
1312 retval->list[i].high_mark = info.list[i].high_mark;
1313 }
1314 drmFree(info.list);
1315 return retval;
1316 }
1317 return NULL;
1318}
1319
Jose Fonsecad2443b22003-05-27 00:37:33 +00001320/**
1321 * Map all DMA buffers into client-virtual space.
1322 *
1323 * \param fd file descriptor.
1324 *
1325 * \return a pointer to a ::drmBufMap structure.
1326 *
1327 * \note The client may not use these buffers until obtaining buffer indices
1328 * with drmDMA().
1329 *
1330 * \internal
1331 * This function calls the DRM_IOCTL_MAP_BUFS ioctl and copies the returned
1332 * information about the buffers in a drm_buf_map structure into the
1333 * client-visible data structures.
1334 */
Daryll Straussb3a57661999-12-05 01:19:48 +00001335drmBufMapPtr drmMapBufs(int fd)
1336{
1337 drm_buf_map_t bufs;
1338 drmBufMapPtr retval;
1339 int i;
Gareth Hughes36047532001-02-15 08:12:14 +00001340
Daniel Vetterfd387942015-02-11 12:41:04 +01001341 memclear(bufs);
Keith Packard8b9ab102008-06-13 16:03:22 -07001342 if (drmIoctl(fd, DRM_IOCTL_MAP_BUFS, &bufs))
Brianccd7b6e2007-05-29 14:54:00 -06001343 return NULL;
Daryll Straussb3a57661999-12-05 01:19:48 +00001344
Brianccd7b6e2007-05-29 14:54:00 -06001345 if (!bufs.count)
1346 return NULL;
Jon Smirl8696e712004-07-07 04:36:36 +00001347
Daryll Straussb3a57661999-12-05 01:19:48 +00001348 if (!(bufs.list = drmMalloc(bufs.count * sizeof(*bufs.list))))
1349 return NULL;
1350
Keith Packard8b9ab102008-06-13 16:03:22 -07001351 if (drmIoctl(fd, DRM_IOCTL_MAP_BUFS, &bufs)) {
Daryll Straussb3a57661999-12-05 01:19:48 +00001352 drmFree(bufs.list);
1353 return NULL;
1354 }
Adam Jackson22e41ef2006-02-20 23:09:00 +00001355
Daryll Straussb3a57661999-12-05 01:19:48 +00001356 retval = drmMalloc(sizeof(*retval));
1357 retval->count = bufs.count;
1358 retval->list = drmMalloc(bufs.count * sizeof(*retval->list));
1359 for (i = 0; i < bufs.count; i++) {
1360 retval->list[i].idx = bufs.list[i].idx;
1361 retval->list[i].total = bufs.list[i].total;
1362 retval->list[i].used = 0;
1363 retval->list[i].address = bufs.list[i].address;
1364 }
Jon Smirl8696e712004-07-07 04:36:36 +00001365
1366 drmFree(bufs.list);
1367
Daryll Straussb3a57661999-12-05 01:19:48 +00001368 return retval;
Daryll Straussb3a57661999-12-05 01:19:48 +00001369}
1370
Jose Fonsecad2443b22003-05-27 00:37:33 +00001371
1372/**
1373 * Unmap buffers allocated with drmMapBufs().
1374 *
1375 * \return zero on success, or negative value on failure.
1376 *
1377 * \internal
Jon Smirl8696e712004-07-07 04:36:36 +00001378 * Calls munmap() for every buffer stored in \p bufs and frees the
1379 * memory allocated by drmMapBufs().
Jose Fonsecad2443b22003-05-27 00:37:33 +00001380 */
Daryll Straussb3a57661999-12-05 01:19:48 +00001381int drmUnmapBufs(drmBufMapPtr bufs)
1382{
1383 int i;
Gareth Hughes36047532001-02-15 08:12:14 +00001384
Daryll Straussb3a57661999-12-05 01:19:48 +00001385 for (i = 0; i < bufs->count; i++) {
Emil Velikovfaf51d52014-09-07 20:03:05 +01001386 drm_munmap(bufs->list[i].address, bufs->list[i].total);
Daryll Straussb3a57661999-12-05 01:19:48 +00001387 }
Jon Smirl8696e712004-07-07 04:36:36 +00001388
1389 drmFree(bufs->list);
1390 drmFree(bufs);
1391
Daryll Straussb3a57661999-12-05 01:19:48 +00001392 return 0;
1393}
1394
Jose Fonsecad2443b22003-05-27 00:37:33 +00001395
Gareth Hughes36047532001-02-15 08:12:14 +00001396#define DRM_DMA_RETRY 16
1397
Jose Fonsecad2443b22003-05-27 00:37:33 +00001398/**
1399 * Reserve DMA buffers.
1400 *
1401 * \param fd file descriptor.
1402 * \param request
1403 *
1404 * \return zero on success, or a negative value on failure.
1405 *
1406 * \internal
1407 * Assemble the arguments into a drm_dma structure and keeps issuing the
1408 * DRM_IOCTL_DMA ioctl until success or until maximum number of retries.
1409 */
Daryll Straussb3a57661999-12-05 01:19:48 +00001410int drmDMA(int fd, drmDMAReqPtr request)
1411{
1412 drm_dma_t dma;
Gareth Hughes36047532001-02-15 08:12:14 +00001413 int ret, i = 0;
Daryll Straussb3a57661999-12-05 01:19:48 +00001414
Daryll Straussb3a57661999-12-05 01:19:48 +00001415 dma.context = request->context;
1416 dma.send_count = request->send_count;
1417 dma.send_indices = request->send_list;
1418 dma.send_sizes = request->send_sizes;
1419 dma.flags = request->flags;
1420 dma.request_count = request->request_count;
1421 dma.request_size = request->request_size;
1422 dma.request_indices = request->request_list;
1423 dma.request_sizes = request->request_sizes;
Jon Smirl8696e712004-07-07 04:36:36 +00001424 dma.granted_count = 0;
Gareth Hughes36047532001-02-15 08:12:14 +00001425
1426 do {
1427 ret = ioctl( fd, DRM_IOCTL_DMA, &dma );
1428 } while ( ret && errno == EAGAIN && i++ < DRM_DMA_RETRY );
1429
1430 if ( ret == 0 ) {
1431 request->granted_count = dma.granted_count;
1432 return 0;
1433 } else {
1434 return -errno;
1435 }
Daryll Straussb3a57661999-12-05 01:19:48 +00001436}
1437
Jose Fonsecad2443b22003-05-27 00:37:33 +00001438
1439/**
1440 * Obtain heavyweight hardware lock.
1441 *
1442 * \param fd file descriptor.
1443 * \param context context.
1444 * \param flags flags that determine the sate of the hardware when the function
1445 * returns.
1446 *
1447 * \return always zero.
1448 *
1449 * \internal
1450 * This function translates the arguments into a drm_lock structure and issue
1451 * the DRM_IOCTL_LOCK ioctl until the lock is successfully acquired.
1452 */
Jon Smirl8696e712004-07-07 04:36:36 +00001453int drmGetLock(int fd, drm_context_t context, drmLockFlags flags)
Daryll Straussb3a57661999-12-05 01:19:48 +00001454{
1455 drm_lock_t lock;
1456
Daniel Vetterfd387942015-02-11 12:41:04 +01001457 memclear(lock);
Daryll Straussb3a57661999-12-05 01:19:48 +00001458 lock.context = context;
1459 lock.flags = 0;
1460 if (flags & DRM_LOCK_READY) lock.flags |= _DRM_LOCK_READY;
1461 if (flags & DRM_LOCK_QUIESCENT) lock.flags |= _DRM_LOCK_QUIESCENT;
1462 if (flags & DRM_LOCK_FLUSH) lock.flags |= _DRM_LOCK_FLUSH;
1463 if (flags & DRM_LOCK_FLUSH_ALL) lock.flags |= _DRM_LOCK_FLUSH_ALL;
1464 if (flags & DRM_HALT_ALL_QUEUES) lock.flags |= _DRM_HALT_ALL_QUEUES;
1465 if (flags & DRM_HALT_CUR_QUEUES) lock.flags |= _DRM_HALT_CUR_QUEUES;
Gareth Hughes36047532001-02-15 08:12:14 +00001466
Keith Packard8b9ab102008-06-13 16:03:22 -07001467 while (drmIoctl(fd, DRM_IOCTL_LOCK, &lock))
Daryll Straussb3a57661999-12-05 01:19:48 +00001468 ;
1469 return 0;
1470}
1471
Jose Fonsecad2443b22003-05-27 00:37:33 +00001472/**
1473 * Release the hardware lock.
1474 *
1475 * \param fd file descriptor.
1476 * \param context context.
1477 *
1478 * \return zero on success, or a negative value on failure.
1479 *
1480 * \internal
1481 * This function is a wrapper around the DRM_IOCTL_UNLOCK ioctl, passing the
1482 * argument in a drm_lock structure.
1483 */
Jon Smirl8696e712004-07-07 04:36:36 +00001484int drmUnlock(int fd, drm_context_t context)
Daryll Straussb3a57661999-12-05 01:19:48 +00001485{
1486 drm_lock_t lock;
1487
Daniel Vetterfd387942015-02-11 12:41:04 +01001488 memclear(lock);
Daryll Straussb3a57661999-12-05 01:19:48 +00001489 lock.context = context;
Keith Packard8b9ab102008-06-13 16:03:22 -07001490 return drmIoctl(fd, DRM_IOCTL_UNLOCK, &lock);
Daryll Straussb3a57661999-12-05 01:19:48 +00001491}
1492
Adam Jackson22e41ef2006-02-20 23:09:00 +00001493drm_context_t *drmGetReservedContextList(int fd, int *count)
Daryll Straussb3a57661999-12-05 01:19:48 +00001494{
1495 drm_ctx_res_t res;
1496 drm_ctx_t *list;
Jon Smirl8696e712004-07-07 04:36:36 +00001497 drm_context_t * retval;
Daryll Straussb3a57661999-12-05 01:19:48 +00001498 int i;
1499
Daniel Vetterfd387942015-02-11 12:41:04 +01001500 memclear(res);
Keith Packard8b9ab102008-06-13 16:03:22 -07001501 if (drmIoctl(fd, DRM_IOCTL_RES_CTX, &res))
Brianccd7b6e2007-05-29 14:54:00 -06001502 return NULL;
Daryll Straussb3a57661999-12-05 01:19:48 +00001503
Brianccd7b6e2007-05-29 14:54:00 -06001504 if (!res.count)
1505 return NULL;
Daryll Straussb3a57661999-12-05 01:19:48 +00001506
Brianccd7b6e2007-05-29 14:54:00 -06001507 if (!(list = drmMalloc(res.count * sizeof(*list))))
1508 return NULL;
Daryll Straussb3a57661999-12-05 01:19:48 +00001509 if (!(retval = drmMalloc(res.count * sizeof(*retval)))) {
1510 drmFree(list);
1511 return NULL;
1512 }
1513
1514 res.contexts = list;
Keith Packard8b9ab102008-06-13 16:03:22 -07001515 if (drmIoctl(fd, DRM_IOCTL_RES_CTX, &res))
Brianccd7b6e2007-05-29 14:54:00 -06001516 return NULL;
Daryll Straussb3a57661999-12-05 01:19:48 +00001517
Brianccd7b6e2007-05-29 14:54:00 -06001518 for (i = 0; i < res.count; i++)
1519 retval[i] = list[i].handle;
Daryll Straussb3a57661999-12-05 01:19:48 +00001520 drmFree(list);
1521
1522 *count = res.count;
1523 return retval;
1524}
1525
Adam Jackson22e41ef2006-02-20 23:09:00 +00001526void drmFreeReservedContextList(drm_context_t *pt)
Daryll Straussb3a57661999-12-05 01:19:48 +00001527{
1528 drmFree(pt);
1529}
1530
Jose Fonsecad2443b22003-05-27 00:37:33 +00001531/**
1532 * Create context.
1533 *
1534 * Used by the X server during GLXContext initialization. This causes
1535 * per-context kernel-level resources to be allocated.
1536 *
1537 * \param fd file descriptor.
1538 * \param handle is set on success. To be used by the client when requesting DMA
1539 * dispatch with drmDMA().
1540 *
1541 * \return zero on success, or a negative value on failure.
1542 *
1543 * \note May only be called by root.
1544 *
1545 * \internal
1546 * This function is a wrapper around the DRM_IOCTL_ADD_CTX ioctl, passing the
1547 * argument in a drm_ctx structure.
1548 */
Adam Jackson22e41ef2006-02-20 23:09:00 +00001549int drmCreateContext(int fd, drm_context_t *handle)
Daryll Straussb3a57661999-12-05 01:19:48 +00001550{
1551 drm_ctx_t ctx;
1552
Daniel Vetterfd387942015-02-11 12:41:04 +01001553 memclear(ctx);
Keith Packard8b9ab102008-06-13 16:03:22 -07001554 if (drmIoctl(fd, DRM_IOCTL_ADD_CTX, &ctx))
Brianccd7b6e2007-05-29 14:54:00 -06001555 return -errno;
Daryll Straussb3a57661999-12-05 01:19:48 +00001556 *handle = ctx.handle;
1557 return 0;
1558}
1559
Jon Smirl8696e712004-07-07 04:36:36 +00001560int drmSwitchToContext(int fd, drm_context_t context)
Daryll Straussb3a57661999-12-05 01:19:48 +00001561{
1562 drm_ctx_t ctx;
1563
Daniel Vetterfd387942015-02-11 12:41:04 +01001564 memclear(ctx);
Daryll Straussb3a57661999-12-05 01:19:48 +00001565 ctx.handle = context;
Keith Packard8b9ab102008-06-13 16:03:22 -07001566 if (drmIoctl(fd, DRM_IOCTL_SWITCH_CTX, &ctx))
Brianccd7b6e2007-05-29 14:54:00 -06001567 return -errno;
Daryll Straussb3a57661999-12-05 01:19:48 +00001568 return 0;
1569}
1570
Jon Smirl8696e712004-07-07 04:36:36 +00001571int drmSetContextFlags(int fd, drm_context_t context, drm_context_tFlags flags)
Daryll Straussb3a57661999-12-05 01:19:48 +00001572{
1573 drm_ctx_t ctx;
1574
Adam Jackson22e41ef2006-02-20 23:09:00 +00001575 /*
1576 * Context preserving means that no context switches are done between DMA
1577 * buffers from one context and the next. This is suitable for use in the
1578 * X server (which promises to maintain hardware context), or in the
1579 * client-side library when buffers are swapped on behalf of two threads.
1580 */
Daniel Vetterfd387942015-02-11 12:41:04 +01001581 memclear(ctx);
Daryll Straussb3a57661999-12-05 01:19:48 +00001582 ctx.handle = context;
Brianccd7b6e2007-05-29 14:54:00 -06001583 if (flags & DRM_CONTEXT_PRESERVED)
1584 ctx.flags |= _DRM_CONTEXT_PRESERVED;
1585 if (flags & DRM_CONTEXT_2DONLY)
1586 ctx.flags |= _DRM_CONTEXT_2DONLY;
Keith Packard8b9ab102008-06-13 16:03:22 -07001587 if (drmIoctl(fd, DRM_IOCTL_MOD_CTX, &ctx))
Brianccd7b6e2007-05-29 14:54:00 -06001588 return -errno;
Daryll Straussb3a57661999-12-05 01:19:48 +00001589 return 0;
1590}
1591
Adam Jackson22e41ef2006-02-20 23:09:00 +00001592int drmGetContextFlags(int fd, drm_context_t context,
1593 drm_context_tFlagsPtr flags)
Daryll Straussb3a57661999-12-05 01:19:48 +00001594{
1595 drm_ctx_t ctx;
1596
Daniel Vetterfd387942015-02-11 12:41:04 +01001597 memclear(ctx);
Daryll Straussb3a57661999-12-05 01:19:48 +00001598 ctx.handle = context;
Keith Packard8b9ab102008-06-13 16:03:22 -07001599 if (drmIoctl(fd, DRM_IOCTL_GET_CTX, &ctx))
Brianccd7b6e2007-05-29 14:54:00 -06001600 return -errno;
Daryll Straussb3a57661999-12-05 01:19:48 +00001601 *flags = 0;
Brianccd7b6e2007-05-29 14:54:00 -06001602 if (ctx.flags & _DRM_CONTEXT_PRESERVED)
1603 *flags |= DRM_CONTEXT_PRESERVED;
1604 if (ctx.flags & _DRM_CONTEXT_2DONLY)
1605 *flags |= DRM_CONTEXT_2DONLY;
Daryll Straussb3a57661999-12-05 01:19:48 +00001606 return 0;
1607}
Gareth Hughes36047532001-02-15 08:12:14 +00001608
Jose Fonsecad2443b22003-05-27 00:37:33 +00001609/**
1610 * Destroy context.
1611 *
1612 * Free any kernel-level resources allocated with drmCreateContext() associated
1613 * with the context.
1614 *
1615 * \param fd file descriptor.
1616 * \param handle handle given by drmCreateContext().
1617 *
1618 * \return zero on success, or a negative value on failure.
1619 *
1620 * \note May only be called by root.
1621 *
1622 * \internal
1623 * This function is a wrapper around the DRM_IOCTL_RM_CTX ioctl, passing the
1624 * argument in a drm_ctx structure.
1625 */
Jon Smirl8696e712004-07-07 04:36:36 +00001626int drmDestroyContext(int fd, drm_context_t handle)
Daryll Straussb3a57661999-12-05 01:19:48 +00001627{
1628 drm_ctx_t ctx;
Daniel Vetterfd387942015-02-11 12:41:04 +01001629
1630 memclear(ctx);
Daryll Straussb3a57661999-12-05 01:19:48 +00001631 ctx.handle = handle;
Keith Packard8b9ab102008-06-13 16:03:22 -07001632 if (drmIoctl(fd, DRM_IOCTL_RM_CTX, &ctx))
Brianccd7b6e2007-05-29 14:54:00 -06001633 return -errno;
Daryll Straussb3a57661999-12-05 01:19:48 +00001634 return 0;
1635}
1636
Adam Jackson22e41ef2006-02-20 23:09:00 +00001637int drmCreateDrawable(int fd, drm_drawable_t *handle)
Daryll Straussb3a57661999-12-05 01:19:48 +00001638{
1639 drm_draw_t draw;
Daniel Vetterfd387942015-02-11 12:41:04 +01001640
1641 memclear(draw);
Keith Packard8b9ab102008-06-13 16:03:22 -07001642 if (drmIoctl(fd, DRM_IOCTL_ADD_DRAW, &draw))
Brianccd7b6e2007-05-29 14:54:00 -06001643 return -errno;
Daryll Straussb3a57661999-12-05 01:19:48 +00001644 *handle = draw.handle;
1645 return 0;
1646}
1647
Jon Smirl8696e712004-07-07 04:36:36 +00001648int drmDestroyDrawable(int fd, drm_drawable_t handle)
Daryll Straussb3a57661999-12-05 01:19:48 +00001649{
1650 drm_draw_t draw;
Daniel Vetterfd387942015-02-11 12:41:04 +01001651
1652 memclear(draw);
Daryll Straussb3a57661999-12-05 01:19:48 +00001653 draw.handle = handle;
Keith Packard8b9ab102008-06-13 16:03:22 -07001654 if (drmIoctl(fd, DRM_IOCTL_RM_DRAW, &draw))
Brianccd7b6e2007-05-29 14:54:00 -06001655 return -errno;
Daryll Straussb3a57661999-12-05 01:19:48 +00001656 return 0;
1657}
1658
Michel Dänzer9810ec22006-08-22 16:40:07 +02001659int drmUpdateDrawableInfo(int fd, drm_drawable_t handle,
1660 drm_drawable_info_type_t type, unsigned int num,
1661 void *data)
1662{
1663 drm_update_draw_t update;
1664
Daniel Vetterfd387942015-02-11 12:41:04 +01001665 memclear(update);
Michel Dänzer9810ec22006-08-22 16:40:07 +02001666 update.handle = handle;
1667 update.type = type;
1668 update.num = num;
1669 update.data = (unsigned long long)(unsigned long)data;
1670
Keith Packard8b9ab102008-06-13 16:03:22 -07001671 if (drmIoctl(fd, DRM_IOCTL_UPDATE_DRAW, &update))
Brianccd7b6e2007-05-29 14:54:00 -06001672 return -errno;
Michel Dänzer9810ec22006-08-22 16:40:07 +02001673
1674 return 0;
1675}
1676
Jose Fonsecad2443b22003-05-27 00:37:33 +00001677/**
1678 * Acquire the AGP device.
1679 *
1680 * Must be called before any of the other AGP related calls.
1681 *
1682 * \param fd file descriptor.
1683 *
1684 * \return zero on success, or a negative value on failure.
1685 *
1686 * \internal
1687 * This function is a wrapper around the DRM_IOCTL_AGP_ACQUIRE ioctl.
1688 */
Jeff Hartmannba1b1ae2000-04-04 22:08:14 +00001689int drmAgpAcquire(int fd)
1690{
Keith Packard8b9ab102008-06-13 16:03:22 -07001691 if (drmIoctl(fd, DRM_IOCTL_AGP_ACQUIRE, NULL))
Brianccd7b6e2007-05-29 14:54:00 -06001692 return -errno;
Jeff Hartmannba1b1ae2000-04-04 22:08:14 +00001693 return 0;
1694}
1695
Jose Fonsecad2443b22003-05-27 00:37:33 +00001696
1697/**
1698 * Release the AGP device.
1699 *
1700 * \param fd file descriptor.
1701 *
1702 * \return zero on success, or a negative value on failure.
1703 *
1704 * \internal
1705 * This function is a wrapper around the DRM_IOCTL_AGP_RELEASE ioctl.
1706 */
Jeff Hartmannba1b1ae2000-04-04 22:08:14 +00001707int drmAgpRelease(int fd)
1708{
Keith Packard8b9ab102008-06-13 16:03:22 -07001709 if (drmIoctl(fd, DRM_IOCTL_AGP_RELEASE, NULL))
Brianccd7b6e2007-05-29 14:54:00 -06001710 return -errno;
Jeff Hartmannba1b1ae2000-04-04 22:08:14 +00001711 return 0;
1712}
1713
Jose Fonsecad2443b22003-05-27 00:37:33 +00001714
1715/**
1716 * Set the AGP mode.
1717 *
1718 * \param fd file descriptor.
1719 * \param mode AGP mode.
1720 *
1721 * \return zero on success, or a negative value on failure.
1722 *
1723 * \internal
1724 * This function is a wrapper around the DRM_IOCTL_AGP_ENABLE ioctl, passing the
1725 * argument in a drm_agp_mode structure.
1726 */
Jeff Hartmannba1b1ae2000-04-04 22:08:14 +00001727int drmAgpEnable(int fd, unsigned long mode)
1728{
1729 drm_agp_mode_t m;
1730
Connor Behan14900552015-03-24 13:53:51 -04001731 memclear(m);
Jeff Hartmannba1b1ae2000-04-04 22:08:14 +00001732 m.mode = mode;
Keith Packard8b9ab102008-06-13 16:03:22 -07001733 if (drmIoctl(fd, DRM_IOCTL_AGP_ENABLE, &m))
Brianccd7b6e2007-05-29 14:54:00 -06001734 return -errno;
Jeff Hartmannba1b1ae2000-04-04 22:08:14 +00001735 return 0;
1736}
1737
Jose Fonsecad2443b22003-05-27 00:37:33 +00001738
1739/**
1740 * Allocate a chunk of AGP memory.
1741 *
1742 * \param fd file descriptor.
1743 * \param size requested memory size in bytes. Will be rounded to page boundary.
1744 * \param type type of memory to allocate.
1745 * \param address if not zero, will be set to the physical address of the
1746 * allocated memory.
1747 * \param handle on success will be set to a handle of the allocated memory.
1748 *
1749 * \return zero on success, or a negative value on failure.
1750 *
1751 * \internal
1752 * This function is a wrapper around the DRM_IOCTL_AGP_ALLOC ioctl, passing the
1753 * arguments in a drm_agp_buffer structure.
1754 */
Jeff Hartmannba1b1ae2000-04-04 22:08:14 +00001755int drmAgpAlloc(int fd, unsigned long size, unsigned long type,
Dave Airlie7ede2092005-11-29 09:50:47 +00001756 unsigned long *address, drm_handle_t *handle)
Jeff Hartmannba1b1ae2000-04-04 22:08:14 +00001757{
1758 drm_agp_buffer_t b;
Alan Hourihaneb0a92852003-09-24 14:39:25 +00001759
Daniel Vetterfd387942015-02-11 12:41:04 +01001760 memclear(b);
Alan Hourihaneb0a92852003-09-24 14:39:25 +00001761 *handle = DRM_AGP_NO_HANDLE;
Jeff Hartmannba1b1ae2000-04-04 22:08:14 +00001762 b.size = size;
Jeff Hartmannba1b1ae2000-04-04 22:08:14 +00001763 b.type = type;
Keith Packard8b9ab102008-06-13 16:03:22 -07001764 if (drmIoctl(fd, DRM_IOCTL_AGP_ALLOC, &b))
Brianccd7b6e2007-05-29 14:54:00 -06001765 return -errno;
1766 if (address != 0UL)
1767 *address = b.physical;
Jeff Hartmannba1b1ae2000-04-04 22:08:14 +00001768 *handle = b.handle;
1769 return 0;
1770}
1771
Jose Fonsecad2443b22003-05-27 00:37:33 +00001772
1773/**
1774 * Free a chunk of AGP memory.
1775 *
1776 * \param fd file descriptor.
1777 * \param handle handle to the allocated memory, as given by drmAgpAllocate().
1778 *
1779 * \return zero on success, or a negative value on failure.
1780 *
1781 * \internal
1782 * This function is a wrapper around the DRM_IOCTL_AGP_FREE ioctl, passing the
1783 * argument in a drm_agp_buffer structure.
1784 */
Dave Airlie7ede2092005-11-29 09:50:47 +00001785int drmAgpFree(int fd, drm_handle_t handle)
Jeff Hartmannba1b1ae2000-04-04 22:08:14 +00001786{
1787 drm_agp_buffer_t b;
1788
Daniel Vetterfd387942015-02-11 12:41:04 +01001789 memclear(b);
Jeff Hartmannba1b1ae2000-04-04 22:08:14 +00001790 b.handle = handle;
Keith Packard8b9ab102008-06-13 16:03:22 -07001791 if (drmIoctl(fd, DRM_IOCTL_AGP_FREE, &b))
Brianccd7b6e2007-05-29 14:54:00 -06001792 return -errno;
Jeff Hartmannba1b1ae2000-04-04 22:08:14 +00001793 return 0;
1794}
1795
Jose Fonsecad2443b22003-05-27 00:37:33 +00001796
1797/**
1798 * Bind a chunk of AGP memory.
1799 *
1800 * \param fd file descriptor.
1801 * \param handle handle to the allocated memory, as given by drmAgpAllocate().
1802 * \param offset offset in bytes. It will round to page boundary.
1803 *
1804 * \return zero on success, or a negative value on failure.
1805 *
1806 * \internal
1807 * This function is a wrapper around the DRM_IOCTL_AGP_BIND ioctl, passing the
1808 * argument in a drm_agp_binding structure.
1809 */
Dave Airlie7ede2092005-11-29 09:50:47 +00001810int drmAgpBind(int fd, drm_handle_t handle, unsigned long offset)
Jeff Hartmannba1b1ae2000-04-04 22:08:14 +00001811{
1812 drm_agp_binding_t b;
1813
Daniel Vetterfd387942015-02-11 12:41:04 +01001814 memclear(b);
Jeff Hartmannba1b1ae2000-04-04 22:08:14 +00001815 b.handle = handle;
1816 b.offset = offset;
Keith Packard8b9ab102008-06-13 16:03:22 -07001817 if (drmIoctl(fd, DRM_IOCTL_AGP_BIND, &b))
Brianccd7b6e2007-05-29 14:54:00 -06001818 return -errno;
Jeff Hartmannba1b1ae2000-04-04 22:08:14 +00001819 return 0;
1820}
1821
Jose Fonsecad2443b22003-05-27 00:37:33 +00001822
1823/**
1824 * Unbind a chunk of AGP memory.
1825 *
1826 * \param fd file descriptor.
1827 * \param handle handle to the allocated memory, as given by drmAgpAllocate().
1828 *
1829 * \return zero on success, or a negative value on failure.
1830 *
1831 * \internal
1832 * This function is a wrapper around the DRM_IOCTL_AGP_UNBIND ioctl, passing
1833 * the argument in a drm_agp_binding structure.
1834 */
Dave Airlie7ede2092005-11-29 09:50:47 +00001835int drmAgpUnbind(int fd, drm_handle_t handle)
Jeff Hartmannba1b1ae2000-04-04 22:08:14 +00001836{
1837 drm_agp_binding_t b;
1838
Daniel Vetterfd387942015-02-11 12:41:04 +01001839 memclear(b);
Jeff Hartmannba1b1ae2000-04-04 22:08:14 +00001840 b.handle = handle;
Keith Packard8b9ab102008-06-13 16:03:22 -07001841 if (drmIoctl(fd, DRM_IOCTL_AGP_UNBIND, &b))
Brianccd7b6e2007-05-29 14:54:00 -06001842 return -errno;
Jeff Hartmannba1b1ae2000-04-04 22:08:14 +00001843 return 0;
1844}
1845
Jose Fonsecad2443b22003-05-27 00:37:33 +00001846
1847/**
1848 * Get AGP driver major version number.
1849 *
1850 * \param fd file descriptor.
1851 *
1852 * \return major version number on success, or a negative value on failure..
1853 *
1854 * \internal
1855 * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
1856 * necessary information in a drm_agp_info structure.
1857 */
Jeff Hartmannba1b1ae2000-04-04 22:08:14 +00001858int drmAgpVersionMajor(int fd)
1859{
1860 drm_agp_info_t i;
1861
Daniel Vetterfd387942015-02-11 12:41:04 +01001862 memclear(i);
1863
Keith Packard8b9ab102008-06-13 16:03:22 -07001864 if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
Brianccd7b6e2007-05-29 14:54:00 -06001865 return -errno;
Jeff Hartmannba1b1ae2000-04-04 22:08:14 +00001866 return i.agp_version_major;
1867}
1868
Jose Fonsecad2443b22003-05-27 00:37:33 +00001869
1870/**
1871 * Get AGP driver minor version number.
1872 *
1873 * \param fd file descriptor.
1874 *
1875 * \return minor version number on success, or a negative value on failure.
1876 *
1877 * \internal
1878 * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
1879 * necessary information in a drm_agp_info structure.
1880 */
Jeff Hartmannba1b1ae2000-04-04 22:08:14 +00001881int drmAgpVersionMinor(int fd)
1882{
1883 drm_agp_info_t i;
1884
Daniel Vetterfd387942015-02-11 12:41:04 +01001885 memclear(i);
1886
Keith Packard8b9ab102008-06-13 16:03:22 -07001887 if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
Brianccd7b6e2007-05-29 14:54:00 -06001888 return -errno;
Jeff Hartmannba1b1ae2000-04-04 22:08:14 +00001889 return i.agp_version_minor;
1890}
1891
Jose Fonsecad2443b22003-05-27 00:37:33 +00001892
1893/**
1894 * Get AGP mode.
1895 *
1896 * \param fd file descriptor.
1897 *
1898 * \return mode on success, or zero on failure.
1899 *
1900 * \internal
1901 * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
1902 * necessary information in a drm_agp_info structure.
1903 */
Jeff Hartmannba1b1ae2000-04-04 22:08:14 +00001904unsigned long drmAgpGetMode(int fd)
1905{
1906 drm_agp_info_t i;
1907
Daniel Vetterfd387942015-02-11 12:41:04 +01001908 memclear(i);
1909
Keith Packard8b9ab102008-06-13 16:03:22 -07001910 if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
Brianccd7b6e2007-05-29 14:54:00 -06001911 return 0;
Jeff Hartmannba1b1ae2000-04-04 22:08:14 +00001912 return i.mode;
1913}
1914
Jose Fonsecad2443b22003-05-27 00:37:33 +00001915
1916/**
1917 * Get AGP aperture base.
1918 *
1919 * \param fd file descriptor.
1920 *
1921 * \return aperture base on success, zero on failure.
1922 *
1923 * \internal
1924 * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
1925 * necessary information in a drm_agp_info structure.
1926 */
Jeff Hartmannba1b1ae2000-04-04 22:08:14 +00001927unsigned long drmAgpBase(int fd)
1928{
1929 drm_agp_info_t i;
1930
Daniel Vetterfd387942015-02-11 12:41:04 +01001931 memclear(i);
1932
Keith Packard8b9ab102008-06-13 16:03:22 -07001933 if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
Brianccd7b6e2007-05-29 14:54:00 -06001934 return 0;
Jeff Hartmannba1b1ae2000-04-04 22:08:14 +00001935 return i.aperture_base;
1936}
1937
Jose Fonsecad2443b22003-05-27 00:37:33 +00001938
1939/**
1940 * Get AGP aperture size.
1941 *
1942 * \param fd file descriptor.
1943 *
1944 * \return aperture size on success, zero on failure.
1945 *
1946 * \internal
1947 * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
1948 * necessary information in a drm_agp_info structure.
1949 */
Jeff Hartmannba1b1ae2000-04-04 22:08:14 +00001950unsigned long drmAgpSize(int fd)
1951{
1952 drm_agp_info_t i;
1953
Daniel Vetterfd387942015-02-11 12:41:04 +01001954 memclear(i);
1955
Keith Packard8b9ab102008-06-13 16:03:22 -07001956 if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
Brianccd7b6e2007-05-29 14:54:00 -06001957 return 0;
Jeff Hartmannba1b1ae2000-04-04 22:08:14 +00001958 return i.aperture_size;
1959}
1960
Jose Fonsecad2443b22003-05-27 00:37:33 +00001961
1962/**
1963 * Get used AGP memory.
1964 *
1965 * \param fd file descriptor.
1966 *
1967 * \return memory used on success, or zero on failure.
1968 *
1969 * \internal
1970 * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
1971 * necessary information in a drm_agp_info structure.
1972 */
Jeff Hartmannba1b1ae2000-04-04 22:08:14 +00001973unsigned long drmAgpMemoryUsed(int fd)
1974{
1975 drm_agp_info_t i;
1976
Daniel Vetterfd387942015-02-11 12:41:04 +01001977 memclear(i);
1978
Keith Packard8b9ab102008-06-13 16:03:22 -07001979 if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
Brianccd7b6e2007-05-29 14:54:00 -06001980 return 0;
Jeff Hartmannba1b1ae2000-04-04 22:08:14 +00001981 return i.memory_used;
1982}
1983
Jose Fonsecad2443b22003-05-27 00:37:33 +00001984
1985/**
1986 * Get available AGP memory.
1987 *
1988 * \param fd file descriptor.
1989 *
1990 * \return memory available on success, or zero on failure.
1991 *
1992 * \internal
1993 * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
1994 * necessary information in a drm_agp_info structure.
1995 */
Jeff Hartmannba1b1ae2000-04-04 22:08:14 +00001996unsigned long drmAgpMemoryAvail(int fd)
1997{
1998 drm_agp_info_t i;
1999
Daniel Vetterfd387942015-02-11 12:41:04 +01002000 memclear(i);
2001
Keith Packard8b9ab102008-06-13 16:03:22 -07002002 if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
Brianccd7b6e2007-05-29 14:54:00 -06002003 return 0;
Jeff Hartmannba1b1ae2000-04-04 22:08:14 +00002004 return i.memory_allowed;
2005}
2006
Jose Fonsecad2443b22003-05-27 00:37:33 +00002007
2008/**
2009 * Get hardware vendor ID.
2010 *
2011 * \param fd file descriptor.
2012 *
2013 * \return vendor ID on success, or zero on failure.
2014 *
2015 * \internal
2016 * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
2017 * necessary information in a drm_agp_info structure.
2018 */
Jeff Hartmannba1b1ae2000-04-04 22:08:14 +00002019unsigned int drmAgpVendorId(int fd)
2020{
2021 drm_agp_info_t i;
2022
Daniel Vetterfd387942015-02-11 12:41:04 +01002023 memclear(i);
2024
Keith Packard8b9ab102008-06-13 16:03:22 -07002025 if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
Brianccd7b6e2007-05-29 14:54:00 -06002026 return 0;
Jeff Hartmannba1b1ae2000-04-04 22:08:14 +00002027 return i.id_vendor;
2028}
2029
Jose Fonsecad2443b22003-05-27 00:37:33 +00002030
2031/**
2032 * Get hardware device ID.
2033 *
2034 * \param fd file descriptor.
2035 *
2036 * \return zero on success, or zero on failure.
2037 *
2038 * \internal
2039 * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
2040 * necessary information in a drm_agp_info structure.
2041 */
Jeff Hartmannba1b1ae2000-04-04 22:08:14 +00002042unsigned int drmAgpDeviceId(int fd)
2043{
2044 drm_agp_info_t i;
2045
Daniel Vetterfd387942015-02-11 12:41:04 +01002046 memclear(i);
2047
Keith Packard8b9ab102008-06-13 16:03:22 -07002048 if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
Brianccd7b6e2007-05-29 14:54:00 -06002049 return 0;
Jeff Hartmannba1b1ae2000-04-04 22:08:14 +00002050 return i.id_device;
2051}
2052
Dave Airlie7ede2092005-11-29 09:50:47 +00002053int drmScatterGatherAlloc(int fd, unsigned long size, drm_handle_t *handle)
Kevin E Martin5d6ddbc2001-04-05 22:16:12 +00002054{
2055 drm_scatter_gather_t sg;
2056
Daniel Vetterfd387942015-02-11 12:41:04 +01002057 memclear(sg);
2058
Kevin E Martin5d6ddbc2001-04-05 22:16:12 +00002059 *handle = 0;
2060 sg.size = size;
Keith Packard8b9ab102008-06-13 16:03:22 -07002061 if (drmIoctl(fd, DRM_IOCTL_SG_ALLOC, &sg))
Brianccd7b6e2007-05-29 14:54:00 -06002062 return -errno;
Kevin E Martin5d6ddbc2001-04-05 22:16:12 +00002063 *handle = sg.handle;
2064 return 0;
2065}
2066
Dave Airlie7ede2092005-11-29 09:50:47 +00002067int drmScatterGatherFree(int fd, drm_handle_t handle)
Kevin E Martin5d6ddbc2001-04-05 22:16:12 +00002068{
2069 drm_scatter_gather_t sg;
2070
Daniel Vetterfd387942015-02-11 12:41:04 +01002071 memclear(sg);
Kevin E Martin5d6ddbc2001-04-05 22:16:12 +00002072 sg.handle = handle;
Keith Packard8b9ab102008-06-13 16:03:22 -07002073 if (drmIoctl(fd, DRM_IOCTL_SG_FREE, &sg))
Brianccd7b6e2007-05-29 14:54:00 -06002074 return -errno;
Kevin E Martin5d6ddbc2001-04-05 22:16:12 +00002075 return 0;
2076}
2077
Jose Fonsecad2443b22003-05-27 00:37:33 +00002078/**
2079 * Wait for VBLANK.
2080 *
2081 * \param fd file descriptor.
2082 * \param vbl pointer to a drmVBlank structure.
2083 *
2084 * \return zero on success, or a negative value on failure.
2085 *
2086 * \internal
2087 * This function is a wrapper around the DRM_IOCTL_WAIT_VBLANK ioctl.
2088 */
Michel Daenzer55acd0d2002-09-25 17:18:19 +00002089int drmWaitVBlank(int fd, drmVBlankPtr vbl)
2090{
Jesse Barnesf4f76a62009-01-07 10:18:08 -08002091 struct timespec timeout, cur;
Michel Daenzer55acd0d2002-09-25 17:18:19 +00002092 int ret;
2093
Jesse Barnesf4f76a62009-01-07 10:18:08 -08002094 ret = clock_gettime(CLOCK_MONOTONIC, &timeout);
2095 if (ret < 0) {
Daniel Kurtz1eb28602013-03-28 14:05:40 +08002096 fprintf(stderr, "clock_gettime failed: %s\n", strerror(errno));
Jesse Barnesf4f76a62009-01-07 10:18:08 -08002097 goto out;
2098 }
2099 timeout.tv_sec++;
2100
Michel Daenzer55acd0d2002-09-25 17:18:19 +00002101 do {
Jesse Barnesf4f76a62009-01-07 10:18:08 -08002102 ret = ioctl(fd, DRM_IOCTL_WAIT_VBLANK, vbl);
Michel Daenzerc7d471b2003-02-02 03:06:47 +00002103 vbl->request.type &= ~DRM_VBLANK_RELATIVE;
Jesse Barnesca370772009-01-07 10:48:26 -08002104 if (ret && errno == EINTR) {
2105 clock_gettime(CLOCK_MONOTONIC, &cur);
2106 /* Timeout after 1s */
2107 if (cur.tv_sec > timeout.tv_sec + 1 ||
2108 (cur.tv_sec == timeout.tv_sec && cur.tv_nsec >=
2109 timeout.tv_nsec)) {
2110 errno = EBUSY;
2111 ret = -1;
2112 break;
2113 }
Jesse Barnesf4f76a62009-01-07 10:18:08 -08002114 }
Michel Daenzer55acd0d2002-09-25 17:18:19 +00002115 } while (ret && errno == EINTR);
2116
Jesse Barnesf4f76a62009-01-07 10:18:08 -08002117out:
Michel Daenzer55acd0d2002-09-25 17:18:19 +00002118 return ret;
2119}
2120
Daryll Straussb3a57661999-12-05 01:19:48 +00002121int drmError(int err, const char *label)
2122{
2123 switch (err) {
Brianccd7b6e2007-05-29 14:54:00 -06002124 case DRM_ERR_NO_DEVICE:
2125 fprintf(stderr, "%s: no device\n", label);
2126 break;
2127 case DRM_ERR_NO_ACCESS:
2128 fprintf(stderr, "%s: no access\n", label);
2129 break;
2130 case DRM_ERR_NOT_ROOT:
2131 fprintf(stderr, "%s: not root\n", label);
2132 break;
2133 case DRM_ERR_INVALID:
2134 fprintf(stderr, "%s: invalid args\n", label);
2135 break;
Daryll Straussb3a57661999-12-05 01:19:48 +00002136 default:
Brianccd7b6e2007-05-29 14:54:00 -06002137 if (err < 0)
2138 err = -err;
Daryll Straussb3a57661999-12-05 01:19:48 +00002139 fprintf( stderr, "%s: error %d (%s)\n", label, err, strerror(err) );
2140 break;
2141 }
2142
2143 return 1;
2144}
2145
Jose Fonsecad2443b22003-05-27 00:37:33 +00002146/**
2147 * Install IRQ handler.
2148 *
2149 * \param fd file descriptor.
2150 * \param irq IRQ number.
2151 *
2152 * \return zero on success, or a negative value on failure.
2153 *
2154 * \internal
2155 * This function is a wrapper around the DRM_IOCTL_CONTROL ioctl, passing the
2156 * argument in a drm_control structure.
2157 */
Daryll Straussb3a57661999-12-05 01:19:48 +00002158int drmCtlInstHandler(int fd, int irq)
2159{
2160 drm_control_t ctl;
2161
Daniel Vetterfd387942015-02-11 12:41:04 +01002162 memclear(ctl);
Daryll Straussb3a57661999-12-05 01:19:48 +00002163 ctl.func = DRM_INST_HANDLER;
Daryll Straussb3a57661999-12-05 01:19:48 +00002164 ctl.irq = irq;
Keith Packard8b9ab102008-06-13 16:03:22 -07002165 if (drmIoctl(fd, DRM_IOCTL_CONTROL, &ctl))
Brianccd7b6e2007-05-29 14:54:00 -06002166 return -errno;
Daryll Straussb3a57661999-12-05 01:19:48 +00002167 return 0;
2168}
2169
Jose Fonsecad2443b22003-05-27 00:37:33 +00002170
2171/**
2172 * Uninstall IRQ handler.
2173 *
2174 * \param fd file descriptor.
2175 *
2176 * \return zero on success, or a negative value on failure.
2177 *
2178 * \internal
2179 * This function is a wrapper around the DRM_IOCTL_CONTROL ioctl, passing the
2180 * argument in a drm_control structure.
2181 */
Daryll Straussb3a57661999-12-05 01:19:48 +00002182int drmCtlUninstHandler(int fd)
2183{
2184 drm_control_t ctl;
2185
Daniel Vetterfd387942015-02-11 12:41:04 +01002186 memclear(ctl);
Daryll Straussb3a57661999-12-05 01:19:48 +00002187 ctl.func = DRM_UNINST_HANDLER;
Daryll Straussb3a57661999-12-05 01:19:48 +00002188 ctl.irq = 0;
Keith Packard8b9ab102008-06-13 16:03:22 -07002189 if (drmIoctl(fd, DRM_IOCTL_CONTROL, &ctl))
Brianccd7b6e2007-05-29 14:54:00 -06002190 return -errno;
Daryll Straussb3a57661999-12-05 01:19:48 +00002191 return 0;
2192}
2193
2194int drmFinish(int fd, int context, drmLockFlags flags)
2195{
2196 drm_lock_t lock;
2197
Daniel Vetterfd387942015-02-11 12:41:04 +01002198 memclear(lock);
Daryll Straussb3a57661999-12-05 01:19:48 +00002199 lock.context = context;
Daryll Straussb3a57661999-12-05 01:19:48 +00002200 if (flags & DRM_LOCK_READY) lock.flags |= _DRM_LOCK_READY;
2201 if (flags & DRM_LOCK_QUIESCENT) lock.flags |= _DRM_LOCK_QUIESCENT;
2202 if (flags & DRM_LOCK_FLUSH) lock.flags |= _DRM_LOCK_FLUSH;
2203 if (flags & DRM_LOCK_FLUSH_ALL) lock.flags |= _DRM_LOCK_FLUSH_ALL;
2204 if (flags & DRM_HALT_ALL_QUEUES) lock.flags |= _DRM_HALT_ALL_QUEUES;
2205 if (flags & DRM_HALT_CUR_QUEUES) lock.flags |= _DRM_HALT_CUR_QUEUES;
Keith Packard8b9ab102008-06-13 16:03:22 -07002206 if (drmIoctl(fd, DRM_IOCTL_FINISH, &lock))
Brianccd7b6e2007-05-29 14:54:00 -06002207 return -errno;
Daryll Straussb3a57661999-12-05 01:19:48 +00002208 return 0;
2209}
2210
Jose Fonsecad2443b22003-05-27 00:37:33 +00002211/**
2212 * Get IRQ from bus ID.
2213 *
2214 * \param fd file descriptor.
2215 * \param busnum bus number.
2216 * \param devnum device number.
2217 * \param funcnum function number.
2218 *
2219 * \return IRQ number on success, or a negative value on failure.
2220 *
2221 * \internal
2222 * This function is a wrapper around the DRM_IOCTL_IRQ_BUSID ioctl, passing the
2223 * arguments in a drm_irq_busid structure.
2224 */
Daryll Straussb3a57661999-12-05 01:19:48 +00002225int drmGetInterruptFromBusID(int fd, int busnum, int devnum, int funcnum)
2226{
2227 drm_irq_busid_t p;
2228
Daniel Vetterfd387942015-02-11 12:41:04 +01002229 memclear(p);
Daryll Straussb3a57661999-12-05 01:19:48 +00002230 p.busnum = busnum;
2231 p.devnum = devnum;
2232 p.funcnum = funcnum;
Keith Packard8b9ab102008-06-13 16:03:22 -07002233 if (drmIoctl(fd, DRM_IOCTL_IRQ_BUSID, &p))
Brianccd7b6e2007-05-29 14:54:00 -06002234 return -errno;
Daryll Straussb3a57661999-12-05 01:19:48 +00002235 return p.irq;
2236}
2237
Jon Smirl8696e712004-07-07 04:36:36 +00002238int drmAddContextTag(int fd, drm_context_t context, void *tag)
Daryll Straussb3a57661999-12-05 01:19:48 +00002239{
2240 drmHashEntry *entry = drmGetEntry(fd);
2241
2242 if (drmHashInsert(entry->tagTable, context, tag)) {
2243 drmHashDelete(entry->tagTable, context);
2244 drmHashInsert(entry->tagTable, context, tag);
2245 }
2246 return 0;
2247}
2248
Jon Smirl8696e712004-07-07 04:36:36 +00002249int drmDelContextTag(int fd, drm_context_t context)
Daryll Straussb3a57661999-12-05 01:19:48 +00002250{
2251 drmHashEntry *entry = drmGetEntry(fd);
2252
2253 return drmHashDelete(entry->tagTable, context);
2254}
2255
Jon Smirl8696e712004-07-07 04:36:36 +00002256void *drmGetContextTag(int fd, drm_context_t context)
Daryll Straussb3a57661999-12-05 01:19:48 +00002257{
2258 drmHashEntry *entry = drmGetEntry(fd);
2259 void *value;
Gareth Hughes36047532001-02-15 08:12:14 +00002260
Brianccd7b6e2007-05-29 14:54:00 -06002261 if (drmHashLookup(entry->tagTable, context, &value))
2262 return NULL;
Daryll Straussb3a57661999-12-05 01:19:48 +00002263
2264 return value;
2265}
2266
Adam Jackson22e41ef2006-02-20 23:09:00 +00002267int drmAddContextPrivateMapping(int fd, drm_context_t ctx_id,
2268 drm_handle_t handle)
Kevin E Martin74e19a42001-03-14 22:22:50 +00002269{
2270 drm_ctx_priv_map_t map;
2271
Daniel Vetterfd387942015-02-11 12:41:04 +01002272 memclear(map);
Kevin E Martin74e19a42001-03-14 22:22:50 +00002273 map.ctx_id = ctx_id;
Jeremy Huddleston961bf9b2011-11-01 14:42:13 -07002274 map.handle = (void *)(uintptr_t)handle;
Kevin E Martin74e19a42001-03-14 22:22:50 +00002275
Keith Packard8b9ab102008-06-13 16:03:22 -07002276 if (drmIoctl(fd, DRM_IOCTL_SET_SAREA_CTX, &map))
Brianccd7b6e2007-05-29 14:54:00 -06002277 return -errno;
Kevin E Martin74e19a42001-03-14 22:22:50 +00002278 return 0;
2279}
2280
Adam Jackson22e41ef2006-02-20 23:09:00 +00002281int drmGetContextPrivateMapping(int fd, drm_context_t ctx_id,
2282 drm_handle_t *handle)
Kevin E Martin74e19a42001-03-14 22:22:50 +00002283{
2284 drm_ctx_priv_map_t map;
2285
Daniel Vetterfd387942015-02-11 12:41:04 +01002286 memclear(map);
Kevin E Martin74e19a42001-03-14 22:22:50 +00002287 map.ctx_id = ctx_id;
2288
Keith Packard8b9ab102008-06-13 16:03:22 -07002289 if (drmIoctl(fd, DRM_IOCTL_GET_SAREA_CTX, &map))
Brianccd7b6e2007-05-29 14:54:00 -06002290 return -errno;
2291 if (handle)
Jeremy Huddleston961bf9b2011-11-01 14:42:13 -07002292 *handle = (drm_handle_t)(uintptr_t)map.handle;
Kevin E Martin74e19a42001-03-14 22:22:50 +00002293
2294 return 0;
2295}
2296
Jon Smirl8696e712004-07-07 04:36:36 +00002297int drmGetMap(int fd, int idx, drm_handle_t *offset, drmSize *size,
2298 drmMapType *type, drmMapFlags *flags, drm_handle_t *handle,
Rik Faith88dbee52001-02-28 09:27:44 +00002299 int *mtrr)
2300{
2301 drm_map_t map;
2302
Daniel Vetterfd387942015-02-11 12:41:04 +01002303 memclear(map);
Rik Faith88dbee52001-02-28 09:27:44 +00002304 map.offset = idx;
Keith Packard8b9ab102008-06-13 16:03:22 -07002305 if (drmIoctl(fd, DRM_IOCTL_GET_MAP, &map))
Brianccd7b6e2007-05-29 14:54:00 -06002306 return -errno;
Rik Faith88dbee52001-02-28 09:27:44 +00002307 *offset = map.offset;
2308 *size = map.size;
2309 *type = map.type;
2310 *flags = map.flags;
2311 *handle = (unsigned long)map.handle;
2312 *mtrr = map.mtrr;
2313 return 0;
2314}
2315
2316int drmGetClient(int fd, int idx, int *auth, int *pid, int *uid,
2317 unsigned long *magic, unsigned long *iocs)
2318{
2319 drm_client_t client;
2320
Daniel Vetterfd387942015-02-11 12:41:04 +01002321 memclear(client);
Rik Faith88dbee52001-02-28 09:27:44 +00002322 client.idx = idx;
Keith Packard8b9ab102008-06-13 16:03:22 -07002323 if (drmIoctl(fd, DRM_IOCTL_GET_CLIENT, &client))
Brianccd7b6e2007-05-29 14:54:00 -06002324 return -errno;
Rik Faith88dbee52001-02-28 09:27:44 +00002325 *auth = client.auth;
2326 *pid = client.pid;
2327 *uid = client.uid;
2328 *magic = client.magic;
2329 *iocs = client.iocs;
2330 return 0;
2331}
2332
2333int drmGetStats(int fd, drmStatsT *stats)
2334{
2335 drm_stats_t s;
Jan Veselyde8532d2014-11-30 12:53:18 -05002336 unsigned i;
Rik Faith88dbee52001-02-28 09:27:44 +00002337
Daniel Vetterfd387942015-02-11 12:41:04 +01002338 memclear(s);
Keith Packard8b9ab102008-06-13 16:03:22 -07002339 if (drmIoctl(fd, DRM_IOCTL_GET_STATS, &s))
Brianccd7b6e2007-05-29 14:54:00 -06002340 return -errno;
Rik Faith88dbee52001-02-28 09:27:44 +00002341
2342 stats->count = 0;
2343 memset(stats, 0, sizeof(*stats));
2344 if (s.count > sizeof(stats->data)/sizeof(stats->data[0]))
2345 return -1;
2346
2347#define SET_VALUE \
2348 stats->data[i].long_format = "%-20.20s"; \
2349 stats->data[i].rate_format = "%8.8s"; \
2350 stats->data[i].isvalue = 1; \
2351 stats->data[i].verbose = 0
2352
2353#define SET_COUNT \
2354 stats->data[i].long_format = "%-20.20s"; \
2355 stats->data[i].rate_format = "%5.5s"; \
2356 stats->data[i].isvalue = 0; \
2357 stats->data[i].mult_names = "kgm"; \
2358 stats->data[i].mult = 1000; \
2359 stats->data[i].verbose = 0
2360
2361#define SET_BYTE \
2362 stats->data[i].long_format = "%-20.20s"; \
2363 stats->data[i].rate_format = "%5.5s"; \
2364 stats->data[i].isvalue = 0; \
2365 stats->data[i].mult_names = "KGM"; \
2366 stats->data[i].mult = 1024; \
2367 stats->data[i].verbose = 0
2368
2369
2370 stats->count = s.count;
2371 for (i = 0; i < s.count; i++) {
2372 stats->data[i].value = s.data[i].value;
2373 switch (s.data[i].type) {
2374 case _DRM_STAT_LOCK:
2375 stats->data[i].long_name = "Lock";
2376 stats->data[i].rate_name = "Lock";
2377 SET_VALUE;
2378 break;
2379 case _DRM_STAT_OPENS:
2380 stats->data[i].long_name = "Opens";
2381 stats->data[i].rate_name = "O";
2382 SET_COUNT;
2383 stats->data[i].verbose = 1;
2384 break;
2385 case _DRM_STAT_CLOSES:
2386 stats->data[i].long_name = "Closes";
2387 stats->data[i].rate_name = "Lock";
2388 SET_COUNT;
2389 stats->data[i].verbose = 1;
2390 break;
2391 case _DRM_STAT_IOCTLS:
2392 stats->data[i].long_name = "Ioctls";
2393 stats->data[i].rate_name = "Ioc/s";
2394 SET_COUNT;
2395 break;
2396 case _DRM_STAT_LOCKS:
2397 stats->data[i].long_name = "Locks";
2398 stats->data[i].rate_name = "Lck/s";
2399 SET_COUNT;
2400 break;
2401 case _DRM_STAT_UNLOCKS:
2402 stats->data[i].long_name = "Unlocks";
2403 stats->data[i].rate_name = "Unl/s";
2404 SET_COUNT;
2405 break;
2406 case _DRM_STAT_IRQ:
2407 stats->data[i].long_name = "IRQs";
2408 stats->data[i].rate_name = "IRQ/s";
2409 SET_COUNT;
2410 break;
2411 case _DRM_STAT_PRIMARY:
2412 stats->data[i].long_name = "Primary Bytes";
2413 stats->data[i].rate_name = "PB/s";
2414 SET_BYTE;
2415 break;
2416 case _DRM_STAT_SECONDARY:
2417 stats->data[i].long_name = "Secondary Bytes";
2418 stats->data[i].rate_name = "SB/s";
2419 SET_BYTE;
2420 break;
2421 case _DRM_STAT_DMA:
2422 stats->data[i].long_name = "DMA";
2423 stats->data[i].rate_name = "DMA/s";
2424 SET_COUNT;
2425 break;
2426 case _DRM_STAT_SPECIAL:
2427 stats->data[i].long_name = "Special DMA";
2428 stats->data[i].rate_name = "dma/s";
2429 SET_COUNT;
2430 break;
2431 case _DRM_STAT_MISSED:
2432 stats->data[i].long_name = "Miss";
2433 stats->data[i].rate_name = "Ms/s";
2434 SET_COUNT;
2435 break;
2436 case _DRM_STAT_VALUE:
2437 stats->data[i].long_name = "Value";
2438 stats->data[i].rate_name = "Value";
2439 SET_VALUE;
2440 break;
2441 case _DRM_STAT_BYTE:
2442 stats->data[i].long_name = "Bytes";
2443 stats->data[i].rate_name = "B/s";
2444 SET_BYTE;
2445 break;
2446 case _DRM_STAT_COUNT:
2447 default:
2448 stats->data[i].long_name = "Count";
2449 stats->data[i].rate_name = "Cnt/s";
2450 SET_COUNT;
2451 break;
2452 }
2453 }
2454 return 0;
2455}
2456
Jose Fonsecad2443b22003-05-27 00:37:33 +00002457/**
Eric Anholt06cb1322003-10-23 02:23:31 +00002458 * Issue a set-version ioctl.
2459 *
2460 * \param fd file descriptor.
2461 * \param drmCommandIndex command index
2462 * \param data source pointer of the data to be read and written.
2463 * \param size size of the data to be read and written.
2464 *
2465 * \return zero on success, or a negative value on failure.
2466 *
2467 * \internal
2468 * It issues a read-write ioctl given by
2469 * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
2470 */
Adam Jackson22e41ef2006-02-20 23:09:00 +00002471int drmSetInterfaceVersion(int fd, drmSetVersion *version)
Eric Anholt06cb1322003-10-23 02:23:31 +00002472{
2473 int retcode = 0;
2474 drm_set_version_t sv;
2475
Daniel Vetterfd387942015-02-11 12:41:04 +01002476 memclear(sv);
Eric Anholt06cb1322003-10-23 02:23:31 +00002477 sv.drm_di_major = version->drm_di_major;
2478 sv.drm_di_minor = version->drm_di_minor;
2479 sv.drm_dd_major = version->drm_dd_major;
2480 sv.drm_dd_minor = version->drm_dd_minor;
2481
Keith Packard8b9ab102008-06-13 16:03:22 -07002482 if (drmIoctl(fd, DRM_IOCTL_SET_VERSION, &sv)) {
Eric Anholt06cb1322003-10-23 02:23:31 +00002483 retcode = -errno;
2484 }
2485
2486 version->drm_di_major = sv.drm_di_major;
2487 version->drm_di_minor = sv.drm_di_minor;
2488 version->drm_dd_major = sv.drm_dd_major;
2489 version->drm_dd_minor = sv.drm_dd_minor;
2490
2491 return retcode;
2492}
2493
2494/**
Jose Fonsecad2443b22003-05-27 00:37:33 +00002495 * Send a device-specific command.
2496 *
2497 * \param fd file descriptor.
2498 * \param drmCommandIndex command index
2499 *
2500 * \return zero on success, or a negative value on failure.
2501 *
2502 * \internal
2503 * It issues a ioctl given by
2504 * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
2505 */
Jens Owen3903e5a2002-04-09 21:54:56 +00002506int drmCommandNone(int fd, unsigned long drmCommandIndex)
2507{
Jens Owen3903e5a2002-04-09 21:54:56 +00002508 unsigned long request;
2509
2510 request = DRM_IO( DRM_COMMAND_BASE + drmCommandIndex);
2511
Daniel Vetterfd387942015-02-11 12:41:04 +01002512 if (drmIoctl(fd, request, NULL)) {
Jens Owen3903e5a2002-04-09 21:54:56 +00002513 return -errno;
2514 }
2515 return 0;
2516}
2517
Jose Fonsecad2443b22003-05-27 00:37:33 +00002518
2519/**
2520 * Send a device-specific read command.
2521 *
2522 * \param fd file descriptor.
2523 * \param drmCommandIndex command index
2524 * \param data destination pointer of the data to be read.
2525 * \param size size of the data to be read.
2526 *
2527 * \return zero on success, or a negative value on failure.
2528 *
2529 * \internal
2530 * It issues a read ioctl given by
2531 * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
2532 */
Adam Jackson22e41ef2006-02-20 23:09:00 +00002533int drmCommandRead(int fd, unsigned long drmCommandIndex, void *data,
2534 unsigned long size)
Jens Owen3903e5a2002-04-09 21:54:56 +00002535{
2536 unsigned long request;
2537
Alan Hourihane74ef13f2002-07-05 08:31:11 +00002538 request = DRM_IOC( DRM_IOC_READ, DRM_IOCTL_BASE,
2539 DRM_COMMAND_BASE + drmCommandIndex, size);
Jens Owen3903e5a2002-04-09 21:54:56 +00002540
Keith Packard8b9ab102008-06-13 16:03:22 -07002541 if (drmIoctl(fd, request, data)) {
Jens Owen3903e5a2002-04-09 21:54:56 +00002542 return -errno;
2543 }
2544 return 0;
2545}
2546
Jose Fonsecad2443b22003-05-27 00:37:33 +00002547
2548/**
2549 * Send a device-specific write command.
2550 *
2551 * \param fd file descriptor.
2552 * \param drmCommandIndex command index
2553 * \param data source pointer of the data to be written.
2554 * \param size size of the data to be written.
2555 *
2556 * \return zero on success, or a negative value on failure.
2557 *
2558 * \internal
2559 * It issues a write ioctl given by
2560 * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
2561 */
Adam Jackson22e41ef2006-02-20 23:09:00 +00002562int drmCommandWrite(int fd, unsigned long drmCommandIndex, void *data,
2563 unsigned long size)
Jens Owen3903e5a2002-04-09 21:54:56 +00002564{
2565 unsigned long request;
2566
Alan Hourihane74ef13f2002-07-05 08:31:11 +00002567 request = DRM_IOC( DRM_IOC_WRITE, DRM_IOCTL_BASE,
2568 DRM_COMMAND_BASE + drmCommandIndex, size);
Jens Owen3903e5a2002-04-09 21:54:56 +00002569
Keith Packard8b9ab102008-06-13 16:03:22 -07002570 if (drmIoctl(fd, request, data)) {
Jens Owen3903e5a2002-04-09 21:54:56 +00002571 return -errno;
2572 }
2573 return 0;
2574}
2575
Jose Fonsecad2443b22003-05-27 00:37:33 +00002576
2577/**
2578 * Send a device-specific read-write command.
2579 *
2580 * \param fd file descriptor.
2581 * \param drmCommandIndex command index
2582 * \param data source pointer of the data to be read and written.
2583 * \param size size of the data to be read and written.
2584 *
2585 * \return zero on success, or a negative value on failure.
2586 *
2587 * \internal
2588 * It issues a read-write ioctl given by
2589 * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
2590 */
Adam Jackson22e41ef2006-02-20 23:09:00 +00002591int drmCommandWriteRead(int fd, unsigned long drmCommandIndex, void *data,
2592 unsigned long size)
Jens Owen3903e5a2002-04-09 21:54:56 +00002593{
2594 unsigned long request;
2595
Alan Hourihane74ef13f2002-07-05 08:31:11 +00002596 request = DRM_IOC( DRM_IOC_READ|DRM_IOC_WRITE, DRM_IOCTL_BASE,
2597 DRM_COMMAND_BASE + drmCommandIndex, size);
Jens Owen3903e5a2002-04-09 21:54:56 +00002598
Keith Packard8b9ab102008-06-13 16:03:22 -07002599 if (drmIoctl(fd, request, data))
Jens Owen3903e5a2002-04-09 21:54:56 +00002600 return -errno;
Jens Owen3903e5a2002-04-09 21:54:56 +00002601 return 0;
2602}
Thomas Hellstrom166da932006-08-21 21:02:08 +02002603
Dave Airlied51e1bb2006-11-09 08:55:58 +11002604#define DRM_MAX_FDS 16
2605static struct {
Brianccd7b6e2007-05-29 14:54:00 -06002606 char *BusID;
2607 int fd;
2608 int refcount;
Jammy Zhoudbc8b112015-02-02 18:06:27 +08002609 int type;
Dave Airlied51e1bb2006-11-09 08:55:58 +11002610} connection[DRM_MAX_FDS];
2611
2612static int nr_fds = 0;
2613
2614int drmOpenOnce(void *unused,
2615 const char *BusID,
2616 int *newlyopened)
2617{
Jammy Zhoudbc8b112015-02-02 18:06:27 +08002618 return drmOpenOnceWithType(BusID, newlyopened, DRM_NODE_PRIMARY);
2619}
2620
2621int drmOpenOnceWithType(const char *BusID, int *newlyopened, int type)
2622{
Brianccd7b6e2007-05-29 14:54:00 -06002623 int i;
2624 int fd;
Dave Airlied51e1bb2006-11-09 08:55:58 +11002625
Brianccd7b6e2007-05-29 14:54:00 -06002626 for (i = 0; i < nr_fds; i++)
Jammy Zhoudbc8b112015-02-02 18:06:27 +08002627 if ((strcmp(BusID, connection[i].BusID) == 0) &&
2628 (connection[i].type == type)) {
Brianccd7b6e2007-05-29 14:54:00 -06002629 connection[i].refcount++;
2630 *newlyopened = 0;
2631 return connection[i].fd;
2632 }
Dave Airlied51e1bb2006-11-09 08:55:58 +11002633
Jammy Zhoudbc8b112015-02-02 18:06:27 +08002634 fd = drmOpenWithType(NULL, BusID, type);
Emil Velikovc1cd3d92015-07-14 15:05:18 +01002635 if (fd < 0 || nr_fds == DRM_MAX_FDS)
Brianccd7b6e2007-05-29 14:54:00 -06002636 return fd;
Dave Airlied51e1bb2006-11-09 08:55:58 +11002637
Brianccd7b6e2007-05-29 14:54:00 -06002638 connection[nr_fds].BusID = strdup(BusID);
2639 connection[nr_fds].fd = fd;
2640 connection[nr_fds].refcount = 1;
Jammy Zhoudbc8b112015-02-02 18:06:27 +08002641 connection[nr_fds].type = type;
Brianccd7b6e2007-05-29 14:54:00 -06002642 *newlyopened = 1;
Dave Airlied51e1bb2006-11-09 08:55:58 +11002643
Brianccd7b6e2007-05-29 14:54:00 -06002644 if (0)
2645 fprintf(stderr, "saved connection %d for %s %d\n",
2646 nr_fds, connection[nr_fds].BusID,
2647 strcmp(BusID, connection[nr_fds].BusID));
Dave Airlied51e1bb2006-11-09 08:55:58 +11002648
Brianccd7b6e2007-05-29 14:54:00 -06002649 nr_fds++;
Dave Airlied51e1bb2006-11-09 08:55:58 +11002650
Brianccd7b6e2007-05-29 14:54:00 -06002651 return fd;
Dave Airlied51e1bb2006-11-09 08:55:58 +11002652}
2653
2654void drmCloseOnce(int fd)
2655{
Brianccd7b6e2007-05-29 14:54:00 -06002656 int i;
Dave Airlied51e1bb2006-11-09 08:55:58 +11002657
Brianccd7b6e2007-05-29 14:54:00 -06002658 for (i = 0; i < nr_fds; i++) {
2659 if (fd == connection[i].fd) {
2660 if (--connection[i].refcount == 0) {
2661 drmClose(connection[i].fd);
2662 free(connection[i].BusID);
Dave Airlied51e1bb2006-11-09 08:55:58 +11002663
Brianccd7b6e2007-05-29 14:54:00 -06002664 if (i < --nr_fds)
2665 connection[i] = connection[nr_fds];
Dave Airlied51e1bb2006-11-09 08:55:58 +11002666
Brianccd7b6e2007-05-29 14:54:00 -06002667 return;
2668 }
2669 }
2670 }
Dave Airlied51e1bb2006-11-09 08:55:58 +11002671}
Jesse Barnes731cd552008-12-17 10:09:49 -08002672
2673int drmSetMaster(int fd)
2674{
Daniel Vetterfd387942015-02-11 12:41:04 +01002675 return drmIoctl(fd, DRM_IOCTL_SET_MASTER, NULL);
Jesse Barnes731cd552008-12-17 10:09:49 -08002676}
2677
2678int drmDropMaster(int fd)
2679{
Daniel Vetterfd387942015-02-11 12:41:04 +01002680 return drmIoctl(fd, DRM_IOCTL_DROP_MASTER, NULL);
Jesse Barnes731cd552008-12-17 10:09:49 -08002681}
Kristian Høgsberg22d46662009-11-23 20:51:34 -05002682
2683char *drmGetDeviceNameFromFd(int fd)
2684{
2685 char name[128];
2686 struct stat sbuf;
2687 dev_t d;
2688 int i;
2689
2690 /* The whole drmOpen thing is a fiasco and we need to find a way
2691 * back to just using open(2). For now, however, lets just make
2692 * things worse with even more ad hoc directory walking code to
2693 * discover the device file name. */
2694
2695 fstat(fd, &sbuf);
2696 d = sbuf.st_rdev;
2697
2698 for (i = 0; i < DRM_MAX_MINOR; i++) {
2699 snprintf(name, sizeof name, DRM_DEV_NAME, DRM_DIR_NAME, i);
2700 if (stat(name, &sbuf) == 0 && sbuf.st_rdev == d)
2701 break;
2702 }
2703 if (i == DRM_MAX_MINOR)
2704 return NULL;
2705
Adam Jackson0a1ff352010-10-27 18:44:53 -04002706 return strdup(name);
Kristian Høgsberg22d46662009-11-23 20:51:34 -05002707}
Dave Airliecc0a1452012-07-14 09:52:17 +00002708
Frank Binns1f735782015-02-13 10:51:15 +00002709int drmGetNodeTypeFromFd(int fd)
2710{
2711 struct stat sbuf;
2712 int maj, min, type;
2713
2714 if (fstat(fd, &sbuf))
2715 return -1;
2716
2717 maj = major(sbuf.st_rdev);
2718 min = minor(sbuf.st_rdev);
2719
2720 if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode)) {
2721 errno = EINVAL;
2722 return -1;
2723 }
2724
2725 type = drmGetMinorType(min);
2726 if (type == -1)
2727 errno = ENODEV;
2728 return type;
2729}
2730
Dave Airliecc0a1452012-07-14 09:52:17 +00002731int drmPrimeHandleToFD(int fd, uint32_t handle, uint32_t flags, int *prime_fd)
2732{
2733 struct drm_prime_handle args;
2734 int ret;
2735
Guillaume Desmottes4bca42f2015-04-29 10:16:22 +02002736 memclear(args);
2737 args.fd = -1;
Dave Airliecc0a1452012-07-14 09:52:17 +00002738 args.handle = handle;
2739 args.flags = flags;
2740 ret = drmIoctl(fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &args);
2741 if (ret)
2742 return ret;
2743
2744 *prime_fd = args.fd;
2745 return 0;
2746}
2747
2748int drmPrimeFDToHandle(int fd, int prime_fd, uint32_t *handle)
2749{
2750 struct drm_prime_handle args;
2751 int ret;
2752
Guillaume Desmottes4bca42f2015-04-29 10:16:22 +02002753 memclear(args);
Dave Airliecc0a1452012-07-14 09:52:17 +00002754 args.fd = prime_fd;
Dave Airliecc0a1452012-07-14 09:52:17 +00002755 ret = drmIoctl(fd, DRM_IOCTL_PRIME_FD_TO_HANDLE, &args);
2756 if (ret)
2757 return ret;
2758
2759 *handle = args.handle;
2760 return 0;
2761}
2762
Emil Velikov0ca03a42015-03-07 00:58:39 +00002763static char *drmGetMinorNameForFD(int fd, int type)
2764{
2765#ifdef __linux__
2766 DIR *sysdir;
2767 struct dirent *pent, *ent;
2768 struct stat sbuf;
2769 const char *name = drmGetMinorName(type);
2770 int len;
2771 char dev_name[64], buf[64];
2772 long name_max;
2773 int maj, min;
2774
2775 if (!name)
2776 return NULL;
2777
2778 len = strlen(name);
2779
2780 if (fstat(fd, &sbuf))
2781 return NULL;
2782
2783 maj = major(sbuf.st_rdev);
2784 min = minor(sbuf.st_rdev);
2785
2786 if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode))
2787 return NULL;
2788
2789 snprintf(buf, sizeof(buf), "/sys/dev/char/%d:%d/device/drm", maj, min);
2790
2791 sysdir = opendir(buf);
2792 if (!sysdir)
2793 return NULL;
2794
2795 name_max = fpathconf(dirfd(sysdir), _PC_NAME_MAX);
2796 if (name_max == -1)
2797 goto out_close_dir;
2798
2799 pent = malloc(offsetof(struct dirent, d_name) + name_max + 1);
2800 if (pent == NULL)
2801 goto out_close_dir;
2802
2803 while (readdir_r(sysdir, pent, &ent) == 0 && ent != NULL) {
2804 if (strncmp(ent->d_name, name, len) == 0) {
Mathias Tillman5c42b5e2015-08-24 11:56:13 +08002805 snprintf(dev_name, sizeof(dev_name), DRM_DIR_NAME "/%s",
2806 ent->d_name);
2807
Emil Velikov0ca03a42015-03-07 00:58:39 +00002808 free(pent);
2809 closedir(sysdir);
2810
Emil Velikov0ca03a42015-03-07 00:58:39 +00002811 return strdup(dev_name);
2812 }
2813 }
2814
2815 free(pent);
2816
2817out_close_dir:
2818 closedir(sysdir);
Emil Velikov8415a002015-09-07 18:29:05 +01002819#else
2820#warning "Missing implementation of drmGetMinorNameForFD"
Emil Velikov0ca03a42015-03-07 00:58:39 +00002821#endif
2822 return NULL;
2823}
2824
2825char *drmGetPrimaryDeviceNameFromFd(int fd)
2826{
2827 return drmGetMinorNameForFD(fd, DRM_NODE_PRIMARY);
2828}
2829
2830char *drmGetRenderDeviceNameFromFd(int fd)
2831{
2832 return drmGetMinorNameForFD(fd, DRM_NODE_RENDER);
2833}
Emil Velikovb556ea12015-08-17 11:09:06 +08002834
Emil Velikova250fce2015-09-07 12:54:27 +01002835static int drmParseSubsystemType(int maj, int min)
Emil Velikovb556ea12015-08-17 11:09:06 +08002836{
Emil Velikov291b2bb2015-09-07 18:26:34 +01002837#ifdef __linux__
Emil Velikova250fce2015-09-07 12:54:27 +01002838 char path[PATH_MAX + 1];
Emil Velikovb556ea12015-08-17 11:09:06 +08002839 char link[PATH_MAX + 1] = "";
2840 char *name;
2841
Emil Velikova250fce2015-09-07 12:54:27 +01002842 snprintf(path, PATH_MAX, "/sys/dev/char/%d:%d/device/subsystem",
2843 maj, min);
2844
2845 if (readlink(path, link, PATH_MAX) < 0)
2846 return -errno;
Emil Velikovb556ea12015-08-17 11:09:06 +08002847
2848 name = strrchr(link, '/');
2849 if (!name)
2850 return -EINVAL;
2851
Emil Velikova250fce2015-09-07 12:54:27 +01002852 if (strncmp(name, "/pci", 4) == 0)
Emil Velikovb556ea12015-08-17 11:09:06 +08002853 return DRM_BUS_PCI;
2854
2855 return -EINVAL;
Emil Velikov291b2bb2015-09-07 18:26:34 +01002856#else
2857#warning "Missing implementation of drmParseSubsystemType"
2858 return -EINVAL;
2859#endif
Emil Velikovb556ea12015-08-17 11:09:06 +08002860}
2861
Emil Velikov536e0de2015-09-07 12:37:57 +01002862static int drmParsePciBusInfo(int maj, int min, drmPciBusInfoPtr info)
Emil Velikovb556ea12015-08-17 11:09:06 +08002863{
Emil Velikov291b2bb2015-09-07 18:26:34 +01002864#ifdef __linux__
Emil Velikov536e0de2015-09-07 12:37:57 +01002865 char path[PATH_MAX + 1];
2866 char data[128];
2867 char *str;
Emil Velikovb556ea12015-08-17 11:09:06 +08002868 int domain, bus, dev, func;
Emil Velikov536e0de2015-09-07 12:37:57 +01002869 int fd, ret;
Emil Velikovb556ea12015-08-17 11:09:06 +08002870
Emil Velikov536e0de2015-09-07 12:37:57 +01002871 snprintf(path, PATH_MAX, "/sys/dev/char/%d:%d/device/uevent", maj, min);
2872 fd = open(path, O_RDONLY);
2873 if (fd < 0)
2874 return -errno;
2875
2876 ret = read(fd, data, sizeof(data));
2877 close(fd);
2878 if (ret < 0)
2879 return -errno;
2880
2881#define TAG "PCI_SLOT_NAME="
2882 str = strstr(data, TAG);
Emil Velikovb556ea12015-08-17 11:09:06 +08002883 if (str == NULL)
2884 return -EINVAL;
2885
Emil Velikov536e0de2015-09-07 12:37:57 +01002886 if (sscanf(str, TAG "%04x:%02x:%02x.%1u",
Emil Velikovb556ea12015-08-17 11:09:06 +08002887 &domain, &bus, &dev, &func) != 4)
2888 return -EINVAL;
Emil Velikov536e0de2015-09-07 12:37:57 +01002889#undef TAG
Emil Velikovb556ea12015-08-17 11:09:06 +08002890
2891 info->domain = domain;
2892 info->bus = bus;
2893 info->dev = dev;
2894 info->func = func;
2895
2896 return 0;
Emil Velikov291b2bb2015-09-07 18:26:34 +01002897#else
2898#warning "Missing implementation of drmParsePciBusInfo"
2899 return -EINVAL;
2900#endif
Emil Velikovb556ea12015-08-17 11:09:06 +08002901}
2902
Emil Velikovbc2aca92015-09-07 13:51:54 +01002903static int drmCompareBusInfo(drmDevicePtr a, drmDevicePtr b)
Emil Velikovb556ea12015-08-17 11:09:06 +08002904{
Emil Velikovbc2aca92015-09-07 13:51:54 +01002905 if (a == NULL || b == NULL)
2906 return -1;
2907
Emil Velikovb556ea12015-08-17 11:09:06 +08002908 if (a->bustype != b->bustype)
Emil Velikovbc2aca92015-09-07 13:51:54 +01002909 return -1;
Emil Velikovb556ea12015-08-17 11:09:06 +08002910
2911 switch (a->bustype) {
2912 case DRM_BUS_PCI:
Emil Velikovbc2aca92015-09-07 13:51:54 +01002913 return memcmp(a->businfo.pci, b->businfo.pci, sizeof(drmPciBusInfo));
Emil Velikovb556ea12015-08-17 11:09:06 +08002914 default:
2915 break;
2916 }
2917
Emil Velikovbc2aca92015-09-07 13:51:54 +01002918 return -1;
Emil Velikovb556ea12015-08-17 11:09:06 +08002919}
2920
2921static int drmGetNodeType(const char *name)
2922{
2923 if (strncmp(name, DRM_PRIMARY_MINOR_NAME,
2924 sizeof(DRM_PRIMARY_MINOR_NAME) - 1) == 0)
2925 return DRM_NODE_PRIMARY;
2926
2927 if (strncmp(name, DRM_CONTROL_MINOR_NAME,
2928 sizeof(DRM_CONTROL_MINOR_NAME ) - 1) == 0)
2929 return DRM_NODE_CONTROL;
2930
2931 if (strncmp(name, DRM_RENDER_MINOR_NAME,
2932 sizeof(DRM_RENDER_MINOR_NAME) - 1) == 0)
2933 return DRM_NODE_RENDER;
2934
2935 return -EINVAL;
2936}
2937
Emil Velikov5f68d312015-09-07 13:54:32 +01002938static int drmGetMaxNodeName(void)
2939{
2940 return sizeof(DRM_DIR_NAME) +
2941 MAX3(sizeof(DRM_PRIMARY_MINOR_NAME),
2942 sizeof(DRM_CONTROL_MINOR_NAME),
2943 sizeof(DRM_RENDER_MINOR_NAME)) +
2944 3 /* lenght of the node number */;
2945}
2946
Emil Velikovef5192e2015-09-07 12:47:47 +01002947static int drmParsePciDeviceInfo(const char *d_name,
Emil Velikovb556ea12015-08-17 11:09:06 +08002948 drmPciDeviceInfoPtr device)
2949{
Emil Velikov291b2bb2015-09-07 18:26:34 +01002950#ifdef __linux__
Emil Velikovef5192e2015-09-07 12:47:47 +01002951 char path[PATH_MAX + 1];
2952 unsigned char config[64];
2953 int fd, ret;
2954
2955 snprintf(path, PATH_MAX, "/sys/class/drm/%s/device/config", d_name);
2956 fd = open(path, O_RDONLY);
2957 if (fd < 0)
2958 return -errno;
2959
2960 ret = read(fd, config, sizeof(config));
2961 close(fd);
2962 if (ret < 0)
2963 return -errno;
Emil Velikovb556ea12015-08-17 11:09:06 +08002964
2965 device->vendor_id = config[0] | (config[1] << 8);
2966 device->device_id = config[2] | (config[3] << 8);
2967 device->revision_id = config[8];
2968 device->subvendor_id = config[44] | (config[45] << 8);
2969 device->subdevice_id = config[46] | (config[47] << 8);
2970
2971 return 0;
Emil Velikov291b2bb2015-09-07 18:26:34 +01002972#else
2973#warning "Missing implementation of drmParsePciDeviceInfo"
2974 return -EINVAL;
2975#endif
Emil Velikovb556ea12015-08-17 11:09:06 +08002976}
2977
Emil Velikovccedf662015-09-09 16:02:18 +01002978void drmFreeDevice(drmDevicePtr *device)
Emil Velikovb556ea12015-08-17 11:09:06 +08002979{
Emil Velikovb556ea12015-08-17 11:09:06 +08002980 if (device == NULL)
2981 return;
2982
Emil Velikov5f68d312015-09-07 13:54:32 +01002983 free(*device);
2984 *device = NULL;
Emil Velikovb556ea12015-08-17 11:09:06 +08002985}
2986
2987void drmFreeDevices(drmDevicePtr devices[], int count)
2988{
2989 int i;
2990
2991 if (devices == NULL)
2992 return;
2993
Emil Velikov5f68d312015-09-07 13:54:32 +01002994 for (i = 0; i < count && devices[i] != NULL; i++)
2995 drmFreeDevice(&devices[i]);
Emil Velikovb556ea12015-08-17 11:09:06 +08002996}
2997
Emil Velikovfae59d72015-09-09 17:54:34 +01002998static int drmProcessPciDevice(drmDevicePtr *device, const char *d_name,
2999 const char *node, int node_type,
3000 int maj, int min, bool fetch_deviceinfo)
3001{
3002 const int max_node_str = drmGetMaxNodeName();
3003 int ret, i;
Michel Dänzer30455232015-10-14 12:48:52 +09003004 char *addr;
Emil Velikovfae59d72015-09-09 17:54:34 +01003005
Michel Dänzer30455232015-10-14 12:48:52 +09003006 *device = calloc(1, sizeof(drmDevice) +
3007 (DRM_NODE_MAX * (sizeof(void *) + max_node_str)) +
3008 sizeof(drmPciBusInfo) +
3009 sizeof(drmPciDeviceInfo));
Emil Velikovfae59d72015-09-09 17:54:34 +01003010 if (!*device)
3011 return -ENOMEM;
3012
Michel Dänzer30455232015-10-14 12:48:52 +09003013 addr = (char*)*device;
3014
Emil Velikovfae59d72015-09-09 17:54:34 +01003015 (*device)->bustype = DRM_BUS_PCI;
3016 (*device)->available_nodes = 1 << node_type;
3017
3018 addr += sizeof(drmDevice);
Michel Dänzer30455232015-10-14 12:48:52 +09003019 (*device)->nodes = (char**)addr;
Emil Velikovfae59d72015-09-09 17:54:34 +01003020
3021 addr += DRM_NODE_MAX * sizeof(void *);
3022 for (i = 0; i < DRM_NODE_MAX; i++) {
3023 (*device)->nodes[i] = addr;
3024 addr += max_node_str;
3025 }
3026 memcpy((*device)->nodes[node_type], node, max_node_str);
3027
Michel Dänzer30455232015-10-14 12:48:52 +09003028 (*device)->businfo.pci = (drmPciBusInfoPtr)addr;
Emil Velikovfae59d72015-09-09 17:54:34 +01003029
3030 ret = drmParsePciBusInfo(maj, min, (*device)->businfo.pci);
3031 if (ret)
3032 goto free_device;
3033
3034 // Fetch the device info if the user has requested it
3035 if (fetch_deviceinfo) {
3036 addr += sizeof(drmPciBusInfo);
Michel Dänzer30455232015-10-14 12:48:52 +09003037 (*device)->deviceinfo.pci = (drmPciDeviceInfoPtr)addr;
Emil Velikovfae59d72015-09-09 17:54:34 +01003038
3039 ret = drmParsePciDeviceInfo(d_name, (*device)->deviceinfo.pci);
3040 if (ret)
3041 goto free_device;
3042 }
3043 return 0;
3044
3045free_device:
3046 free(*device);
3047 *device = NULL;
3048 return ret;
3049}
3050
3051static void drmFoldDuplicatedDevices(drmDevicePtr local_devices[], int count)
3052{
3053 int node_type, i, j;
3054
3055 for (i = 0; i < count; i++) {
3056 for (j = i + 1; j < count; j++) {
3057 if (drmCompareBusInfo(local_devices[i], local_devices[j]) == 0) {
3058 local_devices[i]->available_nodes |= local_devices[j]->available_nodes;
3059 node_type = log2(local_devices[j]->available_nodes);
3060 memcpy(local_devices[i]->nodes[node_type],
3061 local_devices[j]->nodes[node_type], drmGetMaxNodeName());
3062 drmFreeDevice(&local_devices[j]);
3063 }
3064 }
3065 }
3066}
3067
Emil Velikovb556ea12015-08-17 11:09:06 +08003068/**
Emil Velikovccedf662015-09-09 16:02:18 +01003069 * Get information about the opened drm device
3070 *
3071 * \param fd file descriptor of the drm device
3072 * \param device the address of a drmDevicePtr where the information
3073 * will be allocated in stored
3074 *
3075 * \return zero on success, negative error code otherwise.
3076 */
3077int drmGetDevice(int fd, drmDevicePtr *device)
3078{
3079 drmDevicePtr *local_devices;
3080 drmDevicePtr d;
3081 DIR *sysdir;
3082 struct dirent *dent;
3083 struct stat sbuf;
3084 char node[PATH_MAX + 1];
3085 int node_type, subsystem_type;
3086 int maj, min;
3087 int ret, i, node_count;
3088 int max_count = 16;
3089
3090 if (fd == -1 || device == NULL)
3091 return -EINVAL;
3092
3093 if (fstat(fd, &sbuf))
3094 return -errno;
3095
3096 maj = major(sbuf.st_rdev);
3097 min = minor(sbuf.st_rdev);
3098
3099 if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode))
3100 return -EINVAL;
3101
3102 subsystem_type = drmParseSubsystemType(maj, min);
3103
3104 local_devices = calloc(max_count, sizeof(drmDevicePtr));
3105 if (local_devices == NULL)
3106 return -ENOMEM;
3107
3108 sysdir = opendir(DRM_DIR_NAME);
3109 if (!sysdir) {
3110 ret = -errno;
Matt Ropercf0f0362015-10-16 15:11:23 -07003111 goto free_locals;
Emil Velikovccedf662015-09-09 16:02:18 +01003112 }
3113
3114 i = 0;
3115 while ((dent = readdir(sysdir))) {
3116 node_type = drmGetNodeType(dent->d_name);
3117 if (node_type < 0)
3118 continue;
3119
3120 snprintf(node, PATH_MAX, "%s/%s", DRM_DIR_NAME, dent->d_name);
3121 if (stat(node, &sbuf))
3122 continue;
3123
3124 maj = major(sbuf.st_rdev);
3125 min = minor(sbuf.st_rdev);
3126
3127 if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode))
3128 continue;
3129
3130 if (drmParseSubsystemType(maj, min) != subsystem_type)
3131 continue;
3132
3133 switch (subsystem_type) {
3134 case DRM_BUS_PCI:
3135 ret = drmProcessPciDevice(&d, dent->d_name, node, node_type,
3136 maj, min, true);
3137 if (ret)
3138 goto free_devices;
3139
3140 break;
3141 default:
3142 fprintf(stderr, "The subsystem type is not supported yet\n");
Matt Roperba5a6ec2015-10-16 15:11:24 -07003143 continue;
Emil Velikovccedf662015-09-09 16:02:18 +01003144 }
3145
3146 if (i >= max_count) {
3147 drmDevicePtr *temp;
3148
3149 max_count += 16;
3150 temp = realloc(local_devices, max_count * sizeof(drmDevicePtr));
3151 if (!temp)
3152 goto free_devices;
3153 local_devices = temp;
3154 }
3155
3156 local_devices[i] = d;
3157 i++;
3158 }
3159 node_count = i;
3160
3161 /* Fold nodes into a single device if they share the same bus info */
3162 drmFoldDuplicatedDevices(local_devices, node_count);
3163
3164 *device = local_devices[0];
3165 for (i = 1; i < node_count && local_devices[i]; i++)
3166 drmFreeDevice(&local_devices[i]);
3167
Emil Velikovccedf662015-09-09 16:02:18 +01003168 closedir(sysdir);
Matt Ropercf0f0362015-10-16 15:11:23 -07003169 free(local_devices);
Emil Velikovccedf662015-09-09 16:02:18 +01003170 return 0;
3171
3172free_devices:
3173 drmFreeDevices(local_devices, i);
Emil Velikovccedf662015-09-09 16:02:18 +01003174 closedir(sysdir);
Matt Ropercf0f0362015-10-16 15:11:23 -07003175
3176free_locals:
3177 free(local_devices);
Emil Velikovccedf662015-09-09 16:02:18 +01003178 return ret;
3179}
3180
3181/**
Emil Velikovb556ea12015-08-17 11:09:06 +08003182 * Get drm devices on the system
3183 *
3184 * \param devices the array of devices with drmDevicePtr elements
3185 * can be NULL to get the device number first
3186 * \param max_devices the maximum number of devices for the array
3187 *
3188 * \return on error - negative error code,
3189 * if devices is NULL - total number of devices available on the system,
3190 * alternatively the number of devices stored in devices[], which is
3191 * capped by the max_devices.
3192 */
3193int drmGetDevices(drmDevicePtr devices[], int max_devices)
3194{
Emil Velikov5f68d312015-09-07 13:54:32 +01003195 drmDevicePtr *local_devices;
3196 drmDevicePtr device;
3197 DIR *sysdir;
3198 struct dirent *dent;
3199 struct stat sbuf;
3200 char node[PATH_MAX + 1];
Emil Velikovb556ea12015-08-17 11:09:06 +08003201 int node_type, subsystem_type;
3202 int maj, min;
Emil Velikovfae59d72015-09-09 17:54:34 +01003203 int ret, i, node_count, device_count;
Emil Velikovb556ea12015-08-17 11:09:06 +08003204 int max_count = 16;
Emil Velikovb556ea12015-08-17 11:09:06 +08003205
Emil Velikov5f68d312015-09-07 13:54:32 +01003206 local_devices = calloc(max_count, sizeof(drmDevicePtr));
3207 if (local_devices == NULL)
Emil Velikovb556ea12015-08-17 11:09:06 +08003208 return -ENOMEM;
3209
3210 sysdir = opendir(DRM_DIR_NAME);
3211 if (!sysdir) {
3212 ret = -errno;
Matt Roper8c4a1cb2015-09-30 09:30:51 -07003213 goto free_locals;
Emil Velikovb556ea12015-08-17 11:09:06 +08003214 }
3215
Emil Velikov5f68d312015-09-07 13:54:32 +01003216 i = 0;
Emil Velikovb556ea12015-08-17 11:09:06 +08003217 while ((dent = readdir(sysdir))) {
3218 node_type = drmGetNodeType(dent->d_name);
3219 if (node_type < 0)
3220 continue;
3221
3222 snprintf(node, PATH_MAX, "%s/%s", DRM_DIR_NAME, dent->d_name);
3223 if (stat(node, &sbuf))
3224 continue;
3225
3226 maj = major(sbuf.st_rdev);
3227 min = minor(sbuf.st_rdev);
3228
3229 if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode))
3230 continue;
3231
Emil Velikova250fce2015-09-07 12:54:27 +01003232 subsystem_type = drmParseSubsystemType(maj, min);
Emil Velikovb556ea12015-08-17 11:09:06 +08003233
3234 if (subsystem_type < 0)
3235 continue;
3236
3237 switch (subsystem_type) {
3238 case DRM_BUS_PCI:
Emil Velikovfae59d72015-09-09 17:54:34 +01003239 ret = drmProcessPciDevice(&device, dent->d_name, node, node_type,
3240 maj, min, devices != NULL);
Emil Velikovb556ea12015-08-17 11:09:06 +08003241 if (ret)
Emil Velikov5f68d312015-09-07 13:54:32 +01003242 goto free_devices;
Emil Velikovb556ea12015-08-17 11:09:06 +08003243
Emil Velikovb556ea12015-08-17 11:09:06 +08003244 break;
3245 default:
3246 fprintf(stderr, "The subsystem type is not supported yet\n");
Matt Roperba5a6ec2015-10-16 15:11:24 -07003247 continue;
Emil Velikovb556ea12015-08-17 11:09:06 +08003248 }
Emil Velikov5f68d312015-09-07 13:54:32 +01003249
3250 if (i >= max_count) {
3251 drmDevicePtr *temp;
3252
3253 max_count += 16;
3254 temp = realloc(local_devices, max_count * sizeof(drmDevicePtr));
3255 if (!temp)
3256 goto free_devices;
3257 local_devices = temp;
3258 }
3259
3260 local_devices[i] = device;
Emil Velikovb556ea12015-08-17 11:09:06 +08003261 i++;
3262 }
Emil Velikovb556ea12015-08-17 11:09:06 +08003263 node_count = i;
3264
Emil Velikov5f68d312015-09-07 13:54:32 +01003265 /* Fold nodes into a single device if they share the same bus info */
Emil Velikovfae59d72015-09-09 17:54:34 +01003266 drmFoldDuplicatedDevices(local_devices, node_count);
Emil Velikovb556ea12015-08-17 11:09:06 +08003267
Emil Velikov5f68d312015-09-07 13:54:32 +01003268 device_count = 0;
3269 for (i = 0; i < node_count && local_devices[i]; i++) {
3270 if ((devices != NULL) && (device_count < max_devices))
3271 devices[device_count] = local_devices[i];
3272 else
3273 drmFreeDevice(&local_devices[i]);
3274
3275 device_count++;
Emil Velikovb556ea12015-08-17 11:09:06 +08003276 }
3277
Emil Velikovb556ea12015-08-17 11:09:06 +08003278 closedir(sysdir);
Matt Roper8c4a1cb2015-09-30 09:30:51 -07003279 free(local_devices);
Emil Velikov5f68d312015-09-07 13:54:32 +01003280 return device_count;
Emil Velikovb556ea12015-08-17 11:09:06 +08003281
Emil Velikov5f68d312015-09-07 13:54:32 +01003282free_devices:
3283 drmFreeDevices(local_devices, i);
Emil Velikovb556ea12015-08-17 11:09:06 +08003284 closedir(sysdir);
Matt Roper8c4a1cb2015-09-30 09:30:51 -07003285
3286free_locals:
3287 free(local_devices);
Emil Velikovb556ea12015-08-17 11:09:06 +08003288 return ret;
3289}