[libcamera-devel] [PATCH 05/12] libcamera: deviceenumerator: add DeviceEnumerator class

Niklas Söderlund niklas.soderlund at ragnatech.se
Sun Dec 23 00:00:34 CET 2018


Provide a DeviceEnumerator base class which enumerates all media devices
in the system and information about them, resolving V4L2 data structures
to paths and a method to search in all the enumerated information.

Signed-off-by: Niklas Söderlund <niklas.soderlund at ragnatech.se>
---
 src/libcamera/deviceenumerator.cpp       | 144 +++++++++++++++++++++++
 src/libcamera/include/deviceenumerator.h |  22 ++++
 2 files changed, 166 insertions(+)

diff --git a/src/libcamera/deviceenumerator.cpp b/src/libcamera/deviceenumerator.cpp
index 17b6874d229c791c..b2f59017e94d14aa 100644
--- a/src/libcamera/deviceenumerator.cpp
+++ b/src/libcamera/deviceenumerator.cpp
@@ -5,6 +5,10 @@
  * deviceenumerator.cpp - Enumeration and matching
  */
 
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+
 #include "deviceenumerator.h"
 #include "log.h"
 
@@ -129,4 +133,144 @@ bool DeviceMatch::matchEntities(const std::vector<std::string> &entities) const
 	return true;
 }
 
+/* -----------------------------------------------------------------------------
+ * Enumerator Base
+ */
+
+DeviceEnumerator::~DeviceEnumerator()
+{
+	for (DeviceInfo *dev : devices_) {
+		if (dev->busy())
+			LOG(Error) << "Removing device info while still in use";
+
+		delete dev;
+	}
+}
+
+int DeviceEnumerator::addDevice(const std::string &devnode)
+{
+	int fd, ret;
+
+	struct media_device_info info = {};
+	std::map<std::string, std::string> entities;
+
+	fd = open(devnode.c_str(), O_RDWR);
+	if (fd < 0)
+		return fd;
+
+	ret = readInfo(fd, info);
+	if (ret)
+		goto out;
+
+	ret = readTopology(fd, entities);
+	if (ret)
+		goto out;
+
+	devices_.push_back(new DeviceInfo(devnode, info, entities));
+out:
+	close(fd);
+
+	return ret;
+}
+
+int DeviceEnumerator::readInfo(int fd, struct media_device_info &info)
+{
+	int ret;
+
+	ret = ioctl(fd, MEDIA_IOC_DEVICE_INFO, &info);
+	if (ret < 0)
+		return -errno;
+
+	return 0;
+}
+
+int DeviceEnumerator::readTopology(int fd, std::map<std::string, std::string> &entities)
+{
+	struct media_v2_topology topology;
+	struct media_v2_entity *ents = NULL;
+	struct media_v2_interface *ifaces = NULL;
+	struct media_v2_link *links = NULL;
+	int ret;
+
+	while (true) {
+		topology = {};
+
+		ret = ioctl(fd, MEDIA_IOC_G_TOPOLOGY, &topology);
+		if (ret < 0)
+			return -errno;
+
+		__u64 version = topology.topology_version;
+
+		ents = new media_v2_entity[topology.num_entities]();
+		ifaces = new media_v2_interface[topology.num_interfaces]();
+		links = new media_v2_link[topology.num_links]();
+		topology.ptr_entities = (__u64)ents;
+		topology.ptr_interfaces = (__u64)ifaces;
+		topology.ptr_links = (__u64)links;
+
+		ret = ioctl(fd, MEDIA_IOC_G_TOPOLOGY, &topology);
+		if (ret < 0) {
+			ret = -errno;
+			goto done;
+		}
+
+		if (version == topology.topology_version)
+			break;
+
+		delete[] links;
+		delete[] ifaces;
+		delete[] ents;
+	}
+
+	for (unsigned int link_id = 0; link_id < topology.num_links; link_id++) {
+		unsigned int iface_id, ent_id;
+		std::string devnode;
+
+		if ((links[link_id].flags & MEDIA_LNK_FL_LINK_TYPE) != MEDIA_LNK_FL_INTERFACE_LINK)
+			continue;
+
+		for (iface_id = 0; iface_id < topology.num_interfaces; iface_id++)
+			if (links[link_id].source_id == ifaces[iface_id].id)
+				break;
+
+		for (ent_id = 0; ent_id < topology.num_entities; ent_id++)
+			if (links[link_id].sink_id == ents[ent_id].id)
+				break;
+
+		if (ent_id >= topology.num_entities || iface_id >= topology.num_interfaces)
+			continue;
+
+		ret = lookupDevnode(devnode,
+				    ifaces[iface_id].devnode.major,
+				    ifaces[iface_id].devnode.minor);
+		if (ret)
+			break;
+
+		entities[ents[ent_id].name] = devnode;
+	}
+done:
+	delete[] links;
+	delete[] ifaces;
+	delete[] ents;
+
+	return ret;
+}
+
+DeviceInfo *DeviceEnumerator::search(DeviceMatch &dm) const
+{
+	DeviceInfo *info = NULL;
+
+	for (DeviceInfo *dev : devices_) {
+		if (dev->busy())
+			continue;
+
+		if (dm.match(dev)) {
+			info = dev;
+			break;
+		}
+	}
+
+	return info;
+}
+
 } /* namespace libcamera */
diff --git a/src/libcamera/include/deviceenumerator.h b/src/libcamera/include/deviceenumerator.h
index fb412b8840cb2ffe..cbe17774edb7fcc5 100644
--- a/src/libcamera/include/deviceenumerator.h
+++ b/src/libcamera/include/deviceenumerator.h
@@ -56,6 +56,28 @@ private:
 	bool matchEntities(const std::vector<std::string> &entities) const;
 };
 
+class DeviceEnumerator
+{
+public:
+	virtual ~DeviceEnumerator();
+
+	virtual int init() = 0;
+	virtual int enumerate() = 0;
+
+	DeviceInfo *search(DeviceMatch &dm) const;
+
+protected:
+	int addDevice(const std::string &devnode);
+
+private:
+	std::vector<DeviceInfo *> devices_;
+
+	int readInfo(int fd, struct media_device_info &info);
+	int readTopology(int fd, std::map<std::string, std::string> &entities);
+
+	virtual int lookupDevnode(std::string &devnode, int major, int minor) = 0;
+};
+
 } /* namespace libcamera */
 
 #endif	/* __LIBCAMERA_DEVICEENUMERATE_H__ */
-- 
2.20.1



More information about the libcamera-devel mailing list