From patchwork Mon Oct 5 15:40:31 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Scally X-Patchwork-Id: 28406 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 C5C86C32F4 for ; Mon, 5 Oct 2026 15:40:42 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id BD2D668A8E; Mon, 5 Oct 2026 17:40:40 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="fXMtaH7S"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 03486689D8 for ; Mon, 5 Oct 2026 17:40:37 +0200 (CEST) Received: from [127.0.1.1] (chfd-03-b2-v4wan-176392-cust229.vm15.cable.virginm.net [82.19.20.230]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 5B280227; Mon, 5 Oct 2026 17:38:41 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1791214721; bh=74t+50F/pujto0JB6Rb3TftL1/tQE0qbDX9AxroL5lg=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=fXMtaH7SbuUcpI/xOyFuxpo88TR28uydRru9IBjxlI7R+lccFCXWfdKGu4zWCGpev ycU41aFya6Z3pQw1pVA+oHHw62vk88MO3MOYA9+tS5Qu6Czip8BX7mSGJhxVaX5TgZ /f7WYpX3TxYg1KdKpiGpYVEU/oC6jc+aropRcxxI= From: Daniel Scally Date: Mon, 05 Oct 2026 16:40:31 +0100 Subject: [PATCH v2 3/3] libcamera: v4l2_device: Make setFrameStartEnabled() generic MIME-Version: 1.0 Message-Id: <20261005-v4l2-events-v2-3-e4883190489d@ideasonboard.com> References: <20261005-v4l2-events-v2-0-e4883190489d@ideasonboard.com> In-Reply-To: <20261005-v4l2-events-v2-0-e4883190489d@ideasonboard.com> To: libcamera-devel@lists.libcamera.org Cc: Daniel Scally X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=9567; i=dan.scally@ideasonboard.com; h=from:subject:message-id; bh=74t+50F/pujto0JB6Rb3TftL1/tQE0qbDX9AxroL5lg=; b=owEBbQKS/ZANAwAKAchJV3psRXUyAcsmYgBqw8TzkeJ/uCbmSvf5MUd3uii65MnS64+SexBW+ GKiTDQGX2OJAjMEAAEKAB0WIQQqyuwyDnZdb+mxmm/ISVd6bEV1MgUCasPE8wAKCRDISVd6bEV1 MsT5D/9eYmcggWt+vmtdAcbq+dS/EAbsPScUkF272wyxib4+3/mncX9JSPYu5EtkgrSwkfVuvEW pPZAAR5/A/g34szxzEex2BigDCr8OkQ2PJFW+nUaagGm3mstsFIYPruesA4na4Iv/WXjSCBDc/J C5jexMp4akEJzEAalaZryfzyh2ADxTv+0IAH0ol3kK55cj1cmXsPr82MQH52GZbqNmBL8NnixxM 90Jmrp0hHyN9qviB9zptiQDHt6a0WG0eIt/baRFTydBXqKXZmiAl3XXQFMr09UqlFK1WeboRLcI TKD3hYq3bF65QjV3BEFElJ2ucGh9kj9aUkfhy3oHv2x//7z0cPtrqM2QqXsU9nZO4svBAFVUYaR ihHeFu2MyIQQqFC3/8bqoBcng5rflPmSPKcDrkuZpZZ+rBcS2WmeiDF9KHCmFVBDCUvMxDArc0i X2RO5HLpzQGcORE4U4ijIReIKaGYUB/Ayym4Adlih8iW31B99FvTZrcwVVQv4RNezd4rXx25ZgR +kWULkaK9R5Ggn7KNlQBPNipOKPO3ylPD30CHQ3X3/IUV3h3OxZMrFiC8DewpFL0GX9oj9jYbr7 Xx6KKeC50vdDKLnAYRgpAyOwHzHA8GLLgUkqnqIbrftytuwd63haw9sCVhL5IqSF6YahUgsusPC l7ZqDnK2RIRBQCQ== X-Developer-Key: i=dan.scally@ideasonboard.com; a=openpgp; fpr=EEC699ACA1B7CB5D31330C0BBD501C2A3546CCF6 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" The current implementation of V4L2Device::setFrameStartEnabled hard codes V4L2_EVENT_FRAME_SYNC as it passes the subscription to the kernel. Re-work the function such that the subscription details are parametised. This will allow consumers to subscribe to any supported events. Signed-off-by: Daniel Scally --- Changes in v2: - use kernel uAPI directly instead of class V4L2Event and V4L2EventSubscription --- include/libcamera/internal/v4l2_device.h | 5 ++-- src/libcamera/pipeline/ipu3/cio2.cpp | 9 +++++-- src/libcamera/pipeline/mali-c55/mali-c55.cpp | 10 ++++++-- src/libcamera/pipeline/rkisp1/rkisp1.cpp | 10 +++++--- .../pipeline/rpi/common/pipeline_base.cpp | 8 +++++-- src/libcamera/pipeline/simple/simple.cpp | 8 +++++-- src/libcamera/v4l2_device.cpp | 28 ++++++++++++---------- 7 files changed, 53 insertions(+), 25 deletions(-) diff --git a/include/libcamera/internal/v4l2_device.h b/include/libcamera/internal/v4l2_device.h index 6b77dd46f654e4b95db0327e73164719c47a77d9..124f6cd9e477b8881de8f7c69d304a144a66c67a 100644 --- a/include/libcamera/internal/v4l2_device.h +++ b/include/libcamera/internal/v4l2_device.h @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -47,7 +48,7 @@ public: std::string devicePath() const; bool supportsEvents(v4l2_event_subscription &sub); - int setFrameStartEnabled(bool enable); + int setEventsEnabled(v4l2_event_subscription &sub, bool enable); Signal eventReady; void updateControlInfo(); @@ -90,7 +91,7 @@ private: UniqueFD fd_; std::unique_ptr fdEventNotifier_; - bool frameStartEnabled_; + std::set> subscribedEvents_; }; } /* namespace libcamera */ diff --git a/src/libcamera/pipeline/ipu3/cio2.cpp b/src/libcamera/pipeline/ipu3/cio2.cpp index 7481b2686df070e94fc5f698141db3d3b97896ea..876f78ace06cbc96fb8100cfc4ed76c73de1d449 100644 --- a/src/libcamera/pipeline/ipu3/cio2.cpp +++ b/src/libcamera/pipeline/ipu3/cio2.cpp @@ -356,7 +356,10 @@ int CIO2Device::start() return ret; } - ret = csi2_->setFrameStartEnabled(true); + v4l2_event_subscription sub{}; + sub.type = V4L2_EVENT_FRAME_SYNC; + + ret = csi2_->setEventsEnabled(sub, true); if (ret) { stop(); return ret; @@ -367,9 +370,11 @@ int CIO2Device::start() int CIO2Device::stop() { + v4l2_event_subscription sub{}; int ret; - csi2_->setFrameStartEnabled(false); + sub.type = V4L2_EVENT_FRAME_SYNC; + csi2_->setEventsEnabled(sub, false); ret = output_->streamOff(); diff --git a/src/libcamera/pipeline/mali-c55/mali-c55.cpp b/src/libcamera/pipeline/mali-c55/mali-c55.cpp index da3153ad7fafc133cdde6accb5e3bd54f80520c9..270efb520c53f10cf456ce89a34e8ba40270d560 100644 --- a/src/libcamera/pipeline/mali-c55/mali-c55.cpp +++ b/src/libcamera/pipeline/mali-c55/mali-c55.cpp @@ -1393,7 +1393,10 @@ int PipelineHandlerMaliC55::start(Camera *camera, [[maybe_unused]] const Control return ret; } - ret = isp_->setFrameStartEnabled(true); + v4l2_event_subscription sub{}; + sub.type = V4L2_EVENT_FRAME_SYNC; + + ret = isp_->setEventsEnabled(sub, true); if (ret) LOG(MaliC55, Error) << "Failed to enable frame start events"; @@ -1404,7 +1407,10 @@ void PipelineHandlerMaliC55::stopDevice(Camera *camera) { MaliC55CameraData *data = cameraData(camera); - isp_->setFrameStartEnabled(false); + v4l2_event_subscription sub{}; + sub.type = V4L2_EVENT_FRAME_SYNC; + + isp_->setEventsEnabled(sub, false); if (auto *mem = std::get_if(&data->input_)) { ivc_->streamOff(); diff --git a/src/libcamera/pipeline/rkisp1/rkisp1.cpp b/src/libcamera/pipeline/rkisp1/rkisp1.cpp index e49dd546ee0a5207c75a364564d5673fd8463b30..967f39a9feb6d9d40d0b8df366adbf7d6863458c 100644 --- a/src/libcamera/pipeline/rkisp1/rkisp1.cpp +++ b/src/libcamera/pipeline/rkisp1/rkisp1.cpp @@ -1304,7 +1304,9 @@ int PipelineHandlerRkISP1::start(Camera *camera, [[maybe_unused]] const ControlL return ret; } - isp_->setFrameStartEnabled(true); + v4l2_event_subscription sub{}; + sub.type = V4L2_EVENT_FRAME_SYNC; + isp_->setEventsEnabled(sub, true); activeCamera_ = camera; @@ -1317,7 +1319,9 @@ void PipelineHandlerRkISP1::stopDevice(Camera *camera) RkISP1CameraData *data = cameraData(camera); int ret; - isp_->setFrameStartEnabled(false); + v4l2_event_subscription sub{}; + sub.type = V4L2_EVENT_FRAME_SYNC; + isp_->setEventsEnabled(sub, false); data->ipa_->stop(); @@ -1653,7 +1657,7 @@ void PipelineHandlerRkISP1::imageBufferReady(FrameBuffer *buffer) * Record the sensor's timestamp in the request metadata. * * \todo The sensor timestamp should be better estimated by connecting - * to the V4L2Device::frameStart signal. + * to the V4L2Device::FrameSync signal. */ request->_d()->metadata().set(controls::SensorTimestamp, metadata.timestamp); diff --git a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp index 2315a1c47dc26ed88fa149106a25dcf1ffbc3ec0..cb642967cf315cb8325fab6edb3723831073aec1 100644 --- a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp +++ b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp @@ -702,7 +702,9 @@ int PipelineHandlerBase::start(Camera *camera, const ControlList *controls) data->state_ = CameraData::State::Idle; /* Enable SOF event generation. */ - data->frontendDevice()->setFrameStartEnabled(true); + v4l2_event_subscription sub{}; + sub.type = V4L2_EVENT_FRAME_SYNC; + data->frontendDevice()->setEventsEnabled(sub, true); data->platformStart(); @@ -731,7 +733,9 @@ void PipelineHandlerBase::stopDevice(Camera *camera) } /* Disable SOF event generation. */ - data->frontendDevice()->setFrameStartEnabled(false); + v4l2_event_subscription sub{}; + sub.type = V4L2_EVENT_FRAME_SYNC; + data->frontendDevice()->setEventsEnabled(sub, false); data->clearIncompleteRequests(); diff --git a/src/libcamera/pipeline/simple/simple.cpp b/src/libcamera/pipeline/simple/simple.cpp index 75e068bf516d80af6c8aeeb94bf00ba265744fdd..04f82a55168e7c87f7024a962f85b818347b3236 100644 --- a/src/libcamera/pipeline/simple/simple.cpp +++ b/src/libcamera/pipeline/simple/simple.cpp @@ -1682,7 +1682,9 @@ int SimplePipelineHandler::start(Camera *camera, [[maybe_unused]] const ControlL data->delayedCtrls_->reset(); if (frameStartEmitter) { - ret = frameStartEmitter->setFrameStartEnabled(true); + v4l2_event_subscription sub{}; + sub.type = V4L2_EVENT_FRAME_SYNC; + ret = frameStartEmitter->setEventsEnabled(sub, true); if (ret) { stop(camera); return ret; @@ -1726,7 +1728,9 @@ void SimplePipelineHandler::stopDevice(Camera *camera) V4L2Subdevice *frameStartEmitter = data->frameStartEmitter_; if (frameStartEmitter) { - frameStartEmitter->setFrameStartEnabled(false); + v4l2_event_subscription sub{}; + sub.type = V4L2_EVENT_FRAME_SYNC; + frameStartEmitter->setEventsEnabled(sub, false); frameStartEmitter->eventReady.connect(data, &SimpleCameraData::handleEvent); } diff --git a/src/libcamera/v4l2_device.cpp b/src/libcamera/v4l2_device.cpp index 192edd802a22d3edc7055132eb84ca00e095dd26..03001fbc6ffd906715d195033676e5d5d529f493 100644 --- a/src/libcamera/v4l2_device.cpp +++ b/src/libcamera/v4l2_device.cpp @@ -57,8 +57,7 @@ LOG_DEFINE_CATEGORY(V4L2) * at open() time, and the \a logTag to prefix log messages with. */ V4L2Device::V4L2Device(const std::string &deviceNode) - : deviceNode_(deviceNode), fdEventNotifier_(nullptr), - frameStartEnabled_(false) + : deviceNode_(deviceNode), fdEventNotifier_(nullptr) { } @@ -489,30 +488,35 @@ bool V4L2Device::supportsEvents(v4l2_event_subscription &sub) } /** - * \brief Enable or disable frame start event notification + * \brief Enable or event notifications + * \param[in] sub Details of the event to subscribe to * \param[in] enable True to enable frame start events, false to disable them * - * This function enables or disables generation of frame start events. Once - * enabled, the events are signalled through the eventReady signal. + * This function enables or disables generation of events for a particular + * subscriptions. Once enabled, the events are signalled through the eventReady + * signal. * * \return 0 on success, a negative error code otherwise */ -int V4L2Device::setFrameStartEnabled(bool enable) +int V4L2Device::setEventsEnabled(v4l2_event_subscription &sub, bool enable) { - if (frameStartEnabled_ == enable) - return 0; + std::tuple subTypeId(sub.type, sub.id); - struct v4l2_event_subscription event{}; - event.type = V4L2_EVENT_FRAME_SYNC; + if (subscribedEvents_.contains(subTypeId)) + return 0; unsigned long request = enable ? VIDIOC_SUBSCRIBE_EVENT : VIDIOC_UNSUBSCRIBE_EVENT; - int ret = ioctl(request, &event); + int ret = ioctl(request, &sub); if (enable && ret) return ret; fdEventNotifier_->setEnabled(enable); - frameStartEnabled_ = enable; + + if (enable) + subscribedEvents_.insert(subTypeId); + else + subscribedEvents_.erase(subTypeId); return ret; }