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 <[email protected]>
27 * James Jones <[email protected]>
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 struct gbm_backend_desc {
46 const char *name;
47 const struct gbm_backend *backend;
48 void *lib;
49 };
50
51 #define BACKEND_LIB_SUFFIX "_gbm"
52 static const char *backend_search_path_vars[] = {
53 "GBM_BACKENDS_PATH",
54 NULL
55 };
56
57 static void
free_backend_desc(const struct gbm_backend_desc * backend_desc)58 free_backend_desc(const struct gbm_backend_desc *backend_desc)
59 {
60 assert(backend_desc->lib);
61
62 dlclose(backend_desc->lib);
63 free((void *)backend_desc->name);
64 free((void *)backend_desc);
65 }
66
67 static struct gbm_backend_desc *
create_backend_desc(const char * name,const struct gbm_backend * backend,void * lib)68 create_backend_desc(const char *name,
69 const struct gbm_backend *backend,
70 void *lib)
71 {
72 struct gbm_backend_desc *new_desc = calloc(1, sizeof(*new_desc));
73
74 if (!new_desc)
75 return NULL;
76
77 new_desc->name = strdup(name);
78
79 if (!new_desc->name) {
80 free(new_desc);
81 return NULL;
82 }
83
84 new_desc->backend = backend;
85 new_desc->lib = lib;
86
87 return new_desc;
88 }
89
90 static struct gbm_device *
backend_create_device(const struct gbm_backend_desc * bd,int fd)91 backend_create_device(const struct gbm_backend_desc *bd, int fd)
92 {
93 const uint32_t abi_ver = VER_MIN(GBM_BACKEND_ABI_VERSION,
94 bd->backend->v0.backend_version);
95 struct gbm_device *dev = bd->backend->v0.create_device(fd, abi_ver);
96
97 if (dev) {
98 if (abi_ver != dev->v0.backend_version) {
99 _gbm_device_destroy(dev);
100 return NULL;
101 }
102 dev->v0.backend_desc = bd;
103 }
104
105 return dev;
106 }
107
108 static struct gbm_device *
load_backend_by_name(const char * name,int fd,bool warn_on_fail)109 load_backend_by_name(const char *name, int fd, bool warn_on_fail)
110 {
111 void *lib = loader_open_driver_lib(name, BACKEND_LIB_SUFFIX,
112 backend_search_path_vars,
113 DEFAULT_BACKENDS_PATH,
114 warn_on_fail);
115
116 if (!lib)
117 return NULL;
118
119 struct gbm_device *dev = NULL;
120 struct gbm_backend_desc *backend_desc;
121 const struct gbm_backend *gbm_backend;
122 GBM_GET_BACKEND_PROC_PTR get_backend;
123
124 get_backend = dlsym(lib, GBM_GET_BACKEND_PROC_NAME);
125
126 if (!get_backend)
127 goto fail;
128
129 gbm_backend = get_backend(&gbm_core);
130 backend_desc = create_backend_desc(name, gbm_backend, lib);
131
132 if (!backend_desc)
133 goto fail;
134
135 dev = backend_create_device(backend_desc, fd);
136
137 if (!dev)
138 free_backend_desc(backend_desc);
139
140 return dev;
141
142 fail:
143 dlclose(lib);
144 return NULL;
145 }
146
147 struct gbm_device *
_gbm_create_device(int fd)148 _gbm_create_device(int fd)
149 {
150 struct gbm_device *dev = NULL;
151
152 const char *b = getenv("GBM_BACKEND");
153 if (b) {
154 dev = load_backend_by_name(b, fd, true);
155 if (dev) return dev;
156 }
157
158 drmVersionPtr v = drmGetVersion(fd);
159 if (v) {
160 dev = load_backend_by_name(v->name, fd, false);
161 drmFreeVersion(v);
162 if (dev) return dev;
163 }
164
165 return load_backend_by_name("dri", fd, true);
166 }
167
168 void
_gbm_device_destroy(struct gbm_device * gbm)169 _gbm_device_destroy(struct gbm_device *gbm)
170 {
171 const struct gbm_backend_desc *backend_desc = gbm->v0.backend_desc;
172 gbm->v0.destroy(gbm);
173
174 if (backend_desc && backend_desc->lib)
175 free_backend_desc(backend_desc);
176 }
177