From patchwork Wed Jan 2 00:49:03 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 129 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 024B160B30 for ; Wed, 2 Jan 2019 01:48:09 +0100 (CET) Received: from avalon.bb.dnainternet.fi (dfj612ybrt5fhg77mgycy-3.rev.dnainternet.fi [IPv6:2001:14ba:21f5:5b00:2e86:4862:ef6a:2804]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 57564505 for ; Wed, 2 Jan 2019 01:48:08 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1546390088; bh=JCv/CXK7OO2ZNTfYo8WanUC1fqo8QVhawn1tOKZoSZc=; h=From:To:Subject:Date:In-Reply-To:References:From; b=HBdGmetstCehblNe1FtMPifu1Ahaq9yyoa3mG2yokBjukqBGNY2lUjPiagT0HubUw E+u0Uyqjr7jsKPtyBkeTljfdmaIGVejVQH9SlUQrS0ofuNLD6y0Epc34pa8heDwhex NXGk22Nl0Crqz5bBzebsGpJqFDe1AaJ43tjPTA4o= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Wed, 2 Jan 2019 02:49:03 +0200 Message-Id: <20190102004903.24190-3-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.19.2 In-Reply-To: <20190102004903.24190-1-laurent.pinchart@ideasonboard.com> References: <20190102004903.24190-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 3/3] libcamera: device_enumerator: Use MediaDevice X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 02 Jan 2019 00:48:09 -0000 From: Jacopo Mondi Replace usage of the DeviceInfo class with MediaDevice in the DeviceEnumerator and remove the DeviceInfo class. Signed-off-by: Jacopo Mondi Signed-off-by: Laurent Pinchart --- 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(-) 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 &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 DeviceInfo::entities() const -{ - std::vector 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 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 &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 &entities); - - int acquire(); - void release(); - bool busy() const; - - const std::string &devnode() const; - const struct media_device_info &info() const; - std::vector 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 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 devices_; - - int readInfo(int fd, struct media_device_info &info); - int readTopology(int fd, std::map &entities); + std::vector 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 #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.