Show a patch.

GET /api/1.1/patches/1470/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 1470,
    "url": "https://patchwork.libcamera.org/api/1.1/patches/1470/?format=api",
    "web_url": "https://patchwork.libcamera.org/patch/1470/",
    "project": {
        "id": 1,
        "url": "https://patchwork.libcamera.org/api/1.1/projects/1/?format=api",
        "name": "libcamera",
        "link_name": "libcamera",
        "list_id": "libcamera_core",
        "list_email": "libcamera-devel@lists.libcamera.org",
        "web_url": "",
        "scm_url": "",
        "webscm_url": ""
    },
    "msgid": "<20190619110548.20742-3-jacopo@jmondi.org>",
    "date": "2019-06-19T11:05:46",
    "name": "[libcamera-devel,v5,2/4] libcamera: Introduce V4L2Device base class",
    "commit_ref": null,
    "pull_url": null,
    "state": "accepted",
    "archived": false,
    "hash": "21138b62b0b5f1ba2e8fa7c81eeeeabd0f92c58a",
    "submitter": {
        "id": 3,
        "url": "https://patchwork.libcamera.org/api/1.1/people/3/?format=api",
        "name": "Jacopo Mondi",
        "email": "jacopo@jmondi.org"
    },
    "delegate": null,
    "mbox": "https://patchwork.libcamera.org/patch/1470/mbox/",
    "series": [
        {
            "id": 363,
            "url": "https://patchwork.libcamera.org/api/1.1/series/363/?format=api",
            "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=363",
            "date": "2019-06-19T11:05:44",
            "name": "libcamera: Introduce V4L2Device base class",
            "version": 5,
            "mbox": "https://patchwork.libcamera.org/series/363/mbox/"
        }
    ],
    "comments": "https://patchwork.libcamera.org/api/patches/1470/comments/",
    "check": "pending",
    "checks": "https://patchwork.libcamera.org/api/patches/1470/checks/",
    "tags": {},
    "headers": {
        "Return-Path": "<jacopo@jmondi.org>",
        "Received": [
            "from relay9-d.mail.gandi.net (relay9-d.mail.gandi.net\n\t[217.70.183.199])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 505AF61A1F\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 19 Jun 2019 13:04:45 +0200 (CEST)",
            "from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101])\n\t(Authenticated sender: jacopo@jmondi.org)\n\tby relay9-d.mail.gandi.net (Postfix) with ESMTPSA id 9E9EBFF809;\n\tWed, 19 Jun 2019 11:04:44 +0000 (UTC)"
        ],
        "X-Originating-IP": "2.224.242.101",
        "From": "Jacopo Mondi <jacopo@jmondi.org>",
        "To": "libcamera-devel@lists.libcamera.org",
        "Date": "Wed, 19 Jun 2019 13:05:46 +0200",
        "Message-Id": "<20190619110548.20742-3-jacopo@jmondi.org>",
        "X-Mailer": "git-send-email 2.21.0",
        "In-Reply-To": "<20190619110548.20742-1-jacopo@jmondi.org>",
        "References": "<20190619110548.20742-1-jacopo@jmondi.org>",
        "MIME-Version": "1.0",
        "Content-Transfer-Encoding": "8bit",
        "Subject": "[libcamera-devel] [PATCH v5 2/4] libcamera: Introduce V4L2Device\n\tbase class",
        "X-BeenThere": "libcamera-devel@lists.libcamera.org",
        "X-Mailman-Version": "2.1.23",
        "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": "Wed, 19 Jun 2019 11:04:45 -0000"
    },
    "content": "The V4L2 devices and subdevices share a few common operations,like\nopening and closing a device node, and perform IOCTLs on the device.\n\nWith the forthcoming introduction of support for V4L2 controls, the\nquantity of shared code will increase, as the control support\nimplementation is identical for the two derived classes.\n\nTo maximize code re-use and avoid duplications, provide a V4L2Device\nbase class which groups the common operations and members.\n\nThe newly introduced base class provides methods to open/close a device\nnode, access the file descriptor, and perform IOCTLs on the device.\n\nSigned-off-by: Jacopo Mondi <jacopo@jmondi.org>\nSigned-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\nReviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\n---\n src/libcamera/include/v4l2_device.h      |  43 +++++++\n src/libcamera/include/v4l2_subdevice.h   |   9 +-\n src/libcamera/include/v4l2_videodevice.h |  10 +-\n src/libcamera/meson.build                |   2 +\n src/libcamera/v4l2_device.cpp            | 144 +++++++++++++++++++++++\n src/libcamera/v4l2_subdevice.cpp         |  84 +++----------\n src/libcamera/v4l2_videodevice.cpp       | 103 +++++-----------\n 7 files changed, 239 insertions(+), 156 deletions(-)\n create mode 100644 src/libcamera/include/v4l2_device.h\n create mode 100644 src/libcamera/v4l2_device.cpp",
    "diff": "diff --git a/src/libcamera/include/v4l2_device.h b/src/libcamera/include/v4l2_device.h\nnew file mode 100644\nindex 000000000000..2c26f3eae2b4\n--- /dev/null\n+++ b/src/libcamera/include/v4l2_device.h\n@@ -0,0 +1,43 @@\n+/* SPDX-License-Identifier: LGPL-2.1-or-later */\n+/*\n+ * Copyright (C) 2019, Google Inc.\n+ *\n+ * v4l2_device.h - Common base for V4L2 video devices and subdevices\n+ */\n+#ifndef __LIBCAMERA_V4L2_DEVICE_H__\n+#define __LIBCAMERA_V4L2_DEVICE_H__\n+\n+#include <string>\n+\n+#include \"log.h\"\n+\n+namespace libcamera {\n+\n+class V4L2Device : protected Loggable\n+{\n+public:\n+\tvoid close();\n+\tbool isOpen() const { return fd_ != -1; }\n+\tconst std::string &deviceNode() const { return deviceNode_; }\n+\n+protected:\n+\tV4L2Device(const std::string &deviceNode, const std::string &logTag);\n+\t~V4L2Device() {}\n+\n+\tint fd() { return fd_; }\n+\n+\tint open(unsigned int flags);\n+\n+\tint ioctl(unsigned long request, void *argp);\n+\n+\tstd::string logPrefix() const { return \"'\" + logTag_ + \"'\"; }\n+\n+private:\n+\tstd::string deviceNode_;\n+\tstd::string logTag_;\n+\tint fd_;\n+};\n+\n+} /* namespace libcamera */\n+\n+#endif /* __LIBCAMERA_V4L2_DEVICE_H__ */\ndiff --git a/src/libcamera/include/v4l2_subdevice.h b/src/libcamera/include/v4l2_subdevice.h\nindex 9afd28b6db02..b1da4a87c553 100644\n--- a/src/libcamera/include/v4l2_subdevice.h\n+++ b/src/libcamera/include/v4l2_subdevice.h\n@@ -16,6 +16,7 @@\n #include \"formats.h\"\n #include \"log.h\"\n #include \"media_object.h\"\n+#include \"v4l2_device.h\"\n \n namespace libcamera {\n \n@@ -28,7 +29,7 @@ struct V4L2SubdeviceFormat {\n \tconst std::string toString() const;\n };\n \n-class V4L2Subdevice : protected Loggable\n+class V4L2Subdevice : public V4L2Device\n {\n public:\n \texplicit V4L2Subdevice(const MediaEntity *entity);\n@@ -37,8 +38,6 @@ public:\n \t~V4L2Subdevice();\n \n \tint open();\n-\tbool isOpen() const;\n-\tvoid close();\n \n \tconst MediaEntity *entity() const { return entity_; }\n \n@@ -53,9 +52,6 @@ public:\n \tstatic V4L2Subdevice *fromEntityName(const MediaDevice *media,\n \t\t\t\t\t     const std::string &entity);\n \n-protected:\n-\tstd::string logPrefix() const;\n-\n private:\n \tstd::vector<unsigned int> enumPadCodes(unsigned int pad);\n \tstd::vector<SizeRange> enumPadSizes(unsigned int pad,\n@@ -65,7 +61,6 @@ private:\n \t\t\t Rectangle *rect);\n \n \tconst MediaEntity *entity_;\n-\tint fd_;\n };\n \n } /* namespace libcamera */\ndiff --git a/src/libcamera/include/v4l2_videodevice.h b/src/libcamera/include/v4l2_videodevice.h\nindex 895658805b47..e73dec13f847 100644\n--- a/src/libcamera/include/v4l2_videodevice.h\n+++ b/src/libcamera/include/v4l2_videodevice.h\n@@ -18,6 +18,7 @@\n \n #include \"formats.h\"\n #include \"log.h\"\n+#include \"v4l2_device.h\"\n \n namespace libcamera {\n \n@@ -112,7 +113,7 @@ public:\n \tconst std::string toString() const;\n };\n \n-class V4L2VideoDevice : protected Loggable\n+class V4L2VideoDevice : public V4L2Device\n {\n public:\n \texplicit V4L2VideoDevice(const std::string &deviceNode);\n@@ -123,13 +124,11 @@ public:\n \tV4L2VideoDevice &operator=(const V4L2VideoDevice &) = delete;\n \n \tint open();\n-\tbool isOpen() const;\n \tvoid close();\n \n \tconst char *driverName() const { return caps_.driver(); }\n \tconst char *deviceName() const { return caps_.card(); }\n \tconst char *busName() const { return caps_.bus_info(); }\n-\tconst std::string &deviceNode() const { return deviceNode_; }\n \n \tint getFormat(V4L2DeviceFormat *format);\n \tint setFormat(V4L2DeviceFormat *format);\n@@ -148,9 +147,6 @@ public:\n \tstatic V4L2VideoDevice *fromEntityName(const MediaDevice *media,\n \t\t\t\t\t       const std::string &entity);\n \n-protected:\n-\tstd::string logPrefix() const;\n-\n private:\n \tint getFormatMeta(V4L2DeviceFormat *format);\n \tint setFormatMeta(V4L2DeviceFormat *format);\n@@ -171,8 +167,6 @@ private:\n \tBuffer *dequeueBuffer();\n \tvoid bufferAvailable(EventNotifier *notifier);\n \n-\tstd::string deviceNode_;\n-\tint fd_;\n \tV4L2Capability caps_;\n \n \tenum v4l2_buf_type bufferType_;\ndiff --git a/src/libcamera/meson.build b/src/libcamera/meson.build\nindex 15ab53b1abbe..f26ad5b2dc57 100644\n--- a/src/libcamera/meson.build\n+++ b/src/libcamera/meson.build\n@@ -23,6 +23,7 @@ libcamera_sources = files([\n     'stream.cpp',\n     'timer.cpp',\n     'utils.cpp',\n+    'v4l2_device.cpp',\n     'v4l2_subdevice.cpp',\n     'v4l2_videodevice.cpp',\n ])\n@@ -41,6 +42,7 @@ libcamera_headers = files([\n     'include/media_object.h',\n     'include/pipeline_handler.h',\n     'include/utils.h',\n+    'include/v4l2_device.h',\n     'include/v4l2_subdevice.h',\n     'include/v4l2_videodevice.h',\n ])\ndiff --git a/src/libcamera/v4l2_device.cpp b/src/libcamera/v4l2_device.cpp\nnew file mode 100644\nindex 000000000000..eeed0a70fb0e\n--- /dev/null\n+++ b/src/libcamera/v4l2_device.cpp\n@@ -0,0 +1,144 @@\n+/* SPDX-License-Identifier: LGPL-2.1-or-later */\n+/*\n+ * Copyright (C) 2019, Google Inc.\n+ *\n+ * v4l2_device.cpp - Common base for V4L2 video devices and subdevices\n+ */\n+\n+#include \"v4l2_device.h\"\n+\n+#include <fcntl.h>\n+#include <string.h>\n+#include <sys/ioctl.h>\n+#include <unistd.h>\n+\n+#include \"log.h\"\n+\n+/**\n+ * \\file v4l2_device.h\n+ * \\brief Common base for V4L2 devices and subdevices\n+ */\n+\n+namespace libcamera {\n+\n+LOG_DEFINE_CATEGORY(V4L2)\n+\n+/**\n+ * \\class V4L2Device\n+ * \\brief Base class for V4L2VideoDevice and V4L2Subdevice\n+ *\n+ * The V4L2Device class groups together the methods and fields common to\n+ * both the V4L2VideoDevice and V4L2Subdevice classes, and provides a base\n+ * class whith methods to open and close the device node associated with the\n+ * device and to perform IOCTL system calls on it.\n+ *\n+ * The V4L2Device class cannot be instantiated directly, as its constructor\n+ * is protected. Users should instead create instances of one the derived\n+ * classes to model either a V4L2 video device or a V4L2 subdevice.\n+ */\n+\n+/**\n+ * \\brief Close the device node\n+ *\n+ * Reset the file descriptor to -1\n+ */\n+void V4L2Device::close()\n+{\n+\tif (!isOpen())\n+\t\treturn;\n+\n+\tif (::close(fd_) < 0)\n+\t\tLOG(V4L2, Error) << \"Failed to close V4L2 device: \"\n+\t\t\t\t << strerror(errno);\n+\tfd_ = -1;\n+}\n+\n+/**\n+ * \\fn V4L2Device::isOpen()\n+ * \\brief Check if the V4L2 device node is open\n+ * \\return True if the V4L2 device node is open, false otherwise\n+ */\n+\n+/**\n+ * \\fn V4L2Device::deviceNode()\n+ * \\brief Retrieve the device node path\n+ * \\return The device node path\n+ */\n+\n+/**\n+ * \\brief Construct a V4L2Device\n+ * \\param[in] deviceNode The device node filesystem path\n+ * \\param[in] logTag The tag to prefix log messages with. Helpful to identify\n+ * the device in the log output\n+ *\n+ * The V4L2Device constructor is protected and can only be accessed by the\n+ * V4L2VideoDevice and V4L2Subdevice derived classes.\n+ *\n+ * Initialize the file descriptor to -1 and store the \\a deviceNode to be used\n+ * at open() time, and the \\a logTag to prefix log messages with.\n+ */\n+V4L2Device::V4L2Device(const std::string &deviceNode, const std::string &logTag)\n+\t: deviceNode_(deviceNode), logTag_(logTag), fd_(-1)\n+{\n+}\n+\n+/**\n+ * \\fn V4L2Device::fd()\n+ * \\brief Retrieve the V4L2 device file descriptor\n+ * \\return The V4L2 device file descriptor, -1 if the device node is not open\n+ */\n+\n+/**\n+ * \\brief Open a V4L2 device node\n+ * \\param[in] flags Access mode flags\n+ *\n+ * Open the device node path with the provided access mode \\a flags and\n+ * initialize the file descriptor, which was initially set to -1.\n+ *\n+ * \\return 0 on success or a negative error code otherwise\n+ */\n+int V4L2Device::open(unsigned int flags)\n+{\n+\tif (isOpen()) {\n+\t\tLOG(V4L2, Error) << \"Device already open\";\n+\t\treturn -EBUSY;\n+\t}\n+\n+\tint ret = ::open(deviceNode_.c_str(), flags);\n+\tif (ret < 0) {\n+\t\tret = -errno;\n+\t\tLOG(V4L2, Error) << \"Failed to open V4L2 device: \"\n+\t\t\t\t << strerror(-ret);\n+\t\treturn ret;\n+\t}\n+\n+\tfd_ = ret;\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * \\brief Perform an IOCTL system call on the device node\n+ * \\param[in] request The IOCTL request code\n+ * \\param[in] argp A pointer to the IOCTL argument\n+ * \\return 0 on success or a negative error code otherwise\n+ */\n+int V4L2Device::ioctl(unsigned long request, void *argp)\n+{\n+\t/*\n+\t * Printing out an error message is usually better performed\n+\t * in the caller, which can provide more context.\n+\t */\n+\tif (::ioctl(fd_, request, argp) < 0)\n+\t\treturn -errno;\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * \\fn V4L2Device::logPrefix()\n+ * \\brief Retrieve the tag to prefix log messages with\n+ * \\return The tag to prefix log messages with\n+ */\n+\n+} /* namespace libcamera */\ndiff --git a/src/libcamera/v4l2_subdevice.cpp b/src/libcamera/v4l2_subdevice.cpp\nindex 48f1fcb30ed4..d0e1d717b26c 100644\n--- a/src/libcamera/v4l2_subdevice.cpp\n+++ b/src/libcamera/v4l2_subdevice.cpp\n@@ -29,7 +29,7 @@\n \n namespace libcamera {\n \n-LOG_DEFINE_CATEGORY(V4L2Subdev)\n+LOG_DECLARE_CATEGORY(V4L2)\n \n /**\n  * \\struct V4L2SubdeviceFormat\n@@ -102,7 +102,7 @@ const std::string V4L2SubdeviceFormat::toString() const\n  * path\n  */\n V4L2Subdevice::V4L2Subdevice(const MediaEntity *entity)\n-\t: entity_(entity), fd_(-1)\n+\t: V4L2Device(entity->deviceNode(), entity->name()), entity_(entity)\n {\n }\n \n@@ -117,45 +117,7 @@ V4L2Subdevice::~V4L2Subdevice()\n  */\n int V4L2Subdevice::open()\n {\n-\tint ret;\n-\n-\tif (isOpen()) {\n-\t\tLOG(V4L2Subdev, Error) << \"Device already open\";\n-\t\treturn -EBUSY;\n-\t}\n-\n-\tret = ::open(entity_->deviceNode().c_str(), O_RDWR);\n-\tif (ret < 0) {\n-\t\tret = -errno;\n-\t\tLOG(V4L2Subdev, Error)\n-\t\t\t<< \"Failed to open V4L2 subdevice '\"\n-\t\t\t<< entity_->deviceNode() << \"': \" << strerror(-ret);\n-\t\treturn ret;\n-\t}\n-\tfd_ = ret;\n-\n-\treturn 0;\n-}\n-\n-/**\n- * \\brief Check if the subdevice is open\n- * \\return True if the subdevice is open, false otherwise\n- */\n-bool V4L2Subdevice::isOpen() const\n-{\n-\treturn fd_ != -1;\n-}\n-\n-/**\n- * \\brief Close the subdevice, releasing any resources acquired by open()\n- */\n-void V4L2Subdevice::close()\n-{\n-\tif (!isOpen())\n-\t\treturn;\n-\n-\t::close(fd_);\n-\tfd_ = -1;\n+\treturn V4L2Device::open(O_RDWR);\n }\n \n /**\n@@ -200,7 +162,7 @@ ImageFormats V4L2Subdevice::formats(unsigned int pad)\n \tImageFormats formats;\n \n \tif (pad >= entity_->pads().size()) {\n-\t\tLOG(V4L2Subdev, Error) << \"Invalid pad: \" << pad;\n+\t\tLOG(V4L2, Error) << \"Invalid pad: \" << pad;\n \t\treturn {};\n \t}\n \n@@ -210,7 +172,7 @@ ImageFormats V4L2Subdevice::formats(unsigned int pad)\n \t\t\treturn {};\n \n \t\tif (formats.addFormat(code, sizes)) {\n-\t\t\tLOG(V4L2Subdev, Error)\n+\t\t\tLOG(V4L2, Error)\n \t\t\t\t<< \"Could not add sizes for media bus code \"\n \t\t\t\t<< code << \" on pad \" << pad;\n \t\t\treturn {};\n@@ -232,10 +194,9 @@ int V4L2Subdevice::getFormat(unsigned int pad, V4L2SubdeviceFormat *format)\n \tsubdevFmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;\n \tsubdevFmt.pad = pad;\n \n-\tint ret = ioctl(fd_, VIDIOC_SUBDEV_G_FMT, &subdevFmt);\n+\tint ret = ioctl(VIDIOC_SUBDEV_G_FMT, &subdevFmt);\n \tif (ret) {\n-\t\tret = -errno;\n-\t\tLOG(V4L2Subdev, Error)\n+\t\tLOG(V4L2, Error)\n \t\t\t<< \"Unable to get format on pad \" << pad\n \t\t\t<< \": \" << strerror(-ret);\n \t\treturn ret;\n@@ -268,10 +229,9 @@ int V4L2Subdevice::setFormat(unsigned int pad, V4L2SubdeviceFormat *format)\n \tsubdevFmt.format.height = format->size.height;\n \tsubdevFmt.format.code = format->mbus_code;\n \n-\tint ret = ioctl(fd_, VIDIOC_SUBDEV_S_FMT, &subdevFmt);\n+\tint ret = ioctl(VIDIOC_SUBDEV_S_FMT, &subdevFmt);\n \tif (ret) {\n-\t\tret = -errno;\n-\t\tLOG(V4L2Subdev, Error)\n+\t\tLOG(V4L2, Error)\n \t\t\t<< \"Unable to set format on pad \" << pad\n \t\t\t<< \": \" << strerror(-ret);\n \t\treturn ret;\n@@ -305,11 +265,6 @@ V4L2Subdevice *V4L2Subdevice::fromEntityName(const MediaDevice *media,\n \treturn new V4L2Subdevice(mediaEntity);\n }\n \n-std::string V4L2Subdevice::logPrefix() const\n-{\n-\treturn \"'\" + entity_->name() + \"'\";\n-}\n-\n std::vector<unsigned int> V4L2Subdevice::enumPadCodes(unsigned int pad)\n {\n \tstd::vector<unsigned int> codes;\n@@ -321,18 +276,17 @@ std::vector<unsigned int> V4L2Subdevice::enumPadCodes(unsigned int pad)\n \t\tmbusEnum.index = index;\n \t\tmbusEnum.which = V4L2_SUBDEV_FORMAT_ACTIVE;\n \n-\t\tret = ioctl(fd_, VIDIOC_SUBDEV_ENUM_MBUS_CODE, &mbusEnum);\n+\t\tret = ioctl(VIDIOC_SUBDEV_ENUM_MBUS_CODE, &mbusEnum);\n \t\tif (ret)\n \t\t\tbreak;\n \n \t\tcodes.push_back(mbusEnum.code);\n \t}\n \n-\tif (ret && errno != EINVAL) {\n-\t\tret = errno;\n-\t\tLOG(V4L2Subdev, Error)\n+\tif (ret < 0 && ret != -EINVAL) {\n+\t\tLOG(V4L2, Error)\n \t\t\t<< \"Unable to enumerate formats on pad \" << pad\n-\t\t\t<< \": \" << strerror(ret);\n+\t\t\t<< \": \" << strerror(-ret);\n \t\treturn {};\n \t}\n \n@@ -352,7 +306,7 @@ std::vector<SizeRange> V4L2Subdevice::enumPadSizes(unsigned int pad,\n \t\tsizeEnum.code = code;\n \t\tsizeEnum.which = V4L2_SUBDEV_FORMAT_ACTIVE;\n \n-\t\tret = ioctl(fd_, VIDIOC_SUBDEV_ENUM_FRAME_SIZE, &sizeEnum);\n+\t\tret = ioctl(VIDIOC_SUBDEV_ENUM_FRAME_SIZE, &sizeEnum);\n \t\tif (ret)\n \t\t\tbreak;\n \n@@ -360,9 +314,8 @@ std::vector<SizeRange> V4L2Subdevice::enumPadSizes(unsigned int pad,\n \t\t\t\t   sizeEnum.max_width, sizeEnum.max_height);\n \t}\n \n-\tif (ret && (errno != EINVAL && errno != ENOTTY)) {\n-\t\tret = -errno;\n-\t\tLOG(V4L2Subdev, Error)\n+\tif (ret < 0 && ret != -EINVAL && ret != -ENOTTY) {\n+\t\tLOG(V4L2, Error)\n \t\t\t<< \"Unable to enumerate sizes on pad \" << pad\n \t\t\t<< \": \" << strerror(-ret);\n \t\treturn {};\n@@ -386,10 +339,9 @@ int V4L2Subdevice::setSelection(unsigned int pad, unsigned int target,\n \tsel.r.width = rect->w;\n \tsel.r.height = rect->h;\n \n-\tint ret = ioctl(fd_, VIDIOC_SUBDEV_S_SELECTION, &sel);\n+\tint ret = ioctl(VIDIOC_SUBDEV_S_SELECTION, &sel);\n \tif (ret < 0) {\n-\t\tret = -errno;\n-\t\tLOG(V4L2Subdev, Error)\n+\t\tLOG(V4L2, Error)\n \t\t\t<< \"Unable to set rectangle \" << target << \" on pad \"\n \t\t\t<< pad << \": \" << strerror(-ret);\n \t\treturn ret;\ndiff --git a/src/libcamera/v4l2_videodevice.cpp b/src/libcamera/v4l2_videodevice.cpp\nindex 0e70498c8bb1..403e0b2e0653 100644\n--- a/src/libcamera/v4l2_videodevice.cpp\n+++ b/src/libcamera/v4l2_videodevice.cpp\n@@ -30,7 +30,7 @@\n  */\n namespace libcamera {\n \n-LOG_DEFINE_CATEGORY(V4L2)\n+LOG_DECLARE_CATEGORY(V4L2)\n \n /**\n  * \\struct V4L2Capability\n@@ -270,7 +270,7 @@ const std::string V4L2DeviceFormat::toString() const\n  * \\param[in] deviceNode The file-system path to the video device node\n  */\n V4L2VideoDevice::V4L2VideoDevice(const std::string &deviceNode)\n-\t: deviceNode_(deviceNode), fd_(-1), bufferPool_(nullptr),\n+\t: V4L2Device(deviceNode, deviceNode), bufferPool_(nullptr),\n \t  queuedBuffersCount_(0), fdEvent_(nullptr)\n {\n \t/*\n@@ -305,23 +305,12 @@ int V4L2VideoDevice::open()\n {\n \tint ret;\n \n-\tif (isOpen()) {\n-\t\tLOG(V4L2, Error) << \"Device already open\";\n-\t\treturn -EBUSY;\n-\t}\n-\n-\tret = ::open(deviceNode_.c_str(), O_RDWR | O_NONBLOCK);\n-\tif (ret < 0) {\n-\t\tret = -errno;\n-\t\tLOG(V4L2, Error)\n-\t\t\t<< \"Failed to open V4L2 device: \" << strerror(-ret);\n+\tret = V4L2Device::open(O_RDWR | O_NONBLOCK);\n+\tif (ret < 0)\n \t\treturn ret;\n-\t}\n-\tfd_ = ret;\n \n-\tret = ioctl(fd_, VIDIOC_QUERYCAP, &caps_);\n+\tret = ioctl(VIDIOC_QUERYCAP, &caps_);\n \tif (ret < 0) {\n-\t\tret = -errno;\n \t\tLOG(V4L2, Error)\n \t\t\t<< \"Failed to query device capabilities: \"\n \t\t\t<< strerror(-ret);\n@@ -342,20 +331,20 @@ int V4L2VideoDevice::open()\n \t * (POLLIN), and write notifications for OUTPUT devices (POLLOUT).\n \t */\n \tif (caps_.isVideoCapture()) {\n-\t\tfdEvent_ = new EventNotifier(fd_, EventNotifier::Read);\n+\t\tfdEvent_ = new EventNotifier(fd(), EventNotifier::Read);\n \t\tbufferType_ = caps_.isMultiplanar()\n \t\t\t    ? V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE\n \t\t\t    : V4L2_BUF_TYPE_VIDEO_CAPTURE;\n \t} else if (caps_.isVideoOutput()) {\n-\t\tfdEvent_ = new EventNotifier(fd_, EventNotifier::Write);\n+\t\tfdEvent_ = new EventNotifier(fd(), EventNotifier::Write);\n \t\tbufferType_ = caps_.isMultiplanar()\n \t\t\t    ? V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE\n \t\t\t    : V4L2_BUF_TYPE_VIDEO_OUTPUT;\n \t} else if (caps_.isMetaCapture()) {\n-\t\tfdEvent_ = new EventNotifier(fd_, EventNotifier::Read);\n+\t\tfdEvent_ = new EventNotifier(fd(), EventNotifier::Read);\n \t\tbufferType_ = V4L2_BUF_TYPE_META_CAPTURE;\n \t} else if (caps_.isMetaOutput()) {\n-\t\tfdEvent_ = new EventNotifier(fd_, EventNotifier::Write);\n+\t\tfdEvent_ = new EventNotifier(fd(), EventNotifier::Write);\n \t\tbufferType_ = V4L2_BUF_TYPE_META_OUTPUT;\n \t} else {\n \t\tLOG(V4L2, Error) << \"Device is not a supported type\";\n@@ -368,28 +357,18 @@ int V4L2VideoDevice::open()\n \treturn 0;\n }\n \n-/**\n- * \\brief Check if device is successfully opened\n- * \\return True if the device is open, false otherwise\n- */\n-bool V4L2VideoDevice::isOpen() const\n-{\n-\treturn fd_ != -1;\n-}\n-\n /**\n  * \\brief Close the device, releasing any resources acquired by open()\n  */\n void V4L2VideoDevice::close()\n {\n-\tif (fd_ < 0)\n+\tif (!isOpen())\n \t\treturn;\n \n \treleaseBuffers();\n \tdelete fdEvent_;\n \n-\t::close(fd_);\n-\tfd_ = -1;\n+\tV4L2Device::close();\n }\n \n /**\n@@ -410,17 +389,6 @@ void V4L2VideoDevice::close()\n  * \\return The string containing the device location\n  */\n \n-/**\n- * \\fn V4L2VideoDevice::deviceNode()\n- * \\brief Retrieve the video device node path\n- * \\return The video device device node path\n- */\n-\n-std::string V4L2VideoDevice::logPrefix() const\n-{\n-\treturn deviceNode_ + (V4L2_TYPE_IS_OUTPUT(bufferType_) ? \"[out]\" : \"[cap]\");\n-}\n-\n /**\n  * \\brief Retrieve the image format set on the V4L2 device\n  * \\param[out] format The image format applied on the device\n@@ -462,9 +430,8 @@ int V4L2VideoDevice::getFormatMeta(V4L2DeviceFormat *format)\n \tint ret;\n \n \tv4l2Format.type = bufferType_;\n-\tret = ioctl(fd_, VIDIOC_G_FMT, &v4l2Format);\n+\tret = ioctl(VIDIOC_G_FMT, &v4l2Format);\n \tif (ret) {\n-\t\tret = -errno;\n \t\tLOG(V4L2, Error) << \"Unable to get format: \" << strerror(-ret);\n \t\treturn ret;\n \t}\n@@ -488,9 +455,8 @@ int V4L2VideoDevice::setFormatMeta(V4L2DeviceFormat *format)\n \tv4l2Format.type = bufferType_;\n \tpix->dataformat = format->fourcc;\n \tpix->buffersize = format->planes[0].size;\n-\tret = ioctl(fd_, VIDIOC_S_FMT, &v4l2Format);\n+\tret = ioctl(VIDIOC_S_FMT, &v4l2Format);\n \tif (ret) {\n-\t\tret = -errno;\n \t\tLOG(V4L2, Error) << \"Unable to set format: \" << strerror(-ret);\n \t\treturn ret;\n \t}\n@@ -516,9 +482,8 @@ int V4L2VideoDevice::getFormatMultiplane(V4L2DeviceFormat *format)\n \tint ret;\n \n \tv4l2Format.type = bufferType_;\n-\tret = ioctl(fd_, VIDIOC_G_FMT, &v4l2Format);\n+\tret = ioctl(VIDIOC_G_FMT, &v4l2Format);\n \tif (ret) {\n-\t\tret = -errno;\n \t\tLOG(V4L2, Error) << \"Unable to get format: \" << strerror(-ret);\n \t\treturn ret;\n \t}\n@@ -554,9 +519,8 @@ int V4L2VideoDevice::setFormatMultiplane(V4L2DeviceFormat *format)\n \t\tpix->plane_fmt[i].sizeimage = format->planes[i].size;\n \t}\n \n-\tret = ioctl(fd_, VIDIOC_S_FMT, &v4l2Format);\n+\tret = ioctl(VIDIOC_S_FMT, &v4l2Format);\n \tif (ret) {\n-\t\tret = -errno;\n \t\tLOG(V4L2, Error) << \"Unable to set format: \" << strerror(-ret);\n \t\treturn ret;\n \t}\n@@ -584,9 +548,8 @@ int V4L2VideoDevice::getFormatSingleplane(V4L2DeviceFormat *format)\n \tint ret;\n \n \tv4l2Format.type = bufferType_;\n-\tret = ioctl(fd_, VIDIOC_G_FMT, &v4l2Format);\n+\tret = ioctl(VIDIOC_G_FMT, &v4l2Format);\n \tif (ret) {\n-\t\tret = -errno;\n \t\tLOG(V4L2, Error) << \"Unable to get format: \" << strerror(-ret);\n \t\treturn ret;\n \t}\n@@ -613,9 +576,8 @@ int V4L2VideoDevice::setFormatSingleplane(V4L2DeviceFormat *format)\n \tpix->pixelformat = format->fourcc;\n \tpix->bytesperline = format->planes[0].bpl;\n \tpix->field = V4L2_FIELD_NONE;\n-\tret = ioctl(fd_, VIDIOC_S_FMT, &v4l2Format);\n+\tret = ioctl(VIDIOC_S_FMT, &v4l2Format);\n \tif (ret) {\n-\t\tret = -errno;\n \t\tLOG(V4L2, Error) << \"Unable to set format: \" << strerror(-ret);\n \t\treturn ret;\n \t}\n@@ -670,9 +632,8 @@ int V4L2VideoDevice::requestBuffers(unsigned int count)\n \trb.type = bufferType_;\n \trb.memory = memoryType_;\n \n-\tret = ioctl(fd_, VIDIOC_REQBUFS, &rb);\n+\tret = ioctl(VIDIOC_REQBUFS, &rb);\n \tif (ret < 0) {\n-\t\tret = -errno;\n \t\tLOG(V4L2, Error)\n \t\t\t<< \"Unable to request \" << count << \" buffers: \"\n \t\t\t<< strerror(-ret);\n@@ -722,9 +683,8 @@ int V4L2VideoDevice::exportBuffers(BufferPool *pool)\n \t\tbuf.length = VIDEO_MAX_PLANES;\n \t\tbuf.m.planes = planes;\n \n-\t\tret = ioctl(fd_, VIDIOC_QUERYBUF, &buf);\n+\t\tret = ioctl(VIDIOC_QUERYBUF, &buf);\n \t\tif (ret < 0) {\n-\t\t\tret = -errno;\n \t\t\tLOG(V4L2, Error)\n \t\t\t\t<< \"Unable to query buffer \" << i << \": \"\n \t\t\t\t<< strerror(-ret);\n@@ -775,9 +735,8 @@ int V4L2VideoDevice::createPlane(Buffer *buffer, unsigned int planeIndex,\n \texpbuf.plane = planeIndex;\n \texpbuf.flags = O_RDWR;\n \n-\tret = ioctl(fd_, VIDIOC_EXPBUF, &expbuf);\n+\tret = ioctl(VIDIOC_EXPBUF, &expbuf);\n \tif (ret < 0) {\n-\t\tret = -errno;\n \t\tLOG(V4L2, Error)\n \t\t\t<< \"Failed to export buffer: \" << strerror(-ret);\n \t\treturn ret;\n@@ -801,15 +760,14 @@ std::vector<unsigned int> V4L2VideoDevice::enumPixelformats()\n \t\tpixelformatEnum.index = index;\n \t\tpixelformatEnum.type = bufferType_;\n \n-\t\tret = ioctl(fd_, VIDIOC_ENUM_FMT, &pixelformatEnum);\n+\t\tret = ioctl(VIDIOC_ENUM_FMT, &pixelformatEnum);\n \t\tif (ret)\n \t\t\tbreak;\n \n \t\tformats.push_back(pixelformatEnum.pixelformat);\n \t}\n \n-\tif (ret && errno != EINVAL) {\n-\t\tret = -errno;\n+\tif (ret && ret != -EINVAL) {\n \t\tLOG(V4L2, Error)\n \t\t\t<< \"Unable to enumerate pixel formats: \"\n \t\t\t<< strerror(-ret);\n@@ -829,7 +787,7 @@ std::vector<SizeRange> V4L2VideoDevice::enumSizes(unsigned int pixelFormat)\n \t\tframeSize.index = index;\n \t\tframeSize.pixel_format = pixelFormat;\n \n-\t\tret = ioctl(fd_, VIDIOC_ENUM_FRAMESIZES, &frameSize);\n+\t\tret = ioctl(VIDIOC_ENUM_FRAMESIZES, &frameSize);\n \t\tif (ret)\n \t\t\tbreak;\n \n@@ -867,8 +825,7 @@ std::vector<SizeRange> V4L2VideoDevice::enumSizes(unsigned int pixelFormat)\n \t\t}\n \t}\n \n-\tif (ret && errno != EINVAL) {\n-\t\tret = -errno;\n+\tif (ret && ret != -EINVAL) {\n \t\tLOG(V4L2, Error)\n \t\t\t<< \"Unable to enumerate frame sizes: \"\n \t\t\t<< strerror(-ret);\n@@ -969,9 +926,8 @@ int V4L2VideoDevice::queueBuffer(Buffer *buffer)\n \n \tLOG(V4L2, Debug) << \"Queueing buffer \" << buf.index;\n \n-\tret = ioctl(fd_, VIDIOC_QBUF, &buf);\n+\tret = ioctl(VIDIOC_QBUF, &buf);\n \tif (ret < 0) {\n-\t\tret = -errno;\n \t\tLOG(V4L2, Error)\n \t\t\t<< \"Failed to queue buffer \" << buf.index << \": \"\n \t\t\t<< strerror(-ret);\n@@ -1006,9 +962,8 @@ Buffer *V4L2VideoDevice::dequeueBuffer()\n \t\tbuf.m.planes = planes;\n \t}\n \n-\tret = ioctl(fd_, VIDIOC_DQBUF, &buf);\n+\tret = ioctl(VIDIOC_DQBUF, &buf);\n \tif (ret < 0) {\n-\t\tret = -errno;\n \t\tLOG(V4L2, Error)\n \t\t\t<< \"Failed to dequeue buffer: \" << strerror(-ret);\n \t\treturn nullptr;\n@@ -1066,9 +1021,8 @@ int V4L2VideoDevice::streamOn()\n {\n \tint ret;\n \n-\tret = ioctl(fd_, VIDIOC_STREAMON, &bufferType_);\n+\tret = ioctl(VIDIOC_STREAMON, &bufferType_);\n \tif (ret < 0) {\n-\t\tret = -errno;\n \t\tLOG(V4L2, Error)\n \t\t\t<< \"Failed to start streaming: \" << strerror(-ret);\n \t\treturn ret;\n@@ -1089,9 +1043,8 @@ int V4L2VideoDevice::streamOff()\n {\n \tint ret;\n \n-\tret = ioctl(fd_, VIDIOC_STREAMOFF, &bufferType_);\n+\tret = ioctl(VIDIOC_STREAMOFF, &bufferType_);\n \tif (ret < 0) {\n-\t\tret = -errno;\n \t\tLOG(V4L2, Error)\n \t\t\t<< \"Failed to stop streaming: \" << strerror(-ret);\n \t\treturn ret;\n",
    "prefixes": [
        "libcamera-devel",
        "v5",
        "2/4"
    ]
}