[libcamera-devel,08/13] libcamera: v4l2_subdevice: Add support for the V4L2 subdev routing API
diff mbox series

Message ID 20220801000543.3501-9-laurent.pinchart@ideasonboard.com
State Accepted
Headers show
Series
  • libcamera: pipeline: simple: Support the NXP i.MX8 ISI
Related show

Commit Message

Laurent Pinchart Aug. 1, 2022, 12:05 a.m. UTC
From: Jacopo Mondi <jacopo@jmondi.org>

Extend the V4L2Subdevice class to support getting and setting routing
tables.

Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
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(+)

Comments

Tomi Valkeinen Aug. 2, 2022, 11:01 a.m. UTC | #1
On 01/08/2022 03:05, Laurent Pinchart via libcamera-devel wrote:
> From: Jacopo Mondi <jacopo@jmondi.org>
> 
> Extend the V4L2Subdevice class to support getting and setting routing
> tables.
> 
> Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> ---
> 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<struct v4l2_subdev_route>
> +	{
> +	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;

I would also add the route flags. Even if it's just a hex number in the 
print, it may help catching bugs.

Other than that:

Reviewed-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>

  Tomi

Patch
diff mbox series

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<struct v4l2_subdev_route>
+	{
+	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<uintptr_t>(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<uintptr_t>(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
  *