1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Copyright © 2011 Intel Corporation 3bf215546Sopenharmony_ci * Copyright © 2021 NVIDIA Corporation 4bf215546Sopenharmony_ci * 5bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 6bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 7bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation 8bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 10bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 11bf215546Sopenharmony_ci * 12bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next 13bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the 14bf215546Sopenharmony_ci * Software. 15bf215546Sopenharmony_ci * 16bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17bf215546Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18bf215546Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19bf215546Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 20bf215546Sopenharmony_ci * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 21bf215546Sopenharmony_ci * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22bf215546Sopenharmony_ci * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23bf215546Sopenharmony_ci * DEALINGS IN THE SOFTWARE. 24bf215546Sopenharmony_ci * 25bf215546Sopenharmony_ci * Authors: 26bf215546Sopenharmony_ci * Benjamin Franzke <benjaminfranzke@googlemail.com> 27bf215546Sopenharmony_ci * James Jones <jajones@nvidia.com> 28bf215546Sopenharmony_ci */ 29bf215546Sopenharmony_ci 30bf215546Sopenharmony_ci#include <stdio.h> 31bf215546Sopenharmony_ci#include <stddef.h> 32bf215546Sopenharmony_ci#include <stdlib.h> 33bf215546Sopenharmony_ci#include <string.h> 34bf215546Sopenharmony_ci#include <limits.h> 35bf215546Sopenharmony_ci#include <assert.h> 36bf215546Sopenharmony_ci#include <dlfcn.h> 37bf215546Sopenharmony_ci#include <xf86drm.h> 38bf215546Sopenharmony_ci 39bf215546Sopenharmony_ci#include "loader.h" 40bf215546Sopenharmony_ci#include "backend.h" 41bf215546Sopenharmony_ci 42bf215546Sopenharmony_ci#define ARRAY_SIZE(a) (sizeof(a)/sizeof((a)[0])) 43bf215546Sopenharmony_ci#define VER_MIN(a, b) ((a) < (b) ? (a) : (b)) 44bf215546Sopenharmony_ci 45bf215546Sopenharmony_ciextern const struct gbm_backend gbm_dri_backend; 46bf215546Sopenharmony_ci 47bf215546Sopenharmony_cistruct gbm_backend_desc { 48bf215546Sopenharmony_ci const char *name; 49bf215546Sopenharmony_ci const struct gbm_backend *backend; 50bf215546Sopenharmony_ci void *lib; 51bf215546Sopenharmony_ci}; 52bf215546Sopenharmony_ci 53bf215546Sopenharmony_cistatic const struct gbm_backend_desc builtin_backends[] = { 54bf215546Sopenharmony_ci { "dri", &gbm_dri_backend }, 55bf215546Sopenharmony_ci}; 56bf215546Sopenharmony_ci 57bf215546Sopenharmony_ci#define BACKEND_LIB_SUFFIX "_gbm" 58bf215546Sopenharmony_cistatic const char *backend_search_path_vars[] = { 59bf215546Sopenharmony_ci "GBM_BACKENDS_PATH", 60bf215546Sopenharmony_ci NULL 61bf215546Sopenharmony_ci}; 62bf215546Sopenharmony_ci 63bf215546Sopenharmony_cistatic void 64bf215546Sopenharmony_cifree_backend_desc(const struct gbm_backend_desc *backend_desc) 65bf215546Sopenharmony_ci{ 66bf215546Sopenharmony_ci assert(backend_desc->lib); 67bf215546Sopenharmony_ci 68bf215546Sopenharmony_ci dlclose(backend_desc->lib); 69bf215546Sopenharmony_ci free((void *)backend_desc->name); 70bf215546Sopenharmony_ci free((void *)backend_desc); 71bf215546Sopenharmony_ci} 72bf215546Sopenharmony_ci 73bf215546Sopenharmony_cistatic struct gbm_backend_desc * 74bf215546Sopenharmony_cicreate_backend_desc(const char *name, 75bf215546Sopenharmony_ci const struct gbm_backend *backend, 76bf215546Sopenharmony_ci void *lib) 77bf215546Sopenharmony_ci{ 78bf215546Sopenharmony_ci struct gbm_backend_desc *new_desc = calloc(1, sizeof(*new_desc)); 79bf215546Sopenharmony_ci 80bf215546Sopenharmony_ci if (!new_desc) 81bf215546Sopenharmony_ci return NULL; 82bf215546Sopenharmony_ci 83bf215546Sopenharmony_ci new_desc->name = strdup(name); 84bf215546Sopenharmony_ci 85bf215546Sopenharmony_ci if (!new_desc->name) { 86bf215546Sopenharmony_ci free(new_desc); 87bf215546Sopenharmony_ci return NULL; 88bf215546Sopenharmony_ci } 89bf215546Sopenharmony_ci 90bf215546Sopenharmony_ci new_desc->backend = backend; 91bf215546Sopenharmony_ci new_desc->lib = lib; 92bf215546Sopenharmony_ci 93bf215546Sopenharmony_ci return new_desc; 94bf215546Sopenharmony_ci} 95bf215546Sopenharmony_ci 96bf215546Sopenharmony_cistatic struct gbm_device * 97bf215546Sopenharmony_cibackend_create_device(const struct gbm_backend_desc *bd, int fd) 98bf215546Sopenharmony_ci{ 99bf215546Sopenharmony_ci const uint32_t abi_ver = VER_MIN(GBM_BACKEND_ABI_VERSION, 100bf215546Sopenharmony_ci bd->backend->v0.backend_version); 101bf215546Sopenharmony_ci struct gbm_device *dev = bd->backend->v0.create_device(fd, abi_ver); 102bf215546Sopenharmony_ci 103bf215546Sopenharmony_ci if (dev) { 104bf215546Sopenharmony_ci if (abi_ver != dev->v0.backend_version) { 105bf215546Sopenharmony_ci _gbm_device_destroy(dev); 106bf215546Sopenharmony_ci return NULL; 107bf215546Sopenharmony_ci } 108bf215546Sopenharmony_ci dev->v0.backend_desc = bd; 109bf215546Sopenharmony_ci } 110bf215546Sopenharmony_ci 111bf215546Sopenharmony_ci return dev; 112bf215546Sopenharmony_ci} 113bf215546Sopenharmony_ci 114bf215546Sopenharmony_cistatic struct gbm_device * 115bf215546Sopenharmony_ciload_backend(void *lib, int fd, const char *name) 116bf215546Sopenharmony_ci{ 117bf215546Sopenharmony_ci struct gbm_device *dev = NULL; 118bf215546Sopenharmony_ci struct gbm_backend_desc *backend_desc; 119bf215546Sopenharmony_ci const struct gbm_backend *gbm_backend; 120bf215546Sopenharmony_ci GBM_GET_BACKEND_PROC_PTR get_backend; 121bf215546Sopenharmony_ci 122bf215546Sopenharmony_ci get_backend = dlsym(lib, GBM_GET_BACKEND_PROC_NAME); 123bf215546Sopenharmony_ci 124bf215546Sopenharmony_ci if (!get_backend) 125bf215546Sopenharmony_ci goto fail; 126bf215546Sopenharmony_ci 127bf215546Sopenharmony_ci gbm_backend = get_backend(&gbm_core); 128bf215546Sopenharmony_ci backend_desc = create_backend_desc(name, gbm_backend, lib); 129bf215546Sopenharmony_ci 130bf215546Sopenharmony_ci if (!backend_desc) 131bf215546Sopenharmony_ci goto fail; 132bf215546Sopenharmony_ci 133bf215546Sopenharmony_ci dev = backend_create_device(backend_desc, fd); 134bf215546Sopenharmony_ci 135bf215546Sopenharmony_ci if (!dev) 136bf215546Sopenharmony_ci free_backend_desc(backend_desc); 137bf215546Sopenharmony_ci 138bf215546Sopenharmony_ci return dev; 139bf215546Sopenharmony_ci 140bf215546Sopenharmony_cifail: 141bf215546Sopenharmony_ci dlclose(lib); 142bf215546Sopenharmony_ci return NULL; 143bf215546Sopenharmony_ci} 144bf215546Sopenharmony_ci 145bf215546Sopenharmony_cistatic struct gbm_device * 146bf215546Sopenharmony_cifind_backend(const char *name, int fd) 147bf215546Sopenharmony_ci{ 148bf215546Sopenharmony_ci struct gbm_device *dev = NULL; 149bf215546Sopenharmony_ci const struct gbm_backend_desc *bd; 150bf215546Sopenharmony_ci void *lib; 151bf215546Sopenharmony_ci unsigned i; 152bf215546Sopenharmony_ci 153bf215546Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(builtin_backends); ++i) { 154bf215546Sopenharmony_ci bd = &builtin_backends[i]; 155bf215546Sopenharmony_ci 156bf215546Sopenharmony_ci if (name && strcmp(bd->name, name)) 157bf215546Sopenharmony_ci continue; 158bf215546Sopenharmony_ci 159bf215546Sopenharmony_ci dev = backend_create_device(bd, fd); 160bf215546Sopenharmony_ci 161bf215546Sopenharmony_ci if (dev) 162bf215546Sopenharmony_ci break; 163bf215546Sopenharmony_ci } 164bf215546Sopenharmony_ci 165bf215546Sopenharmony_ci if (name && !dev) { 166bf215546Sopenharmony_ci lib = loader_open_driver_lib(name, BACKEND_LIB_SUFFIX, 167bf215546Sopenharmony_ci backend_search_path_vars, 168bf215546Sopenharmony_ci DEFAULT_BACKENDS_PATH, 169bf215546Sopenharmony_ci true); 170bf215546Sopenharmony_ci 171bf215546Sopenharmony_ci if (lib) 172bf215546Sopenharmony_ci dev = load_backend(lib, fd, name); 173bf215546Sopenharmony_ci } 174bf215546Sopenharmony_ci 175bf215546Sopenharmony_ci return dev; 176bf215546Sopenharmony_ci} 177bf215546Sopenharmony_ci 178bf215546Sopenharmony_cistatic struct gbm_device * 179bf215546Sopenharmony_cioverride_backend(int fd) 180bf215546Sopenharmony_ci{ 181bf215546Sopenharmony_ci struct gbm_device *dev = NULL; 182bf215546Sopenharmony_ci const char *b; 183bf215546Sopenharmony_ci 184bf215546Sopenharmony_ci b = getenv("GBM_BACKEND"); 185bf215546Sopenharmony_ci if (b) 186bf215546Sopenharmony_ci dev = find_backend(b, fd); 187bf215546Sopenharmony_ci 188bf215546Sopenharmony_ci return dev; 189bf215546Sopenharmony_ci} 190bf215546Sopenharmony_ci 191bf215546Sopenharmony_cistatic struct gbm_device * 192bf215546Sopenharmony_cibackend_from_driver_name(int fd) 193bf215546Sopenharmony_ci{ 194bf215546Sopenharmony_ci struct gbm_device *dev = NULL; 195bf215546Sopenharmony_ci drmVersionPtr v = drmGetVersion(fd); 196bf215546Sopenharmony_ci void *lib; 197bf215546Sopenharmony_ci 198bf215546Sopenharmony_ci if (!v) 199bf215546Sopenharmony_ci return NULL; 200bf215546Sopenharmony_ci 201bf215546Sopenharmony_ci lib = loader_open_driver_lib(v->name, BACKEND_LIB_SUFFIX, 202bf215546Sopenharmony_ci backend_search_path_vars, 203bf215546Sopenharmony_ci DEFAULT_BACKENDS_PATH, 204bf215546Sopenharmony_ci false); 205bf215546Sopenharmony_ci 206bf215546Sopenharmony_ci if (lib) 207bf215546Sopenharmony_ci dev = load_backend(lib, fd, v->name); 208bf215546Sopenharmony_ci 209bf215546Sopenharmony_ci drmFreeVersion(v); 210bf215546Sopenharmony_ci 211bf215546Sopenharmony_ci return dev; 212bf215546Sopenharmony_ci} 213bf215546Sopenharmony_ci 214bf215546Sopenharmony_cistruct gbm_device * 215bf215546Sopenharmony_ci_gbm_create_device(int fd) 216bf215546Sopenharmony_ci{ 217bf215546Sopenharmony_ci struct gbm_device *dev; 218bf215546Sopenharmony_ci 219bf215546Sopenharmony_ci dev = override_backend(fd); 220bf215546Sopenharmony_ci 221bf215546Sopenharmony_ci if (!dev) 222bf215546Sopenharmony_ci dev = backend_from_driver_name(fd); 223bf215546Sopenharmony_ci 224bf215546Sopenharmony_ci if (!dev) 225bf215546Sopenharmony_ci dev = find_backend(NULL, fd); 226bf215546Sopenharmony_ci 227bf215546Sopenharmony_ci return dev; 228bf215546Sopenharmony_ci} 229bf215546Sopenharmony_ci 230bf215546Sopenharmony_civoid 231bf215546Sopenharmony_ci_gbm_device_destroy(struct gbm_device *gbm) 232bf215546Sopenharmony_ci{ 233bf215546Sopenharmony_ci const struct gbm_backend_desc *backend_desc = gbm->v0.backend_desc; 234bf215546Sopenharmony_ci gbm->v0.destroy(gbm); 235bf215546Sopenharmony_ci 236bf215546Sopenharmony_ci if (backend_desc && backend_desc->lib) 237bf215546Sopenharmony_ci free_backend_desc(backend_desc); 238bf215546Sopenharmony_ci} 239