/* 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 <memory> #include "device_enumerator.h" #include "media_device.h" #include "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 Test { int init() { enumerator = unique_ptr<DeviceEnumerator>(DeviceEnumerator::create()); if (!enumerator) { cerr << "Failed to create device enumerator" << endl; return TestFail; } if (enumerator->enumerate()) { cerr << "Failed to enumerate media devices" << endl; return TestFail; } DeviceMatch dm("vimc"); dev_ = enumerator->search(dm); if (!dev_) { cerr << "No VIMC media device found: skip test" << endl; return TestSkip; } dev_->acquire(); if (dev_->open()) { cerr << "Failed to open media device at " << dev_->deviceNode() << endl; return TestFail; } return 0; } int run() { /* * First of all disable all links in the media graph to * ensure we start from a known state. */ if (dev_->disableLinks()) { cerr << "Failed to disable all links in the media graph"; return TestFail; } /* * Test if link can be consistently retrieved through the * different methods the media device offers. */ string linkName("'Debayer A':[1] -> 'Scaler':[0]'"); MediaLink *link = dev_->link("Debayer A", 1, "Scaler", 0); if (!link) { cerr << "Unable to find link: " << linkName << " using lookup by name" << endl; return TestFail; } MediaEntity *source = dev_->getEntityByName("Debayer A"); if (!source) { cerr << "Unable to find entity: 'Debayer A'" << endl; return TestFail; } MediaEntity *sink = dev_->getEntityByName("Scaler"); if (!sink) { cerr << "Unable to find entity: 'Scaler'" << endl; return TestFail; } MediaLink *link2 = dev_->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 = dev_->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 = dev_->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 = dev_->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 = dev_->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 (dev_->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() { dev_->close(); dev_->release(); } private: unique_ptr<DeviceEnumerator> enumerator; MediaDevice *dev_; }; TEST_REGISTER(MediaDeviceLinkTest);