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