From patchwork Tue Jan 15 14:07:46 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 228 Return-Path: Received: from relay12.mail.gandi.net (relay12.mail.gandi.net [217.70.178.232]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 8367A60C85 for ; Tue, 15 Jan 2019 15:07:47 +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 1F305200013; Tue, 15 Jan 2019 14:07:46 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Tue, 15 Jan 2019 15:07:46 +0100 Message-Id: <20190115140749.8297-2-jacopo@jmondi.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190115140749.8297-1-jacopo@jmondi.org> References: <20190115140749.8297-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 1/4] test: list-cameras: Make test output more verbose 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, 15 Jan 2019 14:07:47 -0000 Make the list-cameras test a little more verbose to better describe failures. While at there use the Test class defined TestStatus value as test exit codes, and skip the test if no camera gets registred. Signed-off-by: Jacopo Mondi --- test/list-cameras.cpp | 52 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 45 insertions(+), 7 deletions(-) diff --git a/test/list-cameras.cpp b/test/list-cameras.cpp index e2026c9..b6b0a39 100644 --- a/test/list-cameras.cpp +++ b/test/list-cameras.cpp @@ -7,6 +7,7 @@ #include +#include #include #include "test.h" @@ -14,27 +15,64 @@ using namespace std; using namespace libcamera; +/* + * List all cameras registered in the system, using the CameraManager. + * + * In order for the test to run successfully, a pipeline handler supporting + * the current test platform should be available in the library. + * Libcamera provides a platform-agnostic pipeline handler for the 'vimc' + * virtual media device, which can be used for testing purposes. + * + * The test tries to list all cameras registered in the system, if no + * camera is found the test is skipped. If the test gets skipped on a + * platform where a pipeline handler is known to be available, an error + * in camera enumeration might get un-noticed. + */ class ListTest : public Test { protected: int init() { cm = CameraManager::instance(); - cm->start(); + if (!cm) { + cerr << "Failed to get CameraManager instance" << endl; + return TestFail; + } - return 0; + int ret = cm->start(); + if (ret) { + cerr << "Failed to start the CameraManager" << endl; + return TestFail; + } + + return TestPass; } int run() { - unsigned int count = 0; + vector cameraList = cm->list(); + if (cameraList.empty()) { + cerr << "No cameras registered in the system: test skip" + << endl + << "This might be expected if no pipeline handler" + << " supports the testing platform" + << endl; + return TestSkip; + } + + for (auto name : cameraList) { + Camera *cam = cm->get(name); + if (!cam) { + cerr << "Failed to get camera '" << name + << "' by name" << endl; + return TestFail; + } - for (auto name : cm->list()) { - cout << "- " << name << endl; - count++; + cout << "Camera '" << cam->name() + << "' registered" << endl; } - return count ? 0 : -ENODEV; + return TestPass; } void cleanup() From patchwork Tue Jan 15 14:07:47 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 229 Return-Path: Received: from relay12.mail.gandi.net (relay12.mail.gandi.net [217.70.178.232]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 1D8D260C78 for ; Tue, 15 Jan 2019 15:07:48 +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 AA13920001C; Tue, 15 Jan 2019 14:07:47 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Tue, 15 Jan 2019 15:07:47 +0100 Message-Id: <20190115140749.8297-3-jacopo@jmondi.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190115140749.8297-1-jacopo@jmondi.org> References: <20190115140749.8297-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 2/4] libcamera: Make Camera destructor public 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, 15 Jan 2019 14:07:48 -0000 The Camera class destructor is defined as private, but it needs to be accessed by classes that create Camera instances, such as pipeline handlers. Signed-off-by: Jacopo Mondi Reviewed-by: Kieran Bingham --- include/libcamera/camera.h | 2 +- src/libcamera/pipeline/vimc.cpp | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/include/libcamera/camera.h b/include/libcamera/camera.h index 9a7579d..d751d2d 100644 --- a/include/libcamera/camera.h +++ b/include/libcamera/camera.h @@ -15,13 +15,13 @@ class Camera { public: Camera(const std::string &name); + virtual ~Camera() { }; const std::string &name() const; void get(); void put(); private: - virtual ~Camera() { }; int ref_; std::string name_; }; diff --git a/src/libcamera/pipeline/vimc.cpp b/src/libcamera/pipeline/vimc.cpp index 720d9c2..00c544c 100644 --- a/src/libcamera/pipeline/vimc.cpp +++ b/src/libcamera/pipeline/vimc.cpp @@ -41,6 +41,8 @@ PipeHandlerVimc::~PipeHandlerVimc() if (dev_) dev_->release(); + + delete camera_; } unsigned int PipeHandlerVimc::count() From patchwork Tue Jan 15 14:07:48 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 230 Return-Path: Received: from relay12.mail.gandi.net (relay12.mail.gandi.net [217.70.178.232]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id AC21460C89 for ; Tue, 15 Jan 2019 15:07:48 +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 4AEB1200013; Tue, 15 Jan 2019 14:07:48 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Tue, 15 Jan 2019 15:07:48 +0100 Message-Id: <20190115140749.8297-4-jacopo@jmondi.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190115140749.8297-1-jacopo@jmondi.org> References: <20190115140749.8297-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 3/4] libcamera: media_object: Add functions to entities 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, 15 Jan 2019 14:07:48 -0000 Media entities convey information about their main function in the 'function' field of 'struct media_v2_entity'. Store the main function in the MediaEntity function_ class member and provide a getter function for that. While at there update comments and remove a stale TODO entry. Signed-off-by: Jacopo Mondi Reviewed-by: Kieran Bingham Reviewed-by: Laurent Pinchart --- src/libcamera/include/media_object.h | 2 ++ src/libcamera/media_object.cpp | 18 +++++++++++++----- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/libcamera/include/media_object.h b/src/libcamera/include/media_object.h index 7fc4441..a10f7e1 100644 --- a/src/libcamera/include/media_object.h +++ b/src/libcamera/include/media_object.h @@ -84,6 +84,7 @@ class MediaEntity : public MediaObject { public: const std::string &name() const { return name_; } + unsigned int function() const { return function_; } unsigned int deviceMajor() const { return major_; } unsigned int deviceMinor() const { return minor_; } @@ -103,6 +104,7 @@ private: ~MediaEntity(); std::string name_; + unsigned int function_; std::string devnode_; unsigned int major_; unsigned int minor_; diff --git a/src/libcamera/media_object.cpp b/src/libcamera/media_object.cpp index cb3af85..c47fb53 100644 --- a/src/libcamera/media_object.cpp +++ b/src/libcamera/media_object.cpp @@ -243,10 +243,8 @@ void MediaPad::addLink(MediaLink *link) * API in the media_v2_entity structure. They reference the pads() they contain. * * In addition to its graph id, every media graph entity is identified by a - * name() unique in the media device context. - * - * \todo Add support for associating a devnode to the entity when integrating - * with DeviceEnumerator. + * name() unique in the media device context, a function() and its associated + * devnode, if any. */ /** @@ -255,6 +253,16 @@ void MediaPad::addLink(MediaLink *link) * \return The entity name */ +/** + * \fn MediaEntity::function() + * \brief Retrieve the entity main function + * + * Media entity functions are expressed using the MEDIA_ENT_F_* macros + * defined by the Media Controller API. + * + * \return The entity function + */ + /** * \fn MediaEntity::deviceMajor() * \brief Retrieve the major number of the interface associated with the entity @@ -336,7 +344,7 @@ MediaEntity::MediaEntity(MediaDevice *dev, const struct media_v2_entity *entity, unsigned int major, unsigned int minor) : MediaObject(dev, entity->id), name_(entity->name), - major_(major), minor_(minor) + function_(entity->function), major_(major), minor_(minor) { } From patchwork Tue Jan 15 14:07:49 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 231 Return-Path: Received: from relay12.mail.gandi.net (relay12.mail.gandi.net [217.70.178.232]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 4BCF260C8D for ; Tue, 15 Jan 2019 15:07:49 +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 D5B5B200011; Tue, 15 Jan 2019 14:07:48 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Tue, 15 Jan 2019 15:07:49 +0100 Message-Id: <20190115140749.8297-5-jacopo@jmondi.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190115140749.8297-1-jacopo@jmondi.org> References: <20190115140749.8297-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 4/4] libcamera: pipeline: Add Intel IPU3 pipeline 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, 15 Jan 2019 14:07:49 -0000 Add a pipeline handler for the Intel IPU3 device. The pipeline handler creates a Camera for each image sensor it finds to be connected to an IPU3 CSI-2 receiver, and enables the link between the two. Tested on Soraka, listing detected cameras on the system, verifying the pipeline handler gets matched and links properly enabled. Signed-off-by: Jacopo Mondi Reviewed-by: Kieran Bingham --- src/libcamera/pipeline/ipu3/ipu3.cpp | 249 ++++++++++++++++++++++++ src/libcamera/pipeline/ipu3/meson.build | 3 + src/libcamera/pipeline/meson.build | 2 + 3 files changed, 254 insertions(+) create mode 100644 src/libcamera/pipeline/ipu3/ipu3.cpp create mode 100644 src/libcamera/pipeline/ipu3/meson.build diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp new file mode 100644 index 0000000..4c24c79 --- /dev/null +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -0,0 +1,249 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * ipu3.cpp - Pipeline handler for Intel IPU3 + */ + +#include +#include + +#include + +#include "device_enumerator.h" +#include "log.h" +#include "media_device.h" +#include "pipeline_handler.h" + +namespace libcamera { + +class PipelineHandlerIPU3 : public PipelineHandler +{ +public: + PipelineHandlerIPU3(); + ~PipelineHandlerIPU3(); + + bool match(DeviceEnumerator *enumerator); + + unsigned int count(); + Camera *camera(unsigned int id) final; + +private: + MediaDevice *cio2_; + MediaDevice *imgu_; + + unsigned int numCameras_; + std::map cameras_; + + unsigned int registerCameras(); +}; + +PipelineHandlerIPU3::PipelineHandlerIPU3() + : cio2_(nullptr), imgu_(nullptr), numCameras_(0) +{ +} + +PipelineHandlerIPU3::~PipelineHandlerIPU3() +{ + if (cio2_) + cio2_->release(); + + if (imgu_) + imgu_->release(); + + for (auto camera : cameras_) { + if (!camera.second) + continue; + + camera.second->put(); + + /* + * FIXME + * The lifetime management of Camera instances will be + * soon changed: as of now, the handler creates cameras, and + * -shall- destroy them as well to avoid leaks. + */ + delete camera.second; + } + + cio2_ = nullptr; + imgu_ = nullptr; + cameras_.clear(); +} + +unsigned int PipelineHandlerIPU3::count() +{ + return numCameras_; +} + +Camera *PipelineHandlerIPU3::camera(unsigned int id) +{ + if (id >= numCameras_) + return nullptr; + + /* + * The requested camera id does not match the key index used to store + * Camera instances in the 'cameras_' map. + * + * The 'id' argument represent the n-th valid cameras registered + * in the system, while the indexing key is the CSI-2 receiver index + * the camera sensor is associated to, and some receiver might have no + * camera sensor connected. + */ + for (auto it = cameras_.begin(); it != cameras_.end(); ++it, --id) { + if (id == 0) + return (*it).second; + } + + return nullptr; +} + +bool PipelineHandlerIPU3::match(DeviceEnumerator *enumerator) +{ + DeviceMatch cio2_dm("ipu3-cio2"); + cio2_dm.add("ipu3-csi2 0"); + cio2_dm.add("ipu3-cio2 0"); + cio2_dm.add("ipu3-csi2 1"); + cio2_dm.add("ipu3-cio2 1"); + cio2_dm.add("ipu3-csi2 2"); + cio2_dm.add("ipu3-cio2 2"); + cio2_dm.add("ipu3-csi2 3"); + cio2_dm.add("ipu3-cio2 3"); + + cio2_ = enumerator->search(cio2_dm); + if (!cio2_) + return false; + + cio2_->acquire(); + + DeviceMatch imgu_dm("ipu3-imgu"); + imgu_dm.add("ipu3-imgu 0"); + imgu_dm.add("ipu3-imgu 0 input"); + imgu_dm.add("ipu3-imgu 0 parameters"); + imgu_dm.add("ipu3-imgu 0 output"); + imgu_dm.add("ipu3-imgu 0 viewfinder"); + imgu_dm.add("ipu3-imgu 0 3a stat"); + imgu_dm.add("ipu3-imgu 1"); + imgu_dm.add("ipu3-imgu 1 input"); + imgu_dm.add("ipu3-imgu 1 parameters"); + imgu_dm.add("ipu3-imgu 1 output"); + imgu_dm.add("ipu3-imgu 1 viewfinder"); + imgu_dm.add("ipu3-imgu 1 3a stat"); + + imgu_ = enumerator->search(imgu_dm); + if (!imgu_) { + cio2_->release(); + return false; + } + + imgu_->acquire(); + + /* + * Disable all links that are enabled by default on CIO2, as camera + * creation enables all valid links it finds. + * + * Close the CIO2 media device after, as links are enabled and should + * not need to be changed after. + */ + if (cio2_->open()) { + cio2_->release(); + imgu_->release(); + return false; + } + cio2_->disableLinks(); + + numCameras_ = registerCameras(); + LOG(Debug) << "\"Intel IPU3\" pipeline handler initialized with " + << numCameras_ << " cameras registered"; + + cio2_->close(); + + return true; +} + +/* + * Cameras are created associating an image sensor (represented by a + * media entity with function MEDIA_ENT_F_CAM_SENSOR) to one of the four + * CIO2 CSI-2 receivers. + * + * Cameras are here created and stored in the member field 'cameras_' map, + * indexed by the id of the CSI-2 receiver they are connected, to maintain + * an ordering that does not depend on the device enumeration order. + * + * The function returns the number of cameras found in the system. + */ +unsigned int PipelineHandlerIPU3::registerCameras() +{ + const std::vector entities = cio2_->entities(); + unsigned int numCameras = 0; + struct { + unsigned int id; + MediaEntity *csi2; + } csi2Receivers[] = { + { 0, cio2_->getEntityByName("ipu3-csi2 0") }, + { 1, cio2_->getEntityByName("ipu3-csi2 1") }, + { 2, cio2_->getEntityByName("ipu3-csi2 2") }, + { 3, cio2_->getEntityByName("ipu3-csi2 3") }, + }; + + /* + * For each CSI-2 receiver on the IPU3, create a Camera if an + * image sensor is connected to it. + */ + for (auto csi2Receiver : csi2Receivers) { + MediaEntity *csi2 = csi2Receiver.csi2; + unsigned int id = csi2Receiver.id; + + /* IPU3 CSI-2 receivers have a single sink pad. */ + std::vector pads = csi2->pads(); + MediaPad *sink; + for (MediaPad *pad : pads) { + if (!(pad->flags() & MEDIA_PAD_FL_SINK)) + continue; + + sink = pad; + break; + } + + /* Verify that the receiver is connected to a sensor. */ + std::vector links = sink->links(); + if (links.empty()) + continue; + + /* + * FIXME + * This supports creating a single camera per CSI-2 receiver. + */ + for (MediaLink *link : links) { + MediaEntity *sensor = link->source()->entity(); + if (!sensor) + continue; + + if (sensor->function() != MEDIA_ENT_F_CAM_SENSOR) + continue; + + /* Enable the link between sensor and CSI-2 receiver. */ + if (link->setEnabled(true)) + continue; + + /* Create the camera using the sensor name. */ + std::size_t pos = sensor->name().find(" "); + std::string cameraName = sensor->name().substr(0, pos); + + cameras_[id] = new Camera(cameraName); + + LOG(Debug) << "Registered Camera[" << numCameras + << "] \"" << cameraName << "\"" + << " connected to CSI-2 receiver " << id; + + numCameras++; + break; + } + } + + return numCameras; +} + +REGISTER_PIPELINE_HANDLER(PipelineHandlerIPU3); + +} /* namespace libcamera */ diff --git a/src/libcamera/pipeline/ipu3/meson.build b/src/libcamera/pipeline/ipu3/meson.build new file mode 100644 index 0000000..0ab766a --- /dev/null +++ b/src/libcamera/pipeline/ipu3/meson.build @@ -0,0 +1,3 @@ +libcamera_sources += files([ + 'ipu3.cpp', +]) diff --git a/src/libcamera/pipeline/meson.build b/src/libcamera/pipeline/meson.build index 615ecd2..811c075 100644 --- a/src/libcamera/pipeline/meson.build +++ b/src/libcamera/pipeline/meson.build @@ -1,3 +1,5 @@ libcamera_sources += files([ 'vimc.cpp', ]) + +subdir('ipu3')