summaryrefslogtreecommitdiff
path: root/src/v4l2/v4l2_compat_manager.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/v4l2/v4l2_compat_manager.cpp')
-rw-r--r--src/v4l2/v4l2_compat_manager.cpp129
1 files changed, 72 insertions, 57 deletions
diff --git a/src/v4l2/v4l2_compat_manager.cpp b/src/v4l2/v4l2_compat_manager.cpp
index 961d06b3..f53fb300 100644
--- a/src/v4l2/v4l2_compat_manager.cpp
+++ b/src/v4l2/v4l2_compat_manager.cpp
@@ -1,8 +1,8 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
/*
* Copyright (C) 2019, Google Inc.
*
- * v4l2_compat_manager.cpp - V4L2 compatibility manager
+ * V4L2 compatibility manager
*/
#include "v4l2_compat_manager.h"
@@ -10,7 +10,6 @@
#include <dlfcn.h>
#include <fcntl.h>
#include <map>
-#include <stdarg.h>
#include <string.h>
#include <sys/eventfd.h>
#include <sys/mman.h>
@@ -19,10 +18,14 @@
#include <sys/types.h>
#include <unistd.h>
+#include <libcamera/base/log.h>
+#include <libcamera/base/utils.h>
+
#include <libcamera/camera.h>
#include <libcamera/camera_manager.h>
+#include <libcamera/property_ids.h>
-#include "log.h"
+#include "v4l2_camera_file.h"
using namespace libcamera;
@@ -39,17 +42,17 @@ void get_symbol(T &func, const char *name)
V4L2CompatManager::V4L2CompatManager()
: cm_(nullptr)
{
- get_symbol(fops_.openat, "openat");
+ get_symbol(fops_.openat, "openat64");
get_symbol(fops_.dup, "dup");
get_symbol(fops_.close, "close");
get_symbol(fops_.ioctl, "ioctl");
- get_symbol(fops_.mmap, "mmap");
+ get_symbol(fops_.mmap, "mmap64");
get_symbol(fops_.munmap, "munmap");
}
V4L2CompatManager::~V4L2CompatManager()
{
- devices_.clear();
+ files_.clear();
mmaps_.clear();
if (cm_) {
@@ -79,11 +82,10 @@ int V4L2CompatManager::start()
* For each Camera registered in the system, a V4L2CameraProxy gets
* created here to wrap a camera device.
*/
- unsigned int index = 0;
- for (auto &camera : cm_->cameras()) {
+ auto cameras = cm_->cameras();
+ for (auto [index, camera] : utils::enumerate(cameras)) {
V4L2CameraProxy *proxy = new V4L2CameraProxy(index, camera);
proxies_.emplace_back(proxy);
- ++index;
}
return 0;
@@ -95,13 +97,13 @@ V4L2CompatManager *V4L2CompatManager::instance()
return &instance;
}
-V4L2CameraProxy *V4L2CompatManager::getProxy(int fd)
+std::shared_ptr<V4L2CameraFile> V4L2CompatManager::cameraFile(int fd)
{
- auto device = devices_.find(fd);
- if (device == devices_.end())
+ auto file = files_.find(fd);
+ if (file == files_.end())
return nullptr;
- return device->second;
+ return file->second;
}
int V4L2CompatManager::getCameraIndex(int fd)
@@ -111,15 +113,35 @@ int V4L2CompatManager::getCameraIndex(int fd)
if (ret < 0)
return -1;
- std::shared_ptr<Camera> target = cm_->get(statbuf.st_rdev);
- if (!target)
- return -1;
+ const dev_t devnum = statbuf.st_rdev;
- unsigned int index = 0;
- for (auto &camera : cm_->cameras()) {
- if (camera == target)
- return index;
- ++index;
+ /*
+ * Iterate each known camera and identify if it reports this nodes
+ * device number in its list of SystemDevices.
+ */
+ auto cameras = cm_->cameras();
+ for (auto [index, camera] : utils::enumerate(cameras)) {
+ Span<const int64_t> devices = camera->properties()
+ .get(properties::SystemDevices)
+ .value_or(Span<int64_t>{});
+
+ /*
+ * While there may be multiple cameras that could reference the
+ * same device node, we take a first match as a best effort for
+ * now.
+ *
+ * \todo Each camera can be accessed through any of the video
+ * device nodes that it uses. This may confuse applications.
+ * Consider reworking the V4L2 adaptation layer to instead
+ * expose each Camera instance through a single video device
+ * node (with a consistent and stable mapping). The other
+ * device nodes could possibly be hidden from the application
+ * by intercepting additional calls to the C library.
+ */
+ for (const int64_t dev : devices) {
+ if (dev == static_cast<int64_t>(devnum))
+ return index;
+ }
}
return -1;
@@ -142,27 +164,24 @@ int V4L2CompatManager::openat(int dirfd, const char *path, int oflag, mode_t mod
ret = getCameraIndex(fd);
if (ret < 0) {
- LOG(V4L2Compat, Info) << "No camera found for " << path;
+ LOG(V4L2Compat, Debug) << "No camera found for " << path;
return fd;
}
fops_.close(fd);
- unsigned int camera_index = static_cast<unsigned int>(ret);
-
- V4L2CameraProxy *proxy = proxies_[camera_index].get();
- ret = proxy->open(oflag & O_NONBLOCK);
- if (ret < 0)
- return ret;
-
- int efd = eventfd(0, oflag & (O_CLOEXEC | O_NONBLOCK));
- if (efd < 0) {
- proxy->close();
+ int efd = eventfd(0, EFD_SEMAPHORE |
+ ((oflag & O_CLOEXEC) ? EFD_CLOEXEC : 0) |
+ ((oflag & O_NONBLOCK) ? EFD_NONBLOCK : 0));
+ if (efd < 0)
return efd;
- }
- devices_.emplace(efd, proxy);
+ V4L2CameraProxy *proxy = proxies_[ret].get();
+ files_.emplace(efd, std::make_shared<V4L2CameraFile>(dirfd, path, efd,
+ oflag & O_NONBLOCK,
+ proxy));
+ LOG(V4L2Compat, Debug) << "Opened " << path << " -> fd " << efd;
return efd;
}
@@ -172,40 +191,36 @@ int V4L2CompatManager::dup(int oldfd)
if (newfd < 0)
return newfd;
- auto device = devices_.find(oldfd);
- if (device != devices_.end()) {
- V4L2CameraProxy *proxy = device->second;
- devices_[newfd] = proxy;
- proxy->dup();
- }
+ auto file = files_.find(oldfd);
+ if (file != files_.end())
+ files_[newfd] = file->second;
return newfd;
}
int V4L2CompatManager::close(int fd)
{
- V4L2CameraProxy *proxy = getProxy(fd);
- if (proxy) {
- proxy->close();
- devices_.erase(fd);
- return 0;
- }
+ auto file = files_.find(fd);
+ if (file != files_.end())
+ files_.erase(file);
+ /* We still need to close the eventfd. */
return fops_.close(fd);
}
void *V4L2CompatManager::mmap(void *addr, size_t length, int prot, int flags,
- int fd, off_t offset)
+ int fd, off64_t offset)
{
- V4L2CameraProxy *proxy = getProxy(fd);
- if (!proxy)
+ std::shared_ptr<V4L2CameraFile> file = cameraFile(fd);
+ if (!file)
return fops_.mmap(addr, length, prot, flags, fd, offset);
- void *map = proxy->mmap(addr, length, prot, flags, offset);
+ void *map = file->proxy()->mmap(file.get(), addr, length, prot, flags,
+ offset);
if (map == MAP_FAILED)
return map;
- mmaps_[map] = proxy;
+ mmaps_[map] = file;
return map;
}
@@ -215,9 +230,9 @@ int V4L2CompatManager::munmap(void *addr, size_t length)
if (device == mmaps_.end())
return fops_.munmap(addr, length);
- V4L2CameraProxy *proxy = device->second;
+ V4L2CameraFile *file = device->second.get();
- int ret = proxy->munmap(addr, length);
+ int ret = file->proxy()->munmap(file, addr, length);
if (ret < 0)
return ret;
@@ -228,9 +243,9 @@ int V4L2CompatManager::munmap(void *addr, size_t length)
int V4L2CompatManager::ioctl(int fd, unsigned long request, void *arg)
{
- V4L2CameraProxy *proxy = getProxy(fd);
- if (!proxy)
+ std::shared_ptr<V4L2CameraFile> file = cameraFile(fd);
+ if (!file)
return fops_.ioctl(fd, request, arg);
- return proxy->ioctl(request, arg);
+ return file->proxy()->ioctl(file.get(), request, arg);
}