[libcamera-devel,3/3] libcamera: device_enumerator: Use MediaDevice

Message ID 20190102004903.24190-3-laurent.pinchart@ideasonboard.com
State Accepted
Headers show
Series
  • [libcamera-devel,1/3] libcamera: media_device: Add DeviceInfo features
Related show

Commit Message

Laurent Pinchart Jan. 2, 2019, 12:49 a.m. UTC
From: Jacopo Mondi <jacopo@jmondi.org>

Replace usage of the DeviceInfo class with MediaDevice in the
DeviceEnumerator and remove the DeviceInfo class.

Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 src/libcamera/device_enumerator.cpp       | 313 +++-------------------
 src/libcamera/include/device_enumerator.h |  33 +--
 src/libcamera/pipeline/vimc.cpp           |  17 +-
 3 files changed, 50 insertions(+), 313 deletions(-)

Patch

diff --git a/src/libcamera/device_enumerator.cpp b/src/libcamera/device_enumerator.cpp
index d5ba869f3457..7eef450e0c65 100644
--- a/src/libcamera/device_enumerator.cpp
+++ b/src/libcamera/device_enumerator.cpp
@@ -13,6 +13,7 @@ 
 
 #include "device_enumerator.h"
 #include "log.h"
+#include "media_device.h"
 
 /**
  * \file device_enumerator.h
@@ -28,8 +29,8 @@ 
  * for other parts of libcamera.
  *
  * The DeviceEnumerator can enumerate all or specific media devices in
- * the system. When a new media device is added the enumerator gathers
- * information about it and stores it in a DeviceInfo object.
+ * the system. When a new media device is added the enumerator creates a
+ * corresponding MediaDevice instance.
  *
  * The last functionality provided is the ability to search among the
  * enumerate media devices for one matching information known to the
@@ -42,135 +43,6 @@ 
 
 namespace libcamera {
 
-/**
- * \class DeviceInfo
- * \brief Container of information for enumerated device
- *
- * The DeviceInfo class holds information about a media device. It provides
- * methods to retrieve the information stored and to lookup entity names
- * to device node paths. Furthermore it provides a scheme where a device
- * can be acquired and released to indicate if the device is in use.
- *
- * \todo Look into the possibility to replace this with a more complete MediaDevice model.
- */
-
-/**
- * \brief Construct a container of device information
- *
- * \param[in] devnode The path to the device node of the media device
- * \param[in] info Information retrieved from MEDIA_IOC_DEVICE_INFO IOCTL
- * \param[in] entities A map of media graph 'Entity name' -> 'devnode path'
- *
- * The caller is responsible to provide all information for the device.
- */
-DeviceInfo::DeviceInfo(const std::string &devnode, const struct media_device_info &info,
-		       const std::map<std::string, std::string> &entities)
-	: acquired_(false), devnode_(devnode), info_(info), entities_(entities)
-{
-	for (const auto &entity : entities_)
-		LOG(Info) << "Device: " << devnode_ << " Entity: '" << entity.first << "' -> " << entity.second;
-}
-
-/**
- * \brief Claim a device for exclusive use
- *
- * Once a device is successfully acquired the caller is responsible to
- * release it once it is done wit it.
- *
- * \retval 0 Device claimed
- * \retval -EBUSY Device already claimed by someone else
- */
-int DeviceInfo::acquire()
-{
-	if (acquired_)
-		return -EBUSY;
-
-	acquired_ = true;
-
-	return 0;
-}
-
-/**
- * \brief Release a device from exclusive use
- */
-void DeviceInfo::release()
-{
-	acquired_ = false;
-}
-
-/**
- * \brief Check if a device is in use
- *
- * \retval true Device is in use
- * \retval false Device is free
- */
-bool DeviceInfo::busy() const
-{
-	return acquired_;
-}
-
-/**
- * \brief Retrieve the devnode to the media device
- *
- * \return Path to the media device (example /dev/media0)
- */
-const std::string &DeviceInfo::devnode() const
-{
-	return devnode_;
-}
-
-/**
- * \brief Retrieve the media device v4l2 information
- *
- * \return v4l2 specific information structure
- */
-const struct media_device_info &DeviceInfo::info() const
-{
-	return info_;
-}
-
-/**
- * \brief List all entities of the device
- *
- * List all media entities names from the media graph which are known
- * and to which this instance can lookup the device node path.
- *
- * \return List of strings
- */
-std::vector<std::string> DeviceInfo::entities() const
-{
-	std::vector<std::string> entities;
-
-	for (const auto &entity : entities_)
-		entities.push_back(entity.first);
-
-	return entities;
-}
-
-/**
- * \brief Lookup a media entity name and retrieve its device node path
- *
- * \param[in] name Entity name to lookup
- * \param[out] devnode Path to \a name devnode if lookup is successful
- *
- * The caller is responsible to check the return code of the function
- * to determine if the entity name could be looked up.
- *
- * \return 0 on success none zero otherwise
- */
-int DeviceInfo::lookup(const std::string &name, std::string &devnode) const
-{
-	auto it = entities_.find(name);
-
-	if (it == entities_.end()) {
-		LOG(Error) << "Trying to lookup entity '" << name << "' which does not exist";
-		return -ENODEV;
-	}
-
-	devnode = it->second;
-	return 0;
-}
-
 /**
  * \class DeviceMatch
  * \brief Description of a media device search pattern
@@ -205,25 +77,23 @@  void DeviceMatch::add(const std::string &entity)
 
 /**
  * \brief Compare a search pattern with a media device
- *
- * \param[in] info Information about a enumerated media device
+ * \param[in] device The media device
  *
  * Matching is performed on the Linux device driver name and entity names
  * from the media graph.
  *
- * \retval true The device described in \a info matches search pattern
- * \retval false The device described in \a info do not match search pattern
+ * \return true if the media device matches the search pattern, false otherwise
  */
