13464ebd5Sriastradh/* 23464ebd5Sriastradh * Copyright © 2011 Intel Corporation 37ec681f3Smrg * Copyright © 2021 NVIDIA Corporation 43464ebd5Sriastradh * 53464ebd5Sriastradh * Permission is hereby granted, free of charge, to any person obtaining a 63464ebd5Sriastradh * copy of this software and associated documentation files (the "Software"), 73464ebd5Sriastradh * to deal in the Software without restriction, including without limitation 83464ebd5Sriastradh * the rights to use, copy, modify, merge, publish, distribute, sublicense, 93464ebd5Sriastradh * and/or sell copies of the Software, and to permit persons to whom the 103464ebd5Sriastradh * Software is furnished to do so, subject to the following conditions: 113464ebd5Sriastradh * 123464ebd5Sriastradh * The above copyright notice and this permission notice (including the next 133464ebd5Sriastradh * paragraph) shall be included in all copies or substantial portions of the 143464ebd5Sriastradh * Software. 153464ebd5Sriastradh * 163464ebd5Sriastradh * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 173464ebd5Sriastradh * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 183464ebd5Sriastradh * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 193464ebd5Sriastradh * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 203464ebd5Sriastradh * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 213464ebd5Sriastradh * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 223464ebd5Sriastradh * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 233464ebd5Sriastradh * DEALINGS IN THE SOFTWARE. 243464ebd5Sriastradh * 253464ebd5Sriastradh * Authors: 263464ebd5Sriastradh * Benjamin Franzke <benjaminfranzke@googlemail.com> 277ec681f3Smrg * James Jones <jajones@nvidia.com> 283464ebd5Sriastradh */ 293464ebd5Sriastradh 303464ebd5Sriastradh#include <stdio.h> 313464ebd5Sriastradh#include <stddef.h> 323464ebd5Sriastradh#include <stdlib.h> 333464ebd5Sriastradh#include <string.h> 343464ebd5Sriastradh#include <limits.h> 357ec681f3Smrg#include <assert.h> 367ec681f3Smrg#include <dlfcn.h> 377ec681f3Smrg#include <xf86drm.h> 383464ebd5Sriastradh 397ec681f3Smrg#include "loader.h" 403464ebd5Sriastradh#include "backend.h" 413464ebd5Sriastradh 423464ebd5Sriastradh#define ARRAY_SIZE(a) (sizeof(a)/sizeof((a)[0])) 437ec681f3Smrg#define VER_MIN(a, b) ((a) < (b) ? (a) : (b)) 443464ebd5Sriastradh 453464ebd5Sriastradhextern const struct gbm_backend gbm_dri_backend; 463464ebd5Sriastradh 477ec681f3Smrgstruct gbm_backend_desc { 483464ebd5Sriastradh const char *name; 497ec681f3Smrg const struct gbm_backend *backend; 507ec681f3Smrg void *lib; 513464ebd5Sriastradh}; 523464ebd5Sriastradh 537ec681f3Smrgstatic const struct gbm_backend_desc builtin_backends[] = { 547ec681f3Smrg { "dri", &gbm_dri_backend }, 553464ebd5Sriastradh}; 563464ebd5Sriastradh 577ec681f3Smrg#define BACKEND_LIB_SUFFIX "_gbm" 587ec681f3Smrgstatic const char *backend_search_path_vars[] = { 597ec681f3Smrg "GBM_BACKENDS_PATH", 607ec681f3Smrg NULL 617ec681f3Smrg}; 627ec681f3Smrg 637ec681f3Smrgstatic void 647ec681f3Smrgfree_backend_desc(const struct gbm_backend_desc *backend_desc) 653464ebd5Sriastradh{ 667ec681f3Smrg assert(backend_desc->lib); 673464ebd5Sriastradh 687ec681f3Smrg dlclose(backend_desc->lib); 697ec681f3Smrg free((void *)backend_desc->name); 707ec681f3Smrg free((void *)backend_desc); 717ec681f3Smrg} 727ec681f3Smrg 737ec681f3Smrgstatic struct gbm_backend_desc * 747ec681f3Smrgcreate_backend_desc(const char *name, 757ec681f3Smrg const struct gbm_backend *backend, 767ec681f3Smrg void *lib) 777ec681f3Smrg{ 787ec681f3Smrg struct gbm_backend_desc *new_desc = calloc(1, sizeof(*new_desc)); 797ec681f3Smrg 807ec681f3Smrg if (!new_desc) 813464ebd5Sriastradh return NULL; 823464ebd5Sriastradh 837ec681f3Smrg new_desc->name = strdup(name); 847ec681f3Smrg 857ec681f3Smrg if (!new_desc->name) { 867ec681f3Smrg free(new_desc); 877ec681f3Smrg return NULL; 883464ebd5Sriastradh } 893464ebd5Sriastradh 907ec681f3Smrg new_desc->backend = backend; 917ec681f3Smrg new_desc->lib = lib; 927ec681f3Smrg 937ec681f3Smrg return new_desc; 947ec681f3Smrg} 957ec681f3Smrg 967ec681f3Smrgstatic struct gbm_device * 977ec681f3Smrgbackend_create_device(const struct gbm_backend_desc *bd, int fd) 987ec681f3Smrg{ 997ec681f3Smrg const uint32_t abi_ver = VER_MIN(GBM_BACKEND_ABI_VERSION, 1007ec681f3Smrg bd->backend->v0.backend_version); 1017ec681f3Smrg struct gbm_device *dev = bd->backend->v0.create_device(fd, abi_ver); 1027ec681f3Smrg 1037ec681f3Smrg if (dev) { 1047ec681f3Smrg if (abi_ver != dev->v0.backend_version) { 1057ec681f3Smrg _gbm_device_destroy(dev); 1067ec681f3Smrg return NULL; 1077ec681f3Smrg } 1087ec681f3Smrg dev->v0.backend_desc = bd; 1097ec681f3Smrg } 1107ec681f3Smrg 1117ec681f3Smrg return dev; 1127ec681f3Smrg} 1137ec681f3Smrg 1147ec681f3Smrgstatic struct gbm_device * 1157ec681f3Smrgload_backend(void *lib, int fd, const char *name) 1167ec681f3Smrg{ 1177ec681f3Smrg struct gbm_device *dev = NULL; 1187ec681f3Smrg struct gbm_backend_desc *backend_desc; 1197ec681f3Smrg const struct gbm_backend *gbm_backend; 1207ec681f3Smrg GBM_GET_BACKEND_PROC_PTR get_backend; 1217ec681f3Smrg 1227ec681f3Smrg get_backend = dlsym(lib, GBM_GET_BACKEND_PROC_NAME); 1237ec681f3Smrg 1247ec681f3Smrg if (!get_backend) 1257ec681f3Smrg goto fail; 1267ec681f3Smrg 1277ec681f3Smrg gbm_backend = get_backend(&gbm_core); 1287ec681f3Smrg backend_desc = create_backend_desc(name, gbm_backend, lib); 1297ec681f3Smrg 1307ec681f3Smrg if (!backend_desc) 1317ec681f3Smrg goto fail; 1327ec681f3Smrg 1337ec681f3Smrg dev = backend_create_device(backend_desc, fd); 1347ec681f3Smrg 1357ec681f3Smrg if (!dev) 1367ec681f3Smrg free_backend_desc(backend_desc); 1377ec681f3Smrg 1387ec681f3Smrg return dev; 1397ec681f3Smrg 1407ec681f3Smrgfail: 1417ec681f3Smrg dlclose(lib); 1427ec681f3Smrg return NULL; 1433464ebd5Sriastradh} 1443464ebd5Sriastradh 1457ec681f3Smrgstatic struct gbm_device * 1467ec681f3Smrgfind_backend(const char *name, int fd) 1473464ebd5Sriastradh{ 1487ec681f3Smrg struct gbm_device *dev = NULL; 1497ec681f3Smrg const struct gbm_backend_desc *bd; 1507ec681f3Smrg void *lib; 15101e04c3fSmrg unsigned i; 1523464ebd5Sriastradh 1537ec681f3Smrg for (i = 0; i < ARRAY_SIZE(builtin_backends); ++i) { 1547ec681f3Smrg bd = &builtin_backends[i]; 1557ec681f3Smrg 1567ec681f3Smrg if (name && strcmp(bd->name, name)) 1577ec681f3Smrg continue; 1587ec681f3Smrg 1597ec681f3Smrg dev = backend_create_device(bd, fd); 1607ec681f3Smrg 1617ec681f3Smrg if (dev) 1623464ebd5Sriastradh break; 1633464ebd5Sriastradh } 1643464ebd5Sriastradh 1657ec681f3Smrg if (name && !dev) { 1667ec681f3Smrg lib = loader_open_driver_lib(name, BACKEND_LIB_SUFFIX, 1677ec681f3Smrg backend_search_path_vars, 1687ec681f3Smrg DEFAULT_BACKENDS_PATH, 1697ec681f3Smrg true); 1707ec681f3Smrg 1717ec681f3Smrg if (lib) 1727ec681f3Smrg dev = load_backend(lib, fd, name); 1737ec681f3Smrg } 1747ec681f3Smrg 1757ec681f3Smrg return dev; 1763464ebd5Sriastradh} 1773464ebd5Sriastradh 1787ec681f3Smrgstatic struct gbm_device * 1797ec681f3Smrgoverride_backend(int fd) 1803464ebd5Sriastradh{ 1813464ebd5Sriastradh struct gbm_device *dev = NULL; 1823464ebd5Sriastradh const char *b; 1833464ebd5Sriastradh 1843464ebd5Sriastradh b = getenv("GBM_BACKEND"); 1853464ebd5Sriastradh if (b) 1867ec681f3Smrg dev = find_backend(b, fd); 1873464ebd5Sriastradh 1887ec681f3Smrg return dev; 1897ec681f3Smrg} 1903464ebd5Sriastradh 1917ec681f3Smrgstatic struct gbm_device * 1927ec681f3Smrgbackend_from_driver_name(int fd) 1937ec681f3Smrg{ 1947ec681f3Smrg struct gbm_device *dev = NULL; 1957ec681f3Smrg drmVersionPtr v = drmGetVersion(fd); 1967ec681f3Smrg void *lib; 1977ec681f3Smrg 1987ec681f3Smrg if (!v) 1997ec681f3Smrg return NULL; 2007ec681f3Smrg 2017ec681f3Smrg lib = loader_open_driver_lib(v->name, BACKEND_LIB_SUFFIX, 2027ec681f3Smrg backend_search_path_vars, 2037ec681f3Smrg DEFAULT_BACKENDS_PATH, 2047ec681f3Smrg false); 2057ec681f3Smrg 2067ec681f3Smrg if (lib) 2077ec681f3Smrg dev = load_backend(lib, fd, v->name); 2087ec681f3Smrg 2097ec681f3Smrg drmFreeVersion(v); 2107ec681f3Smrg 2117ec681f3Smrg return dev; 2127ec681f3Smrg} 2137ec681f3Smrg 2147ec681f3Smrgstruct gbm_device * 2157ec681f3Smrg_gbm_create_device(int fd) 2167ec681f3Smrg{ 2177ec681f3Smrg struct gbm_device *dev; 2187ec681f3Smrg 2197ec681f3Smrg dev = override_backend(fd); 2207ec681f3Smrg 2217ec681f3Smrg if (!dev) 2227ec681f3Smrg dev = backend_from_driver_name(fd); 2237ec681f3Smrg 2247ec681f3Smrg if (!dev) 2257ec681f3Smrg dev = find_backend(NULL, fd); 2263464ebd5Sriastradh 2273464ebd5Sriastradh return dev; 2283464ebd5Sriastradh} 2297ec681f3Smrg 2307ec681f3Smrgvoid 2317ec681f3Smrg_gbm_device_destroy(struct gbm_device *gbm) 2327ec681f3Smrg{ 2337ec681f3Smrg const struct gbm_backend_desc *backend_desc = gbm->v0.backend_desc; 2347ec681f3Smrg gbm->v0.destroy(gbm); 2357ec681f3Smrg 2367ec681f3Smrg if (backend_desc && backend_desc->lib) 2377ec681f3Smrg free_backend_desc(backend_desc); 2387ec681f3Smrg} 239