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