-bool DeviceMatch::match(const DeviceInfo *info) const
+bool DeviceMatch::match(const MediaDevice *device) const
 {
-	if (driver_ != info->info().driver)
+	if (driver_ != device->driver())
 		return false;
 
 	for (const std::string &name : entities_) {
 		bool found = false;
 
-		for (const std::string &entity : info->entities()) {
-			if (name == entity) {
+		for (const MediaEntity *entity : device->entities()) {
+			if (name == entity->name()) {
 				found = true;
 				break;
 			}
@@ -281,7 +151,7 @@  DeviceEnumerator *DeviceEnumerator::create()
 
 DeviceEnumerator::~DeviceEnumerator()
 {
-	for (DeviceInfo *dev : devices_) {
+	for (MediaDevice *dev : devices_) {
 		if (dev->busy())
 			LOG(Error) << "Removing device info while still in use";
 
@@ -300,171 +170,62 @@  DeviceEnumerator::~DeviceEnumerator()
  */
 int DeviceEnumerator::addDevice(const std::string &devnode)
 {
-	int fd, ret;
+	MediaDevice *media = new MediaDevice(devnode);
 
-	struct media_device_info info = {};
-	std::map<std::string, std::string> entities;
-
-	fd = open(devnode.c_str(), O_RDWR);
-	if (fd < 0) {
-		ret = -errno;
-		LOG(Info) << "Unable to open " << devnode <<
-			  " (" << strerror(-ret) << "), skipping";
+	int ret = media->open();
+	if (ret < 0)
 		return ret;
-	}
 
-	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;
-}
-
-/**
- * \brief Fetch the MEDIA_IOC_DEVICE_INFO from media device
- *
- * \param[in] fd File pointer to media device
- * \param[out] info Information retrieved from MEDIA_IOC_DEVICE_INFO IOCTL
- *
- * Opens the media device and quires its information.
- *
- * \return 0 on success none zero otherwise
- */
-int DeviceEnumerator::readInfo(int fd, struct media_device_info &info)
-{
-	int ret;
-
-	ret = ioctl(fd, MEDIA_IOC_DEVICE_INFO, &info);
+	ret = media->populate();
 	if (ret < 0) {
-		ret = -errno;
-		LOG(Info) << "Unable to read device info " <<
+		LOG(Info) << "Unable to populate media device " << devnode <<
 			  " (" << strerror(-ret) << "), skipping";
 		return ret;
 	}
 
-	return 0;
-}
-
-/**
- * \brief Fetch the topology from media device
- *
- * \param[in] fd File pointer to media device
- * \param[out] entities Map of entity names to device node paths
- *
- * The media graph is retrieved using MEDIA_IOC_G_TOPOLOGY and the
- * result is transformed to a map where the entity name is the key
- * and the filesystem path for that entity device node is the value.
- *
- * \return 0 on success none zero otherwise
- */
-int DeviceEnumerator::readTopology(int fd, std::map<std::string, std::string> &entities)
-{
-	struct media_v2_topology topology;
-	struct media_v2_entity *ents = nullptr;
-	struct media_v2_interface *ifaces = nullptr;
-	struct media_v2_link *links = nullptr;
-	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 = reinterpret_cast<__u64>(ents);
-		topology.ptr_interfaces = reinterpret_cast<__u64>(ifaces);
-		topology.ptr_links = reinterpret_cast<__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)
+	/* Associate entities to device node paths. */
+	for (MediaEntity *entity : media->entities()) {
+		if (entity->major() == 0 && entity->minor() == 0)
 			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;
+		std::string devnode = lookupDevnode(entity->major(), entity->minor());
+		if (devnode.empty())
+			return -EINVAL;
 
-		devnode = lookupDevnode(ifaces[iface_id].devnode.major,
-					ifaces[iface_id].devnode.minor);
-		if (devnode == "")
-			break;
-
-		entities[ents[ent_id].name] = devnode;
+		ret = entity->setDeviceNode(devnode);
+		if (ret)
+			return ret;
 	}
-done:
-	delete[] links;
-	delete[] ifaces;
-	delete[] ents;
 
-	return ret;
+	devices_.push_back(media);
+	media->close();
+
+	return 0;
 }
 
 /**
  * \brief Search available media devices for a pattern match
  *
- * \param[in] dm search pattern
+ * \param[in] dm Search pattern
  *
- * Search the enumerated media devices who are not already in use
+ * Search in the enumerated media devices that are not already in use
  * for a match described in \a dm. If a match is found and the caller
- * intends to use it the caller is responsible to mark the DeviceInfo
+ * intends to use it the caller is responsible to mark the MediaDevice
  * object as in use and to release it when it's done with it.
  *
- * \return pointer to the matching DeviceInfo, nullptr if no match is found
+ * \return pointer to the matching MediaDevice, nullptr if no match is found
  */
-DeviceInfo *DeviceEnumerator::search(DeviceMatch &dm) const
+MediaDevice *DeviceEnumerator::search(DeviceMatch &dm) const
 {
-	DeviceInfo *info = nullptr;
-
-	for (DeviceInfo *dev : devices_) {
+	for (MediaDevice *dev : devices_) {
 		if (dev->busy())
 			continue;
 
-		if (dm.match(dev)) {
-			info = dev;
-			break;
-		}
+		if (dm.match(dev))
+			return dev;
 	}
 
-	return info;
+	return nullptr;
 }
 
 /**
diff --git a/src/libcamera/include/device_enumerator.h b/src/libcamera/include/device_enumerator.h
index 24bca0e3fc32..0d104667323b 100644
--- a/src/libcamera/include/device_enumerator.h
+++ b/src/libcamera/include/device_enumerator.h
@@ -15,29 +15,7 @@ 
 
 namespace libcamera {
 
-class DeviceInfo
-{
-public:
-	DeviceInfo(const std::string &devnode, const struct media_device_info &info,
-		   const std::map<std::string, std::string> &entities);
-
-	int acquire();
-	void release();
-	bool busy() const;
-
-	const std::string &devnode() const;
-	const struct media_device_info &info() const;
-	std::vector<std::string> entities() const;
-
-	int lookup(const std::string &name, std::string &devnode) const;
-
-private:
-	bool acquired_;
-
-	std::string devnode_;
-	struct media_device_info info_;
-	std::map<std::string, std::string> entities_;
-};
+class MediaDevice;
 
 class DeviceMatch
 {
@@ -46,7 +24,7 @@  public:
 
 	void add(const std::string &entity);
 
-	bool match(const DeviceInfo *info) const;
+	bool match(const MediaDevice *device) const;
 
 private:
 	std::string driver_;
@@ -63,16 +41,13 @@  public:
 	virtual int init() = 0;
 	virtual int enumerate() = 0;
 
-	DeviceInfo *search(DeviceMatch &dm) const;
+	MediaDevice *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);
+	std::vector<MediaDevice *> devices_;
 
 	virtual std::string lookupDevnode(int major, int minor) = 0;
 };
diff --git a/src/libcamera/pipeline/vimc.cpp b/src/libcamera/pipeline/vimc.cpp
index b1e2d32c8ba2..720d9c2031c9 100644
--- a/src/libcamera/pipeline/vimc.cpp
+++ b/src/libcamera/pipeline/vimc.cpp
@@ -8,6 +8,7 @@ 
 #include <libcamera/camera.h>
 
 #include "device_enumerator.h"
+#include "media_device.h"
 #include "pipeline_handler.h"
 
 namespace libcamera {
@@ -24,12 +25,12 @@  public:
 	Camera *camera(unsigned int id) final;
 
 private:
-	DeviceInfo *info_;
+	MediaDevice *dev_;
 	Camera *camera_;
 };
 
 PipeHandlerVimc::PipeHandlerVimc()
-	: info_(nullptr), camera_(nullptr)
+	: dev_(nullptr), camera_(nullptr)
 {
 }
 
@@ -38,8 +39,8 @@  PipeHandlerVimc::~PipeHandlerVimc()
 	if (camera_)
 		camera_->put();
 
-	if (info_)
-		info_->release();
+	if (dev_)
+		dev_->release();
 }
 
 unsigned int PipeHandlerVimc::count()
@@ -69,15 +70,15 @@  bool PipeHandlerVimc::match(DeviceEnumerator *enumerator)
 	dm.add("RGB/YUV Input");
 	dm.add("Scaler");
 
-	info_ = enumerator->search(dm);
-	if (!info_)
+	dev_ = enumerator->search(dm);
+	if (!dev_)
 		return false;
 
-	info_->acquire();
+	dev_->acquire();
 
 	/*
 	 * NOTE: A more complete Camera implementation could
-	 * be passed the DeviceInfo(s) it controls here or
+	 * be passed the MediaDevice(s) it controls here or
 	 * a reference to the PipelineHandler. Which method
 	 * will be chosen depends on how the Camera
 	 * object is modeled.