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