1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 class MessageReceiver : public Object { public: enum Status { NoMessage, InvalidThread, MessageReceived, }; MessageReceiver() : status_(NoMessage) { } Status status() const { return status_; } void reset() { status_ = NoMessage; } protected: void message(Message *msg) { if (thread() != Thread::current()) status_ = InvalidThread; else status_ = MessageReceived; } private: Status status_; }; class MessageTest : public Test { protected: int run() { Message::Type msgType[2] = { Message::registerMessageType(), Message::registerMessageType(), }; if (msgType[0] != Message::UserMessage || msgType[1] != Message::UserMessage + 1) {/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2019, Google Inc. * * v4l2_compat_manager.cpp - V4L2 compatibility manager */ #include "v4l2_compat_manager.h" #include <dlfcn.h> #include <fcntl.h> #include <map> #include <stdarg.h> #include <string.h> #include <sys/eventfd.h> #include <sys/mman.h> #include <sys/stat.h> #include <sys/sysmacros.h> #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 "v4l2_camera_file.h" using namespace libcamera; LOG_DEFINE_CATEGORY(V4L2Compat) namespace { template<typename T> void get_symbol(T &func, const char *name) { func = reinterpret_cast<T>(dlsym(RTLD_NEXT, name)); } } /* namespace */ V4L2CompatManager::V4L2CompatManager() : cm_(nullptr) { get_symbol(fops_.openat, "openat64"); get_symbol(fops_.dup, "dup"); get_symbol(fops_.close, "close"); get_symbol(fops_.ioctl, "ioctl"); get_symbol(fops_.mmap, "mmap64"); get_symbol(fops_.munmap, "munmap"); } V4L2CompatManager::~V4L2CompatManager() { files_.clear(); mmaps_.clear(); if (cm_) { proxies_.clear(); cm_->stop(); delete cm_; cm_ = nullptr; } } int V4L2CompatManager::start() { cm_ = new CameraManager(); int ret = cm_->start(); if (ret) { LOG(V4L2Compat, Error) << "Failed to start camera manager: " << strerror(-ret); delete cm_; cm_ = nullptr; return ret; } LOG(V4L2Compat, Debug) << "Started camera manager"; /* * For each Camera registered in the system, a V4L2CameraProxy gets * created here to wrap a camera device. */ auto cameras = cm_->cameras(); for (auto [index, camera] : utils::enumerate(cameras)) { V4L2CameraProxy *proxy = new V4L2CameraProxy(index, camera); proxies_.emplace_back(proxy); } return 0; } V4L2CompatManager *V4L2CompatManager::instance() { static V4L2CompatManager instance; return &instance; } std::shared_ptr<V4L2CameraFile> V4L2CompatManager::cameraFile(int fd) { auto file = files_.find(fd); if (file == files_.end()) return nullptr; return file->second; } int V4L2CompatManager::getCameraIndex(int fd) { struct stat statbuf; int ret = fstat(fd, &statbuf); if (ret < 0) return -1; std::shared_ptr<Camera> target = cm_->get(statbuf.st_rdev); if (!target) return -1; auto cameras = cm_->cameras(); for (auto [index, camera] : utils::enumerate(cameras)) { if (camera == target) return index; } return -1; } int V4L2CompatManager::openat(int dirfd, const char *path, int oflag, mode_t mode) { int fd = fops_.openat(dirfd, path, oflag, mode); if (fd < 0) return fd; struct stat statbuf; int ret = fstat(fd, &statbuf); if (ret < 0 || (statbuf.st_mode & S_IFMT) != S_IFCHR || major(statbuf.st_rdev) != 81) return fd; if (!cm_) start(); ret = getCameraIndex(fd); if (ret < 0) { LOG(V4L2Compat, Debug) << "No camera found for " << path; return fd; } fops_.close(fd); int efd = eventfd(0, EFD_SEMAPHORE | ((oflag & O_CLOEXEC) ? EFD_CLOEXEC : 0) | ((oflag & O_NONBLOCK) ? EFD_NONBLOCK : 0)); if (efd < 0) return efd; 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; } int V4L2CompatManager::dup(int oldfd) { int newfd = fops_.dup(oldfd); if (newfd < 0) return newfd; auto file = files_.find(oldfd); if (file != files_.end()) files_[newfd] = file->second; return newfd; } int V4L2CompatManager::close(int fd) { 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, off64_t offset) { std::shared_ptr<V4L2CameraFile> file = cameraFile(fd); if (!file) return fops_.mmap(addr, length, prot, flags, fd, offset); void *map = file->proxy()->mmap(file.get(), addr, length, prot, flags, offset); if (map == MAP_FAILED) return map; mmaps_[map] = file; return map; } int V4L2CompatManager::munmap(void *addr, size_t length) { auto device = mmaps_.find(addr); if (device == mmaps_.end()) return fops_.munmap(addr, length); V4L2CameraFile *file = device->second.get(); int ret = file->proxy()->munmap(file, addr, length); if (ret < 0) return ret; mmaps_.erase(device); return 0; } int V4L2CompatManager::ioctl(int fd, unsigned long request, void *arg) { std::shared_ptr<V4L2CameraFile> file = cameraFile(fd); if (!file) return fops_.ioctl(fd, request, arg); return file->proxy()->ioctl(file.get(), request, arg); } |