| /* SPDX-License-Identifier: GPL-2.0-or-later */ |
| /* |
| * Copyright (C) 2019, Google Inc. |
| * |
| * media_device_link_test.cpp - Tests link handling on VIMC media device |
| */ |
| |
| #include <iostream> |
| |
| #include "media_device_test.h" |
| |
| using namespace libcamera; |
| using namespace std; |
| |
| /* |
| * This link test requires a vimc device in order to exercise the |
| * MediaObject link handling API on a graph with a predetermined topology. |
| * |
| * vimc is a Media Controller kernel driver that creates virtual devices. |
| * From a userspace point of view they appear as normal media controller |
| * devices, but are not backed by any particular piece of hardware. They can |
| * thus be used for testing purpose without depending on a particular hardware |
| * platform. |
| * |
| * If no vimc device is found (most likely because the vimc driver is not |
| * loaded) the test is skipped. |
| */ |
| |
| class MediaDeviceLinkTest : public MediaDeviceTest |
| { |
| int init() |
| { |
| int ret = MediaDeviceTest::init(); |
| if (ret) |
| return ret; |
| |
| if (!media_->acquire()) { |
| cerr << "Unable to acquire media device " |
| << media_->deviceNode() << endl; |
| return TestFail; |
| } |
| |
| return TestPass; |
| } |
| |
| int run() |
| { |
| /* |
| * First of all disable all links in the media graph to |
| * ensure we start from a known state. |
| */ |
| if (media_->disableLinks()) { |
| cerr << "Failed to disable all links in the media graph"; |
| return TestFail; |
| } |
| |
| /* |
| * Test if link can be consistently retrieved through the |
| * different functions the media device offers. |
| */ |
| string linkName("'Debayer A':[1] -> 'Scaler':[0]'"); |
| MediaLink *link = media_->link("Debayer A", 1, "Scaler", 0); |
| if (!link) { |
| cerr << "Unable to find link: " << linkName |
| << " using lookup by name" << 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: " << linkName |
| << " using lookup by entity" << endl; |
| return TestFail; |
| } |
| |
| if (link != link2) { |
| cerr << "Link lookup by name and by entity don't match" |
| << endl; |
| return TestFail; |
| } |
| |
| link2 = media_->link(source->getPadByIndex(1), |
| sink->getPadByIndex(0)); |
| if (!link2) { |
| cerr << "Unable to find link: " << linkName |
| << " using lookup by pad" << endl; |
| return TestFail; |
| } |
| |
| if (link != link2) { |
| cerr << "Link lookup by name and by pad don't match" |
| << endl; |
| return TestFail; |
| } |
| |
| /* After reset the link shall not be enabled. */ |
| if (link->flags() & MEDIA_LNK_FL_ENABLED) { |
| cerr << "Link " << linkName |
| << " should not be enabled after a device reset" |
| << endl; |
| return TestFail; |
| } |
| |
| /* Enable the link and test if enabling was successful. */ |
| if (link->setEnabled(true)) { |
| cerr << "Failed to enable link: " << linkName |
| << endl; |
| return TestFail; |
| } |
| |
| if (!(link->flags() & MEDIA_LNK_FL_ENABLED)) { |
| cerr << "Link " << linkName |
| << " was enabled but it is reported as disabled" |
| << endl; |
| return TestFail; |
| } |
| |
| /* Disable the link and test if disabling was successful. */ |
| if (link->setEnabled(false)) { |
| cerr << "Failed to disable link: " << linkName |
| << endl; |
| return TestFail; |
| } |
| |
| if (link->flags() & MEDIA_LNK_FL_ENABLED) { |
| cerr << "Link " << linkName |
| << " was disabled but it is reported as enabled" |
| << endl; |
| return TestFail; |
| } |
| |
| /* Try to get a non existing link. */ |
| linkName = "'Sensor A':[1] -> 'Scaler':[0]"; |
| link = media_->link("Sensor A", 1, "Scaler", 0); |
| if (link) { |
| cerr << "Link lookup for " << linkName |
| << " succeeded but link does not exist" |
| << endl; |
| return TestFail; |
| } |
| |
| /* Now get an immutable link and try to disable it. */ |
| linkName = "'Sensor A':[0] -> 'Raw Capture 0':[0]"; |
| link = media_->link("Sensor A", 0, "Raw Capture 0", 0); |
| if (!link) { |
| cerr << "Unable to find link: " << linkName |
| << " using lookup by name" << endl; |
| return TestFail; |
| } |
| |
| if (!(link->flags() & MEDIA_LNK_FL_IMMUTABLE)) { |
| cerr << "Link " << linkName |
| << " should be 'IMMUTABLE'" << endl; |
| return TestFail; |
| } |
| |
| /* Disabling an immutable link shall fail. */ |
| if (!link->setEnabled(false)) { |
| cerr << "Disabling immutable link " << linkName |
| << " succeeded but should have failed" << endl; |
| return TestFail; |
| } |
| |
| /* |
| * Enable an disabled link, and verify it is disabled again |
| * after disabling all links in the media graph. |
| */ |
| linkName = "'Debayer B':[1] -> 'Scaler':[0]'"; |
| link = media_->link("Debayer B", 1, "Scaler", 0); |
| if (!link) { |
| cerr << "Unable to find link: " << linkName |
| << " using lookup by name" << endl; |
| return TestFail; |
| } |
| |
| if (link->setEnabled(true)) { |
| cerr << "Failed to enable link: " << linkName |
| << endl; |
| return TestFail; |
| } |
| |
| if (!(link->flags() & MEDIA_LNK_FL_ENABLED)) { |
| cerr << "Link " << linkName |
| << " was enabled but it is reported as disabled" |
| << endl; |
| return TestFail; |
| } |
| |
| if (media_->disableLinks()) { |
| cerr << "Failed to disable all links in the media graph"; |
| return TestFail; |
| } |
| |
| if (link->flags() & MEDIA_LNK_FL_ENABLED) { |
| cerr << "All links in the media graph have been disabled" |
| << " but link " << linkName |
| << " is still reported as enabled" << endl; |
| return TestFail; |
| } |
| |
| return 0; |
| } |
| |
| void cleanup() |
| { |
| media_->release(); |
| } |
| }; |
| |
| TEST_REGISTER(MediaDeviceLinkTest) |