1848b8605Smrg/* 2848b8605Smrg * Copyright (C) 2013 Rob Clark <robclark@freedesktop.org> 3b8e80941Smrg * Copyright (C) 2014-2016 Emil Velikov <emil.l.velikov@gmail.com> 4b8e80941Smrg * Copyright (C) 2016 Intel Corporation 5848b8605Smrg * 6848b8605Smrg * Permission is hereby granted, free of charge, to any person obtaining a 7848b8605Smrg * copy of this software and associated documentation files (the "Software"), 8848b8605Smrg * to deal in the Software without restriction, including without limitation 9848b8605Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10848b8605Smrg * and/or sell copies of the Software, and to permit persons to whom the 11848b8605Smrg * Software is furnished to do so, subject to the following conditions: 12848b8605Smrg * 13848b8605Smrg * The above copyright notice and this permission notice (including the next 14848b8605Smrg * paragraph) shall be included in all copies or substantial portions of the 15848b8605Smrg * Software. 16848b8605Smrg * 17848b8605Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18848b8605Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19848b8605Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20848b8605Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21848b8605Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22848b8605Smrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23848b8605Smrg * SOFTWARE. 24848b8605Smrg * 25848b8605Smrg * Authors: 26848b8605Smrg * Rob Clark <robclark@freedesktop.org> 27848b8605Smrg */ 28848b8605Smrg 29b8e80941Smrg#include <dlfcn.h> 30b8e80941Smrg#include <errno.h> 31b8e80941Smrg#include <fcntl.h> 32b8e80941Smrg#include <sys/stat.h> 33848b8605Smrg#include <stdarg.h> 34848b8605Smrg#include <stdio.h> 35b8e80941Smrg#include <stdbool.h> 36848b8605Smrg#include <string.h> 37848b8605Smrg#include <unistd.h> 38848b8605Smrg#include <stdlib.h> 39b8e80941Smrg#include <sys/param.h> 40b8e80941Smrg#ifdef MAJOR_IN_MKDEV 41b8e80941Smrg#include <sys/mkdev.h> 42848b8605Smrg#endif 43b8e80941Smrg#ifdef MAJOR_IN_SYSMACROS 44b8e80941Smrg#include <sys/sysmacros.h> 45848b8605Smrg#endif 46b8e80941Smrg#include <GL/gl.h> 47b8e80941Smrg#include <GL/internal/dri_interface.h> 48848b8605Smrg#include "loader.h" 49848b8605Smrg 50b8e80941Smrg#ifdef HAVE_LIBDRM 51848b8605Smrg#include <xf86drm.h> 52b8e80941Smrg#ifdef USE_DRICONF 53b8e80941Smrg#include "util/xmlconfig.h" 54b8e80941Smrg#include "util/xmlpool.h" 55b8e80941Smrg#endif 56848b8605Smrg#endif 57848b8605Smrg 58848b8605Smrg#define __IS_LOADER 59848b8605Smrg#include "pci_id_driver_map.h" 60848b8605Smrg 61848b8605Smrgstatic void default_logger(int level, const char *fmt, ...) 62848b8605Smrg{ 63848b8605Smrg if (level <= _LOADER_WARNING) { 64848b8605Smrg va_list args; 65848b8605Smrg va_start(args, fmt); 66848b8605Smrg vfprintf(stderr, fmt, args); 67848b8605Smrg va_end(args); 68848b8605Smrg } 69848b8605Smrg} 70848b8605Smrg 71b8e80941Smrgstatic loader_logger *log_ = default_logger; 72848b8605Smrg 73b8e80941Smrgint 74b8e80941Smrgloader_open_device(const char *device_name) 75848b8605Smrg{ 76b8e80941Smrg int fd; 77b8e80941Smrg#ifdef O_CLOEXEC 78b8e80941Smrg fd = open(device_name, O_RDWR | O_CLOEXEC); 79b8e80941Smrg if (fd == -1 && errno == EINVAL) 80b8e80941Smrg#endif 81b8e80941Smrg { 82b8e80941Smrg fd = open(device_name, O_RDWR); 83b8e80941Smrg if (fd != -1) 84b8e80941Smrg fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC); 85848b8605Smrg } 86b8e80941Smrg return fd; 87848b8605Smrg} 88848b8605Smrg 89b8e80941Smrgstatic char *loader_get_kernel_driver_name(int fd) 90848b8605Smrg{ 91b8e80941Smrg#if HAVE_LIBDRM 92b8e80941Smrg char *driver; 93b8e80941Smrg drmVersionPtr version = drmGetVersion(fd); 94848b8605Smrg 95b8e80941Smrg if (!version) { 96b8e80941Smrg log_(_LOADER_WARNING, "failed to get driver name for fd %d\n", fd); 97b8e80941Smrg return NULL; 98b8e80941Smrg } 99848b8605Smrg 100b8e80941Smrg driver = strndup(version->name, version->name_len); 101848b8605Smrg 102b8e80941Smrg drmFreeVersion(version); 103b8e80941Smrg return driver; 104b8e80941Smrg#else 105b8e80941Smrg return NULL; 106b8e80941Smrg#endif 107b8e80941Smrg} 108b8e80941Smrg 109b8e80941Smrg#if defined(HAVE_LIBDRM) 110b8e80941Smrgint 111b8e80941Smrgloader_open_render_node(const char *name) 112848b8605Smrg{ 113b8e80941Smrg drmDevicePtr *devices, device; 114b8e80941Smrg int err, render = -ENOENT, fd; 115b8e80941Smrg unsigned int num, i; 116848b8605Smrg 117b8e80941Smrg err = drmGetDevices2(0, NULL, 0); 118b8e80941Smrg if (err < 0) 119b8e80941Smrg return err; 120848b8605Smrg 121b8e80941Smrg num = err; 122b8e80941Smrg 123b8e80941Smrg devices = calloc(num, sizeof(*devices)); 124b8e80941Smrg if (!devices) 125b8e80941Smrg return -ENOMEM; 126b8e80941Smrg 127b8e80941Smrg err = drmGetDevices2(0, devices, num); 128b8e80941Smrg if (err < 0) { 129b8e80941Smrg render = err; 130b8e80941Smrg goto free; 131848b8605Smrg } 132848b8605Smrg 133b8e80941Smrg for (i = 0; i < num; i++) { 134b8e80941Smrg device = devices[i]; 135b8e80941Smrg 136b8e80941Smrg if ((device->available_nodes & (1 << DRM_NODE_RENDER)) && 137b8e80941Smrg (device->bustype == DRM_BUS_PLATFORM)) { 138b8e80941Smrg drmVersionPtr version; 139b8e80941Smrg 140b8e80941Smrg fd = loader_open_device(device->nodes[DRM_NODE_RENDER]); 141b8e80941Smrg if (fd < 0) 142b8e80941Smrg continue; 143b8e80941Smrg 144b8e80941Smrg version = drmGetVersion(fd); 145b8e80941Smrg if (!version) { 146b8e80941Smrg close(fd); 147b8e80941Smrg continue; 148b8e80941Smrg } 149b8e80941Smrg 150b8e80941Smrg if (strcmp(version->name, name) != 0) { 151b8e80941Smrg drmFreeVersion(version); 152b8e80941Smrg close(fd); 153b8e80941Smrg continue; 154b8e80941Smrg } 155b8e80941Smrg 156b8e80941Smrg drmFreeVersion(version); 157b8e80941Smrg render = fd; 158b8e80941Smrg break; 159b8e80941Smrg } 160848b8605Smrg } 161848b8605Smrg 162b8e80941Smrg drmFreeDevices(devices, num); 163b8e80941Smrg 164b8e80941Smrgfree: 165b8e80941Smrg free(devices); 166b8e80941Smrg return render; 167848b8605Smrg} 168848b8605Smrg 169b8e80941Smrg#ifdef USE_DRICONF 170b8e80941Smrgstatic const char __driConfigOptionsLoader[] = 171b8e80941SmrgDRI_CONF_BEGIN 172b8e80941Smrg DRI_CONF_SECTION_INITIALIZATION 173b8e80941Smrg DRI_CONF_DEVICE_ID_PATH_TAG() 174b8e80941Smrg DRI_CONF_DRI_DRIVER() 175b8e80941Smrg DRI_CONF_SECTION_END 176b8e80941SmrgDRI_CONF_END; 177b8e80941Smrg 178b8e80941Smrgstatic char *loader_get_dri_config_driver(int fd) 179848b8605Smrg{ 180b8e80941Smrg driOptionCache defaultInitOptions; 181b8e80941Smrg driOptionCache userInitOptions; 182b8e80941Smrg char *dri_driver = NULL; 183b8e80941Smrg char *kernel_driver = loader_get_kernel_driver_name(fd); 184b8e80941Smrg 185b8e80941Smrg driParseOptionInfo(&defaultInitOptions, __driConfigOptionsLoader); 186b8e80941Smrg driParseConfigFiles(&userInitOptions, &defaultInitOptions, 0, 187b8e80941Smrg "loader", kernel_driver); 188b8e80941Smrg if (driCheckOption(&userInitOptions, "dri_driver", DRI_STRING)) { 189b8e80941Smrg char *opt = driQueryOptionstr(&userInitOptions, "dri_driver"); 190b8e80941Smrg /* not an empty string */ 191b8e80941Smrg if (*opt) 192b8e80941Smrg dri_driver = strdup(opt); 193848b8605Smrg } 194b8e80941Smrg driDestroyOptionCache(&userInitOptions); 195b8e80941Smrg driDestroyOptionInfo(&defaultInitOptions); 196848b8605Smrg 197b8e80941Smrg free(kernel_driver); 198b8e80941Smrg return dri_driver; 199b8e80941Smrg} 200848b8605Smrg 201b8e80941Smrgstatic char *loader_get_dri_config_device_id(void) 202b8e80941Smrg{ 203b8e80941Smrg driOptionCache defaultInitOptions; 204b8e80941Smrg driOptionCache userInitOptions; 205b8e80941Smrg char *prime = NULL; 206848b8605Smrg 207b8e80941Smrg driParseOptionInfo(&defaultInitOptions, __driConfigOptionsLoader); 208b8e80941Smrg driParseConfigFiles(&userInitOptions, &defaultInitOptions, 0, "loader", NULL); 209b8e80941Smrg if (driCheckOption(&userInitOptions, "device_id", DRI_STRING)) 210b8e80941Smrg prime = strdup(driQueryOptionstr(&userInitOptions, "device_id")); 211b8e80941Smrg driDestroyOptionCache(&userInitOptions); 212b8e80941Smrg driDestroyOptionInfo(&defaultInitOptions); 213b8e80941Smrg 214b8e80941Smrg return prime; 215848b8605Smrg} 216b8e80941Smrg#endif 217848b8605Smrg 218b8e80941Smrgstatic char *drm_construct_id_path_tag(drmDevicePtr device) 219848b8605Smrg{ 220b8e80941Smrg char *tag = NULL; 221b8e80941Smrg 222b8e80941Smrg if (device->bustype == DRM_BUS_PCI) { 223b8e80941Smrg if (asprintf(&tag, "pci-%04x_%02x_%02x_%1u", 224b8e80941Smrg device->businfo.pci->domain, 225b8e80941Smrg device->businfo.pci->bus, 226b8e80941Smrg device->businfo.pci->dev, 227b8e80941Smrg device->businfo.pci->func) < 0) { 228b8e80941Smrg return NULL; 229848b8605Smrg } 230b8e80941Smrg } else if (device->bustype == DRM_BUS_PLATFORM || 231b8e80941Smrg device->bustype == DRM_BUS_HOST1X) { 232b8e80941Smrg char *fullname, *name, *address; 233b8e80941Smrg 234b8e80941Smrg if (device->bustype == DRM_BUS_PLATFORM) 235b8e80941Smrg fullname = device->businfo.platform->fullname; 236b8e80941Smrg else 237b8e80941Smrg fullname = device->businfo.host1x->fullname; 238b8e80941Smrg 239b8e80941Smrg name = strrchr(fullname, '/'); 240b8e80941Smrg if (!name) 241b8e80941Smrg name = strdup(fullname); 242b8e80941Smrg else 243b8e80941Smrg name = strdup(name + 1); 244b8e80941Smrg 245b8e80941Smrg address = strchr(name, '@'); 246b8e80941Smrg if (address) { 247b8e80941Smrg *address++ = '\0'; 248848b8605Smrg 249b8e80941Smrg if (asprintf(&tag, "platform-%s_%s", address, name) < 0) 250b8e80941Smrg tag = NULL; 251b8e80941Smrg } else { 252b8e80941Smrg if (asprintf(&tag, "platform-%s", name) < 0) 253b8e80941Smrg tag = NULL; 254b8e80941Smrg } 255b8e80941Smrg 256b8e80941Smrg free(name); 257848b8605Smrg } 258b8e80941Smrg return tag; 259848b8605Smrg} 260848b8605Smrg 261b8e80941Smrgstatic bool drm_device_matches_tag(drmDevicePtr device, const char *prime_tag) 262848b8605Smrg{ 263b8e80941Smrg char *tag = drm_construct_id_path_tag(device); 264b8e80941Smrg int ret; 265848b8605Smrg 266b8e80941Smrg if (tag == NULL) 267b8e80941Smrg return false; 268848b8605Smrg 269b8e80941Smrg ret = strcmp(tag, prime_tag); 270848b8605Smrg 271b8e80941Smrg free(tag); 272b8e80941Smrg return ret == 0; 273848b8605Smrg} 274848b8605Smrg 275b8e80941Smrgstatic char *drm_get_id_path_tag_for_fd(int fd) 276848b8605Smrg{ 277b8e80941Smrg drmDevicePtr device; 278b8e80941Smrg char *tag; 279848b8605Smrg 280b8e80941Smrg if (drmGetDevice2(fd, 0, &device) != 0) 281b8e80941Smrg return NULL; 282b8e80941Smrg 283b8e80941Smrg tag = drm_construct_id_path_tag(device); 284b8e80941Smrg drmFreeDevice(&device); 285b8e80941Smrg return tag; 286b8e80941Smrg} 287848b8605Smrg 288b8e80941Smrgint loader_get_user_preferred_fd(int default_fd, bool *different_device) 289848b8605Smrg{ 290b8e80941Smrg/* Arbitrary "maximum" value of drm devices. */ 291b8e80941Smrg#define MAX_DRM_DEVICES 32 292848b8605Smrg const char *dri_prime = getenv("DRI_PRIME"); 293b8e80941Smrg char *default_tag, *prime = NULL; 294b8e80941Smrg drmDevicePtr devices[MAX_DRM_DEVICES]; 295b8e80941Smrg int i, num_devices, fd; 296b8e80941Smrg bool found = false; 297848b8605Smrg 298848b8605Smrg if (dri_prime) 299848b8605Smrg prime = strdup(dri_prime); 300848b8605Smrg#ifdef USE_DRICONF 301b8e80941Smrg else 302b8e80941Smrg prime = loader_get_dri_config_device_id(); 303848b8605Smrg#endif 304848b8605Smrg 305848b8605Smrg if (prime == NULL) { 306b8e80941Smrg *different_device = false; 307848b8605Smrg return default_fd; 308848b8605Smrg } 309848b8605Smrg 310b8e80941Smrg default_tag = drm_get_id_path_tag_for_fd(default_fd); 311b8e80941Smrg if (default_tag == NULL) 312b8e80941Smrg goto err; 313848b8605Smrg 314b8e80941Smrg num_devices = drmGetDevices2(0, devices, MAX_DRM_DEVICES); 315b8e80941Smrg if (num_devices < 0) 316b8e80941Smrg goto err; 317848b8605Smrg 318848b8605Smrg /* two format are supported: 319848b8605Smrg * "1": choose any other card than the card used by default. 320848b8605Smrg * id_path_tag: (for example "pci-0000_02_00_0") choose the card 321848b8605Smrg * with this id_path_tag. 322848b8605Smrg */ 323848b8605Smrg if (!strcmp(prime,"1")) { 324b8e80941Smrg /* Hmm... detection for 2-7 seems to be broken. Oh well ... 325b8e80941Smrg * Pick the first render device that is not our own. 326b8e80941Smrg */ 327b8e80941Smrg for (i = 0; i < num_devices; i++) { 328b8e80941Smrg if (devices[i]->available_nodes & 1 << DRM_NODE_RENDER && 329b8e80941Smrg !drm_device_matches_tag(devices[i], default_tag)) { 330b8e80941Smrg 331b8e80941Smrg found = true; 332b8e80941Smrg break; 333b8e80941Smrg } 334b8e80941Smrg } 335b8e80941Smrg } else { 336b8e80941Smrg for (i = 0; i < num_devices; i++) { 337b8e80941Smrg if (devices[i]->available_nodes & 1 << DRM_NODE_RENDER && 338b8e80941Smrg drm_device_matches_tag(devices[i], prime)) { 339b8e80941Smrg 340b8e80941Smrg found = true; 341b8e80941Smrg break; 342b8e80941Smrg } 343b8e80941Smrg } 344848b8605Smrg } 345848b8605Smrg 346b8e80941Smrg if (!found) { 347b8e80941Smrg drmFreeDevices(devices, num_devices); 348b8e80941Smrg goto err; 349848b8605Smrg } 350848b8605Smrg 351b8e80941Smrg fd = loader_open_device(devices[i]->nodes[DRM_NODE_RENDER]); 352b8e80941Smrg drmFreeDevices(devices, num_devices); 353b8e80941Smrg if (fd < 0) 354b8e80941Smrg goto err; 355848b8605Smrg 356b8e80941Smrg close(default_fd); 357848b8605Smrg 358b8e80941Smrg *different_device = !!strcmp(default_tag, prime); 359848b8605Smrg 360b8e80941Smrg free(default_tag); 361b8e80941Smrg free(prime); 362b8e80941Smrg return fd; 363848b8605Smrg 364b8e80941Smrg err: 365b8e80941Smrg *different_device = false; 366848b8605Smrg 367b8e80941Smrg free(default_tag); 368b8e80941Smrg free(prime); 369b8e80941Smrg return default_fd; 370848b8605Smrg} 371b8e80941Smrg#else 372b8e80941Smrgint 373b8e80941Smrgloader_open_render_node(const char *name) 374848b8605Smrg{ 375b8e80941Smrg return -1; 376b8e80941Smrg} 377848b8605Smrg 378b8e80941Smrgint loader_get_user_preferred_fd(int default_fd, bool *different_device) 379b8e80941Smrg{ 380b8e80941Smrg *different_device = false; 381b8e80941Smrg return default_fd; 382848b8605Smrg} 383848b8605Smrg#endif 384848b8605Smrg 385b8e80941Smrg#if defined(HAVE_LIBDRM) 386848b8605Smrg 387848b8605Smrgstatic int 388848b8605Smrgdrm_get_pci_id_for_fd(int fd, int *vendor_id, int *chip_id) 389848b8605Smrg{ 390b8e80941Smrg drmDevicePtr device; 391b8e80941Smrg int ret; 392b8e80941Smrg 393b8e80941Smrg if (drmGetDevice2(fd, 0, &device) == 0) { 394b8e80941Smrg if (device->bustype == DRM_BUS_PCI) { 395b8e80941Smrg *vendor_id = device->deviceinfo.pci->vendor_id; 396b8e80941Smrg *chip_id = device->deviceinfo.pci->device_id; 397b8e80941Smrg ret = 1; 398848b8605Smrg } 399b8e80941Smrg else { 400b8e80941Smrg log_(_LOADER_DEBUG, "MESA-LOADER: device is not located on the PCI bus\n"); 401b8e80941Smrg ret = 0; 402848b8605Smrg } 403b8e80941Smrg drmFreeDevice(&device); 404848b8605Smrg } 405b8e80941Smrg else { 406b8e80941Smrg log_(_LOADER_WARNING, "MESA-LOADER: failed to retrieve device information\n"); 407b8e80941Smrg ret = 0; 408848b8605Smrg } 409848b8605Smrg 410b8e80941Smrg return ret; 411848b8605Smrg} 412848b8605Smrg#endif 413848b8605Smrg 414848b8605Smrg 415848b8605Smrgint 416848b8605Smrgloader_get_pci_id_for_fd(int fd, int *vendor_id, int *chip_id) 417848b8605Smrg{ 418b8e80941Smrg#if HAVE_LIBDRM 419848b8605Smrg if (drm_get_pci_id_for_fd(fd, vendor_id, chip_id)) 420848b8605Smrg return 1; 421848b8605Smrg#endif 422848b8605Smrg return 0; 423848b8605Smrg} 424848b8605Smrg 425848b8605Smrgchar * 426848b8605Smrgloader_get_device_name_for_fd(int fd) 427848b8605Smrg{ 428848b8605Smrg char *result = NULL; 429848b8605Smrg 430b8e80941Smrg#if HAVE_LIBDRM 431b8e80941Smrg result = drmGetDeviceNameFromFd2(fd); 432848b8605Smrg#endif 433b8e80941Smrg 434848b8605Smrg return result; 435848b8605Smrg} 436848b8605Smrg 437848b8605Smrgchar * 438b8e80941Smrgloader_get_driver_for_fd(int fd) 439848b8605Smrg{ 440848b8605Smrg int vendor_id, chip_id, i, j; 441848b8605Smrg char *driver = NULL; 442848b8605Smrg 443b8e80941Smrg /* Allow an environment variable to force choosing a different driver 444b8e80941Smrg * binary. If that driver binary can't survive on this FD, that's the 445b8e80941Smrg * user's problem, but this allows vc4 simulator to run on an i965 host, 446b8e80941Smrg * and may be useful for some touch testing of i915 on an i965 host. 447b8e80941Smrg */ 448b8e80941Smrg if (!issetugid()) { 449b8e80941Smrg driver = getenv("MESA_LOADER_DRIVER_OVERRIDE"); 450b8e80941Smrg if (driver) 451b8e80941Smrg return strdup(driver); 452b8e80941Smrg } 453848b8605Smrg 454b8e80941Smrg#if defined(HAVE_LIBDRM) && defined(USE_DRICONF) 455b8e80941Smrg driver = loader_get_dri_config_driver(fd); 456b8e80941Smrg if (driver) 457b8e80941Smrg return driver; 458848b8605Smrg#endif 459848b8605Smrg 460b8e80941Smrg if (!loader_get_pci_id_for_fd(fd, &vendor_id, &chip_id)) { 461b8e80941Smrg driver = loader_get_kernel_driver_name(fd); 462b8e80941Smrg if (driver) 463b8e80941Smrg log_(_LOADER_INFO, "using driver %s for %d\n", driver, fd); 464848b8605Smrg return driver; 465848b8605Smrg } 466848b8605Smrg 467848b8605Smrg for (i = 0; driver_map[i].driver; i++) { 468848b8605Smrg if (vendor_id != driver_map[i].vendor_id) 469848b8605Smrg continue; 470848b8605Smrg 471848b8605Smrg if (driver_map[i].predicate && !driver_map[i].predicate(fd)) 472848b8605Smrg continue; 473848b8605Smrg 474848b8605Smrg if (driver_map[i].num_chips_ids == -1) { 475848b8605Smrg driver = strdup(driver_map[i].driver); 476848b8605Smrg goto out; 477848b8605Smrg } 478848b8605Smrg 479848b8605Smrg for (j = 0; j < driver_map[i].num_chips_ids; j++) 480848b8605Smrg if (driver_map[i].chip_ids[j] == chip_id) { 481848b8605Smrg driver = strdup(driver_map[i].driver); 482848b8605Smrg goto out; 483848b8605Smrg } 484848b8605Smrg } 485848b8605Smrg 486848b8605Smrgout: 487848b8605Smrg log_(driver ? _LOADER_DEBUG : _LOADER_WARNING, 488848b8605Smrg "pci id for fd %d: %04x:%04x, driver %s\n", 489848b8605Smrg fd, vendor_id, chip_id, driver); 490848b8605Smrg return driver; 491848b8605Smrg} 492848b8605Smrg 493848b8605Smrgvoid 494b8e80941Smrgloader_set_logger(loader_logger *logger) 495848b8605Smrg{ 496848b8605Smrg log_ = logger; 497848b8605Smrg} 498b8e80941Smrg 499b8e80941Smrgchar * 500b8e80941Smrgloader_get_extensions_name(const char *driver_name) 501b8e80941Smrg{ 502b8e80941Smrg char *name = NULL; 503b8e80941Smrg 504b8e80941Smrg if (asprintf(&name, "%s_%s", __DRI_DRIVER_GET_EXTENSIONS, driver_name) < 0) 505b8e80941Smrg return NULL; 506b8e80941Smrg 507b8e80941Smrg const size_t len = strlen(name); 508b8e80941Smrg for (size_t i = 0; i < len; i++) { 509b8e80941Smrg if (name[i] == '-') 510b8e80941Smrg name[i] = '_'; 511b8e80941Smrg } 512b8e80941Smrg 513b8e80941Smrg return name; 514b8e80941Smrg} 515b8e80941Smrg 516b8e80941Smrg/** 517b8e80941Smrg * Opens a DRI driver using its driver name, returning the __DRIextension 518b8e80941Smrg * entrypoints. 519b8e80941Smrg * 520b8e80941Smrg * \param driverName - a name like "i965", "radeon", "nouveau", etc. 521b8e80941Smrg * \param out_driver - Address where the dlopen() return value will be stored. 522b8e80941Smrg * \param search_path_vars - NULL-terminated list of env vars that can be used 523b8e80941Smrg * to override the DEFAULT_DRIVER_DIR search path. 524b8e80941Smrg */ 525b8e80941Smrgconst struct __DRIextensionRec ** 526b8e80941Smrgloader_open_driver(const char *driver_name, 527b8e80941Smrg void **out_driver_handle, 528b8e80941Smrg const char **search_path_vars) 529b8e80941Smrg{ 530b8e80941Smrg char path[PATH_MAX], *search_paths, *next, *end; 531b8e80941Smrg char *get_extensions_name; 532b8e80941Smrg const struct __DRIextensionRec **extensions = NULL; 533b8e80941Smrg const struct __DRIextensionRec **(*get_extensions)(void); 534b8e80941Smrg 535b8e80941Smrg search_paths = NULL; 536b8e80941Smrg if (!issetugid() && search_path_vars) { 537b8e80941Smrg for (int i = 0; search_path_vars[i] != NULL; i++) { 538b8e80941Smrg search_paths = getenv(search_path_vars[i]); 539b8e80941Smrg if (search_paths) 540b8e80941Smrg break; 541b8e80941Smrg } 542b8e80941Smrg } 543b8e80941Smrg if (search_paths == NULL) 544b8e80941Smrg search_paths = DEFAULT_DRIVER_DIR; 545b8e80941Smrg 546b8e80941Smrg void *driver = NULL; 547b8e80941Smrg end = search_paths + strlen(search_paths); 548b8e80941Smrg for (char *p = search_paths; p < end; p = next + 1) { 549b8e80941Smrg int len; 550b8e80941Smrg next = strchr(p, ':'); 551b8e80941Smrg if (next == NULL) 552b8e80941Smrg next = end; 553b8e80941Smrg 554b8e80941Smrg len = next - p; 555b8e80941Smrg#if GLX_USE_TLS 556b8e80941Smrg snprintf(path, sizeof(path), "%.*s/tls/%s_dri.so", len, p, driver_name); 557b8e80941Smrg driver = dlopen(path, RTLD_NOW | RTLD_GLOBAL); 558b8e80941Smrg#endif 559b8e80941Smrg if (driver == NULL) { 560b8e80941Smrg snprintf(path, sizeof(path), "%.*s/%s_dri.so", len, p, driver_name); 561b8e80941Smrg driver = dlopen(path, RTLD_NOW | RTLD_GLOBAL); 562b8e80941Smrg if (driver == NULL) 563b8e80941Smrg log_(_LOADER_DEBUG, "MESA-LOADER: failed to open %s: %s\n", 564b8e80941Smrg path, dlerror()); 565b8e80941Smrg } 566b8e80941Smrg /* not need continue to loop all paths once the driver is found */ 567b8e80941Smrg if (driver != NULL) 568b8e80941Smrg break; 569b8e80941Smrg } 570b8e80941Smrg 571b8e80941Smrg if (driver == NULL) { 572b8e80941Smrg log_(_LOADER_WARNING, "MESA-LOADER: failed to open %s (search paths %s)\n", 573b8e80941Smrg driver_name, search_paths); 574b8e80941Smrg *out_driver_handle = NULL; 575b8e80941Smrg return NULL; 576b8e80941Smrg } 577b8e80941Smrg 578b8e80941Smrg log_(_LOADER_DEBUG, "MESA-LOADER: dlopen(%s)\n", path); 579b8e80941Smrg 580b8e80941Smrg get_extensions_name = loader_get_extensions_name(driver_name); 581b8e80941Smrg if (get_extensions_name) { 582b8e80941Smrg get_extensions = dlsym(driver, get_extensions_name); 583b8e80941Smrg if (get_extensions) { 584b8e80941Smrg extensions = get_extensions(); 585b8e80941Smrg } else { 586b8e80941Smrg log_(_LOADER_DEBUG, "MESA-LOADER: driver does not expose %s(): %s\n", 587b8e80941Smrg get_extensions_name, dlerror()); 588b8e80941Smrg } 589b8e80941Smrg free(get_extensions_name); 590b8e80941Smrg } 591b8e80941Smrg 592b8e80941Smrg if (!extensions) 593b8e80941Smrg extensions = dlsym(driver, __DRI_DRIVER_EXTENSIONS); 594b8e80941Smrg if (extensions == NULL) { 595b8e80941Smrg log_(_LOADER_WARNING, 596b8e80941Smrg "MESA-LOADER: driver exports no extensions (%s)\n", dlerror()); 597b8e80941Smrg dlclose(driver); 598b8e80941Smrg } 599b8e80941Smrg 600b8e80941Smrg *out_driver_handle = driver; 601b8e80941Smrg return extensions; 602b8e80941Smrg} 603