From patchwork Mon Aug 1 00:05:38 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 16885 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 611B3BE173 for ; Mon, 1 Aug 2022 00:06:02 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 137146332A; Mon, 1 Aug 2022 02:06:02 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1659312362; bh=ccCBU6TGpcKxIKorUiUwWP8Ua8AT2WuDW1tPjcXYYfg=; h=To:Date:In-Reply-To:References:Subject:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To: From; b=xK4K1UnF2IM+FY1eOcRYrH//PpZMJpk81zQsASugW6n4r+FNXwbK5TAmqCUlEhJHj hdk6vR6S2FT+CZwQ9E6XV7bFAcdUn9dtbVxlJvGPoDfFF11ek16Zvuf0vWgka9npr/ jcwDoJVY4f5axy1fiL/bTQJjM+67tzdZcw90i/UZZY/xV4aLosjO0FCVLfMXka4Xer dvollPRm6QsO+nT8b65Br36BW0n0YzfKsk6Oi4wQ064uD7N62Vp0AhnQtdwy9tUH4M kS9/dqiedzK4n0djY7OU+sw45vtIHOCOJNVlT8CtDz8icaqeUYN+dOpsLIEG296ZzT wahRmaE5xj4oA== Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 77D9363312 for ; Mon, 1 Aug 2022 02:06:00 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="ptBlot2v"; dkim-atps=neutral Received: from pendragon.ideasonboard.com (62-78-145-57.bb.dnainternet.fi [62.78.145.57]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 14110A42; Mon, 1 Aug 2022 02:06:00 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1659312360; bh=ccCBU6TGpcKxIKorUiUwWP8Ua8AT2WuDW1tPjcXYYfg=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=ptBlot2vzPvK8IVzQ+kjDchacoZmJDWc5cAbyruR+r+lx1M3D8gZlLQ7PcaO2vzZ+ HfeNb1l+DJuEBwtXGA9oYbwXrc0CwwAkof1IqbMrFv3ycwV7eH6Ch7gmENuzYvmvIm brW1NABSL09Nd4yB5ds4I6wov8hc8r5Hvb9vuikw= To: libcamera-devel@lists.libcamera.org Date: Mon, 1 Aug 2022 03:05:38 +0300 Message-Id: <20220801000543.3501-9-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220801000543.3501-1-laurent.pinchart@ideasonboard.com> References: <20220801000543.3501-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 08/13] libcamera: v4l2_subdevice: Add support for the V4L2 subdev routing API 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-Patchwork-Original-From: Laurent Pinchart via libcamera-devel From: Laurent Pinchart Reply-To: Laurent Pinchart Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" From: Jacopo Mondi Extend the V4L2Subdevice class to support getting and setting routing tables. Signed-off-by: Jacopo Mondi Signed-off-by: Laurent Pinchart Reviewed-by: Tomi Valkeinen --- Changes on top of Jacopo's initial work: - Turn Routing struct into a class, an inherit from std::vector - Drop Routing::numRoutes --- include/libcamera/internal/v4l2_subdevice.h | 9 ++ src/libcamera/v4l2_subdevice.cpp | 105 ++++++++++++++++++++ 2 files changed, 114 insertions(+) diff --git a/include/libcamera/internal/v4l2_subdevice.h b/include/libcamera/internal/v4l2_subdevice.h index a1d3144c6a7f..00be17bb1465 100644 --- a/include/libcamera/internal/v4l2_subdevice.h +++ b/include/libcamera/internal/v4l2_subdevice.h @@ -61,6 +61,12 @@ public: ActiveFormat = V4L2_SUBDEV_FORMAT_ACTIVE, }; + class Routing : public std::vector + { + public: + std::string toString() const; + }; + explicit V4L2Subdevice(const MediaEntity *entity); ~V4L2Subdevice(); @@ -80,6 +86,9 @@ public: int setFormat(unsigned int pad, V4L2SubdeviceFormat *format, Whence whence = ActiveFormat); + int getRouting(Routing *routing, Whence whence = ActiveFormat); + int setRouting(Routing *routing, Whence whence = ActiveFormat); + const std::string &model(); const V4L2SubdeviceCapability &caps() const { return caps_; } diff --git a/src/libcamera/v4l2_subdevice.cpp b/src/libcamera/v4l2_subdevice.cpp index a1672b2365f2..fe8b8e4eae2a 100644 --- a/src/libcamera/v4l2_subdevice.cpp +++ b/src/libcamera/v4l2_subdevice.cpp @@ -288,6 +288,32 @@ std::ostream &operator<<(std::ostream &out, const V4L2SubdeviceFormat &f) * \brief The format operation applies to TRY formats */ +/** + * \class V4L2Subdevice::Routing + * \brief V4L2 subdevice routing table + * + * This class stores a subdevice routing table as a vector of routes. + */ + +/** + * \brief Assemble and return a string describing the routing table + * \return A string describing the routing table + */ +std::string V4L2Subdevice::Routing::toString() const +{ + std::stringstream routing; + + for (const auto &[i, route] : utils::enumerate(*this)) { + routing << "[" << i << "] " + << route.sink_pad << "/" << route.sink_stream << " -> " + << route.source_pad << "/" << route.source_stream; + if (i != size() - 1) + routing << ", "; + } + + return routing.str(); +} + /** * \brief Create a V4L2 subdevice from a MediaEntity using its device node * path @@ -517,6 +543,85 @@ int V4L2Subdevice::setFormat(unsigned int pad, V4L2SubdeviceFormat *format, return 0; } +/** + * \brief Retrieve the subdevice's internal routing table + * \param[out] routing The routing table + * \param[in] whence The routing table to get, \ref V4L2Subdevice::ActiveFormat + * "ActiveFormat" or \ref V4L2Subdevice::TryFormat "TryFormat" + * + * \return 0 on success or a negative error code otherwise + */ +int V4L2Subdevice::getRouting(Routing *routing, Whence whence) +{ + if (!caps_.hasStreams()) + return 0; + + struct v4l2_subdev_routing rt = {}; + + rt.which = whence; + + int ret = ioctl(VIDIOC_SUBDEV_G_ROUTING, &rt); + if (ret == 0 || ret == -ENOTTY) + return ret; + + if (ret != -ENOSPC) { + LOG(V4L2, Error) + << "Failed to retrieve number of routes: " + << strerror(-ret); + return ret; + } + + routing->resize(rt.num_routes); + rt.routes = reinterpret_cast(routing->data()); + + ret = ioctl(VIDIOC_SUBDEV_G_ROUTING, &rt); + if (ret) { + LOG(V4L2, Error) + << "Failed to retrieve routes: " << strerror(-ret); + return ret; + } + + if (rt.num_routes != routing->size()) { + LOG(V4L2, Error) << "Invalid number of routes"; + return -EINVAL; + } + + return 0; +} + +/** + * \brief Set a routing table on the V4L2 subdevice + * \param[inout] routing The routing table + * \param[in] whence The routing table to set, \ref V4L2Subdevice::ActiveFormat + * "ActiveFormat" or \ref V4L2Subdevice::TryFormat "TryFormat" + * + * Apply to the V4L2 subdevice the routing table \a routing and update its + * content to reflect the actually applied routing table as getRouting() would + * do. + * + * \return 0 on success or a negative error code otherwise + */ +int V4L2Subdevice::setRouting(Routing *routing, Whence whence) +{ + if (!caps_.hasStreams()) + return 0; + + struct v4l2_subdev_routing rt = {}; + rt.which = whence; + rt.num_routes = routing->size(); + rt.routes = reinterpret_cast(routing->data()); + + int ret = ioctl(VIDIOC_SUBDEV_S_ROUTING, &rt); + if (ret) { + LOG(V4L2, Error) << "Failed to set routes: " << strerror(-ret); + return ret; + } + + routing->resize(rt.num_routes); + + return 0; +} + /** * \brief Retrieve the model name of the device *