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 <unistd.h>
40 #include <string.h>
41 #include <strings.h>
42 #include <ctype.h>
43 #include <dirent.h>
44 #include <stddef.h>
45 #include <fcntl.h>
46 #include <errno.h>
47 #include <signal.h>
48 #include <time.h>
49 #include <sys/types.h>
50 #include <sys/sysmacros.h>
51 #include <sys/stat.h>
52 #define stat_t struct stat
53 #include <sys/ioctl.h>
54 #include <sys/time.h>
55 #include <stdarg.h>
56 #ifdef HAVE_SYS_MKDEV_H
57 # include <sys/mkdev.h> /* defines major(), minor(), and makedev() on Solaris */
58 #endif
59
60 /* Not all systems have MAP_FAILED defined */
61 #ifndef MAP_FAILED
62 #define MAP_FAILED ((void *)-1)
63 #endif
64
65 #include "xf86drm.h"
66 //#include "xf86drmCSC.h"
67 #include "libdrm_macros.h"
68 #include "i915_drm.h"
69
70 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
71 #define DRM_MAJOR 145
72 #endif
73
74 #ifdef __NetBSD__
75 #define DRM_MAJOR 34
76 #endif
77
78 # ifdef __OpenBSD__
79 # define DRM_MAJOR 81
80 # endif
81
82 #ifndef DRM_MAJOR
83 #define DRM_MAJOR 226 /* Linux */
84 #endif
85
86 /*
87 * This definition needs to be changed on some systems if dev_t is a structure.
88 * If there is a header file we can get it from, there would be best.
89 */
90 #ifndef makedev
91 #define makedev(x,y) ((dev_t)(((x) << 8) | (y)))
92 #endif
93
94 #define DRM_MSG_VERBOSITY 3
95
96 #define memclear(s) memset(&s, 0, sizeof(s))
97
98 static drmServerInfoPtr drm_server_info;
99
drmSetServerInfo(drmServerInfoPtr info)100 void drmSetServerInfo(drmServerInfoPtr info)
101 {
102 drm_server_info = info;
103 }
104
105 /**
106 * Output a message to stderr.
107 *
108 * \param format printf() like format string.
109 *
110 * \internal
111 * This function is a wrapper around vfprintf().
112 */
113
114 static int DRM_PRINTFLIKE(1, 0)
drmDebugPrint(const char * format,va_list ap)115 drmDebugPrint(const char *format, va_list ap)
116 {
117 return vfprintf(stderr, format, ap);
118 }
119
120 void
drmMsg(const char * format,...)121 drmMsg(const char *format, ...)
122 {
123 va_list ap;
124 const char *env;
125 if (((env = getenv("LIBGL_DEBUG")) && strstr(env, "verbose")) || drm_server_info)
126 {
127 va_start(ap, format);
128 if (drm_server_info) {
129 drm_server_info->debug_print(format,ap);
130 } else {
131 drmDebugPrint(format, ap);
132 }
133 va_end(ap);
134 }
135 }
136
137 static void *drmHashTable = nullptr; /* Context switch callbacks */
138
drmGetHashTable(void)139 void *drmGetHashTable(void)
140 {
141 return drmHashTable;
142 }
143
drmMalloc(int size)144 void *drmMalloc(int size)
145 {
146 void *pt;
147 if ((pt = malloc(size)))
148 memset(pt, 0, size);
149 return pt;
150 }
151
drmFree(void * pt)152 void drmFree(void *pt)
153 {
154 if (pt)
155 free(pt);
156 }
157
158 /**
159 * Call ioctl, restarting if it is interupted
160 */
161
162 #if defined(__cplusplus)
163 extern "C" {
164 #endif
165 drm_export int
mosdrmIoctl(int fd,unsigned long request,void * arg)166 mosdrmIoctl(int fd, unsigned long request, void *arg)
167 {
168 int ret;
169
170 do {
171 ret = ioctl(fd, request, arg);
172 } while (ret == -1 && (errno == EINTR || errno == EAGAIN));
173 return ret;
174 }
175 drm_export int
drmIoctl(int fd,unsigned long request,void * arg)176 drmIoctl(int fd, unsigned long request, void *arg)
177 {
178 return mosdrmIoctl(fd,request,arg);
179 }
180 #if defined(__cplusplus)
181 }
182 #endif
183
drmGetKeyFromFd(int fd)184 static unsigned long drmGetKeyFromFd(int fd)
185 {
186 stat_t st;
187
188 st.st_rdev = 0;
189 fstat(fd, &st);
190 return st.st_rdev;
191 }
192
drmGetEntry(int fd)193 drmHashEntry *drmGetEntry(int fd)
194 {
195 unsigned long key = drmGetKeyFromFd(fd);
196 void *value = nullptr;
197 drmHashEntry *entry;
198
199 if (!drmHashTable)
200 drmHashTable = drmHashCreate();
201
202 if (drmHashTable && drmHashLookup(drmHashTable, key, &value)) {
203 entry = (drmHashEntry *)drmMalloc(sizeof(*entry));
204 if (!entry)
205 return nullptr;
206 entry->fd = fd;
207 entry->f = nullptr;
208 entry->tagTable = drmHashCreate();
209 if (entry->tagTable) {
210 drmHashInsert(drmHashTable, key, entry);
211 } else {
212 drmFree(entry);
213 entry = nullptr;
214 }
215 } else {
216 entry = (drmHashEntry *)value;
217 }
218 return entry;
219 }
220 /**
221 * Compare two busid strings
222 *
223 * \param first
224 * \param second
225 *
226 * \return 1 if matched.
227 *
228 * \internal
229 * This function compares two bus ID strings. It understands the older
230 * PCI:b:d:f format and the newer pci:oooo:bb:dd.f format. In the format, o is
231 * domain, b is bus, d is device, f is function.
232 */
drmMatchBusID(const char * id1,const char * id2,int pci_domain_ok)233 static int drmMatchBusID(const char *id1, const char *id2, int pci_domain_ok)
234 {
235 /* First, check if the IDs are exactly the same */
236 if (strcasecmp(id1, id2) == 0)
237 return 1;
238
239 /* Try to match old/new-style PCI bus IDs. */
240 if (strncasecmp(id1, "pci", 3) == 0) {
241 unsigned int o1, b1, d1, f1;
242 unsigned int o2, b2, d2, f2;
243 int ret;
244
245 ret = sscanf(id1, "pci:%04x:%02x:%02x.%u", &o1, &b1, &d1, &f1);
246 if (ret != 4) {
247 o1 = 0;
248 ret = sscanf(id1, "PCI:%u:%u:%u", &b1, &d1, &f1);
249 if (ret != 3)
250 return 0;
251 }
252
253 ret = sscanf(id2, "pci:%04x:%02x:%02x.%u", &o2, &b2, &d2, &f2);
254 if (ret != 4) {
255 o2 = 0;
256 ret = sscanf(id2, "PCI:%u:%u:%u", &b2, &d2, &f2);
257 if (ret != 3)
258 return 0;
259 }
260
261 /* If domains aren't properly supported by the kernel interface,
262 * just ignore them, which sucks less than picking a totally random
263 * card with "open by name"
264 */
265 if (!pci_domain_ok)
266 o1 = o2 = 0;
267
268 if ((o1 != o2) || (b1 != b2) || (d1 != d2) || (f1 != f2))
269 return 0;
270 else
271 return 1;
272 }
273 return 0;
274 }
275
276 /**
277 * Handles error checking for chown call.
278 *
279 * \param path to file.
280 * \param id of the new owner.
281 * \param id of the new group.
282 *
283 * \return zero if success or -1 if failure.
284 *
285 * \internal
286 * Checks for failure. If failure was caused by signal call chown again.
287 * If any other failure happened then it will output error mesage using
288 * drmMsg() call.
289 */
290 #if !defined(UDEV)
chown_check_return(const char * path,uid_t owner,gid_t group)291 static int chown_check_return(const char *path, uid_t owner, gid_t group)
292 {
293 int rv;
294
295 do {
296 rv = chown(path, owner, group);
297 } while (rv != 0 && errno == EINTR);
298
299 if (rv == 0)
300 return 0;
301
302 drmMsg("Failed to change owner or group for file %s! %d: %s\n",
303 path, errno, strerror(errno));
304 return -1;
305 }
306 #endif
307
308 /**
309 * Open the DRM device, creating it if necessary.
310 *
311 * \param dev major and minor numbers of the device.
312 * \param minor minor number of the device.
313 *
314 * \return a file descriptor on success, or a negative value on error.
315 *
316 * \internal
317 * Assembles the device name from \p minor and opens it, creating the device
318 * special file node with the major and minor numbers specified by \p dev and
319 * parent directory if necessary and was called by root.
320 */
drmOpenDevice(dev_t dev,int minor,int type)321 static int drmOpenDevice(dev_t dev, int minor, int type)
322 {
323 stat_t st;
324 const char *dev_name;
325 char buf[64];
326 int fd;
327 mode_t devmode = DRM_DEV_MODE, serv_mode;
328 gid_t serv_group;
329 #if !defined(UDEV)
330 int isroot = !geteuid();
331 uid_t user = DRM_DEV_UID;
332 gid_t group = DRM_DEV_GID;
333 #endif
334
335 switch (type) {
336 case DRM_NODE_PRIMARY:
337 dev_name = DRM_DEV_NAME;
338 break;
339 case DRM_NODE_CONTROL:
340 dev_name = DRM_CONTROL_DEV_NAME;
341 break;
342 case DRM_NODE_RENDER:
343 dev_name = DRM_RENDER_DEV_NAME;
344 break;
345 default:
346 return -EINVAL;
347 };
348
349 snprintf(buf, sizeof(buf), dev_name, DRM_DIR_NAME, minor);
350 drmMsg("drmOpenDevice: node name is %s\n", buf);
351
352 if (drm_server_info) {
353 drm_server_info->get_perms(&serv_group, &serv_mode);
354 devmode = serv_mode ? serv_mode : DRM_DEV_MODE;
355 devmode &= ~(S_IXUSR|S_IXGRP|S_IXOTH);
356 }
357
358 #if !defined(UDEV)
359 if (stat(DRM_DIR_NAME, &st)) {
360 if (!isroot)
361 return DRM_ERR_NOT_ROOT;
362 mkdir(DRM_DIR_NAME, DRM_DEV_DIRMODE);
363 chown_check_return(DRM_DIR_NAME, 0, 0); /* root:root */
364 chmod(DRM_DIR_NAME, DRM_DEV_DIRMODE);
365 }
366
367 /* Check if the device node exists and create it if necessary. */
368 if (stat(buf, &st)) {
369 if (!isroot)
370 return DRM_ERR_NOT_ROOT;
371 remove(buf);
372 mknod(buf, S_IFCHR | devmode, dev);
373 }
374
375 if (drm_server_info) {
376 group = serv_group; /*(serv_group >= 0) ? serv_group : DRM_DEV_GID;*/
377 chown_check_return(buf, user, group);
378 chmod(buf, devmode);
379 }
380 #else
381 /* if we modprobed then wait for udev */
382 {
383 int udev_count = 0;
384 wait_for_udev:
385 if (stat(DRM_DIR_NAME, &st)) {
386 usleep(20);
387 udev_count++;
388
389 if (udev_count == 50)
390 return -1;
391 goto wait_for_udev;
392 }
393
394 if (stat(buf, &st)) {
395 usleep(20);
396 udev_count++;
397
398 if (udev_count == 50)
399 return -1;
400 goto wait_for_udev;
401 }
402 }
403 #endif
404
405 fd = open(buf, O_RDWR, 0);
406 drmMsg("drmOpenDevice: open result is %d, (%s)\n",
407 fd, fd < 0 ? strerror(errno) : "OK");
408 if (fd >= 0)
409 return fd;
410
411 #if !defined(UDEV)
412 /* Check if the device node is not what we expect it to be, and recreate it
413 * and try again if so.
414 */
415 if (st.st_rdev != dev) {
416 if (!isroot)
417 return DRM_ERR_NOT_ROOT;
418 remove(buf);
419 mknod(buf, S_IFCHR | devmode, dev);
420 if (drm_server_info) {
421 chown_check_return(buf, user, group);
422 chmod(buf, devmode);
423 }
424 }
425 fd = open(buf, O_RDWR, 0);
426 drmMsg("drmOpenDevice: open result is %d, (%s)\n",
427 fd, fd < 0 ? strerror(errno) : "OK");
428 if (fd >= 0)
429 return fd;
430
431 drmMsg("drmOpenDevice: Open failed\n");
432 remove(buf);
433 #endif
434 return -errno;
435 }
436
437 /**
438 * Open the DRM device
439 *
440 * \param minor device minor number.
441 * \param create allow to create the device if set.
442 *
443 * \return a file descriptor on success, or a negative value on error.
444 *
445 * \internal
446 * Calls drmOpenDevice() if \p create is set, otherwise assembles the device
447 * name from \p minor and opens it.
448 */
drmOpenMinor(int minor,int create,int type)449 static int drmOpenMinor(int minor, int create, int type)
450 {
451 int fd;
452 char buf[64];
453 const char *dev_name;
454
455 if (create)
456 return drmOpenDevice(makedev(DRM_MAJOR, minor), minor, type);
457
458 switch (type) {
459 case DRM_NODE_PRIMARY:
460 dev_name = DRM_DEV_NAME;
461 break;
462 case DRM_NODE_CONTROL:
463 dev_name = DRM_CONTROL_DEV_NAME;
464 break;
465 case DRM_NODE_RENDER:
466 dev_name = DRM_RENDER_DEV_NAME;
467 break;
468 default:
469 return -EINVAL;
470 };
471
472 sprintf(buf, dev_name, DRM_DIR_NAME, minor);
473 if ((fd = open(buf, O_RDWR, 0)) >= 0)
474 return fd;
475 return -errno;
476 }
477
478 /**
479 * Determine whether the DRM kernel driver has been loaded.
480 *
481 * \return 1 if the DRM driver is loaded, 0 otherwise.
482 *
483 * \internal
484 * Determine the presence of the kernel driver by attempting to open the 0
485 * minor and get version information. For backward compatibility with older
486 * Linux implementations, /proc/dri is also checked.
487 */
drmAvailable(void)488 int drmAvailable(void)
489 {
490 drmVersionPtr version;
491 int retval = 0;
492 int fd;
493
494 if ((fd = drmOpenMinor(0, 1, DRM_NODE_PRIMARY)) < 0) {
495 #ifdef __linux__
496 /* Try proc for backward Linux compatibility */
497 if (!access("/proc/dri/0", R_OK))
498 return 1;
499 #endif
500 return 0;
501 }
502
503 if ((version = drmGetVersion(fd))) {
504 retval = 1;
505 drmFreeVersion(version);
506 }
507 close(fd);
508
509 return retval;
510 }
511
drmGetMinorBase(int type)512 static int drmGetMinorBase(int type)
513 {
514 switch (type) {
515 case DRM_NODE_PRIMARY:
516 return 0;
517 case DRM_NODE_CONTROL:
518 return 64;
519 case DRM_NODE_RENDER:
520 return 128;
521 default:
522 return -1;
523 };
524 }
525
drmGetMinorType(int minor)526 static int drmGetMinorType(int minor)
527 {
528 int type = minor >> 6;
529
530 if (minor < 0)
531 return -1;
532
533 switch (type) {
534 case DRM_NODE_PRIMARY:
535 case DRM_NODE_CONTROL:
536 case DRM_NODE_RENDER:
537 return type;
538 default:
539 return -1;
540 }
541 }
542
drmGetMinorName(int type)543 static const char *drmGetMinorName(int type)
544 {
545 switch (type) {
546 case DRM_NODE_PRIMARY:
547 return "card";
548 case DRM_NODE_CONTROL:
549 return "controlD";
550 case DRM_NODE_RENDER:
551 return "renderD";
552 default:
553 return nullptr;
554 }
555 }
556
557 /**
558 * Open the device by bus ID.
559 *
560 * \param busid bus ID.
561 * \param type device node type.
562 *
563 * \return a file descriptor on success, or a negative value on error.
564 *
565 * \internal
566 * This function attempts to open every possible minor (up to DRM_MAX_MINOR),
567 * comparing the device bus ID with the one supplied.
568 *
569 * \sa drmOpenMinor() and drmGetBusid().
570 */
drmOpenByBusid(const char * busid,int type)571 static int drmOpenByBusid(const char *busid, int type)
572 {
573 int i, pci_domain_ok = 1;
574 int fd;
575 const char *buf;
576 drmSetVersion sv;
577 int base = drmGetMinorBase(type);
578
579 if (base < 0)
580 return -1;
581
582 drmMsg("drmOpenByBusid: Searching for BusID %s\n", busid);
583 for (i = base; i < base + DRM_MAX_MINOR; i++) {
584 fd = drmOpenMinor(i, 1, type);
585 drmMsg("drmOpenByBusid: drmOpenMinor returns %d\n", fd);
586 if (fd >= 0) {
587 /* We need to try for 1.4 first for proper PCI domain support
588 * and if that fails, we know the kernel is busted
589 */
590 sv.drm_di_major = 1;
591 sv.drm_di_minor = 4;
592 sv.drm_dd_major = -1; /* Don't care */
593 sv.drm_dd_minor = -1; /* Don't care */
594 if (drmSetInterfaceVersion(fd, &sv)) {
595 #ifndef __alpha__
596 pci_domain_ok = 0;
597 #endif
598 sv.drm_di_major = 1;
599 sv.drm_di_minor = 1;
600 sv.drm_dd_major = -1; /* Don't care */
601 sv.drm_dd_minor = -1; /* Don't care */
602 drmMsg("drmOpenByBusid: Interface 1.4 failed, trying 1.1\n");
603 drmSetInterfaceVersion(fd, &sv);
604 }
605 buf = drmGetBusid(fd);
606 if (buf) {
607 drmMsg("drmOpenByBusid: drmGetBusid reports %s\n", buf);
608 if (drmMatchBusID(buf, busid, pci_domain_ok)) {
609 drmFreeBusid(buf);
610 return fd;
611 }
612 drmFreeBusid(buf);
613 }
614 close(fd);
615 }
616 }
617 return -1;
618 }
619
620 /**
621 * Open the device by name.
622 *
623 * \param name driver name.
624 * \param type the device node type.
625 *
626 * \return a file descriptor on success, or a negative value on error.
627 *
628 * \internal
629 * This function opens the first minor number that matches the driver name and
630 * isn't already in use. If it's in use it then it will already have a bus ID
631 * assigned.
632 *
633 * \sa drmOpenMinor(), drmGetVersion() and drmGetBusid().
634 */
drmOpenByName(const char * name,int type)635 static int drmOpenByName(const char *name, int type)
636 {
637 int i;
638 int fd;
639 drmVersionPtr version;
640 char * id;
641 int base = drmGetMinorBase(type);
642
643 if (base < 0)
644 return -1;
645
646 /*
647 * Open the first minor number that matches the driver name and isn't
648 * already in use. If it's in use it will have a busid assigned already.
649 */
650 for (i = base; i < base + DRM_MAX_MINOR; i++) {
651 if ((fd = drmOpenMinor(i, 1, type)) >= 0) {
652 if ((version = drmGetVersion(fd))) {
653 if (!strcmp(version->name, name)) {
654 drmFreeVersion(version);
655 id = drmGetBusid(fd);
656 drmMsg("drmGetBusid returned '%s'\n", id ? id : "NULL");
657 if (!id || !*id) {
658 if (id)
659 drmFreeBusid(id);
660 return fd;
661 } else {
662 drmFreeBusid(id);
663 }
664 } else {
665 drmFreeVersion(version);
666 }
667 }
668 close(fd);
669 }
670 }
671
672 #ifdef __linux__
673 /* Backward-compatibility /proc support */
674 for (i = 0; i < 8; i++) {
675 char proc_name[64], buf[512];
676 char *driver, *pt, *devstring;
677 int retcode;
678
679 sprintf(proc_name, "/proc/dri/%d/name", i);
680 if ((fd = open(proc_name, 0, 0)) >= 0) {
681 retcode = read(fd, buf, sizeof(buf)-1);
682 close(fd);
683 if (retcode > 0) {
684 buf[retcode-1] = '\0';
685 for (driver = pt = buf; *pt && *pt != ' '; ++pt)
686 ;
687 if (*pt) { /* Device is next */
688 *pt = '\0';
689 if (!strcmp(driver, name)) { /* Match */
690 for (devstring = ++pt; *pt && *pt != ' '; ++pt)
691 ;
692 if (*pt) { /* Found busid */
693 return drmOpenByBusid(++pt, type);
694 } else { /* No busid */
695 return drmOpenDevice(strtol(devstring, nullptr, 0),i, type);
696 }
697 }
698 }
699 }
700 }
701 }
702 #endif
703
704 return -1;
705 }
706
707 /**
708 * Open the DRM device.
709 *
710 * Looks up the specified name and bus ID, and opens the device found. The
711 * entry in /dev/dri is created if necessary and if called by root.
712 *
713 * \param name driver name. Not referenced if bus ID is supplied.
714 * \param busid bus ID. Zero if not known.
715 *
716 * \return a file descriptor on success, or a negative value on error.
717 *
718 * \internal
719 * It calls drmOpenByBusid() if \p busid is specified or drmOpenByName()
720 * otherwise.
721 */
drmOpen(const char * name,const char * busid)722 int drmOpen(const char *name, const char *busid)
723 {
724 return drmOpenWithType(name, busid, DRM_NODE_PRIMARY);
725 }
726
727 /**
728 * Open the DRM device with specified type.
729 *
730 * Looks up the specified name and bus ID, and opens the device found. The
731 * entry in /dev/dri is created if necessary and if called by root.
732 *
733 * \param name driver name. Not referenced if bus ID is supplied.
734 * \param busid bus ID. Zero if not known.
735 * \param type the device node type to open, PRIMARY, CONTROL or RENDER
736 *
737 * \return a file descriptor on success, or a negative value on error.
738 *
739 * \internal
740 * It calls drmOpenByBusid() if \p busid is specified or drmOpenByName()
741 * otherwise.
742 */
drmOpenWithType(const char * name,const char * busid,int type)743 int drmOpenWithType(const char *name, const char *busid, int type)
744 {
745 if (!drmAvailable() && name != nullptr && drm_server_info) {
746 /* try to load the kernel module */
747 if (!drm_server_info->load_module(name)) {
748 drmMsg("[drm] failed to load kernel module \"%s\"\n", name);
749 return -1;
750 }
751 }
752
753 if (busid) {
754 int fd = drmOpenByBusid(busid, type);
755 if (fd >= 0)
756 return fd;
757 }
758
759 if (name)
760 return drmOpenByName(name, type);
761
762 return -1;
763 }
764
drmOpenControl(int minor)765 int drmOpenControl(int minor)
766 {
767 return drmOpenMinor(minor, 0, DRM_NODE_CONTROL);
768 }
769
drmOpenRender(int minor)770 int drmOpenRender(int minor)
771 {
772 return drmOpenMinor(minor, 0, DRM_NODE_RENDER);
773 }
774
775 /**
776 * Free the version information returned by drmGetVersion().
777 *
778 * \param v pointer to the version information.
779 *
780 * \internal
781 * It frees the memory pointed by \p %v as well as all the non-null strings
782 * pointers in it.
783 */
drmFreeVersion(drmVersionPtr v)784 void drmFreeVersion(drmVersionPtr v)
785 {
786 if (!v)
787 return;
788 drmFree(v->name);
789 drmFree(v->date);
790 drmFree(v->desc);
791 drmFree(v);
792 }
793
794 /**
795 * Free the non-public version information returned by the kernel.
796 *
797 * \param v pointer to the version information.
798 *
799 * \internal
800 * Used by drmGetVersion() to free the memory pointed by \p %v as well as all
801 * the non-null strings pointers in it.
802 */
drmFreeKernelVersion(drm_version_t * v)803 static void drmFreeKernelVersion(drm_version_t *v)
804 {
805 if (!v)
806 return;
807 drmFree(v->name);
808 drmFree(v->date);
809 drmFree(v->desc);
810 drmFree(v);
811 }
812
813 /**
814 * Copy version information.
815 *
816 * \param d destination pointer.
817 * \param s source pointer.
818 *
819 * \internal
820 * Used by drmGetVersion() to translate the information returned by the ioctl
821 * interface in a private structure into the public structure counterpart.
822 */
drmCopyVersion(drmVersionPtr d,const drm_version_t * s)823 static void drmCopyVersion(drmVersionPtr d, const drm_version_t *s)
824 {
825 d->version_major = s->version_major;
826 d->version_minor = s->version_minor;
827 d->version_patchlevel = s->version_patchlevel;
828 d->name_len = s->name_len;
829 d->name = strdup(s->name);
830 d->date_len = s->date_len;
831 d->date = strdup(s->date);
832 d->desc_len = s->desc_len;
833 d->desc = strdup(s->desc);
834 }
835
836 /**
837 * Query the driver version information.
838 *
839 * \param fd file descriptor.
840 *
841 * \return pointer to a drmVersion structure which should be freed with
842 * drmFreeVersion().
843 *
844 * \note Similar information is available via /proc/dri.
845 *
846 * \internal
847 * It gets the version information via successive DRM_IOCTL_VERSION ioctls,
848 * first with zeros to get the string lengths, and then the actually strings.
849 * It also null-terminates them since they might not be already.
850 */
drmGetVersion(int fd)851 drmVersionPtr drmGetVersion(int fd)
852 {
853 drmVersionPtr retval;
854 drm_version_t *version = (drm_version_t *)drmMalloc(sizeof(*version));
855 if (!version)
856 return nullptr;
857
858 memclear(*version);
859
860 if (drmIoctl(fd, DRM_IOCTL_VERSION, version)) {
861 drmFreeKernelVersion(version);
862 return nullptr;
863 }
864
865 if (version->name_len)
866 version->name = (char *)drmMalloc(version->name_len + 1);
867 if (version->date_len)
868 version->date = (char *)drmMalloc(version->date_len + 1);
869 if (version->desc_len)
870 version->desc = (char *)drmMalloc(version->desc_len + 1);
871
872 if (drmIoctl(fd, DRM_IOCTL_VERSION, version)) {
873 drmMsg("DRM_IOCTL_VERSION: %s\n", strerror(errno));
874 drmFreeKernelVersion(version);
875 return nullptr;
876 }
877
878 /* The results might not be null-terminated strings, so terminate them. */
879 if (version->name_len) version->name[version->name_len] = '\0';
880 if (version->date_len) version->date[version->date_len] = '\0';
881 if (version->desc_len) version->desc[version->desc_len] = '\0';
882
883 retval = (drmVersionPtr)drmMalloc(sizeof(*retval));
884 if (retval)
885 drmCopyVersion(retval, version);
886
887 drmFreeKernelVersion(version);
888 return retval;
889 }
890
891 /**
892 * Free the bus ID information.
893 *
894 * \param busid bus ID information string as given by drmGetBusid().
895 *
896 * \internal
897 * This function is just frees the memory pointed by \p busid.
898 */
drmFreeBusid(const char * busid)899 void drmFreeBusid(const char *busid)
900 {
901 drmFree((void *)busid);
902 }
903
904 /**
905 * Get the bus ID of the device.
906 *
907 * \param fd file descriptor.
908 *
909 * \return bus ID string.
910 *
911 * \internal
912 * This function gets the bus ID via successive DRM_IOCTL_GET_UNIQUE ioctls to
913 * get the string length and data, passing the arguments in a drm_unique
914 * structure.
915 */
drmGetBusid(int fd)916 char *drmGetBusid(int fd)
917 {
918 drm_unique_t u;
919
920 memclear(u);
921
922 if (drmIoctl(fd, DRM_IOCTL_GET_UNIQUE, &u))
923 return nullptr;
924 u.unique = (char *)drmMalloc(u.unique_len + 1);
925 if (drmIoctl(fd, DRM_IOCTL_GET_UNIQUE, &u))
926 return nullptr;
927 u.unique[u.unique_len] = '\0';
928
929 return u.unique;
930 }
931
932 /**
933 * Close the device.
934 *
935 * \param fd file descriptor.
936 *
937 * \internal
938 * This function closes the file descriptor.
939 */
drmClose(int fd)940 int drmClose(int fd)
941 {
942 unsigned long key = drmGetKeyFromFd(fd);
943 drmHashEntry *entry = drmGetEntry(fd);
944 if(!entry)
945 return -ENOMEM;
946
947 drmHashDestroy(entry->tagTable);
948 entry->fd = 0;
949 entry->f = nullptr;
950 entry->tagTable = nullptr;
951
952 drmHashDelete(drmHashTable, key);
953 drmFree(entry);
954
955 return close(fd);
956 }
957
958 /**
959 * Issue a set-version ioctl.
960 *
961 * \param fd file descriptor.
962 * \param drmCommandIndex command index
963 * \param data source pointer of the data to be read and written.
964 * \param size size of the data to be read and written.
965 *
966 * \return zero on success, or a negative value on failure.
967 *
968 * \internal
969 * It issues a read-write ioctl given by
970 * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
971 */
drmSetInterfaceVersion(int fd,drmSetVersion * version)972 int drmSetInterfaceVersion(int fd, drmSetVersion *version)
973 {
974 int retcode = 0;
975 drm_set_version_t sv;
976
977 memclear(sv);
978 sv.drm_di_major = version->drm_di_major;
979 sv.drm_di_minor = version->drm_di_minor;
980 sv.drm_dd_major = version->drm_dd_major;
981 sv.drm_dd_minor = version->drm_dd_minor;
982
983 if (drmIoctl(fd, DRM_IOCTL_SET_VERSION, &sv)) {
984 retcode = -errno;
985 }
986
987 version->drm_di_major = sv.drm_di_major;
988 version->drm_di_minor = sv.drm_di_minor;
989 version->drm_dd_major = sv.drm_dd_major;
990 version->drm_dd_minor = sv.drm_dd_minor;
991
992 return retcode;
993 }
994
995 #define DRM_MAX_FDS 16
996 static struct {
997 char *BusID;
998 int fd;
999 int refcount;
1000 int type;
1001 } connection[DRM_MAX_FDS];
1002
1003 static int nr_fds = 0;
1004
drmPrimeHandleToFD(int fd,uint32_t handle,uint32_t flags,int * prime_fd)1005 int drmPrimeHandleToFD(int fd, uint32_t handle, uint32_t flags, int *prime_fd)
1006 {
1007 struct drm_prime_handle args;
1008 int ret;
1009
1010 args.handle = handle;
1011 args.flags = flags;
1012 ret = drmIoctl(fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &args);
1013 if (ret)
1014 return ret;
1015
1016 *prime_fd = args.fd;
1017 return 0;
1018 }
1019
drmPrimeFDToHandle(int fd,int prime_fd,uint32_t * handle)1020 int drmPrimeFDToHandle(int fd, int prime_fd, uint32_t *handle)
1021 {
1022 struct drm_prime_handle args;
1023 int ret;
1024
1025 args.fd = prime_fd;
1026 args.flags = 0;
1027 ret = drmIoctl(fd, DRM_IOCTL_PRIME_FD_TO_HANDLE, &args);
1028 if (ret)
1029 return ret;
1030
1031 *handle = args.handle;
1032 return 0;
1033 }
1034