From patchwork Fri Apr 19 09:03:45 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Benjamin GAIGNARD X-Patchwork-Id: 1072 Return-Path: Received: from mx07-00178001.pphosted.com (mx07-00178001.pphosted.com [62.209.51.94]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id C7EDF60DB4 for ; Fri, 19 Apr 2019 11:03:56 +0200 (CEST) Received: from pps.filterd (m0046037.ppops.net [127.0.0.1]) by mx07-00178001.pphosted.com (8.16.0.27/8.16.0.27) with SMTP id x3J925oO020881; Fri, 19 Apr 2019 11:03:55 +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=nMV5JEjXpEQkeRj/istr/ArTazeVQlFmzDP39fjfWh0=; b=IopJJkuKySGlJSJlxjzhkPUm7gmAxpjtnGQSMpOTRkd6In0X4uzpHw0veKJjghWly6YS ktBJzeYjtjyEjjoM0xN6HExoW9n6lO0i18L2KQaWg2aJbMJevGNkRHBZAshJM9fnSSXc JaX460tfjUFeTyuYLU38i6KdmS5CaG7Ij+ChW30/q1iiK+CZEasmqkONg/7sUo3SynRk n95y+GHFc8i6rw7X9gifRFnLqRjufhUqdz4wCoPUH0beJE8C7gOKoU8OAi/ZnAM7KZqB 5h1kIwEQVtyMzfoZBCm/Ie+DVtypSw9WzWCGu3gENZbkwu/9IqbYy/u85tI7EOwVQOdO ng== Received: from beta.dmz-eu.st.com (beta.dmz-eu.st.com [164.129.1.35]) by mx07-00178001.pphosted.com with ESMTP id 2rxrt6p1c3-1 (version=TLSv1 cipher=ECDHE-RSA-AES256-SHA bits=256 verify=NOT); Fri, 19 Apr 2019 11:03:55 +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 3CE803D; Fri, 19 Apr 2019 09:03:55 +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 24C8015C0; Fri, 19 Apr 2019 09:03:55 +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; Fri, 19 Apr 2019 11:03:55 +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; Fri, 19 Apr 2019 11:03:54 +0200 From: Benjamin Gaignard To: CC: , , Benjamin Gaignard Date: Fri, 19 Apr 2019 11:03:45 +0200 Message-ID: <20190419090345.18136-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-19_05:, , signatures=0 Subject: [libcamera-devel] [PATCH v2] 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: Fri, 19 Apr 2019 09:03:57 -0000 Provide a pipeline handler for the stm32 driver. Signed-off-by: Benjamin Gaignard --- version 2: - fix indentation and run checkstyle: ./utils/checkstyle.py --------------------------------------------------------------------------------------------------- 9360626c2158b2c5d865608f4504d203b6d0014f libcamera: pipeline: stm32: add pipeline handler for stm32 --------------------------------------------------------------------------------------------------- No style issue detected - Use the first video node instead of using MEDIA_ENT_FL_DEFAULT flag src/libcamera/pipeline/meson.build | 2 + src/libcamera/pipeline/stm32/meson.build | 3 + src/libcamera/pipeline/stm32/stm32.cpp | 220 +++++++++++++++++++++++++++++++ 3 files changed, 225 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..15c7764 --- /dev/null +++ b/src/libcamera/pipeline/stm32/stm32.cpp @@ -0,0 +1,220 @@ +/* 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); + + /* Open the first video node */ + MediaEntity *entity = media_->entities()[0]; + if (!entity) { + LOG(STM32, Error) << "No video node"; + return false; + } + + data->video_ = new V4L2Device(entity); + 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 */