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