loader.c revision 757f638f
1af69d88dSmrg/* 2af69d88dSmrg * Copyright (C) 2013 Rob Clark <robclark@freedesktop.org> 301e04c3fSmrg * Copyright (C) 2014-2016 Emil Velikov <emil.l.velikov@gmail.com> 401e04c3fSmrg * Copyright (C) 2016 Intel Corporation 5af69d88dSmrg * 6af69d88dSmrg * Permission is hereby granted, free of charge, to any person obtaining a 7af69d88dSmrg * copy of this software and associated documentation files (the "Software"), 8af69d88dSmrg * to deal in the Software without restriction, including without limitation 9af69d88dSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10af69d88dSmrg * and/or sell copies of the Software, and to permit persons to whom the 11af69d88dSmrg * Software is furnished to do so, subject to the following conditions: 12af69d88dSmrg * 13af69d88dSmrg * The above copyright notice and this permission notice (including the next 14af69d88dSmrg * paragraph) shall be included in all copies or substantial portions of the 15af69d88dSmrg * Software. 16af69d88dSmrg * 17af69d88dSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18af69d88dSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19af69d88dSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20af69d88dSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21af69d88dSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22af69d88dSmrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23af69d88dSmrg * SOFTWARE. 24af69d88dSmrg * 25af69d88dSmrg * Authors: 26af69d88dSmrg * Rob Clark <robclark@freedesktop.org> 27af69d88dSmrg */ 28af69d88dSmrg 299f464c52Smaya#include <dlfcn.h> 3001e04c3fSmrg#include <errno.h> 3101e04c3fSmrg#include <fcntl.h> 3201e04c3fSmrg#include <sys/stat.h> 33af69d88dSmrg#include <stdarg.h> 34af69d88dSmrg#include <stdio.h> 3501e04c3fSmrg#include <stdbool.h> 36af69d88dSmrg#include <string.h> 37af69d88dSmrg#include <unistd.h> 38af69d88dSmrg#include <stdlib.h> 399f464c52Smaya#include <sys/param.h> 4001e04c3fSmrg#ifdef MAJOR_IN_MKDEV 4101e04c3fSmrg#include <sys/mkdev.h> 42af69d88dSmrg#endif 4301e04c3fSmrg#ifdef MAJOR_IN_SYSMACROS 4401e04c3fSmrg#include <sys/sysmacros.h> 45af69d88dSmrg#endif 469f464c52Smaya#include <GL/gl.h> 479f464c52Smaya#include <GL/internal/dri_interface.h> 48af69d88dSmrg#include "loader.h" 49af69d88dSmrg 5001e04c3fSmrg#ifdef HAVE_LIBDRM 51af69d88dSmrg#include <xf86drm.h> 5201e04c3fSmrg#ifdef USE_DRICONF 5301e04c3fSmrg#include "util/xmlconfig.h" 5401e04c3fSmrg#include "util/xmlpool.h" 5501e04c3fSmrg#endif 56af69d88dSmrg#endif 57af69d88dSmrg 58af69d88dSmrg#define __IS_LOADER 59af69d88dSmrg#include "pci_id_driver_map.h" 60af69d88dSmrg 61af69d88dSmrgstatic void default_logger(int level, const char *fmt, ...) 62af69d88dSmrg{ 63af69d88dSmrg if (level <= _LOADER_WARNING) { 64af69d88dSmrg va_list args; 65af69d88dSmrg va_start(args, fmt); 66af69d88dSmrg vfprintf(stderr, fmt, args); 67af69d88dSmrg va_end(args); 68af69d88dSmrg } 69af69d88dSmrg} 70af69d88dSmrg 719f464c52Smayastatic loader_logger *log_ = default_logger; 72af69d88dSmrg 7301e04c3fSmrgint 7401e04c3fSmrgloader_open_device(const char *device_name) 75af69d88dSmrg{ 7601e04c3fSmrg int fd; 7701e04c3fSmrg#ifdef O_CLOEXEC 7801e04c3fSmrg fd = open(device_name, O_RDWR | O_CLOEXEC); 7901e04c3fSmrg if (fd == -1 && errno == EINVAL) 8001e04c3fSmrg#endif 8101e04c3fSmrg { 8201e04c3fSmrg fd = open(device_name, O_RDWR); 8301e04c3fSmrg if (fd != -1) 8401e04c3fSmrg fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC); 85af69d88dSmrg } 8601e04c3fSmrg return fd; 87af69d88dSmrg} 88af69d88dSmrg 8901e04c3fSmrgstatic char *loader_get_kernel_driver_name(int fd) 90af69d88dSmrg{ 9101e04c3fSmrg#if HAVE_LIBDRM 9201e04c3fSmrg char *driver; 9301e04c3fSmrg drmVersionPtr version = drmGetVersion(fd); 9401e04c3fSmrg 9501e04c3fSmrg if (!version) { 9601e04c3fSmrg log_(_LOADER_WARNING, "failed to get driver name for fd %d\n", fd); 9701e04c3fSmrg return NULL; 9801e04c3fSmrg } 99af69d88dSmrg 10001e04c3fSmrg driver = strndup(version->name, version->name_len); 101af69d88dSmrg 10201e04c3fSmrg drmFreeVersion(version); 10301e04c3fSmrg return driver; 10401e04c3fSmrg#else 10501e04c3fSmrg return NULL; 10601e04c3fSmrg#endif 10701e04c3fSmrg} 108af69d88dSmrg 10901e04c3fSmrg#if defined(HAVE_LIBDRM) 11001e04c3fSmrgint 11101e04c3fSmrgloader_open_render_node(const char *name) 112af69d88dSmrg{ 11301e04c3fSmrg drmDevicePtr *devices, device; 11401e04c3fSmrg int err, render = -ENOENT, fd; 11501e04c3fSmrg unsigned int num, i; 116af69d88dSmrg 11701e04c3fSmrg err = drmGetDevices2(0, NULL, 0); 11801e04c3fSmrg if (err < 0) 11901e04c3fSmrg return err; 120af69d88dSmrg 12101e04c3fSmrg num = err; 12201e04c3fSmrg 12301e04c3fSmrg devices = calloc(num, sizeof(*devices)); 12401e04c3fSmrg if (!devices) 12501e04c3fSmrg return -ENOMEM; 12601e04c3fSmrg 12701e04c3fSmrg err = drmGetDevices2(0, devices, num); 12801e04c3fSmrg if (err < 0) { 12901e04c3fSmrg render = err; 13001e04c3fSmrg goto free; 131af69d88dSmrg } 132af69d88dSmrg 13301e04c3fSmrg for (i = 0; i < num; i++) { 13401e04c3fSmrg device = devices[i]; 13501e04c3fSmrg 13601e04c3fSmrg if ((device->available_nodes & (1 << DRM_NODE_RENDER)) && 13701e04c3fSmrg (device->bustype == DRM_BUS_PLATFORM)) { 13801e04c3fSmrg drmVersionPtr version; 13901e04c3fSmrg 1409f464c52Smaya fd = loader_open_device(device->nodes[DRM_NODE_RENDER]); 14101e04c3fSmrg if (fd < 0) 14201e04c3fSmrg continue; 14301e04c3fSmrg 14401e04c3fSmrg version = drmGetVersion(fd); 14501e04c3fSmrg if (!version) { 14601e04c3fSmrg close(fd); 14701e04c3fSmrg continue; 14801e04c3fSmrg } 14901e04c3fSmrg 15001e04c3fSmrg if (strcmp(version->name, name) != 0) { 15101e04c3fSmrg drmFreeVersion(version); 15201e04c3fSmrg close(fd); 15301e04c3fSmrg continue; 15401e04c3fSmrg } 15501e04c3fSmrg 15601e04c3fSmrg drmFreeVersion(version); 15701e04c3fSmrg render = fd; 15801e04c3fSmrg break; 15901e04c3fSmrg } 160af69d88dSmrg } 161af69d88dSmrg 16201e04c3fSmrg drmFreeDevices(devices, num); 16301e04c3fSmrg 16401e04c3fSmrgfree: 16501e04c3fSmrg free(devices); 16601e04c3fSmrg return render; 167af69d88dSmrg} 168af69d88dSmrg 16901e04c3fSmrg#ifdef USE_DRICONF 17001e04c3fSmrgstatic const char __driConfigOptionsLoader[] = 17101e04c3fSmrgDRI_CONF_BEGIN 17201e04c3fSmrg DRI_CONF_SECTION_INITIALIZATION 17301e04c3fSmrg DRI_CONF_DEVICE_ID_PATH_TAG() 17401e04c3fSmrg DRI_CONF_DRI_DRIVER() 17501e04c3fSmrg DRI_CONF_SECTION_END 17601e04c3fSmrgDRI_CONF_END; 17701e04c3fSmrg 17801e04c3fSmrgstatic char *loader_get_dri_config_driver(int fd) 179af69d88dSmrg{ 18001e04c3fSmrg driOptionCache defaultInitOptions; 18101e04c3fSmrg driOptionCache userInitOptions; 18201e04c3fSmrg char *dri_driver = NULL; 18301e04c3fSmrg char *kernel_driver = loader_get_kernel_driver_name(fd); 18401e04c3fSmrg 18501e04c3fSmrg driParseOptionInfo(&defaultInitOptions, __driConfigOptionsLoader); 18601e04c3fSmrg driParseConfigFiles(&userInitOptions, &defaultInitOptions, 0, 18701e04c3fSmrg "loader", kernel_driver); 18801e04c3fSmrg if (driCheckOption(&userInitOptions, "dri_driver", DRI_STRING)) { 18901e04c3fSmrg char *opt = driQueryOptionstr(&userInitOptions, "dri_driver"); 19001e04c3fSmrg /* not an empty string */ 19101e04c3fSmrg if (*opt) 19201e04c3fSmrg dri_driver = strdup(opt); 193af69d88dSmrg } 19401e04c3fSmrg driDestroyOptionCache(&userInitOptions); 19501e04c3fSmrg driDestroyOptionInfo(&defaultInitOptions); 196af69d88dSmrg 19701e04c3fSmrg free(kernel_driver); 19801e04c3fSmrg return dri_driver; 19901e04c3fSmrg} 200af69d88dSmrg 20101e04c3fSmrgstatic char *loader_get_dri_config_device_id(void) 20201e04c3fSmrg{ 20301e04c3fSmrg driOptionCache defaultInitOptions; 20401e04c3fSmrg driOptionCache userInitOptions; 20501e04c3fSmrg char *prime = NULL; 206af69d88dSmrg 20701e04c3fSmrg driParseOptionInfo(&defaultInitOptions, __driConfigOptionsLoader); 20801e04c3fSmrg driParseConfigFiles(&userInitOptions, &defaultInitOptions, 0, "loader", NULL); 20901e04c3fSmrg if (driCheckOption(&userInitOptions, "device_id", DRI_STRING)) 21001e04c3fSmrg prime = strdup(driQueryOptionstr(&userInitOptions, "device_id")); 21101e04c3fSmrg driDestroyOptionCache(&userInitOptions); 21201e04c3fSmrg driDestroyOptionInfo(&defaultInitOptions); 21301e04c3fSmrg 21401e04c3fSmrg return prime; 215af69d88dSmrg} 21601e04c3fSmrg#endif 217af69d88dSmrg 21801e04c3fSmrgstatic char *drm_construct_id_path_tag(drmDevicePtr device) 219af69d88dSmrg{ 22001e04c3fSmrg char *tag = NULL; 22101e04c3fSmrg 22201e04c3fSmrg if (device->bustype == DRM_BUS_PCI) { 22301e04c3fSmrg if (asprintf(&tag, "pci-%04x_%02x_%02x_%1u", 22401e04c3fSmrg device->businfo.pci->domain, 22501e04c3fSmrg device->businfo.pci->bus, 22601e04c3fSmrg device->businfo.pci->dev, 22701e04c3fSmrg device->businfo.pci->func) < 0) { 22801e04c3fSmrg return NULL; 229af69d88dSmrg } 23001e04c3fSmrg } else if (device->bustype == DRM_BUS_PLATFORM || 23101e04c3fSmrg device->bustype == DRM_BUS_HOST1X) { 23201e04c3fSmrg char *fullname, *name, *address; 23301e04c3fSmrg 23401e04c3fSmrg if (device->bustype == DRM_BUS_PLATFORM) 23501e04c3fSmrg fullname = device->businfo.platform->fullname; 23601e04c3fSmrg else 23701e04c3fSmrg fullname = device->businfo.host1x->fullname; 238af69d88dSmrg 23901e04c3fSmrg name = strrchr(fullname, '/'); 24001e04c3fSmrg if (!name) 24101e04c3fSmrg name = strdup(fullname); 24201e04c3fSmrg else 24301e04c3fSmrg name = strdup(name + 1); 24401e04c3fSmrg 24501e04c3fSmrg address = strchr(name, '@'); 24601e04c3fSmrg if (address) { 24701e04c3fSmrg *address++ = '\0'; 24801e04c3fSmrg 24901e04c3fSmrg if (asprintf(&tag, "platform-%s_%s", address, name) < 0) 25001e04c3fSmrg tag = NULL; 25101e04c3fSmrg } else { 25201e04c3fSmrg if (asprintf(&tag, "platform-%s", name) < 0) 25301e04c3fSmrg tag = NULL; 25401e04c3fSmrg } 25501e04c3fSmrg 25601e04c3fSmrg free(name); 257af69d88dSmrg } 25801e04c3fSmrg return tag; 259af69d88dSmrg} 260af69d88dSmrg 26101e04c3fSmrgstatic bool drm_device_matches_tag(drmDevicePtr device, const char *prime_tag) 262af69d88dSmrg{ 26301e04c3fSmrg char *tag = drm_construct_id_path_tag(device); 26401e04c3fSmrg int ret; 265af69d88dSmrg 26601e04c3fSmrg if (tag == NULL) 26701e04c3fSmrg return false; 268af69d88dSmrg 26901e04c3fSmrg ret = strcmp(tag, prime_tag); 270af69d88dSmrg 27101e04c3fSmrg free(tag); 27201e04c3fSmrg return ret == 0; 273af69d88dSmrg} 274af69d88dSmrg 27501e04c3fSmrgstatic char *drm_get_id_path_tag_for_fd(int fd) 276af69d88dSmrg{ 27701e04c3fSmrg drmDevicePtr device; 27801e04c3fSmrg char *tag; 279af69d88dSmrg 28001e04c3fSmrg if (drmGetDevice2(fd, 0, &device) != 0) 28101e04c3fSmrg return NULL; 28201e04c3fSmrg 28301e04c3fSmrg tag = drm_construct_id_path_tag(device); 28401e04c3fSmrg drmFreeDevice(&device); 28501e04c3fSmrg return tag; 28601e04c3fSmrg} 287af69d88dSmrg 28801e04c3fSmrgint loader_get_user_preferred_fd(int default_fd, bool *different_device) 289af69d88dSmrg{ 29001e04c3fSmrg/* Arbitrary "maximum" value of drm devices. */ 29101e04c3fSmrg#define MAX_DRM_DEVICES 32 292af69d88dSmrg const char *dri_prime = getenv("DRI_PRIME"); 29301e04c3fSmrg char *default_tag, *prime = NULL; 29401e04c3fSmrg drmDevicePtr devices[MAX_DRM_DEVICES]; 29501e04c3fSmrg int i, num_devices, fd; 29601e04c3fSmrg bool found = false; 297af69d88dSmrg 298af69d88dSmrg if (dri_prime) 299af69d88dSmrg prime = strdup(dri_prime); 300af69d88dSmrg#ifdef USE_DRICONF 30101e04c3fSmrg else 30201e04c3fSmrg prime = loader_get_dri_config_device_id(); 303af69d88dSmrg#endif 304af69d88dSmrg 305af69d88dSmrg if (prime == NULL) { 30601e04c3fSmrg *different_device = false; 307af69d88dSmrg return default_fd; 308af69d88dSmrg } 309af69d88dSmrg 31001e04c3fSmrg default_tag = drm_get_id_path_tag_for_fd(default_fd); 31101e04c3fSmrg if (default_tag == NULL) 31201e04c3fSmrg goto err; 313af69d88dSmrg 31401e04c3fSmrg num_devices = drmGetDevices2(0, devices, MAX_DRM_DEVICES); 31501e04c3fSmrg if (num_devices < 0) 31601e04c3fSmrg goto err; 317af69d88dSmrg 318af69d88dSmrg /* two format are supported: 319af69d88dSmrg * "1": choose any other card than the card used by default. 320af69d88dSmrg * id_path_tag: (for example "pci-0000_02_00_0") choose the card 321af69d88dSmrg * with this id_path_tag. 322af69d88dSmrg */ 323af69d88dSmrg if (!strcmp(prime,"1")) { 32401e04c3fSmrg /* Hmm... detection for 2-7 seems to be broken. Oh well ... 32501e04c3fSmrg * Pick the first render device that is not our own. 32601e04c3fSmrg */ 32701e04c3fSmrg for (i = 0; i < num_devices; i++) { 32801e04c3fSmrg if (devices[i]->available_nodes & 1 << DRM_NODE_RENDER && 32901e04c3fSmrg !drm_device_matches_tag(devices[i], default_tag)) { 33001e04c3fSmrg 33101e04c3fSmrg found = true; 33201e04c3fSmrg break; 33301e04c3fSmrg } 33401e04c3fSmrg } 33501e04c3fSmrg } else { 33601e04c3fSmrg for (i = 0; i < num_devices; i++) { 33701e04c3fSmrg if (devices[i]->available_nodes & 1 << DRM_NODE_RENDER && 33801e04c3fSmrg drm_device_matches_tag(devices[i], prime)) { 33901e04c3fSmrg 34001e04c3fSmrg found = true; 34101e04c3fSmrg break; 34201e04c3fSmrg } 34301e04c3fSmrg } 344af69d88dSmrg } 345af69d88dSmrg 34601e04c3fSmrg if (!found) { 34701e04c3fSmrg drmFreeDevices(devices, num_devices); 34801e04c3fSmrg goto err; 349af69d88dSmrg } 350af69d88dSmrg 35101e04c3fSmrg fd = loader_open_device(devices[i]->nodes[DRM_NODE_RENDER]); 35201e04c3fSmrg drmFreeDevices(devices, num_devices); 35301e04c3fSmrg if (fd < 0) 35401e04c3fSmrg goto err; 355af69d88dSmrg 35601e04c3fSmrg close(default_fd); 357af69d88dSmrg 35801e04c3fSmrg *different_device = !!strcmp(default_tag, prime); 359af69d88dSmrg 36001e04c3fSmrg free(default_tag); 36101e04c3fSmrg free(prime); 36201e04c3fSmrg return fd; 363af69d88dSmrg 36401e04c3fSmrg err: 36501e04c3fSmrg *different_device = false; 366af69d88dSmrg 36701e04c3fSmrg free(default_tag); 36801e04c3fSmrg free(prime); 36901e04c3fSmrg return default_fd; 370af69d88dSmrg} 37101e04c3fSmrg#else 37201e04c3fSmrgint 37301e04c3fSmrgloader_open_render_node(const char *name) 374af69d88dSmrg{ 37501e04c3fSmrg return -1; 37601e04c3fSmrg} 377af69d88dSmrg 37801e04c3fSmrgint loader_get_user_preferred_fd(int default_fd, bool *different_device) 37901e04c3fSmrg{ 38001e04c3fSmrg *different_device = false; 38101e04c3fSmrg return default_fd; 382af69d88dSmrg} 383af69d88dSmrg#endif 384af69d88dSmrg 38501e04c3fSmrg#if defined(HAVE_LIBDRM) 386af69d88dSmrg 387af69d88dSmrgstatic int 388af69d88dSmrgdrm_get_pci_id_for_fd(int fd, int *vendor_id, int *chip_id) 389af69d88dSmrg{ 39001e04c3fSmrg drmDevicePtr device; 39101e04c3fSmrg int ret; 39201e04c3fSmrg 39301e04c3fSmrg if (drmGetDevice2(fd, 0, &device) == 0) { 39401e04c3fSmrg if (device->bustype == DRM_BUS_PCI) { 39501e04c3fSmrg *vendor_id = device->deviceinfo.pci->vendor_id; 39601e04c3fSmrg *chip_id = device->deviceinfo.pci->device_id; 39701e04c3fSmrg ret = 1; 398af69d88dSmrg } 39901e04c3fSmrg else { 40001e04c3fSmrg log_(_LOADER_DEBUG, "MESA-LOADER: device is not located on the PCI bus\n"); 40101e04c3fSmrg ret = 0; 402af69d88dSmrg } 40301e04c3fSmrg drmFreeDevice(&device); 404af69d88dSmrg } 40501e04c3fSmrg else { 40601e04c3fSmrg log_(_LOADER_WARNING, "MESA-LOADER: failed to retrieve device information\n"); 40701e04c3fSmrg ret = 0; 408af69d88dSmrg } 409af69d88dSmrg 41001e04c3fSmrg return ret; 411af69d88dSmrg} 412af69d88dSmrg#endif 413af69d88dSmrg 414af69d88dSmrg 415af69d88dSmrgint 416af69d88dSmrgloader_get_pci_id_for_fd(int fd, int *vendor_id, int *chip_id) 417af69d88dSmrg{ 41801e04c3fSmrg#if HAVE_LIBDRM 419af69d88dSmrg if (drm_get_pci_id_for_fd(fd, vendor_id, chip_id)) 420af69d88dSmrg return 1; 421af69d88dSmrg#endif 422af69d88dSmrg return 0; 423af69d88dSmrg} 424af69d88dSmrg 425af69d88dSmrgchar * 426af69d88dSmrgloader_get_device_name_for_fd(int fd) 427af69d88dSmrg{ 428af69d88dSmrg char *result = NULL; 429af69d88dSmrg 43001e04c3fSmrg#if HAVE_LIBDRM 43101e04c3fSmrg result = drmGetDeviceNameFromFd2(fd); 432af69d88dSmrg#endif 43301e04c3fSmrg 434af69d88dSmrg return result; 435af69d88dSmrg} 436af69d88dSmrg 437af69d88dSmrgchar * 43801e04c3fSmrgloader_get_driver_for_fd(int fd) 439af69d88dSmrg{ 440af69d88dSmrg int vendor_id, chip_id, i, j; 441af69d88dSmrg char *driver = NULL; 442af69d88dSmrg 44301e04c3fSmrg /* Allow an environment variable to force choosing a different driver 44401e04c3fSmrg * binary. If that driver binary can't survive on this FD, that's the 44501e04c3fSmrg * user's problem, but this allows vc4 simulator to run on an i965 host, 44601e04c3fSmrg * and may be useful for some touch testing of i915 on an i965 host. 44701e04c3fSmrg */ 448757f638fSmaya if (!issetugid()) { 44901e04c3fSmrg driver = getenv("MESA_LOADER_DRIVER_OVERRIDE"); 45001e04c3fSmrg if (driver) 45101e04c3fSmrg return strdup(driver); 45201e04c3fSmrg } 453af69d88dSmrg 45401e04c3fSmrg#if defined(HAVE_LIBDRM) && defined(USE_DRICONF) 45501e04c3fSmrg driver = loader_get_dri_config_driver(fd); 45601e04c3fSmrg if (driver) 45701e04c3fSmrg return driver; 458af69d88dSmrg#endif 459af69d88dSmrg 46001e04c3fSmrg if (!loader_get_pci_id_for_fd(fd, &vendor_id, &chip_id)) { 46101e04c3fSmrg driver = loader_get_kernel_driver_name(fd); 46201e04c3fSmrg if (driver) 46301e04c3fSmrg log_(_LOADER_INFO, "using driver %s for %d\n", driver, fd); 464af69d88dSmrg return driver; 465af69d88dSmrg } 466af69d88dSmrg 467af69d88dSmrg for (i = 0; driver_map[i].driver; i++) { 468af69d88dSmrg if (vendor_id != driver_map[i].vendor_id) 469af69d88dSmrg continue; 470af69d88dSmrg 471af69d88dSmrg if (driver_map[i].predicate && !driver_map[i].predicate(fd)) 472af69d88dSmrg continue; 473af69d88dSmrg 474af69d88dSmrg if (driver_map[i].num_chips_ids == -1) { 475af69d88dSmrg driver = strdup(driver_map[i].driver); 476af69d88dSmrg goto out; 477af69d88dSmrg } 478af69d88dSmrg 479af69d88dSmrg for (j = 0; j < driver_map[i].num_chips_ids; j++) 480af69d88dSmrg if (driver_map[i].chip_ids[j] == chip_id) { 481af69d88dSmrg driver = strdup(driver_map[i].driver); 482af69d88dSmrg goto out; 483af69d88dSmrg } 484af69d88dSmrg } 485af69d88dSmrg 486af69d88dSmrgout: 487af69d88dSmrg log_(driver ? _LOADER_DEBUG : _LOADER_WARNING, 488af69d88dSmrg "pci id for fd %d: %04x:%04x, driver %s\n", 489af69d88dSmrg fd, vendor_id, chip_id, driver); 490af69d88dSmrg return driver; 491af69d88dSmrg} 492af69d88dSmrg 493af69d88dSmrgvoid 4949f464c52Smayaloader_set_logger(loader_logger *logger) 495af69d88dSmrg{ 496af69d88dSmrg log_ = logger; 497af69d88dSmrg} 49801e04c3fSmrg 49901e04c3fSmrgchar * 50001e04c3fSmrgloader_get_extensions_name(const char *driver_name) 50101e04c3fSmrg{ 50201e04c3fSmrg char *name = NULL; 50301e04c3fSmrg 50401e04c3fSmrg if (asprintf(&name, "%s_%s", __DRI_DRIVER_GET_EXTENSIONS, driver_name) < 0) 50501e04c3fSmrg return NULL; 50601e04c3fSmrg 50701e04c3fSmrg const size_t len = strlen(name); 50801e04c3fSmrg for (size_t i = 0; i < len; i++) { 50901e04c3fSmrg if (name[i] == '-') 51001e04c3fSmrg name[i] = '_'; 51101e04c3fSmrg } 51201e04c3fSmrg 51301e04c3fSmrg return name; 51401e04c3fSmrg} 5159f464c52Smaya 5169f464c52Smaya/** 5179f464c52Smaya * Opens a DRI driver using its driver name, returning the __DRIextension 5189f464c52Smaya * entrypoints. 5199f464c52Smaya * 5209f464c52Smaya * \param driverName - a name like "i965", "radeon", "nouveau", etc. 5219f464c52Smaya * \param out_driver - Address where the dlopen() return value will be stored. 5229f464c52Smaya * \param search_path_vars - NULL-terminated list of env vars that can be used 5239f464c52Smaya * to override the DEFAULT_DRIVER_DIR search path. 5249f464c52Smaya */ 5259f464c52Smayaconst struct __DRIextensionRec ** 5269f464c52Smayaloader_open_driver(const char *driver_name, 5279f464c52Smaya void **out_driver_handle, 5289f464c52Smaya const char **search_path_vars) 5299f464c52Smaya{ 5309f464c52Smaya char path[PATH_MAX], *search_paths, *next, *end; 5319f464c52Smaya char *get_extensions_name; 5329f464c52Smaya const struct __DRIextensionRec **extensions = NULL; 5339f464c52Smaya const struct __DRIextensionRec **(*get_extensions)(void); 5349f464c52Smaya 5359f464c52Smaya search_paths = NULL; 536757f638fSmaya if (!issetugid() && search_path_vars) { 5379f464c52Smaya for (int i = 0; search_path_vars[i] != NULL; i++) { 5389f464c52Smaya search_paths = getenv(search_path_vars[i]); 5399f464c52Smaya if (search_paths) 5409f464c52Smaya break; 5419f464c52Smaya } 5429f464c52Smaya } 5439f464c52Smaya if (search_paths == NULL) 5449f464c52Smaya search_paths = DEFAULT_DRIVER_DIR; 5459f464c52Smaya 5469f464c52Smaya void *driver = NULL; 5479f464c52Smaya end = search_paths + strlen(search_paths); 5489f464c52Smaya for (char *p = search_paths; p < end; p = next + 1) { 5499f464c52Smaya int len; 5509f464c52Smaya next = strchr(p, ':'); 5519f464c52Smaya if (next == NULL) 5529f464c52Smaya next = end; 5539f464c52Smaya 5549f464c52Smaya len = next - p; 5559f464c52Smaya#if GLX_USE_TLS 5569f464c52Smaya snprintf(path, sizeof(path), "%.*s/tls/%s_dri.so", len, p, driver_name); 5579f464c52Smaya driver = dlopen(path, RTLD_NOW | RTLD_GLOBAL); 5589f464c52Smaya#endif 5599f464c52Smaya if (driver == NULL) { 5609f464c52Smaya snprintf(path, sizeof(path), "%.*s/%s_dri.so", len, p, driver_name); 5619f464c52Smaya driver = dlopen(path, RTLD_NOW | RTLD_GLOBAL); 5629f464c52Smaya if (driver == NULL) 5639f464c52Smaya log_(_LOADER_DEBUG, "MESA-LOADER: failed to open %s: %s\n", 5649f464c52Smaya path, dlerror()); 5659f464c52Smaya } 5669f464c52Smaya /* not need continue to loop all paths once the driver is found */ 5679f464c52Smaya if (driver != NULL) 5689f464c52Smaya break; 5699f464c52Smaya } 5709f464c52Smaya 5719f464c52Smaya if (driver == NULL) { 5729f464c52Smaya log_(_LOADER_WARNING, "MESA-LOADER: failed to open %s (search paths %s)\n", 5739f464c52Smaya driver_name, search_paths); 5749f464c52Smaya *out_driver_handle = NULL; 5759f464c52Smaya return NULL; 5769f464c52Smaya } 5779f464c52Smaya 5789f464c52Smaya log_(_LOADER_DEBUG, "MESA-LOADER: dlopen(%s)\n", path); 5799f464c52Smaya 5809f464c52Smaya get_extensions_name = loader_get_extensions_name(driver_name); 5819f464c52Smaya if (get_extensions_name) { 5829f464c52Smaya get_extensions = dlsym(driver, get_extensions_name); 5839f464c52Smaya if (get_extensions) { 5849f464c52Smaya extensions = get_extensions(); 5859f464c52Smaya } else { 5869f464c52Smaya log_(_LOADER_DEBUG, "MESA-LOADER: driver does not expose %s(): %s\n", 5879f464c52Smaya get_extensions_name, dlerror()); 5889f464c52Smaya } 5899f464c52Smaya free(get_extensions_name); 5909f464c52Smaya } 5919f464c52Smaya 5929f464c52Smaya if (!extensions) 5939f464c52Smaya extensions = dlsym(driver, __DRI_DRIVER_EXTENSIONS); 5949f464c52Smaya if (extensions == NULL) { 5959f464c52Smaya log_(_LOADER_WARNING, 5969f464c52Smaya "MESA-LOADER: driver exports no extensions (%s)\n", dlerror()); 5979f464c52Smaya dlclose(driver); 5989f464c52Smaya } 5999f464c52Smaya 6009f464c52Smaya *out_driver_handle = driver; 6019f464c52Smaya return extensions; 6029f464c52Smaya} 603