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 <stdbool.h>
40 #include <unistd.h>
41 #include <string.h>
42 #include <strings.h>
43 #include <ctype.h>
44 #include <dirent.h>
45 #include <stddef.h>
46 #include <fcntl.h>
47 #include <errno.h>
48 #include <limits.h>
49 #include <signal.h>
50 #include <time.h>
51 #include <sys/types.h>
52 #include <sys/stat.h>
53 #define stat_t struct stat
54 #include <sys/ioctl.h>
55 #include <sys/time.h>
56 #include <stdarg.h>
57 #ifdef MAJOR_IN_MKDEV
58 #include <sys/mkdev.h>
59 #endif
60 #ifdef MAJOR_IN_SYSMACROS
61 #include <sys/sysmacros.h>
62 #endif
63 #include <math.h>
64
65 /* Not all systems have MAP_FAILED defined */
66 #ifndef MAP_FAILED
67 #define MAP_FAILED ((void *)-1)
68 #endif
69
70 #include "xf86drm.h"
71 #include "libdrm_macros.h"
72
73 #include "util_math.h"
74
75 #ifdef __OpenBSD__
76 #define DRM_PRIMARY_MINOR_NAME "drm"
77 #define DRM_CONTROL_MINOR_NAME "drmC"
78 #define DRM_RENDER_MINOR_NAME "drmR"
79 #else
80 #define DRM_PRIMARY_MINOR_NAME "card"
81 #define DRM_CONTROL_MINOR_NAME "controlD"
82 #define DRM_RENDER_MINOR_NAME "renderD"
83 #endif
84
85 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
86 #define DRM_MAJOR 145
87 #endif
88
89 #ifdef __NetBSD__
90 #define DRM_MAJOR 34
91 #endif
92
93 #ifdef __OpenBSD__
94 #ifdef __i386__
95 #define DRM_MAJOR 88
96 #else
97 #define DRM_MAJOR 87
98 #endif
99 #endif /* __OpenBSD__ */
100
101 #ifndef DRM_MAJOR
102 #define DRM_MAJOR 226 /* Linux */
103 #endif
104
105 #ifdef __OpenBSD__
106 struct drm_pciinfo {
107 uint16_t domain;
108 uint8_t bus;
109 uint8_t dev;
110 uint8_t func;
111 uint16_t vendor_id;
112 uint16_t device_id;
113 uint16_t subvendor_id;
114 uint16_t subdevice_id;
115 uint8_t revision_id;
116 };
117
118 #define DRM_IOCTL_GET_PCIINFO DRM_IOR(0x15, struct drm_pciinfo)
119 #endif
120
121 #define DRM_MSG_VERBOSITY 3
122
123 #define memclear(s) memset(&s, 0, sizeof(s))
124
125 static drmServerInfoPtr drm_server_info;
126
drmSetServerInfo(drmServerInfoPtr info)127 void drmSetServerInfo(drmServerInfoPtr info)
128 {
129 drm_server_info = info;
130 }
131
132 /**
133 * Output a message to stderr.
134 *
135 * \param format printf() like format string.
136 *
137 * \internal
138 * This function is a wrapper around vfprintf().
139 */
140
141 static int DRM_PRINTFLIKE(1, 0)
drmDebugPrint(const char * format,va_list ap)142 drmDebugPrint(const char *format, va_list ap)
143 {
144 return vfprintf(stderr, format, ap);
145 }
146
147 void
drmMsg(const char * format,...)148 drmMsg(const char *format, ...)
149 {
150 va_list ap;
151 const char *env;
152 if (((env = getenv("LIBGL_DEBUG")) && strstr(env, "verbose")) ||
153 (drm_server_info && drm_server_info->debug_print))
154 {
155 va_start(ap, format);
156 if (drm_server_info) {
157 drm_server_info->debug_print(format,ap);
158 } else {
159 drmDebugPrint(format, ap);
160 }
161 va_end(ap);
162 }
163 }
164
165 static void *drmHashTable = NULL; /* Context switch callbacks */
166
drmGetHashTable(void)167 void *drmGetHashTable(void)
168 {
169 return drmHashTable;
170 }
171
drmMalloc(int size)172 void *drmMalloc(int size)
173 {
174 return calloc(1, size);
175 }
176
drmFree(void * pt)177 void drmFree(void *pt)
178 {
179 free(pt);
180 }
181
182 /**
183 * Call ioctl, restarting if it is interupted
184 */
185 int
drmIoctl(int fd,unsigned long request,void * arg)186 drmIoctl(int fd, unsigned long request, void *arg)
187 {
188 int ret;
189
190 do {
191 ret = ioctl(fd, request, arg);
192 } while (ret == -1 && (errno == EINTR || errno == EAGAIN));
193 return ret;
194 }
195
drmGetKeyFromFd(int fd)196 static unsigned long drmGetKeyFromFd(int fd)
197 {
198 stat_t st;
199
200 st.st_rdev = 0;
201 fstat(fd, &st);
202 return st.st_rdev;
203 }
204
drmGetEntry(int fd)205 drmHashEntry *drmGetEntry(int fd)
206 {
207 unsigned long key = drmGetKeyFromFd(fd);
208 void *value;
209 drmHashEntry *entry;
210
211 if (!drmHashTable)
212 drmHashTable = drmHashCreate();
213
214 if (drmHashLookup(drmHashTable, key, &value)) {
215 entry = drmMalloc(sizeof(*entry));
216 entry->fd = fd;
217 entry->f = NULL;
218 entry->tagTable = drmHashCreate();
219 drmHashInsert(drmHashTable, key, entry);
220 } else {
221 entry = value;
222 }
223 return entry;
224 }
225
226 /**
227 * Compare two busid strings
228 *
229 * \param first
230 * \param second
231 *
232 * \return 1 if matched.
233 *
234 * \internal
235 * This function compares two bus ID strings. It understands the older
236 * PCI:b:d:f format and the newer pci:oooo:bb:dd.f format. In the format, o is
237 * domain, b is bus, d is device, f is function.
238 */
drmMatchBusID(const char * id1,const char * id2,int pci_domain_ok)239 static int drmMatchBusID(const char *id1, const char *id2, int pci_domain_ok)
240 {
241 /* First, check if the IDs are exactly the same */
242 if (strcasecmp(id1, id2) == 0)
243 return 1;
244
245 /* Try to match old/new-style PCI bus IDs. */
246 if (strncasecmp(id1, "pci", 3) == 0) {
247 unsigned int o1, b1, d1, f1;
248 unsigned int o2, b2, d2, f2;
249 int ret;
250
251 ret = sscanf(id1, "pci:%04x:%02x:%02x.%u", &o1, &b1, &d1, &f1);
252 if (ret != 4) {
253 o1 = 0;
254 ret = sscanf(id1, "PCI:%u:%u:%u", &b1, &d1, &f1);
255 if (ret != 3)
256 return 0;
257 }
258
259 ret = sscanf(id2, "pci:%04x:%02x:%02x.%u", &o2, &b2, &d2, &f2);
260 if (ret != 4) {
261 o2 = 0;
262 ret = sscanf(id2, "PCI:%u:%u:%u", &b2, &d2, &f2);
263 if (ret != 3)
264 return 0;
265 }
266
267 /* If domains aren't properly supported by the kernel interface,
268 * just ignore them, which sucks less than picking a totally random
269 * card with "open by name"
270 */
271 if (!pci_domain_ok)
272 o1 = o2 = 0;
273
274 if ((o1 != o2) || (b1 != b2) || (d1 != d2) || (f1 != f2))
275 return 0;
276 else
277 return 1;
278 }
279 return 0;
280 }
281
282 /**
283 * Handles error checking for chown call.
284 *
285 * \param path to file.
286 * \param id of the new owner.
287 * \param id of the new group.
288 *
289 * \return zero if success or -1 if failure.
290 *
291 * \internal
292 * Checks for failure. If failure was caused by signal call chown again.
293 * If any other failure happened then it will output error mesage using
294 * drmMsg() call.
295 */
296 #if !defined(UDEV)
chown_check_return(const char * path,uid_t owner,gid_t group)297 static int chown_check_return(const char *path, uid_t owner, gid_t group)
298 {
299 int rv;
300
301 do {
302 rv = chown(path, owner, group);
303 } while (rv != 0 && errno == EINTR);
304
305 if (rv == 0)
306 return 0;
307
308 drmMsg("Failed to change owner or group for file %s! %d: %s\n",
309 path, errno, strerror(errno));
310 return -1;
311 }
312 #endif
313
314 /**
315 * Open the DRM device, creating it if necessary.
316 *
317 * \param dev major and minor numbers of the device.
318 * \param minor minor number of the device.
319 *
320 * \return a file descriptor on success, or a negative value on error.
321 *
322 * \internal
323 * Assembles the device name from \p minor and opens it, creating the device
324 * special file node with the major and minor numbers specified by \p dev and
325 * parent directory if necessary and was called by root.
326 */
drmOpenDevice(dev_t dev,int minor,int type)327 static int drmOpenDevice(dev_t dev, int minor, int type)
328 {
329 stat_t st;
330 const char *dev_name;
331 char buf[64];
332 int fd;
333 mode_t devmode = DRM_DEV_MODE, serv_mode;
334 gid_t serv_group;
335 #if !defined(UDEV)
336 int isroot = !geteuid();
337 uid_t user = DRM_DEV_UID;
338 gid_t group = DRM_DEV_GID;
339 #endif
340
341 switch (type) {
342 case DRM_NODE_PRIMARY:
343 dev_name = DRM_DEV_NAME;
344 break;
345 case DRM_NODE_CONTROL:
346 dev_name = DRM_CONTROL_DEV_NAME;
347 break;
348 case DRM_NODE_RENDER:
349 dev_name = DRM_RENDER_DEV_NAME;
350 break;
351 default:
352 return -EINVAL;
353 };
354
355 sprintf(buf, dev_name, DRM_DIR_NAME, minor);
356 drmMsg("drmOpenDevice: node name is %s\n", buf);
357
358 if (drm_server_info && drm_server_info->get_perms) {
359 drm_server_info->get_perms(&serv_group, &serv_mode);
360 devmode = serv_mode ? serv_mode : DRM_DEV_MODE;
361 devmode &= ~(S_IXUSR|S_IXGRP|S_IXOTH);
362 }
363
364 #if !defined(UDEV)
365 if (stat(DRM_DIR_NAME, &st)) {
366 if (!isroot)
367 return DRM_ERR_NOT_ROOT;
368 mkdir(DRM_DIR_NAME, DRM_DEV_DIRMODE);
369 chown_check_return(DRM_DIR_NAME, 0, 0); /* root:root */
370 chmod(DRM_DIR_NAME, DRM_DEV_DIRMODE);
371 }
372
373 /* Check if the device node exists and create it if necessary. */
374 if (stat(buf, &st)) {
375 if (!isroot)
376 return DRM_ERR_NOT_ROOT;
377 remove(buf);
378 mknod(buf, S_IFCHR | devmode, dev);
379 }
380
381 if (drm_server_info && drm_server_info->get_perms) {
382 group = ((int)serv_group >= 0) ? serv_group : DRM_DEV_GID;
383 chown_check_return(buf, user, group);
384 chmod(buf, devmode);
385 }
386 #else
387 /* if we modprobed then wait for udev */
388 {
389 int udev_count = 0;
390 wait_for_udev:
391 if (stat(DRM_DIR_NAME, &st)) {
392 usleep(20);
393 udev_count++;
394
395 if (udev_count == 50)
396 return -1;
397 goto wait_for_udev;
398 }
399
400 if (stat(buf, &st)) {
401 usleep(20);
402 udev_count++;
403
404 if (udev_count == 50)
405 return -1;
406 goto wait_for_udev;
407 }
408 }
409 #endif
410
411 fd = open(buf, O_RDWR, 0);
412 drmMsg("drmOpenDevice: open result is %d, (%s)\n",
413 fd, fd < 0 ? strerror(errno) : "OK");
414 if (fd >= 0)
415 return fd;
416
417 #if !defined(UDEV)
418 /* Check if the device node is not what we expect it to be, and recreate it
419 * and try again if so.
420 */
421 if (st.st_rdev != dev) {
422 if (!isroot)
423 return DRM_ERR_NOT_ROOT;
424 remove(buf);
425 mknod(buf, S_IFCHR | devmode, dev);
426 if (drm_server_info && drm_server_info->get_perms) {
427 chown_check_return(buf, user, group);
428 chmod(buf, devmode);
429 }
430 }
431 fd = open(buf, O_RDWR, 0);
432 drmMsg("drmOpenDevice: open result is %d, (%s)\n",
433 fd, fd < 0 ? strerror(errno) : "OK");
434 if (fd >= 0)
435 return fd;
436
437 drmMsg("drmOpenDevice: Open failed\n");
438 remove(buf);
439 #endif
440 return -errno;
441 }
442
443
444 /**
445 * Open the DRM device
446 *
447 * \param minor device minor number.
448 * \param create allow to create the device if set.
449 *
450 * \return a file descriptor on success, or a negative value on error.
451 *
452 * \internal
453 * Calls drmOpenDevice() if \p create is set, otherwise assembles the device
454 * name from \p minor and opens it.
455 */
drmOpenMinor(int minor,int create,int type)456 static int drmOpenMinor(int minor, int create, int type)
457 {
458 int fd;
459 char buf[64];
460 const char *dev_name;
461
462 if (create)
463 return drmOpenDevice(makedev(DRM_MAJOR, minor), minor, type);
464
465 switch (type) {
466 case DRM_NODE_PRIMARY:
467 dev_name = DRM_DEV_NAME;
468 break;
469 case DRM_NODE_CONTROL:
470 dev_name = DRM_CONTROL_DEV_NAME;
471 break;
472 case DRM_NODE_RENDER:
473 dev_name = DRM_RENDER_DEV_NAME;
474 break;
475 default:
476 return -EINVAL;
477 };
478
479 sprintf(buf, dev_name, DRM_DIR_NAME, minor);
480 if ((fd = open(buf, O_RDWR, 0)) >= 0)
481 return fd;
482 return -errno;
483 }
484
485
486 /**
487 * Determine whether the DRM kernel driver has been loaded.
488 *
489 * \return 1 if the DRM driver is loaded, 0 otherwise.
490 *
491 * \internal
492 * Determine the presence of the kernel driver by attempting to open the 0
493 * minor and get version information. For backward compatibility with older
494 * Linux implementations, /proc/dri is also checked.
495 */
drmAvailable(void)496 int drmAvailable(void)
497 {
498 drmVersionPtr version;
499 int retval = 0;
500 int fd;
501
502 if ((fd = drmOpenMinor(0, 1, DRM_NODE_PRIMARY)) < 0) {
503 #ifdef __linux__
504 /* Try proc for backward Linux compatibility */
505 if (!access("/proc/dri/0", R_OK))
506 return 1;
507 #endif
508 return 0;
509 }
510
511 if ((version = drmGetVersion(fd))) {
512 retval = 1;
513 drmFreeVersion(version);
514 }
515 close(fd);
516
517 return retval;
518 }
519
drmGetMinorBase(int type)520 static int drmGetMinorBase(int type)
521 {
522 switch (type) {
523 case DRM_NODE_PRIMARY:
524 return 0;
525 case DRM_NODE_CONTROL:
526 return 64;
527 case DRM_NODE_RENDER:
528 return 128;
529 default:
530 return -1;
531 };
532 }
533
drmGetMinorType(int minor)534 static int drmGetMinorType(int minor)
535 {
536 int type = minor >> 6;
537
538 if (minor < 0)
539 return -1;
540
541 switch (type) {
542 case DRM_NODE_PRIMARY:
543 case DRM_NODE_CONTROL:
544 case DRM_NODE_RENDER:
545 return type;
546 default:
547 return -1;
548 }
549 }
550
drmGetMinorName(int type)551 static const char *drmGetMinorName(int type)
552 {
553 switch (type) {
554 case DRM_NODE_PRIMARY:
555 return DRM_PRIMARY_MINOR_NAME;
556 case DRM_NODE_CONTROL:
557 return DRM_CONTROL_MINOR_NAME;
558 case DRM_NODE_RENDER:
559 return DRM_RENDER_MINOR_NAME;
560 default:
561 return NULL;
562 }
563 }
564
565 /**
566 * Open the device by bus ID.
567 *
568 * \param busid bus ID.
569 * \param type device node type.
570 *
571 * \return a file descriptor on success, or a negative value on error.
572 *
573 * \internal
574 * This function attempts to open every possible minor (up to DRM_MAX_MINOR),
575 * comparing the device bus ID with the one supplied.
576 *
577 * \sa drmOpenMinor() and drmGetBusid().
578 */
drmOpenByBusid(const char * busid,int type)579 static int drmOpenByBusid(const char *busid, int type)
580 {
581 int i, pci_domain_ok = 1;
582 int fd;
583 const char *buf;
584 drmSetVersion sv;
585 int base = drmGetMinorBase(type);
586
587 if (base < 0)
588 return -1;
589
590 drmMsg("drmOpenByBusid: Searching for BusID %s\n", busid);
591 for (i = base; i < base + DRM_MAX_MINOR; i++) {
592 fd = drmOpenMinor(i, 1, type);
593 drmMsg("drmOpenByBusid: drmOpenMinor returns %d\n", fd);
594 if (fd >= 0) {
595 /* We need to try for 1.4 first for proper PCI domain support
596 * and if that fails, we know the kernel is busted
597 */
598 sv.drm_di_major = 1;
599 sv.drm_di_minor = 4;
600 sv.drm_dd_major = -1; /* Don't care */
601 sv.drm_dd_minor = -1; /* Don't care */
602 if (drmSetInterfaceVersion(fd, &sv)) {
603 #ifndef __alpha__
604 pci_domain_ok = 0;
605 #endif
606 sv.drm_di_major = 1;
607 sv.drm_di_minor = 1;
608 sv.drm_dd_major = -1; /* Don't care */
609 sv.drm_dd_minor = -1; /* Don't care */
610 drmMsg("drmOpenByBusid: Interface 1.4 failed, trying 1.1\n");
611 drmSetInterfaceVersion(fd, &sv);
612 }
613 buf = drmGetBusid(fd);
614 drmMsg("drmOpenByBusid: drmGetBusid reports %s\n", buf);
615 if (buf && drmMatchBusID(buf, busid, pci_domain_ok)) {
616 drmFreeBusid(buf);
617 return fd;
618 }
619 if (buf)
620 drmFreeBusid(buf);
621 close(fd);
622 }
623 }
624 return -1;
625 }
626
627
628 /**
629 * Open the device by name.
630 *
631 * \param name driver name.
632 * \param type the device node type.
633 *
634 * \return a file descriptor on success, or a negative value on error.
635 *
636 * \internal
637 * This function opens the first minor number that matches the driver name and
638 * isn't already in use. If it's in use it then it will already have a bus ID
639 * assigned.
640 *
641 * \sa drmOpenMinor(), drmGetVersion() and drmGetBusid().
642 */
drmOpenByName(const char * name,int type)643 static int drmOpenByName(const char *name, int type)
644 {
645 int i;
646 int fd;
647 drmVersionPtr version;
648 char * id;
649 int base = drmGetMinorBase(type);
650
651 if (base < 0)
652 return -1;
653
654 /*
655 * Open the first minor number that matches the driver name and isn't
656 * already in use. If it's in use it will have a busid assigned already.
657 */
658 for (i = base; i < base + DRM_MAX_MINOR; i++) {
659 if ((fd = drmOpenMinor(i, 1, type)) >= 0) {
660 if ((version = drmGetVersion(fd))) {
661 if (!strcmp(version->name, name)) {
662 drmFreeVersion(version);
663 id = drmGetBusid(fd);
664 drmMsg("drmGetBusid returned '%s'\n", id ? id : "NULL");
665 if (!id || !*id) {
666 if (id)
667 drmFreeBusid(id);
668 return fd;
669 } else {
670 drmFreeBusid(id);
671 }
672 } else {
673 drmFreeVersion(version);
674 }
675 }
676 close(fd);
677 }
678 }
679
680 #ifdef __linux__
681 /* Backward-compatibility /proc support */
682 for (i = 0; i < 8; i++) {
683 char proc_name[64], buf[512];
684 char *driver, *pt, *devstring;
685 int retcode;
686
687 sprintf(proc_name, "/proc/dri/%d/name", i);
688 if ((fd = open(proc_name, 0, 0)) >= 0) {
689 retcode = read(fd, buf, sizeof(buf)-1);
690 close(fd);
691 if (retcode) {
692 buf[retcode-1] = '\0';
693 for (driver = pt = buf; *pt && *pt != ' '; ++pt)
694 ;
695 if (*pt) { /* Device is next */
696 *pt = '\0';
697 if (!strcmp(driver, name)) { /* Match */
698 for (devstring = ++pt; *pt && *pt != ' '; ++pt)
699 ;
700 if (*pt) { /* Found busid */
701 return drmOpenByBusid(++pt, type);
702 } else { /* No busid */
703 return drmOpenDevice(strtol(devstring, NULL, 0),i, type);
704 }
705 }
706 }
707 }
708 }
709 }
710 #endif
711
712 return -1;
713 }
714
715
716 /**
717 * Open the DRM device.
718 *
719 * Looks up the specified name and bus ID, and opens the device found. The
720 * entry in /dev/dri is created if necessary and if called by root.
721 *
722 * \param name driver name. Not referenced if bus ID is supplied.
723 * \param busid bus ID. Zero if not known.
724 *
725 * \return a file descriptor on success, or a negative value on error.
726 *
727 * \internal
728 * It calls drmOpenByBusid() if \p busid is specified or drmOpenByName()
729 * otherwise.
730 */
drmOpen(const char * name,const char * busid)731 int drmOpen(const char *name, const char *busid)
732 {
733 return drmOpenWithType(name, busid, DRM_NODE_PRIMARY);
734 }
735
736 /**
737 * Open the DRM device with specified type.
738 *
739 * Looks up the specified name and bus ID, and opens the device found. The
740 * entry in /dev/dri is created if necessary and if called by root.
741 *
742 * \param name driver name. Not referenced if bus ID is supplied.
743 * \param busid bus ID. Zero if not known.
744 * \param type the device node type to open, PRIMARY, CONTROL or RENDER
745 *
746 * \return a file descriptor on success, or a negative value on error.
747 *
748 * \internal
749 * It calls drmOpenByBusid() if \p busid is specified or drmOpenByName()
750 * otherwise.
751 */
drmOpenWithType(const char * name,const char * busid,int type)752 int drmOpenWithType(const char *name, const char *busid, int type)
753 {
754 if (name != NULL && drm_server_info &&
755 drm_server_info->load_module && !drmAvailable()) {
756 /* try to load the kernel module */
757 if (!drm_server_info->load_module(name)) {
758 drmMsg("[drm] failed to load kernel module \"%s\"\n", name);
759 return -1;
760 }
761 }
762
763 if (busid) {
764 int fd = drmOpenByBusid(busid, type);
765 if (fd >= 0)
766 return fd;
767 }
768
769 if (name)
770 return drmOpenByName(name, type);
771
772 return -1;
773 }
774
drmOpenControl(int minor)775 int drmOpenControl(int minor)
776 {
777 return drmOpenMinor(minor, 0, DRM_NODE_CONTROL);
778 }
779
drmOpenRender(int minor)780 int drmOpenRender(int minor)
781 {
782 return drmOpenMinor(minor, 0, DRM_NODE_RENDER);
783 }
784
785 /**
786 * Free the version information returned by drmGetVersion().
787 *
788 * \param v pointer to the version information.
789 *
790 * \internal
791 * It frees the memory pointed by \p %v as well as all the non-null strings
792 * pointers in it.
793 */
drmFreeVersion(drmVersionPtr v)794 void drmFreeVersion(drmVersionPtr v)
795 {
796 if (!v)
797 return;
798 drmFree(v->name);
799 drmFree(v->date);
800 drmFree(v->desc);
801 drmFree(v);
802 }
803
804
805 /**
806 * Free the non-public version information returned by the kernel.
807 *
808 * \param v pointer to the version information.
809 *
810 * \internal
811 * Used by drmGetVersion() to free the memory pointed by \p %v as well as all
812 * the non-null strings pointers in it.
813 */
drmFreeKernelVersion(drm_version_t * v)814 static void drmFreeKernelVersion(drm_version_t *v)
815 {
816 if (!v)
817 return;
818 drmFree(v->name);
819 drmFree(v->date);
820 drmFree(v->desc);
821 drmFree(v);
822 }
823
824
825 /**
826 * Copy version information.
827 *
828 * \param d destination pointer.
829 * \param s source pointer.
830 *
831 * \internal
832 * Used by drmGetVersion() to translate the information returned by the ioctl
833 * interface in a private structure into the public structure counterpart.
834 */
drmCopyVersion(drmVersionPtr d,const drm_version_t * s)835 static void drmCopyVersion(drmVersionPtr d, const drm_version_t *s)
836 {
837 d->version_major = s->version_major;
838 d->version_minor = s->version_minor;
839 d->version_patchlevel = s->version_patchlevel;
840 d->name_len = s->name_len;
841 d->name = strdup(s->name);
842 d->date_len = s->date_len;
843 d->date = strdup(s->date);
844 d->desc_len = s->desc_len;
845 d->desc = strdup(s->desc);
846 }
847
848
849 /**
850 * Query the driver version information.
851 *
852 * \param fd file descriptor.
853 *
854 * \return pointer to a drmVersion structure which should be freed with
855 * drmFreeVersion().
856 *
857 * \note Similar information is available via /proc/dri.
858 *
859 * \internal
860 * It gets the version information via successive DRM_IOCTL_VERSION ioctls,
861 * first with zeros to get the string lengths, and then the actually strings.
862 * It also null-terminates them since they might not be already.
863 */
drmGetVersion(int fd)864 drmVersionPtr drmGetVersion(int fd)
865 {
866 drmVersionPtr retval;
867 drm_version_t *version = drmMalloc(sizeof(*version));
868
869 memclear(*version);
870
871 if (drmIoctl(fd, DRM_IOCTL_VERSION, version)) {
872 drmFreeKernelVersion(version);
873 return NULL;
874 }
875
876 if (version->name_len)
877 version->name = drmMalloc(version->name_len + 1);
878 if (version->date_len)
879 version->date = drmMalloc(version->date_len + 1);
880 if (version->desc_len)
881 version->desc = drmMalloc(version->desc_len + 1);
882
883 if (drmIoctl(fd, DRM_IOCTL_VERSION, version)) {
884 drmMsg("DRM_IOCTL_VERSION: %s\n", strerror(errno));
885 drmFreeKernelVersion(version);
886 return NULL;
887 }
888
889 /* The results might not be null-terminated strings, so terminate them. */
890 if (version->name_len) version->name[version->name_len] = '\0';
891 if (version->date_len) version->date[version->date_len] = '\0';
892 if (version->desc_len) version->desc[version->desc_len] = '\0';
893
894 retval = drmMalloc(sizeof(*retval));
895 drmCopyVersion(retval, version);
896 drmFreeKernelVersion(version);
897 return retval;
898 }
899
900
901 /**
902 * Get version information for the DRM user space library.
903 *
904 * This version number is driver independent.
905 *
906 * \param fd file descriptor.
907 *
908 * \return version information.
909 *
910 * \internal
911 * This function allocates and fills a drm_version structure with a hard coded
912 * version number.
913 */
drmGetLibVersion(int fd)914 drmVersionPtr drmGetLibVersion(int fd)
915 {
916 drm_version_t *version = drmMalloc(sizeof(*version));
917
918 /* Version history:
919 * NOTE THIS MUST NOT GO ABOVE VERSION 1.X due to drivers needing it
920 * revision 1.0.x = original DRM interface with no drmGetLibVersion
921 * entry point and many drm<Device> extensions
922 * revision 1.1.x = added drmCommand entry points for device extensions
923 * added drmGetLibVersion to identify libdrm.a version
924 * revision 1.2.x = added drmSetInterfaceVersion
925 * modified drmOpen to handle both busid and name
926 * revision 1.3.x = added server + memory manager
927 */
928 version->version_major = 1;
929 version->version_minor = 3;
930 version->version_patchlevel = 0;
931
932 return (drmVersionPtr)version;
933 }
934
drmGetCap(int fd,uint64_t capability,uint64_t * value)935 int drmGetCap(int fd, uint64_t capability, uint64_t *value)
936 {
937 struct drm_get_cap cap;
938 int ret;
939
940 memclear(cap);
941 cap.capability = capability;
942
943 ret = drmIoctl(fd, DRM_IOCTL_GET_CAP, &cap);
944 if (ret)
945 return ret;
946
947 *value = cap.value;
948 return 0;
949 }
950
drmSetClientCap(int fd,uint64_t capability,uint64_t value)951 int drmSetClientCap(int fd, uint64_t capability, uint64_t value)
952 {
953 struct drm_set_client_cap cap;
954
955 memclear(cap);
956 cap.capability = capability;
957 cap.value = value;
958
959 return drmIoctl(fd, DRM_IOCTL_SET_CLIENT_CAP, &cap);
960 }
961
962 /**
963 * Free the bus ID information.
964 *
965 * \param busid bus ID information string as given by drmGetBusid().
966 *
967 * \internal
968 * This function is just frees the memory pointed by \p busid.
969 */
drmFreeBusid(const char * busid)970 void drmFreeBusid(const char *busid)
971 {
972 drmFree((void *)busid);
973 }
974
975
976 /**
977 * Get the bus ID of the device.
978 *
979 * \param fd file descriptor.
980 *
981 * \return bus ID string.
982 *
983 * \internal
984 * This function gets the bus ID via successive DRM_IOCTL_GET_UNIQUE ioctls to
985 * get the string length and data, passing the arguments in a drm_unique
986 * structure.
987 */
drmGetBusid(int fd)988 char *drmGetBusid(int fd)
989 {
990 drm_unique_t u;
991
992 memclear(u);
993
994 if (drmIoctl(fd, DRM_IOCTL_GET_UNIQUE, &u))
995 return NULL;
996 u.unique = drmMalloc(u.unique_len + 1);
997 if (drmIoctl(fd, DRM_IOCTL_GET_UNIQUE, &u))
998 return NULL;
999 u.unique[u.unique_len] = '\0';
1000
1001 return u.unique;
1002 }
1003
1004
1005 /**
1006 * Set the bus ID of the device.
1007 *
1008 * \param fd file descriptor.
1009 * \param busid bus ID string.
1010 *
1011 * \return zero on success, negative on failure.
1012 *
1013 * \internal
1014 * This function is a wrapper around the DRM_IOCTL_SET_UNIQUE ioctl, passing
1015 * the arguments in a drm_unique structure.
1016 */
drmSetBusid(int fd,const char * busid)1017 int drmSetBusid(int fd, const char *busid)
1018 {
1019 drm_unique_t u;
1020
1021 memclear(u);
1022 u.unique = (char *)busid;
1023 u.unique_len = strlen(busid);
1024
1025 if (drmIoctl(fd, DRM_IOCTL_SET_UNIQUE, &u)) {
1026 return -errno;
1027 }
1028 return 0;
1029 }
1030
drmGetMagic(int fd,drm_magic_t * magic)1031 int drmGetMagic(int fd, drm_magic_t * magic)
1032 {
1033 drm_auth_t auth;
1034
1035 memclear(auth);
1036
1037 *magic = 0;
1038 if (drmIoctl(fd, DRM_IOCTL_GET_MAGIC, &auth))
1039 return -errno;
1040 *magic = auth.magic;
1041 return 0;
1042 }
1043
drmAuthMagic(int fd,drm_magic_t magic)1044 int drmAuthMagic(int fd, drm_magic_t magic)
1045 {
1046 drm_auth_t auth;
1047
1048 memclear(auth);
1049 auth.magic = magic;
1050 if (drmIoctl(fd, DRM_IOCTL_AUTH_MAGIC, &auth))
1051 return -errno;
1052 return 0;
1053 }
1054
1055 /**
1056 * Specifies a range of memory that is available for mapping by a
1057 * non-root process.
1058 *
1059 * \param fd file descriptor.
1060 * \param offset usually the physical address. The actual meaning depends of
1061 * the \p type parameter. See below.
1062 * \param size of the memory in bytes.
1063 * \param type type of the memory to be mapped.
1064 * \param flags combination of several flags to modify the function actions.
1065 * \param handle will be set to a value that may be used as the offset
1066 * parameter for mmap().
1067 *
1068 * \return zero on success or a negative value on error.
1069 *
1070 * \par Mapping the frame buffer
1071 * For the frame buffer
1072 * - \p offset will be the physical address of the start of the frame buffer,
1073 * - \p size will be the size of the frame buffer in bytes, and
1074 * - \p type will be DRM_FRAME_BUFFER.
1075 *
1076 * \par
1077 * The area mapped will be uncached. If MTRR support is available in the
1078 * kernel, the frame buffer area will be set to write combining.
1079 *
1080 * \par Mapping the MMIO register area
1081 * For the MMIO register area,
1082 * - \p offset will be the physical address of the start of the register area,
1083 * - \p size will be the size of the register area bytes, and
1084 * - \p type will be DRM_REGISTERS.
1085 * \par
1086 * The area mapped will be uncached.
1087 *
1088 * \par Mapping the SAREA
1089 * For the SAREA,
1090 * - \p offset will be ignored and should be set to zero,
1091 * - \p size will be the desired size of the SAREA in bytes,
1092 * - \p type will be DRM_SHM.
1093 *
1094 * \par
1095 * A shared memory area of the requested size will be created and locked in
1096 * kernel memory. This area may be mapped into client-space by using the handle
1097 * returned.
1098 *
1099 * \note May only be called by root.
1100 *
1101 * \internal
1102 * This function is a wrapper around the DRM_IOCTL_ADD_MAP ioctl, passing
1103 * the arguments in a drm_map structure.
1104 */
drmAddMap(int fd,drm_handle_t offset,drmSize size,drmMapType type,drmMapFlags flags,drm_handle_t * handle)1105 int drmAddMap(int fd, drm_handle_t offset, drmSize size, drmMapType type,
1106 drmMapFlags flags, drm_handle_t *handle)
1107 {
1108 drm_map_t map;
1109
1110 memclear(map);
1111 map.offset = offset;
1112 map.size = size;
1113 map.type = type;
1114 map.flags = flags;
1115 if (drmIoctl(fd, DRM_IOCTL_ADD_MAP, &map))
1116 return -errno;
1117 if (handle)
1118 *handle = (drm_handle_t)(uintptr_t)map.handle;
1119 return 0;
1120 }
1121
drmRmMap(int fd,drm_handle_t handle)1122 int drmRmMap(int fd, drm_handle_t handle)
1123 {
1124 drm_map_t map;
1125
1126 memclear(map);
1127 map.handle = (void *)(uintptr_t)handle;
1128
1129 if(drmIoctl(fd, DRM_IOCTL_RM_MAP, &map))
1130 return -errno;
1131 return 0;
1132 }
1133
1134 /**
1135 * Make buffers available for DMA transfers.
1136 *
1137 * \param fd file descriptor.
1138 * \param count number of buffers.
1139 * \param size size of each buffer.
1140 * \param flags buffer allocation flags.
1141 * \param agp_offset offset in the AGP aperture
1142 *
1143 * \return number of buffers allocated, negative on error.
1144 *
1145 * \internal
1146 * This function is a wrapper around DRM_IOCTL_ADD_BUFS ioctl.
1147 *
1148 * \sa drm_buf_desc.
1149 */
drmAddBufs(int fd,int count,int size,drmBufDescFlags flags,int agp_offset)1150 int drmAddBufs(int fd, int count, int size, drmBufDescFlags flags,
1151 int agp_offset)
1152 {
1153 drm_buf_desc_t request;
1154
1155 memclear(request);
1156 request.count = count;
1157 request.size = size;
1158 request.flags = flags;
1159 request.agp_start = agp_offset;
1160
1161 if (drmIoctl(fd, DRM_IOCTL_ADD_BUFS, &request))
1162 return -errno;
1163 return request.count;
1164 }
1165
drmMarkBufs(int fd,double low,double high)1166 int drmMarkBufs(int fd, double low, double high)
1167 {
1168 drm_buf_info_t info;
1169 int i;
1170
1171 memclear(info);
1172
1173 if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info))
1174 return -EINVAL;
1175
1176 if (!info.count)
1177 return -EINVAL;
1178
1179 if (!(info.list = drmMalloc(info.count * sizeof(*info.list))))
1180 return -ENOMEM;
1181
1182 if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info)) {
1183 int retval = -errno;
1184 drmFree(info.list);
1185 return retval;
1186 }
1187
1188 for (i = 0; i < info.count; i++) {
1189 info.list[i].low_mark = low * info.list[i].count;
1190 info.list[i].high_mark = high * info.list[i].count;
1191 if (drmIoctl(fd, DRM_IOCTL_MARK_BUFS, &info.list[i])) {
1192 int retval = -errno;
1193 drmFree(info.list);
1194 return retval;
1195 }
1196 }
1197 drmFree(info.list);
1198
1199 return 0;
1200 }
1201
1202 /**
1203 * Free buffers.
1204 *
1205 * \param fd file descriptor.
1206 * \param count number of buffers to free.
1207 * \param list list of buffers to be freed.
1208 *
1209 * \return zero on success, or a negative value on failure.
1210 *
1211 * \note This function is primarily used for debugging.
1212 *
1213 * \internal
1214 * This function is a wrapper around the DRM_IOCTL_FREE_BUFS ioctl, passing
1215 * the arguments in a drm_buf_free structure.
1216 */
drmFreeBufs(int fd,int count,int * list)1217 int drmFreeBufs(int fd, int count, int *list)
1218 {
1219 drm_buf_free_t request;
1220
1221 memclear(request);
1222 request.count = count;
1223 request.list = list;
1224 if (drmIoctl(fd, DRM_IOCTL_FREE_BUFS, &request))
1225 return -errno;
1226 return 0;
1227 }
1228
1229
1230 /**
1231 * Close the device.
1232 *
1233 * \param fd file descriptor.
1234 *
1235 * \internal
1236 * This function closes the file descriptor.
1237 */
drmClose(int fd)1238 int drmClose(int fd)
1239 {
1240 unsigned long key = drmGetKeyFromFd(fd);
1241 drmHashEntry *entry = drmGetEntry(fd);
1242
1243 drmHashDestroy(entry->tagTable);
1244 entry->fd = 0;
1245 entry->f = NULL;
1246 entry->tagTable = NULL;
1247
1248 drmHashDelete(drmHashTable, key);
1249 drmFree(entry);
1250
1251 return close(fd);
1252 }
1253
1254
1255 /**
1256 * Map a region of memory.
1257 *
1258 * \param fd file descriptor.
1259 * \param handle handle returned by drmAddMap().
1260 * \param size size in bytes. Must match the size used by drmAddMap().
1261 * \param address will contain the user-space virtual address where the mapping
1262 * begins.
1263 *
1264 * \return zero on success, or a negative value on failure.
1265 *
1266 * \internal
1267 * This function is a wrapper for mmap().
1268 */
drmMap(int fd,drm_handle_t handle,drmSize size,drmAddressPtr address)1269 int drmMap(int fd, drm_handle_t handle, drmSize size, drmAddressPtr address)
1270 {
1271 static unsigned long pagesize_mask = 0;
1272
1273 if (fd < 0)
1274 return -EINVAL;
1275
1276 if (!pagesize_mask)
1277 pagesize_mask = getpagesize() - 1;
1278
1279 size = (size + pagesize_mask) & ~pagesize_mask;
1280
1281 *address = drm_mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, handle);
1282 if (*address == MAP_FAILED)
1283 return -errno;
1284 return 0;
1285 }
1286
1287
1288 /**
1289 * Unmap mappings obtained with drmMap().
1290 *
1291 * \param address address as given by drmMap().
1292 * \param size size in bytes. Must match the size used by drmMap().
1293 *
1294 * \return zero on success, or a negative value on failure.
1295 *
1296 * \internal
1297 * This function is a wrapper for munmap().
1298 */
drmUnmap(drmAddress address,drmSize size)1299 int drmUnmap(drmAddress address, drmSize size)
1300 {
1301 return drm_munmap(address, size);
1302 }
1303
drmGetBufInfo(int fd)1304 drmBufInfoPtr drmGetBufInfo(int fd)
1305 {
1306 drm_buf_info_t info;
1307 drmBufInfoPtr retval;
1308 int i;
1309
1310 memclear(info);
1311
1312 if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info))
1313 return NULL;
1314
1315 if (info.count) {
1316 if (!(info.list = drmMalloc(info.count * sizeof(*info.list))))
1317 return NULL;
1318
1319 if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info)) {
1320 drmFree(info.list);
1321 return NULL;
1322 }
1323
1324 retval = drmMalloc(sizeof(*retval));
1325 retval->count = info.count;
1326 retval->list = drmMalloc(info.count * sizeof(*retval->list));
1327 for (i = 0; i < info.count; i++) {
1328 retval->list[i].count = info.list[i].count;
1329 retval->list[i].size = info.list[i].size;
1330 retval->list[i].low_mark = info.list[i].low_mark;
1331 retval->list[i].high_mark = info.list[i].high_mark;
1332 }
1333 drmFree(info.list);
1334 return retval;
1335 }
1336 return NULL;
1337 }
1338
1339 /**
1340 * Map all DMA buffers into client-virtual space.
1341 *
1342 * \param fd file descriptor.
1343 *
1344 * \return a pointer to a ::drmBufMap structure.
1345 *
1346 * \note The client may not use these buffers until obtaining buffer indices
1347 * with drmDMA().
1348 *
1349 * \internal
1350 * This function calls the DRM_IOCTL_MAP_BUFS ioctl and copies the returned
1351 * information about the buffers in a drm_buf_map structure into the
1352 * client-visible data structures.
1353 */
drmMapBufs(int fd)1354 drmBufMapPtr drmMapBufs(int fd)
1355 {
1356 drm_buf_map_t bufs;
1357 drmBufMapPtr retval;
1358 int i;
1359
1360 memclear(bufs);
1361 if (drmIoctl(fd, DRM_IOCTL_MAP_BUFS, &bufs))
1362 return NULL;
1363
1364 if (!bufs.count)
1365 return NULL;
1366
1367 if (!(bufs.list = drmMalloc(bufs.count * sizeof(*bufs.list))))
1368 return NULL;
1369
1370 if (drmIoctl(fd, DRM_IOCTL_MAP_BUFS, &bufs)) {
1371 drmFree(bufs.list);
1372 return NULL;
1373 }
1374
1375 retval = drmMalloc(sizeof(*retval));
1376 retval->count = bufs.count;
1377 retval->list = drmMalloc(bufs.count * sizeof(*retval->list));
1378 for (i = 0; i < bufs.count; i++) {
1379 retval->list[i].idx = bufs.list[i].idx;
1380 retval->list[i].total = bufs.list[i].total;
1381 retval->list[i].used = 0;
1382 retval->list[i].address = bufs.list[i].address;
1383 }
1384
1385 drmFree(bufs.list);
1386 return retval;
1387 }
1388
1389
1390 /**
1391 * Unmap buffers allocated with drmMapBufs().
1392 *
1393 * \return zero on success, or negative value on failure.
1394 *
1395 * \internal
1396 * Calls munmap() for every buffer stored in \p bufs and frees the
1397 * memory allocated by drmMapBufs().
1398 */
drmUnmapBufs(drmBufMapPtr bufs)1399 int drmUnmapBufs(drmBufMapPtr bufs)
1400 {
1401 int i;
1402
1403 for (i = 0; i < bufs->count; i++) {
1404 drm_munmap(bufs->list[i].address, bufs->list[i].total);
1405 }
1406
1407 drmFree(bufs->list);
1408 drmFree(bufs);
1409 return 0;
1410 }
1411
1412
1413 #define DRM_DMA_RETRY 16
1414
1415 /**
1416 * Reserve DMA buffers.
1417 *
1418 * \param fd file descriptor.
1419 * \param request
1420 *
1421 * \return zero on success, or a negative value on failure.
1422 *
1423 * \internal
1424 * Assemble the arguments into a drm_dma structure and keeps issuing the
1425 * DRM_IOCTL_DMA ioctl until success or until maximum number of retries.
1426 */
drmDMA(int fd,drmDMAReqPtr request)1427 int drmDMA(int fd, drmDMAReqPtr request)
1428 {
1429 drm_dma_t dma;
1430 int ret, i = 0;
1431
1432 dma.context = request->context;
1433 dma.send_count = request->send_count;
1434 dma.send_indices = request->send_list;
1435 dma.send_sizes = request->send_sizes;
1436 dma.flags = request->flags;
1437 dma.request_count = request->request_count;
1438 dma.request_size = request->request_size;
1439 dma.request_indices = request->request_list;
1440 dma.request_sizes = request->request_sizes;
1441 dma.granted_count = 0;
1442
1443 do {
1444 ret = ioctl( fd, DRM_IOCTL_DMA, &dma );
1445 } while ( ret && errno == EAGAIN && i++ < DRM_DMA_RETRY );
1446
1447 if ( ret == 0 ) {
1448 request->granted_count = dma.granted_count;
1449 return 0;
1450 } else {
1451 return -errno;
1452 }
1453 }
1454
1455
1456 /**
1457 * Obtain heavyweight hardware lock.
1458 *
1459 * \param fd file descriptor.
1460 * \param context context.
1461 * \param flags flags that determine the sate of the hardware when the function
1462 * returns.
1463 *
1464 * \return always zero.
1465 *
1466 * \internal
1467 * This function translates the arguments into a drm_lock structure and issue
1468 * the DRM_IOCTL_LOCK ioctl until the lock is successfully acquired.
1469 */
drmGetLock(int fd,drm_context_t context,drmLockFlags flags)1470 int drmGetLock(int fd, drm_context_t context, drmLockFlags flags)
1471 {
1472 drm_lock_t lock;
1473
1474 memclear(lock);
1475 lock.context = context;
1476 lock.flags = 0;
1477 if (flags & DRM_LOCK_READY) lock.flags |= _DRM_LOCK_READY;
1478 if (flags & DRM_LOCK_QUIESCENT) lock.flags |= _DRM_LOCK_QUIESCENT;
1479 if (flags & DRM_LOCK_FLUSH) lock.flags |= _DRM_LOCK_FLUSH;
1480 if (flags & DRM_LOCK_FLUSH_ALL) lock.flags |= _DRM_LOCK_FLUSH_ALL;
1481 if (flags & DRM_HALT_ALL_QUEUES) lock.flags |= _DRM_HALT_ALL_QUEUES;
1482 if (flags & DRM_HALT_CUR_QUEUES) lock.flags |= _DRM_HALT_CUR_QUEUES;
1483
1484 while (drmIoctl(fd, DRM_IOCTL_LOCK, &lock))
1485 ;
1486 return 0;
1487 }
1488
1489 /**
1490 * Release the hardware lock.
1491 *
1492 * \param fd file descriptor.
1493 * \param context context.
1494 *
1495 * \return zero on success, or a negative value on failure.
1496 *
1497 * \internal
1498 * This function is a wrapper around the DRM_IOCTL_UNLOCK ioctl, passing the
1499 * argument in a drm_lock structure.
1500 */
drmUnlock(int fd,drm_context_t context)1501 int drmUnlock(int fd, drm_context_t context)
1502 {
1503 drm_lock_t lock;
1504
1505 memclear(lock);
1506 lock.context = context;
1507 return drmIoctl(fd, DRM_IOCTL_UNLOCK, &lock);
1508 }
1509
drmGetReservedContextList(int fd,int * count)1510 drm_context_t *drmGetReservedContextList(int fd, int *count)
1511 {
1512 drm_ctx_res_t res;
1513 drm_ctx_t *list;
1514 drm_context_t * retval;
1515 int i;
1516
1517 memclear(res);
1518 if (drmIoctl(fd, DRM_IOCTL_RES_CTX, &res))
1519 return NULL;
1520
1521 if (!res.count)
1522 return NULL;
1523
1524 if (!(list = drmMalloc(res.count * sizeof(*list))))
1525 return NULL;
1526 if (!(retval = drmMalloc(res.count * sizeof(*retval)))) {
1527 drmFree(list);
1528 return NULL;
1529 }
1530
1531 res.contexts = list;
1532 if (drmIoctl(fd, DRM_IOCTL_RES_CTX, &res))
1533 return NULL;
1534
1535 for (i = 0; i < res.count; i++)
1536 retval[i] = list[i].handle;
1537 drmFree(list);
1538
1539 *count = res.count;
1540 return retval;
1541 }
1542
drmFreeReservedContextList(drm_context_t * pt)1543 void drmFreeReservedContextList(drm_context_t *pt)
1544 {
1545 drmFree(pt);
1546 }
1547
1548 /**
1549 * Create context.
1550 *
1551 * Used by the X server during GLXContext initialization. This causes
1552 * per-context kernel-level resources to be allocated.
1553 *
1554 * \param fd file descriptor.
1555 * \param handle is set on success. To be used by the client when requesting DMA
1556 * dispatch with drmDMA().
1557 *
1558 * \return zero on success, or a negative value on failure.
1559 *
1560 * \note May only be called by root.
1561 *
1562 * \internal
1563 * This function is a wrapper around the DRM_IOCTL_ADD_CTX ioctl, passing the
1564 * argument in a drm_ctx structure.
1565 */
drmCreateContext(int fd,drm_context_t * handle)1566 int drmCreateContext(int fd, drm_context_t *handle)
1567 {
1568 drm_ctx_t ctx;
1569
1570 memclear(ctx);
1571 if (drmIoctl(fd, DRM_IOCTL_ADD_CTX, &ctx))
1572 return -errno;
1573 *handle = ctx.handle;
1574 return 0;
1575 }
1576
drmSwitchToContext(int fd,drm_context_t context)1577 int drmSwitchToContext(int fd, drm_context_t context)
1578 {
1579 drm_ctx_t ctx;
1580
1581 memclear(ctx);
1582 ctx.handle = context;
1583 if (drmIoctl(fd, DRM_IOCTL_SWITCH_CTX, &ctx))
1584 return -errno;
1585 return 0;
1586 }
1587
drmSetContextFlags(int fd,drm_context_t context,drm_context_tFlags flags)1588 int drmSetContextFlags(int fd, drm_context_t context, drm_context_tFlags flags)
1589 {
1590 drm_ctx_t ctx;
1591
1592 /*
1593 * Context preserving means that no context switches are done between DMA
1594 * buffers from one context and the next. This is suitable for use in the
1595 * X server (which promises to maintain hardware context), or in the
1596 * client-side library when buffers are swapped on behalf of two threads.
1597 */
1598 memclear(ctx);
1599 ctx.handle = context;
1600 if (flags & DRM_CONTEXT_PRESERVED)
1601 ctx.flags |= _DRM_CONTEXT_PRESERVED;
1602 if (flags & DRM_CONTEXT_2DONLY)
1603 ctx.flags |= _DRM_CONTEXT_2DONLY;
1604 if (drmIoctl(fd, DRM_IOCTL_MOD_CTX, &ctx))
1605 return -errno;
1606 return 0;
1607 }
1608
drmGetContextFlags(int fd,drm_context_t context,drm_context_tFlagsPtr flags)1609 int drmGetContextFlags(int fd, drm_context_t context,
1610 drm_context_tFlagsPtr flags)
1611 {
1612 drm_ctx_t ctx;
1613
1614 memclear(ctx);
1615 ctx.handle = context;
1616 if (drmIoctl(fd, DRM_IOCTL_GET_CTX, &ctx))
1617 return -errno;
1618 *flags = 0;
1619 if (ctx.flags & _DRM_CONTEXT_PRESERVED)
1620 *flags |= DRM_CONTEXT_PRESERVED;
1621 if (ctx.flags & _DRM_CONTEXT_2DONLY)
1622 *flags |= DRM_CONTEXT_2DONLY;
1623 return 0;
1624 }
1625
1626 /**
1627 * Destroy context.
1628 *
1629 * Free any kernel-level resources allocated with drmCreateContext() associated
1630 * with the context.
1631 *
1632 * \param fd file descriptor.
1633 * \param handle handle given by drmCreateContext().
1634 *
1635 * \return zero on success, or a negative value on failure.
1636 *
1637 * \note May only be called by root.
1638 *
1639 * \internal
1640 * This function is a wrapper around the DRM_IOCTL_RM_CTX ioctl, passing the
1641 * argument in a drm_ctx structure.
1642 */
drmDestroyContext(int fd,drm_context_t handle)1643 int drmDestroyContext(int fd, drm_context_t handle)
1644 {
1645 drm_ctx_t ctx;
1646
1647 memclear(ctx);
1648 ctx.handle = handle;
1649 if (drmIoctl(fd, DRM_IOCTL_RM_CTX, &ctx))
1650 return -errno;
1651 return 0;
1652 }
1653
drmCreateDrawable(int fd,drm_drawable_t * handle)1654 int drmCreateDrawable(int fd, drm_drawable_t *handle)
1655 {
1656 drm_draw_t draw;
1657
1658 memclear(draw);
1659 if (drmIoctl(fd, DRM_IOCTL_ADD_DRAW, &draw))
1660 return -errno;
1661 *handle = draw.handle;
1662 return 0;
1663 }
1664
drmDestroyDrawable(int fd,drm_drawable_t handle)1665 int drmDestroyDrawable(int fd, drm_drawable_t handle)
1666 {
1667 drm_draw_t draw;
1668
1669 memclear(draw);
1670 draw.handle = handle;
1671 if (drmIoctl(fd, DRM_IOCTL_RM_DRAW, &draw))
1672 return -errno;
1673 return 0;
1674 }
1675
drmUpdateDrawableInfo(int fd,drm_drawable_t handle,drm_drawable_info_type_t type,unsigned int num,void * data)1676 int drmUpdateDrawableInfo(int fd, drm_drawable_t handle,
1677 drm_drawable_info_type_t type, unsigned int num,
1678 void *data)
1679 {
1680 drm_update_draw_t update;
1681
1682 memclear(update);
1683 update.handle = handle;
1684 update.type = type;
1685 update.num = num;
1686 update.data = (unsigned long long)(unsigned long)data;
1687
1688 if (drmIoctl(fd, DRM_IOCTL_UPDATE_DRAW, &update))
1689 return -errno;
1690
1691 return 0;
1692 }
1693
1694 /**
1695 * Acquire the AGP device.
1696 *
1697 * Must be called before any of the other AGP related calls.
1698 *
1699 * \param fd file descriptor.
1700 *
1701 * \return zero on success, or a negative value on failure.
1702 *
1703 * \internal
1704 * This function is a wrapper around the DRM_IOCTL_AGP_ACQUIRE ioctl.
1705 */
drmAgpAcquire(int fd)1706 int drmAgpAcquire(int fd)
1707 {
1708 if (drmIoctl(fd, DRM_IOCTL_AGP_ACQUIRE, NULL))
1709 return -errno;
1710 return 0;
1711 }
1712
1713
1714 /**
1715 * Release the AGP device.
1716 *
1717 * \param fd file descriptor.
1718 *
1719 * \return zero on success, or a negative value on failure.
1720 *
1721 * \internal
1722 * This function is a wrapper around the DRM_IOCTL_AGP_RELEASE ioctl.
1723 */
drmAgpRelease(int fd)1724 int drmAgpRelease(int fd)
1725 {
1726 if (drmIoctl(fd, DRM_IOCTL_AGP_RELEASE, NULL))
1727 return -errno;
1728 return 0;
1729 }
1730
1731
1732 /**
1733 * Set the AGP mode.
1734 *
1735 * \param fd file descriptor.
1736 * \param mode AGP mode.
1737 *
1738 * \return zero on success, or a negative value on failure.
1739 *
1740 * \internal
1741 * This function is a wrapper around the DRM_IOCTL_AGP_ENABLE ioctl, passing the
1742 * argument in a drm_agp_mode structure.
1743 */
drmAgpEnable(int fd,unsigned long mode)1744 int drmAgpEnable(int fd, unsigned long mode)
1745 {
1746 drm_agp_mode_t m;
1747
1748 memclear(m);
1749 m.mode = mode;
1750 if (drmIoctl(fd, DRM_IOCTL_AGP_ENABLE, &m))
1751 return -errno;
1752 return 0;
1753 }
1754
1755
1756 /**
1757 * Allocate a chunk of AGP memory.
1758 *
1759 * \param fd file descriptor.
1760 * \param size requested memory size in bytes. Will be rounded to page boundary.
1761 * \param type type of memory to allocate.
1762 * \param address if not zero, will be set to the physical address of the
1763 * allocated memory.
1764 * \param handle on success will be set to a handle of the allocated memory.
1765 *
1766 * \return zero on success, or a negative value on failure.
1767 *
1768 * \internal
1769 * This function is a wrapper around the DRM_IOCTL_AGP_ALLOC ioctl, passing the
1770 * arguments in a drm_agp_buffer structure.
1771 */
drmAgpAlloc(int fd,unsigned long size,unsigned long type,unsigned long * address,drm_handle_t * handle)1772 int drmAgpAlloc(int fd, unsigned long size, unsigned long type,
1773 unsigned long *address, drm_handle_t *handle)
1774 {
1775 drm_agp_buffer_t b;
1776
1777 memclear(b);
1778 *handle = DRM_AGP_NO_HANDLE;
1779 b.size = size;
1780 b.type = type;
1781 if (drmIoctl(fd, DRM_IOCTL_AGP_ALLOC, &b))
1782 return -errno;
1783 if (address != 0UL)
1784 *address = b.physical;
1785 *handle = b.handle;
1786 return 0;
1787 }
1788
1789
1790 /**
1791 * Free a chunk of AGP memory.
1792 *
1793 * \param fd file descriptor.
1794 * \param handle handle to the allocated memory, as given by drmAgpAllocate().
1795 *
1796 * \return zero on success, or a negative value on failure.
1797 *
1798 * \internal
1799 * This function is a wrapper around the DRM_IOCTL_AGP_FREE ioctl, passing the
1800 * argument in a drm_agp_buffer structure.
1801 */
drmAgpFree(int fd,drm_handle_t handle)1802 int drmAgpFree(int fd, drm_handle_t handle)
1803 {
1804 drm_agp_buffer_t b;
1805
1806 memclear(b);
1807 b.handle = handle;
1808 if (drmIoctl(fd, DRM_IOCTL_AGP_FREE, &b))
1809 return -errno;
1810 return 0;
1811 }
1812
1813
1814 /**
1815 * Bind a chunk of AGP memory.
1816 *
1817 * \param fd file descriptor.
1818 * \param handle handle to the allocated memory, as given by drmAgpAllocate().
1819 * \param offset offset in bytes. It will round to page boundary.
1820 *
1821 * \return zero on success, or a negative value on failure.
1822 *
1823 * \internal
1824 * This function is a wrapper around the DRM_IOCTL_AGP_BIND ioctl, passing the
1825 * argument in a drm_agp_binding structure.
1826 */
drmAgpBind(int fd,drm_handle_t handle,unsigned long offset)1827 int drmAgpBind(int fd, drm_handle_t handle, unsigned long offset)
1828 {
1829 drm_agp_binding_t b;
1830
1831 memclear(b);
1832 b.handle = handle;
1833 b.offset = offset;
1834 if (drmIoctl(fd, DRM_IOCTL_AGP_BIND, &b))
1835 return -errno;
1836 return 0;
1837 }
1838
1839
1840 /**
1841 * Unbind a chunk of AGP memory.
1842 *
1843 * \param fd file descriptor.
1844 * \param handle handle to the allocated memory, as given by drmAgpAllocate().
1845 *
1846 * \return zero on success, or a negative value on failure.
1847 *
1848 * \internal
1849 * This function is a wrapper around the DRM_IOCTL_AGP_UNBIND ioctl, passing
1850 * the argument in a drm_agp_binding structure.
1851 */
drmAgpUnbind(int fd,drm_handle_t handle)1852 int drmAgpUnbind(int fd, drm_handle_t handle)
1853 {
1854 drm_agp_binding_t b;
1855
1856 memclear(b);
1857 b.handle = handle;
1858 if (drmIoctl(fd, DRM_IOCTL_AGP_UNBIND, &b))
1859 return -errno;
1860 return 0;
1861 }
1862
1863
1864 /**
1865 * Get AGP driver major version number.
1866 *
1867 * \param fd file descriptor.
1868 *
1869 * \return major version number on success, or a negative value on failure..
1870 *
1871 * \internal
1872 * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
1873 * necessary information in a drm_agp_info structure.
1874 */
drmAgpVersionMajor(int fd)1875 int drmAgpVersionMajor(int fd)
1876 {
1877 drm_agp_info_t i;
1878
1879 memclear(i);
1880
1881 if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
1882 return -errno;
1883 return i.agp_version_major;
1884 }
1885
1886
1887 /**
1888 * Get AGP driver minor version number.
1889 *
1890 * \param fd file descriptor.
1891 *
1892 * \return minor version number on success, or a negative value on failure.
1893 *
1894 * \internal
1895 * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
1896 * necessary information in a drm_agp_info structure.
1897 */
drmAgpVersionMinor(int fd)1898 int drmAgpVersionMinor(int fd)
1899 {
1900 drm_agp_info_t i;
1901
1902 memclear(i);
1903
1904 if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
1905 return -errno;
1906 return i.agp_version_minor;
1907 }
1908
1909
1910 /**
1911 * Get AGP mode.
1912 *
1913 * \param fd file descriptor.
1914 *
1915 * \return mode on success, or zero on failure.
1916 *
1917 * \internal
1918 * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
1919 * necessary information in a drm_agp_info structure.
1920 */
drmAgpGetMode(int fd)1921 unsigned long drmAgpGetMode(int fd)
1922 {
1923 drm_agp_info_t i;
1924
1925 memclear(i);
1926
1927 if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
1928 return 0;
1929 return i.mode;
1930 }
1931
1932
1933 /**
1934 * Get AGP aperture base.
1935 *
1936 * \param fd file descriptor.
1937 *
1938 * \return aperture base on success, zero on failure.
1939 *
1940 * \internal
1941 * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
1942 * necessary information in a drm_agp_info structure.
1943 */
drmAgpBase(int fd)1944 unsigned long drmAgpBase(int fd)
1945 {
1946 drm_agp_info_t i;
1947
1948 memclear(i);
1949
1950 if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
1951 return 0;
1952 return i.aperture_base;
1953 }
1954
1955
1956 /**
1957 * Get AGP aperture size.
1958 *
1959 * \param fd file descriptor.
1960 *
1961 * \return aperture size on success, zero on failure.
1962 *
1963 * \internal
1964 * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
1965 * necessary information in a drm_agp_info structure.
1966 */
drmAgpSize(int fd)1967 unsigned long drmAgpSize(int fd)
1968 {
1969 drm_agp_info_t i;
1970
1971 memclear(i);
1972
1973 if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
1974 return 0;
1975 return i.aperture_size;
1976 }
1977
1978
1979 /**
1980 * Get used AGP memory.
1981 *
1982 * \param fd file descriptor.
1983 *
1984 * \return memory used on success, or zero on failure.
1985 *
1986 * \internal
1987 * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
1988 * necessary information in a drm_agp_info structure.
1989 */
drmAgpMemoryUsed(int fd)1990 unsigned long drmAgpMemoryUsed(int fd)
1991 {
1992 drm_agp_info_t i;
1993
1994 memclear(i);
1995
1996 if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
1997 return 0;
1998 return i.memory_used;
1999 }
2000
2001
2002 /**
2003 * Get available AGP memory.
2004 *
2005 * \param fd file descriptor.
2006 *
2007 * \return memory available on success, or zero on failure.
2008 *
2009 * \internal
2010 * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
2011 * necessary information in a drm_agp_info structure.
2012 */
drmAgpMemoryAvail(int fd)2013 unsigned long drmAgpMemoryAvail(int fd)
2014 {
2015 drm_agp_info_t i;
2016
2017 memclear(i);
2018
2019 if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
2020 return 0;
2021 return i.memory_allowed;
2022 }
2023
2024
2025 /**
2026 * Get hardware vendor ID.
2027 *
2028 * \param fd file descriptor.
2029 *
2030 * \return vendor ID on success, or zero on failure.
2031 *
2032 * \internal
2033 * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
2034 * necessary information in a drm_agp_info structure.
2035 */
drmAgpVendorId(int fd)2036 unsigned int drmAgpVendorId(int fd)
2037 {
2038 drm_agp_info_t i;
2039
2040 memclear(i);
2041
2042 if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
2043 return 0;
2044 return i.id_vendor;
2045 }
2046
2047
2048 /**
2049 * Get hardware device ID.
2050 *
2051 * \param fd file descriptor.
2052 *
2053 * \return zero on success, or zero on failure.
2054 *
2055 * \internal
2056 * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
2057 * necessary information in a drm_agp_info structure.
2058 */
drmAgpDeviceId(int fd)2059 unsigned int drmAgpDeviceId(int fd)
2060 {
2061 drm_agp_info_t i;
2062
2063 memclear(i);
2064
2065 if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
2066 return 0;
2067 return i.id_device;
2068 }
2069
drmScatterGatherAlloc(int fd,unsigned long size,drm_handle_t * handle)2070 int drmScatterGatherAlloc(int fd, unsigned long size, drm_handle_t *handle)
2071 {
2072 drm_scatter_gather_t sg;
2073
2074 memclear(sg);
2075
2076 *handle = 0;
2077 sg.size = size;
2078 if (drmIoctl(fd, DRM_IOCTL_SG_ALLOC, &sg))
2079 return -errno;
2080 *handle = sg.handle;
2081 return 0;
2082 }
2083
drmScatterGatherFree(int fd,drm_handle_t handle)2084 int drmScatterGatherFree(int fd, drm_handle_t handle)
2085 {
2086 drm_scatter_gather_t sg;
2087
2088 memclear(sg);
2089 sg.handle = handle;
2090 if (drmIoctl(fd, DRM_IOCTL_SG_FREE, &sg))
2091 return -errno;
2092 return 0;
2093 }
2094
2095 /**
2096 * Wait for VBLANK.
2097 *
2098 * \param fd file descriptor.
2099 * \param vbl pointer to a drmVBlank structure.
2100 *
2101 * \return zero on success, or a negative value on failure.
2102 *
2103 * \internal
2104 * This function is a wrapper around the DRM_IOCTL_WAIT_VBLANK ioctl.
2105 */
drmWaitVBlank(int fd,drmVBlankPtr vbl)2106 int drmWaitVBlank(int fd, drmVBlankPtr vbl)
2107 {
2108 struct timespec timeout, cur;
2109 int ret;
2110
2111 ret = clock_gettime(CLOCK_MONOTONIC, &timeout);
2112 if (ret < 0) {
2113 fprintf(stderr, "clock_gettime failed: %s\n", strerror(errno));
2114 goto out;
2115 }
2116 timeout.tv_sec++;
2117
2118 do {
2119 ret = ioctl(fd, DRM_IOCTL_WAIT_VBLANK, vbl);
2120 vbl->request.type &= ~DRM_VBLANK_RELATIVE;
2121 if (ret && errno == EINTR) {
2122 clock_gettime(CLOCK_MONOTONIC, &cur);
2123 /* Timeout after 1s */
2124 if (cur.tv_sec > timeout.tv_sec + 1 ||
2125 (cur.tv_sec == timeout.tv_sec && cur.tv_nsec >=
2126 timeout.tv_nsec)) {
2127 errno = EBUSY;
2128 ret = -1;
2129 break;
2130 }
2131 }
2132 } while (ret && errno == EINTR);
2133
2134 out:
2135 return ret;
2136 }
2137
drmError(int err,const char * label)2138 int drmError(int err, const char *label)
2139 {
2140 switch (err) {
2141 case DRM_ERR_NO_DEVICE:
2142 fprintf(stderr, "%s: no device\n", label);
2143 break;
2144 case DRM_ERR_NO_ACCESS:
2145 fprintf(stderr, "%s: no access\n", label);
2146 break;
2147 case DRM_ERR_NOT_ROOT:
2148 fprintf(stderr, "%s: not root\n", label);
2149 break;
2150 case DRM_ERR_INVALID:
2151 fprintf(stderr, "%s: invalid args\n", label);
2152 break;
2153 default:
2154 if (err < 0)
2155 err = -err;
2156 fprintf( stderr, "%s: error %d (%s)\n", label, err, strerror(err) );
2157 break;
2158 }
2159
2160 return 1;
2161 }
2162
2163 /**
2164 * Install IRQ handler.
2165 *
2166 * \param fd file descriptor.
2167 * \param irq IRQ number.
2168 *
2169 * \return zero on success, or a negative value on failure.
2170 *
2171 * \internal
2172 * This function is a wrapper around the DRM_IOCTL_CONTROL ioctl, passing the
2173 * argument in a drm_control structure.
2174 */
drmCtlInstHandler(int fd,int irq)2175 int drmCtlInstHandler(int fd, int irq)
2176 {
2177 drm_control_t ctl;
2178
2179 memclear(ctl);
2180 ctl.func = DRM_INST_HANDLER;
2181 ctl.irq = irq;
2182 if (drmIoctl(fd, DRM_IOCTL_CONTROL, &ctl))
2183 return -errno;
2184 return 0;
2185 }
2186
2187
2188 /**
2189 * Uninstall IRQ handler.
2190 *
2191 * \param fd file descriptor.
2192 *
2193 * \return zero on success, or a negative value on failure.
2194 *
2195 * \internal
2196 * This function is a wrapper around the DRM_IOCTL_CONTROL ioctl, passing the
2197 * argument in a drm_control structure.
2198 */
drmCtlUninstHandler(int fd)2199 int drmCtlUninstHandler(int fd)
2200 {
2201 drm_control_t ctl;
2202
2203 memclear(ctl);
2204 ctl.func = DRM_UNINST_HANDLER;
2205 ctl.irq = 0;
2206 if (drmIoctl(fd, DRM_IOCTL_CONTROL, &ctl))
2207 return -errno;
2208 return 0;
2209 }
2210
drmFinish(int fd,int context,drmLockFlags flags)2211 int drmFinish(int fd, int context, drmLockFlags flags)
2212 {
2213 drm_lock_t lock;
2214
2215 memclear(lock);
2216 lock.context = context;
2217 if (flags & DRM_LOCK_READY) lock.flags |= _DRM_LOCK_READY;
2218 if (flags & DRM_LOCK_QUIESCENT) lock.flags |= _DRM_LOCK_QUIESCENT;
2219 if (flags & DRM_LOCK_FLUSH) lock.flags |= _DRM_LOCK_FLUSH;
2220 if (flags & DRM_LOCK_FLUSH_ALL) lock.flags |= _DRM_LOCK_FLUSH_ALL;
2221 if (flags & DRM_HALT_ALL_QUEUES) lock.flags |= _DRM_HALT_ALL_QUEUES;
2222 if (flags & DRM_HALT_CUR_QUEUES) lock.flags |= _DRM_HALT_CUR_QUEUES;
2223 if (drmIoctl(fd, DRM_IOCTL_FINISH, &lock))
2224 return -errno;
2225 return 0;
2226 }
2227
2228 /**
2229 * Get IRQ from bus ID.
2230 *
2231 * \param fd file descriptor.
2232 * \param busnum bus number.
2233 * \param devnum device number.
2234 * \param funcnum function number.
2235 *
2236 * \return IRQ number on success, or a negative value on failure.
2237 *
2238 * \internal
2239 * This function is a wrapper around the DRM_IOCTL_IRQ_BUSID ioctl, passing the
2240 * arguments in a drm_irq_busid structure.
2241 */
drmGetInterruptFromBusID(int fd,int busnum,int devnum,int funcnum)2242 int drmGetInterruptFromBusID(int fd, int busnum, int devnum, int funcnum)
2243 {
2244 drm_irq_busid_t p;
2245
2246 memclear(p);
2247 p.busnum = busnum;
2248 p.devnum = devnum;
2249 p.funcnum = funcnum;
2250 if (drmIoctl(fd, DRM_IOCTL_IRQ_BUSID, &p))
2251 return -errno;
2252 return p.irq;
2253 }
2254
drmAddContextTag(int fd,drm_context_t context,void * tag)2255 int drmAddContextTag(int fd, drm_context_t context, void *tag)
2256 {
2257 drmHashEntry *entry = drmGetEntry(fd);
2258
2259 if (drmHashInsert(entry->tagTable, context, tag)) {
2260 drmHashDelete(entry->tagTable, context);
2261 drmHashInsert(entry->tagTable, context, tag);
2262 }
2263 return 0;
2264 }
2265
drmDelContextTag(int fd,drm_context_t context)2266 int drmDelContextTag(int fd, drm_context_t context)
2267 {
2268 drmHashEntry *entry = drmGetEntry(fd);
2269
2270 return drmHashDelete(entry->tagTable, context);
2271 }
2272
drmGetContextTag(int fd,drm_context_t context)2273 void *drmGetContextTag(int fd, drm_context_t context)
2274 {
2275 drmHashEntry *entry = drmGetEntry(fd);
2276 void *value;
2277
2278 if (drmHashLookup(entry->tagTable, context, &value))
2279 return NULL;
2280
2281 return value;
2282 }
2283
drmAddContextPrivateMapping(int fd,drm_context_t ctx_id,drm_handle_t handle)2284 int drmAddContextPrivateMapping(int fd, drm_context_t ctx_id,
2285 drm_handle_t handle)
2286 {
2287 drm_ctx_priv_map_t map;
2288
2289 memclear(map);
2290 map.ctx_id = ctx_id;
2291 map.handle = (void *)(uintptr_t)handle;
2292
2293 if (drmIoctl(fd, DRM_IOCTL_SET_SAREA_CTX, &map))
2294 return -errno;
2295 return 0;
2296 }
2297
drmGetContextPrivateMapping(int fd,drm_context_t ctx_id,drm_handle_t * handle)2298 int drmGetContextPrivateMapping(int fd, drm_context_t ctx_id,
2299 drm_handle_t *handle)
2300 {
2301 drm_ctx_priv_map_t map;
2302
2303 memclear(map);
2304 map.ctx_id = ctx_id;
2305
2306 if (drmIoctl(fd, DRM_IOCTL_GET_SAREA_CTX, &map))
2307 return -errno;
2308 if (handle)
2309 *handle = (drm_handle_t)(uintptr_t)map.handle;
2310
2311 return 0;
2312 }
2313
drmGetMap(int fd,int idx,drm_handle_t * offset,drmSize * size,drmMapType * type,drmMapFlags * flags,drm_handle_t * handle,int * mtrr)2314 int drmGetMap(int fd, int idx, drm_handle_t *offset, drmSize *size,
2315 drmMapType *type, drmMapFlags *flags, drm_handle_t *handle,
2316 int *mtrr)
2317 {
2318 drm_map_t map;
2319
2320 memclear(map);
2321 map.offset = idx;
2322 if (drmIoctl(fd, DRM_IOCTL_GET_MAP, &map))
2323 return -errno;
2324 *offset = map.offset;
2325 *size = map.size;
2326 *type = map.type;
2327 *flags = map.flags;
2328 *handle = (unsigned long)map.handle;
2329 *mtrr = map.mtrr;
2330 return 0;
2331 }
2332
drmGetClient(int fd,int idx,int * auth,int * pid,int * uid,unsigned long * magic,unsigned long * iocs)2333 int drmGetClient(int fd, int idx, int *auth, int *pid, int *uid,
2334 unsigned long *magic, unsigned long *iocs)
2335 {
2336 drm_client_t client;
2337
2338 memclear(client);
2339 client.idx = idx;
2340 if (drmIoctl(fd, DRM_IOCTL_GET_CLIENT, &client))
2341 return -errno;
2342 *auth = client.auth;
2343 *pid = client.pid;
2344 *uid = client.uid;
2345 *magic = client.magic;
2346 *iocs = client.iocs;
2347 return 0;
2348 }
2349
drmGetStats(int fd,drmStatsT * stats)2350 int drmGetStats(int fd, drmStatsT *stats)
2351 {
2352 drm_stats_t s;
2353 unsigned i;
2354
2355 memclear(s);
2356 if (drmIoctl(fd, DRM_IOCTL_GET_STATS, &s))
2357 return -errno;
2358
2359 stats->count = 0;
2360 memset(stats, 0, sizeof(*stats));
2361 if (s.count > sizeof(stats->data)/sizeof(stats->data[0]))
2362 return -1;
2363
2364 #define SET_VALUE \
2365 stats->data[i].long_format = "%-20.20s"; \
2366 stats->data[i].rate_format = "%8.8s"; \
2367 stats->data[i].isvalue = 1; \
2368 stats->data[i].verbose = 0
2369
2370 #define SET_COUNT \
2371 stats->data[i].long_format = "%-20.20s"; \
2372 stats->data[i].rate_format = "%5.5s"; \
2373 stats->data[i].isvalue = 0; \
2374 stats->data[i].mult_names = "kgm"; \
2375 stats->data[i].mult = 1000; \
2376 stats->data[i].verbose = 0
2377
2378 #define SET_BYTE \
2379 stats->data[i].long_format = "%-20.20s"; \
2380 stats->data[i].rate_format = "%5.5s"; \
2381 stats->data[i].isvalue = 0; \
2382 stats->data[i].mult_names = "KGM"; \
2383 stats->data[i].mult = 1024; \
2384 stats->data[i].verbose = 0
2385
2386
2387 stats->count = s.count;
2388 for (i = 0; i < s.count; i++) {
2389 stats->data[i].value = s.data[i].value;
2390 switch (s.data[i].type) {
2391 case _DRM_STAT_LOCK:
2392 stats->data[i].long_name = "Lock";
2393 stats->data[i].rate_name = "Lock";
2394 SET_VALUE;
2395 break;
2396 case _DRM_STAT_OPENS:
2397 stats->data[i].long_name = "Opens";
2398 stats->data[i].rate_name = "O";
2399 SET_COUNT;
2400 stats->data[i].verbose = 1;
2401 break;
2402 case _DRM_STAT_CLOSES:
2403 stats->data[i].long_name = "Closes";
2404 stats->data[i].rate_name = "Lock";
2405 SET_COUNT;
2406 stats->data[i].verbose = 1;
2407 break;
2408 case _DRM_STAT_IOCTLS:
2409 stats->data[i].long_name = "Ioctls";
2410 stats->data[i].rate_name = "Ioc/s";
2411 SET_COUNT;
2412 break;
2413 case _DRM_STAT_LOCKS:
2414 stats->data[i].long_name = "Locks";
2415 stats->data[i].rate_name = "Lck/s";
2416 SET_COUNT;
2417 break;
2418 case _DRM_STAT_UNLOCKS:
2419 stats->data[i].long_name = "Unlocks";
2420 stats->data[i].rate_name = "Unl/s";
2421 SET_COUNT;
2422 break;
2423 case _DRM_STAT_IRQ:
2424 stats->data[i].long_name = "IRQs";
2425 stats->data[i].rate_name = "IRQ/s";
2426 SET_COUNT;
2427 break;
2428 case _DRM_STAT_PRIMARY:
2429 stats->data[i].long_name = "Primary Bytes";
2430 stats->data[i].rate_name = "PB/s";
2431 SET_BYTE;
2432 break;
2433 case _DRM_STAT_SECONDARY:
2434 stats->data[i].long_name = "Secondary Bytes";
2435 stats->data[i].rate_name = "SB/s";
2436 SET_BYTE;
2437 break;
2438 case _DRM_STAT_DMA:
2439 stats->data[i].long_name = "DMA";
2440 stats->data[i].rate_name = "DMA/s";
2441 SET_COUNT;
2442 break;
2443 case _DRM_STAT_SPECIAL:
2444 stats->data[i].long_name = "Special DMA";
2445 stats->data[i].rate_name = "dma/s";
2446 SET_COUNT;
2447 break;
2448 case _DRM_STAT_MISSED:
2449 stats->data[i].long_name = "Miss";
2450 stats->data[i].rate_name = "Ms/s";
2451 SET_COUNT;
2452 break;
2453 case _DRM_STAT_VALUE:
2454 stats->data[i].long_name = "Value";
2455 stats->data[i].rate_name = "Value";
2456 SET_VALUE;
2457 break;
2458 case _DRM_STAT_BYTE:
2459 stats->data[i].long_name = "Bytes";
2460 stats->data[i].rate_name = "B/s";
2461 SET_BYTE;
2462 break;
2463 case _DRM_STAT_COUNT:
2464 default:
2465 stats->data[i].long_name = "Count";
2466 stats->data[i].rate_name = "Cnt/s";
2467 SET_COUNT;
2468 break;
2469 }
2470 }
2471 return 0;
2472 }
2473
2474 /**
2475 * Issue a set-version ioctl.
2476 *
2477 * \param fd file descriptor.
2478 * \param drmCommandIndex command index
2479 * \param data source pointer of the data to be read and written.
2480 * \param size size of the data to be read and written.
2481 *
2482 * \return zero on success, or a negative value on failure.
2483 *
2484 * \internal
2485 * It issues a read-write ioctl given by
2486 * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
2487 */
drmSetInterfaceVersion(int fd,drmSetVersion * version)2488 int drmSetInterfaceVersion(int fd, drmSetVersion *version)
2489 {
2490 int retcode = 0;
2491 drm_set_version_t sv;
2492
2493 memclear(sv);
2494 sv.drm_di_major = version->drm_di_major;
2495 sv.drm_di_minor = version->drm_di_minor;
2496 sv.drm_dd_major = version->drm_dd_major;
2497 sv.drm_dd_minor = version->drm_dd_minor;
2498
2499 if (drmIoctl(fd, DRM_IOCTL_SET_VERSION, &sv)) {
2500 retcode = -errno;
2501 }
2502
2503 version->drm_di_major = sv.drm_di_major;
2504 version->drm_di_minor = sv.drm_di_minor;
2505 version->drm_dd_major = sv.drm_dd_major;
2506 version->drm_dd_minor = sv.drm_dd_minor;
2507
2508 return retcode;
2509 }
2510
2511 /**
2512 * Send a device-specific command.
2513 *
2514 * \param fd file descriptor.
2515 * \param drmCommandIndex command index
2516 *
2517 * \return zero on success, or a negative value on failure.
2518 *
2519 * \internal
2520 * It issues a ioctl given by
2521 * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
2522 */
drmCommandNone(int fd,unsigned long drmCommandIndex)2523 int drmCommandNone(int fd, unsigned long drmCommandIndex)
2524 {
2525 unsigned long request;
2526
2527 request = DRM_IO( DRM_COMMAND_BASE + drmCommandIndex);
2528
2529 if (drmIoctl(fd, request, NULL)) {
2530 return -errno;
2531 }
2532 return 0;
2533 }
2534
2535
2536 /**
2537 * Send a device-specific read command.
2538 *
2539 * \param fd file descriptor.
2540 * \param drmCommandIndex command index
2541 * \param data destination pointer of the data to be read.
2542 * \param size size of the data to be read.
2543 *
2544 * \return zero on success, or a negative value on failure.
2545 *
2546 * \internal
2547 * It issues a read ioctl given by
2548 * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
2549 */
drmCommandRead(int fd,unsigned long drmCommandIndex,void * data,unsigned long size)2550 int drmCommandRead(int fd, unsigned long drmCommandIndex, void *data,
2551 unsigned long size)
2552 {
2553 unsigned long request;
2554
2555 request = DRM_IOC( DRM_IOC_READ, DRM_IOCTL_BASE,
2556 DRM_COMMAND_BASE + drmCommandIndex, size);
2557
2558 if (drmIoctl(fd, request, data)) {
2559 return -errno;
2560 }
2561 return 0;
2562 }
2563
2564
2565 /**
2566 * Send a device-specific write command.
2567 *
2568 * \param fd file descriptor.
2569 * \param drmCommandIndex command index
2570 * \param data source pointer of the data to be written.
2571 * \param size size of the data to be written.
2572 *
2573 * \return zero on success, or a negative value on failure.
2574 *
2575 * \internal
2576 * It issues a write ioctl given by
2577 * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
2578 */
drmCommandWrite(int fd,unsigned long drmCommandIndex,void * data,unsigned long size)2579 int drmCommandWrite(int fd, unsigned long drmCommandIndex, void *data,
2580 unsigned long size)
2581 {
2582 unsigned long request;
2583
2584 request = DRM_IOC( DRM_IOC_WRITE, DRM_IOCTL_BASE,
2585 DRM_COMMAND_BASE + drmCommandIndex, size);
2586
2587 if (drmIoctl(fd, request, data)) {
2588 return -errno;
2589 }
2590 return 0;
2591 }
2592
2593
2594 /**
2595 * Send a device-specific read-write command.
2596 *
2597 * \param fd file descriptor.
2598 * \param drmCommandIndex command index
2599 * \param data source pointer of the data to be read and written.
2600 * \param size size of the data to be read and written.
2601 *
2602 * \return zero on success, or a negative value on failure.
2603 *
2604 * \internal
2605 * It issues a read-write ioctl given by
2606 * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
2607 */
drmCommandWriteRead(int fd,unsigned long drmCommandIndex,void * data,unsigned long size)2608 int drmCommandWriteRead(int fd, unsigned long drmCommandIndex, void *data,
2609 unsigned long size)
2610 {
2611 unsigned long request;
2612
2613 request = DRM_IOC( DRM_IOC_READ|DRM_IOC_WRITE, DRM_IOCTL_BASE,
2614 DRM_COMMAND_BASE + drmCommandIndex, size);
2615
2616 if (drmIoctl(fd, request, data))
2617 return -errno;
2618 return 0;
2619 }
2620
2621 #define DRM_MAX_FDS 16
2622 static struct {
2623 char *BusID;
2624 int fd;
2625 int refcount;
2626 int type;
2627 } connection[DRM_MAX_FDS];
2628
2629 static int nr_fds = 0;
2630
drmOpenOnce(void * unused,const char * BusID,int * newlyopened)2631 int drmOpenOnce(void *unused,
2632 const char *BusID,
2633 int *newlyopened)
2634 {
2635 return drmOpenOnceWithType(BusID, newlyopened, DRM_NODE_PRIMARY);
2636 }
2637
drmOpenOnceWithType(const char * BusID,int * newlyopened,int type)2638 int drmOpenOnceWithType(const char *BusID, int *newlyopened, int type)
2639 {
2640 int i;
2641 int fd;
2642
2643 for (i = 0; i < nr_fds; i++)
2644 if ((strcmp(BusID, connection[i].BusID) == 0) &&
2645 (connection[i].type == type)) {
2646 connection[i].refcount++;
2647 *newlyopened = 0;
2648 return connection[i].fd;
2649 }
2650
2651 fd = drmOpenWithType(NULL, BusID, type);
2652 if (fd < 0 || nr_fds == DRM_MAX_FDS)
2653 return fd;
2654
2655 connection[nr_fds].BusID = strdup(BusID);
2656 connection[nr_fds].fd = fd;
2657 connection[nr_fds].refcount = 1;
2658 connection[nr_fds].type = type;
2659 *newlyopened = 1;
2660
2661 if (0)
2662 fprintf(stderr, "saved connection %d for %s %d\n",
2663 nr_fds, connection[nr_fds].BusID,
2664 strcmp(BusID, connection[nr_fds].BusID));
2665
2666 nr_fds++;
2667
2668 return fd;
2669 }
2670
drmCloseOnce(int fd)2671 void drmCloseOnce(int fd)
2672 {
2673 int i;
2674
2675 for (i = 0; i < nr_fds; i++) {
2676 if (fd == connection[i].fd) {
2677 if (--connection[i].refcount == 0) {
2678 drmClose(connection[i].fd);
2679 free(connection[i].BusID);
2680
2681 if (i < --nr_fds)
2682 connection[i] = connection[nr_fds];
2683
2684 return;
2685 }
2686 }
2687 }
2688 }
2689
drmSetMaster(int fd)2690 int drmSetMaster(int fd)
2691 {
2692 return drmIoctl(fd, DRM_IOCTL_SET_MASTER, NULL);
2693 }
2694
drmDropMaster(int fd)2695 int drmDropMaster(int fd)
2696 {
2697 return drmIoctl(fd, DRM_IOCTL_DROP_MASTER, NULL);
2698 }
2699
drmGetDeviceNameFromFd(int fd)2700 char *drmGetDeviceNameFromFd(int fd)
2701 {
2702 char name[128];
2703 struct stat sbuf;
2704 dev_t d;
2705 int i;
2706
2707 /* The whole drmOpen thing is a fiasco and we need to find a way
2708 * back to just using open(2). For now, however, lets just make
2709 * things worse with even more ad hoc directory walking code to
2710 * discover the device file name. */
2711
2712 fstat(fd, &sbuf);
2713 d = sbuf.st_rdev;
2714
2715 for (i = 0; i < DRM_MAX_MINOR; i++) {
2716 snprintf(name, sizeof name, DRM_DEV_NAME, DRM_DIR_NAME, i);
2717 if (stat(name, &sbuf) == 0 && sbuf.st_rdev == d)
2718 break;
2719 }
2720 if (i == DRM_MAX_MINOR)
2721 return NULL;
2722
2723 return strdup(name);
2724 }
2725
drmGetNodeTypeFromFd(int fd)2726 int drmGetNodeTypeFromFd(int fd)
2727 {
2728 struct stat sbuf;
2729 int maj, min, type;
2730
2731 if (fstat(fd, &sbuf))
2732 return -1;
2733
2734 maj = major(sbuf.st_rdev);
2735 min = minor(sbuf.st_rdev);
2736
2737 if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode)) {
2738 errno = EINVAL;
2739 return -1;
2740 }
2741
2742 type = drmGetMinorType(min);
2743 if (type == -1)
2744 errno = ENODEV;
2745 return type;
2746 }
2747
drmPrimeHandleToFD(int fd,uint32_t handle,uint32_t flags,int * prime_fd)2748 int drmPrimeHandleToFD(int fd, uint32_t handle, uint32_t flags, int *prime_fd)
2749 {
2750 struct drm_prime_handle args;
2751 int ret;
2752
2753 memclear(args);
2754 args.fd = -1;
2755 args.handle = handle;
2756 args.flags = flags;
2757 ret = drmIoctl(fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &args);
2758 if (ret)
2759 return ret;
2760
2761 *prime_fd = args.fd;
2762 return 0;
2763 }
2764
drmPrimeFDToHandle(int fd,int prime_fd,uint32_t * handle)2765 int drmPrimeFDToHandle(int fd, int prime_fd, uint32_t *handle)
2766 {
2767 struct drm_prime_handle args;
2768 int ret;
2769
2770 memclear(args);
2771 args.fd = prime_fd;
2772 ret = drmIoctl(fd, DRM_IOCTL_PRIME_FD_TO_HANDLE, &args);
2773 if (ret)
2774 return ret;
2775
2776 *handle = args.handle;
2777 return 0;
2778 }
2779
drmGetMinorNameForFD(int fd,int type)2780 static char *drmGetMinorNameForFD(int fd, int type)
2781 {
2782 #ifdef __linux__
2783 DIR *sysdir;
2784 struct dirent *pent, *ent;
2785 struct stat sbuf;
2786 const char *name = drmGetMinorName(type);
2787 int len;
2788 char dev_name[64], buf[64];
2789 long name_max;
2790 int maj, min;
2791
2792 if (!name)
2793 return NULL;
2794
2795 len = strlen(name);
2796
2797 if (fstat(fd, &sbuf))
2798 return NULL;
2799
2800 maj = major(sbuf.st_rdev);
2801 min = minor(sbuf.st_rdev);
2802
2803 if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode))
2804 return NULL;
2805
2806 snprintf(buf, sizeof(buf), "/sys/dev/char/%d:%d/device/drm", maj, min);
2807
2808 sysdir = opendir(buf);
2809 if (!sysdir)
2810 return NULL;
2811
2812 name_max = fpathconf(dirfd(sysdir), _PC_NAME_MAX);
2813 if (name_max == -1)
2814 goto out_close_dir;
2815
2816 pent = malloc(offsetof(struct dirent, d_name) + name_max + 1);
2817 if (pent == NULL)
2818 goto out_close_dir;
2819
2820 while (readdir_r(sysdir, pent, &ent) == 0 && ent != NULL) {
2821 if (strncmp(ent->d_name, name, len) == 0) {
2822 snprintf(dev_name, sizeof(dev_name), DRM_DIR_NAME "/%s",
2823 ent->d_name);
2824
2825 free(pent);
2826 closedir(sysdir);
2827
2828 return strdup(dev_name);
2829 }
2830 }
2831
2832 free(pent);
2833
2834 out_close_dir:
2835 closedir(sysdir);
2836 #else
2837 struct stat sbuf;
2838 char buf[PATH_MAX + 1];
2839 const char *dev_name;
2840 unsigned int maj, min;
2841 int n, base;
2842
2843 if (fstat(fd, &sbuf))
2844 return NULL;
2845
2846 maj = major(sbuf.st_rdev);
2847 min = minor(sbuf.st_rdev);
2848
2849 if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode))
2850 return NULL;
2851
2852 switch (type) {
2853 case DRM_NODE_PRIMARY:
2854 dev_name = DRM_DEV_NAME;
2855 break;
2856 case DRM_NODE_CONTROL:
2857 dev_name = DRM_CONTROL_DEV_NAME;
2858 break;
2859 case DRM_NODE_RENDER:
2860 dev_name = DRM_RENDER_DEV_NAME;
2861 break;
2862 default:
2863 return NULL;
2864 };
2865
2866 base = drmGetMinorBase(type);
2867 if (base < 0)
2868 return NULL;
2869
2870 n = snprintf(buf, sizeof(buf), dev_name, DRM_DIR_NAME, min - base);
2871 if (n == -1 || n >= sizeof(buf))
2872 return NULL;
2873
2874 return strdup(buf);
2875 #endif
2876 return NULL;
2877 }
2878
drmGetPrimaryDeviceNameFromFd(int fd)2879 char *drmGetPrimaryDeviceNameFromFd(int fd)
2880 {
2881 return drmGetMinorNameForFD(fd, DRM_NODE_PRIMARY);
2882 }
2883
drmGetRenderDeviceNameFromFd(int fd)2884 char *drmGetRenderDeviceNameFromFd(int fd)
2885 {
2886 return drmGetMinorNameForFD(fd, DRM_NODE_RENDER);
2887 }
2888
2889 #ifdef __linux__
2890 static char * DRM_PRINTFLIKE(2, 3)
sysfs_uevent_get(const char * path,const char * fmt,...)2891 sysfs_uevent_get(const char *path, const char *fmt, ...)
2892 {
2893 char filename[PATH_MAX + 1], *key, *line = NULL, *value = NULL;
2894 size_t size = 0, len;
2895 ssize_t num;
2896 va_list ap;
2897 FILE *fp;
2898
2899 va_start(ap, fmt);
2900 num = vasprintf(&key, fmt, ap);
2901 va_end(ap);
2902 len = num;
2903
2904 snprintf(filename, sizeof(filename), "%s/uevent", path);
2905
2906 fp = fopen(filename, "r");
2907 if (!fp) {
2908 free(key);
2909 return NULL;
2910 }
2911
2912 while ((num = getline(&line, &size, fp)) >= 0) {
2913 if ((strncmp(line, key, len) == 0) && (line[len] == '=')) {
2914 char *start = line + len + 1, *end = line + num - 1;
2915
2916 if (*end != '\n')
2917 end++;
2918
2919 value = strndup(start, end - start);
2920 break;
2921 }
2922 }
2923
2924 free(line);
2925 fclose(fp);
2926
2927 free(key);
2928
2929 return value;
2930 }
2931 #endif
2932
drmParseSubsystemType(int maj,int min)2933 static int drmParseSubsystemType(int maj, int min)
2934 {
2935 #ifdef __linux__
2936 char path[PATH_MAX + 1];
2937 char link[PATH_MAX + 1] = "";
2938 char *name;
2939
2940 snprintf(path, PATH_MAX, "/sys/dev/char/%d:%d/device/subsystem",
2941 maj, min);
2942
2943 if (readlink(path, link, PATH_MAX) < 0)
2944 return -errno;
2945
2946 name = strrchr(link, '/');
2947 if (!name)
2948 return -EINVAL;
2949
2950 if (strncmp(name, "/pci", 4) == 0)
2951 return DRM_BUS_PCI;
2952
2953 if (strncmp(name, "/usb", 4) == 0)
2954 return DRM_BUS_USB;
2955
2956 if (strncmp(name, "/platform", 9) == 0)
2957 return DRM_BUS_PLATFORM;
2958
2959 if (strncmp(name, "/host1x", 7) == 0)
2960 return DRM_BUS_HOST1X;
2961
2962 return -EINVAL;
2963 #elif defined(__OpenBSD__)
2964 return DRM_BUS_PCI;
2965 #else
2966 #warning "Missing implementation of drmParseSubsystemType"
2967 return -EINVAL;
2968 #endif
2969 }
2970
drmParsePciBusInfo(int maj,int min,drmPciBusInfoPtr info)2971 static int drmParsePciBusInfo(int maj, int min, drmPciBusInfoPtr info)
2972 {
2973 #ifdef __linux__
2974 unsigned int domain, bus, dev, func;
2975 char path[PATH_MAX + 1], *value;
2976 int num;
2977
2978 snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min);
2979
2980 value = sysfs_uevent_get(path, "PCI_SLOT_NAME");
2981 if (!value)
2982 return -ENOENT;
2983
2984 num = sscanf(value, "%04x:%02x:%02x.%1u", &domain, &bus, &dev, &func);
2985 free(value);
2986
2987 if (num != 4)
2988 return -EINVAL;
2989
2990 info->domain = domain;
2991 info->bus = bus;
2992 info->dev = dev;
2993 info->func = func;
2994
2995 return 0;
2996 #elif defined(__OpenBSD__)
2997 struct drm_pciinfo pinfo;
2998 int fd, type;
2999
3000 type = drmGetMinorType(min);
3001 if (type == -1)
3002 return -ENODEV;
3003
3004 fd = drmOpenMinor(min, 0, type);
3005 if (fd < 0)
3006 return -errno;
3007
3008 if (drmIoctl(fd, DRM_IOCTL_GET_PCIINFO, &pinfo)) {
3009 close(fd);
3010 return -errno;
3011 }
3012 close(fd);
3013
3014 info->domain = pinfo.domain;
3015 info->bus = pinfo.bus;
3016 info->dev = pinfo.dev;
3017 info->func = pinfo.func;
3018
3019 return 0;
3020 #else
3021 #warning "Missing implementation of drmParsePciBusInfo"
3022 return -EINVAL;
3023 #endif
3024 }
3025
drmCompareBusInfo(drmDevicePtr a,drmDevicePtr b)3026 static int drmCompareBusInfo(drmDevicePtr a, drmDevicePtr b)
3027 {
3028 if (a == NULL || b == NULL)
3029 return -1;
3030
3031 if (a->bustype != b->bustype)
3032 return -1;
3033
3034 switch (a->bustype) {
3035 case DRM_BUS_PCI:
3036 return memcmp(a->businfo.pci, b->businfo.pci, sizeof(drmPciBusInfo));
3037
3038 case DRM_BUS_USB:
3039 return memcmp(a->businfo.usb, b->businfo.usb, sizeof(drmUsbBusInfo));
3040
3041 case DRM_BUS_PLATFORM:
3042 return memcmp(a->businfo.platform, b->businfo.platform, sizeof(drmPlatformBusInfo));
3043
3044 case DRM_BUS_HOST1X:
3045 return memcmp(a->businfo.host1x, b->businfo.host1x, sizeof(drmHost1xBusInfo));
3046
3047 default:
3048 break;
3049 }
3050
3051 return -1;
3052 }
3053
drmGetNodeType(const char * name)3054 static int drmGetNodeType(const char *name)
3055 {
3056 if (strncmp(name, DRM_PRIMARY_MINOR_NAME,
3057 sizeof(DRM_PRIMARY_MINOR_NAME) - 1) == 0)
3058 return DRM_NODE_PRIMARY;
3059
3060 if (strncmp(name, DRM_CONTROL_MINOR_NAME,
3061 sizeof(DRM_CONTROL_MINOR_NAME ) - 1) == 0)
3062 return DRM_NODE_CONTROL;
3063
3064 if (strncmp(name, DRM_RENDER_MINOR_NAME,
3065 sizeof(DRM_RENDER_MINOR_NAME) - 1) == 0)
3066 return DRM_NODE_RENDER;
3067
3068 return -EINVAL;
3069 }
3070
drmGetMaxNodeName(void)3071 static int drmGetMaxNodeName(void)
3072 {
3073 return sizeof(DRM_DIR_NAME) +
3074 MAX3(sizeof(DRM_PRIMARY_MINOR_NAME),
3075 sizeof(DRM_CONTROL_MINOR_NAME),
3076 sizeof(DRM_RENDER_MINOR_NAME)) +
3077 3 /* length of the node number */;
3078 }
3079
3080 #ifdef __linux__
parse_separate_sysfs_files(int maj,int min,drmPciDeviceInfoPtr device,bool ignore_revision)3081 static int parse_separate_sysfs_files(int maj, int min,
3082 drmPciDeviceInfoPtr device,
3083 bool ignore_revision)
3084 {
3085 #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
3086 static const char *attrs[] = {
3087 "revision", /* Older kernels are missing the file, so check for it first */
3088 "vendor",
3089 "device",
3090 "subsystem_vendor",
3091 "subsystem_device",
3092 };
3093 char path[PATH_MAX + 1];
3094 unsigned int data[ARRAY_SIZE(attrs)];
3095 FILE *fp;
3096 int ret;
3097
3098 for (unsigned i = ignore_revision ? 1 : 0; i < ARRAY_SIZE(attrs); i++) {
3099 snprintf(path, PATH_MAX, "/sys/dev/char/%d:%d/device/%s", maj, min,
3100 attrs[i]);
3101 fp = fopen(path, "r");
3102 if (!fp)
3103 return -errno;
3104
3105 ret = fscanf(fp, "%x", &data[i]);
3106 fclose(fp);
3107 if (ret != 1)
3108 return -errno;
3109
3110 }
3111
3112 device->revision_id = ignore_revision ? 0xff : data[0] & 0xff;
3113 device->vendor_id = data[1] & 0xffff;
3114 device->device_id = data[2] & 0xffff;
3115 device->subvendor_id = data[3] & 0xffff;
3116 device->subdevice_id = data[4] & 0xffff;
3117
3118 return 0;
3119 }
3120
parse_config_sysfs_file(int maj,int min,drmPciDeviceInfoPtr device)3121 static int parse_config_sysfs_file(int maj, int min,
3122 drmPciDeviceInfoPtr device)
3123 {
3124 char path[PATH_MAX + 1];
3125 unsigned char config[64];
3126 int fd, ret;
3127
3128 snprintf(path, PATH_MAX, "/sys/dev/char/%d:%d/device/config", maj, min);
3129 fd = open(path, O_RDONLY);
3130 if (fd < 0)
3131 return -errno;
3132
3133 ret = read(fd, config, sizeof(config));
3134 close(fd);
3135 if (ret < 0)
3136 return -errno;
3137
3138 device->vendor_id = config[0] | (config[1] << 8);
3139 device->device_id = config[2] | (config[3] << 8);
3140 device->revision_id = config[8];
3141 device->subvendor_id = config[44] | (config[45] << 8);
3142 device->subdevice_id = config[46] | (config[47] << 8);
3143
3144 return 0;
3145 }
3146 #endif
3147
drmParsePciDeviceInfo(int maj,int min,drmPciDeviceInfoPtr device,uint32_t flags)3148 static int drmParsePciDeviceInfo(int maj, int min,
3149 drmPciDeviceInfoPtr device,
3150 uint32_t flags)
3151 {
3152 #ifdef __linux__
3153 if (!(flags & DRM_DEVICE_GET_PCI_REVISION))
3154 return parse_separate_sysfs_files(maj, min, device, true);
3155
3156 if (parse_separate_sysfs_files(maj, min, device, false))
3157 return parse_config_sysfs_file(maj, min, device);
3158
3159 return 0;
3160 #elif defined(__OpenBSD__)
3161 struct drm_pciinfo pinfo;
3162 int fd, type;
3163
3164 type = drmGetMinorType(min);
3165 if (type == -1)
3166 return -ENODEV;
3167
3168 fd = drmOpenMinor(min, 0, type);
3169 if (fd < 0)
3170 return -errno;
3171
3172 if (drmIoctl(fd, DRM_IOCTL_GET_PCIINFO, &pinfo)) {
3173 close(fd);
3174 return -errno;
3175 }
3176 close(fd);
3177
3178 device->vendor_id = pinfo.vendor_id;
3179 device->device_id = pinfo.device_id;
3180 device->revision_id = pinfo.revision_id;
3181 device->subvendor_id = pinfo.subvendor_id;
3182 device->subdevice_id = pinfo.subdevice_id;
3183
3184 return 0;
3185 #else
3186 #warning "Missing implementation of drmParsePciDeviceInfo"
3187 return -EINVAL;
3188 #endif
3189 }
3190
drmFreePlatformDevice(drmDevicePtr device)3191 static void drmFreePlatformDevice(drmDevicePtr device)
3192 {
3193 if (device->deviceinfo.platform) {
3194 if (device->deviceinfo.platform->compatible) {
3195 char **compatible = device->deviceinfo.platform->compatible;
3196
3197 while (*compatible) {
3198 free(*compatible);
3199 compatible++;
3200 }
3201
3202 free(device->deviceinfo.platform->compatible);
3203 }
3204 }
3205 }
3206
drmFreeHost1xDevice(drmDevicePtr device)3207 static void drmFreeHost1xDevice(drmDevicePtr device)
3208 {
3209 if (device->deviceinfo.host1x) {
3210 if (device->deviceinfo.host1x->compatible) {
3211 char **compatible = device->deviceinfo.host1x->compatible;
3212
3213 while (*compatible) {
3214 free(*compatible);
3215 compatible++;
3216 }
3217
3218 free(device->deviceinfo.host1x->compatible);
3219 }
3220 }
3221 }
3222
drmFreeDevice(drmDevicePtr * device)3223 void drmFreeDevice(drmDevicePtr *device)
3224 {
3225 if (device == NULL)
3226 return;
3227
3228 if (*device) {
3229 switch ((*device)->bustype) {
3230 case DRM_BUS_PLATFORM:
3231 drmFreePlatformDevice(*device);
3232 break;
3233
3234 case DRM_BUS_HOST1X:
3235 drmFreeHost1xDevice(*device);
3236 break;
3237 }
3238 }
3239
3240 free(*device);
3241 *device = NULL;
3242 }
3243
drmFreeDevices(drmDevicePtr devices[],int count)3244 void drmFreeDevices(drmDevicePtr devices[], int count)
3245 {
3246 int i;
3247
3248 if (devices == NULL)
3249 return;
3250
3251 for (i = 0; i < count; i++)
3252 if (devices[i])
3253 drmFreeDevice(&devices[i]);
3254 }
3255
drmDeviceAlloc(unsigned int type,const char * node,size_t bus_size,size_t device_size,char ** ptrp)3256 static drmDevicePtr drmDeviceAlloc(unsigned int type, const char *node,
3257 size_t bus_size, size_t device_size,
3258 char **ptrp)
3259 {
3260 size_t max_node_length, extra, size;
3261 drmDevicePtr device;
3262 unsigned int i;
3263 char *ptr;
3264
3265 max_node_length = ALIGN(drmGetMaxNodeName(), sizeof(void *));
3266 extra = DRM_NODE_MAX * (sizeof(void *) + max_node_length);
3267
3268 size = sizeof(*device) + extra + bus_size + device_size;
3269
3270 device = calloc(1, size);
3271 if (!device)
3272 return NULL;
3273
3274 device->available_nodes = 1 << type;
3275
3276 ptr = (char *)device + sizeof(*device);
3277 device->nodes = (char **)ptr;
3278
3279 ptr += DRM_NODE_MAX * sizeof(void *);
3280
3281 for (i = 0; i < DRM_NODE_MAX; i++) {
3282 device->nodes[i] = ptr;
3283 ptr += max_node_length;
3284 }
3285
3286 memcpy(device->nodes[type], node, max_node_length);
3287
3288 *ptrp = ptr;
3289
3290 return device;
3291 }
3292
drmProcessPciDevice(drmDevicePtr * device,const char * node,int node_type,int maj,int min,bool fetch_deviceinfo,uint32_t flags)3293 static int drmProcessPciDevice(drmDevicePtr *device,
3294 const char *node, int node_type,
3295 int maj, int min, bool fetch_deviceinfo,
3296 uint32_t flags)
3297 {
3298 drmDevicePtr dev;
3299 char *addr;
3300 int ret;
3301
3302 dev = drmDeviceAlloc(node_type, node, sizeof(drmPciBusInfo),
3303 sizeof(drmPciDeviceInfo), &addr);
3304 if (!dev)
3305 return -ENOMEM;
3306
3307 dev->bustype = DRM_BUS_PCI;
3308
3309 dev->businfo.pci = (drmPciBusInfoPtr)addr;
3310
3311 ret = drmParsePciBusInfo(maj, min, dev->businfo.pci);
3312 if (ret)
3313 goto free_device;
3314
3315 // Fetch the device info if the user has requested it
3316 if (fetch_deviceinfo) {
3317 addr += sizeof(drmPciBusInfo);
3318 dev->deviceinfo.pci = (drmPciDeviceInfoPtr)addr;
3319
3320 ret = drmParsePciDeviceInfo(maj, min, dev->deviceinfo.pci, flags);
3321 if (ret)
3322 goto free_device;
3323 }
3324
3325 *device = dev;
3326
3327 return 0;
3328
3329 free_device:
3330 free(dev);
3331 return ret;
3332 }
3333
drmParseUsbBusInfo(int maj,int min,drmUsbBusInfoPtr info)3334 static int drmParseUsbBusInfo(int maj, int min, drmUsbBusInfoPtr info)
3335 {
3336 #ifdef __linux__
3337 char path[PATH_MAX + 1], *value;
3338 unsigned int bus, dev;
3339 int ret;
3340
3341 snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min);
3342
3343 value = sysfs_uevent_get(path, "BUSNUM");
3344 if (!value)
3345 return -ENOENT;
3346
3347 ret = sscanf(value, "%03u", &bus);
3348 free(value);
3349
3350 if (ret <= 0)
3351 return -errno;
3352
3353 value = sysfs_uevent_get(path, "DEVNUM");
3354 if (!value)
3355 return -ENOENT;
3356
3357 ret = sscanf(value, "%03u", &dev);
3358 free(value);
3359
3360 if (ret <= 0)
3361 return -errno;
3362
3363 info->bus = bus;
3364 info->dev = dev;
3365
3366 return 0;
3367 #else
3368 #warning "Missing implementation of drmParseUsbBusInfo"
3369 return -EINVAL;
3370 #endif
3371 }
3372
drmParseUsbDeviceInfo(int maj,int min,drmUsbDeviceInfoPtr info)3373 static int drmParseUsbDeviceInfo(int maj, int min, drmUsbDeviceInfoPtr info)
3374 {
3375 #ifdef __linux__
3376 char path[PATH_MAX + 1], *value;
3377 unsigned int vendor, product;
3378 int ret;
3379
3380 snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min);
3381
3382 value = sysfs_uevent_get(path, "PRODUCT");
3383 if (!value)
3384 return -ENOENT;
3385
3386 ret = sscanf(value, "%x/%x", &vendor, &product);
3387 free(value);
3388
3389 if (ret <= 0)
3390 return -errno;
3391
3392 info->vendor = vendor;
3393 info->product = product;
3394
3395 return 0;
3396 #else
3397 #warning "Missing implementation of drmParseUsbDeviceInfo"
3398 return -EINVAL;
3399 #endif
3400 }
3401
drmProcessUsbDevice(drmDevicePtr * device,const char * node,int node_type,int maj,int min,bool fetch_deviceinfo,uint32_t flags)3402 static int drmProcessUsbDevice(drmDevicePtr *device, const char *node,
3403 int node_type, int maj, int min,
3404 bool fetch_deviceinfo, uint32_t flags)
3405 {
3406 drmDevicePtr dev;
3407 char *ptr;
3408 int ret;
3409
3410 dev = drmDeviceAlloc(node_type, node, sizeof(drmUsbBusInfo),
3411 sizeof(drmUsbDeviceInfo), &ptr);
3412 if (!dev)
3413 return -ENOMEM;
3414
3415 dev->bustype = DRM_BUS_USB;
3416
3417 dev->businfo.usb = (drmUsbBusInfoPtr)ptr;
3418
3419 ret = drmParseUsbBusInfo(maj, min, dev->businfo.usb);
3420 if (ret < 0)
3421 goto free_device;
3422
3423 if (fetch_deviceinfo) {
3424 ptr += sizeof(drmUsbBusInfo);
3425 dev->deviceinfo.usb = (drmUsbDeviceInfoPtr)ptr;
3426
3427 ret = drmParseUsbDeviceInfo(maj, min, dev->deviceinfo.usb);
3428 if (ret < 0)
3429 goto free_device;
3430 }
3431
3432 *device = dev;
3433
3434 return 0;
3435
3436 free_device:
3437 free(dev);
3438 return ret;
3439 }
3440
drmParsePlatformBusInfo(int maj,int min,drmPlatformBusInfoPtr info)3441 static int drmParsePlatformBusInfo(int maj, int min, drmPlatformBusInfoPtr info)
3442 {
3443 #ifdef __linux__
3444 char path[PATH_MAX + 1], *name;
3445
3446 snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min);
3447
3448 name = sysfs_uevent_get(path, "OF_FULLNAME");
3449 if (!name)
3450 return -ENOENT;
3451
3452 strncpy(info->fullname, name, DRM_PLATFORM_DEVICE_NAME_LEN);
3453 info->fullname[DRM_PLATFORM_DEVICE_NAME_LEN - 1] = '\0';
3454 free(name);
3455
3456 return 0;
3457 #else
3458 #warning "Missing implementation of drmParsePlatformBusInfo"
3459 return -EINVAL;
3460 #endif
3461 }
3462
drmParsePlatformDeviceInfo(int maj,int min,drmPlatformDeviceInfoPtr info)3463 static int drmParsePlatformDeviceInfo(int maj, int min,
3464 drmPlatformDeviceInfoPtr info)
3465 {
3466 #ifdef __linux__
3467 char path[PATH_MAX + 1], *value;
3468 unsigned int count, i;
3469 int err;
3470
3471 snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min);
3472
3473 value = sysfs_uevent_get(path, "OF_COMPATIBLE_N");
3474 if (!value)
3475 return -ENOENT;
3476
3477 sscanf(value, "%u", &count);
3478 free(value);
3479
3480 info->compatible = calloc(count + 1, sizeof(*info->compatible));
3481 if (!info->compatible)
3482 return -ENOMEM;
3483
3484 for (i = 0; i < count; i++) {
3485 value = sysfs_uevent_get(path, "OF_COMPATIBLE_%u", i);
3486 if (!value) {
3487 err = -ENOENT;
3488 goto free;
3489 }
3490
3491 info->compatible[i] = value;
3492 }
3493
3494 return 0;
3495
3496 free:
3497 while (i--)
3498 free(info->compatible[i]);
3499
3500 free(info->compatible);
3501 return err;
3502 #else
3503 #warning "Missing implementation of drmParsePlatformDeviceInfo"
3504 return -EINVAL;
3505 #endif
3506 }
3507
drmProcessPlatformDevice(drmDevicePtr * device,const char * node,int node_type,int maj,int min,bool fetch_deviceinfo,uint32_t flags)3508 static int drmProcessPlatformDevice(drmDevicePtr *device,
3509 const char *node, int node_type,
3510 int maj, int min, bool fetch_deviceinfo,
3511 uint32_t flags)
3512 {
3513 drmDevicePtr dev;
3514 char *ptr;
3515 int ret;
3516
3517 dev = drmDeviceAlloc(node_type, node, sizeof(drmPlatformBusInfo),
3518 sizeof(drmPlatformDeviceInfo), &ptr);
3519 if (!dev)
3520 return -ENOMEM;
3521
3522 dev->bustype = DRM_BUS_PLATFORM;
3523
3524 dev->businfo.platform = (drmPlatformBusInfoPtr)ptr;
3525
3526 ret = drmParsePlatformBusInfo(maj, min, dev->businfo.platform);
3527 if (ret < 0)
3528 goto free_device;
3529
3530 if (fetch_deviceinfo) {
3531 ptr += sizeof(drmPlatformBusInfo);
3532 dev->deviceinfo.platform = (drmPlatformDeviceInfoPtr)ptr;
3533
3534 ret = drmParsePlatformDeviceInfo(maj, min, dev->deviceinfo.platform);
3535 if (ret < 0)
3536 goto free_device;
3537 }
3538
3539 *device = dev;
3540
3541 return 0;
3542
3543 free_device:
3544 free(dev);
3545 return ret;
3546 }
3547
drmParseHost1xBusInfo(int maj,int min,drmHost1xBusInfoPtr info)3548 static int drmParseHost1xBusInfo(int maj, int min, drmHost1xBusInfoPtr info)
3549 {
3550 #ifdef __linux__
3551 char path[PATH_MAX + 1], *name;
3552
3553 snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min);
3554
3555 name = sysfs_uevent_get(path, "OF_FULLNAME");
3556 if (!name)
3557 return -ENOENT;
3558
3559 strncpy(info->fullname, name, DRM_HOST1X_DEVICE_NAME_LEN);
3560 info->fullname[DRM_HOST1X_DEVICE_NAME_LEN - 1] = '\0';
3561 free(name);
3562
3563 return 0;
3564 #else
3565 #warning "Missing implementation of drmParseHost1xBusInfo"
3566 return -EINVAL;
3567 #endif
3568 }
3569
drmParseHost1xDeviceInfo(int maj,int min,drmHost1xDeviceInfoPtr info)3570 static int drmParseHost1xDeviceInfo(int maj, int min,
3571 drmHost1xDeviceInfoPtr info)
3572 {
3573 #ifdef __linux__
3574 char path[PATH_MAX + 1], *value;
3575 unsigned int count, i;
3576 int err;
3577
3578 snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min);
3579
3580 value = sysfs_uevent_get(path, "OF_COMPATIBLE_N");
3581 if (!value)
3582 return -ENOENT;
3583
3584 sscanf(value, "%u", &count);
3585 free(value);
3586
3587 info->compatible = calloc(count + 1, sizeof(*info->compatible));
3588 if (!info->compatible)
3589 return -ENOMEM;
3590
3591 for (i = 0; i < count; i++) {
3592 value = sysfs_uevent_get(path, "OF_COMPATIBLE_%u", i);
3593 if (!value) {
3594 err = -ENOENT;
3595 goto free;
3596 }
3597
3598 info->compatible[i] = value;
3599 }
3600
3601 return 0;
3602
3603 free:
3604 while (i--)
3605 free(info->compatible[i]);
3606
3607 free(info->compatible);
3608 return err;
3609 #else
3610 #warning "Missing implementation of drmParseHost1xDeviceInfo"
3611 return -EINVAL;
3612 #endif
3613 }
3614
drmProcessHost1xDevice(drmDevicePtr * device,const char * node,int node_type,int maj,int min,bool fetch_deviceinfo,uint32_t flags)3615 static int drmProcessHost1xDevice(drmDevicePtr *device,
3616 const char *node, int node_type,
3617 int maj, int min, bool fetch_deviceinfo,
3618 uint32_t flags)
3619 {
3620 drmDevicePtr dev;
3621 char *ptr;
3622 int ret;
3623
3624 dev = drmDeviceAlloc(node_type, node, sizeof(drmHost1xBusInfo),
3625 sizeof(drmHost1xDeviceInfo), &ptr);
3626 if (!dev)
3627 return -ENOMEM;
3628
3629 dev->bustype = DRM_BUS_HOST1X;
3630
3631 dev->businfo.host1x = (drmHost1xBusInfoPtr)ptr;
3632
3633 ret = drmParseHost1xBusInfo(maj, min, dev->businfo.host1x);
3634 if (ret < 0)
3635 goto free_device;
3636
3637 if (fetch_deviceinfo) {
3638 ptr += sizeof(drmHost1xBusInfo);
3639 dev->deviceinfo.host1x = (drmHost1xDeviceInfoPtr)ptr;
3640
3641 ret = drmParseHost1xDeviceInfo(maj, min, dev->deviceinfo.host1x);
3642 if (ret < 0)
3643 goto free_device;
3644 }
3645
3646 *device = dev;
3647
3648 return 0;
3649
3650 free_device:
3651 free(dev);
3652 return ret;
3653 }
3654
3655 /* Consider devices located on the same bus as duplicate and fold the respective
3656 * entries into a single one.
3657 *
3658 * Note: this leaves "gaps" in the array, while preserving the length.
3659 */
drmFoldDuplicatedDevices(drmDevicePtr local_devices[],int count)3660 static void drmFoldDuplicatedDevices(drmDevicePtr local_devices[], int count)
3661 {
3662 int node_type, i, j;
3663
3664 for (i = 0; i < count; i++) {
3665 for (j = i + 1; j < count; j++) {
3666 if (drmCompareBusInfo(local_devices[i], local_devices[j]) == 0) {
3667 local_devices[i]->available_nodes |= local_devices[j]->available_nodes;
3668 node_type = log2(local_devices[j]->available_nodes);
3669 memcpy(local_devices[i]->nodes[node_type],
3670 local_devices[j]->nodes[node_type], drmGetMaxNodeName());
3671 drmFreeDevice(&local_devices[j]);
3672 }
3673 }
3674 }
3675 }
3676
3677 /* Check that the given flags are valid returning 0 on success */
3678 static int
drm_device_validate_flags(uint32_t flags)3679 drm_device_validate_flags(uint32_t flags)
3680 {
3681 return (flags & ~DRM_DEVICE_GET_PCI_REVISION);
3682 }
3683
3684 /**
3685 * Get information about the opened drm device
3686 *
3687 * \param fd file descriptor of the drm device
3688 * \param flags feature/behaviour bitmask
3689 * \param device the address of a drmDevicePtr where the information
3690 * will be allocated in stored
3691 *
3692 * \return zero on success, negative error code otherwise.
3693 *
3694 * \note Unlike drmGetDevice it does not retrieve the pci device revision field
3695 * unless the DRM_DEVICE_GET_PCI_REVISION \p flag is set.
3696 */
drmGetDevice2(int fd,uint32_t flags,drmDevicePtr * device)3697 int drmGetDevice2(int fd, uint32_t flags, drmDevicePtr *device)
3698 {
3699 #ifdef __OpenBSD__
3700 /*
3701 * DRI device nodes on OpenBSD are not in their own directory, they reside
3702 * in /dev along with a large number of statically generated /dev nodes.
3703 * Avoid stat'ing all of /dev needlessly by implementing this custom path.
3704 */
3705 drmDevicePtr d;
3706 struct stat sbuf;
3707 char node[PATH_MAX + 1];
3708 const char *dev_name;
3709 int node_type, subsystem_type;
3710 int maj, min, n, ret, base;
3711
3712 if (fd == -1 || device == NULL)
3713 return -EINVAL;
3714
3715 if (fstat(fd, &sbuf))
3716 return -errno;
3717
3718 maj = major(sbuf.st_rdev);
3719 min = minor(sbuf.st_rdev);
3720
3721 if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode))
3722 return -EINVAL;
3723
3724 node_type = drmGetMinorType(min);
3725 if (node_type == -1)
3726 return -ENODEV;
3727
3728 switch (node_type) {
3729 case DRM_NODE_PRIMARY:
3730 dev_name = DRM_DEV_NAME;
3731 break;
3732 case DRM_NODE_CONTROL:
3733 dev_name = DRM_CONTROL_DEV_NAME;
3734 break;
3735 case DRM_NODE_RENDER:
3736 dev_name = DRM_RENDER_DEV_NAME;
3737 break;
3738 default:
3739 return -EINVAL;
3740 };
3741
3742 base = drmGetMinorBase(node_type);
3743 if (base < 0)
3744 return -EINVAL;
3745
3746 n = snprintf(node, PATH_MAX, dev_name, DRM_DIR_NAME, min - base);
3747 if (n == -1 || n >= PATH_MAX)
3748 return -errno;
3749 if (stat(node, &sbuf))
3750 return -EINVAL;
3751
3752 subsystem_type = drmParseSubsystemType(maj, min);
3753 if (subsystem_type != DRM_BUS_PCI)
3754 return -ENODEV;
3755
3756 ret = drmProcessPciDevice(&d, node, node_type, maj, min, true, flags);
3757 if (ret)
3758 return ret;
3759
3760 *device = d;
3761
3762 return 0;
3763 #else
3764 drmDevicePtr *local_devices;
3765 drmDevicePtr d;
3766 DIR *sysdir;
3767 struct dirent *dent;
3768 struct stat sbuf;
3769 char node[PATH_MAX + 1];
3770 int node_type, subsystem_type;
3771 int maj, min;
3772 int ret, i, node_count;
3773 int max_count = 16;
3774 dev_t find_rdev;
3775
3776 if (drm_device_validate_flags(flags))
3777 return -EINVAL;
3778
3779 if (fd == -1 || device == NULL)
3780 return -EINVAL;
3781
3782 if (fstat(fd, &sbuf))
3783 return -errno;
3784
3785 find_rdev = sbuf.st_rdev;
3786 maj = major(sbuf.st_rdev);
3787 min = minor(sbuf.st_rdev);
3788
3789 if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode))
3790 return -EINVAL;
3791
3792 subsystem_type = drmParseSubsystemType(maj, min);
3793
3794 local_devices = calloc(max_count, sizeof(drmDevicePtr));
3795 if (local_devices == NULL)
3796 return -ENOMEM;
3797
3798 sysdir = opendir(DRM_DIR_NAME);
3799 if (!sysdir) {
3800 ret = -errno;
3801 goto free_locals;
3802 }
3803
3804 i = 0;
3805 while ((dent = readdir(sysdir))) {
3806 node_type = drmGetNodeType(dent->d_name);
3807 if (node_type < 0)
3808 continue;
3809
3810 snprintf(node, PATH_MAX, "%s/%s", DRM_DIR_NAME, dent->d_name);
3811 if (stat(node, &sbuf))
3812 continue;
3813
3814 maj = major(sbuf.st_rdev);
3815 min = minor(sbuf.st_rdev);
3816
3817 if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode))
3818 continue;
3819
3820 if (drmParseSubsystemType(maj, min) != subsystem_type)
3821 continue;
3822
3823 switch (subsystem_type) {
3824 case DRM_BUS_PCI:
3825 ret = drmProcessPciDevice(&d, node, node_type, maj, min, true, flags);
3826 if (ret)
3827 continue;
3828
3829 break;
3830
3831 case DRM_BUS_USB:
3832 ret = drmProcessUsbDevice(&d, node, node_type, maj, min, true, flags);
3833 if (ret)
3834 continue;
3835
3836 break;
3837
3838 case DRM_BUS_PLATFORM:
3839 ret = drmProcessPlatformDevice(&d, node, node_type, maj, min, true, flags);
3840 if (ret)
3841 continue;
3842
3843 break;
3844
3845 case DRM_BUS_HOST1X:
3846 ret = drmProcessHost1xDevice(&d, node, node_type, maj, min, true, flags);
3847 if (ret)
3848 continue;
3849
3850 break;
3851
3852 default:
3853 continue;
3854 }
3855
3856 if (i >= max_count) {
3857 drmDevicePtr *temp;
3858
3859 max_count += 16;
3860 temp = realloc(local_devices, max_count * sizeof(drmDevicePtr));
3861 if (!temp)
3862 goto free_devices;
3863 local_devices = temp;
3864 }
3865
3866 /* store target at local_devices[0] for ease to use below */
3867 if (find_rdev == sbuf.st_rdev && i) {
3868 local_devices[i] = local_devices[0];
3869 local_devices[0] = d;
3870 }
3871 else
3872 local_devices[i] = d;
3873 i++;
3874 }
3875 node_count = i;
3876
3877 drmFoldDuplicatedDevices(local_devices, node_count);
3878
3879 *device = local_devices[0];
3880 drmFreeDevices(&local_devices[1], node_count - 1);
3881
3882 closedir(sysdir);
3883 free(local_devices);
3884 if (*device == NULL)
3885 return -ENODEV;
3886 return 0;
3887
3888 free_devices:
3889 drmFreeDevices(local_devices, i);
3890 closedir(sysdir);
3891
3892 free_locals:
3893 free(local_devices);
3894 return ret;
3895 #endif
3896 }
3897
3898 /**
3899 * Get information about the opened drm device
3900 *
3901 * \param fd file descriptor of the drm device
3902 * \param device the address of a drmDevicePtr where the information
3903 * will be allocated in stored
3904 *
3905 * \return zero on success, negative error code otherwise.
3906 */
drmGetDevice(int fd,drmDevicePtr * device)3907 int drmGetDevice(int fd, drmDevicePtr *device)
3908 {
3909 return drmGetDevice2(fd, DRM_DEVICE_GET_PCI_REVISION, device);
3910 }
3911
3912 /**
3913 * Get drm devices on the system
3914 *
3915 * \param flags feature/behaviour bitmask
3916 * \param devices the array of devices with drmDevicePtr elements
3917 * can be NULL to get the device number first
3918 * \param max_devices the maximum number of devices for the array
3919 *
3920 * \return on error - negative error code,
3921 * if devices is NULL - total number of devices available on the system,
3922 * alternatively the number of devices stored in devices[], which is
3923 * capped by the max_devices.
3924 *
3925 * \note Unlike drmGetDevices it does not retrieve the pci device revision field
3926 * unless the DRM_DEVICE_GET_PCI_REVISION \p flag is set.
3927 */
drmGetDevices2(uint32_t flags,drmDevicePtr devices[],int max_devices)3928 int drmGetDevices2(uint32_t flags, drmDevicePtr devices[], int max_devices)
3929 {
3930 drmDevicePtr *local_devices;
3931 drmDevicePtr device;
3932 DIR *sysdir;
3933 struct dirent *dent;
3934 struct stat sbuf;
3935 char node[PATH_MAX + 1];
3936 int node_type, subsystem_type;
3937 int maj, min;
3938 int ret, i, node_count, device_count;
3939 int max_count = 16;
3940
3941 if (drm_device_validate_flags(flags))
3942 return -EINVAL;
3943
3944 local_devices = calloc(max_count, sizeof(drmDevicePtr));
3945 if (local_devices == NULL)
3946 return -ENOMEM;
3947
3948 sysdir = opendir(DRM_DIR_NAME);
3949 if (!sysdir) {
3950 ret = -errno;
3951 goto free_locals;
3952 }
3953
3954 i = 0;
3955 while ((dent = readdir(sysdir))) {
3956 node_type = drmGetNodeType(dent->d_name);
3957 if (node_type < 0)
3958 continue;
3959
3960 snprintf(node, PATH_MAX, "%s/%s", DRM_DIR_NAME, dent->d_name);
3961 if (stat(node, &sbuf))
3962 continue;
3963
3964 maj = major(sbuf.st_rdev);
3965 min = minor(sbuf.st_rdev);
3966
3967 if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode))
3968 continue;
3969
3970 subsystem_type = drmParseSubsystemType(maj, min);
3971
3972 if (subsystem_type < 0)
3973 continue;
3974
3975 switch (subsystem_type) {
3976 case DRM_BUS_PCI:
3977 ret = drmProcessPciDevice(&device, node, node_type,
3978 maj, min, devices != NULL, flags);
3979 if (ret)
3980 continue;
3981
3982 break;
3983
3984 case DRM_BUS_USB:
3985 ret = drmProcessUsbDevice(&device, node, node_type, maj, min,
3986 devices != NULL, flags);
3987 if (ret)
3988 goto free_devices;
3989
3990 break;
3991
3992 case DRM_BUS_PLATFORM:
3993 ret = drmProcessPlatformDevice(&device, node, node_type, maj, min,
3994 devices != NULL, flags);
3995 if (ret)
3996 goto free_devices;
3997
3998 break;
3999
4000 case DRM_BUS_HOST1X:
4001 ret = drmProcessHost1xDevice(&device, node, node_type, maj, min,
4002 devices != NULL, flags);
4003 if (ret)
4004 goto free_devices;
4005
4006 break;
4007
4008 default:
4009 continue;
4010 }
4011
4012 if (i >= max_count) {
4013 drmDevicePtr *temp;
4014
4015 max_count += 16;
4016 temp = realloc(local_devices, max_count * sizeof(drmDevicePtr));
4017 if (!temp)
4018 goto free_devices;
4019 local_devices = temp;
4020 }
4021
4022 local_devices[i] = device;
4023 i++;
4024 }
4025 node_count = i;
4026
4027 drmFoldDuplicatedDevices(local_devices, node_count);
4028
4029 device_count = 0;
4030 for (i = 0; i < node_count; i++) {
4031 if (!local_devices[i])
4032 continue;
4033
4034 if ((devices != NULL) && (device_count < max_devices))
4035 devices[device_count] = local_devices[i];
4036 else
4037 drmFreeDevice(&local_devices[i]);
4038
4039 device_count++;
4040 }
4041
4042 closedir(sysdir);
4043 free(local_devices);
4044 return device_count;
4045
4046 free_devices:
4047 drmFreeDevices(local_devices, i);
4048 closedir(sysdir);
4049
4050 free_locals:
4051 free(local_devices);
4052 return ret;
4053 }
4054
4055 /**
4056 * Get drm devices on the system
4057 *
4058 * \param devices the array of devices with drmDevicePtr elements
4059 * can be NULL to get the device number first
4060 * \param max_devices the maximum number of devices for the array
4061 *
4062 * \return on error - negative error code,
4063 * if devices is NULL - total number of devices available on the system,
4064 * alternatively the number of devices stored in devices[], which is
4065 * capped by the max_devices.
4066 */
drmGetDevices(drmDevicePtr devices[],int max_devices)4067 int drmGetDevices(drmDevicePtr devices[], int max_devices)
4068 {
4069 return drmGetDevices2(DRM_DEVICE_GET_PCI_REVISION, devices, max_devices);
4070 }
4071
drmGetDeviceNameFromFd2(int fd)4072 char *drmGetDeviceNameFromFd2(int fd)
4073 {
4074 #ifdef __linux__
4075 struct stat sbuf;
4076 char path[PATH_MAX + 1], *value;
4077 unsigned int maj, min;
4078
4079 if (fstat(fd, &sbuf))
4080 return NULL;
4081
4082 maj = major(sbuf.st_rdev);
4083 min = minor(sbuf.st_rdev);
4084
4085 if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode))
4086 return NULL;
4087
4088 snprintf(path, sizeof(path), "/sys/dev/char/%d:%d", maj, min);
4089
4090 value = sysfs_uevent_get(path, "DEVNAME");
4091 if (!value)
4092 return NULL;
4093
4094 snprintf(path, sizeof(path), "/dev/%s", value);
4095 free(value);
4096
4097 return strdup(path);
4098 #else
4099 struct stat sbuf;
4100 char node[PATH_MAX + 1];
4101 const char *dev_name;
4102 int node_type;
4103 int maj, min, n, base;
4104
4105 if (fstat(fd, &sbuf))
4106 return NULL;
4107
4108 maj = major(sbuf.st_rdev);
4109 min = minor(sbuf.st_rdev);
4110
4111 if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode))
4112 return NULL;
4113
4114 node_type = drmGetMinorType(min);
4115 if (node_type == -1)
4116 return NULL;
4117
4118 switch (node_type) {
4119 case DRM_NODE_PRIMARY:
4120 dev_name = DRM_DEV_NAME;
4121 break;
4122 case DRM_NODE_CONTROL:
4123 dev_name = DRM_CONTROL_DEV_NAME;
4124 break;
4125 case DRM_NODE_RENDER:
4126 dev_name = DRM_RENDER_DEV_NAME;
4127 break;
4128 default:
4129 return NULL;
4130 };
4131
4132 base = drmGetMinorBase(node_type);
4133 if (base < 0)
4134 return NULL;
4135
4136 n = snprintf(node, PATH_MAX, dev_name, DRM_DIR_NAME, min - base);
4137 if (n == -1 || n >= PATH_MAX)
4138 return NULL;
4139
4140 return strdup(node);
4141 #endif
4142 }
4143