From patchwork Mon Apr 8 12:43:22 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Benjamin GAIGNARD X-Patchwork-Id: 939 Return-Path: Received: from mx07-00178001.pphosted.com (mx08-00178001.pphosted.com [91.207.212.93]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id D73DE60004 for ; Mon, 8 Apr 2019 14:43:31 +0200 (CEST) Received: from pps.filterd (m0046660.ppops.net [127.0.0.1]) by mx08-00178001.pphosted.com (8.16.0.27/8.16.0.27) with SMTP id x38CQruv006785; Mon, 8 Apr 2019 14:43:30 +0200 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=st.com; h=from : to : cc : subject : date : message-id : mime-version : content-type; s=STMicroelectronics; bh=1EBM7zB/Yi2f0fPkXmZBnbof71Dj77xUlyFkYeGOm64=; b=bt+mHUUTdmzvzmrGGPzPlZBNkq53fYO4rzmPKA4GLSXICVAggHDxl7p7mHDO1RoR+o7H r0SvPoXuSdopTKujJnsJbdPcrI3RIJH04yjD5auSO6whz6Ms6p1kE3O3CPvQLHiv6A9a l1TF89iA6W2zxUbFak0KR3uQ4tNX0qWIh5BQdHVq7kaECqKG+UzRQlbtvCZkGeZ1rG4k sQFsnq/ZiXdas69zB5IlGW2hKvaoCb3r0os985eOzkr07z7dKlao6RZ/hjHlmmyI07RA g7i72HbYnLzQg200NubcHvBYq6E2Q4Y6rMgeC5RYq7PwU2gYUDhjL3tlWvHP7YZrDJ8k Ng== Received: from beta.dmz-eu.st.com (beta.dmz-eu.st.com [164.129.1.35]) by mx08-00178001.pphosted.com with ESMTP id 2rprcf32c7-1 (version=TLSv1 cipher=ECDHE-RSA-AES256-SHA bits=256 verify=NOT); Mon, 08 Apr 2019 14:43:30 +0200 Received: from zeta.dmz-eu.st.com (zeta.dmz-eu.st.com [164.129.230.9]) by beta.dmz-eu.st.com (STMicroelectronics) with ESMTP id 1507031; Mon, 8 Apr 2019 12:43:30 +0000 (GMT) Received: from Webmail-eu.st.com (Safex1hubcas23.st.com [10.75.90.46]) by zeta.dmz-eu.st.com (STMicroelectronics) with ESMTP id F0CF626A2; Mon, 8 Apr 2019 12:43:29 +0000 (GMT) Received: from SAFEX1HUBCAS22.st.com (10.75.90.93) by SAFEX1HUBCAS23.st.com (10.75.90.46) with Microsoft SMTP Server (TLS) id 14.3.439.0; Mon, 8 Apr 2019 14:43:29 +0200 Received: from localhost (10.201.20.122) by Webmail-ga.st.com (10.75.90.48) with Microsoft SMTP Server (TLS) id 14.3.361.1; Mon, 8 Apr 2019 14:43:29 +0200 From: Benjamin Gaignard To: CC: , , Benjamin Gaignard Date: Mon, 8 Apr 2019 14:43:22 +0200 Message-ID: <20190408124322.6869-1-benjamin.gaignard@st.com> X-Mailer: git-send-email 2.15.0 MIME-Version: 1.0 X-Originating-IP: [10.201.20.122] X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:, , definitions=2019-04-08_04:, , signatures=0 X-Mailman-Approved-At: Mon, 08 Apr 2019 15:08:57 +0200 Subject: [libcamera-devel] [PATCH] libcamera: pipeline: stm32: add pipeline handler for stm32 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: Mon, 08 Apr 2019 12:43:32 -0000 Provide a pipeline handler for the stm32 driver. Signed-off-by: Benjamin Gaignard --- src/libcamera/pipeline/meson.build | 2 + src/libcamera/pipeline/stm32/meson.build | 3 + src/libcamera/pipeline/stm32/stm32.cpp | 205 +++++++++++++++++++++++++++++++ 3 files changed, 210 insertions(+) create mode 100644 src/libcamera/pipeline/stm32/meson.build create mode 100644 src/libcamera/pipeline/stm32/stm32.cpp diff --git a/src/libcamera/pipeline/meson.build b/src/libcamera/pipeline/meson.build index 40bb264..08d6e1c 100644 --- a/src/libcamera/pipeline/meson.build +++ b/src/libcamera/pipeline/meson.build @@ -4,3 +4,5 @@ libcamera_sources += files([ ]) subdir('ipu3') + +subdir('stm32') diff --git a/src/libcamera/pipeline/stm32/meson.build b/src/libcamera/pipeline/stm32/meson.build new file mode 100644 index 0000000..cb6f16b --- /dev/null +++ b/src/libcamera/pipeline/stm32/meson.build @@ -0,0 +1,3 @@ +libcamera_sources += files([ + 'stm32.cpp', +]) diff --git a/src/libcamera/pipeline/stm32/stm32.cpp b/src/libcamera/pipeline/stm32/stm32.cpp new file mode 100644 index 0000000..301fdfc --- /dev/null +++ b/src/libcamera/pipeline/stm32/stm32.cpp @@ -0,0 +1,205 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * stm32.cpp - Pipeline handler for stm32 devices + */ + +#include +#include +#include + +#include "device_enumerator.h" +#include "log.h" +#include "media_device.h" +#include "pipeline_handler.h" +#include "utils.h" +#include "v4l2_device.h" + +namespace libcamera { + +LOG_DEFINE_CATEGORY(STM32) + +class PipelineHandlerSTM32 : public PipelineHandler { +public: + PipelineHandlerSTM32(CameraManager *manager); + ~PipelineHandlerSTM32(); + + std::map + streamConfiguration(Camera *camera, std::set &streams) override; + int configureStreams( + Camera *camera, std::map &config) override; + + int allocateBuffers(Camera *camera, Stream *stream) override; + int freeBuffers(Camera *camera, Stream *stream) override; + + int start(Camera *camera) override; + void stop(Camera *camera) override; + + int queueRequest(Camera *camera, Request *request) override; + + bool match(DeviceEnumerator *enumerator); + +private: + class STM32CameraData : public CameraData { + public: + STM32CameraData(PipelineHandler *pipe) + : CameraData(pipe), video_(nullptr) {} + + ~STM32CameraData() { delete video_; } + + void bufferReady(Buffer *buffer); + + V4L2Device *video_; + Stream stream_; + }; + + STM32CameraData *cameraData(const Camera *camera) { + return static_cast(PipelineHandler::cameraData(camera)); + } + + std::shared_ptr media_; +}; + +PipelineHandlerSTM32::PipelineHandlerSTM32(CameraManager *manager) + : PipelineHandler(manager), media_(nullptr) {} + +PipelineHandlerSTM32::~PipelineHandlerSTM32() { + if (media_) + media_->release(); +} + +std::map +PipelineHandlerSTM32::streamConfiguration(Camera *camera, + std::set &streams) { + STM32CameraData *data = cameraData(camera); + + std::map configs; + StreamConfiguration config{}; + + LOG(STM32, Debug) << "Retrieving default format"; + config.width = 640; + config.height = 480; + config.pixelFormat = V4L2_PIX_FMT_YUYV; + config.bufferCount = 4; + + configs[&data->stream_] = config; + + return configs; +} + +int PipelineHandlerSTM32::configureStreams( + Camera *camera, std::map &config) { + STM32CameraData *data = cameraData(camera); + StreamConfiguration *cfg = &config[&data->stream_]; + int ret; + + LOG(STM32, Debug) << "Configure the camera for resolution " << cfg->width + << "x" << cfg->height; + + V4L2DeviceFormat format = {}; + format.width = cfg->width; + format.height = cfg->height; + format.fourcc = cfg->pixelFormat; + + ret = data->video_->setFormat(&format); + if (ret) + return ret; + + if (format.width != cfg->width || format.height != cfg->height || + format.fourcc != cfg->pixelFormat) + return -EINVAL; + + return 0; +} + +int PipelineHandlerSTM32::allocateBuffers(Camera *camera, Stream *stream) { + STM32CameraData *data = cameraData(camera); + const StreamConfiguration &cfg = stream->configuration(); + + LOG(STM32, Debug) << "Requesting " << cfg.bufferCount << " buffers"; + + return data->video_->exportBuffers(&stream->bufferPool()); +} + +int PipelineHandlerSTM32::freeBuffers(Camera *camera, Stream *stream) { + STM32CameraData *data = cameraData(camera); + return data->video_->releaseBuffers(); +} + +int PipelineHandlerSTM32::start(Camera *camera) { + STM32CameraData *data = cameraData(camera); + return data->video_->streamOn(); +} + +void PipelineHandlerSTM32::stop(Camera *camera) { + STM32CameraData *data = cameraData(camera); + data->video_->streamOff(); + PipelineHandler::stop(camera); +} + +int PipelineHandlerSTM32::queueRequest(Camera *camera, Request *request) { + STM32CameraData *data = cameraData(camera); + Buffer *buffer = request->findBuffer(&data->stream_); + if (!buffer) { + LOG(STM32, Error) << "Attempt to queue request with invalid stream"; + + return -ENOENT; + } + + int ret = data->video_->queueBuffer(buffer); + if (ret < 0) + return ret; + + PipelineHandler::queueRequest(camera, request); + + return 0; +} + +bool PipelineHandlerSTM32::match(DeviceEnumerator *enumerator) { + DeviceMatch dm("stm32-dcmi"); + + media_ = enumerator->search(dm); + if (!media_) + return false; + + media_->acquire(); + + std::unique_ptr data = + utils::make_unique(this); + + /* Locate and open the default video node. */ + for (MediaEntity *entity : media_->entities()) { + if (entity->flags() & MEDIA_ENT_FL_DEFAULT) { + data->video_ = new V4L2Device(entity); + break; + } + } + + if (!data->video_) { + LOG(STM32, Error) << "Could not find a default video device"; + return false; + } + + if (data->video_->open()) + return false; + + data->video_->bufferReady.connect(data.get(), &STM32CameraData::bufferReady); + + /* Create and register the camera. */ + std::set streams{&data->stream_}; + std::shared_ptr camera = + Camera::create(this, media_->model(), streams); + registerCamera(std::move(camera), std::move(data)); + + return true; +} + +void PipelineHandlerSTM32::STM32CameraData::bufferReady(Buffer *buffer) { + Request *request = queuedRequests_.front(); + + pipe_->completeBuffer(camera_, request, buffer); + pipe_->completeRequest(camera_, request); +} + +REGISTER_PIPELINE_HANDLER(PipelineHandlerSTM32); + +} /* namespace libcamera */