From patchwork Fri Jun 19 05:41:07 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 4081 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 CD8A1609C3 for ; Fri, 19 Jun 2020 07:41:37 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="ACHmaiAT"; dkim-atps=neutral Received: from jade.flets-east.jp (unknown [IPv6:2400:4051:61:600:e972:d773:e99a:4f79]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 44549556; Fri, 19 Jun 2020 07:41:35 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1592545297; bh=sGpECNNuvQhy36csLwcUlYnqDWMX3dqit3oJ1LHQneg=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=ACHmaiATHk6IIehPUNTJfTVvdvG1a61hlnndxL3s6rBBpFGNXJMEQhJuRM0ZXFb6q 4i89No2Db96/AqJV7uAbrZE6fo01Cm4tIZxiYzxt22BTzM3jn7Zv+HMOiyFGC2Eg25 zVth6mg4Lq4gCfjBpInV3Ehl7XzfImb0UY/0myuA= From: Paul Elder To: libcamera-devel@lists.libcamera.org Date: Fri, 19 Jun 2020 14:41:07 +0900 Message-Id: <20200619054123.19052-2-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20200619054123.19052-1-paul.elder@ideasonboard.com> References: <20200619054123.19052-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 01/17] 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: Fri, 19 Jun 2020 05:41:38 -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 --- New in v2 --- src/v4l2/meson.build | 1 + src/v4l2/v4l2_camera_file.cpp | 45 +++++++++++++++++++++++++++++++++++ src/v4l2/v4l2_camera_file.h | 35 +++++++++++++++++++++++++++ 3 files changed, 81 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..8916729 --- /dev/null +++ b/src/v4l2/v4l2_camera_file.cpp @@ -0,0 +1,45 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * v4l2_camera_file.h - V4L2 compatibility camera file descriptor information + */ + +#include "v4l2_camera_file.h" + +#include + +#include "libcamera/internal/log.h" + +#include "v4l2_camera_proxy.h" + +using namespace libcamera; + +LOG_DECLARE_CATEGORY(V4L2Compat); + +V4L2CameraFile::V4L2CameraFile(int efd, bool nonBlocking, V4L2CameraProxy *proxy) + : priority_(V4L2_PRIORITY_DEFAULT), proxy_(proxy), + nonBlocking_(nonBlocking), efd_(efd) +{ + proxy_->open(nonBlocking); +} + +V4L2CameraFile::~V4L2CameraFile() +{ + proxy_->close(); +} + +V4L2CameraProxy *V4L2CameraFile::proxy() +{ + return proxy_; +} + +bool V4L2CameraFile::nonBlocking() +{ + return nonBlocking_; +} + +int V4L2CameraFile::efd() +{ + return efd_; +} diff --git a/src/v4l2/v4l2_camera_file.h b/src/v4l2/v4l2_camera_file.h new file mode 100644 index 0000000..cf282e9 --- /dev/null +++ b/src/v4l2/v4l2_camera_file.h @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * v4l2_camera_file.h - V4L2 compatibility camera file descriptor 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(); + + bool nonBlocking(); + int efd(); + + enum v4l2_priority priority_; + +private: + V4L2CameraProxy *proxy_; + + bool nonBlocking_; + int efd_; +}; + +#endif /* __V4L2_CAMERA_FILE_H__ */ From patchwork Fri Jun 19 05:41:08 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 4082 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 59F23603BF for ; Fri, 19 Jun 2020 07:41:40 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="PedOHCHd"; dkim-atps=neutral Received: from jade.flets-east.jp (unknown [IPv6:2400:4051:61:600:e972:d773:e99a:4f79]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 58614560; Fri, 19 Jun 2020 07:41:37 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1592545299; bh=NNsvtSY1y0JWES4pCRY/WP/gNPOjNaCwhM+//iyYG8g=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=PedOHCHddPGS+tZzRy5AMvuhg+9iYW0cmnuJrceQ+s2DesMJqgLezII2Ib/NjeguP KGUXihRXYZWim0zeBrNeL8a3NUFUVCWQUqFxwYTNohrfAnWc1KudkVw6VFbQwWAWE3 a01njqfOAeuWBZIh0/TbdN2YWYM8GNP5rWyYNGkE= From: Paul Elder To: libcamera-devel@lists.libcamera.org Date: Fri, 19 Jun 2020 14:41:08 +0900 Message-Id: <20200619054123.19052-3-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20200619054123.19052-1-paul.elder@ideasonboard.com> References: <20200619054123.19052-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 02/17] 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: Fri, 19 Jun 2020 05:41:40 -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 an exclusive lock on the V4L2Camera. All vidioc ioctls prior to reqbufs > 0 (except for s_fmt) are able to access the camera without this exclusive lock. A call to reqbufs > 0 (and s_fmt) will take the lock, and the lock will be released at reqbufs = 0. While the lock is taken, the eventfd that should be signaled (and cleared) by V4L2Camera and V4L2CameraProxy is set to the fd that has taken the lock, and is cleared when the lock is released. In case close() is called without a reqbufs = 0 first, the lock 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. We also handle dup in V4L2CompatManager instead, since that is just another int fd pointing to the same V4L2CameraFile instance. V4L2CompatManager is also modified to access the V4L2CameraProxy through the V4L2CameraFile. Signed-off-by: Paul Elder --- 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_file.cpp | 4 +- src/v4l2/v4l2_camera_proxy.cpp | 201 ++++++++++++++++++++++--------- src/v4l2/v4l2_camera_proxy.h | 47 +++++--- src/v4l2/v4l2_compat_manager.cpp | 71 +++++------ src/v4l2/v4l2_compat_manager.h | 4 +- 7 files changed, 215 insertions(+), 122 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_file.cpp b/src/v4l2/v4l2_camera_file.cpp index 8916729..d07b936 100644 --- a/src/v4l2/v4l2_camera_file.cpp +++ b/src/v4l2/v4l2_camera_file.cpp @@ -21,12 +21,12 @@ V4L2CameraFile::V4L2CameraFile(int efd, bool nonBlocking, V4L2CameraProxy *proxy : priority_(V4L2_PRIORITY_DEFAULT), proxy_(proxy), nonBlocking_(nonBlocking), efd_(efd) { - proxy_->open(nonBlocking); + proxy_->open(this); } V4L2CameraFile::~V4L2CameraFile() { - proxy_->close(); + proxy_->close(this); } V4L2CameraProxy *V4L2CameraFile::proxy() diff --git a/src/v4l2/v4l2_camera_proxy.cpp b/src/v4l2/v4l2_camera_proxy.cpp index bf47aa7..f06f58d 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)) @@ -34,45 +35,57 @@ 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)), efd_(-1), + acquiredCf_(nullptr), initialized_(false) { querycap(camera); } -int V4L2CameraProxy::open(bool nonBlocking) +int V4L2CameraProxy::open(V4L2CameraFile *cf) { - LOG(V4L2Compat, Debug) << "Servicing open"; + LOG(V4L2Compat, Debug) << "Servicing open fd = " << cf->efd(); - int ret = vcam_->open(); - if (ret < 0) { - errno = -ret; - return -1; - } + refcount_++; + + if (initialized_) + return 0; - nonBlocking_ = nonBlocking; + /* + * We will open the camera here, once, and keep it open until the last + * V4L2CameraFile is closed. Before any reqbufs with count > 0 is + * called, anybody can call any ioctl. Once reqbufs is called with + * count > 0, the * exclusive lock will be assigned to that + * V4L2CameraFile, in acquiredCf_. At this point, no other fd can call + * any ioctl (except for querycap, try_fmt, g/s_priority, and + * enum/g/s_input), and they will return -EBUSY. After reqbufs is + * called with count = 0, the exclusive lock will be released. + */ + + initialized_ = true; + + int ret = vcam_->open(); + if (ret < 0) + return ret; vcam_->getStreamConfig(&streamConfig_); setFmtFromConfig(streamConfig_); sizeimage_ = calculateSizeImage(streamConfig_); - refcount_++; - return 0; } -void V4L2CameraProxy::dup() +void V4L2CameraProxy::close(V4L2CameraFile *cf) { - refcount_++; -} + LOG(V4L2Compat, Debug) << "Servicing close fd = " << cf->efd(); -void V4L2CameraProxy::close() -{ - LOG(V4L2Compat, Debug) << "Servicing close"; + unlock(cf); if (--refcount_ > 0) return; vcam_->close(); + + initialized_ = false; } void *V4L2CameraProxy::mmap(void *addr, size_t length, int prot, int flags, @@ -221,9 +234,10 @@ 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 *cf, struct v4l2_fmtdesc *arg) { - LOG(V4L2Compat, Debug) << "Servicing vidioc_enum_fmt"; + LOG(V4L2Compat, Debug) << "Servicing vidioc_enum_fmt fd = " << cf->efd(); + if (!validateBufferType(arg->type) || arg->index >= streamConfig_.formats().pixelformats().size()) @@ -237,9 +251,10 @@ 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 *cf, struct v4l2_format *arg) { - LOG(V4L2Compat, Debug) << "Servicing vidioc_g_fmt"; + LOG(V4L2Compat, Debug) << "Servicing vidioc_g_fmt fd = " << cf->efd(); + if (!validateBufferType(arg->type)) return -EINVAL; @@ -275,9 +290,13 @@ 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 *cf, struct v4l2_format *arg) { - LOG(V4L2Compat, Debug) << "Servicing vidioc_s_fmt"; + LOG(V4L2Compat, Debug) << "Servicing vidioc_s_fmt fd = " << cf->efd(); + + int ret = lock(cf); + if (ret < 0) + return ret; if (!validateBufferType(arg->type)) return -EINVAL; @@ -285,9 +304,9 @@ int V4L2CameraProxy::vidioc_s_fmt(struct v4l2_format *arg) 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; @@ -302,9 +321,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 *cf, struct v4l2_format *arg) { - LOG(V4L2Compat, Debug) << "Servicing vidioc_try_fmt"; + LOG(V4L2Compat, Debug) << "Servicing vidioc_try_fmt fd = " << cf->efd(); if (!validateBufferType(arg->type)) return -EINVAL; @@ -329,11 +348,13 @@ int V4L2CameraProxy::freeBuffers() return 0; } -int V4L2CameraProxy::vidioc_reqbufs(struct v4l2_requestbuffers *arg) +int V4L2CameraProxy::vidioc_reqbufs(V4L2CameraFile *cf, struct v4l2_requestbuffers *arg) { - int ret; + LOG(V4L2Compat, Debug) << "Servicing vidioc_reqbufs fd = " << cf->efd(); - LOG(V4L2Compat, Debug) << "Servicing vidioc_reqbufs"; + int ret = lock(cf); + if (ret < 0) + return ret; if (!validateBufferType(arg->type) || !validateMemoryType(arg->memory)) @@ -342,9 +363,21 @@ int V4L2CameraProxy::vidioc_reqbufs(struct v4l2_requestbuffers *arg) LOG(V4L2Compat, Debug) << arg->count << " buffers requested "; arg->capabilities = V4L2_BUF_CAP_SUPPORTS_MMAP; + memset(arg->reserved, 0, sizeof(arg->reserved)); - if (arg->count == 0) + if (arg->count == 0) { + unlock(cf); return freeBuffers(); + } + + if (bufferCount_ > 0) { + ret = freeBuffers(); + if (ret < 0) { + LOG(V4L2Compat, Error) + << "Failed to free libcamera buffers for re-reqbufs"; + return ret; + } + } Size size(curV4L2Format_.fmt.pix.width, curV4L2Format_.fmt.pix.height); ret = vcam_->configure(&streamConfig_, size, @@ -387,6 +420,7 @@ int V4L2CameraProxy::vidioc_reqbufs(struct v4l2_requestbuffers *arg) 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; } @@ -396,9 +430,13 @@ int V4L2CameraProxy::vidioc_reqbufs(struct v4l2_requestbuffers *arg) return 0; } -int V4L2CameraProxy::vidioc_querybuf(struct v4l2_buffer *arg) +int V4L2CameraProxy::vidioc_querybuf(V4L2CameraFile *cf, struct v4l2_buffer *arg) { - LOG(V4L2Compat, Debug) << "Servicing vidioc_querybuf"; + LOG(V4L2Compat, Debug) << "Servicing vidioc_querybuf fd = " << cf->efd(); + + int ret = lock(cf); + if (ret < 0) + return ret; if (!validateBufferType(arg->type) || arg->index >= bufferCount_) @@ -411,17 +449,21 @@ int V4L2CameraProxy::vidioc_querybuf(struct v4l2_buffer *arg) return 0; } -int V4L2CameraProxy::vidioc_qbuf(struct v4l2_buffer *arg) +int V4L2CameraProxy::vidioc_qbuf(V4L2CameraFile *cf, struct v4l2_buffer *arg) { LOG(V4L2Compat, Debug) << "Servicing vidioc_qbuf, index = " - << arg->index; + << arg->index << " fd = " << cf->efd(); + + int ret = lock(cf); + if (ret < 0) + return ret; if (!validateBufferType(arg->type) || !validateMemoryType(arg->memory) || arg->index >= bufferCount_) return -EINVAL; - int ret = vcam_->qbuf(arg->index); + ret = vcam_->qbuf(arg->index); if (ret < 0) return ret; @@ -431,15 +473,19 @@ int V4L2CameraProxy::vidioc_qbuf(struct v4l2_buffer *arg) return ret; } -int V4L2CameraProxy::vidioc_dqbuf(struct v4l2_buffer *arg) +int V4L2CameraProxy::vidioc_dqbuf(V4L2CameraFile *cf, struct v4l2_buffer *arg) { - LOG(V4L2Compat, Debug) << "Servicing vidioc_dqbuf"; + LOG(V4L2Compat, Debug) << "Servicing vidioc_dqbuf fd = " << cf->efd(); + + int ret = lock(cf); + if (ret < 0) + return ret; if (!validateBufferType(arg->type) || !validateMemoryType(arg->memory)) return -EINVAL; - if (!nonBlocking_) + if (!(cf->nonBlocking())) vcam_->bufferSema_.acquire(); else if (!vcam_->bufferSema_.tryAcquire()) return -EAGAIN; @@ -455,16 +501,20 @@ int V4L2CameraProxy::vidioc_dqbuf(struct v4l2_buffer *arg) currentBuf_ = (currentBuf_ + 1) % bufferCount_; uint64_t data; - int ret = ::read(efd_, &data, sizeof(data)); + ret = ::read(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 *cf, int *arg) { - LOG(V4L2Compat, Debug) << "Servicing vidioc_streamon"; + LOG(V4L2Compat, Debug) << "Servicing vidioc_streamon fd = " << cf->efd(); + + int ret = lock(cf); + if (ret < 0) + return ret; if (!validateBufferType(*arg)) return -EINVAL; @@ -474,14 +524,18 @@ int V4L2CameraProxy::vidioc_streamon(int *arg) return vcam_->streamOn(); } -int V4L2CameraProxy::vidioc_streamoff(int *arg) +int V4L2CameraProxy::vidioc_streamoff(V4L2CameraFile *cf, int *arg) { - LOG(V4L2Compat, Debug) << "Servicing vidioc_streamoff"; + LOG(V4L2Compat, Debug) << "Servicing vidioc_streamoff fd = " << cf->efd(); + + int ret = lock(cf); + if (ret < 0) + return ret; if (!validateBufferType(*arg)) return -EINVAL; - int ret = vcam_->streamOff(); + ret = vcam_->streamOff(); for (struct v4l2_buffer &buf : buffers_) buf.flags &= ~(V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_DONE); @@ -489,7 +543,7 @@ int V4L2CameraProxy::vidioc_streamoff(int *arg) return ret; } -int V4L2CameraProxy::ioctl(unsigned long request, void *arg) +int V4L2CameraProxy::ioctl(V4L2CameraFile *cf, unsigned long request, void *arg) { int ret; switch (request) { @@ -497,34 +551,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(cf, static_cast(arg)); break; case VIDIOC_G_FMT: - ret = vidioc_g_fmt(static_cast(arg)); + ret = vidioc_g_fmt(cf, static_cast(arg)); break; case VIDIOC_S_FMT: - ret = vidioc_s_fmt(static_cast(arg)); + ret = vidioc_s_fmt(cf, static_cast(arg)); break; case VIDIOC_TRY_FMT: - ret = vidioc_try_fmt(static_cast(arg)); + ret = vidioc_try_fmt(cf, static_cast(arg)); break; case VIDIOC_REQBUFS: - ret = vidioc_reqbufs(static_cast(arg)); + ret = vidioc_reqbufs(cf, static_cast(arg)); break; case VIDIOC_QUERYBUF: - ret = vidioc_querybuf(static_cast(arg)); + ret = vidioc_querybuf(cf, static_cast(arg)); break; case VIDIOC_QBUF: - ret = vidioc_qbuf(static_cast(arg)); + ret = vidioc_qbuf(cf, static_cast(arg)); break; case VIDIOC_DQBUF: - ret = vidioc_dqbuf(static_cast(arg)); + ret = vidioc_dqbuf(cf, static_cast(arg)); break; case VIDIOC_STREAMON: - ret = vidioc_streamon(static_cast(arg)); + ret = vidioc_streamon(cf, static_cast(arg)); break; case VIDIOC_STREAMOFF: - ret = vidioc_streamoff(static_cast(arg)); + ret = vidioc_streamoff(cf, static_cast(arg)); break; default: ret = -ENOTTY; @@ -539,10 +593,37 @@ int V4L2CameraProxy::ioctl(unsigned long request, void *arg) return ret; } -void V4L2CameraProxy::bind(int fd) +/** + * \brief Acquire an exclusive lock on the V4L2Camera + * + * \return Zero on success or if already acquired, and negative error on + * failure. + */ +int V4L2CameraProxy::lock(V4L2CameraFile *cf) +{ + if (acquiredCf_ == cf) + return 0; + + if (acquiredCf_) + return -EBUSY; + + efd_ = cf->efd(); + vcam_->bind(efd_); + + acquiredCf_ = cf; + + return 0; +} + +void V4L2CameraProxy::unlock(V4L2CameraFile *cf) { - efd_ = fd; - vcam_->bind(fd); + if (acquiredCf_ != cf) + return; + + efd_ = -1; + vcam_->unbind(); + + acquiredCf_ = nullptr; } struct PixelFormatPlaneInfo { diff --git a/src/v4l2/v4l2_camera_proxy.h b/src/v4l2/v4l2_camera_proxy.h index 27d3e50..43290ca 100644 --- a/src/v4l2/v4l2_camera_proxy.h +++ b/src/v4l2/v4l2_camera_proxy.h @@ -21,20 +21,19 @@ 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 *cfile); + void close(V4L2CameraFile *cf); 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 *cf, unsigned long request, void *arg); private: bool validateBufferType(uint32_t type); @@ -47,16 +46,19 @@ 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 *cf, struct v4l2_fmtdesc *arg); + int vidioc_g_fmt(V4L2CameraFile *cf, struct v4l2_format *arg); + int vidioc_s_fmt(V4L2CameraFile *cf, struct v4l2_format *arg); + int vidioc_try_fmt(V4L2CameraFile *cf, struct v4l2_format *arg); + int vidioc_reqbufs(V4L2CameraFile *cf, struct v4l2_requestbuffers *arg); + int vidioc_querybuf(V4L2CameraFile *cf, struct v4l2_buffer *arg); + int vidioc_qbuf(V4L2CameraFile *cf, struct v4l2_buffer *arg); + int vidioc_dqbuf(V4L2CameraFile *cf, struct v4l2_buffer *arg); + int vidioc_streamon(V4L2CameraFile *cf, int *arg); + int vidioc_streamoff(V4L2CameraFile *cf, int *arg); + + int lock(V4L2CameraFile *cf); + void unlock(V4L2CameraFile *cf); static unsigned int bplMultiplier(uint32_t format); static unsigned int imageSize(uint32_t format, unsigned int width, @@ -67,7 +69,6 @@ private: unsigned int refcount_; unsigned int index_; - bool nonBlocking_; struct v4l2_format curV4L2Format_; StreamConfiguration streamConfig_; @@ -82,6 +83,18 @@ private: std::unique_ptr vcam_; int efd_; + + /* + * This is an exclusive lock on the camera. When this is not taken, + * anybody can call any ioctl before reqbufs. reqbufs with count > 0 + * will claim this lock, and reqbufs with count = 0 will release it. + * Any ioctl is called while the lock is taken will return -EBUSY + * (if applicable, eg. try_fmt, querycap, g/s_priority, and + * enum/g/s_input are exempt). + */ + V4L2CameraFile *acquiredCf_; + + bool initialized_; }; #endif /* __V4L2_CAMERA_PROXY_H__ */ diff --git a/src/v4l2/v4l2_compat_manager.cpp b/src/v4l2/v4l2_compat_manager.cpp index 8da3316..9cede76 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(); + cameraFiles_.clear(); mmaps_.clear(); if (cm_) { @@ -95,13 +97,13 @@ V4L2CompatManager *V4L2CompatManager::instance() return &instance; } -V4L2CameraProxy *V4L2CompatManager::getProxy(int fd) +std::shared_ptr V4L2CompatManager::getCameraFile(int fd) { - auto device = devices_.find(fd); - if (device == devices_.end()) - return nullptr; + auto cameraFile = cameraFiles_.find(fd); + if (cameraFile == cameraFiles_.end()) + return std::shared_ptr(); - return device->second; + return cameraFile->second; } int V4L2CompatManager::getCameraIndex(int fd) @@ -148,25 +150,17 @@ 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); + unsigned int camera_index = static_cast(ret); + + V4L2CameraProxy *proxy = proxies_[camera_index].get(); + + cameraFiles_.emplace(efd, std::make_shared(efd, oflag & O_NONBLOCK, proxy)); return efd; } @@ -177,40 +171,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 cameraFile = cameraFiles_.find(oldfd); + if (cameraFile != cameraFiles_.end()) + cameraFiles_[newfd] = cameraFile->second; return newfd; } int V4L2CompatManager::close(int fd) { - V4L2CameraProxy *proxy = getProxy(fd); - if (proxy) { - proxy->close(); - devices_.erase(fd); - return 0; - } + std::shared_ptr cameraFile = getCameraFile(fd); + if (cameraFile) + cameraFiles_.erase(fd); + /* 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 cameraFile = getCameraFile(fd); + if (!cameraFile) return fops_.mmap(addr, length, prot, flags, fd, offset); - void *map = proxy->mmap(addr, length, prot, flags, offset); + void *map = cameraFile->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] = cameraFile->proxy(); return map; } @@ -233,9 +226,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 cameraFile = getCameraFile(fd); + if (!cameraFile) return fops_.ioctl(fd, request, arg); - return proxy->ioctl(request, arg); + return cameraFile->proxy()->ioctl(cameraFile.get(), request, arg); } diff --git a/src/v4l2/v4l2_compat_manager.h b/src/v4l2/v4l2_compat_manager.h index 3d4e512..b92f147 100644 --- a/src/v4l2/v4l2_compat_manager.h +++ b/src/v4l2/v4l2_compat_manager.h @@ -44,7 +44,7 @@ public: static V4L2CompatManager *instance(); - V4L2CameraProxy *getProxy(int fd); + std::shared_ptr getCameraFile(int fd); const FileOperations &fops() const { return fops_; } int openat(int dirfd, const char *path, int oflag, mode_t mode); @@ -68,7 +68,7 @@ private: CameraManager *cm_; std::vector> proxies_; - std::map devices_; + std::map> cameraFiles_; std::map mmaps_; }; From patchwork Fri Jun 19 05:41:09 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 4083 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 43972603BF for ; Fri, 19 Jun 2020 07:41:42 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="oNNbvBke"; dkim-atps=neutral Received: from jade.flets-east.jp (unknown [IPv6:2400:4051:61:600:e972:d773:e99a:4f79]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id BF14D556; Fri, 19 Jun 2020 07:41:40 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1592545302; bh=qsEFtr5cbT/jPDimSbuKHA1vG1SLI29s7gEV9/ny+18=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=oNNbvBkeuA+dvOgyZXYwuTft8pwS5+7mNfC1C2LPN7CJt8mQKWXkjuREP8p+LprcV 2uHDmG54dxNiSb+K/mdLS+twKIYdaqDLVmXS22IBbam/4zUYVtLN58Zgv9gRUau0V/ /9gZd/I5XkJYYiE4YW7cEy2pfknZzzrn+LzT9+Ag= From: Paul Elder To: libcamera-devel@lists.libcamera.org Date: Fri, 19 Jun 2020 14:41:09 +0900 Message-Id: <20200619054123.19052-4-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20200619054123.19052-1-paul.elder@ideasonboard.com> References: <20200619054123.19052-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 03/17] 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: Fri, 19 Jun 2020 05:41:42 -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 --- 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 | 27 +++++++++++++++++++++++++-- src/v4l2/v4l2_camera_proxy.h | 3 +++ 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/src/v4l2/v4l2_camera_proxy.cpp b/src/v4l2/v4l2_camera_proxy.cpp index f06f58d..cff6562 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 @@ -238,7 +239,6 @@ int V4L2CameraProxy::vidioc_enum_fmt(V4L2CameraFile *cf, struct v4l2_fmtdesc *ar { LOG(V4L2Compat, Debug) << "Servicing vidioc_enum_fmt fd = " << cf->efd(); - if (!validateBufferType(arg->type) || arg->index >= streamConfig_.formats().pixelformats().size()) return -EINVAL; @@ -255,7 +255,6 @@ int V4L2CameraProxy::vidioc_g_fmt(V4L2CameraFile *cf, struct v4l2_format *arg) { LOG(V4L2Compat, Debug) << "Servicing vidioc_g_fmt fd = " << cf->efd(); - if (!validateBufferType(arg->type)) return -EINVAL; @@ -543,8 +542,32 @@ int V4L2CameraProxy::vidioc_streamoff(V4L2CameraFile *cf, int *arg) return ret; } +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 *cf, unsigned long request, void *arg) { + if (supportedIoctls_.find(request) == supportedIoctls_.end()) { + errno = ENOTTY; + return -1; + } + + if (!arg) { + 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 43290ca..dd7e793 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 @@ -67,6 +68,8 @@ private: static PixelFormat v4l2ToDrm(uint32_t format); static uint32_t drmToV4L2(const PixelFormat &format); + static std::set supportedIoctls_; + unsigned int refcount_; unsigned int index_; From patchwork Fri Jun 19 05:41:10 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 4084 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 7CF83603BF for ; Fri, 19 Jun 2020 07:41:44 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="kJwh05q1"; dkim-atps=neutral Received: from jade.flets-east.jp (unknown [IPv6:2400:4051:61:600:e972:d773:e99a:4f79]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id B1A1D556; Fri, 19 Jun 2020 07:41:42 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1592545304; bh=33ssX//7W0WG6gbEODzOKGfeQ0U+cLC4dpbe21cX/m8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=kJwh05q1IrkFskIpBkZHDtgw8E9cpLKorM/xUCl7eilaBeRKkbgjrfOpTb9SQ+v65 bdDONi7eVJQIJC2T1K8zIaqIFtYgJ6+SDnp/7+81/mQIkg+VFkz970w06ZN54d4Ste 0Ipvs8Y+lg4kArRo4AcHjVOd0UjDCfLbDIWxNBQ0= From: Paul Elder To: libcamera-devel@lists.libcamera.org Date: Fri, 19 Jun 2020 14:41:10 +0900 Message-Id: <20200619054123.19052-5-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20200619054123.19052-1-paul.elder@ideasonboard.com> References: <20200619054123.19052-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 04/17] 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: Fri, 19 Jun 2020 05:41:44 -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 --- 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 | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/v4l2/v4l2_camera_proxy.cpp b/src/v4l2/v4l2_camera_proxy.cpp index cff6562..117d7ff 100644 --- a/src/v4l2/v4l2_camera_proxy.cpp +++ b/src/v4l2/v4l2_camera_proxy.cpp @@ -168,6 +168,9 @@ 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; } unsigned int V4L2CameraProxy::calculateSizeImage(StreamConfiguration &streamConfig) @@ -194,7 +197,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)); @@ -243,11 +248,15 @@ int V4L2CameraProxy::vidioc_enum_fmt(V4L2CameraFile *cf, struct v4l2_fmtdesc *ar 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; } @@ -287,6 +296,9 @@ 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; } int V4L2CameraProxy::vidioc_s_fmt(V4L2CameraFile *cf, struct v4l2_format *arg) From patchwork Fri Jun 19 05:41:11 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 4085 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 7FD1A603BF for ; Fri, 19 Jun 2020 07:41:46 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="twaA/TXG"; dkim-atps=neutral Received: from jade.flets-east.jp (unknown [IPv6:2400:4051:61:600:e972:d773:e99a:4f79]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id EF232556; Fri, 19 Jun 2020 07:41:44 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1592545306; bh=gFr7DJnqrrD48VO4JMq4OvrvnusUHZbSZNpenGeTllg=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=twaA/TXGwvbNrOPnJ8lC0p4H6cDtsDjR3N88I5MV+xb+i90M/ZKdBIuTzzw9XvmRp 3U02VZkgAEf+3ST6eCCWeqKS1+AO4zvOGxHUDEYe6pZIQALiIxFvVkUNiakq1wpxpj I4l4fL6MreGYrLbF+kH1cp7OowuWNQtDafhX1jkM= From: Paul Elder To: libcamera-devel@lists.libcamera.org Date: Fri, 19 Jun 2020 14:41:11 +0900 Message-Id: <20200619054123.19052-6-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20200619054123.19052-1-paul.elder@ideasonboard.com> References: <20200619054123.19052-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 05/17] 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: Fri, 19 Jun 2020 05:41:46 -0000 Implement VIDIOC_G_PRIORITY and VIDIOC_S_PRIORITY, according to what v4l2-compliance wants. Signed-off-by: Paul Elder --- Changes in v2: - use V4L2CameraFile instead of fd and priorities map --- src/v4l2/v4l2_camera_proxy.cpp | 42 +++++++++++++++++++++++++++++++++- src/v4l2/v4l2_camera_proxy.h | 3 +++ 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/src/v4l2/v4l2_camera_proxy.cpp b/src/v4l2/v4l2_camera_proxy.cpp index 117d7ff..3e95645 100644 --- a/src/v4l2/v4l2_camera_proxy.cpp +++ b/src/v4l2/v4l2_camera_proxy.cpp @@ -37,7 +37,8 @@ V4L2CameraProxy::V4L2CameraProxy(unsigned int index, std::shared_ptr camera) : refcount_(0), index_(index), bufferCount_(0), currentBuf_(0), vcam_(std::make_unique(camera)), efd_(-1), - acquiredCf_(nullptr), initialized_(false) + v4l2RecordPriorityCf_(nullptr), acquiredCf_(nullptr), + initialized_(false) { querycap(camera); } @@ -344,6 +345,37 @@ int V4L2CameraProxy::vidioc_try_fmt(V4L2CameraFile *cf, struct v4l2_format *arg) return 0; } +int V4L2CameraProxy::vidioc_g_priority(V4L2CameraFile *cf, enum v4l2_priority *arg) +{ + LOG(V4L2Compat, Debug) << "Servicing vidioc_g_priority fd = " << cf->efd(); + + if (v4l2RecordPriorityCf_) + *arg = V4L2_PRIORITY_RECORD; + else + *arg = cf->priority_; + + return 0; +} + +int V4L2CameraProxy::vidioc_s_priority(V4L2CameraFile *cf, enum v4l2_priority *arg) +{ + LOG(V4L2Compat, Debug) + << "Servicing vidioc_s_priority fd = " << cf->efd() + << " prio = " << (int)*arg; + + if (v4l2RecordPriorityCf_ && v4l2RecordPriorityCf_ != cf) + return -EBUSY; + + if (*arg == V4L2_PRIORITY_RECORD) + v4l2RecordPriorityCf_ = cf; + else if (v4l2RecordPriorityCf_ == cf) + v4l2RecordPriorityCf_ = nullptr; + + cf->priority_ = *arg; + + return 0; +} + int V4L2CameraProxy::freeBuffers() { LOG(V4L2Compat, Debug) << "Freeing libcamera bufs"; @@ -560,6 +592,8 @@ 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, @@ -597,6 +631,12 @@ int V4L2CameraProxy::ioctl(V4L2CameraFile *cf, unsigned long request, void *arg) case VIDIOC_TRY_FMT: ret = vidioc_try_fmt(cf, static_cast(arg)); break; + case VIDIOC_G_PRIORITY: + ret = vidioc_g_priority(cf, static_cast(arg)); + break; + case VIDIOC_S_PRIORITY: + ret = vidioc_s_priority(cf, static_cast(arg)); + break; case VIDIOC_REQBUFS: ret = vidioc_reqbufs(cf, static_cast(arg)); break; diff --git a/src/v4l2/v4l2_camera_proxy.h b/src/v4l2/v4l2_camera_proxy.h index dd7e793..3260eec 100644 --- a/src/v4l2/v4l2_camera_proxy.h +++ b/src/v4l2/v4l2_camera_proxy.h @@ -51,6 +51,8 @@ private: int vidioc_g_fmt(V4L2CameraFile *cf, struct v4l2_format *arg); int vidioc_s_fmt(V4L2CameraFile *cf, struct v4l2_format *arg); int vidioc_try_fmt(V4L2CameraFile *cf, struct v4l2_format *arg); + int vidioc_g_priority(V4L2CameraFile *cf, enum v4l2_priority *arg); + int vidioc_s_priority(V4L2CameraFile *cf, enum v4l2_priority *arg); int vidioc_reqbufs(V4L2CameraFile *cf, struct v4l2_requestbuffers *arg); int vidioc_querybuf(V4L2CameraFile *cf, struct v4l2_buffer *arg); int vidioc_qbuf(V4L2CameraFile *cf, struct v4l2_buffer *arg); @@ -87,6 +89,7 @@ private: int efd_; + V4L2CameraFile *v4l2RecordPriorityCf_; /* * This is an exclusive lock on the camera. When this is not taken, * anybody can call any ioctl before reqbufs. reqbufs with count > 0 From patchwork Fri Jun 19 05:41:12 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 4086 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 0879D603BF for ; Fri, 19 Jun 2020 07:41:49 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="s9tUmBdp"; dkim-atps=neutral Received: from jade.flets-east.jp (unknown [IPv6:2400:4051:61:600:e972:d773:e99a:4f79]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id E2139556; Fri, 19 Jun 2020 07:41:46 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1592545308; bh=USR0E8AUhRg8JcikxWau5HbGH0xOr85PKz/bM+2Dn54=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=s9tUmBdpg0W4AoJjY84p/5PzzsgnzSJMSFMtY/nurkVuzHOgsOFCNs9FsjgxWlp4A 41HvIBk1ABlh9LBEIENEgsMkB97hpE4Y9BQeQggnibFXzKahd/vAf9SRvgJG8vtgUt SRkJeaaIqgxKfYVE2cZmK6nH1otm8Rk7harZUZMU= From: Paul Elder To: libcamera-devel@lists.libcamera.org Date: Fri, 19 Jun 2020 14:41:12 +0900 Message-Id: <20200619054123.19052-7-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20200619054123.19052-1-paul.elder@ideasonboard.com> References: <20200619054123.19052-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 06/17] 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: Fri, 19 Jun 2020 05:41:49 -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 --- 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 3e95645..3ac9068 100644 --- a/src/v4l2/v4l2_camera_proxy.cpp +++ b/src/v4l2/v4l2_camera_proxy.cpp @@ -376,6 +376,42 @@ int V4L2CameraProxy::vidioc_s_priority(V4L2CameraFile *cf, enum v4l2_priority *a return 0; } +int V4L2CameraProxy::vidioc_enuminput(V4L2CameraFile *cf, struct v4l2_input *arg) +{ + LOG(V4L2Compat, Debug) << "Servicing vidioc_enuminput fd = " << cf->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 *cf, int *arg) +{ + LOG(V4L2Compat, Debug) << "Servicing vidioc_g_input fd = " << cf->efd(); + + *arg = 0; + + return 0; +} + +int V4L2CameraProxy::vidioc_s_input(V4L2CameraFile *cf, int *arg) +{ + LOG(V4L2Compat, Debug) << "Servicing vidioc_s_input fd = " << cf->efd(); + + if (*arg != 0) + return -EINVAL; + + return 0; +} + int V4L2CameraProxy::freeBuffers() { LOG(V4L2Compat, Debug) << "Freeing libcamera bufs"; @@ -594,6 +630,9 @@ 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, @@ -637,6 +676,15 @@ int V4L2CameraProxy::ioctl(V4L2CameraFile *cf, unsigned long request, void *arg) case VIDIOC_S_PRIORITY: ret = vidioc_s_priority(cf, static_cast(arg)); break; + case VIDIOC_ENUMINPUT: + ret = vidioc_enuminput(cf, static_cast(arg)); + break; + case VIDIOC_G_INPUT: + ret = vidioc_g_input(cf, static_cast(arg)); + break; + case VIDIOC_S_INPUT: + ret = vidioc_s_input(cf, static_cast(arg)); + break; case VIDIOC_REQBUFS: ret = vidioc_reqbufs(cf, static_cast(arg)); break; diff --git a/src/v4l2/v4l2_camera_proxy.h b/src/v4l2/v4l2_camera_proxy.h index 3260eec..46573e7 100644 --- a/src/v4l2/v4l2_camera_proxy.h +++ b/src/v4l2/v4l2_camera_proxy.h @@ -53,6 +53,9 @@ private: int vidioc_try_fmt(V4L2CameraFile *cf, struct v4l2_format *arg); int vidioc_g_priority(V4L2CameraFile *cf, enum v4l2_priority *arg); int vidioc_s_priority(V4L2CameraFile *cf, enum v4l2_priority *arg); + int vidioc_enuminput(V4L2CameraFile *cf, struct v4l2_input *arg); + int vidioc_g_input(V4L2CameraFile *cf, int *arg); + int vidioc_s_input(V4L2CameraFile *cf, int *arg); int vidioc_reqbufs(V4L2CameraFile *cf, struct v4l2_requestbuffers *arg); int vidioc_querybuf(V4L2CameraFile *cf, struct v4l2_buffer *arg); int vidioc_qbuf(V4L2CameraFile *cf, struct v4l2_buffer *arg); From patchwork Fri Jun 19 05:41:13 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 4087 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 42A7C609E1 for ; Fri, 19 Jun 2020 07:41:51 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="r0cOPaQk"; dkim-atps=neutral Received: from jade.flets-east.jp (unknown [IPv6:2400:4051:61:600:e972:d773:e99a:4f79]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 76A78556; Fri, 19 Jun 2020 07:41:49 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1592545311; bh=vGb0v2Qe4a5GkACDESiVUZkH+2mUvCWPa0Kz/ayyStQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=r0cOPaQkJtQAN1pvlixK7rIdoHvlvhAhuKf73sdzAraUE6ffsVpooBhetB62QTnG2 xWpt/LHSQcEhvK73OB4gVLxKCGmFXLEtVjTKa7az/rBxq1bLlCO4PkVCwKKyYeVVJH pF4PjtE7EwJVxmE2bT/78FrkUlkVvR2s4R+S8ulA= From: Paul Elder To: libcamera-devel@lists.libcamera.org Date: Fri, 19 Jun 2020 14:41:13 +0900 Message-Id: <20200619054123.19052-8-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20200619054123.19052-1-paul.elder@ideasonboard.com> References: <20200619054123.19052-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 07/17] 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: Fri, 19 Jun 2020 05:41:51 -0000 Implement VIDIOC_ENUM_FRAMESIZES in the V4L2 compatibility layer. Signed-off-by: Paul Elder Reviewed-by: Laurent Pinchart --- 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 3ac9068..c3032f5 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 *cf, struct v4l2_frmsizeenum *arg) +{ + LOG(V4L2Compat, Debug) << "Servicing vidioc_enum_framesizes fd = " << cf->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 *cf, struct v4l2_fmtdesc *arg) { LOG(V4L2Compat, Debug) << "Servicing vidioc_enum_fmt fd = " << cf->efd(); @@ -624,6 +646,7 @@ int V4L2CameraProxy::vidioc_streamoff(V4L2CameraFile *cf, int *arg) std::set V4L2CameraProxy::supportedIoctls_ = { VIDIOC_QUERYCAP, + VIDIOC_ENUM_FRAMESIZES, VIDIOC_ENUM_FMT, VIDIOC_G_FMT, VIDIOC_S_FMT, @@ -658,6 +681,9 @@ int V4L2CameraProxy::ioctl(V4L2CameraFile *cf, unsigned long request, void *arg) case VIDIOC_QUERYCAP: ret = vidioc_querycap(static_cast(arg)); break; + case VIDIOC_ENUM_FRAMESIZES: + ret = vidioc_enum_framesizes(cf, static_cast(arg)); + break; case VIDIOC_ENUM_FMT: ret = vidioc_enum_fmt(cf, static_cast(arg)); break; diff --git a/src/v4l2/v4l2_camera_proxy.h b/src/v4l2/v4l2_camera_proxy.h index 46573e7..363d366 100644 --- a/src/v4l2/v4l2_camera_proxy.h +++ b/src/v4l2/v4l2_camera_proxy.h @@ -47,6 +47,7 @@ private: int freeBuffers(); int vidioc_querycap(struct v4l2_capability *arg); + int vidioc_enum_framesizes(V4L2CameraFile *cf, struct v4l2_frmsizeenum *arg); int vidioc_enum_fmt(V4L2CameraFile *cf, struct v4l2_fmtdesc *arg); int vidioc_g_fmt(V4L2CameraFile *cf, struct v4l2_format *arg); int vidioc_s_fmt(V4L2CameraFile *cf, struct v4l2_format *arg); From patchwork Fri Jun 19 05:41:14 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 4088 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 513E0609A5 for ; Fri, 19 Jun 2020 07:41:53 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="WoY3/tEV"; dkim-atps=neutral Received: from jade.flets-east.jp (unknown [IPv6:2400:4051:61:600:e972:d773:e99a:4f79]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id B4566560; Fri, 19 Jun 2020 07:41:51 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1592545313; bh=/1L4CVU2+G6aI+2mN32EUHKd69uGE54tmIScfYS8VQo=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=WoY3/tEVdrjrb06lbXxfHLc79r8q5wWGzGK2NdYexmRbQt6BjhF3XVr5x+/EIyiiO S1O98pp+Hq4x11JVZucjZQ8fYbQjJ0itnm5+zxugnWYOVAw7p5Z+f449wkVQBameLJ 2+y4aNpR66C/b8GBVXHUUGlrt6Q08KrVQUuMsvb8= From: Paul Elder To: libcamera-devel@lists.libcamera.org Date: Fri, 19 Jun 2020 14:41:14 +0900 Message-Id: <20200619054123.19052-9-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20200619054123.19052-1-paul.elder@ideasonboard.com> References: <20200619054123.19052-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 08/17] 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: Fri, 19 Jun 2020 05:41:53 -0000 Add a method isRunning() to V4L2Camera so that V4L2CameraProxy can use it for checks. Signed-off-by: Paul Elder Reviewed-by: Laurent Pinchart --- 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..c157a80 100644 --- a/src/v4l2/v4l2_camera.h +++ b/src/v4l2/v4l2_camera.h @@ -59,6 +59,8 @@ public: Semaphore bufferSema_; + bool isRunning(); + private: void requestComplete(Request *request); From patchwork Fri Jun 19 05:41:15 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 4089 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 3F393603BF for ; Fri, 19 Jun 2020 07:41:55 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="wFTJp/Zp"; dkim-atps=neutral Received: from jade.flets-east.jp (unknown [IPv6:2400:4051:61:600:e972:d773:e99a:4f79]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id C09C7556; Fri, 19 Jun 2020 07:41:53 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1592545315; bh=yWM+IpS+mbq48Xu1ydHWgzLhFuqMRaz6VRkM/ncO3ts=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=wFTJp/Zp0tDIeeK+yWZI2hgk0IeajalDY5shaUJvmJA+UOcp6wTnuW+jJ8n57Pl0y KbW0MmaEXtcE5QFZbYflzvNSfrAZ3g3qL5baDe7wCaX6IcErbAcPbFTvfhudaHKwne 12lG4sMsRwjwfTPoLK+0uuZfMM5zYLDF8f0I6ziY= From: Paul Elder To: libcamera-devel@lists.libcamera.org Date: Fri, 19 Jun 2020 14:41:15 +0900 Message-Id: <20200619054123.19052-10-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20200619054123.19052-1-paul.elder@ideasonboard.com> References: <20200619054123.19052-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 09/17] 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: Fri, 19 Jun 2020 05:41:55 -0000 Make VIDIOC_DQBUF return -EINVAL if the stream is not turned on. Signed-off-by: Paul Elder Reviewed-by: Laurent Pinchart --- 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 c3032f5..63c6a2c 100644 --- a/src/v4l2/v4l2_camera_proxy.cpp +++ b/src/v4l2/v4l2_camera_proxy.cpp @@ -578,6 +578,9 @@ int V4L2CameraProxy::vidioc_dqbuf(V4L2CameraFile *cf, struct v4l2_buffer *arg) { LOG(V4L2Compat, Debug) << "Servicing vidioc_dqbuf fd = " << cf->efd(); + if (!vcam_->isRunning()) + return -EINVAL; + int ret = lock(cf); if (ret < 0) return ret; From patchwork Fri Jun 19 05:41:16 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 4090 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 5A0E060AF2 for ; Fri, 19 Jun 2020 07:41:57 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="uW6h0MdB"; dkim-atps=neutral Received: from jade.flets-east.jp (unknown [IPv6:2400:4051:61:600:e972:d773:e99a:4f79]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id B3000556; Fri, 19 Jun 2020 07:41:55 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1592545316; bh=H/ZXtk9Q6IOQXuUmU2vYulaC9dDGP7RKuMI30+7YygM=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=uW6h0MdB0/JDzMk6pbnVJQ1fHtubi1siilWpZt0mzn38zmLW88h6nKmxUcyfSHwNd XmxLTuF6Hap7Hgv4pZlOVKlnb8laZ0yAYD6Dv73TRjRC5UKY50HRHpTgot1PKqBFjv 1P5v9qedzcpQcUmCYzZKCxR6QGdSPiY9nfDpm1Es= From: Paul Elder To: libcamera-devel@lists.libcamera.org Date: Fri, 19 Jun 2020 14:41:16 +0900 Message-Id: <20200619054123.19052-11-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20200619054123.19052-1-paul.elder@ideasonboard.com> References: <20200619054123.19052-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 10/17] 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: Fri, 19 Jun 2020 05:41:57 -0000 If VIDIOC_STREMAON is called when the stream is already on, do a noop. Signed-off-by: Paul Elder Reviewed-by: Laurent Pinchart --- 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 63c6a2c..4d37662 100644 --- a/src/v4l2/v4l2_camera_proxy.cpp +++ b/src/v4l2/v4l2_camera_proxy.cpp @@ -616,6 +616,9 @@ int V4L2CameraProxy::vidioc_streamon(V4L2CameraFile *cf, int *arg) { LOG(V4L2Compat, Debug) << "Servicing vidioc_streamon fd = " << cf->efd(); + if (vcam_->isRunning()) + return 0; + int ret = lock(cf); if (ret < 0) return ret; From patchwork Fri Jun 19 05:41:17 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 4091 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 75478603BF for ; Fri, 19 Jun 2020 07:41:59 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="bB+uM5R5"; dkim-atps=neutral Received: from jade.flets-east.jp (unknown [IPv6:2400:4051:61:600:e972:d773:e99a:4f79]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id D78BA560; Fri, 19 Jun 2020 07:41:57 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1592545319; bh=W52v2DQg7LLqnYD/r4aRbVYa6Ehhg8VDTR30Lz3Zo18=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=bB+uM5R5z1k//GFldIY+n5yu2BZlLY0cd1/eZn3fI4a5tbKLAxeXpUpNXA0xiKaOk oJji9RBKcXzNefslVuin99nXHpz2RQ8DnixnJKLyy/ZJA/hzAF2heH4wA4CgE4l2qp qdlV/yXApr/zjy6B6HSHK4OiOtxdi+MvHrLCEpj0= From: Paul Elder To: libcamera-devel@lists.libcamera.org Date: Fri, 19 Jun 2020 14:41:17 +0900 Message-Id: <20200619054123.19052-12-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20200619054123.19052-1-paul.elder@ideasonboard.com> References: <20200619054123.19052-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 11/17] v4l2: v4l2_camera_proxy: Reset buffer flags 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: Fri, 19 Jun 2020 05:41:59 -0000 VIDIOC_REQBUFS with count = 0 should also exhibit the same effects as VIDIOC_STREAMOFF if the stream is on. Mainly, the queued and done flags need to be cleared. Do these in the handler for VIDIOC_REQBUFS. Signed-off-by: Paul Elder --- Changes in v2: - call only the necessary components, instead of V4L2CameraProxy::vidioc_streamoff --- src/v4l2/v4l2_camera_proxy.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/v4l2/v4l2_camera_proxy.cpp b/src/v4l2/v4l2_camera_proxy.cpp index 4d37662..ea9222e 100644 --- a/src/v4l2/v4l2_camera_proxy.cpp +++ b/src/v4l2/v4l2_camera_proxy.cpp @@ -467,6 +467,11 @@ int V4L2CameraProxy::vidioc_reqbufs(V4L2CameraFile *cf, struct v4l2_requestbuffe memset(arg->reserved, 0, sizeof(arg->reserved)); if (arg->count == 0) { + if (vcam_->isRunning()) { + for (struct v4l2_buffer &buf : buffers_) + buf.flags &= ~(V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_DONE); + } + unlock(cf); return freeBuffers(); } From patchwork Fri Jun 19 05:41:18 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 4092 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 72367609A7 for ; Fri, 19 Jun 2020 07:42:01 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="OHm2W6X1"; dkim-atps=neutral Received: from jade.flets-east.jp (unknown [IPv6:2400:4051:61:600:e972:d773:e99a:4f79]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id E34FA560; Fri, 19 Jun 2020 07:41:59 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1592545321; bh=P8VxN//P3vIGvUWSadYiGJnZywgwSjWut3in5YWpaFs=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=OHm2W6X1Ut+YVirMnHPIN8YDGhngab0sDWDQL5mrvxqsiYtCdRVLgV/wCuspm3UQh TdAyC/o3Jc+H/UNiIx/WzzQv5hKKmUNcwRlkU35WQcVMGhZ0p+TYpsvUm4Rim+wYtl am7437HKSzSFU0EV9Nui9woz6YPhffvwK2Ct62lQ= From: Paul Elder To: libcamera-devel@lists.libcamera.org Date: Fri, 19 Jun 2020 14:41:18 +0900 Message-Id: <20200619054123.19052-13-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20200619054123.19052-1-paul.elder@ideasonboard.com> References: <20200619054123.19052-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 12/17] 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: Fri, 19 Jun 2020 05:42:01 -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 --- Changes in v2: - remove mutex for isRunning_ - use V4L2Camera::isRunning() instead of V4L2CameraProxy::streaming_ in the dqbuf ioctl handler --- src/v4l2/v4l2_camera.cpp | 28 ++++++++++++++++++++++++++-- src/v4l2/v4l2_camera.h | 7 ++++++- src/v4l2/v4l2_camera_proxy.cpp | 11 +++++++++-- 3 files changed, 41 insertions(+), 5 deletions(-) diff --git a/src/v4l2/v4l2_camera.cpp b/src/v4l2/v4l2_camera.cpp index 177b1ea..99d34b9 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,9 @@ 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, @@ -144,6 +146,7 @@ int V4L2Camera::allocBuffers(unsigned int count) void V4L2Camera::freeBuffers() { Stream *stream = *camera_->streams().begin(); + bufferAllocator_->free(stream); } @@ -193,6 +196,7 @@ int V4L2Camera::streamOff() return ret == -EACCES ? -EBUSY : ret; isRunning_ = false; + bufferCV_.notify_all(); return 0; } @@ -228,6 +232,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 c157a80..515e906 100644 --- a/src/v4l2/v4l2_camera.h +++ b/src/v4l2/v4l2_camera.h @@ -57,7 +57,8 @@ public: int qbuf(unsigned int index); - Semaphore bufferSema_; + void waitForBufferAvailable(); + bool isBufferAvailable(); bool isRunning(); @@ -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 ea9222e..2723450 100644 --- a/src/v4l2/v4l2_camera_proxy.cpp +++ b/src/v4l2/v4l2_camera_proxy.cpp @@ -595,10 +595,17 @@ int V4L2CameraProxy::vidioc_dqbuf(V4L2CameraFile *cf, struct v4l2_buffer *arg) return -EINVAL; if (!(cf->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 dqbuf. + */ + if (!vcam_->isRunning()) + return -EINVAL; + updateBuffers(); struct v4l2_buffer &buf = buffers_[currentBuf_]; From patchwork Fri Jun 19 05:41:19 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 4093 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 9FD84603BF for ; Fri, 19 Jun 2020 07:42:03 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="hR5DiO/s"; dkim-atps=neutral Received: from jade.flets-east.jp (unknown [IPv6:2400:4051:61:600:e972:d773:e99a:4f79]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id D5F55560; Fri, 19 Jun 2020 07:42:01 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1592545323; bh=V65Bq0jLP4sLjT4P5OiWcus3Rt72bXo3FMcikhMaMuY=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=hR5DiO/sbBwPgBh1/gK/y9EftL9yAwpuEb83y6yLN4RhxU82AyVUUU3mt6CB4blQO RCVfcP0aWoKfgy9QBDTJQq8972eCx0xDdS36a9KNvfUvNW/kT6DdkZPsvCUFx7phMo wbYHvu8MG1NtMwcsZC8VjwIh9SvFAh8AMyG6Se1E= From: Paul Elder To: libcamera-devel@lists.libcamera.org Date: Fri, 19 Jun 2020 14:41:19 +0900 Message-Id: <20200619054123.19052-14-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20200619054123.19052-1-paul.elder@ideasonboard.com> References: <20200619054123.19052-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 13/17] 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: Fri, 19 Jun 2020 05:42:03 -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 --- Changes in v2: - also clear pending request queue on streamOff - clarify the issue in changelog --- src/v4l2/v4l2_camera.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/v4l2/v4l2_camera.cpp b/src/v4l2/v4l2_camera.cpp index 99d34b9..301a80e 100644 --- a/src/v4l2/v4l2_camera.cpp +++ b/src/v4l2/v4l2_camera.cpp @@ -148,6 +148,7 @@ void V4L2Camera::freeBuffers() Stream *stream = *camera_->streams().begin(); bufferAllocator_->free(stream); + pendingRequests_.clear(); } FileDescriptor V4L2Camera::getBufferFd(unsigned int index) @@ -187,7 +188,8 @@ int V4L2Camera::streamOn() int V4L2Camera::streamOff() { - /* \todo Restore buffers to reqbufs state? */ + pendingRequests_.clear(); + if (!isRunning_) return 0; From patchwork Fri Jun 19 05:41:20 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 4094 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 3F8D4609B3 for ; Fri, 19 Jun 2020 07:42:06 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="DEM+aRg2"; dkim-atps=neutral Received: from jade.flets-east.jp (unknown [IPv6:2400:4051:61:600:e972:d773:e99a:4f79]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 1FE59556; Fri, 19 Jun 2020 07:42:03 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1592545325; bh=b+SYRZB8mkMQgjcjO0CZfoF0cBbxQ7PSL4voYt6+5dw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=DEM+aRg2kfAPLJbJqB838avZsQt2ZxUoo6/pGNp4EZcflcCSdSl64NbtN2XR/BC/j Ypgzs8cQVweYd4g3l4cMqle7o8GPXAoLxNtqyUGVcrDX3xMo6I59ZqlOBOAR+nQoL5 COebupB33prCijjLjluRvmroC7YhQLyNxGs/yjag= From: Paul Elder To: libcamera-devel@lists.libcamera.org Date: Fri, 19 Jun 2020 14:41:20 +0900 Message-Id: <20200619054123.19052-15-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20200619054123.19052-1-paul.elder@ideasonboard.com> References: <20200619054123.19052-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 14/17] 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: Fri, 19 Jun 2020 05:42:06 -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 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 2723450..8396f58 100644 --- a/src/v4l2/v4l2_camera_proxy.cpp +++ b/src/v4l2/v4l2_camera_proxy.cpp @@ -540,6 +540,9 @@ int V4L2CameraProxy::vidioc_querybuf(V4L2CameraFile *cf, struct v4l2_buffer *arg { LOG(V4L2Compat, Debug) << "Servicing vidioc_querybuf fd = " << cf->efd(); + if (arg->index >= bufferCount_) + return -EINVAL; + int ret = lock(cf); if (ret < 0) return ret; @@ -560,6 +563,9 @@ int V4L2CameraProxy::vidioc_qbuf(V4L2CameraFile *cf, struct v4l2_buffer *arg) LOG(V4L2Compat, Debug) << "Servicing vidioc_qbuf, index = " << arg->index << " fd = " << cf->efd(); + if (arg->index >= bufferCount_) + return -EINVAL; + int ret = lock(cf); if (ret < 0) return ret; @@ -586,6 +592,9 @@ int V4L2CameraProxy::vidioc_dqbuf(V4L2CameraFile *cf, struct v4l2_buffer *arg) if (!vcam_->isRunning()) return -EINVAL; + if (arg->index >= bufferCount_) + return -EINVAL; + int ret = lock(cf); if (ret < 0) return ret; From patchwork Fri Jun 19 05:41:21 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 4095 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 27EBF603BF for ; Fri, 19 Jun 2020 07:42:08 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="EMwF9Ee9"; dkim-atps=neutral Received: from jade.flets-east.jp (unknown [IPv6:2400:4051:61:600:e972:d773:e99a:4f79]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id A8466560; Fri, 19 Jun 2020 07:42:06 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1592545327; bh=4rytgg7NfyKgZ0viLomnAy+wSknPB7xeLvYF6T6EvPI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=EMwF9Ee9y569ZVZB4z044YGULKAsikyedcnUTCCHK5LLwf9F3wfFve5uW+dikmg0P vf1p/0lRsVtXwUPd7F1hqPytGdS9D0spgKkxFPY83PgapdkHwQOMjEv+Yyh/f9CVdH V4mXgfPZMCs3Ni0yCZnbvxk4SeTB6Dcxu+Ym7Hxw= From: Paul Elder To: libcamera-devel@lists.libcamera.org Date: Fri, 19 Jun 2020 14:41:21 +0900 Message-Id: <20200619054123.19052-16-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20200619054123.19052-1-paul.elder@ideasonboard.com> References: <20200619054123.19052-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 15/17] 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: Fri, 19 Jun 2020 05:42:08 -0000 Make VIDIOC_STREAMON return -EINVAL if no buffers have been allocated with reqbufs. Signed-off-by: Paul Elder Reviewed-by: Laurent Pinchart --- 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 8396f58..a7f987a 100644 --- a/src/v4l2/v4l2_camera_proxy.cpp +++ b/src/v4l2/v4l2_camera_proxy.cpp @@ -637,6 +637,9 @@ int V4L2CameraProxy::vidioc_streamon(V4L2CameraFile *cf, int *arg) { LOG(V4L2Compat, Debug) << "Servicing vidioc_streamon fd = " << cf->efd(); + if (bufferCount_ == 0) + return -EINVAL; + if (vcam_->isRunning()) return 0; From patchwork Fri Jun 19 05:41:22 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 4096 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 23CB1609A7 for ; Fri, 19 Jun 2020 07:42:10 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="K2fxGWdo"; dkim-atps=neutral Received: from jade.flets-east.jp (unknown [IPv6:2400:4051:61:600:e972:d773:e99a:4f79]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 9B543556; Fri, 19 Jun 2020 07:42:08 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1592545329; bh=LGblM1q/cDUOsGiN3Djel4GcaxzFDP6hIhNGvI3NTEc=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=K2fxGWdoJyfLe2JzuThUu0YiLVuDsMUaKVAi59Wk7FpQ5/mWIy6QYGpW4h+MlxE7k Wg/M42uOgj5ydLGpigsJZg/oQ2rcqBt497iUygKNOIaiyHyZ26gdL7A52qL3QC2rmK N8stgV/EUjpbDiCiQGWbi+9lJ5P1ZTP/mMNd9q0I= From: Paul Elder To: libcamera-devel@lists.libcamera.org Date: Fri, 19 Jun 2020 14:41:22 +0900 Message-Id: <20200619054123.19052-17-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20200619054123.19052-1-paul.elder@ideasonboard.com> References: <20200619054123.19052-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 16/17] 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: Fri, 19 Jun 2020 05:42:10 -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 --- 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 a7f987a..2eb2fcc 100644 --- a/src/v4l2/v4l2_camera_proxy.cpp +++ b/src/v4l2/v4l2_camera_proxy.cpp @@ -467,6 +467,9 @@ int V4L2CameraProxy::vidioc_reqbufs(V4L2CameraFile *cf, struct v4l2_requestbuffe memset(arg->reserved, 0, sizeof(arg->reserved)); if (arg->count == 0) { + if (!mmaps_.empty()) + return -EBUSY; + if (vcam_->isRunning()) { for (struct v4l2_buffer &buf : buffers_) buf.flags &= ~(V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_DONE); From patchwork Fri Jun 19 05:41:23 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 4097 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 56B57609DD for ; Fri, 19 Jun 2020 07:42:12 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="p+VW1rl2"; dkim-atps=neutral Received: from jade.flets-east.jp (unknown [IPv6:2400:4051:61:600:e972:d773:e99a:4f79]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 8DA68556; Fri, 19 Jun 2020 07:42:10 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1592545331; bh=YxEW6VVufPyBPGSwpSB8itMRgrhhLx4SYQq5aw0s6XE=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=p+VW1rl23g5zu8J9jwp7+1nuYMYtJIi4tK33a5uGzVMs+mNlvIWUXUn+AxJl2B68o kqLlsexAanYpUSZNDZxpMZXZCz0YyED4GgloHROX49uLQvbb72F7316lagTNUrrIa+ bOFluVTlPWfTTPG9FAF7zN73r+Lsym/O93WMU2XA= From: Paul Elder To: libcamera-devel@lists.libcamera.org Date: Fri, 19 Jun 2020 14:41:23 +0900 Message-Id: <20200619054123.19052-18-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20200619054123.19052-1-paul.elder@ideasonboard.com> References: <20200619054123.19052-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 17/17] 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: Fri, 19 Jun 2020 05:42:12 -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 set the done flag on dequeueing - set the mapped flag on enqueueing - set the flags in V4L2CameraProxy's internal buffers, and not just in the buffers returned from qbuf Signed-off-by: Paul Elder --- New in v2 - split from "Fix v4l2-compliance streaming tests" --- src/v4l2/v4l2_camera_proxy.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/v4l2/v4l2_camera_proxy.cpp b/src/v4l2/v4l2_camera_proxy.cpp index 2eb2fcc..3e5fb7c 100644 --- a/src/v4l2/v4l2_camera_proxy.cpp +++ b/src/v4l2/v4l2_camera_proxy.cpp @@ -221,7 +221,6 @@ void V4L2CameraProxy::updateBuffers() buf.timestamp.tv_usec = fmd.timestamp % 1000000; buf.sequence = fmd.sequence; - buf.flags |= V4L2_BUF_FLAG_DONE; break; case FrameMetadata::FrameError: buf.flags |= V4L2_BUF_FLAG_ERROR; @@ -569,6 +568,9 @@ int V4L2CameraProxy::vidioc_qbuf(V4L2CameraFile *cf, struct v4l2_buffer *arg) if (arg->index >= bufferCount_) return -EINVAL; + if (buffers_[arg->index].flags & V4L2_BUF_FLAG_QUEUED) + return -EINVAL; + int ret = lock(cf); if (ret < 0) return ret; @@ -582,9 +584,12 @@ int V4L2CameraProxy::vidioc_qbuf(V4L2CameraFile *cf, struct v4l2_buffer *arg) if (ret < 0) return ret; - arg->flags |= V4L2_BUF_FLAG_QUEUED; + arg->flags |= V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_MAPPED; arg->flags &= ~V4L2_BUF_FLAG_DONE; + buffers_[arg->index].flags |= V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_MAPPED; + buffers_[arg->index].flags &= ~V4L2_BUF_FLAG_DONE; + return ret; }