xref: /aosp_15_r20/external/intel-media-driver/media_softlet/linux/common/os/i915/xf86drm.c (revision ba62d9d3abf0e404f2022b4cd7a85e107f48596f)
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