From patchwork Fri Oct 16 06:16:02 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Prasanth R X-Patchwork-Id: 28471 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 329BBC3305 for ; Fri, 16 Oct 2026 10:19:34 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 109B668E25; Fri, 16 Oct 2026 12:19:32 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="ey5m+p/q"; dkim-atps=neutral Received: from mail-pj1-x102d.google.com (mail-pj1-x102d.google.com [IPv6:2607:f8b0:4864:20::102d]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 37C6568E14 for ; Fri, 16 Oct 2026 08:16:19 +0200 (CEST) Received: by mail-pj1-x102d.google.com with SMTP id 98e67ed59e1d1-398b3c37877so3098380a91.0 for ; Thu, 15 Oct 2026 23:16:19 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1792131377; x=1792736177; darn=lists.libcamera.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=R52/8bWNk45kvwe+COuY2AaASRLedHfjMpOGtTN2Zww=; b=ey5m+p/qIu2rfM1pXn4l20OLmSUukxHwxoL3R4lpa9n+MhDGdhz8VtlAk7N+X+VOIa 2nSwfKM3Kbp3lgsqDrPAIHw0KrPGVNXN9do4DUkRdxhuPxiaS9PHa2u661DpOneO0aTn d6cEqyM2QEjPnFKz249Y9YIebQJVUYoysehangJimZIhXb7TLpcsv0r1n6ghylnmyGDv ACjl0CdprLcLRtUNzCrb1yjdcfw3Hznkul3gBKYqDK8tqIH9PgPRMCoqyCtrjJqhVI50 Fxx2S34dkG43JjO4oSnCXGPR41Dr1GlH8V+e1l3VquflWJ4yeft70zXOYV93Xjo3vXOY kCrw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1792131377; x=1792736177; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=R52/8bWNk45kvwe+COuY2AaASRLedHfjMpOGtTN2Zww=; b=YMFN9LjkeUb9wLnjNgQXh0ieRXL6bXZ3zWL7wneFUmxInIKE/+mAcaga9DtUfJo26W TBVmjs0ozOAOki7DUhLyaGroQ61qNjlj18I0ObCmg81BJLONIVVMfyPqCT7ksImls/2U gHM4l5NjJuJ2oeZrBdiOU6+xQN+b549BtCWACLKciOKEJbVirmA3OEP6H9KqTpQyvHeS j3rQ8is9ljXzaN3JC/iJWKBWw3+YVI0SriXaXTuSv3s8WhmAkGmCtlZBFrbuu7RZhOod qgzvMrONNQ1HJI41IXWiy6WbfbvPSmjUGdhZzjVi80Xg4B5//gshZWYXTZNet7SMVqyG OOKQ== X-Gm-Message-State: AFq9FYIfTtmpPxZURgPrwBaY3MiSYgRTagR2ea9kF9xTxWv7PfwjEc3O QP45Nm8xG+xMYSGwowSZc0tR68GoJv2z6zNCkKj0jKs2fM5s8OvfsXMO2+qlSrM5 X-Gm-Gg: AYBFou2t2pQVoUAECG5aUD8JRJHxqkD34Ur3/8TnHJDsCGEJQqsEB/E82LzSnM/r2P3 KpiJV4QOy98swa3p0VijY/+nl51HgvBG45yOsa3uSp25+xbzpUQpYVQMgLLLlcUjLlF0jA5O4NL i5wA6c0X7SrXJdCHKttuTNV/fUBOU4bKwtErDqdgjmqwDIH+0Lr1cknGCKwJRZuck+Lzfyligi8 zCDIE2Ug8X3ryRJuXIlaHBeWKDlPYln8hegtB0qcyNAAzXk2bg99EOP3SPAR7ZKrtx+2vyE4I1C pLYN8CXXjgKmCBIH3zLh18qWKLLW7m+nYwMKHKuxAKw60o0fwdqUUM6S+zXTmUg3PsWMRW2zSu6 Y+j7lEokSW58iA+3OCwIS5FElLSZepJS1gpbqhsZ/xA3E3h6t9p2ta8sxEmrQ8B+M5regWzO7dk E0qoYbS6Gmh6v8HEP9PLB2GZpqcUGiUxETQ46DYlJaNFEWH5hdpONwMAXc9gGFz2CSEBgvUjdVw w2XwiBQmpcHhrPLvQkcUkV4xkJE3vOc9A== X-Received: by 2002:a17:90a:fc50:b0:3ac:a203:e0ab with SMTP id 98e67ed59e1d1-3aca203e3a4mr3492009a91.48.1792131377371; Thu, 15 Oct 2026 23:16:17 -0700 (PDT) Received: from prasanth.alps.lineo.co.jp (vpn1.lineo.co.jp. [203.141.200.204]) by smtp.gmail.com with ESMTPSA id 98e67ed59e1d1-3acd0aa3c24sm962605a91.4.2026.10.15.23.16.15 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 15 Oct 2026 23:16:16 -0700 (PDT) From: Prasanth R To: libcamera-devel@lists.libcamera.org Cc: paul.elder@ideasonboard.com, kieran.bingham@ideasonboard.com, barnabas.pocze@ideasonboard.com, Prasanth R Subject: [PATCH] v4l2: v4l2_camera_proxy: Handle 64-bit time_t buffer ioctls Date: Fri, 16 Oct 2026 15:16:02 +0900 Message-Id: <20261016061602.1710285-1-ragaprasanth@gmail.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20260122121015.3842322-1-paul.elder@ideasonboard.com> References: <20260122121015.3842322-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 X-Mailman-Approved-At: Fri, 16 Oct 2026 12:19:30 +0200 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" On 32-bit platforms the V4L2 compatibility layer is built with a 32-bit time_t, but applications are now usually built with _TIME_BITS=64. struct v4l2_buffer embeds a struct timeval, so for them it grows from 68 to 80 bytes on 32-bit Arm, and VIDIOC_QUERYBUF, VIDIOC_QBUF, VIDIOC_DQBUF and VIDIOC_PREPARE_BUF get different request numbers. These fail with ENOTTY and streaming does not work. Recognise the 64-bit time_t requests and convert the buffer to and from the native layout around the existing handlers. Only the timestamp differs between the two layouts. Buffer timestamps are monotonic, so they fit in the native timeval. Nothing changes where both layouts are the same. Closes: https://gitlab.freedesktop.org/camera/libcamera/-/issues/290 Signed-off-by: Prasanth R --- This applies on top of Paul's "v4l2: v4l2_compat: Handle __ioctl_time64" (https://patchwork.libcamera.org/patch/25925/), which is needed for the ioctls to reach the proxy at all. Tested on a Raspberry Pi 4 with a 32-bit, 64-bit time_t userspace (Yocto) and a UVC camera, libcamera v0.4.0 with both patches: libcamerify v4l2-ctl --stream-mmap --stream-count=30 streams at 15 fps, 5/5 runs; without this patch VIDIOC_QUERYBUF fails with ENOTTY. src/v4l2/v4l2_camera_proxy.cpp | 76 ++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/src/v4l2/v4l2_camera_proxy.cpp b/src/v4l2/v4l2_camera_proxy.cpp index 559ffc617..554e81f8d 100644 --- a/src/v4l2/v4l2_camera_proxy.cpp +++ b/src/v4l2/v4l2_camera_proxy.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -39,6 +40,64 @@ using namespace std::literals::chrono_literals; LOG_DECLARE_CATEGORY(V4L2Compat) +namespace { + +/* + * On 32-bit platforms the V4L2 compatibility layer is built with a 32-bit + * time_t (see src/v4l2/meson.build), while applications are commonly built + * with _TIME_BITS=64. struct v4l2_buffer embeds a struct timeval, so the two + * disagree on the structure size, and thus on the buffer ioctl numbers. Only + * the timestamp differs, the fields before and after it are the same. + */ +struct v4l2_buffer_time64 { + __u8 head[offsetof(struct v4l2_buffer, timestamp)]; + struct { + long long tv_sec; + long long tv_usec; + } timestamp; + __u8 tail[sizeof(struct v4l2_buffer) - offsetof(struct v4l2_buffer, timecode)]; +}; + +/* + * Return the native request for a 64-bit time_t buffer ioctl, or 0 if the + * request is not one or both layouts are the same. + */ +unsigned int bufferRequestFromTime64(unsigned int request) +{ + if (sizeof(struct v4l2_buffer_time64) == sizeof(struct v4l2_buffer)) + return 0; + + switch (request) { + case _IOWR('V', 9, struct v4l2_buffer_time64): /* VIDIOC_QUERYBUF */ + case _IOWR('V', 15, struct v4l2_buffer_time64): /* VIDIOC_QBUF */ + case _IOWR('V', 17, struct v4l2_buffer_time64): /* VIDIOC_DQBUF */ + case _IOWR('V', 93, struct v4l2_buffer_time64): /* VIDIOC_PREPARE_BUF */ + return _IOWR('V', _IOC_NR(request), struct v4l2_buffer); + default: + return 0; + } +} + +void bufferFromTime64(const struct v4l2_buffer_time64 &src, + struct v4l2_buffer *dst) +{ + memcpy(dst, src.head, sizeof(src.head)); + dst->timestamp.tv_sec = src.timestamp.tv_sec; + dst->timestamp.tv_usec = src.timestamp.tv_usec; + memcpy(&dst->timecode, src.tail, sizeof(src.tail)); +} + +void bufferToTime64(const struct v4l2_buffer &src, + struct v4l2_buffer_time64 *dst) +{ + memcpy(dst->head, &src, sizeof(dst->head)); + dst->timestamp.tv_sec = src.timestamp.tv_sec; + dst->timestamp.tv_usec = src.timestamp.tv_usec; + memcpy(dst->tail, &src.timecode, sizeof(dst->tail)); +} + +} /* namespace */ + V4L2CameraProxy::V4L2CameraProxy(unsigned int index, std::shared_ptr camera) : refcount_(0), index_(index), bufferCount_(0), currentBuf_(0), @@ -873,6 +932,20 @@ int V4L2CameraProxy::ioctl(V4L2CameraFile *file, unsigned long longRequest, void return -1; } + /* + * Translate buffer ioctls from applications built with a 64-bit + * time_t to the native struct v4l2_buffer layout. + */ + struct v4l2_buffer_time64 *buf64 = nullptr; + struct v4l2_buffer buf = {}; + unsigned int bufRequest = bufferRequestFromTime64(request); + if (bufRequest) { + buf64 = static_cast(arg); + bufferFromTime64(*buf64, &buf); + request = bufRequest; + arg = &buf; + } + if (supportedIoctls_.find(request) == supportedIoctls_.end()) { errno = ENOTTY; return -1; @@ -955,6 +1028,9 @@ int V4L2CameraProxy::ioctl(V4L2CameraFile *file, unsigned long longRequest, void return -1; } + if (buf64) + bufferToTime64(buf, buf64); + return ret; }