1 /*
2 * Copyright (C) 2010 Nokia Corporation <multimedia@maemo.org>
3
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation; either version 2.1 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18
19 #include <stdarg.h>
20 #include <dlfcn.h>
21 #include <fcntl.h>
22 #include <glob.h>
23 #include <sys/stat.h>
24 #include <sys/mman.h>
25 #include "libv4l2.h"
26 #include "libv4l2-priv.h"
27 #include "libv4l-plugin.h"
28
29 /* libv4l plugin support:
30 it is provided by functions v4l2_plugin_[open,close,etc].
31
32 When open() is called libv4l dlopens files in /usr/lib[64]/libv4l/plugins
33 1 at a time and call open callback passing through the applications
34 parameters unmodified.
35
36 If a plugin is relevant for the specified device node, it can indicate so
37 by returning a value other than -1 (the actual file descriptor).
38 As soon as a plugin returns another value than -1 plugin loading stops and
39 information about it (fd and corresponding library handle) is stored. For
40 each function v4l2_[ioctl,read,close,etc] is called corresponding
41 v4l2_plugin_* function which looks if there is loaded plugin for that file
42 and call it's callbacks.
43
44 v4l2_plugin_* function indicates by it's first argument if plugin was used,
45 and if it was not then v4l2_* functions proceed with their usual behavior.
46 */
47
48 #define PLUGINS_PATTERN LIBV4L2_PLUGIN_DIR "/*.so"
49
v4l2_plugin_init(int fd,void ** plugin_lib_ret,void ** plugin_priv_ret,const struct libv4l_dev_ops ** dev_ops_ret)50 void v4l2_plugin_init(int fd, void **plugin_lib_ret, void **plugin_priv_ret,
51 const struct libv4l_dev_ops **dev_ops_ret)
52 {
53 char *error;
54 int glob_ret, i;
55 void *plugin_library = NULL;
56 const struct libv4l_dev_ops *libv4l2_plugin = NULL;
57 glob_t globbuf;
58
59 *dev_ops_ret = v4lconvert_get_default_dev_ops();
60 *plugin_lib_ret = NULL;
61 *plugin_priv_ret = NULL;
62
63 glob_ret = glob(PLUGINS_PATTERN, 0, NULL, &globbuf);
64
65 if (glob_ret == GLOB_NOSPACE)
66 return;
67
68 if (glob_ret == GLOB_ABORTED || glob_ret == GLOB_NOMATCH)
69 goto leave;
70
71 for (i = 0; i < globbuf.gl_pathc; i++) {
72 V4L2_LOG("PLUGIN: dlopen(%s);\n", globbuf.gl_pathv[i]);
73
74 plugin_library = dlopen(globbuf.gl_pathv[i], RTLD_LAZY);
75 if (!plugin_library)
76 continue;
77
78 dlerror(); /* Clear any existing error */
79 libv4l2_plugin = (struct libv4l_dev_ops *)
80 dlsym(plugin_library, "libv4l2_plugin");
81 error = dlerror();
82 if (error != NULL) {
83 V4L2_LOG_ERR("PLUGIN: dlsym failed: %s\n", error);
84 dlclose(plugin_library);
85 continue;
86 }
87
88 if (!libv4l2_plugin->init ||
89 !libv4l2_plugin->close ||
90 !libv4l2_plugin->ioctl) {
91 V4L2_LOG("PLUGIN: does not have all mandatory ops\n");
92 dlclose(plugin_library);
93 continue;
94 }
95
96 *plugin_priv_ret = libv4l2_plugin->init(fd);
97 if (!*plugin_priv_ret) {
98 V4L2_LOG("PLUGIN: plugin open() returned NULL\n");
99 dlclose(plugin_library);
100 continue;
101 }
102
103 *plugin_lib_ret = plugin_library;
104 *dev_ops_ret = libv4l2_plugin;
105 break;
106 }
107
108 leave:
109 globfree(&globbuf);
110 }
111
v4l2_plugin_cleanup(void * plugin_lib,void * plugin_priv,const struct libv4l_dev_ops * dev_ops)112 void v4l2_plugin_cleanup(void *plugin_lib, void *plugin_priv,
113 const struct libv4l_dev_ops *dev_ops)
114 {
115 if (plugin_lib) {
116 dev_ops->close(plugin_priv);
117 dlclose(plugin_lib);
118 }
119 }
120