From patchwork Wed Jun 24 14:52:35 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 8399 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 4930760103 for ; Wed, 24 Jun 2020 16:53:18 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="jRjffJ5o"; dkim-atps=neutral Received: from jade.rasen.tech (unknown [IPv6:2400:4051:61:600:8147:f2a2:a8c6:9087]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id DA9142A8; Wed, 24 Jun 2020 16:53:15 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1593010397; bh=6mIM5PBpg8o0x92o8pBhs6mUlFj0aBmX5X01zeq6HVA=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=jRjffJ5oB/NACXdK3hFZnxSDgmUd9VpklFBBwo88nWwJvSZsLZaL9DyS8/s7lknfn XpUH1XnU+lz6Wfr92Q9pPe0VO/a3dNCmqmcRo/hF9+4VjfaB1ZWAvYhaZeisDGibYy /3Ql1gPVTe2Aa+ibLthprLquL1dukeoYqMQhjrTk= From: Paul Elder To: libcamera-devel@lists.libcamera.org Date: Wed, 24 Jun 2020 23:52:35 +0900 Message-Id: <20200624145256.48266-2-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20200624145256.48266-1-paul.elder@ideasonboard.com> References: <20200624145256.48266-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 01/22] v4l2: v4l2_camera_file: Add V4L2CameraFile to model the opened camera file X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 24 Jun 2020 14:53:18 -0000 With relation to opening files, the kernel has three objects related to files: - inodes, that represent files on disk - file objects, that are allocated at open() time and store all data related to the open file - file descriptors, that are integers that map to a file In the V4L2 compatibility layer, V4L2CameraProxy, which wraps a single libcamera camera via V4L2Camera, is more or less equivalent to the inode. We also already have file descriptors (that are really eventfds) that mirror the file descriptors. Here we create a V4L2CameraFile to model the file objects, to contain information related to the open file, namely if the file has been opened as non-blocking, and the V4L2 priority (to support VIDIOC_G/S_PRIORITY later on). This new class allows us to more cleanly support multiple open later on, since we can move out of V4L2CameraProxy the handling of mapping the fd to the open file information. Signed-off-by: Paul Elder Reviewed-by: Laurent Pinchart --- No change in v4 Changes in v3: - cosmetic changes - change public V4L2CameraFile::priority_ to private with public getter and setter New in v2 --- src/v4l2/meson.build | 1 + src/v4l2/v4l2_camera_file.cpp | 26 ++++++++++++++++++++++++ src/v4l2/v4l2_camera_file.h | 37 +++++++++++++++++++++++++++++++++++ 3 files changed, 64 insertions(+) create mode 100644 src/v4l2/v4l2_camera_file.cpp create mode 100644 src/v4l2/v4l2_camera_file.h diff --git a/src/v4l2/meson.build b/src/v4l2/meson.build index f2e4aaf..e3838f0 100644 --- a/src/v4l2/meson.build +++ b/src/v4l2/meson.build @@ -2,6 +2,7 @@ v4l2_compat_sources = files([ 'v4l2_camera.cpp', + 'v4l2_camera_file.cpp', 'v4l2_camera_proxy.cpp', 'v4l2_compat.cpp', 'v4l2_compat_manager.cpp', diff --git a/src/v4l2/v4l2_camera_file.cpp b/src/v4l2/v4l2_camera_file.cpp new file mode 100644 index 0000000..d3232ab --- /dev/null +++ b/src/v4l2/v4l2_camera_file.cpp @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2020, Google Inc. + * + * v4l2_camera_file.h - V4L2 compatibility camera file information + */ + +#include "v4l2_camera_file.h" + +#include + +#include "v4l2_camera_proxy.h" + +using namespace libcamera; + +V4L2CameraFile::V4L2CameraFile(int efd, bool nonBlocking, V4L2CameraProxy *proxy) + : proxy_(proxy), nonBlocking_(nonBlocking), efd_(efd), + priority_(V4L2_PRIORITY_DEFAULT) +{ + proxy_->open(nonBlocking); +} + +V4L2CameraFile::~V4L2CameraFile() +{ + proxy_->close(); +} diff --git a/src/v4l2/v4l2_camera_file.h b/src/v4l2/v4l2_camera_file.h new file mode 100644 index 0000000..8f4670a --- /dev/null +++ b/src/v4l2/v4l2_camera_file.h @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2020, Google Inc. + * + * v4l2_camera_file.h - V4L2 compatibility camera file information + */ + +#ifndef __V4L2_CAMERA_FILE_H__ +#define __V4L2_CAMERA_FILE_H__ + +#include + +class V4L2CameraProxy; + +class V4L2CameraFile +{ +public: + V4L2CameraFile(int efd, bool nonBlocking, V4L2CameraProxy *proxy); + ~V4L2CameraFile(); + + V4L2CameraProxy *proxy() const { return proxy_; } + + bool nonBlocking() const { return nonBlocking_; } + int efd() const { return efd_; } + + enum v4l2_priority priority() const { return priority_; } + void setPriority(enum v4l2_priority priority) { priority_ = priority; } + +private: + V4L2CameraProxy *proxy_; + + bool nonBlocking_; + int efd_; + enum v4l2_priority priority_; +}; + +#endif /* __V4L2_CAMERA_FILE_H__ */ From patchwork Wed Jun 24 14:52:36 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 8400 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id E13A1603B8 for ; Wed, 24 Jun 2020 16:53:20 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="Ak/ZIZbb"; dkim-atps=neutral Received: from jade.rasen.tech (unknown [IPv6:2400:4051:61:600:8147:f2a2:a8c6:9087]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id A16BC2A8; Wed, 24 Jun 2020 16:53:18 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1593010400; bh=4o2wBbXHPGTMfjiS1gqISl1+udDI2rb3ZfA07gyCPbU=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Ak/ZIZbb8KDfMdaDHLNxj8rrZMYZ/qACvdzlOwoImrqZwiz3UJT+VyP2UaFs+MZ5y YtjuTOAYhNM4+u2Nm+wU62ct5GmDdRcPTgBftsOhGddRW3drugi166y10nISga/jSe q6o20kTOBKeCUaEl/xNrCR9DGrWlWeXoxikU6D1E= From: Paul Elder To: libcamera-devel@lists.libcamera.org Date: Wed, 24 Jun 2020 23:52:36 +0900 Message-Id: <20200624145256.48266-3-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20200624145256.48266-1-paul.elder@ideasonboard.com> References: <20200624145256.48266-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 02/22] v4l2: V4L2CameraProxy: Take V4L2CameraFile as argument for intercepted calls X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 24 Jun 2020 14:53:21 -0000 Prepare for using the V4L2CameraFile as a container for file-specific information in the V4L2 compatibility layer by making it a required argument for all V4L2CameraProxy calls that are directed from V4L2CompatManager, which are intercepted via LD_PRELOAD. Change V4L2CameraFile accordingly. Also change V4L2CompatManager accordingly. Instead of keeping a map of file descriptors to V4L2CameraProxy instances, we keep a map of V4L2CameraFile instances to V4L2CameraProxy instances. When the proxy methods are called, feed the file as a parameter. The dup function is also modified, in that it is removed from V4L2CameraProxy, and is handled completely in V4L2CompatManager, as a map from file descriptors to V4L2CameraFile instances. Signed-off-by: Paul Elder Reviewed-by: Laurent Pinchart --- Changes in v4: - cosmetic changes New in v3 - split from "v4l2: v4l2_compat: Support multiple open" --- src/v4l2/v4l2_camera_file.cpp | 4 +- src/v4l2/v4l2_camera_proxy.cpp | 89 +++++++++++++++----------------- src/v4l2/v4l2_camera_proxy.h | 31 ++++++----- src/v4l2/v4l2_compat_manager.cpp | 66 ++++++++++------------- src/v4l2/v4l2_compat_manager.h | 4 +- 5 files changed, 88 insertions(+), 106 deletions(-) diff --git a/src/v4l2/v4l2_camera_file.cpp b/src/v4l2/v4l2_camera_file.cpp index d3232ab..a07679b 100644 --- a/src/v4l2/v4l2_camera_file.cpp +++ b/src/v4l2/v4l2_camera_file.cpp @@ -17,10 +17,10 @@ V4L2CameraFile::V4L2CameraFile(int efd, bool nonBlocking, V4L2CameraProxy *proxy : proxy_(proxy), nonBlocking_(nonBlocking), efd_(efd), priority_(V4L2_PRIORITY_DEFAULT) { - proxy_->open(nonBlocking); + proxy_->open(this); } V4L2CameraFile::~V4L2CameraFile() { - proxy_->close(); + proxy_->close(this); } diff --git a/src/v4l2/v4l2_camera_proxy.cpp b/src/v4l2/v4l2_camera_proxy.cpp index bf47aa7..ef3d062 100644 --- a/src/v4l2/v4l2_camera_proxy.cpp +++ b/src/v4l2/v4l2_camera_proxy.cpp @@ -23,6 +23,7 @@ #include "libcamera/internal/utils.h" #include "v4l2_camera.h" +#include "v4l2_camera_file.h" #include "v4l2_compat_manager.h" #define KERNEL_VERSION(a, b, c) (((a) << 16) + ((b) << 8) + (c)) @@ -39,9 +40,9 @@ V4L2CameraProxy::V4L2CameraProxy(unsigned int index, querycap(camera); } -int V4L2CameraProxy::open(bool nonBlocking) +int V4L2CameraProxy::open(V4L2CameraFile *file) { - LOG(V4L2Compat, Debug) << "Servicing open"; + LOG(V4L2Compat, Debug) << "Servicing open fd = " << file->efd(); int ret = vcam_->open(); if (ret < 0) { @@ -49,8 +50,6 @@ int V4L2CameraProxy::open(bool nonBlocking) return -1; } - nonBlocking_ = nonBlocking; - vcam_->getStreamConfig(&streamConfig_); setFmtFromConfig(streamConfig_); sizeimage_ = calculateSizeImage(streamConfig_); @@ -60,14 +59,10 @@ int V4L2CameraProxy::open(bool nonBlocking) return 0; } -void V4L2CameraProxy::dup() +void V4L2CameraProxy::close(V4L2CameraFile *file) { - refcount_++; -} + LOG(V4L2Compat, Debug) << "Servicing close fd = " << file->efd(); -void V4L2CameraProxy::close() -{ - LOG(V4L2Compat, Debug) << "Servicing close"; if (--refcount_ > 0) return; @@ -221,9 +216,9 @@ int V4L2CameraProxy::vidioc_querycap(struct v4l2_capability *arg) return 0; } -int V4L2CameraProxy::vidioc_enum_fmt(struct v4l2_fmtdesc *arg) +int V4L2CameraProxy::vidioc_enum_fmt(V4L2CameraFile *file, struct v4l2_fmtdesc *arg) { - LOG(V4L2Compat, Debug) << "Servicing vidioc_enum_fmt"; + LOG(V4L2Compat, Debug) << "Servicing vidioc_enum_fmt fd = " << file->efd(); if (!validateBufferType(arg->type) || arg->index >= streamConfig_.formats().pixelformats().size()) @@ -237,9 +232,9 @@ int V4L2CameraProxy::vidioc_enum_fmt(struct v4l2_fmtdesc *arg) return 0; } -int V4L2CameraProxy::vidioc_g_fmt(struct v4l2_format *arg) +int V4L2CameraProxy::vidioc_g_fmt(V4L2CameraFile *file, struct v4l2_format *arg) { - LOG(V4L2Compat, Debug) << "Servicing vidioc_g_fmt"; + LOG(V4L2Compat, Debug) << "Servicing vidioc_g_fmt fd = " << file->efd(); if (!validateBufferType(arg->type)) return -EINVAL; @@ -275,9 +270,9 @@ void V4L2CameraProxy::tryFormat(struct v4l2_format *arg) arg->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB; } -int V4L2CameraProxy::vidioc_s_fmt(struct v4l2_format *arg) +int V4L2CameraProxy::vidioc_s_fmt(V4L2CameraFile *file, struct v4l2_format *arg) { - LOG(V4L2Compat, Debug) << "Servicing vidioc_s_fmt"; + LOG(V4L2Compat, Debug) << "Servicing vidioc_s_fmt fd = " << file->efd(); if (!validateBufferType(arg->type)) return -EINVAL; @@ -302,9 +297,9 @@ int V4L2CameraProxy::vidioc_s_fmt(struct v4l2_format *arg) return 0; } -int V4L2CameraProxy::vidioc_try_fmt(struct v4l2_format *arg) +int V4L2CameraProxy::vidioc_try_fmt(V4L2CameraFile *file, struct v4l2_format *arg) { - LOG(V4L2Compat, Debug) << "Servicing vidioc_try_fmt"; + LOG(V4L2Compat, Debug) << "Servicing vidioc_try_fmt fd = " << file->efd(); if (!validateBufferType(arg->type)) return -EINVAL; @@ -329,11 +324,9 @@ int V4L2CameraProxy::freeBuffers() return 0; } -int V4L2CameraProxy::vidioc_reqbufs(struct v4l2_requestbuffers *arg) +int V4L2CameraProxy::vidioc_reqbufs(V4L2CameraFile *file, struct v4l2_requestbuffers *arg) { - int ret; - - LOG(V4L2Compat, Debug) << "Servicing vidioc_reqbufs"; + LOG(V4L2Compat, Debug) << "Servicing vidioc_reqbufs fd = " << file->efd(); if (!validateBufferType(arg->type) || !validateMemoryType(arg->memory)) @@ -347,9 +340,9 @@ int V4L2CameraProxy::vidioc_reqbufs(struct v4l2_requestbuffers *arg) return freeBuffers(); Size size(curV4L2Format_.fmt.pix.width, curV4L2Format_.fmt.pix.height); - ret = vcam_->configure(&streamConfig_, size, - v4l2ToDrm(curV4L2Format_.fmt.pix.pixelformat), - arg->count); + int ret = vcam_->configure(&streamConfig_, size, + v4l2ToDrm(curV4L2Format_.fmt.pix.pixelformat), + arg->count); if (ret < 0) return -EINVAL; @@ -396,9 +389,9 @@ int V4L2CameraProxy::vidioc_reqbufs(struct v4l2_requestbuffers *arg) return 0; } -int V4L2CameraProxy::vidioc_querybuf(struct v4l2_buffer *arg) +int V4L2CameraProxy::vidioc_querybuf(V4L2CameraFile *file, struct v4l2_buffer *arg) { - LOG(V4L2Compat, Debug) << "Servicing vidioc_querybuf"; + LOG(V4L2Compat, Debug) << "Servicing vidioc_querybuf fd = " << file->efd(); if (!validateBufferType(arg->type) || arg->index >= bufferCount_) @@ -411,10 +404,10 @@ int V4L2CameraProxy::vidioc_querybuf(struct v4l2_buffer *arg) return 0; } -int V4L2CameraProxy::vidioc_qbuf(struct v4l2_buffer *arg) +int V4L2CameraProxy::vidioc_qbuf(V4L2CameraFile *file, struct v4l2_buffer *arg) { LOG(V4L2Compat, Debug) << "Servicing vidioc_qbuf, index = " - << arg->index; + << arg->index << " fd = " << file->efd(); if (!validateBufferType(arg->type) || !validateMemoryType(arg->memory) || @@ -431,15 +424,15 @@ int V4L2CameraProxy::vidioc_qbuf(struct v4l2_buffer *arg) return ret; } -int V4L2CameraProxy::vidioc_dqbuf(struct v4l2_buffer *arg) +int V4L2CameraProxy::vidioc_dqbuf(V4L2CameraFile *file, struct v4l2_buffer *arg) { - LOG(V4L2Compat, Debug) << "Servicing vidioc_dqbuf"; + LOG(V4L2Compat, Debug) << "Servicing vidioc_dqbuf fd = " << file->efd(); if (!validateBufferType(arg->type) || !validateMemoryType(arg->memory)) return -EINVAL; - if (!nonBlocking_) + if (!file->nonBlocking()) vcam_->bufferSema_.acquire(); else if (!vcam_->bufferSema_.tryAcquire()) return -EAGAIN; @@ -455,16 +448,16 @@ int V4L2CameraProxy::vidioc_dqbuf(struct v4l2_buffer *arg) currentBuf_ = (currentBuf_ + 1) % bufferCount_; uint64_t data; - int ret = ::read(efd_, &data, sizeof(data)); + int ret = ::read(file->efd(), &data, sizeof(data)); if (ret != sizeof(data)) LOG(V4L2Compat, Error) << "Failed to clear eventfd POLLIN"; return 0; } -int V4L2CameraProxy::vidioc_streamon(int *arg) +int V4L2CameraProxy::vidioc_streamon(V4L2CameraFile *file, int *arg) { - LOG(V4L2Compat, Debug) << "Servicing vidioc_streamon"; + LOG(V4L2Compat, Debug) << "Servicing vidioc_streamon fd = " << file->efd(); if (!validateBufferType(*arg)) return -EINVAL; @@ -474,9 +467,9 @@ int V4L2CameraProxy::vidioc_streamon(int *arg) return vcam_->streamOn(); } -int V4L2CameraProxy::vidioc_streamoff(int *arg) +int V4L2CameraProxy::vidioc_streamoff(V4L2CameraFile *file, int *arg) { - LOG(V4L2Compat, Debug) << "Servicing vidioc_streamoff"; + LOG(V4L2Compat, Debug) << "Servicing vidioc_streamoff fd = " << file->efd(); if (!validateBufferType(*arg)) return -EINVAL; @@ -489,7 +482,7 @@ int V4L2CameraProxy::vidioc_streamoff(int *arg) return ret; } -int V4L2CameraProxy::ioctl(unsigned long request, void *arg) +int V4L2CameraProxy::ioctl(V4L2CameraFile *file, unsigned long request, void *arg) { int ret; switch (request) { @@ -497,34 +490,34 @@ int V4L2CameraProxy::ioctl(unsigned long request, void *arg) ret = vidioc_querycap(static_cast(arg)); break; case VIDIOC_ENUM_FMT: - ret = vidioc_enum_fmt(static_cast(arg)); + ret = vidioc_enum_fmt(file, static_cast(arg)); break; case VIDIOC_G_FMT: - ret = vidioc_g_fmt(static_cast(arg)); + ret = vidioc_g_fmt(file, static_cast(arg)); break; case VIDIOC_S_FMT: - ret = vidioc_s_fmt(static_cast(arg)); + ret = vidioc_s_fmt(file, static_cast(arg)); break; case VIDIOC_TRY_FMT: - ret = vidioc_try_fmt(static_cast(arg)); + ret = vidioc_try_fmt(file, static_cast(arg)); break; case VIDIOC_REQBUFS: - ret = vidioc_reqbufs(static_cast(arg)); + ret = vidioc_reqbufs(file, static_cast(arg)); break; case VIDIOC_QUERYBUF: - ret = vidioc_querybuf(static_cast(arg)); + ret = vidioc_querybuf(file, static_cast(arg)); break; case VIDIOC_QBUF: - ret = vidioc_qbuf(static_cast(arg)); + ret = vidioc_qbuf(file, static_cast(arg)); break; case VIDIOC_DQBUF: - ret = vidioc_dqbuf(static_cast(arg)); + ret = vidioc_dqbuf(file, static_cast(arg)); break; case VIDIOC_STREAMON: - ret = vidioc_streamon(static_cast(arg)); + ret = vidioc_streamon(file, static_cast(arg)); break; case VIDIOC_STREAMOFF: - ret = vidioc_streamoff(static_cast(arg)); + ret = vidioc_streamoff(file, static_cast(arg)); break; default: ret = -ENOTTY; diff --git a/src/v4l2/v4l2_camera_proxy.h b/src/v4l2/v4l2_camera_proxy.h index 27d3e50..b2197ef 100644 --- a/src/v4l2/v4l2_camera_proxy.h +++ b/src/v4l2/v4l2_camera_proxy.h @@ -21,20 +21,20 @@ using namespace libcamera; +class V4L2CameraFile; + class V4L2CameraProxy { public: V4L2CameraProxy(unsigned int index, std::shared_ptr camera); - int open(bool nonBlocking); - void dup(); - void close(); + int open(V4L2CameraFile *file); + void close(V4L2CameraFile *file); void *mmap(void *addr, size_t length, int prot, int flags, off64_t offset); int munmap(void *addr, size_t length); - int ioctl(unsigned long request, void *arg); - void bind(int fd); + int ioctl(V4L2CameraFile *file, unsigned long request, void *arg); private: bool validateBufferType(uint32_t type); @@ -47,16 +47,16 @@ private: int freeBuffers(); int vidioc_querycap(struct v4l2_capability *arg); - int vidioc_enum_fmt(struct v4l2_fmtdesc *arg); - int vidioc_g_fmt(struct v4l2_format *arg); - int vidioc_s_fmt(struct v4l2_format *arg); - int vidioc_try_fmt(struct v4l2_format *arg); - int vidioc_reqbufs(struct v4l2_requestbuffers *arg); - int vidioc_querybuf(struct v4l2_buffer *arg); - int vidioc_qbuf(struct v4l2_buffer *arg); - int vidioc_dqbuf(struct v4l2_buffer *arg); - int vidioc_streamon(int *arg); - int vidioc_streamoff(int *arg); + int vidioc_enum_fmt(V4L2CameraFile *file, struct v4l2_fmtdesc *arg); + int vidioc_g_fmt(V4L2CameraFile *file, struct v4l2_format *arg); + int vidioc_s_fmt(V4L2CameraFile *file, struct v4l2_format *arg); + int vidioc_try_fmt(V4L2CameraFile *file, struct v4l2_format *arg); + int vidioc_reqbufs(V4L2CameraFile *file, struct v4l2_requestbuffers *arg); + int vidioc_querybuf(V4L2CameraFile *file, struct v4l2_buffer *arg); + int vidioc_qbuf(V4L2CameraFile *file, struct v4l2_buffer *arg); + int vidioc_dqbuf(V4L2CameraFile *file, struct v4l2_buffer *arg); + int vidioc_streamon(V4L2CameraFile *file, int *arg); + int vidioc_streamoff(V4L2CameraFile *file, int *arg); static unsigned int bplMultiplier(uint32_t format); static unsigned int imageSize(uint32_t format, unsigned int width, @@ -67,7 +67,6 @@ private: unsigned int refcount_; unsigned int index_; - bool nonBlocking_; struct v4l2_format curV4L2Format_; StreamConfiguration streamConfig_; diff --git a/src/v4l2/v4l2_compat_manager.cpp b/src/v4l2/v4l2_compat_manager.cpp index 8da3316..90c0f01 100644 --- a/src/v4l2/v4l2_compat_manager.cpp +++ b/src/v4l2/v4l2_compat_manager.cpp @@ -24,6 +24,8 @@ #include "libcamera/internal/log.h" +#include "v4l2_camera_file.h" + using namespace libcamera; LOG_DEFINE_CATEGORY(V4L2Compat) @@ -49,7 +51,7 @@ V4L2CompatManager::V4L2CompatManager() V4L2CompatManager::~V4L2CompatManager() { - devices_.clear(); + files_.clear(); mmaps_.clear(); if (cm_) { @@ -95,13 +97,13 @@ V4L2CompatManager *V4L2CompatManager::instance() return &instance; } -V4L2CameraProxy *V4L2CompatManager::getProxy(int fd) +std::shared_ptr 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) @@ -148,25 +150,14 @@ int V4L2CompatManager::openat(int dirfd, const char *path, int oflag, mode_t mod fops_.close(fd); - unsigned int camera_index = static_cast(ret); - - V4L2CameraProxy *proxy = proxies_[camera_index].get(); - ret = proxy->open(oflag & O_NONBLOCK); - if (ret < 0) - return ret; - int efd = eventfd(0, EFD_SEMAPHORE | ((oflag & O_CLOEXEC) ? EFD_CLOEXEC : 0) | ((oflag & O_NONBLOCK) ? EFD_NONBLOCK : 0)); - if (efd < 0) { - int err = errno; - proxy->close(); - errno = err; + if (efd < 0) return efd; - } - proxy->bind(efd); - devices_.emplace(efd, proxy); + V4L2CameraProxy *proxy = proxies_[ret].get(); + files_.emplace(efd, std::make_shared(efd, oflag & O_NONBLOCK, proxy)); return efd; } @@ -177,40 +168,39 @@ 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, off64_t offset) { - V4L2CameraProxy *proxy = getProxy(fd); - if (!proxy) + std::shared_ptr 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(addr, length, prot, flags, offset); if (map == MAP_FAILED) return map; - mmaps_[map] = proxy; + /* + * Map to V4L2CameraProxy directly to prevent adding more references + * to V4L2CameraFile. + */ + mmaps_[map] = file->proxy(); return map; } @@ -233,9 +223,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 file = cameraFile(fd); + if (!file) return fops_.ioctl(fd, request, arg); - return proxy->ioctl(request, arg); + return file->proxy()->ioctl(file.get(), request, arg); } diff --git a/src/v4l2/v4l2_compat_manager.h b/src/v4l2/v4l2_compat_manager.h index 3d4e512..bc548ab 100644 --- a/src/v4l2/v4l2_compat_manager.h +++ b/src/v4l2/v4l2_compat_manager.h @@ -44,7 +44,6 @@ public: static V4L2CompatManager *instance(); - V4L2CameraProxy *getProxy(int fd); const FileOperations &fops() const { return fops_; } int openat(int dirfd, const char *path, int oflag, mode_t mode); @@ -62,13 +61,14 @@ private: int start(); int getCameraIndex(int fd); + std::shared_ptr cameraFile(int fd); FileOperations fops_; CameraManager *cm_; std::vector> proxies_; - std::map devices_; + std::map> files_; std::map mmaps_; }; From patchwork Wed Jun 24 14:52:37 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 8401 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 18F75603B8 for ; Wed, 24 Jun 2020 16:53:23 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="QweyTC3f"; dkim-atps=neutral Received: from jade.rasen.tech (unknown [IPv6:2400:4051:61:600:8147:f2a2:a8c6:9087]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 4ED982A8; Wed, 24 Jun 2020 16:53:21 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1593010402; bh=f9gj0pOEGH1eClO6WWDw87amxovsW33yeoqFhCfrTIE=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=QweyTC3f3SQYmfg/TDxU7oG+gbMOVWBlAnbMp/ZCLr/T9QJjP2G9yjwObcw5LvoAB HIOTppF1FoXNQyRgFP38xDYkVUp77o8CxZTs2TjxOPl8LIdf/uvAf3FXpC+5F5jNT2 6cIsFAgyxAqDQ7QIY1JS/erIB1qfkJfHg1zV3//U= From: Paul Elder To: libcamera-devel@lists.libcamera.org Date: Wed, 24 Jun 2020 23:52:37 +0900 Message-Id: <20200624145256.48266-4-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20200624145256.48266-1-paul.elder@ideasonboard.com> References: <20200624145256.48266-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 03/22] v4l2: v4l2_compat: Support multiple open X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 24 Jun 2020 14:53:23 -0000 Previously, since we acquired the libcamera camera upon open(), it was impossible to support multiple open, as any subsequent opens would return error because the camera would already be acquired. To fix this, we first initialize the camera in the first call to V4L2CameraProxy::open(), just to heat up the stream format cache. We then add ownership by a V4L2CameraFile of a V4L2Camera via the V4L2CameraProxy. All vidioc ioctls prior to reqbufs > 0 (except for s_fmt) are able to access the camera without ownership. A call to reqbufs > 0 (and s_fmt) will take ownership, and the ownership will be released at reqbufs = 0. While ownership is assigned, the eventfd that should be signaled (and cleared) by V4L2Camera and V4L2CameraProxy is set to the V4L2CameraFile that has ownership, and is cleared when the ownership is released. In case close() is called without a reqbufs = 0 first, the ownership is also released on close(). We also use the V4L2CameraFile to contain all the information specific to an open instance of the file. This removes the need to keep track of such information within V4L2CameraProxy via multiple maps from int fd to info. Since V4L2 does not expect reqbufs 0 to ever return error, make V4L2CameraProxy::freeBuffers() return void. Signed-off-by: Paul Elder Reviewed-by: Laurent Pinchart --- Changes in v4: - return void from V4L2CameraProxy::freeBuffers() - acquire ownership at the end of V4L2CameraProxy::vidioc_reqbufs, instead of at beginning Changes in v3: - split V4L2CompatManager stuff into separate patch - split changing the fd argument to camera file argument in all proxy methods into the separate patch - remove V4L2CameraProxy::efd_ (it's duplicated from V4L2CameraFile::efd()) - rename cf in all the V4L2CameraProxy methods to file - rename V4L2CameraProxy::acquiredCf_ to V4L2CameraProxy::owner_ - remove V4L2CameraProxy::initialized_; just use V4L2CameraProxy::refcount_ - move bufferCount_ > 0 in reqbufs to different patch - move TIMESTAMP_MONOTONIC to different patch - don't take the lock for querybuf - add V4L2CameraProxy::hasOwnership - rename lock() to acquire() and unlock() to release() - only lock on s_fmt and reqbufs > 0, in other ioctls only check for ownership - add explanation about not supporting polling for events from an fd different than the one that owns the device for polling for bufs Changes in v2: - use V4L2CameraFile in V4L2CompatManager to deal with dup, and in V4L2CameraProxy to deal with information specific to the open file (nonblock and priority) - unlock exclusive camera lock on close() --- src/v4l2/v4l2_camera.cpp | 9 ++- src/v4l2/v4l2_camera.h | 1 + src/v4l2/v4l2_camera_proxy.cpp | 109 +++++++++++++++++++++++++++------ src/v4l2/v4l2_camera_proxy.h | 18 +++++- 4 files changed, 113 insertions(+), 24 deletions(-) diff --git a/src/v4l2/v4l2_camera.cpp b/src/v4l2/v4l2_camera.cpp index 9a1ebc8..2557320 100644 --- a/src/v4l2/v4l2_camera.cpp +++ b/src/v4l2/v4l2_camera.cpp @@ -17,7 +17,8 @@ using namespace libcamera; LOG_DECLARE_CATEGORY(V4L2Compat); V4L2Camera::V4L2Camera(std::shared_ptr camera) - : camera_(camera), isRunning_(false), bufferAllocator_(nullptr) + : camera_(camera), isRunning_(false), bufferAllocator_(nullptr), + efd_(-1) { camera_->requestCompleted.connect(this, &V4L2Camera::requestComplete); } @@ -29,7 +30,6 @@ V4L2Camera::~V4L2Camera() int V4L2Camera::open() { - /* \todo Support multiple open. */ if (camera_->acquire() < 0) { LOG(V4L2Compat, Error) << "Failed to acquire camera"; return -EINVAL; @@ -59,6 +59,11 @@ void V4L2Camera::bind(int efd) efd_ = efd; } +void V4L2Camera::unbind() +{ + efd_ = -1; +} + void V4L2Camera::getStreamConfig(StreamConfiguration *streamConfig) { *streamConfig = config_->at(0); diff --git a/src/v4l2/v4l2_camera.h b/src/v4l2/v4l2_camera.h index 33f5eb0..30114ed 100644 --- a/src/v4l2/v4l2_camera.h +++ b/src/v4l2/v4l2_camera.h @@ -40,6 +40,7 @@ public: int open(); void close(); void bind(int efd); + void unbind(); void getStreamConfig(StreamConfiguration *streamConfig); std::vector completedBuffers(); diff --git a/src/v4l2/v4l2_camera_proxy.cpp b/src/v4l2/v4l2_camera_proxy.cpp index ef3d062..240420c 100644 --- a/src/v4l2/v4l2_camera_proxy.cpp +++ b/src/v4l2/v4l2_camera_proxy.cpp @@ -35,7 +35,7 @@ LOG_DECLARE_CATEGORY(V4L2Compat); V4L2CameraProxy::V4L2CameraProxy(unsigned int index, std::shared_ptr camera) : refcount_(0), index_(index), bufferCount_(0), currentBuf_(0), - vcam_(std::make_unique(camera)) + vcam_(std::make_unique(camera)), owner_(nullptr) { querycap(camera); } @@ -44,18 +44,29 @@ int V4L2CameraProxy::open(V4L2CameraFile *file) { LOG(V4L2Compat, Debug) << "Servicing open fd = " << file->efd(); + if (refcount_++) + return 0; + + /* + * We open the camera here, once, and keep it open until the last + * V4L2CameraFile is closed. The proxy is initially not owned by any + * file. The first file that calls reqbufs with count > 0 or s_fmt + * will become the owner, and no other file will be allowed to call + * buffer-related ioctls (except querybuf), set the format, or start or + * stop the stream until ownership is released with a call to reqbufs + * with count = 0. + */ + int ret = vcam_->open(); if (ret < 0) { - errno = -ret; - return -1; + refcount_--; + return ret; } vcam_->getStreamConfig(&streamConfig_); setFmtFromConfig(streamConfig_); sizeimage_ = calculateSizeImage(streamConfig_); - refcount_++; - return 0; } @@ -63,6 +74,7 @@ void V4L2CameraProxy::close(V4L2CameraFile *file) { LOG(V4L2Compat, Debug) << "Servicing close fd = " << file->efd(); + release(file); if (--refcount_ > 0) return; @@ -277,12 +289,16 @@ int V4L2CameraProxy::vidioc_s_fmt(V4L2CameraFile *file, struct v4l2_format *arg) if (!validateBufferType(arg->type)) return -EINVAL; + int ret = acquire(file); + if (ret < 0) + return ret; + tryFormat(arg); Size size(arg->fmt.pix.width, arg->fmt.pix.height); - int ret = vcam_->configure(&streamConfig_, size, - v4l2ToDrm(arg->fmt.pix.pixelformat), - bufferCount_); + ret = vcam_->configure(&streamConfig_, size, + v4l2ToDrm(arg->fmt.pix.pixelformat), + bufferCount_); if (ret < 0) return -EINVAL; @@ -309,19 +325,16 @@ int V4L2CameraProxy::vidioc_try_fmt(V4L2CameraFile *file, struct v4l2_format *ar return 0; } -int V4L2CameraProxy::freeBuffers() +void V4L2CameraProxy::freeBuffers() { LOG(V4L2Compat, Debug) << "Freeing libcamera bufs"; int ret = vcam_->streamOff(); - if (ret < 0) { + if (ret < 0) LOG(V4L2Compat, Error) << "Failed to stop stream"; - return ret; - } + vcam_->freeBuffers(); bufferCount_ = 0; - - return 0; } int V4L2CameraProxy::vidioc_reqbufs(V4L2CameraFile *file, struct v4l2_requestbuffers *arg) @@ -334,10 +347,17 @@ int V4L2CameraProxy::vidioc_reqbufs(V4L2CameraFile *file, struct v4l2_requestbuf LOG(V4L2Compat, Debug) << arg->count << " buffers requested "; + if (!hasOwnership(file) && owner_) + return -EBUSY; + arg->capabilities = V4L2_BUF_CAP_SUPPORTS_MMAP; - if (arg->count == 0) - return freeBuffers(); + if (arg->count == 0) { + freeBuffers(); + release(file); + + return 0; + } Size size(curV4L2Format_.fmt.pix.width, curV4L2Format_.fmt.pix.height); int ret = vcam_->configure(&streamConfig_, size, @@ -386,6 +406,10 @@ int V4L2CameraProxy::vidioc_reqbufs(V4L2CameraFile *file, struct v4l2_requestbuf LOG(V4L2Compat, Debug) << "Allocated " << arg->count << " buffers"; + ret = acquire(file); + if (ret < 0) + return ret; + return 0; } @@ -409,6 +433,9 @@ int V4L2CameraProxy::vidioc_qbuf(V4L2CameraFile *file, struct v4l2_buffer *arg) LOG(V4L2Compat, Debug) << "Servicing vidioc_qbuf, index = " << arg->index << " fd = " << file->efd(); + if (!hasOwnership(file)) + return -EBUSY; + if (!validateBufferType(arg->type) || !validateMemoryType(arg->memory) || arg->index >= bufferCount_) @@ -428,6 +455,9 @@ int V4L2CameraProxy::vidioc_dqbuf(V4L2CameraFile *file, struct v4l2_buffer *arg) { LOG(V4L2Compat, Debug) << "Servicing vidioc_dqbuf fd = " << file->efd(); + if (!hasOwnership(file)) + return -EBUSY; + if (!validateBufferType(arg->type) || !validateMemoryType(arg->memory)) return -EINVAL; @@ -462,6 +492,9 @@ int V4L2CameraProxy::vidioc_streamon(V4L2CameraFile *file, int *arg) if (!validateBufferType(*arg)) return -EINVAL; + if (!hasOwnership(file)) + return -EBUSY; + currentBuf_ = 0; return vcam_->streamOn(); @@ -474,6 +507,9 @@ int V4L2CameraProxy::vidioc_streamoff(V4L2CameraFile *file, int *arg) if (!validateBufferType(*arg)) return -EINVAL; + if (!hasOwnership(file) && owner_) + return -EBUSY; + int ret = vcam_->streamOff(); for (struct v4l2_buffer &buf : buffers_) @@ -532,10 +568,45 @@ int V4L2CameraProxy::ioctl(V4L2CameraFile *file, unsigned long request, void *ar return ret; } -void V4L2CameraProxy::bind(int fd) +bool V4L2CameraProxy::hasOwnership(V4L2CameraFile *file) +{ + return owner_ == file; +} + +/** + * \brief Acquire exclusive ownership of the V4L2Camera + * + * \return Zero on success or if already acquired, and negative error on + * failure. + * + * This is sufficient for poll()ing for buffers. Events, however, are signaled + * on the file level, so all fds must be signaled. poll()ing from a different + * fd than the one that locks the device is a corner case, and is currently not + * supported. + */ +int V4L2CameraProxy::acquire(V4L2CameraFile *file) +{ + if (owner_ == file) + return 0; + + if (owner_) + return -EBUSY; + + vcam_->bind(file->efd()); + + owner_ = file; + + return 0; +} + +void V4L2CameraProxy::release(V4L2CameraFile *file) { - efd_ = fd; - vcam_->bind(fd); + if (owner_ != file) + return; + + vcam_->unbind(); + + owner_ = nullptr; } struct PixelFormatPlaneInfo { diff --git a/src/v4l2/v4l2_camera_proxy.h b/src/v4l2/v4l2_camera_proxy.h index b2197ef..36d1dbc 100644 --- a/src/v4l2/v4l2_camera_proxy.h +++ b/src/v4l2/v4l2_camera_proxy.h @@ -33,7 +33,6 @@ public: void *mmap(void *addr, size_t length, int prot, int flags, off64_t offset); int munmap(void *addr, size_t length); - void bind(int fd); int ioctl(V4L2CameraFile *file, unsigned long request, void *arg); private: @@ -44,7 +43,7 @@ private: void querycap(std::shared_ptr camera); void tryFormat(struct v4l2_format *arg); void updateBuffers(); - int freeBuffers(); + void freeBuffers(); int vidioc_querycap(struct v4l2_capability *arg); int vidioc_enum_fmt(V4L2CameraFile *file, struct v4l2_fmtdesc *arg); @@ -58,6 +57,10 @@ private: int vidioc_streamon(V4L2CameraFile *file, int *arg); int vidioc_streamoff(V4L2CameraFile *file, int *arg); + bool hasOwnership(V4L2CameraFile *file); + int acquire(V4L2CameraFile *file); + void release(V4L2CameraFile *file); + static unsigned int bplMultiplier(uint32_t format); static unsigned int imageSize(uint32_t format, unsigned int width, unsigned int height); @@ -80,7 +83,16 @@ private: std::unique_ptr vcam_; - int efd_; + /* + * This is the exclusive owner of this V4L2CameraProxy instance. + * When there is no owner, anybody can call any ioctl before reqbufs. + * The first file to call reqbufs with count > 0 or s_fmt will become + * the owner, and when the owner calls reqbufs with count = 0 it will + * release ownership. Any buffer-related ioctl (except querybuf) or + * s_fmt that is called by a non-owner while there exists an owner + * will return -EBUSY. + */ + V4L2CameraFile *owner_; }; #endif /* __V4L2_CAMERA_PROXY_H__ */ From patchwork Wed Jun 24 14:52:38 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 8402 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 7FCDD609B3 for ; Wed, 24 Jun 2020 16:53:25 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="mRhdKTve"; dkim-atps=neutral Received: from jade.rasen.tech (unknown [IPv6:2400:4051:61:600:8147:f2a2:a8c6:9087]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id A550D2A8; Wed, 24 Jun 2020 16:53:23 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1593010405; bh=fjl37sOhCxIzztCUNmlsV53bSzFFBIYNv4n3UqLHj2g=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=mRhdKTveI1gEjg88bDeWeGevig9ovGw7XYGA4vo7dcn0Qm7qdwZoom0GCNSXMhMa8 nJ0Y7LdylzNAPxYeFf0TnQg33FdOMJIVG+6PhIh+RqS+J7y+E5eT4bwzH/GkrmGrWd 9GhIy40oWxgWCr8ScUWkAREN0rCiu/0NA64F3NVs= From: Paul Elder To: libcamera-devel@lists.libcamera.org Date: Wed, 24 Jun 2020 23:52:38 +0900 Message-Id: <20200624145256.48266-5-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20200624145256.48266-1-paul.elder@ideasonboard.com> References: <20200624145256.48266-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 04/22] v4l2: v4l2_camera_proxy: Free old buffers on reqbufs > 0 X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 24 Jun 2020 14:53:25 -0000 Free buffers, if any were previously allocated, at VIDIOC_REQBUFS with count > 0. Signed-off-by: Paul Elder Reviewed-by: Laurent Pinchart --- Changes in v4: - don't check return value of V4L2CameraProxy::freeBuffers() New in v3 - split from... a conglomerate of v4l2-compliance fixes patch --- src/v4l2/v4l2_camera_proxy.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/v4l2/v4l2_camera_proxy.cpp b/src/v4l2/v4l2_camera_proxy.cpp index 240420c..c6959a8 100644 --- a/src/v4l2/v4l2_camera_proxy.cpp +++ b/src/v4l2/v4l2_camera_proxy.cpp @@ -359,6 +359,9 @@ int V4L2CameraProxy::vidioc_reqbufs(V4L2CameraFile *file, struct v4l2_requestbuf return 0; } + if (bufferCount_ > 0) + freeBuffers(); + Size size(curV4L2Format_.fmt.pix.width, curV4L2Format_.fmt.pix.height); int ret = vcam_->configure(&streamConfig_, size, v4l2ToDrm(curV4L2Format_.fmt.pix.pixelformat), From patchwork Wed Jun 24 14:52:39 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 8403 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id E0A0A60103 for ; Wed, 24 Jun 2020 16:53:27 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="Son+x29Q"; dkim-atps=neutral Received: from jade.rasen.tech (unknown [IPv6:2400:4051:61:600:8147:f2a2:a8c6:9087]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 21105595; Wed, 24 Jun 2020 16:53:25 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1593010407; bh=10rnG1+6roTsr6CpxLQpAkWRmLAn+20b1gdT54FlRK0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Son+x29QAW3di2W/Jc0bUqrSaV3E2ai5pr4zg5gxBsLJpT+u+MNUPJVHBCRIQQC7Y ezrSIhfqENyS0b0vdIQxBpnIwQmIxQPkPT8ojj6IPY/LkO8y/7sY3CNmbRHceafi8K 1hiFmL9hiiw/XGz1cW/s1kNJzc9Qx1jjcFeIvyiM= From: Paul Elder To: libcamera-devel@lists.libcamera.org Date: Wed, 24 Jun 2020 23:52:39 +0900 Message-Id: <20200624145256.48266-6-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20200624145256.48266-1-paul.elder@ideasonboard.com> References: <20200624145256.48266-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 05/22] v4l2: v4l2_camera_proxy: Clear reserved field in reqbufs X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 24 Jun 2020 14:53:28 -0000 Clear the reserved field in arg struct v4l2_reqbuffers of VIDIOC_REQBUFS. Signed-off-by: Paul Elder Reviewed-by: Laurent Pinchart --- No change in v4 New in v3 - split from a conglomerate of v4l2-compliance fixes patch --- src/v4l2/v4l2_camera_proxy.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/v4l2/v4l2_camera_proxy.cpp b/src/v4l2/v4l2_camera_proxy.cpp index c6959a8..3d6703a 100644 --- a/src/v4l2/v4l2_camera_proxy.cpp +++ b/src/v4l2/v4l2_camera_proxy.cpp @@ -351,6 +351,7 @@ int V4L2CameraProxy::vidioc_reqbufs(V4L2CameraFile *file, struct v4l2_requestbuf return -EBUSY; arg->capabilities = V4L2_BUF_CAP_SUPPORTS_MMAP; + memset(arg->reserved, 0, sizeof(arg->reserved)); if (arg->count == 0) { freeBuffers(); From patchwork Wed Jun 24 14:52:40 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 8404 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 06EE860103 for ; Wed, 24 Jun 2020 16:53:30 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="en6zBNCo"; dkim-atps=neutral Received: from jade.rasen.tech (unknown [IPv6:2400:4051:61:600:8147:f2a2:a8c6:9087]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 45BC32A8; Wed, 24 Jun 2020 16:53:28 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1593010409; bh=4nj7erCdTKzQRtlUFk4Io6Ek2Vh+EReJHKfP5CiXHQY=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=en6zBNCov41fwVfFmPmHdF8KPVzDGZec7rrrsYhtNvn5Amr0IBlBcFahTDooKaB1d uzBDNJSNj5ASK4XfBoLroMDEKh4jjQ77GZqRY740htsAgFJSp1O2Y6xPuw/0m+iibq 8JU/4ywoKlk2pu4GECFvVKP4FcBmOy/Gfekou1LM= From: Paul Elder To: libcamera-devel@lists.libcamera.org Date: Wed, 24 Jun 2020 23:52:40 +0900 Message-Id: <20200624145256.48266-7-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20200624145256.48266-1-paul.elder@ideasonboard.com> References: <20200624145256.48266-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 06/22] v4l2: v4l2_camera_proxy: Set timestamp monotonic buffer flag on reqbufs X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 24 Jun 2020 14:53:30 -0000 Set buffer flag V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC at VIDIOC_REQBUFS after the buffers have been allocated. Signed-off-by: Paul Elder --- No change in v4 New in v3 - split from a conglomerate of v4l2-compliance fixes patch --- src/v4l2/v4l2_camera_proxy.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/v4l2/v4l2_camera_proxy.cpp b/src/v4l2/v4l2_camera_proxy.cpp index 3d6703a..66feb77 100644 --- a/src/v4l2/v4l2_camera_proxy.cpp +++ b/src/v4l2/v4l2_camera_proxy.cpp @@ -404,6 +404,7 @@ int V4L2CameraProxy::vidioc_reqbufs(V4L2CameraFile *file, struct v4l2_requestbuf buf.memory = V4L2_MEMORY_MMAP; buf.m.offset = i * curV4L2Format_.fmt.pix.sizeimage; buf.index = i; + buf.flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; buffers_[i] = buf; } From patchwork Wed Jun 24 14:52:41 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 8405 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 5AED460103 for ; Wed, 24 Jun 2020 16:53:32 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="sCg0us9d"; dkim-atps=neutral Received: from jade.rasen.tech (unknown [IPv6:2400:4051:61:600:8147:f2a2:a8c6:9087]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 6AACB2A8; Wed, 24 Jun 2020 16:53:30 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1593010411; bh=G36meBW3/oabvoBeWi92FPqTWw9anNR8EVNw9Ert6l8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=sCg0us9d7VMBotLFcJQUNmbLnZVtOXSrk6u9LjkCb8AlLAwaHLSNhs2KODPRekDSa cBHjVgGWCfrIcsM6fQpOgNWrr6SrKXWe5TJSQ+Xcxo35j/g+MpglqT6MF43TlNZB2N nf2Z+q3OPqbAiAGRpU3DrD1ue3yhW5lNr4YAdqXg= From: Paul Elder To: libcamera-devel@lists.libcamera.org Date: Wed, 24 Jun 2020 23:52:41 +0900 Message-Id: <20200624145256.48266-8-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20200624145256.48266-1-paul.elder@ideasonboard.com> References: <20200624145256.48266-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 07/22] v4l2: v4l2_camera_proxy: Check for null arg values in main ioctl handler X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 24 Jun 2020 14:53:32 -0000 The ioctl handlers currently don't check if arg is null, so if it ever is, it will cause a segfault. Check that arg is null and return -EFAULT in the main vidioc ioctl handler. Signed-off-by: Paul Elder Reviewed-by: Laurent Pinchart --- No change in v4 Changes in v3: - check ioctl rw flags for proper return value error - cosmetic changes Changes in v2: - moved !arg check to main ioctl handler, and added a set of supported ioctls - use !arg instead of arg == nullptr --- src/v4l2/v4l2_camera_proxy.cpp | 30 ++++++++++++++++++++++++++++++ src/v4l2/v4l2_camera_proxy.h | 3 +++ 2 files changed, 33 insertions(+) diff --git a/src/v4l2/v4l2_camera_proxy.cpp b/src/v4l2/v4l2_camera_proxy.cpp index 66feb77..011e4a4 100644 --- a/src/v4l2/v4l2_camera_proxy.cpp +++ b/src/v4l2/v4l2_camera_proxy.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -523,8 +524,37 @@ int V4L2CameraProxy::vidioc_streamoff(V4L2CameraFile *file, int *arg) return ret; } +const std::set V4L2CameraProxy::supportedIoctls_ = { + VIDIOC_QUERYCAP, + VIDIOC_ENUM_FMT, + VIDIOC_G_FMT, + VIDIOC_S_FMT, + VIDIOC_TRY_FMT, + VIDIOC_REQBUFS, + VIDIOC_QUERYBUF, + VIDIOC_QBUF, + VIDIOC_DQBUF, + VIDIOC_STREAMON, + VIDIOC_STREAMOFF, +}; + int V4L2CameraProxy::ioctl(V4L2CameraFile *file, unsigned long request, void *arg) { + if (!arg && (_IOC_DIR(request) & _IOC_WRITE)) { + errno = EFAULT; + return -1; + } + + if (supportedIoctls_.find(request) == supportedIoctls_.end()) { + errno = ENOTTY; + return -1; + } + + if (!arg && (_IOC_DIR(request) & _IOC_READ)) { + errno = EFAULT; + return -1; + } + int ret; switch (request) { case VIDIOC_QUERYCAP: diff --git a/src/v4l2/v4l2_camera_proxy.h b/src/v4l2/v4l2_camera_proxy.h index 36d1dbc..86c1a7d 100644 --- a/src/v4l2/v4l2_camera_proxy.h +++ b/src/v4l2/v4l2_camera_proxy.h @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -68,6 +69,8 @@ private: static PixelFormat v4l2ToDrm(uint32_t format); static uint32_t drmToV4L2(const PixelFormat &format); + static const std::set supportedIoctls_; + unsigned int refcount_; unsigned int index_; From patchwork Wed Jun 24 14:52:42 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 8406 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 4761A60103 for ; Wed, 24 Jun 2020 16:53:35 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="VaDkki/E"; dkim-atps=neutral Received: from jade.rasen.tech (unknown [IPv6:2400:4051:61:600:8147:f2a2:a8c6:9087]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id DA4D32A8; Wed, 24 Jun 2020 16:53:32 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1593010415; bh=hMhoFSNYXhsi7/Z1kQATMyjKSSR31SVZzF85QPUEuMA=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=VaDkki/EyMDkddmftJmvD5BP82YCVK24cafhTpp+fuvGDoS84Lxt1KBKzkbIvnjtx 6k1qDfRgVoSBq0NXLeexoQZaOEcBsXLc9iTkh2nabVaSu0TsmLPy/tZFsgZc9Mx45Y Ds0sRO02qn8k1XuHVajR9LiFW03Xe1d+boA+1ZPs= From: Paul Elder To: libcamera-devel@lists.libcamera.org Date: Wed, 24 Jun 2020 23:52:42 +0900 Message-Id: <20200624145256.48266-9-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20200624145256.48266-1-paul.elder@ideasonboard.com> References: <20200624145256.48266-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 08/22] v4l2: v4l2_camera_proxy: Fix v4l2-compliance support for extended formats X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 24 Jun 2020 14:53:35 -0000 Fix the following v4l2-compliance error: fail: v4l2-compliance.cpp(652): !(caps & V4L2_CAP_EXT_PIX_FORMAT) Simply add V4L2_CAP_EXT_PIX_FORMAT to capabilities in querycap. In addition, populate the necessary fields in struct v4l2_pix_format to support extended pixel formats in try_fmt and g/s_fmt, and clear the reserved field for enum_fmt. Signed-off-by: Paul Elder Acked-by: Jacopo Mondi Reviewed-by: Laurent Pinchart --- No change in v4 Changes in v3: - also populate xfer_func Changes in v2: - squashed the "Fix v4l2-compliance format tests" into this one, since those fixes were a necessity of this fix (plus they're related) - use _DEFAULT for ycbcr_enc and quantization --- src/v4l2/v4l2_camera_proxy.cpp | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/v4l2/v4l2_camera_proxy.cpp b/src/v4l2/v4l2_camera_proxy.cpp index 011e4a4..ad9fa84 100644 --- a/src/v4l2/v4l2_camera_proxy.cpp +++ b/src/v4l2/v4l2_camera_proxy.cpp @@ -162,6 +162,10 @@ void V4L2CameraProxy::setFmtFromConfig(StreamConfiguration &streamConfig) curV4L2Format_.fmt.pix.width, curV4L2Format_.fmt.pix.height); curV4L2Format_.fmt.pix.colorspace = V4L2_COLORSPACE_SRGB; + curV4L2Format_.fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC; + curV4L2Format_.fmt.pix.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; + curV4L2Format_.fmt.pix.quantization = V4L2_QUANTIZATION_DEFAULT; + curV4L2Format_.fmt.pix.xfer_func = V4L2_XFER_FUNC_DEFAULT; } unsigned int V4L2CameraProxy::calculateSizeImage(StreamConfiguration &streamConfig) @@ -188,7 +192,9 @@ void V4L2CameraProxy::querycap(std::shared_ptr camera) sizeof(capabilities_.bus_info)); /* \todo Put this in a header/config somewhere. */ capabilities_.version = KERNEL_VERSION(5, 2, 0); - capabilities_.device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; + capabilities_.device_caps = V4L2_CAP_VIDEO_CAPTURE + | V4L2_CAP_STREAMING + | V4L2_CAP_EXT_PIX_FORMAT; capabilities_.capabilities = capabilities_.device_caps | V4L2_CAP_DEVICE_CAPS; memset(capabilities_.reserved, 0, sizeof(capabilities_.reserved)); @@ -237,11 +243,15 @@ int V4L2CameraProxy::vidioc_enum_fmt(V4L2CameraFile *file, struct v4l2_fmtdesc * arg->index >= streamConfig_.formats().pixelformats().size()) return -EINVAL; + /* \todo Set V4L2_FMT_FLAG_COMPRESSED for compressed formats. */ + arg->flags = 0; /* \todo Add map from format to description. */ - utils::strlcpy(reinterpret_cast(arg->description), "Video Format Description", - sizeof(arg->description)); + utils::strlcpy(reinterpret_cast(arg->description), + "Video Format Description", sizeof(arg->description)); arg->pixelformat = drmToV4L2(streamConfig_.formats().pixelformats()[arg->index]); + memset(arg->reserved, 0, sizeof(arg->reserved)); + return 0; } @@ -281,6 +291,10 @@ void V4L2CameraProxy::tryFormat(struct v4l2_format *arg) arg->fmt.pix.width, arg->fmt.pix.height); arg->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB; + arg->fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC; + arg->fmt.pix.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; + arg->fmt.pix.quantization = V4L2_QUANTIZATION_DEFAULT; + arg->fmt.pix.xfer_func = V4L2_XFER_FUNC_DEFAULT; } int V4L2CameraProxy::vidioc_s_fmt(V4L2CameraFile *file, struct v4l2_format *arg) From patchwork Wed Jun 24 14:52:43 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 8407 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id C37A8609A5 for ; Wed, 24 Jun 2020 16:53:37 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="CLAvEjr3"; dkim-atps=neutral Received: from jade.rasen.tech (unknown [IPv6:2400:4051:61:600:8147:f2a2:a8c6:9087]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id A43FE2A8; Wed, 24 Jun 2020 16:53:35 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1593010417; bh=amBAHxtTzJeRczpGy1Dv9gTWz1UaDzCb7r4PFA5PcuY=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=CLAvEjr3DuBj+szJV4enULzihFPneUhg90/LoFP2J52Qn8sEP9oQlC5LLjCNuS0s/ QXrotHaMkz4Yt8EHEdOYgQCiJJpqcsd8Z+y24ILbkFjE6Pe86vNJnWzQqLP7eBmmWk Olk5mVV89xXOVeqYJ7z8vFkcnYOYaT9/KEsVvMpM= From: Paul Elder To: libcamera-devel@lists.libcamera.org Date: Wed, 24 Jun 2020 23:52:43 +0900 Message-Id: <20200624145256.48266-10-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20200624145256.48266-1-paul.elder@ideasonboard.com> References: <20200624145256.48266-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 09/22] v4l2: v4l2_camera_proxy: Implement VIDIOC_G/S_PRIORITY X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 24 Jun 2020 14:53:38 -0000 Implement VIDIOC_G_PRIORITY and VIDIOC_S_PRIORITY. The behaviour documented in the V4L2 specification doesn't match the implementation in the Linux kernel, implement the latter. Signed-off-by: Paul Elder Reviewed-by: Laurent Pinchart --- Changes in v4: - cosmetic changes Changes in v3: - save the priorities of every file - they're saved in V4L2CameraFile, so save a set of these in V4L2CameraProxy - they're unique from the perspective of the proxy so set is fine - actually check the priority for s_fmt, reqbufs, streamon, streamoff, s_input, and s_priority Changes in v2: - use V4L2CameraFile instead of fd and priorities map --- src/v4l2/v4l2_camera_proxy.cpp | 62 +++++++++++++++++++++++++++++++++- src/v4l2/v4l2_camera_proxy.h | 5 +++ 2 files changed, 66 insertions(+), 1 deletion(-) diff --git a/src/v4l2/v4l2_camera_proxy.cpp b/src/v4l2/v4l2_camera_proxy.cpp index ad9fa84..99586c3 100644 --- a/src/v4l2/v4l2_camera_proxy.cpp +++ b/src/v4l2/v4l2_camera_proxy.cpp @@ -45,8 +45,10 @@ int V4L2CameraProxy::open(V4L2CameraFile *file) { LOG(V4L2Compat, Debug) << "Servicing open fd = " << file->efd(); - if (refcount_++) + if (refcount_++) { + files_.insert(file); return 0; + } /* * We open the camera here, once, and keep it open until the last @@ -68,6 +70,8 @@ int V4L2CameraProxy::open(V4L2CameraFile *file) setFmtFromConfig(streamConfig_); sizeimage_ = calculateSizeImage(streamConfig_); + files_.insert(file); + return 0; } @@ -75,6 +79,8 @@ void V4L2CameraProxy::close(V4L2CameraFile *file) { LOG(V4L2Compat, Debug) << "Servicing close fd = " << file->efd(); + files_.erase(file); + release(file); if (--refcount_ > 0) @@ -304,6 +310,9 @@ int V4L2CameraProxy::vidioc_s_fmt(V4L2CameraFile *file, struct v4l2_format *arg) if (!validateBufferType(arg->type)) return -EINVAL; + if (file->priority() < maxPriority()) + return -EBUSY; + int ret = acquire(file); if (ret < 0) return ret; @@ -340,6 +349,40 @@ int V4L2CameraProxy::vidioc_try_fmt(V4L2CameraFile *file, struct v4l2_format *ar return 0; } +enum v4l2_priority V4L2CameraProxy::maxPriority() +{ + auto max = std::max_element(files_.begin(), files_.end(), + [](const V4L2CameraFile *a, const V4L2CameraFile *b) { + return a->priority() < b->priority(); + }); + return max != files_.end() ? (*max)->priority() : V4L2_PRIORITY_UNSET; +} + +int V4L2CameraProxy::vidioc_g_priority(V4L2CameraFile *file, enum v4l2_priority *arg) +{ + LOG(V4L2Compat, Debug) << "Servicing vidioc_g_priority fd = " << file->efd(); + + *arg = maxPriority(); + + return 0; +} + +int V4L2CameraProxy::vidioc_s_priority(V4L2CameraFile *file, enum v4l2_priority *arg) +{ + LOG(V4L2Compat, Debug) + << "Servicing vidioc_s_priority fd = " << file->efd(); + + if (*arg > V4L2_PRIORITY_RECORD) + return -EINVAL; + + if (file->priority() < maxPriority()) + return -EBUSY; + + file->setPriority(*arg); + + return 0; +} + void V4L2CameraProxy::freeBuffers() { LOG(V4L2Compat, Debug) << "Freeing libcamera bufs"; @@ -362,6 +405,9 @@ int V4L2CameraProxy::vidioc_reqbufs(V4L2CameraFile *file, struct v4l2_requestbuf LOG(V4L2Compat, Debug) << arg->count << " buffers requested "; + if (file->priority() < maxPriority()) + return -EBUSY; + if (!hasOwnership(file) && owner_) return -EBUSY; @@ -512,6 +558,9 @@ int V4L2CameraProxy::vidioc_streamon(V4L2CameraFile *file, int *arg) if (!validateBufferType(*arg)) return -EINVAL; + if (file->priority() < maxPriority()) + return -EBUSY; + if (!hasOwnership(file)) return -EBUSY; @@ -527,6 +576,9 @@ int V4L2CameraProxy::vidioc_streamoff(V4L2CameraFile *file, int *arg) if (!validateBufferType(*arg)) return -EINVAL; + if (file->priority() < maxPriority()) + return -EBUSY; + if (!hasOwnership(file) && owner_) return -EBUSY; @@ -544,6 +596,8 @@ const std::set V4L2CameraProxy::supportedIoctls_ = { VIDIOC_G_FMT, VIDIOC_S_FMT, VIDIOC_TRY_FMT, + VIDIOC_G_PRIORITY, + VIDIOC_S_PRIORITY, VIDIOC_REQBUFS, VIDIOC_QUERYBUF, VIDIOC_QBUF, @@ -586,6 +640,12 @@ int V4L2CameraProxy::ioctl(V4L2CameraFile *file, unsigned long request, void *ar case VIDIOC_TRY_FMT: ret = vidioc_try_fmt(file, static_cast(arg)); break; + case VIDIOC_G_PRIORITY: + ret = vidioc_g_priority(file, static_cast(arg)); + break; + case VIDIOC_S_PRIORITY: + ret = vidioc_s_priority(file, static_cast(arg)); + break; case VIDIOC_REQBUFS: ret = vidioc_reqbufs(file, static_cast(arg)); break; diff --git a/src/v4l2/v4l2_camera_proxy.h b/src/v4l2/v4l2_camera_proxy.h index 86c1a7d..8de306b 100644 --- a/src/v4l2/v4l2_camera_proxy.h +++ b/src/v4l2/v4l2_camera_proxy.h @@ -43,6 +43,7 @@ private: unsigned int calculateSizeImage(StreamConfiguration &streamConfig); void querycap(std::shared_ptr camera); void tryFormat(struct v4l2_format *arg); + enum v4l2_priority maxPriority(); void updateBuffers(); void freeBuffers(); @@ -51,6 +52,8 @@ private: int vidioc_g_fmt(V4L2CameraFile *file, struct v4l2_format *arg); int vidioc_s_fmt(V4L2CameraFile *file, struct v4l2_format *arg); int vidioc_try_fmt(V4L2CameraFile *file, struct v4l2_format *arg); + int vidioc_g_priority(V4L2CameraFile *file, enum v4l2_priority *arg); + int vidioc_s_priority(V4L2CameraFile *file, enum v4l2_priority *arg); int vidioc_reqbufs(V4L2CameraFile *file, struct v4l2_requestbuffers *arg); int vidioc_querybuf(V4L2CameraFile *file, struct v4l2_buffer *arg); int vidioc_qbuf(V4L2CameraFile *file, struct v4l2_buffer *arg); @@ -84,6 +87,8 @@ private: std::vector buffers_; std::map mmaps_; + std::set files_; + std::unique_ptr vcam_; /* From patchwork Wed Jun 24 14:52:44 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 8408 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 62436609A9 for ; Wed, 24 Jun 2020 16:53:40 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="TexvYPbd"; dkim-atps=neutral Received: from jade.rasen.tech (unknown [IPv6:2400:4051:61:600:8147:f2a2:a8c6:9087]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 4E8512A8; Wed, 24 Jun 2020 16:53:38 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1593010420; bh=iFElNjVQnZTQQnfU+8yxLeFarVTA5fdGEmgGife8r2U=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=TexvYPbdyEfJNYN8VPj8HRp9yqqVcG8itLXGVjF2l55V8VydxfP3R3Dbg/bbuSkCs YZTh/LpA01p6s174WI6jFb75ee7Vsu8xmfqYHDvOOs3re81SLN2BcO1bmggz8HOnw4 oCFDJ4DXn9htNqBBYCPd435fMBJrn7KWX9rhrFUI= From: Paul Elder To: libcamera-devel@lists.libcamera.org Date: Wed, 24 Jun 2020 23:52:44 +0900 Message-Id: <20200624145256.48266-11-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20200624145256.48266-1-paul.elder@ideasonboard.com> References: <20200624145256.48266-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 10/22] v4l2: v4l2_camera_proxy: Implement VIDIOC_ENUMINPUT, VIDIOC_G/S_INPUT X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 24 Jun 2020 14:53:40 -0000 Implement VIDIOC_ENUMINPUT, VIDIOC_G_INPUT, and VIDIOC_S_INPUT. Only the zeroth input device is supported, and the info returned by enuminput is hardcoded and basic. This is sufficient to pass v4l2-compliance. Signed-off-by: Paul Elder Reviewed-by: Jacopo Mondi Reviewed-by: Laurent Pinchart --- No change in v4 Changes in v3: - cosmetic changes Changes in v2: - use V4L2CameraFile instead of fd - remove arg == nullptr check as it has been moved away to the main ioctl handler --- src/v4l2/v4l2_camera_proxy.cpp | 48 ++++++++++++++++++++++++++++++++++ src/v4l2/v4l2_camera_proxy.h | 3 +++ 2 files changed, 51 insertions(+) diff --git a/src/v4l2/v4l2_camera_proxy.cpp b/src/v4l2/v4l2_camera_proxy.cpp index 99586c3..2bbe821 100644 --- a/src/v4l2/v4l2_camera_proxy.cpp +++ b/src/v4l2/v4l2_camera_proxy.cpp @@ -383,6 +383,42 @@ int V4L2CameraProxy::vidioc_s_priority(V4L2CameraFile *file, enum v4l2_priority return 0; } +int V4L2CameraProxy::vidioc_enuminput(V4L2CameraFile *file, struct v4l2_input *arg) +{ + LOG(V4L2Compat, Debug) << "Servicing vidioc_enuminput fd = " << file->efd(); + + if (arg->index != 0) + return -EINVAL; + + memset(arg, 0, sizeof(*arg)); + + utils::strlcpy(reinterpret_cast(arg->name), + reinterpret_cast(capabilities_.card), + sizeof(arg->name)); + arg->type = V4L2_INPUT_TYPE_CAMERA; + + return 0; +} + +int V4L2CameraProxy::vidioc_g_input(V4L2CameraFile *file, int *arg) +{ + LOG(V4L2Compat, Debug) << "Servicing vidioc_g_input fd = " << file->efd(); + + *arg = 0; + + return 0; +} + +int V4L2CameraProxy::vidioc_s_input(V4L2CameraFile *file, int *arg) +{ + LOG(V4L2Compat, Debug) << "Servicing vidioc_s_input fd = " << file->efd(); + + if (*arg != 0) + return -EINVAL; + + return 0; +} + void V4L2CameraProxy::freeBuffers() { LOG(V4L2Compat, Debug) << "Freeing libcamera bufs"; @@ -598,6 +634,9 @@ const std::set V4L2CameraProxy::supportedIoctls_ = { VIDIOC_TRY_FMT, VIDIOC_G_PRIORITY, VIDIOC_S_PRIORITY, + VIDIOC_ENUMINPUT, + VIDIOC_G_INPUT, + VIDIOC_S_INPUT, VIDIOC_REQBUFS, VIDIOC_QUERYBUF, VIDIOC_QBUF, @@ -646,6 +685,15 @@ int V4L2CameraProxy::ioctl(V4L2CameraFile *file, unsigned long request, void *ar case VIDIOC_S_PRIORITY: ret = vidioc_s_priority(file, static_cast(arg)); break; + case VIDIOC_ENUMINPUT: + ret = vidioc_enuminput(file, static_cast(arg)); + break; + case VIDIOC_G_INPUT: + ret = vidioc_g_input(file, static_cast(arg)); + break; + case VIDIOC_S_INPUT: + ret = vidioc_s_input(file, static_cast(arg)); + break; case VIDIOC_REQBUFS: ret = vidioc_reqbufs(file, static_cast(arg)); break; diff --git a/src/v4l2/v4l2_camera_proxy.h b/src/v4l2/v4l2_camera_proxy.h index 8de306b..707a0de 100644 --- a/src/v4l2/v4l2_camera_proxy.h +++ b/src/v4l2/v4l2_camera_proxy.h @@ -54,6 +54,9 @@ private: int vidioc_try_fmt(V4L2CameraFile *file, struct v4l2_format *arg); int vidioc_g_priority(V4L2CameraFile *file, enum v4l2_priority *arg); int vidioc_s_priority(V4L2CameraFile *file, enum v4l2_priority *arg); + int vidioc_enuminput(V4L2CameraFile *file, struct v4l2_input *arg); + int vidioc_g_input(V4L2CameraFile *file, int *arg); + int vidioc_s_input(V4L2CameraFile *file, int *arg); int vidioc_reqbufs(V4L2CameraFile *file, struct v4l2_requestbuffers *arg); int vidioc_querybuf(V4L2CameraFile *file, struct v4l2_buffer *arg); int vidioc_qbuf(V4L2CameraFile *file, struct v4l2_buffer *arg); From patchwork Wed Jun 24 14:52:45 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 8409 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id BC979609B3 for ; Wed, 24 Jun 2020 16:53:42 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="UHPBfqKe"; dkim-atps=neutral Received: from jade.rasen.tech (unknown [IPv6:2400:4051:61:600:8147:f2a2:a8c6:9087]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id BE0B42A8; Wed, 24 Jun 2020 16:53:40 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1593010422; bh=9A/tCXnsu07q67BIzOfac4YKy3YgDnXJDDGvyaF5yNs=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=UHPBfqKewXSZqx50/pkWCPmGoKTk/VUm69uk6tioFBKnUTswGcQdJxw+T8wXhrmpk wz0fq4OQZceT2Q0L5bbNg5BSU2DZZ5T2/gXmAbysDFpzTGOInvq+OF2SpyvwFCF7eV eIYNew/iQWEV0wwFBXUwPViWgnuDAUjbh4NL4TOw= From: Paul Elder To: libcamera-devel@lists.libcamera.org Date: Wed, 24 Jun 2020 23:52:45 +0900 Message-Id: <20200624145256.48266-12-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20200624145256.48266-1-paul.elder@ideasonboard.com> References: <20200624145256.48266-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 11/22] v4l2: v4l2_camera_proxy: Implement VIDIOC_ENUM_FRAMESIZES X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 24 Jun 2020 14:53:43 -0000 Implement VIDIOC_ENUM_FRAMESIZES in the V4L2 compatibility layer. Signed-off-by: Paul Elder Reviewed-by: Laurent Pinchart --- No change in v4 Changes in v3: - cosmetic changes Changes in v2: - use V4L2CameraFile instead of fd - added todo for not many pipeline handlers reporting StreamFormats --- src/v4l2/v4l2_camera_proxy.cpp | 26 ++++++++++++++++++++++++++ src/v4l2/v4l2_camera_proxy.h | 1 + 2 files changed, 27 insertions(+) diff --git a/src/v4l2/v4l2_camera_proxy.cpp b/src/v4l2/v4l2_camera_proxy.cpp index 2bbe821..b027f8f 100644 --- a/src/v4l2/v4l2_camera_proxy.cpp +++ b/src/v4l2/v4l2_camera_proxy.cpp @@ -241,6 +241,28 @@ int V4L2CameraProxy::vidioc_querycap(struct v4l2_capability *arg) return 0; } +int V4L2CameraProxy::vidioc_enum_framesizes(V4L2CameraFile *file, struct v4l2_frmsizeenum *arg) +{ + LOG(V4L2Compat, Debug) << "Servicing vidioc_enum_framesizes fd = " << file->efd(); + + PixelFormat argFormat = v4l2ToDrm(arg->pixel_format); + /* + * \todo This might need to be expanded as few pipeline handlers + * report StreamFormats. + */ + const std::vector &frameSizes = streamConfig_.formats().sizes(argFormat); + + if (arg->index >= frameSizes.size()) + return -EINVAL; + + arg->type = V4L2_FRMSIZE_TYPE_DISCRETE; + arg->discrete.width = frameSizes[arg->index].width; + arg->discrete.height = frameSizes[arg->index].height; + memset(arg->reserved, 0, sizeof(arg->reserved)); + + return 0; +} + int V4L2CameraProxy::vidioc_enum_fmt(V4L2CameraFile *file, struct v4l2_fmtdesc *arg) { LOG(V4L2Compat, Debug) << "Servicing vidioc_enum_fmt fd = " << file->efd(); @@ -628,6 +650,7 @@ int V4L2CameraProxy::vidioc_streamoff(V4L2CameraFile *file, int *arg) const std::set V4L2CameraProxy::supportedIoctls_ = { VIDIOC_QUERYCAP, + VIDIOC_ENUM_FRAMESIZES, VIDIOC_ENUM_FMT, VIDIOC_G_FMT, VIDIOC_S_FMT, @@ -667,6 +690,9 @@ int V4L2CameraProxy::ioctl(V4L2CameraFile *file, unsigned long request, void *ar case VIDIOC_QUERYCAP: ret = vidioc_querycap(static_cast(arg)); break; + case VIDIOC_ENUM_FRAMESIZES: + ret = vidioc_enum_framesizes(file, static_cast(arg)); + break; case VIDIOC_ENUM_FMT: ret = vidioc_enum_fmt(file, static_cast(arg)); break; diff --git a/src/v4l2/v4l2_camera_proxy.h b/src/v4l2/v4l2_camera_proxy.h index 707a0de..5de2c5a 100644 --- a/src/v4l2/v4l2_camera_proxy.h +++ b/src/v4l2/v4l2_camera_proxy.h @@ -48,6 +48,7 @@ private: void freeBuffers(); int vidioc_querycap(struct v4l2_capability *arg); + int vidioc_enum_framesizes(V4L2CameraFile *file, struct v4l2_frmsizeenum *arg); int vidioc_enum_fmt(V4L2CameraFile *file, struct v4l2_fmtdesc *arg); int vidioc_g_fmt(V4L2CameraFile *file, struct v4l2_format *arg); int vidioc_s_fmt(V4L2CameraFile *file, struct v4l2_format *arg); From patchwork Wed Jun 24 14:52:46 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 8410 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id DE5DA609A9 for ; Wed, 24 Jun 2020 16:53:44 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="aIFcdbip"; dkim-atps=neutral Received: from jade.rasen.tech (unknown [IPv6:2400:4051:61:600:8147:f2a2:a8c6:9087]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 20A522A8; Wed, 24 Jun 2020 16:53:42 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1593010424; bh=ekB4A6flPCV3R7AVeZrD4sxawp8TAkhOEGwQkOE2TYE=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=aIFcdbipK7eWUA5b/YE6JpqfUIGFJCu6zEPzDwiTWt/39V7kT/2qj/dyJYlHFlzwA yi2M4l52LU9hiJhzNwyTEGqFTfa/sAuosnoI3SeH668mb3Y2IOtuInjioztFQDcY5S lSdfdrjTjpzPyUAD1gHctX2kRW1QOVuJKiDlHc5g= From: Paul Elder To: libcamera-devel@lists.libcamera.org Date: Wed, 24 Jun 2020 23:52:46 +0900 Message-Id: <20200624145256.48266-13-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20200624145256.48266-1-paul.elder@ideasonboard.com> References: <20200624145256.48266-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 12/22] v4l2: v4l2_camera: Add isRunning() X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 24 Jun 2020 14:53:45 -0000 Add a method isRunning() to V4L2Camera so that V4L2CameraProxy can use it for checks. Signed-off-by: Paul Elder Reviewed-by: Laurent Pinchart --- No change in v4 Changes in v3: - cosmetic changes Changes in v2: - replace V4L2CameraProxy::streaming_ with V4L2CameraProxy::isRunning() - moved the checks to different patches --- src/v4l2/v4l2_camera.cpp | 5 +++++ src/v4l2/v4l2_camera.h | 2 ++ 2 files changed, 7 insertions(+) diff --git a/src/v4l2/v4l2_camera.cpp b/src/v4l2/v4l2_camera.cpp index 2557320..177b1ea 100644 --- a/src/v4l2/v4l2_camera.cpp +++ b/src/v4l2/v4l2_camera.cpp @@ -227,3 +227,8 @@ int V4L2Camera::qbuf(unsigned int index) return 0; } + +bool V4L2Camera::isRunning() +{ + return isRunning_; +} diff --git a/src/v4l2/v4l2_camera.h b/src/v4l2/v4l2_camera.h index 30114ed..ee53c2b 100644 --- a/src/v4l2/v4l2_camera.h +++ b/src/v4l2/v4l2_camera.h @@ -57,6 +57,8 @@ public: int qbuf(unsigned int index); + bool isRunning(); + Semaphore bufferSema_; private: From patchwork Wed Jun 24 14:52:47 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 8411 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 42850609C6 for ; Wed, 24 Jun 2020 16:53:47 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="fvSFpgzY"; dkim-atps=neutral Received: from jade.rasen.tech (unknown [IPv6:2400:4051:61:600:8147:f2a2:a8c6:9087]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 4561F2A8; Wed, 24 Jun 2020 16:53:45 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1593010427; bh=e1QUHIZoXqFfUEYT6CYHNordEr8bQNKNVL3BASPPqWY=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=fvSFpgzYB2EY1MkYLi9u+DH2bPXR4nbv2orObrE4lXSqit+QpF5wFHDEF3fbtkJhZ 0Du8WtoOGHekjgxLO46y8utPh5+HH1b+FazLdTVxRFuRNsfGorNq0uMQZWJalQCKMO qIW/u0gGcxZ0/PhubdnnQvYKLphbfr5WZNHlOvQg= From: Paul Elder To: libcamera-devel@lists.libcamera.org Date: Wed, 24 Jun 2020 23:52:47 +0900 Message-Id: <20200624145256.48266-14-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20200624145256.48266-1-paul.elder@ideasonboard.com> References: <20200624145256.48266-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 13/22] v4l2: v4l2_camera_proxy: Disallow dqbuf when not streaming X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 24 Jun 2020 14:53:47 -0000 Make VIDIOC_DQBUF return -EINVAL if the stream is not turned on. Signed-off-by: Paul Elder Reviewed-by: Laurent Pinchart --- No change in v4 Changes in v3: - move isRunning check to after taking lock New in v2 (split from "v4l2: v4l2_camera: Add isRunning()") --- src/v4l2/v4l2_camera_proxy.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/v4l2/v4l2_camera_proxy.cpp b/src/v4l2/v4l2_camera_proxy.cpp index b027f8f..f8e8d79 100644 --- a/src/v4l2/v4l2_camera_proxy.cpp +++ b/src/v4l2/v4l2_camera_proxy.cpp @@ -582,6 +582,9 @@ int V4L2CameraProxy::vidioc_dqbuf(V4L2CameraFile *file, struct v4l2_buffer *arg) if (!hasOwnership(file)) return -EBUSY; + if (!vcam_->isRunning()) + return -EINVAL; + if (!validateBufferType(arg->type) || !validateMemoryType(arg->memory)) return -EINVAL; From patchwork Wed Jun 24 14:52:48 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 8412 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 6688D609C5 for ; Wed, 24 Jun 2020 16:53:49 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="tNTBCbdP"; dkim-atps=neutral Received: from jade.rasen.tech (unknown [IPv6:2400:4051:61:600:8147:f2a2:a8c6:9087]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 9C5FB2A8; Wed, 24 Jun 2020 16:53:47 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1593010429; bh=JN+fsVE6f2eE8BPtIsHz0iQYBapWF5nD+gkAItMv/k0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=tNTBCbdPH/RynwuZijaIxeg7M4UmVgqzG9XddrqYCc4Ftj8vbal3WphpGNJJYjRgV KB3nVGfbtGHJMhWreRRKYbyqXy00EsSt6ifv2PDQFdNqHOzXv3iUYAsFTEvD4XCsnT S3uT51psYTK6+e/WEvuS8KrLTAJ9wBP/frylt7+w= From: Paul Elder To: libcamera-devel@lists.libcamera.org Date: Wed, 24 Jun 2020 23:52:48 +0900 Message-Id: <20200624145256.48266-15-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20200624145256.48266-1-paul.elder@ideasonboard.com> References: <20200624145256.48266-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 14/22] v4l2: v4l2_camera_proxy: noop if streamon when stream is already on X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 24 Jun 2020 14:53:49 -0000 If VIDIOC_STREMAON is called when the stream is already on, do a noop. Signed-off-by: Paul Elder Reviewed-by: Laurent Pinchart --- No change in v4 Changes in v3: - move isRunning check to after ownership check New in v2: (split from "v4l2: v4l2_camera: Add isRunning()") --- src/v4l2/v4l2_camera_proxy.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/v4l2/v4l2_camera_proxy.cpp b/src/v4l2/v4l2_camera_proxy.cpp index f8e8d79..7b269a5 100644 --- a/src/v4l2/v4l2_camera_proxy.cpp +++ b/src/v4l2/v4l2_camera_proxy.cpp @@ -625,6 +625,9 @@ int V4L2CameraProxy::vidioc_streamon(V4L2CameraFile *file, int *arg) if (!hasOwnership(file)) return -EBUSY; + if (vcam_->isRunning()) + return 0; + currentBuf_ = 0; return vcam_->streamOn(); From patchwork Wed Jun 24 14:52:49 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 8413 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id B3519609C5 for ; Wed, 24 Jun 2020 16:53:51 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="bnndQHaz"; dkim-atps=neutral Received: from jade.rasen.tech (unknown [IPv6:2400:4051:61:600:8147:f2a2:a8c6:9087]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id CA5902A8; Wed, 24 Jun 2020 16:53:49 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1593010431; bh=kLZGupO242hvH2AcNydhWhWZII+Zp57aGQ/nzI8zmao=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=bnndQHazS0Mb7ZRAbWpb/iJm6i1NAIoSsOyAsTGP3mjEuBQzMWZzJt/Hm4zE7tdsO OgOJMh5iK9SvzfzjpemSVNOr8OULZ1OCliQex/so640zV4MqO7sedckh6kWNu+yZ0e ALu0NRtxXbFIvp76b2sLNu3/f6CQp23iEbKwWaOQ= From: Paul Elder To: libcamera-devel@lists.libcamera.org Date: Wed, 24 Jun 2020 23:52:49 +0900 Message-Id: <20200624145256.48266-16-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20200624145256.48266-1-paul.elder@ideasonboard.com> References: <20200624145256.48266-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 15/22] v4l2: v4l2_camera_proxy: Clear internal buffer vector on reqbufs 0 X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 24 Jun 2020 14:53:52 -0000 If VIDIOC_REQBUFS with count = 0 is called when the stream is not on, clear the proxy's internal vector of buffer. If the stream is on when reqbufs 0 is called, return -EBUSY. Note that this is contrary to what the V4L2 docs say (reqbufs 0 when streaming should also streamoff), but it is how the V4L2 implementation works. v4l2-compliance doesn't seem to care either way, however, so we cater to the implementation, and no longer call streamoff on reqbufs 0. Signed-off-by: Paul Elder Reviewed-by: Laurent Pinchart --- Changes in v4: - instead of resetting flags, clear the buffer vector in the proxy Changes in v3: - don't streamoff in reqbufs 0; return -EBUSY instead Changes in v2: - call only the necessary components, instead of V4L2CameraProxy::vidioc_streamoff --- src/v4l2/v4l2_camera_proxy.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/v4l2/v4l2_camera_proxy.cpp b/src/v4l2/v4l2_camera_proxy.cpp index 7b269a5..9965a53 100644 --- a/src/v4l2/v4l2_camera_proxy.cpp +++ b/src/v4l2/v4l2_camera_proxy.cpp @@ -445,11 +445,8 @@ void V4L2CameraProxy::freeBuffers() { LOG(V4L2Compat, Debug) << "Freeing libcamera bufs"; - int ret = vcam_->streamOff(); - if (ret < 0) - LOG(V4L2Compat, Error) << "Failed to stop stream"; - vcam_->freeBuffers(); + buffers_.clear(); bufferCount_ = 0; } @@ -473,6 +470,9 @@ int V4L2CameraProxy::vidioc_reqbufs(V4L2CameraFile *file, struct v4l2_requestbuf memset(arg->reserved, 0, sizeof(arg->reserved)); if (arg->count == 0) { + if (vcam_->isRunning()) + return -EBUSY; + freeBuffers(); release(file); From patchwork Wed Jun 24 14:52:50 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 8414 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 16EBB609B3 for ; Wed, 24 Jun 2020 16:53:54 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="ItgpG+UP"; dkim-atps=neutral Received: from jade.rasen.tech (unknown [IPv6:2400:4051:61:600:8147:f2a2:a8c6:9087]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 625C3595; Wed, 24 Jun 2020 16:53:51 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1593010433; bh=hULpYTBQvTYKOONtsF/mqy2j5E3JHOwx6xyxrWlZ+RQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=ItgpG+UPdITIuIoa7TfrGRMwHfwjrk3OP69or5vWzAM3YDcdUPZWntcazOk3JWu7N mLpRzDu3+RxeBhPpf4OopAPu61DBFVBOdFacHzNb542HilUJkrl6RtT0xu/MtjT60H 2n/iRMaTy/a//RrM/jSE4w3cWrTSoLRHl6F2s2FA= From: Paul Elder To: libcamera-devel@lists.libcamera.org Date: Wed, 24 Jun 2020 23:52:50 +0900 Message-Id: <20200624145256.48266-17-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20200624145256.48266-1-paul.elder@ideasonboard.com> References: <20200624145256.48266-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 16/22] v4l2: v4l2_camera: Don't use libcamera::Semaphore for available buffers X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 24 Jun 2020 14:53:54 -0000 In V4L2, a blocked dqbuf should not not also block a streamoff. This means that on streamoff, the blocked dqbuf must return (with error). We cannot do this with the libcamera semaphore, so pull out the necessary components of a semaphore, and put them into V4L2Camera, so that dqbuf from V4L2CameraProxy can wait on a disjunct condition of the availability of the semaphore or the stopping of the stream. Signed-off-by: Paul Elder Reviewed-by: Laurent Pinchart --- Changes in v4: - cosmetic changes Changes in v3: - don't notify all with the lock held Changes in v2: - remove mutex for isRunning_ - use V4L2Camera::isRunning() instead of V4L2CameraProxy::streaming_ in the dqbuf ioctl handler --- src/v4l2/v4l2_camera.cpp | 34 +++++++++++++++++++++++++++++++--- src/v4l2/v4l2_camera.h | 9 +++++++-- src/v4l2/v4l2_camera_proxy.cpp | 11 +++++++++-- 3 files changed, 47 insertions(+), 7 deletions(-) diff --git a/src/v4l2/v4l2_camera.cpp b/src/v4l2/v4l2_camera.cpp index 177b1ea..f7df9b8 100644 --- a/src/v4l2/v4l2_camera.cpp +++ b/src/v4l2/v4l2_camera.cpp @@ -18,7 +18,7 @@ LOG_DECLARE_CATEGORY(V4L2Compat); V4L2Camera::V4L2Camera(std::shared_ptr camera) : camera_(camera), isRunning_(false), bufferAllocator_(nullptr), - efd_(-1) + efd_(-1), bufferAvailableCount_(0) { camera_->requestCompleted.connect(this, &V4L2Camera::requestComplete); } @@ -100,7 +100,11 @@ void V4L2Camera::requestComplete(Request *request) if (ret != sizeof(data)) LOG(V4L2Compat, Error) << "Failed to signal eventfd POLLIN"; - bufferSema_.release(); + { + MutexLocker locker(bufferMutex_); + bufferAvailableCount_++; + } + bufferCV_.notify_all(); } int V4L2Camera::configure(StreamConfiguration *streamConfigOut, @@ -192,7 +196,11 @@ int V4L2Camera::streamOff() if (ret < 0) return ret == -EACCES ? -EBUSY : ret; - isRunning_ = false; + { + MutexLocker locker(bufferMutex_); + isRunning_ = false; + } + bufferCV_.notify_all(); return 0; } @@ -228,6 +236,26 @@ int V4L2Camera::qbuf(unsigned int index) return 0; } +void V4L2Camera::waitForBufferAvailable() +{ + MutexLocker locker(bufferMutex_); + bufferCV_.wait(locker, [&] { + return bufferAvailableCount_ >= 1 || !isRunning_; + }); + if (isRunning_) + bufferAvailableCount_--; +} + +bool V4L2Camera::isBufferAvailable() +{ + MutexLocker locker(bufferMutex_); + if (bufferAvailableCount_ < 1) + return false; + + bufferAvailableCount_--; + return true; +} + bool V4L2Camera::isRunning() { return isRunning_; diff --git a/src/v4l2/v4l2_camera.h b/src/v4l2/v4l2_camera.h index ee53c2b..515e906 100644 --- a/src/v4l2/v4l2_camera.h +++ b/src/v4l2/v4l2_camera.h @@ -57,9 +57,10 @@ public: int qbuf(unsigned int index); - bool isRunning(); + void waitForBufferAvailable(); + bool isBufferAvailable(); - Semaphore bufferSema_; + bool isRunning(); private: void requestComplete(Request *request); @@ -76,6 +77,10 @@ private: std::deque> completedBuffers_; int efd_; + + Mutex bufferMutex_; + std::condition_variable bufferCV_; + unsigned int bufferAvailableCount_; }; #endif /* __V4L2_CAMERA_H__ */ diff --git a/src/v4l2/v4l2_camera_proxy.cpp b/src/v4l2/v4l2_camera_proxy.cpp index 9965a53..4c140eb 100644 --- a/src/v4l2/v4l2_camera_proxy.cpp +++ b/src/v4l2/v4l2_camera_proxy.cpp @@ -590,10 +590,17 @@ int V4L2CameraProxy::vidioc_dqbuf(V4L2CameraFile *file, struct v4l2_buffer *arg) return -EINVAL; if (!file->nonBlocking()) - vcam_->bufferSema_.acquire(); - else if (!vcam_->bufferSema_.tryAcquire()) + vcam_->waitForBufferAvailable(); + else if (!vcam_->isBufferAvailable()) return -EAGAIN; + /* + * We need to check here again in case stream was turned off while we + * were blocked on waitForBufferAvailable(). + */ + if (!vcam_->isRunning()) + return -EINVAL; + updateBuffers(); struct v4l2_buffer &buf = buffers_[currentBuf_]; From patchwork Wed Jun 24 14:52:51 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 8415 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 9BA82609B3 for ; Wed, 24 Jun 2020 16:53:56 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="Rky2R81w"; dkim-atps=neutral Received: from jade.rasen.tech (unknown [IPv6:2400:4051:61:600:8147:f2a2:a8c6:9087]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 7A16A2A8; Wed, 24 Jun 2020 16:53:54 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1593010436; bh=+JZqZReMXotnIPxlzWAao6FhXtvnDG+Qy2Bxax/Och4=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Rky2R81wXN7tKS+zQtH67AZwSrg/u4t2GY7YJgwtnrzOuBR6ZitOwKNpJ5n97/BVU h/oB6n+k5oMKVw+mmqjHkiE0NVHLKZloP9L+FO7fIWoT1yzgjG5qBPZMtXemS2nnUA 9UDP6BHT1wm69tLmwExOuagIy7CBQNCB9NNiGxxM= From: Paul Elder To: libcamera-devel@lists.libcamera.org Date: Wed, 24 Jun 2020 23:52:51 +0900 Message-Id: <20200624145256.48266-18-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20200624145256.48266-1-paul.elder@ideasonboard.com> References: <20200624145256.48266-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 17/22] v4l2: v4l2_camera: Clear pending requests on freeBuffers and streamOff X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 24 Jun 2020 14:53:56 -0000 V4L2 allows buffer queueing before streamon while libcamera does not. The compatibility layer thus saves these buffers in a pending queue until streamon, and then automatically queues them. However, this pending queue is not cleared when the buffers are freed, so the following sequence of actions will cause a use-after-free: 1. queue buffers 2. free buffers - buffers from 1. stay in pending queue but have been freed 3. queue buffers 4. streamon - buffers from 1. are enqueued, then the buffers from 3. are enqueued. Use-after-free segfault when libcamera tries to handle the enqueued buffers from 1. Fix this by clearing the pending request queue upon buffers being freed. Also clear the pending request queue on streamOff, for correctness. Signed-off-by: Paul Elder Reviewed-by: Jacopo Mondi Reviewed-by: Laurent Pinchart --- No change in v4 Changes in v3: - reorder clearing the pending request queue, to before freeing buffers, and to after checking isRunning Changes in v2: - also clear pending request queue on streamOff - clarify the issue in changelog --- src/v4l2/v4l2_camera.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/v4l2/v4l2_camera.cpp b/src/v4l2/v4l2_camera.cpp index f7df9b8..ffc1230 100644 --- a/src/v4l2/v4l2_camera.cpp +++ b/src/v4l2/v4l2_camera.cpp @@ -147,6 +147,8 @@ int V4L2Camera::allocBuffers(unsigned int count) void V4L2Camera::freeBuffers() { + pendingRequests_.clear(); + Stream *stream = *camera_->streams().begin(); bufferAllocator_->free(stream); } @@ -188,10 +190,11 @@ int V4L2Camera::streamOn() int V4L2Camera::streamOff() { - /* \todo Restore buffers to reqbufs state? */ if (!isRunning_) return 0; + pendingRequests_.clear(); + int ret = camera_->stop(); if (ret < 0) return ret == -EACCES ? -EBUSY : ret; From patchwork Wed Jun 24 14:52:52 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 8416 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 0EBF9609C7 for ; Wed, 24 Jun 2020 16:53:59 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="aXFHeXm+"; dkim-atps=neutral Received: from jade.rasen.tech (unknown [IPv6:2400:4051:61:600:8147:f2a2:a8c6:9087]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id E9E9A2A8; Wed, 24 Jun 2020 16:53:56 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1593010438; bh=JTCBD0W7YzEbkXc5BhCVTvw3r7+8ZOtn8SCRH6eGFQg=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=aXFHeXm+z/CsPiQGTTesXbfXjaCpjXqcNhpBeEmOD1vdnwLpZiYER05cV43qf9T6z jWBU2EOeLCjfj0wnUt2lR6SM6e497nyw79MLf32ooYhUydajLcoTtuy6RyXZRP94Jb arSkZi6Vuy/43AsbH6sdW5koboLw9a6gHhNn99B4= From: Paul Elder To: libcamera-devel@lists.libcamera.org Date: Wed, 24 Jun 2020 23:52:52 +0900 Message-Id: <20200624145256.48266-19-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20200624145256.48266-1-paul.elder@ideasonboard.com> References: <20200624145256.48266-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 18/22] v4l2: v4l2_camera_proxy: Check arg->index bounds for querybuf, qbuf, dqbuf X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 24 Jun 2020 14:53:59 -0000 There were no bounds checks for the index argument for VIDIOC_QUERYBUF, VIDIOC_QBUF, and VIDIOC_DQBUF. Add them. Signed-off-by: Paul Elder Reviewed-by: Jacopo Mondi Reviewed-by: Laurent Pinchart --- No change in v4 Changes in v3: - don't check for ownership on querybuf No change in v2 --- src/v4l2/v4l2_camera_proxy.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/v4l2/v4l2_camera_proxy.cpp b/src/v4l2/v4l2_camera_proxy.cpp index 4c140eb..2aff53e 100644 --- a/src/v4l2/v4l2_camera_proxy.cpp +++ b/src/v4l2/v4l2_camera_proxy.cpp @@ -541,6 +541,9 @@ int V4L2CameraProxy::vidioc_querybuf(V4L2CameraFile *file, struct v4l2_buffer *a { LOG(V4L2Compat, Debug) << "Servicing vidioc_querybuf fd = " << file->efd(); + if (arg->index >= bufferCount_) + return -EINVAL; + if (!validateBufferType(arg->type) || arg->index >= bufferCount_) return -EINVAL; @@ -557,6 +560,9 @@ int V4L2CameraProxy::vidioc_qbuf(V4L2CameraFile *file, struct v4l2_buffer *arg) LOG(V4L2Compat, Debug) << "Servicing vidioc_qbuf, index = " << arg->index << " fd = " << file->efd(); + if (arg->index >= bufferCount_) + return -EINVAL; + if (!hasOwnership(file)) return -EBUSY; @@ -579,6 +585,9 @@ int V4L2CameraProxy::vidioc_dqbuf(V4L2CameraFile *file, struct v4l2_buffer *arg) { LOG(V4L2Compat, Debug) << "Servicing vidioc_dqbuf fd = " << file->efd(); + if (arg->index >= bufferCount_) + return -EINVAL; + if (!hasOwnership(file)) return -EBUSY; From patchwork Wed Jun 24 14:52:53 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 8417 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 269D0609C5 for ; Wed, 24 Jun 2020 16:54:01 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="fx0I5zHX"; dkim-atps=neutral Received: from jade.rasen.tech (unknown [IPv6:2400:4051:61:600:8147:f2a2:a8c6:9087]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 65C58595; Wed, 24 Jun 2020 16:53:59 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1593010440; bh=bYTIsuiQa6XLouqxrGYy1X+Cg77rT/kmgAUs+8UbaIc=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=fx0I5zHX1jxgyPvxpKIx4zXbUabecmabMPw5YA9tBjuXdfMzFB5apeKl2MJlJ4uMk zdKF645GvxywIU9fOvZFQxsrmGPbFYw8SpRlkc8DLiWAMpdH4wGacBZaCFPt5Rq359 w6UkUfBVYa2RKTOIBFWU3eJ8RHB9zs0t88zXrsTA= From: Paul Elder To: libcamera-devel@lists.libcamera.org Date: Wed, 24 Jun 2020 23:52:53 +0900 Message-Id: <20200624145256.48266-20-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20200624145256.48266-1-paul.elder@ideasonboard.com> References: <20200624145256.48266-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 19/22] v4l2: v4l2_camera_proxy: Don't allow streamon if no buffers have been requested X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 24 Jun 2020 14:54:01 -0000 Make VIDIOC_STREAMON return -EINVAL if no buffers have been allocated with reqbufs. Signed-off-by: Paul Elder Reviewed-by: Laurent Pinchart --- No change in v4 No change in v3 New in v2 - split from "Fix v4l2-compliance streaming tests" --- src/v4l2/v4l2_camera_proxy.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/v4l2/v4l2_camera_proxy.cpp b/src/v4l2/v4l2_camera_proxy.cpp index 2aff53e..2dbeef3 100644 --- a/src/v4l2/v4l2_camera_proxy.cpp +++ b/src/v4l2/v4l2_camera_proxy.cpp @@ -632,6 +632,9 @@ int V4L2CameraProxy::vidioc_streamon(V4L2CameraFile *file, int *arg) { LOG(V4L2Compat, Debug) << "Servicing vidioc_streamon fd = " << file->efd(); + if (bufferCount_ == 0) + return -EINVAL; + if (!validateBufferType(*arg)) return -EINVAL; From patchwork Wed Jun 24 14:52:54 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 8418 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 4BB93609C3 for ; Wed, 24 Jun 2020 16:54:03 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="dxbNd/pX"; dkim-atps=neutral Received: from jade.rasen.tech (unknown [IPv6:2400:4051:61:600:8147:f2a2:a8c6:9087]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 87D242A8; Wed, 24 Jun 2020 16:54:01 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1593010443; bh=pu86KmKFVtINlzQhg6zRy5w3BRoOG280URxjslj0/zg=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=dxbNd/pXVLzfG2PN2Nx+CmX1oooihXEckb+Tn+8XEfScSV6et61D12kIKap0vWKIv gUxojdshZD42N1NNxDoX8l9hY6RjLDzh90DJGECbrk2J57+kpRQB1K5dlEf34kN+ay eYUYVVtk9qklhrhcIAGZnF/va6HG6BpUG4azc4Y4= From: Paul Elder To: libcamera-devel@lists.libcamera.org Date: Wed, 24 Jun 2020 23:52:54 +0900 Message-Id: <20200624145256.48266-21-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20200624145256.48266-1-paul.elder@ideasonboard.com> References: <20200624145256.48266-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 20/22] v4l2: v4l2_camera_proxy: Don't allow buffers to be freed if still mmaped X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 24 Jun 2020 14:54:03 -0000 In VIDIOC_REQBUFS with count = 0, if the buffers are still mmaped, they should not be allowed to be freed. Add a check for this. Signed-off-by: Paul Elder Reviewed-by: Laurent Pinchart --- Changes in v4: - add todo to support buffer orphaning No change in v3 New in v2 - split from "Fix v4l2-compliance streaming tests" --- src/v4l2/v4l2_camera_proxy.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/v4l2/v4l2_camera_proxy.cpp b/src/v4l2/v4l2_camera_proxy.cpp index 2dbeef3..d5c146f 100644 --- a/src/v4l2/v4l2_camera_proxy.cpp +++ b/src/v4l2/v4l2_camera_proxy.cpp @@ -470,6 +470,10 @@ int V4L2CameraProxy::vidioc_reqbufs(V4L2CameraFile *file, struct v4l2_requestbuf memset(arg->reserved, 0, sizeof(arg->reserved)); if (arg->count == 0) { + /* \todo Add buffer orphaning support */ + if (!mmaps_.empty()) + return -EBUSY; + if (vcam_->isRunning()) return -EBUSY; From patchwork Wed Jun 24 14:52:55 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 8419 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 94888609C5 for ; Wed, 24 Jun 2020 16:54:05 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="DueO6vjJ"; dkim-atps=neutral Received: from jade.rasen.tech (unknown [IPv6:2400:4051:61:600:8147:f2a2:a8c6:9087]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id E908F2A8; Wed, 24 Jun 2020 16:54:03 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1593010445; bh=rqiojEVYnxD2uLtrdleH9sNQB/HOT8ls2RMDcSFoO8Q=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=DueO6vjJVAZw/kjWgqFcx3ptpt56hLETtPp1rp61LrnspegsM9DoXSyn45OqiPyuN JDL164D5CfyxpJzPb9zGxoea2eLs0wx5kNCYtIiEBRQFcGMeD7VfWrPTGG8VQPQxRe tE4p9pYuEtfccLZDsSDGlzQfKwHFIO5mZ0RJii4w= From: Paul Elder To: libcamera-devel@lists.libcamera.org Date: Wed, 24 Jun 2020 23:52:55 +0900 Message-Id: <20200624145256.48266-22-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20200624145256.48266-1-paul.elder@ideasonboard.com> References: <20200624145256.48266-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 21/22] v4l2: v4l2_camera_proxy: Fix buffer flags related to queueing X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 24 Jun 2020 14:54:05 -0000 Fix buffer flags related to queueing and dequeueing: - don't allow a buffer with the same index that is already in the queue to be enqueued again - don't clear the done flag upon qbuf - do clear the done flag upon dqbuf - set the flags in V4L2CameraProxy's internal buffers, and not just in the buffers returned from qbuf Signed-off-by: Paul Elder Reviewed-by: Laurent Pinchart --- Changes in v4: - fix the V4L2_BUF_FLAG_DONE flag properly - clear in dqbuf, set in updateBuffers (latter is already there) Changes in v3: - remove "set the mapped flag on enqueueing" - clean up some logic - expand commit message very slightly New in v2 - split from "Fix v4l2-compliance streaming tests" --- src/v4l2/v4l2_camera_proxy.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/v4l2/v4l2_camera_proxy.cpp b/src/v4l2/v4l2_camera_proxy.cpp index d5c146f..3b7a6f4 100644 --- a/src/v4l2/v4l2_camera_proxy.cpp +++ b/src/v4l2/v4l2_camera_proxy.cpp @@ -567,6 +567,9 @@ int V4L2CameraProxy::vidioc_qbuf(V4L2CameraFile *file, struct v4l2_buffer *arg) if (arg->index >= bufferCount_) return -EINVAL; + if (buffers_[arg->index].flags & V4L2_BUF_FLAG_QUEUED) + return -EINVAL; + if (!hasOwnership(file)) return -EBUSY; @@ -579,8 +582,9 @@ int V4L2CameraProxy::vidioc_qbuf(V4L2CameraFile *file, struct v4l2_buffer *arg) if (ret < 0) return ret; - arg->flags |= V4L2_BUF_FLAG_QUEUED; - arg->flags &= ~V4L2_BUF_FLAG_DONE; + buffers_[arg->index].flags |= V4L2_BUF_FLAG_QUEUED; + + arg->flags = buffers_[arg->index].flags; return ret; } @@ -618,7 +622,7 @@ int V4L2CameraProxy::vidioc_dqbuf(V4L2CameraFile *file, struct v4l2_buffer *arg) struct v4l2_buffer &buf = buffers_[currentBuf_]; - buf.flags &= ~V4L2_BUF_FLAG_QUEUED; + buf.flags &= ~(V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_DONE); buf.length = sizeimage_; *arg = buf; From patchwork Wed Jun 24 14:52:56 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 8420 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id B6BB5609A5 for ; Wed, 24 Jun 2020 16:54:07 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="VGDtdiN+"; dkim-atps=neutral Received: from jade.rasen.tech (unknown [IPv6:2400:4051:61:600:8147:f2a2:a8c6:9087]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id ECB462A8; Wed, 24 Jun 2020 16:54:05 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1593010447; bh=4PjURdrMQaH5PwCLBd19kqpMlFRZU1ZDQ80XITlobP4=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=VGDtdiN+dJu93JXDXMoow3g6aPatWPFD/TdCrwDIP8QyspG7WcsBWaE4WWe+CbecB ERUXeY+lef6/gNxrzLX6nhe/dw+7b6LvOfoeS03QkXu+25WV9szvzTa74LdkCjqo/e +/4jEV5gnBjDJgBxyf3YHROgv8T1mUNVpo5Se2i8= From: Paul Elder To: libcamera-devel@lists.libcamera.org Date: Wed, 24 Jun 2020 23:52:56 +0900 Message-Id: <20200624145256.48266-23-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20200624145256.48266-1-paul.elder@ideasonboard.com> References: <20200624145256.48266-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 22/22] v4l2: v4l2_camera_proxy: Serialize accesses to the proxy X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 24 Jun 2020 14:54:08 -0000 Make the V4L2 compatibility layer thread-safe by serializing accesses to the V4L2CameraProxy with a lock. Release the lock when blocking for dqbuf. Signed-off-by: Paul Elder Reviewed-by: Laurent Pinchart --- Changes in v4: - cosmetic changes New in v3 --- src/v4l2/v4l2_camera_proxy.cpp | 21 +++++++++++++++++---- src/v4l2/v4l2_camera_proxy.h | 5 ++++- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/src/v4l2/v4l2_camera_proxy.cpp b/src/v4l2/v4l2_camera_proxy.cpp index 3b7a6f4..6896e55 100644 --- a/src/v4l2/v4l2_camera_proxy.cpp +++ b/src/v4l2/v4l2_camera_proxy.cpp @@ -45,6 +45,8 @@ int V4L2CameraProxy::open(V4L2CameraFile *file) { LOG(V4L2Compat, Debug) << "Servicing open fd = " << file->efd(); + MutexLocker locker(proxyMutex_); + if (refcount_++) { files_.insert(file); return 0; @@ -79,6 +81,8 @@ void V4L2CameraProxy::close(V4L2CameraFile *file) { LOG(V4L2Compat, Debug) << "Servicing close fd = " << file->efd(); + MutexLocker locker(proxyMutex_); + files_.erase(file); release(file); @@ -94,6 +98,8 @@ void *V4L2CameraProxy::mmap(void *addr, size_t length, int prot, int flags, { LOG(V4L2Compat, Debug) << "Servicing mmap"; + MutexLocker locker(proxyMutex_); + /* \todo Validate prot and flags properly. */ if (prot != (PROT_READ | PROT_WRITE)) { errno = EINVAL; @@ -128,6 +134,8 @@ int V4L2CameraProxy::munmap(void *addr, size_t length) { LOG(V4L2Compat, Debug) << "Servicing munmap"; + MutexLocker locker(proxyMutex_); + auto iter = mmaps_.find(addr); if (iter == mmaps_.end() || length != sizeimage_) { errno = EINVAL; @@ -589,7 +597,8 @@ int V4L2CameraProxy::vidioc_qbuf(V4L2CameraFile *file, struct v4l2_buffer *arg) return ret; } -int V4L2CameraProxy::vidioc_dqbuf(V4L2CameraFile *file, struct v4l2_buffer *arg) +int V4L2CameraProxy::vidioc_dqbuf(V4L2CameraFile *file, struct v4l2_buffer *arg, + MutexLocker *locker) { LOG(V4L2Compat, Debug) << "Servicing vidioc_dqbuf fd = " << file->efd(); @@ -606,9 +615,11 @@ int V4L2CameraProxy::vidioc_dqbuf(V4L2CameraFile *file, struct v4l2_buffer *arg) !validateMemoryType(arg->memory)) return -EINVAL; - if (!file->nonBlocking()) + if (!file->nonBlocking()) { + locker->unlock(); vcam_->waitForBufferAvailable(); - else if (!vcam_->isBufferAvailable()) + locker->lock(); + } else if (!vcam_->isBufferAvailable()) return -EAGAIN; /* @@ -703,6 +714,8 @@ const std::set V4L2CameraProxy::supportedIoctls_ = { int V4L2CameraProxy::ioctl(V4L2CameraFile *file, unsigned long request, void *arg) { + MutexLocker locker(proxyMutex_); + if (!arg && (_IOC_DIR(request) & _IOC_WRITE)) { errno = EFAULT; return -1; @@ -763,7 +776,7 @@ int V4L2CameraProxy::ioctl(V4L2CameraFile *file, unsigned long request, void *ar ret = vidioc_qbuf(file, static_cast(arg)); break; case VIDIOC_DQBUF: - ret = vidioc_dqbuf(file, static_cast(arg)); + ret = vidioc_dqbuf(file, static_cast(arg), &locker); break; case VIDIOC_STREAMON: ret = vidioc_streamon(file, static_cast(arg)); diff --git a/src/v4l2/v4l2_camera_proxy.h b/src/v4l2/v4l2_camera_proxy.h index 5de2c5a..d78a472 100644 --- a/src/v4l2/v4l2_camera_proxy.h +++ b/src/v4l2/v4l2_camera_proxy.h @@ -61,7 +61,7 @@ private: int vidioc_reqbufs(V4L2CameraFile *file, struct v4l2_requestbuffers *arg); int vidioc_querybuf(V4L2CameraFile *file, struct v4l2_buffer *arg); int vidioc_qbuf(V4L2CameraFile *file, struct v4l2_buffer *arg); - int vidioc_dqbuf(V4L2CameraFile *file, struct v4l2_buffer *arg); + int vidioc_dqbuf(V4L2CameraFile *file, struct v4l2_buffer *arg, MutexLocker *locker); int vidioc_streamon(V4L2CameraFile *file, int *arg); int vidioc_streamoff(V4L2CameraFile *file, int *arg); @@ -105,6 +105,9 @@ private: * will return -EBUSY. */ V4L2CameraFile *owner_; + + /* This mutex is to serialize access to the proxy. */ + Mutex proxyMutex_; }; #endif /* __V4L2_CAMERA_PROXY_H__ */