From patchwork Thu Aug 28 13:09:39 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matthias Fend X-Patchwork-Id: 24254 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 31689BD87C for ; Thu, 28 Aug 2025 13:09:52 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id DC597692F8; Thu, 28 Aug 2025 15:09:47 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=emfend.at header.i=@emfend.at header.b="A64Ktvs2"; dkim-atps=neutral Received: from lx20.hoststar.hosting (lx20.hoststar.hosting [168.119.41.54]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 23A9F692E1 for ; Thu, 28 Aug 2025 15:09:44 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=emfend.at; s=mail; h=Cc:To:In-Reply-To:References:Message-Id:Content-Transfer-Encoding: Content-Type:MIME-Version:Subject:Date:From:Sender:Reply-To:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=AAuuYJIjlyUZSTXRpT052wDEQAn2HGC4nOuFufwxx08=; b=A64Ktvs2acqXZJbF950OGr6nOj n1pzHRZ5ouKgHl1qpQ9WlxVntomtMy860TSIs4xBOikaYLYpfW9nmaS7j5NcyOk5SLsUX1VyHk8ks qrzNXkP1Vhxm51JDBH4t9w8NA4TZJ86lk3T2ja5RU+4rnc7A5C97W/LNs34sF/Fs7R+E=; Received: from 194-208-208-245.tele.net ([194.208.208.245]:56023 helo=[127.0.1.1]) by lx20.hoststar.hosting with esmtpsa (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.93) (envelope-from ) id 1urcNq-00BORr-Lt; Thu, 28 Aug 2025 15:09:43 +0200 From: Matthias Fend Date: Thu, 28 Aug 2025 15:09:39 +0200 Subject: [PATCH 2/5] libcamera: Add support for camera flash devices MIME-Version: 1.0 Message-Id: <20250828-flash-support-v1-2-4c5dc674a05b@emfend.at> References: <20250828-flash-support-v1-0-4c5dc674a05b@emfend.at> In-Reply-To: <20250828-flash-support-v1-0-4c5dc674a05b@emfend.at> To: libcamera-devel@lists.libcamera.org Cc: Matthias Fend X-Mailer: b4 0.14.2 X-Spam-Score: -1.0 X-Spam-Bar: - X-Spam-Report: Spam detection software, running on the system "lx20.hoststar.hosting", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see the administrator of that system for details. Content preview: Define a set of controls to control camera flash devices. Signed-off-by: Matthias Fend --- src/libcamera/control_ids_draft.yaml | 69 ++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) Content analysis details: (-1.0 points, 5.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- -1.0 ALL_TRUSTED Passed through trusted hosts only via SMTP 0.0 TVD_RCVD_IP Message was received from an IP address 0.0 Local_hs1_NotHoststar Sender is not from hoststar.ch|de|com 0.0 KAM_DMARC_STATUS Test Rule for DKIM or SPF Failure with Strict Alignment X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Add a class to model camera flash devices. Currently, only v4l2 flash devices are supported. The v4l2 flash devices are implemented similar to the camera lenses. Signed-off-by: Matthias Fend --- include/libcamera/internal/camera_flash.h | 75 ++++++++ include/libcamera/internal/camera_sensor.h | 2 + src/libcamera/camera_flash.cpp | 248 ++++++++++++++++++++++++++ src/libcamera/meson.build | 1 + src/libcamera/sensor/camera_sensor_legacy.cpp | 13 ++ src/libcamera/sensor/camera_sensor_raw.cpp | 13 ++ 6 files changed, 352 insertions(+) diff --git a/include/libcamera/internal/camera_flash.h b/include/libcamera/internal/camera_flash.h new file mode 100644 index 0000000000000000000000000000000000000000..e41afef2ab84852a340a12a012e3994f00cac27a --- /dev/null +++ b/include/libcamera/internal/camera_flash.h @@ -0,0 +1,75 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2025, matthias.fend@emfend.at + * + * Camera flash support + */ +#pragma once + +#include +#include +#include + +#include +#include + +#include + +namespace libcamera { + +class MediaEntity; +class V4L2Subdevice; + +class CameraFlash : protected Loggable +{ +public: + enum Mode { + None, + Flash, + Torch, + }; + + enum StrobeSource { + Software, + External, + }; + + explicit CameraFlash(const MediaEntity *entity); + ~CameraFlash(); + int init(); + Mode getMode() const; + int setMode(Mode mode); + const ControlInfo &getFlashIntensityInfo() const; + int32_t getFlashIntensity() const; + int setFlashIntensity(int32_t intensity); + const ControlInfo &getFlashTimeoutInfo() const; + int32_t getFlashTimeout() const; + int setFlashTimeout(int32_t timeout_us); + StrobeSource getStrobeSource() const; + int setStrobeSource(StrobeSource source); + int startStrobe(); + int stopStrobe(); + const ControlInfo &getTorchIntensityInfo() const; + int32_t getTorchIntensity() const; + int setTorchIntensity(int32_t intensity); + + const std::string &model() const; + const ControlInfoMap &controls() const; + +protected: + std::string logPrefix() const override; + +private: + LIBCAMERA_DISABLE_COPY_AND_MOVE(CameraFlash) + + int32_t getSubdevControl(uint32_t id) const; + int setSubdevControl(uint32_t id, int32_t value); + int validateDriver(); + + const MediaEntity *entity_; + std::unique_ptr subdev_; + std::string model_; + const ControlInfoMap *controlInfoMap_ = nullptr; +}; + +} /* namespace libcamera */ diff --git a/include/libcamera/internal/camera_sensor.h b/include/libcamera/internal/camera_sensor.h index f6ef4df170d43500bc652762e9a575010a6c1cbd..faeecf244c8d42a43eca52ae04813e0c2f80e516 100644 --- a/include/libcamera/internal/camera_sensor.h +++ b/include/libcamera/internal/camera_sensor.h @@ -28,6 +28,7 @@ namespace libcamera { +class CameraFlash; class CameraLens; class MediaEntity; class SensorConfiguration; @@ -48,6 +49,7 @@ public: virtual V4L2Subdevice *device() = 0; virtual CameraLens *focusLens() = 0; + virtual CameraFlash *flash() = 0; virtual const std::vector &mbusCodes() const = 0; virtual std::vector sizes(unsigned int mbusCode) const = 0; diff --git a/src/libcamera/camera_flash.cpp b/src/libcamera/camera_flash.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4702c590c91e0bcb20d173e7ce03608e1ae6ecfd --- /dev/null +++ b/src/libcamera/camera_flash.cpp @@ -0,0 +1,248 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2025, matthias.fend@emfend.at + * + * Camera flash support + */ + +#include "libcamera/internal/camera_flash.h" + +#include + +#include "libcamera/internal/v4l2_subdevice.h" + +namespace libcamera { + +LOG_DEFINE_CATEGORY(CameraFlash) + +CameraFlash::CameraFlash(const MediaEntity *entity) + : entity_(entity) +{ +} + +CameraFlash::~CameraFlash() = default; + +int CameraFlash::init() +{ + if (entity_->function() != MEDIA_ENT_F_FLASH) { + LOG(CameraFlash, Error) + << "Invalid flash function " + << utils::hex(entity_->function()); + return -EINVAL; + } + + subdev_ = std::make_unique(entity_); + int ret = subdev_->open(); + if (ret < 0) + return ret; + + controlInfoMap_ = &subdev_->controls(); + + ret = validateDriver(); + if (ret) + return ret; + + model_ = subdev_->model(); + + return 0; +} + +CameraFlash::Mode CameraFlash::getMode() const +{ + Mode m; + + switch (getSubdevControl(V4L2_CID_FLASH_LED_MODE)) { + case V4L2_FLASH_LED_MODE_FLASH: + m = Flash; + break; + case V4L2_FLASH_LED_MODE_TORCH: + m = Torch; + break; + case V4L2_FLASH_LED_MODE_NONE: + default: + m = None; + break; + } + + return m; +} + +int CameraFlash::setMode(Mode mode) +{ + int32_t m; + + switch (mode) { + case Flash: + m = V4L2_FLASH_LED_MODE_FLASH; + break; + case Torch: + m = V4L2_FLASH_LED_MODE_TORCH; + break; + case None: + m = V4L2_FLASH_LED_MODE_NONE; + break; + default: + return -EINVAL; + } + + return setSubdevControl(V4L2_CID_FLASH_LED_MODE, m); +} + +const ControlInfo &CameraFlash::getFlashIntensityInfo() const +{ + return controlInfoMap_->find(V4L2_CID_FLASH_INTENSITY)->second; +} + +int32_t CameraFlash::getFlashIntensity() const +{ + return getSubdevControl(V4L2_CID_FLASH_INTENSITY); +} + +int CameraFlash::setFlashIntensity(int32_t intensity) +{ + return setSubdevControl(V4L2_CID_FLASH_INTENSITY, intensity); +} + +const ControlInfo &CameraFlash::getFlashTimeoutInfo() const +{ + return controlInfoMap_->find(V4L2_CID_FLASH_TIMEOUT)->second; +} + +int32_t CameraFlash::getFlashTimeout() const +{ + return getSubdevControl(V4L2_CID_FLASH_TIMEOUT); +} + +int CameraFlash::setFlashTimeout(int32_t timeout) +{ + return setSubdevControl(V4L2_CID_FLASH_TIMEOUT, timeout); +} + +CameraFlash::StrobeSource CameraFlash::getStrobeSource() const +{ + StrobeSource s; + + switch (getSubdevControl(V4L2_CID_FLASH_STROBE_SOURCE)) { + case V4L2_FLASH_STROBE_SOURCE_EXTERNAL: + s = External; + break; + case V4L2_FLASH_STROBE_SOURCE_SOFTWARE: + default: + s = Software; + break; + } + + return s; +} + +int CameraFlash::setStrobeSource(StrobeSource source) +{ + int32_t s; + + switch (source) { + case External: + s = V4L2_FLASH_STROBE_SOURCE_EXTERNAL; + break; + case Software: + s = V4L2_FLASH_STROBE_SOURCE_SOFTWARE; + break; + default: + return -EINVAL; + } + + return setSubdevControl(V4L2_CID_FLASH_STROBE_SOURCE, s); +} + +int CameraFlash::startStrobe() +{ + return setSubdevControl(V4L2_CID_FLASH_STROBE, 1); +} + +int CameraFlash::stopStrobe() +{ + return setSubdevControl(V4L2_CID_FLASH_STROBE_STOP, 1); +} + +const ControlInfo &CameraFlash::getTorchIntensityInfo() const +{ + return controlInfoMap_->find(V4L2_CID_FLASH_TORCH_INTENSITY)->second; +} + +int32_t CameraFlash::getTorchIntensity() const +{ + return getSubdevControl(V4L2_CID_FLASH_TORCH_INTENSITY); +} + +int CameraFlash::setTorchIntensity(int32_t intensity) +{ + return setSubdevControl(V4L2_CID_FLASH_TORCH_INTENSITY, intensity); +} + +const std::string &CameraFlash::model() const +{ + return model_; +} + +const ControlInfoMap &CameraFlash::controls() const +{ + return subdev_->controls(); +} + +std::string CameraFlash::logPrefix() const +{ + return "'" + entity_->name() + "'"; +} + +int32_t CameraFlash::getSubdevControl(uint32_t id) const +{ + ControlList controlList = subdev_->getControls(std::vector{ id }); + + return controlList.get(id).get(); +} + +int CameraFlash::setSubdevControl(uint32_t id, int32_t value) +{ + ControlList flashCtrls(subdev_->controls()); + + flashCtrls.set(id, value); + + if (subdev_->setControls(&flashCtrls)) + return -EINVAL; + + return 0; +} + +int CameraFlash::validateDriver() +{ + int ret = 0; + static constexpr uint32_t mandatoryControls[] = { + V4L2_CID_FLASH_LED_MODE, + V4L2_CID_FLASH_STROBE_SOURCE, + V4L2_CID_FLASH_STROBE, + V4L2_CID_FLASH_TIMEOUT, + V4L2_CID_FLASH_INTENSITY, + V4L2_CID_FLASH_TORCH_INTENSITY, + }; + + for (uint32_t ctrl : mandatoryControls) { + if (!controlInfoMap_->count(ctrl)) { + LOG(CameraFlash, Error) + << "Mandatory V4L2 control " << utils::hex(ctrl) + << " not available"; + ret = -EINVAL; + } + } + + if (ret) { + LOG(CameraFlash, Error) + << "The flash kernel driver needs to be fixed"; + LOG(CameraFlash, Error) + << "See Documentation/flash_driver_requirements.rst in" + << " the libcamera sources for more information"; + return ret; + } + + return ret; +} + +} /* namespace libcamera */ diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build index b3ca27f217da4ba3a896ef7cbfb5502fa82a4907..0f125661a51e2431c1febc353cef30a1219f9ce7 100644 --- a/src/libcamera/meson.build +++ b/src/libcamera/meson.build @@ -20,6 +20,7 @@ libcamera_internal_sources = files([ 'bayer_format.cpp', 'byte_stream_buffer.cpp', 'camera_controls.cpp', + 'camera_flash.cpp', 'camera_lens.cpp', 'clock_recovery.cpp', 'control_serializer.cpp', diff --git a/src/libcamera/sensor/camera_sensor_legacy.cpp b/src/libcamera/sensor/camera_sensor_legacy.cpp index f9e685a9acc499fc91d51ed1d66780a0ad2d2a8f..632b66ea0aa15fcd654e7f0efb50c24cb9b973bf 100644 --- a/src/libcamera/sensor/camera_sensor_legacy.cpp +++ b/src/libcamera/sensor/camera_sensor_legacy.cpp @@ -31,6 +31,7 @@ #include #include "libcamera/internal/bayer_format.h" +#include "libcamera/internal/camera_flash.h" #include "libcamera/internal/camera_lens.h" #include "libcamera/internal/camera_sensor.h" #include "libcamera/internal/camera_sensor_properties.h" @@ -68,6 +69,7 @@ public: V4L2Subdevice *device() override { return subdev_.get(); } CameraLens *focusLens() override { return focusLens_.get(); } + CameraFlash *flash() override { return flash_.get(); } const std::vector &mbusCodes() const override { return mbusCodes_; } std::vector sizes(unsigned int mbusCode) const override; @@ -139,6 +141,7 @@ private: ControlList properties_; std::unique_ptr focusLens_; + std::unique_ptr flash_; }; /** @@ -665,6 +668,16 @@ int CameraSensorLegacy::discoverAncillaryDevices() } break; + case MEDIA_ENT_F_FLASH: + flash_ = std::make_unique(ancillary); + ret = flash_->init(); + if (ret) { + LOG(CameraSensor, Error) + << "Flash initialisation failed, flash disabled"; + flash_.reset(); + } + break; + default: LOG(CameraSensor, Warning) << "Unsupported ancillary entity function " diff --git a/src/libcamera/sensor/camera_sensor_raw.cpp b/src/libcamera/sensor/camera_sensor_raw.cpp index 8ea4423698cd8c1eaae43eb5ba8b5d524b94d515..9d533d814b9df453aa4009a87818c1558bcbd665 100644 --- a/src/libcamera/sensor/camera_sensor_raw.cpp +++ b/src/libcamera/sensor/camera_sensor_raw.cpp @@ -32,6 +32,7 @@ #include #include "libcamera/internal/bayer_format.h" +#include "libcamera/internal/camera_flash.h" #include "libcamera/internal/camera_lens.h" #include "libcamera/internal/camera_sensor.h" #include "libcamera/internal/camera_sensor_properties.h" @@ -69,6 +70,7 @@ public: V4L2Subdevice *device() override { return subdev_.get(); } CameraLens *focusLens() override { return focusLens_.get(); } + CameraFlash *flash() override { return flash_.get(); } const std::vector &mbusCodes() const override { return mbusCodes_; } std::vector sizes(unsigned int mbusCode) const override; @@ -150,6 +152,7 @@ private: ControlList properties_; std::unique_ptr focusLens_; + std::unique_ptr flash_; }; /** @@ -513,6 +516,16 @@ std::optional CameraSensorRaw::init() } break; + case MEDIA_ENT_F_FLASH: + flash_ = std::make_unique(ancillary); + ret = flash_->init(); + if (ret) { + LOG(CameraSensor, Error) + << "Flash initialisation failed, flash disabled"; + flash_.reset(); + } + break; + default: LOG(CameraSensor, Warning) << "Unsupported ancillary entity function "