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