From 495aac658dcedd7622b4108daf6c8ca4d8327599 Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Wed, 30 Mar 2022 12:27:03 +0200 Subject: libcamera: v4l2_subdevice: Add support for the V4L2 subdev routing API 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 Tested-by: Jacopo Mondi --- src/libcamera/v4l2_subdevice.cpp | 106 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) (limited to 'src') diff --git a/src/libcamera/v4l2_subdevice.cpp b/src/libcamera/v4l2_subdevice.cpp index a1672b23..e5d20f2c 100644 --- a/src/libcamera/v4l2_subdevice.cpp +++ b/src/libcamera/v4l2_subdevice.cpp @@ -288,6 +288,33 @@ 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 + << " (" << utils::hex(route.flags) << ")"; + if (i != size() - 1) + routing << ", "; + } + + return routing.str(); +} + /** * \brief Create a V4L2 subdevice from a MediaEntity using its device node * path @@ -517,6 +544,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 * -- cgit v1.2.1