1/*
2 * Copyright © 2011 Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 *
24 * Authors:
25 *    Benjamin Franzke <benjaminfranzke@googlemail.com>
26 */
27
28#include <stdio.h>
29#include <stddef.h>
30#include <stdlib.h>
31#include <string.h>
32#include <limits.h>
33#include <dlfcn.h>
34
35#include "backend.h"
36
37#define ARRAY_SIZE(a) (sizeof(a)/sizeof((a)[0]))
38
39extern const struct gbm_backend gbm_dri_backend;
40
41struct backend_desc {
42   const char *name;
43   const struct gbm_backend *builtin;
44};
45
46static const struct backend_desc backends[] = {
47   { "gbm_dri.so", &gbm_dri_backend },
48   { "gbm_gallium_drm.so", NULL },
49};
50
51static const void *
52load_backend(const struct backend_desc *backend)
53{
54   char path[PATH_MAX];
55   const void *init = NULL;
56   void *module;
57   const char *name;
58   const char *entrypoint = "gbm_backend";
59
60   if (backend == NULL)
61      return NULL;
62
63   name = backend->name;
64
65   if (backend->builtin) {
66      init = backend->builtin;
67   } else {
68      if (name[0] != '/')
69         snprintf(path, sizeof path, MODULEDIR "/%s", name);
70      else
71         snprintf(path, sizeof path, "%s", name);
72
73      module = dlopen(path, RTLD_NOW | RTLD_GLOBAL);
74      if (!module) {
75         fprintf(stderr,
76                 "failed to load module: %s\n", dlerror());
77         return NULL;
78      }
79
80      init = dlsym(module, entrypoint);
81      if (!init)
82         return NULL;
83   }
84
85   return init;
86}
87
88static const struct backend_desc *
89find_backend(const char *name)
90{
91   const struct backend_desc *backend = NULL;
92   int i;
93
94   for (i = 0; i < ARRAY_SIZE(backends); ++i) {
95      if (strcmp(backends[i].name, name) == 0) {
96         backend = &backends[i];
97         break;
98      }
99   }
100
101   return backend;
102}
103
104struct gbm_device *
105_gbm_create_device(int fd)
106{
107   const struct gbm_backend *backend = NULL;
108   struct gbm_device *dev = NULL;
109   int i;
110   const char *b;
111
112   b = getenv("GBM_BACKEND");
113   if (b)
114      backend = load_backend(find_backend(b));
115
116   if (backend)
117      dev = backend->create_device(fd);
118
119   for (i = 0; i < ARRAY_SIZE(backends) && dev == NULL; ++i) {
120      backend = load_backend(&backends[i]);
121      if (backend == NULL)
122         continue;
123
124      dev = backend->create_device(fd);
125   }
126
127   return dev;
128}
129