1 /**
2 * \file xf86drm.c
3 * User-level interface to DRM device
4 *
5 * \author Rickard E. (Rik) Faith <faith@valinux.com>
6 * \author Kevin E. Martin <martin@valinux.com>
7 */
8
9 /*
10 * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
11 * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
12 * 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:
20 *
21 * 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.
24 *
25 * 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.
32 */
33
34 #ifdef HAVE_CONFIG_H
35 # include <config.h>
36 #endif
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <stdbool.h>
40 #include <unistd.h>
41 #include <string.h>
42 #include <strings.h>
43 #include <ctype.h>
44 #include <dirent.h>
45 #include <stddef.h>
46 #include <fcntl.h>
47 #include <errno.h>
48 #include <limits.h>
49 #include <signal.h>
50 #include <time.h>
51 #include <sys/types.h>
52 #include <sys/stat.h>
53 #define stat_t struct stat
54 #include <sys/ioctl.h>
55 #include <sys/time.h>
56 #include <stdarg.h>
57 #ifdef HAVE_SYS_MKDEV_H
58 # include <sys/mkdev.h> /* defines major(), minor(), and makedev() on Solaris */
59 #endif
60 #include <math.h>
61
62 /* Not all systems have MAP_FAILED defined */
63 #ifndef MAP_FAILED
64 #define MAP_FAILED ((void *)-1)
65 #endif
66
67 #include "xf86drm.h"
68 #include "libdrm_macros.h"
69
70 #include "util_math.h"
71
72 #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
82 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
83 #define DRM_MAJOR 145
84 #endif
85
86 #ifdef __NetBSD__
87 #define DRM_MAJOR 34
88 #endif
89
90 #ifdef __OpenBSD__
91 #ifdef __i386__
92 #define DRM_MAJOR 88
93 #else
94 #define DRM_MAJOR 87
95 #endif
96 #endif /* __OpenBSD__ */
97
98 #ifndef DRM_MAJOR
99 #define DRM_MAJOR 226 /* Linux */
100 #endif
101
102 #define DRM_MSG_VERBOSITY 3
103
104 #define memclear(s) memset(&s, 0, sizeof(s))
105
106 static drmServerInfoPtr drm_server_info;
107
drmSetServerInfo(drmServerInfoPtr info)108 void drmSetServerInfo(drmServerInfoPtr info)
109 {
110 drm_server_info = info;
111 }
112
113 /**
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 */
121
122 static int DRM_PRINTFLIKE(1, 0)
drmDebugPrint(const char * format,va_list ap)123 drmDebugPrint(const char *format, va_list ap)
124 {
125 return vfprintf(stderr, format, ap);
126 }
127
128 void
drmMsg(const char * format,...)129 drmMsg(const char *format, ...)
130 {
131 va_list ap;
132 const char *env;
133 if (((env = getenv("LIBGL_DEBUG")) && strstr(env, "verbose")) ||
134 (drm_server_info && drm_server_info->debug_print))
135 {
136 va_start(ap, format);
137 if (drm_server_info) {
138 drm_server_info->debug_print(format,ap);
139 } else {
140 drmDebugPrint(format, ap);
141 }
142 va_end(ap);
143 }
144 }
145
146 static void *drmHashTable = NULL; /* Context switch callbacks */
147
drmGetHashTable(void)148 void *drmGetHashTable(void)
149 {
150 return drmHashTable;
151 }
152
drmMalloc(int size)153 void *drmMalloc(int size)
154 {
155 return calloc(1, size);
156 }
157
drmFree(void * pt)158 void drmFree(void *pt)
159 {
160 free(pt);
161 }
162
163 /**
164 * Call ioctl, restarting if it is interupted
165 */
166 int
drmIoctl(int fd,unsigned long request,void * arg)167 drmIoctl(int fd, unsigned long request, void *arg)
168 {
169 int ret;
170
171 do {
172 ret = ioctl(fd, request, arg);
173 } while (ret == -1 && (errno == EINTR || errno == EAGAIN));
174 return ret;
175 }
176
drmGetKeyFromFd(int fd)177 static unsigned long drmGetKeyFromFd(int fd)
178 {
179 stat_t st;
180
181 st.st_rdev = 0;
182 fstat(fd, &st);
183 return st.st_rdev;
184 }
185
drmGetEntry(int fd)186 drmHashEntry *drmGetEntry(int fd)
187 {
188 unsigned long key = drmGetKeyFromFd(fd);
189 void *value;
190 drmHashEntry *entry;
191
192 if (!drmHashTable)
193 drmHashTable = drmHashCreate();
194
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
207 /**
208 * 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 */
drmMatchBusID(const char * id1,const char * id2,int pci_domain_ok)220 static int drmMatchBusID(const char *id1, const char *id2, int pci_domain_ok)
221 {
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) {
228 unsigned int o1, b1, d1, f1;
229 unsigned int o2, b2, d2, f2;
230 int ret;
231
232 ret = sscanf(id1, "pci:%04x:%02x:%02x.%u", &o1, &b1, &d1, &f1);
233 if (ret != 4) {
234 o1 = 0;
235 ret = sscanf(id1, "PCI:%u:%u:%u", &b1, &d1, &f1);
236 if (ret != 3)
237 return 0;
238 }
239
240 ret = sscanf(id2, "pci:%04x:%02x:%02x.%u", &o2, &b2, &d2, &f2);
241 if (ret != 4) {
242 o2 = 0;
243 ret = sscanf(id2, "PCI:%u:%u:%u", &b2, &d2, &f2);
244 if (ret != 3)
245 return 0;
246 }
247
248 /* 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
255 if ((o1 != o2) || (b1 != b2) || (d1 != d2) || (f1 != f2))
256 return 0;
257 else
258 return 1;
259 }
260 return 0;
261 }
262
263 /**
264 * 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 */
277 #if !defined(UDEV)
chown_check_return(const char * path,uid_t owner,gid_t group)278 static 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 }
293 #endif
294
295 /**
296 * 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 */
drmOpenDevice(dev_t dev,int minor,int type)308 static int drmOpenDevice(dev_t dev, int minor, int type)
309 {
310 stat_t st;
311 const char *dev_name;
312 char buf[64];
313 int fd;
314 mode_t devmode = DRM_DEV_MODE, serv_mode;
315 gid_t serv_group;
316 #if !defined(UDEV)
317 int isroot = !geteuid();
318 uid_t user = DRM_DEV_UID;
319 gid_t group = DRM_DEV_GID;
320 #endif
321
322 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);
337 drmMsg("drmOpenDevice: node name is %s\n", buf);
338
339 if (drm_server_info && drm_server_info->get_perms) {
340 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);
343 }
344
345 #if !defined(UDEV)
346 if (stat(DRM_DIR_NAME, &st)) {
347 if (!isroot)
348 return DRM_ERR_NOT_ROOT;
349 mkdir(DRM_DIR_NAME, DRM_DEV_DIRMODE);
350 chown_check_return(DRM_DIR_NAME, 0, 0); /* root:root */
351 chmod(DRM_DIR_NAME, DRM_DEV_DIRMODE);
352 }
353
354 /* Check if the device node exists and create it if necessary. */
355 if (stat(buf, &st)) {
356 if (!isroot)
357 return DRM_ERR_NOT_ROOT;
358 remove(buf);
359 mknod(buf, S_IFCHR | devmode, dev);
360 }
361
362 if (drm_server_info && drm_server_info->get_perms) {
363 group = ((int)serv_group >= 0) ? serv_group : DRM_DEV_GID;
364 chown_check_return(buf, user, group);
365 chmod(buf, devmode);
366 }
367 #else
368 /* if we modprobed then wait for udev */
369 {
370 int udev_count = 0;
371 wait_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
391
392 fd = open(buf, O_RDWR, 0);
393 drmMsg("drmOpenDevice: open result is %d, (%s)\n",
394 fd, fd < 0 ? strerror(errno) : "OK");
395 if (fd >= 0)
396 return fd;
397
398 #if !defined(UDEV)
399 /* Check if the device node is not what we expect it to be, and recreate it
400 * and try again if so.
401 */
402 if (st.st_rdev != dev) {
403 if (!isroot)
404 return DRM_ERR_NOT_ROOT;
405 remove(buf);
406 mknod(buf, S_IFCHR | devmode, dev);
407 if (drm_server_info && drm_server_info->get_perms) {
408 chown_check_return(buf, user, group);
409 chmod(buf, devmode);
410 }
411 }
412 fd = open(buf, O_RDWR, 0);
413 drmMsg("drmOpenDevice: open result is %d, (%s)\n",
414 fd, fd < 0 ? strerror(errno) : "OK");
415 if (fd >= 0)
416 return fd;
417
418 drmMsg("drmOpenDevice: Open failed\n");
419 remove(buf);
420 #endif
421 return -errno;
422 }
423
424
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 */
drmOpenMinor(int minor,int create,int type)437 static int drmOpenMinor(int minor, int create, int type)
438 {
439 int fd;
440 char buf[64];
441 const char *dev_name;
442
443 if (create)
444 return drmOpenDevice(makedev(DRM_MAJOR, minor), minor, type);
445
446 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);
461 if ((fd = open(buf, O_RDWR, 0)) >= 0)
462 return fd;
463 return -errno;
464 }
465
466
467 /**
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 */
drmAvailable(void)477 int drmAvailable(void)
478 {
479 drmVersionPtr version;
480 int retval = 0;
481 int fd;
482
483 if ((fd = drmOpenMinor(0, 1, DRM_NODE_PRIMARY)) < 0) {
484 #ifdef __linux__
485 /* Try proc for backward Linux compatibility */
486 if (!access("/proc/dri/0", R_OK))
487 return 1;
488 #endif
489 return 0;
490 }
491
492 if ((version = drmGetVersion(fd))) {
493 retval = 1;
494 drmFreeVersion(version);
495 }
496 close(fd);
497
498 return retval;
499 }
500
drmGetMinorBase(int type)501 static 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 }
514
drmGetMinorType(int minor)515 static 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
drmGetMinorName(int type)532 static const char *drmGetMinorName(int type)
533 {
534 switch (type) {
535 case DRM_NODE_PRIMARY:
536 return DRM_PRIMARY_MINOR_NAME;
537 case DRM_NODE_CONTROL:
538 return DRM_CONTROL_MINOR_NAME;
539 case DRM_NODE_RENDER:
540 return DRM_RENDER_MINOR_NAME;
541 default:
542 return NULL;
543 }
544 }
545
546 /**
547 * Open the device by bus ID.
548 *
549 * \param busid bus ID.
550 * \param type device node type.
551 *
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 */
drmOpenByBusid(const char * busid,int type)560 static int drmOpenByBusid(const char *busid, int type)
561 {
562 int i, pci_domain_ok = 1;
563 int fd;
564 const char *buf;
565 drmSetVersion sv;
566 int base = drmGetMinorBase(type);
567
568 if (base < 0)
569 return -1;
570
571 drmMsg("drmOpenByBusid: Searching for BusID %s\n", busid);
572 for (i = base; i < base + DRM_MAX_MINOR; i++) {
573 fd = drmOpenMinor(i, 1, type);
574 drmMsg("drmOpenByBusid: drmOpenMinor returns %d\n", fd);
575 if (fd >= 0) {
576 /* 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 */
579 sv.drm_di_major = 1;
580 sv.drm_di_minor = 4;
581 sv.drm_dd_major = -1; /* Don't care */
582 sv.drm_dd_minor = -1; /* Don't care */
583 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 */
591 drmMsg("drmOpenByBusid: Interface 1.4 failed, trying 1.1\n");
592 drmSetInterfaceVersion(fd, &sv);
593 }
594 buf = drmGetBusid(fd);
595 drmMsg("drmOpenByBusid: drmGetBusid reports %s\n", buf);
596 if (buf && drmMatchBusID(buf, busid, pci_domain_ok)) {
597 drmFreeBusid(buf);
598 return fd;
599 }
600 if (buf)
601 drmFreeBusid(buf);
602 close(fd);
603 }
604 }
605 return -1;
606 }
607
608
609 /**
610 * Open the device by name.
611 *
612 * \param name driver name.
613 * \param type the device node type.
614 *
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 */
drmOpenByName(const char * name,int type)624 static int drmOpenByName(const char *name, int type)
625 {
626 int i;
627 int fd;
628 drmVersionPtr version;
629 char * id;
630 int base = drmGetMinorBase(type);
631
632 if (base < 0)
633 return -1;
634
635 /*
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 */
639 for (i = base; i < base + DRM_MAX_MINOR; i++) {
640 if ((fd = drmOpenMinor(i, 1, type)) >= 0) {
641 if ((version = drmGetVersion(fd))) {
642 if (!strcmp(version->name, name)) {
643 drmFreeVersion(version);
644 id = drmGetBusid(fd);
645 drmMsg("drmGetBusid returned '%s'\n", id ? id : "NULL");
646 if (!id || !*id) {
647 if (id)
648 drmFreeBusid(id);
649 return fd;
650 } else {
651 drmFreeBusid(id);
652 }
653 } else {
654 drmFreeVersion(version);
655 }
656 }
657 close(fd);
658 }
659 }
660
661 #ifdef __linux__
662 /* Backward-compatibility /proc support */
663 for (i = 0; i < 8; i++) {
664 char proc_name[64], buf[512];
665 char *driver, *pt, *devstring;
666 int retcode;
667
668 sprintf(proc_name, "/proc/dri/%d/name", i);
669 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 ;
676 if (*pt) { /* Device is next */
677 *pt = '\0';
678 if (!strcmp(driver, name)) { /* Match */
679 for (devstring = ++pt; *pt && *pt != ' '; ++pt)
680 ;
681 if (*pt) { /* Found busid */
682 return drmOpenByBusid(++pt, type);
683 } else { /* No busid */
684 return drmOpenDevice(strtol(devstring, NULL, 0),i, type);
685 }
686 }
687 }
688 }
689 }
690 }
691 #endif
692
693 return -1;
694 }
695
696
697 /**
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 */
drmOpen(const char * name,const char * busid)712 int drmOpen(const char *name, const char *busid)
713 {
714 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 */
drmOpenWithType(const char * name,const char * busid,int type)733 int drmOpenWithType(const char *name, const char *busid, int type)
734 {
735 if (!drmAvailable() && name != NULL && drm_server_info &&
736 drm_server_info->load_module) {
737 /* try to load the kernel module */
738 if (!drm_server_info->load_module(name)) {
739 drmMsg("[drm] failed to load kernel module \"%s\"\n", name);
740 return -1;
741 }
742 }
743
744 if (busid) {
745 int fd = drmOpenByBusid(busid, type);
746 if (fd >= 0)
747 return fd;
748 }
749
750 if (name)
751 return drmOpenByName(name, type);
752
753 return -1;
754 }
755
drmOpenControl(int minor)756 int drmOpenControl(int minor)
757 {
758 return drmOpenMinor(minor, 0, DRM_NODE_CONTROL);
759 }
760
drmOpenRender(int minor)761 int drmOpenRender(int minor)
762 {
763 return drmOpenMinor(minor, 0, DRM_NODE_RENDER);
764 }
765
766 /**
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 */
drmFreeVersion(drmVersionPtr v)775 void drmFreeVersion(drmVersionPtr v)
776 {
777 if (!v)
778 return;
779 drmFree(v->name);
780 drmFree(v->date);
781 drmFree(v->desc);
782 drmFree(v);
783 }
784
785
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 */
drmFreeKernelVersion(drm_version_t * v)795 static void drmFreeKernelVersion(drm_version_t *v)
796 {
797 if (!v)
798 return;
799 drmFree(v->name);
800 drmFree(v->date);
801 drmFree(v->desc);
802 drmFree(v);
803 }
804
805
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 */
drmCopyVersion(drmVersionPtr d,const drm_version_t * s)816 static void drmCopyVersion(drmVersionPtr d, const drm_version_t *s)
817 {
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;
822 d->name = strdup(s->name);
823 d->date_len = s->date_len;
824 d->date = strdup(s->date);
825 d->desc_len = s->desc_len;
826 d->desc = strdup(s->desc);
827 }
828
829
830 /**
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 */
drmGetVersion(int fd)845 drmVersionPtr drmGetVersion(int fd)
846 {
847 drmVersionPtr retval;
848 drm_version_t *version = drmMalloc(sizeof(*version));
849
850 memclear(*version);
851
852 if (drmIoctl(fd, DRM_IOCTL_VERSION, version)) {
853 drmFreeKernelVersion(version);
854 return NULL;
855 }
856
857 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);
863
864 if (drmIoctl(fd, DRM_IOCTL_VERSION, version)) {
865 drmMsg("DRM_IOCTL_VERSION: %s\n", strerror(errno));
866 drmFreeKernelVersion(version);
867 return NULL;
868 }
869
870 /* The results might not be null-terminated strings, so terminate them. */
871 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
875 retval = drmMalloc(sizeof(*retval));
876 drmCopyVersion(retval, version);
877 drmFreeKernelVersion(version);
878 return retval;
879 }
880
881
882 /**
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 */
drmGetLibVersion(int fd)895 drmVersionPtr drmGetLibVersion(int fd)
896 {
897 drm_version_t *version = drmMalloc(sizeof(*version));
898
899 /* Version history:
900 * NOTE THIS MUST NOT GO ABOVE VERSION 1.X due to drivers needing it
901 * 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
905 * revision 1.2.x = added drmSetInterfaceVersion
906 * modified drmOpen to handle both busid and name
907 * revision 1.3.x = added server + memory manager
908 */
909 version->version_major = 1;
910 version->version_minor = 3;
911 version->version_patchlevel = 0;
912
913 return (drmVersionPtr)version;
914 }
915
drmGetCap(int fd,uint64_t capability,uint64_t * value)916 int drmGetCap(int fd, uint64_t capability, uint64_t *value)
917 {
918 struct drm_get_cap cap;
919 int ret;
920
921 memclear(cap);
922 cap.capability = capability;
923
924 ret = drmIoctl(fd, DRM_IOCTL_GET_CAP, &cap);
925 if (ret)
926 return ret;
927
928 *value = cap.value;
929 return 0;
930 }
931
drmSetClientCap(int fd,uint64_t capability,uint64_t value)932 int drmSetClientCap(int fd, uint64_t capability, uint64_t value)
933 {
934 struct drm_set_client_cap cap;
935
936 memclear(cap);
937 cap.capability = capability;
938 cap.value = value;
939
940 return drmIoctl(fd, DRM_IOCTL_SET_CLIENT_CAP, &cap);
941 }
942
943 /**
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 */
drmFreeBusid(const char * busid)951 void drmFreeBusid(const char *busid)
952 {
953 drmFree((void *)busid);
954 }
955
956
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 */
drmGetBusid(int fd)969 char *drmGetBusid(int fd)
970 {
971 drm_unique_t u;
972
973 memclear(u);
974
975 if (drmIoctl(fd, DRM_IOCTL_GET_UNIQUE, &u))
976 return NULL;
977 u.unique = drmMalloc(u.unique_len + 1);
978 if (drmIoctl(fd, DRM_IOCTL_GET_UNIQUE, &u))
979 return NULL;
980 u.unique[u.unique_len] = '\0';
981
982 return u.unique;
983 }
984
985
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 */
drmSetBusid(int fd,const char * busid)998 int drmSetBusid(int fd, const char *busid)
999 {
1000 drm_unique_t u;
1001
1002 memclear(u);
1003 u.unique = (char *)busid;
1004 u.unique_len = strlen(busid);
1005
1006 if (drmIoctl(fd, DRM_IOCTL_SET_UNIQUE, &u)) {
1007 return -errno;
1008 }
1009 return 0;
1010 }
1011
drmGetMagic(int fd,drm_magic_t * magic)1012 int drmGetMagic(int fd, drm_magic_t * magic)
1013 {
1014 drm_auth_t auth;
1015
1016 memclear(auth);
1017
1018 *magic = 0;
1019 if (drmIoctl(fd, DRM_IOCTL_GET_MAGIC, &auth))
1020 return -errno;
1021 *magic = auth.magic;
1022 return 0;
1023 }
1024
drmAuthMagic(int fd,drm_magic_t magic)1025 int drmAuthMagic(int fd, drm_magic_t magic)
1026 {
1027 drm_auth_t auth;
1028
1029 memclear(auth);
1030 auth.magic = magic;
1031 if (drmIoctl(fd, DRM_IOCTL_AUTH_MAGIC, &auth))
1032 return -errno;
1033 return 0;
1034 }
1035
1036 /**
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 */
drmAddMap(int fd,drm_handle_t offset,drmSize size,drmMapType type,drmMapFlags flags,drm_handle_t * handle)1086 int drmAddMap(int fd, drm_handle_t offset, drmSize size, drmMapType type,
1087 drmMapFlags flags, drm_handle_t *handle)
1088 {
1089 drm_map_t map;
1090
1091 memclear(map);
1092 map.offset = offset;
1093 map.size = size;
1094 map.type = type;
1095 map.flags = flags;
1096 if (drmIoctl(fd, DRM_IOCTL_ADD_MAP, &map))
1097 return -errno;
1098 if (handle)
1099 *handle = (drm_handle_t)(uintptr_t)map.handle;
1100 return 0;
1101 }
1102
drmRmMap(int fd,drm_handle_t handle)1103 int drmRmMap(int fd, drm_handle_t handle)
1104 {
1105 drm_map_t map;
1106
1107 memclear(map);
1108 map.handle = (void *)(uintptr_t)handle;
1109
1110 if(drmIoctl(fd, DRM_IOCTL_RM_MAP, &map))
1111 return -errno;
1112 return 0;
1113 }
1114
1115 /**
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 */
drmAddBufs(int fd,int count,int size,drmBufDescFlags flags,int agp_offset)1131 int drmAddBufs(int fd, int count, int size, drmBufDescFlags flags,
1132 int agp_offset)
1133 {
1134 drm_buf_desc_t request;
1135
1136 memclear(request);
1137 request.count = count;
1138 request.size = size;
1139 request.flags = flags;
1140 request.agp_start = agp_offset;
1141
1142 if (drmIoctl(fd, DRM_IOCTL_ADD_BUFS, &request))
1143 return -errno;
1144 return request.count;
1145 }
1146
drmMarkBufs(int fd,double low,double high)1147 int drmMarkBufs(int fd, double low, double high)
1148 {
1149 drm_buf_info_t info;
1150 int i;
1151
1152 memclear(info);
1153
1154 if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info))
1155 return -EINVAL;
1156
1157 if (!info.count)
1158 return -EINVAL;
1159
1160 if (!(info.list = drmMalloc(info.count * sizeof(*info.list))))
1161 return -ENOMEM;
1162
1163 if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info)) {
1164 int retval = -errno;
1165 drmFree(info.list);
1166 return retval;
1167 }
1168
1169 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;
1172 if (drmIoctl(fd, DRM_IOCTL_MARK_BUFS, &info.list[i])) {
1173 int retval = -errno;
1174 drmFree(info.list);
1175 return retval;
1176 }
1177 }
1178 drmFree(info.list);
1179
1180 return 0;
1181 }
1182
1183 /**
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 */
drmFreeBufs(int fd,int count,int * list)1198 int drmFreeBufs(int fd, int count, int *list)
1199 {
1200 drm_buf_free_t request;
1201
1202 memclear(request);
1203 request.count = count;
1204 request.list = list;
1205 if (drmIoctl(fd, DRM_IOCTL_FREE_BUFS, &request))
1206 return -errno;
1207 return 0;
1208 }
1209
1210
1211 /**
1212 * Close the device.
1213 *
1214 * \param fd file descriptor.
1215 *
1216 * \internal
1217 * This function closes the file descriptor.
1218 */
drmClose(int fd)1219 int drmClose(int fd)
1220 {
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
1235
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 */
drmMap(int fd,drm_handle_t handle,drmSize size,drmAddressPtr address)1250 int drmMap(int fd, drm_handle_t handle, drmSize size, drmAddressPtr address)
1251 {
1252 static unsigned long pagesize_mask = 0;
1253
1254 if (fd < 0)
1255 return -EINVAL;
1256
1257 if (!pagesize_mask)
1258 pagesize_mask = getpagesize() - 1;
1259
1260 size = (size + pagesize_mask) & ~pagesize_mask;
1261
1262 *address = drm_mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, handle);
1263 if (*address == MAP_FAILED)
1264 return -errno;
1265 return 0;
1266 }
1267
1268
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
1278 * This function is a wrapper for munmap().
1279 */
drmUnmap(drmAddress address,drmSize size)1280 int drmUnmap(drmAddress address, drmSize size)
1281 {
1282 return drm_munmap(address, size);
1283 }
1284
drmGetBufInfo(int fd)1285 drmBufInfoPtr drmGetBufInfo(int fd)
1286 {
1287 drm_buf_info_t info;
1288 drmBufInfoPtr retval;
1289 int i;
1290
1291 memclear(info);
1292
1293 if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info))
1294 return NULL;
1295
1296 if (info.count) {
1297 if (!(info.list = drmMalloc(info.count * sizeof(*info.list))))
1298 return NULL;
1299
1300 if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info)) {
1301 drmFree(info.list);
1302 return NULL;
1303 }
1304
1305 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
1320 /**
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 */
drmMapBufs(int fd)1335 drmBufMapPtr drmMapBufs(int fd)
1336 {
1337 drm_buf_map_t bufs;
1338 drmBufMapPtr retval;
1339 int i;
1340
1341 memclear(bufs);
1342 if (drmIoctl(fd, DRM_IOCTL_MAP_BUFS, &bufs))
1343 return NULL;
1344
1345 if (!bufs.count)
1346 return NULL;
1347
1348 if (!(bufs.list = drmMalloc(bufs.count * sizeof(*bufs.list))))
1349 return NULL;
1350
1351 if (drmIoctl(fd, DRM_IOCTL_MAP_BUFS, &bufs)) {
1352 drmFree(bufs.list);
1353 return NULL;
1354 }
1355
1356 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 }
1365
1366 drmFree(bufs.list);
1367
1368 return retval;
1369 }
1370
1371
1372 /**
1373 * Unmap buffers allocated with drmMapBufs().
1374 *
1375 * \return zero on success, or negative value on failure.
1376 *
1377 * \internal
1378 * Calls munmap() for every buffer stored in \p bufs and frees the
1379 * memory allocated by drmMapBufs().
1380 */
drmUnmapBufs(drmBufMapPtr bufs)1381 int drmUnmapBufs(drmBufMapPtr bufs)
1382 {
1383 int i;
1384
1385 for (i = 0; i < bufs->count; i++) {
1386 drm_munmap(bufs->list[i].address, bufs->list[i].total);
1387 }
1388
1389 drmFree(bufs->list);
1390 drmFree(bufs);
1391
1392 return 0;
1393 }
1394
1395
1396 #define DRM_DMA_RETRY 16
1397
1398 /**
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 */
drmDMA(int fd,drmDMAReqPtr request)1410 int drmDMA(int fd, drmDMAReqPtr request)
1411 {
1412 drm_dma_t dma;
1413 int ret, i = 0;
1414
1415 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;
1424 dma.granted_count = 0;
1425
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 }
1436 }
1437
1438
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 */
drmGetLock(int fd,drm_context_t context,drmLockFlags flags)1453 int drmGetLock(int fd, drm_context_t context, drmLockFlags flags)
1454 {
1455 drm_lock_t lock;
1456
1457 memclear(lock);
1458 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;
1466
1467 while (drmIoctl(fd, DRM_IOCTL_LOCK, &lock))
1468 ;
1469 return 0;
1470 }
1471
1472 /**
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 */
drmUnlock(int fd,drm_context_t context)1484 int drmUnlock(int fd, drm_context_t context)
1485 {
1486 drm_lock_t lock;
1487
1488 memclear(lock);
1489 lock.context = context;
1490 return drmIoctl(fd, DRM_IOCTL_UNLOCK, &lock);
1491 }
1492
drmGetReservedContextList(int fd,int * count)1493 drm_context_t *drmGetReservedContextList(int fd, int *count)
1494 {
1495 drm_ctx_res_t res;
1496 drm_ctx_t *list;
1497 drm_context_t * retval;
1498 int i;
1499
1500 memclear(res);
1501 if (drmIoctl(fd, DRM_IOCTL_RES_CTX, &res))
1502 return NULL;
1503
1504 if (!res.count)
1505 return NULL;
1506
1507 if (!(list = drmMalloc(res.count * sizeof(*list))))
1508 return NULL;
1509 if (!(retval = drmMalloc(res.count * sizeof(*retval)))) {
1510 drmFree(list);
1511 return NULL;
1512 }
1513
1514 res.contexts = list;
1515 if (drmIoctl(fd, DRM_IOCTL_RES_CTX, &res))
1516 return NULL;
1517
1518 for (i = 0; i < res.count; i++)
1519 retval[i] = list[i].handle;
1520 drmFree(list);
1521
1522 *count = res.count;
1523 return retval;
1524 }
1525
drmFreeReservedContextList(drm_context_t * pt)1526 void drmFreeReservedContextList(drm_context_t *pt)
1527 {
1528 drmFree(pt);
1529 }
1530
1531 /**
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 */
drmCreateContext(int fd,drm_context_t * handle)1549 int drmCreateContext(int fd, drm_context_t *handle)
1550 {
1551 drm_ctx_t ctx;
1552
1553 memclear(ctx);
1554 if (drmIoctl(fd, DRM_IOCTL_ADD_CTX, &ctx))
1555 return -errno;
1556 *handle = ctx.handle;
1557 return 0;
1558 }
1559
drmSwitchToContext(int fd,drm_context_t context)1560 int drmSwitchToContext(int fd, drm_context_t context)
1561 {
1562 drm_ctx_t ctx;
1563
1564 memclear(ctx);
1565 ctx.handle = context;
1566 if (drmIoctl(fd, DRM_IOCTL_SWITCH_CTX, &ctx))
1567 return -errno;
1568 return 0;
1569 }
1570
drmSetContextFlags(int fd,drm_context_t context,drm_context_tFlags flags)1571 int drmSetContextFlags(int fd, drm_context_t context, drm_context_tFlags flags)
1572 {
1573 drm_ctx_t ctx;
1574
1575 /*
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 */
1581 memclear(ctx);
1582 ctx.handle = context;
1583 if (flags & DRM_CONTEXT_PRESERVED)
1584 ctx.flags |= _DRM_CONTEXT_PRESERVED;
1585 if (flags & DRM_CONTEXT_2DONLY)
1586 ctx.flags |= _DRM_CONTEXT_2DONLY;
1587 if (drmIoctl(fd, DRM_IOCTL_MOD_CTX, &ctx))
1588 return -errno;
1589 return 0;
1590 }
1591
drmGetContextFlags(int fd,drm_context_t context,drm_context_tFlagsPtr flags)1592 int drmGetContextFlags(int fd, drm_context_t context,
1593 drm_context_tFlagsPtr flags)
1594 {
1595 drm_ctx_t ctx;
1596
1597 memclear(ctx);
1598 ctx.handle = context;
1599 if (drmIoctl(fd, DRM_IOCTL_GET_CTX, &ctx))
1600 return -errno;
1601 *flags = 0;
1602 if (ctx.flags & _DRM_CONTEXT_PRESERVED)
1603 *flags |= DRM_CONTEXT_PRESERVED;
1604 if (ctx.flags & _DRM_CONTEXT_2DONLY)
1605 *flags |= DRM_CONTEXT_2DONLY;
1606 return 0;
1607 }
1608
1609 /**
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 */
drmDestroyContext(int fd,drm_context_t handle)1626 int drmDestroyContext(int fd, drm_context_t handle)
1627 {
1628 drm_ctx_t ctx;
1629
1630 memclear(ctx);
1631 ctx.handle = handle;
1632 if (drmIoctl(fd, DRM_IOCTL_RM_CTX, &ctx))
1633 return -errno;
1634 return 0;
1635 }
1636
drmCreateDrawable(int fd,drm_drawable_t * handle)1637 int drmCreateDrawable(int fd, drm_drawable_t *handle)
1638 {
1639 drm_draw_t draw;
1640
1641 memclear(draw);
1642 if (drmIoctl(fd, DRM_IOCTL_ADD_DRAW, &draw))
1643 return -errno;
1644 *handle = draw.handle;
1645 return 0;
1646 }
1647
drmDestroyDrawable(int fd,drm_drawable_t handle)1648 int drmDestroyDrawable(int fd, drm_drawable_t handle)
1649 {
1650 drm_draw_t draw;
1651
1652 memclear(draw);
1653 draw.handle = handle;
1654 if (drmIoctl(fd, DRM_IOCTL_RM_DRAW, &draw))
1655 return -errno;
1656 return 0;
1657 }
1658
drmUpdateDrawableInfo(int fd,drm_drawable_t handle,drm_drawable_info_type_t type,unsigned int num,void * data)1659 int 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
1665 memclear(update);
1666 update.handle = handle;
1667 update.type = type;
1668 update.num = num;
1669 update.data = (unsigned long long)(unsigned long)data;
1670
1671 if (drmIoctl(fd, DRM_IOCTL_UPDATE_DRAW, &update))
1672 return -errno;
1673
1674 return 0;
1675 }
1676
1677 /**
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 */
drmAgpAcquire(int fd)1689 int drmAgpAcquire(int fd)
1690 {
1691 if (drmIoctl(fd, DRM_IOCTL_AGP_ACQUIRE, NULL))
1692 return -errno;
1693 return 0;
1694 }
1695
1696
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 */
drmAgpRelease(int fd)1707 int drmAgpRelease(int fd)
1708 {
1709 if (drmIoctl(fd, DRM_IOCTL_AGP_RELEASE, NULL))
1710 return -errno;
1711 return 0;
1712 }
1713
1714
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 */
drmAgpEnable(int fd,unsigned long mode)1727 int drmAgpEnable(int fd, unsigned long mode)
1728 {
1729 drm_agp_mode_t m;
1730
1731 memclear(m);
1732 m.mode = mode;
1733 if (drmIoctl(fd, DRM_IOCTL_AGP_ENABLE, &m))
1734 return -errno;
1735 return 0;
1736 }
1737
1738
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 */
drmAgpAlloc(int fd,unsigned long size,unsigned long type,unsigned long * address,drm_handle_t * handle)1755 int drmAgpAlloc(int fd, unsigned long size, unsigned long type,
1756 unsigned long *address, drm_handle_t *handle)
1757 {
1758 drm_agp_buffer_t b;
1759
1760 memclear(b);
1761 *handle = DRM_AGP_NO_HANDLE;
1762 b.size = size;
1763 b.type = type;
1764 if (drmIoctl(fd, DRM_IOCTL_AGP_ALLOC, &b))
1765 return -errno;
1766 if (address != 0UL)
1767 *address = b.physical;
1768 *handle = b.handle;
1769 return 0;
1770 }
1771
1772
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 */
drmAgpFree(int fd,drm_handle_t handle)1785 int drmAgpFree(int fd, drm_handle_t handle)
1786 {
1787 drm_agp_buffer_t b;
1788
1789 memclear(b);
1790 b.handle = handle;
1791 if (drmIoctl(fd, DRM_IOCTL_AGP_FREE, &b))
1792 return -errno;
1793 return 0;
1794 }
1795
1796
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 */
drmAgpBind(int fd,drm_handle_t handle,unsigned long offset)1810 int drmAgpBind(int fd, drm_handle_t handle, unsigned long offset)
1811 {
1812 drm_agp_binding_t b;
1813
1814 memclear(b);
1815 b.handle = handle;
1816 b.offset = offset;
1817 if (drmIoctl(fd, DRM_IOCTL_AGP_BIND, &b))
1818 return -errno;
1819 return 0;
1820 }
1821
1822
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 */
drmAgpUnbind(int fd,drm_handle_t handle)1835 int drmAgpUnbind(int fd, drm_handle_t handle)
1836 {
1837 drm_agp_binding_t b;
1838
1839 memclear(b);
1840 b.handle = handle;
1841 if (drmIoctl(fd, DRM_IOCTL_AGP_UNBIND, &b))
1842 return -errno;
1843 return 0;
1844 }
1845
1846
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 */
drmAgpVersionMajor(int fd)1858 int drmAgpVersionMajor(int fd)
1859 {
1860 drm_agp_info_t i;
1861
1862 memclear(i);
1863
1864 if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
1865 return -errno;
1866 return i.agp_version_major;
1867 }
1868
1869
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 */
drmAgpVersionMinor(int fd)1881 int drmAgpVersionMinor(int fd)
1882 {
1883 drm_agp_info_t i;
1884
1885 memclear(i);
1886
1887 if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
1888 return -errno;
1889 return i.agp_version_minor;
1890 }
1891
1892
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 */
drmAgpGetMode(int fd)1904 unsigned long drmAgpGetMode(int fd)
1905 {
1906 drm_agp_info_t i;
1907
1908 memclear(i);
1909
1910 if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
1911 return 0;
1912 return i.mode;
1913 }
1914
1915
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 */
drmAgpBase(int fd)1927 unsigned long drmAgpBase(int fd)
1928 {
1929 drm_agp_info_t i;
1930
1931 memclear(i);
1932
1933 if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
1934 return 0;
1935 return i.aperture_base;
1936 }
1937
1938
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 */
drmAgpSize(int fd)1950 unsigned long drmAgpSize(int fd)
1951 {
1952 drm_agp_info_t i;
1953
1954 memclear(i);
1955
1956 if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
1957 return 0;
1958 return i.aperture_size;
1959 }
1960
1961
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 */
drmAgpMemoryUsed(int fd)1973 unsigned long drmAgpMemoryUsed(int fd)
1974 {
1975 drm_agp_info_t i;
1976
1977 memclear(i);
1978
1979 if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
1980 return 0;
1981 return i.memory_used;
1982 }
1983
1984
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 */
drmAgpMemoryAvail(int fd)1996 unsigned long drmAgpMemoryAvail(int fd)
1997 {
1998 drm_agp_info_t i;
1999
2000 memclear(i);
2001
2002 if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
2003 return 0;
2004 return i.memory_allowed;
2005 }
2006
2007
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 */
drmAgpVendorId(int fd)2019 unsigned int drmAgpVendorId(int fd)
2020 {
2021 drm_agp_info_t i;
2022
2023 memclear(i);
2024
2025 if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
2026 return 0;
2027 return i.id_vendor;
2028 }
2029
2030
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 */
drmAgpDeviceId(int fd)2042 unsigned int drmAgpDeviceId(int fd)
2043 {
2044 drm_agp_info_t i;
2045
2046 memclear(i);
2047
2048 if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
2049 return 0;
2050 return i.id_device;
2051 }
2052
drmScatterGatherAlloc(int fd,unsigned long size,drm_handle_t * handle)2053 int drmScatterGatherAlloc(int fd, unsigned long size, drm_handle_t *handle)
2054 {
2055 drm_scatter_gather_t sg;
2056
2057 memclear(sg);
2058
2059 *handle = 0;
2060 sg.size = size;
2061 if (drmIoctl(fd, DRM_IOCTL_SG_ALLOC, &sg))
2062 return -errno;
2063 *handle = sg.handle;
2064 return 0;
2065 }
2066
drmScatterGatherFree(int fd,drm_handle_t handle)2067 int drmScatterGatherFree(int fd, drm_handle_t handle)
2068 {
2069 drm_scatter_gather_t sg;
2070
2071 memclear(sg);
2072 sg.handle = handle;
2073 if (drmIoctl(fd, DRM_IOCTL_SG_FREE, &sg))
2074 return -errno;
2075 return 0;
2076 }
2077
2078 /**
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 */
drmWaitVBlank(int fd,drmVBlankPtr vbl)2089 int drmWaitVBlank(int fd, drmVBlankPtr vbl)
2090 {
2091 struct timespec timeout, cur;
2092 int ret;
2093
2094 ret = clock_gettime(CLOCK_MONOTONIC, &timeout);
2095 if (ret < 0) {
2096 fprintf(stderr, "clock_gettime failed: %s\n", strerror(errno));
2097 goto out;
2098 }
2099 timeout.tv_sec++;
2100
2101 do {
2102 ret = ioctl(fd, DRM_IOCTL_WAIT_VBLANK, vbl);
2103 vbl->request.type &= ~DRM_VBLANK_RELATIVE;
2104 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 }
2114 }
2115 } while (ret && errno == EINTR);
2116
2117 out:
2118 return ret;
2119 }
2120
drmError(int err,const char * label)2121 int drmError(int err, const char *label)
2122 {
2123 switch (err) {
2124 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;
2136 default:
2137 if (err < 0)
2138 err = -err;
2139 fprintf( stderr, "%s: error %d (%s)\n", label, err, strerror(err) );
2140 break;
2141 }
2142
2143 return 1;
2144 }
2145
2146 /**
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 */
drmCtlInstHandler(int fd,int irq)2158 int drmCtlInstHandler(int fd, int irq)
2159 {
2160 drm_control_t ctl;
2161
2162 memclear(ctl);
2163 ctl.func = DRM_INST_HANDLER;
2164 ctl.irq = irq;
2165 if (drmIoctl(fd, DRM_IOCTL_CONTROL, &ctl))
2166 return -errno;
2167 return 0;
2168 }
2169
2170
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 */
drmCtlUninstHandler(int fd)2182 int drmCtlUninstHandler(int fd)
2183 {
2184 drm_control_t ctl;
2185
2186 memclear(ctl);
2187 ctl.func = DRM_UNINST_HANDLER;
2188 ctl.irq = 0;
2189 if (drmIoctl(fd, DRM_IOCTL_CONTROL, &ctl))
2190 return -errno;
2191 return 0;
2192 }
2193
drmFinish(int fd,int context,drmLockFlags flags)2194 int drmFinish(int fd, int context, drmLockFlags flags)
2195 {
2196 drm_lock_t lock;
2197
2198 memclear(lock);
2199 lock.context = context;
2200 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;
2206 if (drmIoctl(fd, DRM_IOCTL_FINISH, &lock))
2207 return -errno;
2208 return 0;
2209 }
2210
2211 /**
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 */
drmGetInterruptFromBusID(int fd,int busnum,int devnum,int funcnum)2225 int drmGetInterruptFromBusID(int fd, int busnum, int devnum, int funcnum)
2226 {
2227 drm_irq_busid_t p;
2228
2229 memclear(p);
2230 p.busnum = busnum;
2231 p.devnum = devnum;
2232 p.funcnum = funcnum;
2233 if (drmIoctl(fd, DRM_IOCTL_IRQ_BUSID, &p))
2234 return -errno;
2235 return p.irq;
2236 }
2237
drmAddContextTag(int fd,drm_context_t context,void * tag)2238 int drmAddContextTag(int fd, drm_context_t context, void *tag)
2239 {
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
drmDelContextTag(int fd,drm_context_t context)2249 int drmDelContextTag(int fd, drm_context_t context)
2250 {
2251 drmHashEntry *entry = drmGetEntry(fd);
2252
2253 return drmHashDelete(entry->tagTable, context);
2254 }
2255
drmGetContextTag(int fd,drm_context_t context)2256 void *drmGetContextTag(int fd, drm_context_t context)
2257 {
2258 drmHashEntry *entry = drmGetEntry(fd);
2259 void *value;
2260
2261 if (drmHashLookup(entry->tagTable, context, &value))
2262 return NULL;
2263
2264 return value;
2265 }
2266
drmAddContextPrivateMapping(int fd,drm_context_t ctx_id,drm_handle_t handle)2267 int drmAddContextPrivateMapping(int fd, drm_context_t ctx_id,
2268 drm_handle_t handle)
2269 {
2270 drm_ctx_priv_map_t map;
2271
2272 memclear(map);
2273 map.ctx_id = ctx_id;
2274 map.handle = (void *)(uintptr_t)handle;
2275
2276 if (drmIoctl(fd, DRM_IOCTL_SET_SAREA_CTX, &map))
2277 return -errno;
2278 return 0;
2279 }
2280
drmGetContextPrivateMapping(int fd,drm_context_t ctx_id,drm_handle_t * handle)2281 int drmGetContextPrivateMapping(int fd, drm_context_t ctx_id,
2282 drm_handle_t *handle)
2283 {
2284 drm_ctx_priv_map_t map;
2285
2286 memclear(map);
2287 map.ctx_id = ctx_id;
2288
2289 if (drmIoctl(fd, DRM_IOCTL_GET_SAREA_CTX, &map))
2290 return -errno;
2291 if (handle)
2292 *handle = (drm_handle_t)(uintptr_t)map.handle;
2293
2294 return 0;
2295 }
2296
drmGetMap(int fd,int idx,drm_handle_t * offset,drmSize * size,drmMapType * type,drmMapFlags * flags,drm_handle_t * handle,int * mtrr)2297 int drmGetMap(int fd, int idx, drm_handle_t *offset, drmSize *size,
2298 drmMapType *type, drmMapFlags *flags, drm_handle_t *handle,
2299 int *mtrr)
2300 {
2301 drm_map_t map;
2302
2303 memclear(map);
2304 map.offset = idx;
2305 if (drmIoctl(fd, DRM_IOCTL_GET_MAP, &map))
2306 return -errno;
2307 *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
drmGetClient(int fd,int idx,int * auth,int * pid,int * uid,unsigned long * magic,unsigned long * iocs)2316 int 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
2321 memclear(client);
2322 client.idx = idx;
2323 if (drmIoctl(fd, DRM_IOCTL_GET_CLIENT, &client))
2324 return -errno;
2325 *auth = client.auth;
2326 *pid = client.pid;
2327 *uid = client.uid;
2328 *magic = client.magic;
2329 *iocs = client.iocs;
2330 return 0;
2331 }
2332
drmGetStats(int fd,drmStatsT * stats)2333 int drmGetStats(int fd, drmStatsT *stats)
2334 {
2335 drm_stats_t s;
2336 unsigned i;
2337
2338 memclear(s);
2339 if (drmIoctl(fd, DRM_IOCTL_GET_STATS, &s))
2340 return -errno;
2341
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
2457 /**
2458 * 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 */
drmSetInterfaceVersion(int fd,drmSetVersion * version)2471 int drmSetInterfaceVersion(int fd, drmSetVersion *version)
2472 {
2473 int retcode = 0;
2474 drm_set_version_t sv;
2475
2476 memclear(sv);
2477 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
2482 if (drmIoctl(fd, DRM_IOCTL_SET_VERSION, &sv)) {
2483 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 /**
2495 * 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 */
drmCommandNone(int fd,unsigned long drmCommandIndex)2506 int drmCommandNone(int fd, unsigned long drmCommandIndex)
2507 {
2508 unsigned long request;
2509
2510 request = DRM_IO( DRM_COMMAND_BASE + drmCommandIndex);
2511
2512 if (drmIoctl(fd, request, NULL)) {
2513 return -errno;
2514 }
2515 return 0;
2516 }
2517
2518
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 */
drmCommandRead(int fd,unsigned long drmCommandIndex,void * data,unsigned long size)2533 int drmCommandRead(int fd, unsigned long drmCommandIndex, void *data,
2534 unsigned long size)
2535 {
2536 unsigned long request;
2537
2538 request = DRM_IOC( DRM_IOC_READ, DRM_IOCTL_BASE,
2539 DRM_COMMAND_BASE + drmCommandIndex, size);
2540
2541 if (drmIoctl(fd, request, data)) {
2542 return -errno;
2543 }
2544 return 0;
2545 }
2546
2547
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 */
drmCommandWrite(int fd,unsigned long drmCommandIndex,void * data,unsigned long size)2562 int drmCommandWrite(int fd, unsigned long drmCommandIndex, void *data,
2563 unsigned long size)
2564 {
2565 unsigned long request;
2566
2567 request = DRM_IOC( DRM_IOC_WRITE, DRM_IOCTL_BASE,
2568 DRM_COMMAND_BASE + drmCommandIndex, size);
2569
2570 if (drmIoctl(fd, request, data)) {
2571 return -errno;
2572 }
2573 return 0;
2574 }
2575
2576
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 */
drmCommandWriteRead(int fd,unsigned long drmCommandIndex,void * data,unsigned long size)2591 int drmCommandWriteRead(int fd, unsigned long drmCommandIndex, void *data,
2592 unsigned long size)
2593 {
2594 unsigned long request;
2595
2596 request = DRM_IOC( DRM_IOC_READ|DRM_IOC_WRITE, DRM_IOCTL_BASE,
2597 DRM_COMMAND_BASE + drmCommandIndex, size);
2598
2599 if (drmIoctl(fd, request, data))
2600 return -errno;
2601 return 0;
2602 }
2603
2604 #define DRM_MAX_FDS 16
2605 static struct {
2606 char *BusID;
2607 int fd;
2608 int refcount;
2609 int type;
2610 } connection[DRM_MAX_FDS];
2611
2612 static int nr_fds = 0;
2613
drmOpenOnce(void * unused,const char * BusID,int * newlyopened)2614 int drmOpenOnce(void *unused,
2615 const char *BusID,
2616 int *newlyopened)
2617 {
2618 return drmOpenOnceWithType(BusID, newlyopened, DRM_NODE_PRIMARY);
2619 }
2620
drmOpenOnceWithType(const char * BusID,int * newlyopened,int type)2621 int drmOpenOnceWithType(const char *BusID, int *newlyopened, int type)
2622 {
2623 int i;
2624 int fd;
2625
2626 for (i = 0; i < nr_fds; i++)
2627 if ((strcmp(BusID, connection[i].BusID) == 0) &&
2628 (connection[i].type == type)) {
2629 connection[i].refcount++;
2630 *newlyopened = 0;
2631 return connection[i].fd;
2632 }
2633
2634 fd = drmOpenWithType(NULL, BusID, type);
2635 if (fd < 0 || nr_fds == DRM_MAX_FDS)
2636 return fd;
2637
2638 connection[nr_fds].BusID = strdup(BusID);
2639 connection[nr_fds].fd = fd;
2640 connection[nr_fds].refcount = 1;
2641 connection[nr_fds].type = type;
2642 *newlyopened = 1;
2643
2644 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));
2648
2649 nr_fds++;
2650
2651 return fd;
2652 }
2653
drmCloseOnce(int fd)2654 void drmCloseOnce(int fd)
2655 {
2656 int i;
2657
2658 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);
2663
2664 if (i < --nr_fds)
2665 connection[i] = connection[nr_fds];
2666
2667 return;
2668 }
2669 }
2670 }
2671 }
2672
drmSetMaster(int fd)2673 int drmSetMaster(int fd)
2674 {
2675 return drmIoctl(fd, DRM_IOCTL_SET_MASTER, NULL);
2676 }
2677
drmDropMaster(int fd)2678 int drmDropMaster(int fd)
2679 {
2680 return drmIoctl(fd, DRM_IOCTL_DROP_MASTER, NULL);
2681 }
2682
drmGetDeviceNameFromFd(int fd)2683 char *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
2706 return strdup(name);
2707 }
2708
drmGetNodeTypeFromFd(int fd)2709 int 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
drmPrimeHandleToFD(int fd,uint32_t handle,uint32_t flags,int * prime_fd)2731 int drmPrimeHandleToFD(int fd, uint32_t handle, uint32_t flags, int *prime_fd)
2732 {
2733 struct drm_prime_handle args;
2734 int ret;
2735
2736 memclear(args);
2737 args.fd = -1;
2738 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
drmPrimeFDToHandle(int fd,int prime_fd,uint32_t * handle)2748 int drmPrimeFDToHandle(int fd, int prime_fd, uint32_t *handle)
2749 {
2750 struct drm_prime_handle args;
2751 int ret;
2752
2753 memclear(args);
2754 args.fd = prime_fd;
2755 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
drmGetMinorNameForFD(int fd,int type)2763 static 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) {
2805 snprintf(dev_name, sizeof(dev_name), DRM_DIR_NAME "/%s",
2806 ent->d_name);
2807
2808 free(pent);
2809 closedir(sysdir);
2810
2811 return strdup(dev_name);
2812 }
2813 }
2814
2815 free(pent);
2816
2817 out_close_dir:
2818 closedir(sysdir);
2819 #else
2820 #warning "Missing implementation of drmGetMinorNameForFD"
2821 #endif
2822 return NULL;
2823 }
2824
drmGetPrimaryDeviceNameFromFd(int fd)2825 char *drmGetPrimaryDeviceNameFromFd(int fd)
2826 {
2827 return drmGetMinorNameForFD(fd, DRM_NODE_PRIMARY);
2828 }
2829
drmGetRenderDeviceNameFromFd(int fd)2830 char *drmGetRenderDeviceNameFromFd(int fd)
2831 {
2832 return drmGetMinorNameForFD(fd, DRM_NODE_RENDER);
2833 }
2834
drmParseSubsystemType(int maj,int min)2835 static int drmParseSubsystemType(int maj, int min)
2836 {
2837 #ifdef __linux__
2838 char path[PATH_MAX + 1];
2839 char link[PATH_MAX + 1] = "";
2840 char *name;
2841
2842 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;
2847
2848 name = strrchr(link, '/');
2849 if (!name)
2850 return -EINVAL;
2851
2852 if (strncmp(name, "/pci", 4) == 0)
2853 return DRM_BUS_PCI;
2854
2855 return -EINVAL;
2856 #else
2857 #warning "Missing implementation of drmParseSubsystemType"
2858 return -EINVAL;
2859 #endif
2860 }
2861
drmParsePciBusInfo(int maj,int min,drmPciBusInfoPtr info)2862 static int drmParsePciBusInfo(int maj, int min, drmPciBusInfoPtr info)
2863 {
2864 #ifdef __linux__
2865 char path[PATH_MAX + 1];
2866 char data[128];
2867 char *str;
2868 int domain, bus, dev, func;
2869 int fd, ret;
2870
2871 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);
2883 if (str == NULL)
2884 return -EINVAL;
2885
2886 if (sscanf(str, TAG "%04x:%02x:%02x.%1u",
2887 &domain, &bus, &dev, &func) != 4)
2888 return -EINVAL;
2889 #undef TAG
2890
2891 info->domain = domain;
2892 info->bus = bus;
2893 info->dev = dev;
2894 info->func = func;
2895
2896 return 0;
2897 #else
2898 #warning "Missing implementation of drmParsePciBusInfo"
2899 return -EINVAL;
2900 #endif
2901 }
2902
drmCompareBusInfo(drmDevicePtr a,drmDevicePtr b)2903 static int drmCompareBusInfo(drmDevicePtr a, drmDevicePtr b)
2904 {
2905 if (a == NULL || b == NULL)
2906 return -1;
2907
2908 if (a->bustype != b->bustype)
2909 return -1;
2910
2911 switch (a->bustype) {
2912 case DRM_BUS_PCI:
2913 return memcmp(a->businfo.pci, b->businfo.pci, sizeof(drmPciBusInfo));
2914 default:
2915 break;
2916 }
2917
2918 return -1;
2919 }
2920
drmGetNodeType(const char * name)2921 static 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
drmGetMaxNodeName(void)2938 static 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
drmParsePciDeviceInfo(const char * d_name,drmPciDeviceInfoPtr device)2947 static int drmParsePciDeviceInfo(const char *d_name,
2948 drmPciDeviceInfoPtr device)
2949 {
2950 #ifdef __linux__
2951 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;
2964
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;
2972 #else
2973 #warning "Missing implementation of drmParsePciDeviceInfo"
2974 return -EINVAL;
2975 #endif
2976 }
2977
drmFreeDevice(drmDevicePtr * device)2978 void drmFreeDevice(drmDevicePtr *device)
2979 {
2980 if (device == NULL)
2981 return;
2982
2983 free(*device);
2984 *device = NULL;
2985 }
2986
drmFreeDevices(drmDevicePtr devices[],int count)2987 void drmFreeDevices(drmDevicePtr devices[], int count)
2988 {
2989 int i;
2990
2991 if (devices == NULL)
2992 return;
2993
2994 for (i = 0; i < count && devices[i] != NULL; i++)
2995 drmFreeDevice(&devices[i]);
2996 }
2997
drmProcessPciDevice(drmDevicePtr * device,const char * d_name,const char * node,int node_type,int maj,int min,bool fetch_deviceinfo)2998 static 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;
3004 char *addr;
3005
3006 *device = calloc(1, sizeof(drmDevice) +
3007 (DRM_NODE_MAX * (sizeof(void *) + max_node_str)) +
3008 sizeof(drmPciBusInfo) +
3009 sizeof(drmPciDeviceInfo));
3010 if (!*device)
3011 return -ENOMEM;
3012
3013 addr = (char*)*device;
3014
3015 (*device)->bustype = DRM_BUS_PCI;
3016 (*device)->available_nodes = 1 << node_type;
3017
3018 addr += sizeof(drmDevice);
3019 (*device)->nodes = (char**)addr;
3020
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
3028 (*device)->businfo.pci = (drmPciBusInfoPtr)addr;
3029
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);
3037 (*device)->deviceinfo.pci = (drmPciDeviceInfoPtr)addr;
3038
3039 ret = drmParsePciDeviceInfo(d_name, (*device)->deviceinfo.pci);
3040 if (ret)
3041 goto free_device;
3042 }
3043 return 0;
3044
3045 free_device:
3046 free(*device);
3047 *device = NULL;
3048 return ret;
3049 }
3050
drmFoldDuplicatedDevices(drmDevicePtr local_devices[],int count)3051 static 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
3068 /**
3069 * 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 */
drmGetDevice(int fd,drmDevicePtr * device)3077 int 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;
3111 goto free_locals;
3112 }
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");
3143 continue;
3144 }
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
3168 closedir(sysdir);
3169 free(local_devices);
3170 return 0;
3171
3172 free_devices:
3173 drmFreeDevices(local_devices, i);
3174 closedir(sysdir);
3175
3176 free_locals:
3177 free(local_devices);
3178 return ret;
3179 }
3180
3181 /**
3182 * 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 */
drmGetDevices(drmDevicePtr devices[],int max_devices)3193 int drmGetDevices(drmDevicePtr devices[], int max_devices)
3194 {
3195 drmDevicePtr *local_devices;
3196 drmDevicePtr device;
3197 DIR *sysdir;
3198 struct dirent *dent;
3199 struct stat sbuf;
3200 char node[PATH_MAX + 1];
3201 int node_type, subsystem_type;
3202 int maj, min;
3203 int ret, i, node_count, device_count;
3204 int max_count = 16;
3205
3206 local_devices = calloc(max_count, sizeof(drmDevicePtr));
3207 if (local_devices == NULL)
3208 return -ENOMEM;
3209
3210 sysdir = opendir(DRM_DIR_NAME);
3211 if (!sysdir) {
3212 ret = -errno;
3213 goto free_locals;
3214 }
3215
3216 i = 0;
3217 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
3232 subsystem_type = drmParseSubsystemType(maj, min);
3233
3234 if (subsystem_type < 0)
3235 continue;
3236
3237 switch (subsystem_type) {
3238 case DRM_BUS_PCI:
3239 ret = drmProcessPciDevice(&device, dent->d_name, node, node_type,
3240 maj, min, devices != NULL);
3241 if (ret)
3242 goto free_devices;
3243
3244 break;
3245 default:
3246 fprintf(stderr, "The subsystem type is not supported yet\n");
3247 continue;
3248 }
3249
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;
3261 i++;
3262 }
3263 node_count = i;
3264
3265 /* Fold nodes into a single device if they share the same bus info */
3266 drmFoldDuplicatedDevices(local_devices, node_count);
3267
3268 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++;
3276 }
3277
3278 closedir(sysdir);
3279 free(local_devices);
3280 return device_count;
3281
3282 free_devices:
3283 drmFreeDevices(local_devices, i);
3284 closedir(sysdir);
3285
3286 free_locals:
3287 free(local_devices);
3288 return ret;
3289 }
3290