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