[libcamera-devel,v2] libcamera: media_device: Fallback to legacy ioctls on older kernels

Message ID 20190125225247.16541-1-laurent.pinchart@ideasonboard.com
State Superseded
Headers show
Series
  • [libcamera-devel,v2] libcamera: media_device: Fallback to legacy ioctls on older kernels
Related show

Commit Message

Laurent Pinchart Jan. 25, 2019, 10:52 p.m. UTC
Prior to kernel v4.19, the MEDIA_IOC_G_TOPOLOGY ioctl didn't expose
entity flags. Fallback to calling MEDIA_IOC_ENUM_ENTITIES for each
entity to retrieve the flags in that case.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>
---
 src/libcamera/include/media_device.h |  3 ++
 src/libcamera/media_device.cpp       | 44 ++++++++++++++++++++++++++--
 2 files changed, 44 insertions(+), 3 deletions(-)

Patch

diff --git a/src/libcamera/include/media_device.h b/src/libcamera/include/media_device.h
index 27a2b46a4392..31413b9e4605 100644
--- a/src/libcamera/include/media_device.h
+++ b/src/libcamera/include/media_device.h
@@ -56,6 +56,8 @@  private:
 	std::string driver_;
 	std::string deviceNode_;
 	std::string model_;
+	unsigned int version_;
+
 	int fd_;
 	bool valid_;
 	bool acquired_;
@@ -72,6 +74,7 @@  private:
 	bool populateEntities(const struct media_v2_topology &topology);
 	bool populatePads(const struct media_v2_topology &topology);
 	bool populateLinks(const struct media_v2_topology &topology);
+	void fixupEntity(struct media_v2_entity *entity);
 
 	friend int MediaLink::setEnabled(bool enable);
 	int setupLink(const MediaLink *link, unsigned int flags);
diff --git a/src/libcamera/media_device.cpp b/src/libcamera/media_device.cpp
index be81bd8c4c23..715ba8263436 100644
--- a/src/libcamera/media_device.cpp
+++ b/src/libcamera/media_device.cpp
@@ -167,6 +167,7 @@  int MediaDevice::open()
 
 	driver_ = info.driver;
 	model_ = info.model;
+	version_ = info.media_version;
 
 	return 0;
 }
@@ -553,20 +554,24 @@  bool MediaDevice::populateEntities(const struct media_v2_topology &topology)
 						(topology.ptr_entities);
 
 	for (unsigned int i = 0; i < topology.num_entities; ++i) {
+		struct media_v2_entity *ent = &mediaEntities[i];
+
+		fixupEntity(ent);
+
 		/*
 		 * Find the interface linked to this entity to get the device
 		 * node major and minor numbers.
 		 */
 		struct media_v2_interface *iface =
-			findInterface(topology, mediaEntities[i].id);
+			findInterface(topology, ent->id);
 
 		MediaEntity *entity;
 		if (iface)
-			entity = new MediaEntity(this, &mediaEntities[i],
+			entity = new MediaEntity(this, ent,
 						 iface->devnode.major,
 						 iface->devnode.minor);
 		else
-			entity = new MediaEntity(this, &mediaEntities[i]);
+			entity = new MediaEntity(this, ent);
 
 		if (!addObject(entity)) {
 			delete entity;
@@ -657,6 +662,39 @@  bool MediaDevice::populateLinks(const struct media_v2_topology &topology)
 	return true;
 }
 
+/**
+ * \brief Fixup entity information using legacy API
+ * \param[in] entity The entity
+ *
+ * This function is used as a fallback to query entity information using the
+ * legacy MEDIA_IOC_ENUM_ENTITIES ioctl when running on a kernel version that
+ * doesn't provide all the information needed through the MEDIA_IOC_G_TOPOLOGY
+ * ioctl.
+ */
+void MediaDevice::fixupEntity(struct media_v2_entity *entity)
+{
+	/*
+	 * The media_v2_entity structure was missing the flag field before
+	 * v4.19.
+	 */
+	if (MEDIA_V2_ENTITY_HAS_FLAGS(version_))
+		return;
+
+	struct media_entity_desc desc = {};
+	desc.id = entity->id;
+
+	int ret = ioctl(fd_, MEDIA_IOC_ENUM_ENTITIES, &desc);
+	if (ret < 0) {
+		ret = -errno;
+		LOG(MediaDevice, Debug)
+			<< "Failed to retrieve information for entity "
+			<< entity->id << ": " << strerror(-ret);
+		return;
+	}
+
+	entity->flags = desc.flags;
+}
+
 /**
  * \brief Apply \a flags to a link between two pads
  * \param link The link to apply flags to