From patchwork Tue Jan 8 17:04:04 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 182 Return-Path: Received: from relay12.mail.gandi.net (relay12.mail.gandi.net [217.70.178.232]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 5C20260B2E for ; Tue, 8 Jan 2019 18:04:09 +0100 (CET) Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay12.mail.gandi.net (Postfix) with ESMTPSA id E012B20000D; Tue, 8 Jan 2019 17:04:08 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Tue, 8 Jan 2019 18:04:04 +0100 Message-Id: <20190108170407.4770-2-jacopo@jmondi.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190108170407.4770-1-jacopo@jmondi.org> References: <20190108170407.4770-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 1/4] libcamera: Add pointer to MediaDevice to MediaObject 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: Tue, 08 Jan 2019 17:04:09 -0000 Add a MediaDevice member field to the MediaObject class hierarcy. Each media object now has a reference to the media device it belongs to, and which it has been created by. Signed-off-by: Jacopo Mondi Reviewed-by: Laurent Pinchart --- v1->v2: - Use the entity MediaDevice in MediaPad and MediaLink constructors - Incorporate comments changes from Laurent and Niklas on v1 src/libcamera/include/media_object.h | 7 +++++-- src/libcamera/media_device.cpp | 4 ++-- src/libcamera/media_object.cpp | 27 +++++++++++++++++++-------- 3 files changed, 26 insertions(+), 12 deletions(-) -- 2.20.1 diff --git a/src/libcamera/include/media_object.h b/src/libcamera/include/media_object.h index 04b9a89..d92aab3 100644 --- a/src/libcamera/include/media_object.h +++ b/src/libcamera/include/media_object.h @@ -22,13 +22,16 @@ class MediaObject { public: unsigned int id() const { return id_; } + MediaDevice *dev() const { return dev_; } protected: friend class MediaDevice; - MediaObject(unsigned int id) : id_(id) { } + MediaObject(MediaDevice *dev, unsigned int id) : + dev_(dev), id_(id) { } virtual ~MediaObject() { } + MediaDevice *dev_; unsigned int id_; }; @@ -93,7 +96,7 @@ public: private: friend class MediaDevice; - MediaEntity(const struct media_v2_entity *entity, + MediaEntity(MediaDevice *media, const struct media_v2_entity *entity, unsigned int major = 0, unsigned int minor = 0); MediaEntity(const MediaEntity &) = delete; ~MediaEntity(); diff --git a/src/libcamera/media_device.cpp b/src/libcamera/media_device.cpp index cf4ff90..b0d10ed 100644 --- a/src/libcamera/media_device.cpp +++ b/src/libcamera/media_device.cpp @@ -430,11 +430,11 @@ bool MediaDevice::populateEntities(const struct media_v2_topology &topology) MediaEntity *entity; if (iface) - entity = new MediaEntity(&mediaEntities[i], + entity = new MediaEntity(this, &mediaEntities[i], iface->devnode.major, iface->devnode.minor); else - entity = new MediaEntity(&mediaEntities[i]); + entity = new MediaEntity(this, &mediaEntities[i]); if (!addObject(entity)) { delete entity; diff --git a/src/libcamera/media_object.cpp b/src/libcamera/media_object.cpp index 06a8d64..612550d 100644 --- a/src/libcamera/media_object.cpp +++ b/src/libcamera/media_object.cpp @@ -42,16 +42,20 @@ namespace libcamera { * \class MediaObject * \brief Base class for all media objects * - * MediaObject is an abstract base class for all media objects in the media - * graph. Every media graph object is identified by an id unique in the media - * device context, and this base class provides that. + * MediaObject is an abstract base class for all media objects in the + * media graph. Each object is identified by a reference to the media + * device it belongs to and a unique id within that media device. + * This base class provide helpers to media objects to keep track of + * these identifiers. * * \sa MediaEntity, MediaPad, MediaLink */ /** * \fn MediaObject::MediaObject() - * \brief Construct a MediaObject with \a id + * \brief Construct a MediaObject part of the MediaDevice \a dev, + * identified by the \a id unique in within the device + * \param dev The media device this object belongs to * \param id The media object id * * The caller shall ensure unicity of the object id in the media device context. @@ -69,6 +73,11 @@ namespace libcamera { * \brief The media object id */ +/** + * \var MediaObject::dev_ + * \brief The media device the media object belongs to + */ + /** * \class MediaLink * \brief The MediaLink represents a link between two pads in the media graph. @@ -88,7 +97,7 @@ namespace libcamera { */ MediaLink::MediaLink(const struct media_v2_link *link, MediaPad *source, MediaPad *sink) - : MediaObject(link->id), source_(source), + : MediaObject(source->dev(), link->id), source_(source), sink_(sink), flags_(link->flags) { } @@ -139,7 +148,7 @@ MediaLink::MediaLink(const struct media_v2_link *link, MediaPad *source, * \param entity The entity the pad belongs to */ MediaPad::MediaPad(const struct media_v2_pad *pad, MediaEntity *entity) - : MediaObject(pad->id), index_(pad->index), entity_(entity), + : MediaObject(entity->dev(), pad->id), index_(pad->index), entity_(entity), flags_(pad->flags) { } @@ -283,13 +292,15 @@ int MediaEntity::setDeviceNode(const std::string &devnode) /** * \brief Construct a MediaEntity + * \param dev The media device this entity belongs to * \param entity The media entity kernel data * \param major The major number of the entity associated interface * \param minor The minor number of the entity associated interface */ -MediaEntity::MediaEntity(const struct media_v2_entity *entity, +MediaEntity::MediaEntity(MediaDevice *dev, + const struct media_v2_entity *entity, unsigned int major, unsigned int minor) - : MediaObject(entity->id), name_(entity->name), + : MediaObject(dev, entity->id), name_(entity->name), major_(major), minor_(minor) { } From patchwork Tue Jan 8 17:04:05 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 183 Return-Path: Received: from relay12.mail.gandi.net (relay12.mail.gandi.net [217.70.178.232]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id D75A060B2E for ; Tue, 8 Jan 2019 18:04:09 +0100 (CET) Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay12.mail.gandi.net (Postfix) with ESMTPSA id 7B15A200013; Tue, 8 Jan 2019 17:04:09 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Tue, 8 Jan 2019 18:04:05 +0100 Message-Id: <20190108170407.4770-3-jacopo@jmondi.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190108170407.4770-1-jacopo@jmondi.org> References: <20190108170407.4770-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 2/4] libcamera: media_device: Add functions to get a MediaLink 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: Tue, 08 Jan 2019 17:04:10 -0000 Add three overloaded functions 'link()' to retrieve a link between two pads. Each overloaded implementation exposes a different method to identify the source and sink pads. Signed-off-by: Jacopo Mondi Reviewed-by: Laurent Pinchart --- v1->v2: - Drop error handling: let the ioctl fail and report the error - Drop the const qualifier to link() methods - Incorporate comments changes src/libcamera/include/media_device.h | 6 +++ src/libcamera/media_device.cpp | 79 ++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+) -- 2.20.1 diff --git a/src/libcamera/include/media_device.h b/src/libcamera/include/media_device.h index 9f45fc7..397d349 100644 --- a/src/libcamera/include/media_device.h +++ b/src/libcamera/include/media_device.h @@ -40,6 +40,12 @@ public: const std::vector &entities() const { return entities_; } MediaEntity *getEntityByName(const std::string &name) const; + MediaLink *link(const std::string sourceName, unsigned int sourceIdx, + const std::string sinkName, unsigned int sinkIdx); + MediaLink *link(const MediaEntity *source, unsigned int sourceIdx, + const MediaEntity *sink, unsigned int sinkIdx); + MediaLink *link(const MediaPad *source, const MediaPad *sink); + private: std::string driver_; std::string devnode_; diff --git a/src/libcamera/media_device.cpp b/src/libcamera/media_device.cpp index b0d10ed..7ce5c22 100644 --- a/src/libcamera/media_device.cpp +++ b/src/libcamera/media_device.cpp @@ -306,6 +306,85 @@ MediaEntity *MediaDevice::getEntityByName(const std::string &name) const return nullptr; } +/** + * \brief Retrieve the MediaLink connecting two pads, identified by entity + * names and pad indexes + * \param sourceName The source entity name + * \param sourceIdx The index of the source pad + * \param sinkName The sink entity name + * \param sinkIdx The index of the sink pad + * + * Find the link that connects the pads at index \a sourceIdx of the source + * entity with name \a sourceName, to the pad at index \a sinkIdx of the + * sink entity with name \a sinkName, if any. + * + * \sa MediaDevice::link(const MediaEntity *source, unsigned int sourceIdx, const MediaEntity *sink, unsigned int sinkIdx) const + * \sa MediaDevice::link(const MediaPad *source, const MediaPad *sink) const + * + * \return The link that connects the two entities, or nullptr if not such a + * link exists + */ +MediaLink *MediaDevice::link(const std::string sourceName, unsigned int sourceIdx, + const std::string sinkName, unsigned int sinkIdx) +{ + const MediaEntity *source = getEntityByName(sourceName); + const MediaEntity *sink = getEntityByName(sinkName); + if (!source || !sink) + return nullptr; + + return link(source, sourceIdx, sink, sinkIdx); +} + +/** + * \brief Retrieve the MediaLink connecting two pads, identified by the + * entities they belong to and pad indexes + * \param source The source entity + * \param sourceIdx The index of the source pad + * \param sink The sink entity + * \param sinkIdx The index of the sink pad + * + * Find the link that connects the pads at index \a sourceIdx of the source + * entity \a source, to the pad at index \a sinkIdx of the sink entity \a + * sink, if any. + * + * \sa MediaDevice::link(const std::string sourceName, unsigned int sourceIdx, const std::string sinkName, unsigned int sinkIdx) const + * \sa MediaDevice::link(const MediaPad *source, const MediaPad *sink) const + * + * \return The link that connects the two entities, or nullptr if not such a + * link exists + */ +MediaLink *MediaDevice::link(const MediaEntity *source, unsigned int sourceIdx, + const MediaEntity *sink, unsigned int sinkIdx) +{ + + const MediaPad *sourcePad = source->getPadByIndex(sourceIdx); + const MediaPad *sinkPad = sink->getPadByIndex(sinkIdx); + if (!sourcePad || !sinkPad) + return nullptr; + + return link(sourcePad, sinkPad); +} + +/** + * \brief Retrieve the MediaLink that connects two pads + * \param source The source pad + * \param sink The sink pad + * + * \sa MediaDevice::link(const std::string sourceName, unsigned int sourceIdx, const std::string sinkName, unsigned int sinkIdx) const + * \sa MediaDevice::link(const MediaEntity *source, unsigned int sourceIdx, const MediaEntity *sink, unsigned int sinkIdx) const + * + * \return The link that connects the two entities, nullptr otherwise + */ +MediaLink *MediaDevice::link(const MediaPad *source, const MediaPad *sink) +{ + for (MediaLink *link : source->links()) { + if (link->sink()->id() == sink->id()) + return link; + } + + return nullptr; +} + /** * \var MediaDevice::objects_ * \brief Global map of media objects (entities, pads, links) keyed by their From patchwork Tue Jan 8 17:04:06 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 184 Return-Path: Received: from relay12.mail.gandi.net (relay12.mail.gandi.net [217.70.178.232]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 6E2A460B31 for ; Tue, 8 Jan 2019 18:04:10 +0100 (CET) Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay12.mail.gandi.net (Postfix) with ESMTPSA id 0B52E20000E; Tue, 8 Jan 2019 17:04:09 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Tue, 8 Jan 2019 18:04:06 +0100 Message-Id: <20190108170407.4770-4-jacopo@jmondi.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190108170407.4770-1-jacopo@jmondi.org> References: <20190108170407.4770-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 3/4] libcamera: Add link handling functions 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: Tue, 08 Jan 2019 17:04:11 -0000 Add a function to the MediaLink class to set the state of a link to enabled or disabled. The function makes use of an internal MediaDevice method, which is defined private and only accessible by the MediaLink setEnable() function itself. Also add to MediaDevice a function to reset all links registered in the media graph. Signed-off-by: Jacopo Mondi --- v1->v2: - Add resetLinks() function - s/enable()/setEnable() - s/setLink()/setupLink() - Pass MediaLink and not two MediaPads to MediaDevice::setupLink src/libcamera/include/media_device.h | 4 ++ src/libcamera/include/media_object.h | 1 + src/libcamera/media_device.cpp | 75 ++++++++++++++++++++++++++++ src/libcamera/media_object.cpp | 29 +++++++++++ 4 files changed, 109 insertions(+) -- 2.20.1 diff --git a/src/libcamera/include/media_device.h b/src/libcamera/include/media_device.h index 397d349..0f423aa 100644 --- a/src/libcamera/include/media_device.h +++ b/src/libcamera/include/media_device.h @@ -45,6 +45,7 @@ public: MediaLink *link(const MediaEntity *source, unsigned int sourceIdx, const MediaEntity *sink, unsigned int sinkIdx); MediaLink *link(const MediaPad *source, const MediaPad *sink); + int resetLinks(); private: std::string driver_; @@ -65,6 +66,9 @@ 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); + + friend int MediaLink::setEnable(bool enable); + int setupLink(const MediaLink *link, unsigned int flags); }; } /* namespace libcamera */ diff --git a/src/libcamera/include/media_object.h b/src/libcamera/include/media_object.h index d92aab3..bb46fac 100644 --- a/src/libcamera/include/media_object.h +++ b/src/libcamera/include/media_object.h @@ -41,6 +41,7 @@ public: MediaPad *source() const { return source_; } MediaPad *sink() const { return sink_; } unsigned int flags() const { return flags_; } + int setEnable(bool enable); private: friend class MediaDevice; diff --git a/src/libcamera/media_device.cpp b/src/libcamera/media_device.cpp index 7ce5c22..9900c3f 100644 --- a/src/libcamera/media_device.cpp +++ b/src/libcamera/media_device.cpp @@ -385,6 +385,35 @@ MediaLink *MediaDevice::link(const MediaPad *source, const MediaPad *sink) return nullptr; } +/** + * \brief Reset all links in the media device + * + * Reset the media device links, clearing the MEDIA_LNK_FL_ENABLED flag + * on links which are not flagged as IMMUTABLE. + * + * \return 0 for success, or a negative error code otherwise + */ +int MediaDevice::resetLinks() +{ + for (MediaEntity *entity : entities_) { + for (MediaPad *pad : entity->pads()) { + if (pad->flags() & MEDIA_PAD_FL_SINK) + continue; + + for (MediaLink *link : pad->links()) { + if (link->flags() & MEDIA_LNK_FL_IMMUTABLE) + continue; + + int ret = link->setEnable(false); + if (ret) + return ret; + } + } + } + + return 0; +} + /** * \var MediaDevice::objects_ * \brief Global map of media objects (entities, pads, links) keyed by their @@ -601,4 +630,50 @@ bool MediaDevice::populateLinks(const struct media_v2_topology &topology) return true; } +/** + * \brief Apply \a flags to a link between two pads + * \param link The link to apply flags on + * \param flags The flags to apply to the link + * + * This function applies the link \a flags (as defined by the MEDIA_LNK_FL_* + * macros from the Media Controller API) to the given \a link. It implements + * low-level link setup as it performs no checks on the validity of the \a + * flags, and assumes that the supplied \a flags are valid for the link (e.g. + * immutable links cannot be disabled)." +* + * \sa MediaLink::setEnable(bool enable) + * + * \return 0 for success, or a negative error code otherwise + */ +int MediaDevice::setupLink(const MediaLink *link, unsigned int flags) +{ + struct media_link_desc linkDesc = { }; + MediaPad *source = link->source(); + MediaPad *sink = link->sink(); + + linkDesc.source.entity = source->entity()->id(); + linkDesc.source.index = source->index(); + linkDesc.source.flags = MEDIA_PAD_FL_SOURCE; + + linkDesc.sink.entity = sink->entity()->id(); + linkDesc.sink.index = sink->index(); + linkDesc.sink.flags = MEDIA_PAD_FL_SINK; + + linkDesc.flags = flags; + + int ret = ioctl(fd_, MEDIA_IOC_SETUP_LINK, &linkDesc); + if (ret) { + ret = -errno; + LOG(Error) << "Failed to setup link: " << strerror(-ret); + return ret; + } + + LOG(Debug) << source->entity()->name() << "[" + << source->index() << "] -> " + << sink->entity()->name() << "[" + << sink->index() << "]: " << flags; + + return 0; +} + } /* namespace libcamera */ diff --git a/src/libcamera/media_object.cpp b/src/libcamera/media_object.cpp index 612550d..c6cb02b 100644 --- a/src/libcamera/media_object.cpp +++ b/src/libcamera/media_object.cpp @@ -15,6 +15,7 @@ #include #include "log.h" +#include "media_device.h" #include "media_object.h" /** @@ -89,6 +90,34 @@ namespace libcamera { * Each link is referenced in the link array of both of the pads it connect. */ +/** + * \brief Enable or disable a lik + * \param enable True to enable the link, false to disable it + * + * Set the status of a link, according to the value of \a enable. + * Links between two pads can be set to the enabled or disabled state freely, + * unless they're immutable links, whose status cannot be changed. + * Enabling an immutable link is not considered an error, while trying to + * disable it is. + * + * Enabling a link establishes a data connection between two pads, while + * disabling it interrupts such a connections. + * + * \return 0 on success, or a negative error code otherwise + */ +int MediaLink::setEnable(bool enable) +{ + unsigned int flags = enable ? MEDIA_LNK_FL_ENABLED : 0; + + int ret = dev_->setupLink(this, flags); + if (ret) + return ret; + + flags_ = flags; + + return 0; +} + /** * \brief Construct a MediaLink * \param link The media link kernel data From patchwork Tue Jan 8 17:04:07 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 185 Return-Path: Received: from relay12.mail.gandi.net (relay12.mail.gandi.net [217.70.178.232]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id E7CA660B3B for ; Tue, 8 Jan 2019 18:04:10 +0100 (CET) Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay12.mail.gandi.net (Postfix) with ESMTPSA id 8DB8520000F; Tue, 8 Jan 2019 17:04:10 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Tue, 8 Jan 2019 18:04:07 +0100 Message-Id: <20190108170407.4770-5-jacopo@jmondi.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190108170407.4770-1-jacopo@jmondi.org> References: <20190108170407.4770-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 4/4] test: MediaDevice: Add link exercise test 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: Tue, 08 Jan 2019 17:04:11 -0000 Add test function to exercise the link handling abilities of the media device. Signed-off-by: Jacopo Mondi --- v1->v2: - Make the link handling test work only on vimc as operating on a known graph makes it possible to identify unexpected results. test/media_device/media_device_test.cpp | 147 +++++++++++++++++++++++- 1 file changed, 143 insertions(+), 4 deletions(-) -- 2.20.1 diff --git a/test/media_device/media_device_test.cpp b/test/media_device/media_device_test.cpp index c482b2e..2b2f5cd 100644 --- a/test/media_device/media_device_test.cpp +++ b/test/media_device/media_device_test.cpp @@ -42,8 +42,145 @@ private: void printMediaGraph(const MediaDevice &media, ostream &os); void printLinkFlags(const MediaLink *link, ostream &os); void printNode(const MediaPad *pad, ostream &os); + + int exerciseLinks(MediaDevice &media); }; +/* + * Exercise the link handling interface. + * + * Try to get existing and non-existing links, and try to enable + * disable links. + * + * WARNING: this test only runs on VIMC, as a known media graph allows + * the test to exercise known links and verify the result of operations + * known to fail or succeed. If the 'vimc' driver is not loaded, the test is + * skipped. + */ +int MediaDeviceTest::exerciseLinks(MediaDevice &media) +{ + if (media.driver() != "vimc") + return TestSkip; + + /* First of all reset all links in the media graph. */ + int ret = media.resetLinks(); + if (ret) + return ret; + + /* + * Test if link can be consistently retrieved through the different + * methods the media device offers. + */ + MediaLink *link = media.link("Debayer A", 1, "Scaler", 0); + if (!link) { + cerr << "Unable to find link \"Debayer A\"[1] -> \"Scaler\"[0]" + << endl << "This link exists in VIMC media graph" << endl; + return TestFail; + } + + MediaEntity *source = media.getEntityByName("Debayer A"); + if (!source) { + cerr << "Unable to find entity \"Debayer A\"" << endl; + return TestFail; + } + + MediaEntity *sink = media.getEntityByName("Scaler"); + if (!sink) { + cerr << "Unable to find entity \"Scaler\"" << endl; + return TestFail; + } + + MediaLink *link2 = media.link(source, 1, sink, 0); + if (!link2) { + cerr << "Unable to find link \"Debayer A\"[1] -> \"Scaler\"[0]" + << endl << "This link exists in VIMC media graph" << endl; + return TestFail; + } + + if (link != link2) { + cerr << "The returned link does not match what was expected" + << endl; + return TestFail; + } + + link2 = media.link(source->getPadByIndex(1), sink->getPadByIndex(0)); + if (!link2) { + cerr << "Unable to find link \"Debayer A\"[1] -> \"Scaler\"[0]" + << endl << "This link exists in VIMC media graph" << endl; + return TestFail; + } + + if (link != link2) { + cerr << "The returned link does not match what was expected" + << endl; + return TestFail; + } + + /* After reset the link shall not be enabled. */ + if (link->flags() & MEDIA_LNK_FL_ENABLED) { + cerr << "Link \"Debayer A\"[1] -> \"Scaler\"[0]" + << " should not be enabled after a media device reset" + << endl; + return TestFail; + } + + /* Enable the link and test if enabling was successful. */ + ret = link->setEnable(true); + if (ret) + return TestFail; + + if (!(link->flags() & MEDIA_LNK_FL_ENABLED)) { + cerr << "Link \"Debayer A\"[1] -> \"Scaler\"[0]" + << " should now be enabled" << endl; + return TestFail; + } + + /* Disable the link and test if disabling was successful. */ + ret = link->setEnable(false); + if (ret) + return TestFail; + + if (link->flags() & MEDIA_LNK_FL_ENABLED) { + cerr << "Link \"Debayer A\"[1] -> \"Scaler\"[0]" + << " should now be disabled" << endl; + return TestFail; + } + + /* Try to get a non existing link. */ + link = media.link("Sensor A", 1, "Scaler", 0); + if (link) { + cerr << "Link \"Sensor A\"[1] -> \"Scaler\"[0]" + << " does not exist but something was returned" + << endl; + return TestFail; + } + + /* Now get an immutable link and try to disable it. */ + link = media.link("Sensor A", 0, "Raw Capture 0", 0); + if (!link) { + cerr << "Unable to find link \"Sensor A\"[0] -> " + << "\"Raw Capture 0\"[0]" + << endl << "This link exists in VIMC media graph" << endl; + return TestFail; + } + + if (!(link->flags() & MEDIA_LNK_FL_IMMUTABLE)) { + cerr << "Link \"Sensor A\"[0] -> \"Raw Capture 0\"[0]" + << " should have been 'IMMUTABLE'" << endl; + return TestFail; + } + + /* Disabling an immutable link shall fail. */ + ret = link->setEnable(false); + if (!ret) { + cerr << "Link \"Sensor A\"[0] -> \"Raw Capture 0\"[0]" + << " is 'IMMUTABLE', it shouldn't be disabled" << endl; + return TestFail; + } + + return 0; +} + void MediaDeviceTest::printNode(const MediaPad *pad, ostream &os) { const MediaEntity *entity = pad->entity(); @@ -136,11 +273,14 @@ int MediaDeviceTest::testMediaDevice(const string devnode) /* Run tests in sequence. */ printMediaGraph(dev, cerr); + + ret = exerciseLinks(dev); + /* TODO: add more tests here. */ dev.close(); - return 0; + return ret; } /* Run tests on all media devices. */ @@ -149,7 +289,7 @@ int MediaDeviceTest::run() { const string devnode("/dev/media"); unsigned int i; - int ret = 77; /* skip test exit code */ + int ret = TestSkip; /* * Run the test sequence on all media device found in the @@ -163,9 +303,8 @@ int MediaDeviceTest::run() continue; ret = testMediaDevice(mediadev); - if (ret) + if (ret && ret != TestSkip) return ret; - } return ret;