diff options
author | Laurent Pinchart <laurent.pinchart@ideasonboard.com> | 2014-11-18 22:52:06 +0200 |
---|---|---|
committer | Laurent Pinchart <laurent.pinchart@ideasonboard.com> | 2016-05-24 03:03:01 +0300 |
commit | c9601d407a7ca943e53fa49a5a5f69b868c6ed11 (patch) | |
tree | 248d13a9e817ba3c73fc50e2d655b4cd12013e10 /lib/xlnx-plugin.c | |
parent | 3653f5e4d877176a30035d9123ac65daf46ba787 (diff) |
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Diffstat (limited to 'lib/xlnx-plugin.c')
-rw-r--r-- | lib/xlnx-plugin.c | 220 |
1 files changed, 220 insertions, 0 deletions
diff --git a/lib/xlnx-plugin.c b/lib/xlnx-plugin.c new file mode 100644 index 0000000..bd4553d --- /dev/null +++ b/lib/xlnx-plugin.c @@ -0,0 +1,220 @@ +/* + * Xilinx Video Library - Plugin API + * + * Copyright (C) 2014-2016 Ideas on board Oy + * + * Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.com> + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#include <dirent.h> +#include <dlfcn.h> +#include <errno.h> +#include <string.h> +#include <sys/types.h> + +#include <mediactl.h> + +#include <xlnx-plugin.h> +#include <xlnx-video.h> + +#include "xlnx-priv.h" + +#define __stringify(n) #n +#define _stringify(n) __stringify(n) + +#define XLNX_VIDEO_PLUGIN_DIR "/usr/lib/xilinx/video/plugins" +#define XLNX_VIDEO_PLUGIN_SYMBOL_NAME _stringify(XLNX_VIDEO_PLUGIN_SYMBOL) + +struct xlnx_video_plugin { + struct list_entry list; + void *handle; + const struct xlnx_video_plugin_ops *ops; + const struct xlnx_video_plugin_info *info; +}; + +struct xlnx_video_component *xlnx_video_plugin_scan(struct xlnx_video *xv, + struct media_device *mdev) +{ + const struct media_device_info *mdev_info = media_get_info(mdev); + struct xlnx_video_component *xvcomp; + struct xlnx_video_plugin *plugin; + + xlnx_dbg(xv, "Searching plugin for media device %s (%s)\n", + mdev_info->model, mdev_info->bus_info); + + list_for_each_entry(plugin, &xv->plugins, list) { + xlnx_dbg(xv, "Trying plugin `%s'\n", plugin->info->name); + xvcomp = plugin->ops->scan(xv, mdev); + if (xvcomp) { + xlnx_dbg(xv, "Plugin supports media device\n"); + return xvcomp; + } + } + + xlnx_dbg(xv, "No matching plugin found\n"); + return NULL; +} + +static int xlnx_video_plugin_load_file(struct xlnx_video *xv, const char *filename) +{ + const struct xlnx_video_plugin_ops *plugin_ops; + struct xlnx_video_plugin *plugin; + void *plugin_so; + int ret; + + xlnx_dbg(xv, "Loading plugin from file %s\n", filename); + + plugin_so = dlopen(filename, RTLD_LAZY); + if (!plugin_so) { + xlnx_dbg(xv, "Failed to open shared library (%s)\n", dlerror()); + return -EINVAL; + } + + plugin_ops = dlsym(plugin_so, XLNX_VIDEO_PLUGIN_SYMBOL_NAME); + if (!plugin_ops) { + xlnx_dbg(xv, "Plugin symbol not found (%s)\n", dlerror()); + ret = -EINVAL; + goto error; + } + + plugin = calloc(1, sizeof(*plugin)); + if (!plugin) { + ret = -ENOMEM; + goto error; + } + + plugin->handle = plugin_so; + plugin->ops = plugin_ops; + plugin->info = plugin_ops->info(); + + list_append(&plugin->list, &xv->plugins); + + xlnx_dbg(xv, "Plugin loaded successfully\n"); + return 0; + +error: + dlclose(plugin_so); + return ret; +} + +/** + * \brief Load plugins from a given directory + * \param xv the library context + * \param path the full path name to the directory containing plugins + * + * This function attempts to load all plugins from the \a path directory. A + * plugin is a shared object whose name ends with '.so' and contains a symbol + * named '__xlnx_video_plugin' pointing to a struct xlnx_video_plugin_ops + * instance. + * + * When a valid plugin is found and loaded, call the init function supplied in + * the plugin operations structure. + * + * Shared objects that fail to load, don't export the plugin operations + * structure, don't implement the init function or return an error from their + * init function are ignored and not considered as a fatal error. + * + * \return Return the number of plugins successfully loaded, or a negative error + * code if a fatal error occurs. + */ +int xlnx_video_plugin_load_directory(struct xlnx_video *xv, const char *path) +{ + struct dirent *entry; + unsigned int count = 0; + size_t pathlen; + DIR *dir; + int ret = 0; + + xlnx_dbg(xv, "Loading plugins from directory %s\n", path); + + dir = opendir(path); + if (!dir) { + xlnx_dbg(xv, "Failed to open directory\n"); + return -errno; + } + + pathlen = strlen(path); + + while ((entry = readdir(dir))) { + char *filename; + size_t len; + + if (entry->d_type != DT_REG && entry->d_type != DT_LNK && + entry->d_type != DT_UNKNOWN) + continue; + + len = strlen(entry->d_name); + if (strcmp(entry->d_name + len - 3, ".so")) + continue; + + filename = malloc(pathlen + 1 + len + 1); + if (!filename) + break; + + strcpy(filename, path); + filename[pathlen] = '/'; + strcpy(filename + pathlen + 1, entry->d_name); + + ret = xlnx_video_plugin_load_file(xv, filename); + free(filename); + + if (ret < 0) + continue; + + count++; + } + + closedir(dir); + + return ret < 0 ? ret : (int)count; +} + +/** \cond INTERNAL_API */ + +/** + * \brief Initialize plugin support + * \param xv the library context + * + * Initialize plugin support and load plugins from the system default plugin + * directory ('/usr/lib/xilinx/video/plugins' by default). + * + * \return 0 on success or a negative error code if an error occurs. + */ +int xlnx_video_plugin_init(struct xlnx_video *xv) +{ + xlnx_video_plugin_load_directory(xv, XLNX_VIDEO_PLUGIN_DIR); + + return 0; +} + +/** + * \brief Initialize plugin support + * \param xv the library context + * + * Initialize plugin support and load plugins from the system default plugin + * directory ('/usr/lib/xilinx/video/plugins' by default). + * + * \return 0 on success or a negative error code if an error occurs. + */ +void xlnx_video_plugin_fini(struct xlnx_video *xv) +{ + struct xlnx_video_plugin *plugin, *next; + + list_for_each_entry_safe(plugin, next, &xv->plugins, list) { + list_remove(&plugin->list); + dlclose(plugin->handle); + free(plugin); + } +} + +/** \endcond */ |