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__ 106struct 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 125static drmServerInfoPtr drm_server_info; 126 127void 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 141static int DRM_PRINTFLIKE(1, 0) 142drmDebugPrint(const char *format, va_list ap) 143{ 144 return vfprintf(stderr, format, ap); 145} 146 147void 148drmMsg(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 165static void *drmHashTable = NULL; /* Context switch callbacks */ 166 167void *drmGetHashTable(void) 168{ 169 return drmHashTable; 170} 171 172void *drmMalloc(int size) 173{ 174 return calloc(1, size); 175} 176 177void drmFree(void *pt) 178{ 179 free(pt); 180} 181 182/** 183 * Call ioctl, restarting if it is interupted 184 */ 185int 186drmIoctl(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 196static 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 205drmHashEntry *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 */ 239static 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) 297static 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 */ 327static 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; 390wait_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 */ 456static 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 */ 496int 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 520static 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 534static 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 551static 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 */ 579static 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 */ 643static 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 */ 731int 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 */ 752int drmOpenWithType(const char *name, const char *busid, int type) 753{ 754 if (!drmAvailable() && name != NULL && drm_server_info && 755 drm_server_info->load_module) { 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 775int drmOpenControl(int minor) 776{ 777 return drmOpenMinor(minor, 0, DRM_NODE_CONTROL); 778} 779 780int 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 */ 794void 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 */ 814static 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 */ 835static 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 */ 864drmVersionPtr 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 */ 914drmVersionPtr 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 935int 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 951int 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 */ 970void 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 */ 988char *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 */ 1017int 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 1031int 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 1044int 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 */ 1105int 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 1122int 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 */ 1150int 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 1166int 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 */ 1217int 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 */ 1238int 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 */ 1269int 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 */ 1299int drmUnmap(drmAddress address, drmSize size) 1300{ 1301 return drm_munmap(address, size); 1302} 1303 1304drmBufInfoPtr 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 */ 1354drmBufMapPtr 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 */ 1399int 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 */ 1427int 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 */ 1470int 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 */ 1501int 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 1510drm_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 1543void 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 */ 1566int 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 1577int 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 1588int 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 1609int 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 */ 1643int 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 1654int 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 1665int 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 1676int 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 */ 1706int 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 */ 1724int 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 */ 1744int 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 */ 1772int 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 */ 1802int 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 */ 1827int 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 */ 1852int 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 */ 1875int 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 */ 1898int 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 */ 1921unsigned 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 */ 1944unsigned 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 */ 1967unsigned 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 */ 1990unsigned 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 */ 2013unsigned 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 */ 2036unsigned 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 */ 2059unsigned 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 2070int 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 2084int 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 */ 2106int 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 2134out: 2135 return ret; 2136} 2137 2138int 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 */ 2175int 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 */ 2199int 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 2211int 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 */ 2242int 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 2255int 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 2266int drmDelContextTag(int fd, drm_context_t context) 2267{ 2268 drmHashEntry *entry = drmGetEntry(fd); 2269 2270 return drmHashDelete(entry->tagTable, context); 2271} 2272 2273void *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 2284int 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 2298int 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 2314int 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 2333int 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 2350int 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 */ 2488int 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 */ 2523int 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 */ 2550int 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 */ 2579int 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 */ 2608int 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 2622static struct { 2623 char *BusID; 2624 int fd; 2625 int refcount; 2626 int type; 2627} connection[DRM_MAX_FDS]; 2628 2629static int nr_fds = 0; 2630 2631int drmOpenOnce(void *unused, 2632 const char *BusID, 2633 int *newlyopened) 2634{ 2635 return drmOpenOnceWithType(BusID, newlyopened, DRM_NODE_PRIMARY); 2636} 2637 2638int 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 2671void 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 2690int drmSetMaster(int fd) 2691{ 2692 return drmIoctl(fd, DRM_IOCTL_SET_MASTER, NULL); 2693} 2694 2695int drmDropMaster(int fd) 2696{ 2697 return drmIoctl(fd, DRM_IOCTL_DROP_MASTER, NULL); 2698} 2699 2700char *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 2726int 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 2748int 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 2765int 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 2780static 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 2834out_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 2879char *drmGetPrimaryDeviceNameFromFd(int fd) 2880{ 2881 return drmGetMinorNameForFD(fd, DRM_NODE_PRIMARY); 2882} 2883 2884char *drmGetRenderDeviceNameFromFd(int fd) 2885{ 2886 return drmGetMinorNameForFD(fd, DRM_NODE_RENDER); 2887} 2888 2889#ifdef __linux__ 2890static char * DRM_PRINTFLIKE(2, 3) 2891sysfs_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 2933static 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 2971static 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 3026static 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 3054static 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 3071static 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__ 3081static 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 3121static 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 3148static 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 3191static 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 3207static 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 3223void 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 3244void 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 3256static 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 3293static 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 3329free_device: 3330 free(dev); 3331 return ret; 3332} 3333 3334static 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 3373static 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 3402static 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 3436free_device: 3437 free(dev); 3438 return ret; 3439} 3440 3441static 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 3463static 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 3496free: 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 3508static 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 3543free_device: 3544 free(dev); 3545 return ret; 3546} 3547 3548static 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 3570static 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 3603free: 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 3615static 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 3650free_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 */ 3660static 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 */ 3678static int 3679drm_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 */ 3697int 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 3888free_devices: 3889 drmFreeDevices(local_devices, i); 3890 closedir(sysdir); 3891 3892free_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 */ 3907int 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 */ 3928int 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 4046free_devices: 4047 drmFreeDevices(local_devices, i); 4048 closedir(sysdir); 4049 4050free_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 */ 4067int drmGetDevices(drmDevicePtr devices[], int max_devices) 4068{ 4069 return drmGetDevices2(DRM_DEVICE_GET_PCI_REVISION, devices, max_devices); 4070} 4071 4072char *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