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