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