@@ -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;
}
/**
@@ -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;
};
@@ -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.