{"id":4176,"url":"https://patchwork.libcamera.org/api/1.1/patches/4176/?format=json","web_url":"https://patchwork.libcamera.org/patch/4176/","project":{"id":1,"url":"https://patchwork.libcamera.org/api/1.1/projects/1/?format=json","name":"libcamera","link_name":"libcamera","list_id":"libcamera_core","list_email":"libcamera-devel@lists.libcamera.org","web_url":"","scm_url":"","webscm_url":""},"msgid":"<20200623190836.53446-3-paul.elder@ideasonboard.com>","date":"2020-06-23T19:08:16","name":"[libcamera-devel,v3,02/22] v4l2: V4L2CameraProxy: Take V4L2CameraFile as argument for intercepted calls","commit_ref":null,"pull_url":null,"state":"superseded","archived":false,"hash":"f9ad9ba163f0c5fc17728c66f2999a822716c6ec","submitter":{"id":17,"url":"https://patchwork.libcamera.org/api/1.1/people/17/?format=json","name":"Paul Elder","email":"paul.elder@ideasonboard.com"},"delegate":null,"mbox":"https://patchwork.libcamera.org/patch/4176/mbox/","series":[{"id":1034,"url":"https://patchwork.libcamera.org/api/1.1/series/1034/?format=json","web_url":"https://patchwork.libcamera.org/project/libcamera/list/?series=1034","date":"2020-06-23T19:08:14","name":"Support v4l2-compliance","version":3,"mbox":"https://patchwork.libcamera.org/series/1034/mbox/"}],"comments":"https://patchwork.libcamera.org/api/patches/4176/comments/","check":"pending","checks":"https://patchwork.libcamera.org/api/patches/4176/checks/","tags":{},"headers":{"Return-Path":"<paul.elder@ideasonboard.com>","Received":["from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 7C94F609C6\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 23 Jun 2020 21:09:07 +0200 (CEST)","from jade.rasen.tech (unknown\n\t[IPv6:2400:4051:61:600:8147:f2a2:a8c6:9087])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id BE5CF329;\n\tTue, 23 Jun 2020 21:09:05 +0200 (CEST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key; \n\tunprotected) header.d=ideasonboard.com\n\theader.i=@ideasonboard.com\n\theader.b=\"ONVz81Un\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1592939347;\n\tbh=/QJsJSD1wnk2C7tJzBlBn/MeDkC0CFgL6rDguYYXavU=;\n\th=From:To:Cc:Subject:Date:In-Reply-To:References:From;\n\tb=ONVz81Unyme3wTI/VO8pk49ptz1GDxG9syyxDJga88LuQU6QnDKAVlXfJ5v90ZdJo\n\t4du0RkAppxvqYx2chMhVmnf4P+pnZKTVBFd/hQXKC0PWrEmqPQNloO9W7CBbJdA39S\n\tR/98dTTRUsOQtu9qC/k7WNKtrcs4Jd6ELpQAdqnc=","From":"Paul Elder <paul.elder@ideasonboard.com>","To":"libcamera-devel@lists.libcamera.org","Date":"Wed, 24 Jun 2020 04:08:16 +0900","Message-Id":"<20200623190836.53446-3-paul.elder@ideasonboard.com>","X-Mailer":"git-send-email 2.27.0","In-Reply-To":"<20200623190836.53446-1-paul.elder@ideasonboard.com>","References":"<20200623190836.53446-1-paul.elder@ideasonboard.com>","MIME-Version":"1.0","Content-Transfer-Encoding":"8bit","Subject":"[libcamera-devel] [PATCH v3 02/22] v4l2: V4L2CameraProxy: Take\n\tV4L2CameraFile as argument for intercepted calls","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","X-List-Received-Date":"Tue, 23 Jun 2020 19:09:08 -0000"},"content":"Prepare for using the V4L2CameraFile as a container for file-specific\ninformation in the V4L2 compatibility layer by making it a required\nargument for all V4L2CameraProxy calls that are directed from\nV4L2CompatManager, which are intercepted via LD_PRELOAD. Change\nV4L2CameraFile accordingly.\n\nAlso change V4L2CompatManager accordingly. Instead of keeping a map of\nfile descriptors to V4L2CameraProxy instances, we keep a map of\nV4L2CameraFile instances to V4L2CameraProxy instances. When the\nproxy methods are called, feed the file as a parameter.\n\nThe dup function is also modified, in that it is removed from\nV4L2CameraProxy, and is handled completely in V4L2CompatManager, as a\nmap from file descriptors to V4L2CameraFile instances.\n\nSigned-off-by: Paul Elder <paul.elder@ideasonboard.com>\n\n---\nNew in v3\n- split from \"v4l2: v4l2_compat: Support multiple open\"\n---\n src/v4l2/v4l2_camera_file.cpp    |  4 +-\n src/v4l2/v4l2_camera_proxy.cpp   | 89 +++++++++++++++-----------------\n src/v4l2/v4l2_camera_proxy.h     | 31 ++++++-----\n src/v4l2/v4l2_compat_manager.cpp | 69 +++++++++++--------------\n src/v4l2/v4l2_compat_manager.h   |  4 +-\n 5 files changed, 90 insertions(+), 107 deletions(-)","diff":"diff --git a/src/v4l2/v4l2_camera_file.cpp b/src/v4l2/v4l2_camera_file.cpp\nindex d3232ab..a07679b 100644\n--- a/src/v4l2/v4l2_camera_file.cpp\n+++ b/src/v4l2/v4l2_camera_file.cpp\n@@ -17,10 +17,10 @@ V4L2CameraFile::V4L2CameraFile(int efd, bool nonBlocking, V4L2CameraProxy *proxy\n \t: proxy_(proxy), nonBlocking_(nonBlocking), efd_(efd),\n \t  priority_(V4L2_PRIORITY_DEFAULT)\n {\n-\tproxy_->open(nonBlocking);\n+\tproxy_->open(this);\n }\n \n V4L2CameraFile::~V4L2CameraFile()\n {\n-\tproxy_->close();\n+\tproxy_->close(this);\n }\ndiff --git a/src/v4l2/v4l2_camera_proxy.cpp b/src/v4l2/v4l2_camera_proxy.cpp\nindex bf47aa7..c1ee1be 100644\n--- a/src/v4l2/v4l2_camera_proxy.cpp\n+++ b/src/v4l2/v4l2_camera_proxy.cpp\n@@ -23,6 +23,7 @@\n #include \"libcamera/internal/utils.h\"\n \n #include \"v4l2_camera.h\"\n+#include \"v4l2_camera_file.h\"\n #include \"v4l2_compat_manager.h\"\n \n #define KERNEL_VERSION(a, b, c) (((a) << 16) + ((b) << 8) + (c))\n@@ -39,9 +40,9 @@ V4L2CameraProxy::V4L2CameraProxy(unsigned int index,\n \tquerycap(camera);\n }\n \n-int V4L2CameraProxy::open(bool nonBlocking)\n+int V4L2CameraProxy::open(V4L2CameraFile *file)\n {\n-\tLOG(V4L2Compat, Debug) << \"Servicing open\";\n+\tLOG(V4L2Compat, Debug) << \"Servicing open fd = \" << file->efd();\n \n \tint ret = vcam_->open();\n \tif (ret < 0) {\n@@ -49,8 +50,6 @@ int V4L2CameraProxy::open(bool nonBlocking)\n \t\treturn -1;\n \t}\n \n-\tnonBlocking_ = nonBlocking;\n-\n \tvcam_->getStreamConfig(&streamConfig_);\n \tsetFmtFromConfig(streamConfig_);\n \tsizeimage_ = calculateSizeImage(streamConfig_);\n@@ -60,14 +59,10 @@ int V4L2CameraProxy::open(bool nonBlocking)\n \treturn 0;\n }\n \n-void V4L2CameraProxy::dup()\n+void V4L2CameraProxy::close(V4L2CameraFile *file)\n {\n-\trefcount_++;\n-}\n+\tLOG(V4L2Compat, Debug) << \"Servicing close fd = \" << file->efd();\n \n-void V4L2CameraProxy::close()\n-{\n-\tLOG(V4L2Compat, Debug) << \"Servicing close\";\n \n \tif (--refcount_ > 0)\n \t\treturn;\n@@ -221,9 +216,9 @@ int V4L2CameraProxy::vidioc_querycap(struct v4l2_capability *arg)\n \treturn 0;\n }\n \n-int V4L2CameraProxy::vidioc_enum_fmt(struct v4l2_fmtdesc *arg)\n+int V4L2CameraProxy::vidioc_enum_fmt(V4L2CameraFile *file, struct v4l2_fmtdesc *arg)\n {\n-\tLOG(V4L2Compat, Debug) << \"Servicing vidioc_enum_fmt\";\n+\tLOG(V4L2Compat, Debug) << \"Servicing vidioc_enum_fmt fd = \" << file->efd();\n \n \tif (!validateBufferType(arg->type) ||\n \t    arg->index >= streamConfig_.formats().pixelformats().size())\n@@ -237,9 +232,9 @@ int V4L2CameraProxy::vidioc_enum_fmt(struct v4l2_fmtdesc *arg)\n \treturn 0;\n }\n \n-int V4L2CameraProxy::vidioc_g_fmt(struct v4l2_format *arg)\n+int V4L2CameraProxy::vidioc_g_fmt(V4L2CameraFile *file, struct v4l2_format *arg)\n {\n-\tLOG(V4L2Compat, Debug) << \"Servicing vidioc_g_fmt\";\n+\tLOG(V4L2Compat, Debug) << \"Servicing vidioc_g_fmt fd = \" << file->efd();\n \n \tif (!validateBufferType(arg->type))\n \t\treturn -EINVAL;\n@@ -275,9 +270,9 @@ void V4L2CameraProxy::tryFormat(struct v4l2_format *arg)\n \targ->fmt.pix.colorspace   = V4L2_COLORSPACE_SRGB;\n }\n \n-int V4L2CameraProxy::vidioc_s_fmt(struct v4l2_format *arg)\n+int V4L2CameraProxy::vidioc_s_fmt(V4L2CameraFile *file, struct v4l2_format *arg)\n {\n-\tLOG(V4L2Compat, Debug) << \"Servicing vidioc_s_fmt\";\n+\tLOG(V4L2Compat, Debug) << \"Servicing vidioc_s_fmt fd = \" << file->efd();\n \n \tif (!validateBufferType(arg->type))\n \t\treturn -EINVAL;\n@@ -302,9 +297,9 @@ int V4L2CameraProxy::vidioc_s_fmt(struct v4l2_format *arg)\n \treturn 0;\n }\n \n-int V4L2CameraProxy::vidioc_try_fmt(struct v4l2_format *arg)\n+int V4L2CameraProxy::vidioc_try_fmt(V4L2CameraFile *file, struct v4l2_format *arg)\n {\n-\tLOG(V4L2Compat, Debug) << \"Servicing vidioc_try_fmt\";\n+\tLOG(V4L2Compat, Debug) << \"Servicing vidioc_try_fmt fd = \" << file->efd();\n \n \tif (!validateBufferType(arg->type))\n \t\treturn -EINVAL;\n@@ -329,11 +324,9 @@ int V4L2CameraProxy::freeBuffers()\n \treturn 0;\n }\n \n-int V4L2CameraProxy::vidioc_reqbufs(struct v4l2_requestbuffers *arg)\n+int V4L2CameraProxy::vidioc_reqbufs(V4L2CameraFile *file, struct v4l2_requestbuffers *arg)\n {\n-\tint ret;\n-\n-\tLOG(V4L2Compat, Debug) << \"Servicing vidioc_reqbufs\";\n+\tLOG(V4L2Compat, Debug) << \"Servicing vidioc_reqbufs fd = \" << file->efd();\n \n \tif (!validateBufferType(arg->type) ||\n \t    !validateMemoryType(arg->memory))\n@@ -347,9 +340,9 @@ int V4L2CameraProxy::vidioc_reqbufs(struct v4l2_requestbuffers *arg)\n \t\treturn freeBuffers();\n \n \tSize size(curV4L2Format_.fmt.pix.width, curV4L2Format_.fmt.pix.height);\n-\tret = vcam_->configure(&streamConfig_, size,\n-\t\t\t       v4l2ToDrm(curV4L2Format_.fmt.pix.pixelformat),\n-\t\t\t       arg->count);\n+\tint ret = vcam_->configure(&streamConfig_, size,\n+\t\t\t\t   v4l2ToDrm(curV4L2Format_.fmt.pix.pixelformat),\n+\t\t\t\t   arg->count);\n \tif (ret < 0)\n \t\treturn -EINVAL;\n \n@@ -396,9 +389,9 @@ int V4L2CameraProxy::vidioc_reqbufs(struct v4l2_requestbuffers *arg)\n \treturn 0;\n }\n \n-int V4L2CameraProxy::vidioc_querybuf(struct v4l2_buffer *arg)\n+int V4L2CameraProxy::vidioc_querybuf(V4L2CameraFile *file, struct v4l2_buffer *arg)\n {\n-\tLOG(V4L2Compat, Debug) << \"Servicing vidioc_querybuf\";\n+\tLOG(V4L2Compat, Debug) << \"Servicing vidioc_querybuf fd = \" << file->efd();\n \n \tif (!validateBufferType(arg->type) ||\n \t    arg->index >= bufferCount_)\n@@ -411,10 +404,10 @@ int V4L2CameraProxy::vidioc_querybuf(struct v4l2_buffer *arg)\n \treturn 0;\n }\n \n-int V4L2CameraProxy::vidioc_qbuf(struct v4l2_buffer *arg)\n+int V4L2CameraProxy::vidioc_qbuf(V4L2CameraFile *file, struct v4l2_buffer *arg)\n {\n \tLOG(V4L2Compat, Debug) << \"Servicing vidioc_qbuf, index = \"\n-\t\t\t       << arg->index;\n+\t\t\t       << arg->index << \" fd = \" << file->efd();\n \n \tif (!validateBufferType(arg->type) ||\n \t    !validateMemoryType(arg->memory) ||\n@@ -431,15 +424,15 @@ int V4L2CameraProxy::vidioc_qbuf(struct v4l2_buffer *arg)\n \treturn ret;\n }\n \n-int V4L2CameraProxy::vidioc_dqbuf(struct v4l2_buffer *arg)\n+int V4L2CameraProxy::vidioc_dqbuf(V4L2CameraFile *file, struct v4l2_buffer *arg)\n {\n-\tLOG(V4L2Compat, Debug) << \"Servicing vidioc_dqbuf\";\n+\tLOG(V4L2Compat, Debug) << \"Servicing vidioc_dqbuf fd = \" << file->efd();\n \n \tif (!validateBufferType(arg->type) ||\n \t    !validateMemoryType(arg->memory))\n \t\treturn -EINVAL;\n \n-\tif (!nonBlocking_)\n+\tif (!(file->nonBlocking()))\n \t\tvcam_->bufferSema_.acquire();\n \telse if (!vcam_->bufferSema_.tryAcquire())\n \t\treturn -EAGAIN;\n@@ -455,16 +448,16 @@ int V4L2CameraProxy::vidioc_dqbuf(struct v4l2_buffer *arg)\n \tcurrentBuf_ = (currentBuf_ + 1) % bufferCount_;\n \n \tuint64_t data;\n-\tint ret = ::read(efd_, &data, sizeof(data));\n+\tint ret = ::read(file->efd(), &data, sizeof(data));\n \tif (ret != sizeof(data))\n \t\tLOG(V4L2Compat, Error) << \"Failed to clear eventfd POLLIN\";\n \n \treturn 0;\n }\n \n-int V4L2CameraProxy::vidioc_streamon(int *arg)\n+int V4L2CameraProxy::vidioc_streamon(V4L2CameraFile *file, int *arg)\n {\n-\tLOG(V4L2Compat, Debug) << \"Servicing vidioc_streamon\";\n+\tLOG(V4L2Compat, Debug) << \"Servicing vidioc_streamon fd = \" << file->efd();\n \n \tif (!validateBufferType(*arg))\n \t\treturn -EINVAL;\n@@ -474,9 +467,9 @@ int V4L2CameraProxy::vidioc_streamon(int *arg)\n \treturn vcam_->streamOn();\n }\n \n-int V4L2CameraProxy::vidioc_streamoff(int *arg)\n+int V4L2CameraProxy::vidioc_streamoff(V4L2CameraFile *file, int *arg)\n {\n-\tLOG(V4L2Compat, Debug) << \"Servicing vidioc_streamoff\";\n+\tLOG(V4L2Compat, Debug) << \"Servicing vidioc_streamoff fd = \" << file->efd();\n \n \tif (!validateBufferType(*arg))\n \t\treturn -EINVAL;\n@@ -489,7 +482,7 @@ int V4L2CameraProxy::vidioc_streamoff(int *arg)\n \treturn ret;\n }\n \n-int V4L2CameraProxy::ioctl(unsigned long request, void *arg)\n+int V4L2CameraProxy::ioctl(V4L2CameraFile *file, unsigned long request, void *arg)\n {\n \tint ret;\n \tswitch (request) {\n@@ -497,34 +490,34 @@ int V4L2CameraProxy::ioctl(unsigned long request, void *arg)\n \t\tret = vidioc_querycap(static_cast<struct v4l2_capability *>(arg));\n \t\tbreak;\n \tcase VIDIOC_ENUM_FMT:\n-\t\tret = vidioc_enum_fmt(static_cast<struct v4l2_fmtdesc *>(arg));\n+\t\tret = vidioc_enum_fmt(file, static_cast<struct v4l2_fmtdesc *>(arg));\n \t\tbreak;\n \tcase VIDIOC_G_FMT:\n-\t\tret = vidioc_g_fmt(static_cast<struct v4l2_format *>(arg));\n+\t\tret = vidioc_g_fmt(file, static_cast<struct v4l2_format *>(arg));\n \t\tbreak;\n \tcase VIDIOC_S_FMT:\n-\t\tret = vidioc_s_fmt(static_cast<struct v4l2_format *>(arg));\n+\t\tret = vidioc_s_fmt(file, static_cast<struct v4l2_format *>(arg));\n \t\tbreak;\n \tcase VIDIOC_TRY_FMT:\n-\t\tret = vidioc_try_fmt(static_cast<struct v4l2_format *>(arg));\n+\t\tret = vidioc_try_fmt(file, static_cast<struct v4l2_format *>(arg));\n \t\tbreak;\n \tcase VIDIOC_REQBUFS:\n-\t\tret = vidioc_reqbufs(static_cast<struct v4l2_requestbuffers *>(arg));\n+\t\tret = vidioc_reqbufs(file, static_cast<struct v4l2_requestbuffers *>(arg));\n \t\tbreak;\n \tcase VIDIOC_QUERYBUF:\n-\t\tret = vidioc_querybuf(static_cast<struct v4l2_buffer *>(arg));\n+\t\tret = vidioc_querybuf(file, static_cast<struct v4l2_buffer *>(arg));\n \t\tbreak;\n \tcase VIDIOC_QBUF:\n-\t\tret = vidioc_qbuf(static_cast<struct v4l2_buffer *>(arg));\n+\t\tret = vidioc_qbuf(file, static_cast<struct v4l2_buffer *>(arg));\n \t\tbreak;\n \tcase VIDIOC_DQBUF:\n-\t\tret = vidioc_dqbuf(static_cast<struct v4l2_buffer *>(arg));\n+\t\tret = vidioc_dqbuf(file, static_cast<struct v4l2_buffer *>(arg));\n \t\tbreak;\n \tcase VIDIOC_STREAMON:\n-\t\tret = vidioc_streamon(static_cast<int *>(arg));\n+\t\tret = vidioc_streamon(file, static_cast<int *>(arg));\n \t\tbreak;\n \tcase VIDIOC_STREAMOFF:\n-\t\tret = vidioc_streamoff(static_cast<int *>(arg));\n+\t\tret = vidioc_streamoff(file, static_cast<int *>(arg));\n \t\tbreak;\n \tdefault:\n \t\tret = -ENOTTY;\ndiff --git a/src/v4l2/v4l2_camera_proxy.h b/src/v4l2/v4l2_camera_proxy.h\nindex 27d3e50..b2197ef 100644\n--- a/src/v4l2/v4l2_camera_proxy.h\n+++ b/src/v4l2/v4l2_camera_proxy.h\n@@ -21,20 +21,20 @@\n \n using namespace libcamera;\n \n+class V4L2CameraFile;\n+\n class V4L2CameraProxy\n {\n public:\n \tV4L2CameraProxy(unsigned int index, std::shared_ptr<Camera> camera);\n \n-\tint open(bool nonBlocking);\n-\tvoid dup();\n-\tvoid close();\n+\tint open(V4L2CameraFile *file);\n+\tvoid close(V4L2CameraFile *file);\n \tvoid *mmap(void *addr, size_t length, int prot, int flags, off64_t offset);\n \tint munmap(void *addr, size_t length);\n \n-\tint ioctl(unsigned long request, void *arg);\n-\n \tvoid bind(int fd);\n+\tint ioctl(V4L2CameraFile *file, unsigned long request, void *arg);\n \n private:\n \tbool validateBufferType(uint32_t type);\n@@ -47,16 +47,16 @@ private:\n \tint freeBuffers();\n \n \tint vidioc_querycap(struct v4l2_capability *arg);\n-\tint vidioc_enum_fmt(struct v4l2_fmtdesc *arg);\n-\tint vidioc_g_fmt(struct v4l2_format *arg);\n-\tint vidioc_s_fmt(struct v4l2_format *arg);\n-\tint vidioc_try_fmt(struct v4l2_format *arg);\n-\tint vidioc_reqbufs(struct v4l2_requestbuffers *arg);\n-\tint vidioc_querybuf(struct v4l2_buffer *arg);\n-\tint vidioc_qbuf(struct v4l2_buffer *arg);\n-\tint vidioc_dqbuf(struct v4l2_buffer *arg);\n-\tint vidioc_streamon(int *arg);\n-\tint vidioc_streamoff(int *arg);\n+\tint vidioc_enum_fmt(V4L2CameraFile *file, struct v4l2_fmtdesc *arg);\n+\tint vidioc_g_fmt(V4L2CameraFile *file, struct v4l2_format *arg);\n+\tint vidioc_s_fmt(V4L2CameraFile *file, struct v4l2_format *arg);\n+\tint vidioc_try_fmt(V4L2CameraFile *file, struct v4l2_format *arg);\n+\tint vidioc_reqbufs(V4L2CameraFile *file, struct v4l2_requestbuffers *arg);\n+\tint vidioc_querybuf(V4L2CameraFile *file, struct v4l2_buffer *arg);\n+\tint vidioc_qbuf(V4L2CameraFile *file, struct v4l2_buffer *arg);\n+\tint vidioc_dqbuf(V4L2CameraFile *file, struct v4l2_buffer *arg);\n+\tint vidioc_streamon(V4L2CameraFile *file, int *arg);\n+\tint vidioc_streamoff(V4L2CameraFile *file, int *arg);\n \n \tstatic unsigned int bplMultiplier(uint32_t format);\n \tstatic unsigned int imageSize(uint32_t format, unsigned int width,\n@@ -67,7 +67,6 @@ private:\n \n \tunsigned int refcount_;\n \tunsigned int index_;\n-\tbool nonBlocking_;\n \n \tstruct v4l2_format curV4L2Format_;\n \tStreamConfiguration streamConfig_;\ndiff --git a/src/v4l2/v4l2_compat_manager.cpp b/src/v4l2/v4l2_compat_manager.cpp\nindex 8da3316..8118170 100644\n--- a/src/v4l2/v4l2_compat_manager.cpp\n+++ b/src/v4l2/v4l2_compat_manager.cpp\n@@ -24,6 +24,8 @@\n \n #include \"libcamera/internal/log.h\"\n \n+#include \"v4l2_camera_file.h\"\n+\n using namespace libcamera;\n \n LOG_DEFINE_CATEGORY(V4L2Compat)\n@@ -49,7 +51,7 @@ V4L2CompatManager::V4L2CompatManager()\n \n V4L2CompatManager::~V4L2CompatManager()\n {\n-\tdevices_.clear();\n+\tfiles_.clear();\n \tmmaps_.clear();\n \n \tif (cm_) {\n@@ -95,13 +97,13 @@ V4L2CompatManager *V4L2CompatManager::instance()\n \treturn &instance;\n }\n \n-V4L2CameraProxy *V4L2CompatManager::getProxy(int fd)\n+std::shared_ptr<V4L2CameraFile> V4L2CompatManager::cameraFile(int fd)\n {\n-\tauto device = devices_.find(fd);\n-\tif (device == devices_.end())\n-\t\treturn nullptr;\n+\tauto file = files_.find(fd);\n+\tif (file == files_.end())\n+\t\treturn std::shared_ptr<V4L2CameraFile>();\n \n-\treturn device->second;\n+\treturn file->second;\n }\n \n int V4L2CompatManager::getCameraIndex(int fd)\n@@ -148,25 +150,15 @@ int V4L2CompatManager::openat(int dirfd, const char *path, int oflag, mode_t mod\n \n \tfops_.close(fd);\n \n-\tunsigned int camera_index = static_cast<unsigned int>(ret);\n-\n-\tV4L2CameraProxy *proxy = proxies_[camera_index].get();\n-\tret = proxy->open(oflag & O_NONBLOCK);\n-\tif (ret < 0)\n-\t\treturn ret;\n-\n \tint efd = eventfd(0, EFD_SEMAPHORE |\n \t\t\t     ((oflag & O_CLOEXEC) ? EFD_CLOEXEC : 0) |\n \t\t\t     ((oflag & O_NONBLOCK) ? EFD_NONBLOCK : 0));\n-\tif (efd < 0) {\n-\t\tint err = errno;\n-\t\tproxy->close();\n-\t\terrno = err;\n+\tif (efd < 0)\n \t\treturn efd;\n-\t}\n \n-\tproxy->bind(efd);\n-\tdevices_.emplace(efd, proxy);\n+\tunsigned int index = static_cast<unsigned int>(ret);\n+\tV4L2CameraProxy *proxy = proxies_[index].get();\n+\tfiles_.emplace(efd, std::make_shared<V4L2CameraFile>(efd, oflag & O_NONBLOCK, proxy));\n \n \treturn efd;\n }\n@@ -177,40 +169,39 @@ int V4L2CompatManager::dup(int oldfd)\n \tif (newfd < 0)\n \t\treturn newfd;\n \n-\tauto device = devices_.find(oldfd);\n-\tif (device != devices_.end()) {\n-\t\tV4L2CameraProxy *proxy = device->second;\n-\t\tdevices_[newfd] = proxy;\n-\t\tproxy->dup();\n-\t}\n+\tauto file = files_.find(oldfd);\n+\tif (file != files_.end())\n+\t\tfiles_[newfd] = file->second;\n \n \treturn newfd;\n }\n \n int V4L2CompatManager::close(int fd)\n {\n-\tV4L2CameraProxy *proxy = getProxy(fd);\n-\tif (proxy) {\n-\t\tproxy->close();\n-\t\tdevices_.erase(fd);\n-\t\treturn 0;\n-\t}\n+\tauto file = files_.find(fd);\n+\tif (file != files_.end())\n+\t\tfiles_.erase(file);\n \n+\t/* We still need to close the eventfd. */\n \treturn fops_.close(fd);\n }\n \n void *V4L2CompatManager::mmap(void *addr, size_t length, int prot, int flags,\n \t\t\t      int fd, off64_t offset)\n {\n-\tV4L2CameraProxy *proxy = getProxy(fd);\n-\tif (!proxy)\n+\tstd::shared_ptr<V4L2CameraFile> file = cameraFile(fd);\n+\tif (!file)\n \t\treturn fops_.mmap(addr, length, prot, flags, fd, offset);\n \n-\tvoid *map = proxy->mmap(addr, length, prot, flags, offset);\n+\tvoid *map = file->proxy()->mmap(addr, length, prot, flags, offset);\n \tif (map == MAP_FAILED)\n \t\treturn map;\n \n-\tmmaps_[map] = proxy;\n+\t/*\n+\t * Map to V4L2CameraProxy directly to prevent adding more references\n+\t * to V4L2CameraFile.\n+\t */\n+\tmmaps_[map] = file->proxy();\n \treturn map;\n }\n \n@@ -233,9 +224,9 @@ int V4L2CompatManager::munmap(void *addr, size_t length)\n \n int V4L2CompatManager::ioctl(int fd, unsigned long request, void *arg)\n {\n-\tV4L2CameraProxy *proxy = getProxy(fd);\n-\tif (!proxy)\n+\tstd::shared_ptr<V4L2CameraFile> file = cameraFile(fd);\n+\tif (!file)\n \t\treturn fops_.ioctl(fd, request, arg);\n \n-\treturn proxy->ioctl(request, arg);\n+\treturn file->proxy()->ioctl(file.get(), request, arg);\n }\ndiff --git a/src/v4l2/v4l2_compat_manager.h b/src/v4l2/v4l2_compat_manager.h\nindex 3d4e512..bc548ab 100644\n--- a/src/v4l2/v4l2_compat_manager.h\n+++ b/src/v4l2/v4l2_compat_manager.h\n@@ -44,7 +44,6 @@ public:\n \n \tstatic V4L2CompatManager *instance();\n \n-\tV4L2CameraProxy *getProxy(int fd);\n \tconst FileOperations &fops() const { return fops_; }\n \n \tint openat(int dirfd, const char *path, int oflag, mode_t mode);\n@@ -62,13 +61,14 @@ private:\n \n \tint start();\n \tint getCameraIndex(int fd);\n+\tstd::shared_ptr<V4L2CameraFile> cameraFile(int fd);\n \n \tFileOperations fops_;\n \n \tCameraManager *cm_;\n \n \tstd::vector<std::unique_ptr<V4L2CameraProxy>> proxies_;\n-\tstd::map<int, V4L2CameraProxy *> devices_;\n+\tstd::map<int, std::shared_ptr<V4L2CameraFile>> files_;\n \tstd::map<void *, V4L2CameraProxy *> mmaps_;\n };\n \n","prefixes":["libcamera-devel","v3","02/22"]}