From patchwork Tue Oct 8 09:11:14 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Boris Brezillon X-Patchwork-Id: 11179203 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id BAE8717D4 for ; Tue, 8 Oct 2019 09:11:31 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 93C5421721 for ; Tue, 8 Oct 2019 09:11:31 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729986AbfJHJLa (ORCPT ); Tue, 8 Oct 2019 05:11:30 -0400 Received: from bhuna.collabora.co.uk ([46.235.227.227]:42842 "EHLO bhuna.collabora.co.uk" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729440AbfJHJL3 (ORCPT ); Tue, 8 Oct 2019 05:11:29 -0400 Received: from localhost.localdomain (unknown [IPv6:2a01:e0a:2c:6930:5cf4:84a1:2763:fe0d]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) (Authenticated sender: bbrezillon) by bhuna.collabora.co.uk (Postfix) with ESMTPSA id BEA6D28F7F6; Tue, 8 Oct 2019 10:11:24 +0100 (BST) From: Boris Brezillon To: Mauro Carvalho Chehab , Hans Verkuil , Laurent Pinchart , Sakari Ailus , linux-media@vger.kernel.org Cc: Tomasz Figa , Hirokazu Honda , Nicolas Dufresne , Brian Starkey , kernel@collabora.com, Boris Brezillon Subject: [RFC PATCH v3 1/6] media: v4l2: Extend pixel formats to unify single/multi-planar handling (and more) Date: Tue, 8 Oct 2019 11:11:14 +0200 Message-Id: <20191008091119.7294-2-boris.brezillon@collabora.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20191008091119.7294-1-boris.brezillon@collabora.com> References: <20191008091119.7294-1-boris.brezillon@collabora.com> MIME-Version: 1.0 Sender: linux-media-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org This is part of the multiplanar and singleplanar unification process. v4l2_ext_pix_format is supposed to work for both cases. We also add the concept of modifiers already employed in DRM to expose HW-specific formats (like tiled or compressed formats) and allow exchanging this information with the DRM subsystem in a consistent way. Note that V4L2_BUF_TYPE_VIDEO[_OUTPUT]_OVERLAY and V4L2_BUF_TYPE_VIDEO_{CAPTURE,OUTPUT}_MPLANE types are no longer accepted in v4l2_ext_format and will be rejected if you use the {G,S,TRY}EXT_FMT ioctls. V4L2_BUF_TYPE_VIDEO_{CAPTURE,OUTPUT}_MPLANE is dropped as part of the multiplanar/singleplanar unification. V4L2_BUF_TYPE_VIDEO[_OUTPUT]_OVERLAY seems to be used mostly on old drivers and supporting it would require some extra rework. New hooks have been added to v4l2_ioctl_ops to support those new ioctls in drivers, but, in the meantime, the core takes care of converting {S,G,TRY}_EXT_FMT requests into {S,G,TRY}_FMT so that old drivers can still work if the userspace app/lib uses the new ioctls. The conversion is also done the other around to allow userspace apps/libs using {S,G,TRY}_FMT to work with drivers implementing the _ext_ hooks. Signed-off-by: Boris Brezillon --- Changes in v3: - Rebased on top of media/master (post 5.4-rc1) Changes in v2: - Move the modifier in v4l2_ext_format (was formerly placed in v4l2_ext_plane) - Fix a few bugs in the converters and add a strict parameter to allow conversion of uninitialized/mis-initialized objects --- drivers/media/v4l2-core/v4l2-dev.c | 24 +- drivers/media/v4l2-core/v4l2-ioctl.c | 699 ++++++++++++++++++++++++--- include/media/v4l2-ioctl.h | 33 ++ include/uapi/linux/videodev2.h | 81 ++++ 4 files changed, 754 insertions(+), 83 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c index 4037689a945a..9aad715537b3 100644 --- a/drivers/media/v4l2-core/v4l2-dev.c +++ b/drivers/media/v4l2-core/v4l2-dev.c @@ -595,32 +595,44 @@ static void determine_valid_ioctls(struct video_device *vdev) ops->vidioc_enum_fmt_meta_out))) set_bit(_IOC_NR(VIDIOC_ENUM_FMT), valid_ioctls); if ((is_rx && (ops->vidioc_g_fmt_vid_cap || + ops->vidioc_g_ext_fmt_vid_cap || ops->vidioc_g_fmt_vid_cap_mplane || ops->vidioc_g_fmt_vid_overlay || ops->vidioc_g_fmt_meta_cap)) || (is_tx && (ops->vidioc_g_fmt_vid_out || + ops->vidioc_g_ext_fmt_vid_out || ops->vidioc_g_fmt_vid_out_mplane || ops->vidioc_g_fmt_vid_out_overlay || - ops->vidioc_g_fmt_meta_out))) - set_bit(_IOC_NR(VIDIOC_G_FMT), valid_ioctls); + ops->vidioc_g_fmt_meta_out))) { + set_bit(_IOC_NR(VIDIOC_G_FMT), valid_ioctls); + set_bit(_IOC_NR(VIDIOC_G_EXT_FMT), valid_ioctls); + } if ((is_rx && (ops->vidioc_s_fmt_vid_cap || + ops->vidioc_s_ext_fmt_vid_cap || ops->vidioc_s_fmt_vid_cap_mplane || ops->vidioc_s_fmt_vid_overlay || ops->vidioc_s_fmt_meta_cap)) || (is_tx && (ops->vidioc_s_fmt_vid_out || + ops->vidioc_s_ext_fmt_vid_out || ops->vidioc_s_fmt_vid_out_mplane || ops->vidioc_s_fmt_vid_out_overlay || - ops->vidioc_s_fmt_meta_out))) - set_bit(_IOC_NR(VIDIOC_S_FMT), valid_ioctls); + ops->vidioc_s_fmt_meta_out))) { + set_bit(_IOC_NR(VIDIOC_S_FMT), valid_ioctls); + set_bit(_IOC_NR(VIDIOC_S_EXT_FMT), valid_ioctls); + } if ((is_rx && (ops->vidioc_try_fmt_vid_cap || + ops->vidioc_try_ext_fmt_vid_cap || ops->vidioc_try_fmt_vid_cap_mplane || ops->vidioc_try_fmt_vid_overlay || ops->vidioc_try_fmt_meta_cap)) || (is_tx && (ops->vidioc_try_fmt_vid_out || + ops->vidioc_try_ext_fmt_vid_out || ops->vidioc_try_fmt_vid_out_mplane || ops->vidioc_try_fmt_vid_out_overlay || - ops->vidioc_try_fmt_meta_out))) - set_bit(_IOC_NR(VIDIOC_TRY_FMT), valid_ioctls); + ops->vidioc_try_fmt_meta_out))) { + set_bit(_IOC_NR(VIDIOC_TRY_FMT), valid_ioctls); + set_bit(_IOC_NR(VIDIOC_TRY_EXT_FMT), valid_ioctls); + } SET_VALID_IOCTL(ops, VIDIOC_OVERLAY, vidioc_overlay); SET_VALID_IOCTL(ops, VIDIOC_G_FBUF, vidioc_g_fbuf); SET_VALID_IOCTL(ops, VIDIOC_S_FBUF, vidioc_s_fbuf); diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index 51b912743f0f..78e14c1dc76f 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -377,6 +377,82 @@ static void v4l_print_format(const void *arg, bool write_only) } } +static void v4l_print_ext_format(const void *arg, bool write_only) +{ + const struct v4l2_ext_format *p = arg; + const struct v4l2_ext_pix_format *pix; + const struct v4l2_vbi_format *vbi; + const struct v4l2_sliced_vbi_format *sliced; + const struct v4l2_sdr_format *sdr; + const struct v4l2_meta_format *meta; + unsigned int i; + u32 planes; + + pr_cont("type=%s", prt_names(p->type, v4l2_type_names)); + switch (p->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + pix = &p->fmt.pix; + pr_cont(", width=%u, height=%u, format=%c%c%c%c, modifier %llx, field=%s, colorspace=%d, num_planes=%u, flags=0x%x, ycbcr_enc=%u, quantization=%u, xfer_func=%u\n", + pix->width, pix->height, + (pix->pixelformat & 0xff), + (pix->pixelformat >> 8) & 0xff, + (pix->pixelformat >> 16) & 0xff, + (pix->pixelformat >> 24) & 0xff, + pix->modifier, prt_names(pix->field, v4l2_field_names), + pix->colorspace, pix->num_planes, pix->flags, + pix->ycbcr_enc, pix->quantization, pix->xfer_func); + planes = min_t(u32, pix->num_planes, VIDEO_MAX_PLANES); + for (i = 0; i < planes; i++) + pr_debug("plane %u: bytesperline=%u sizeimage=%u\n", + i, pix->plane_fmt[i].bytesperline, + pix->plane_fmt[i].sizeimage); + break; + case V4L2_BUF_TYPE_VBI_CAPTURE: + case V4L2_BUF_TYPE_VBI_OUTPUT: + vbi = &p->fmt.vbi; + pr_cont(", sampling_rate=%u, offset=%u, samples_per_line=%u, sample_format=%c%c%c%c, start=%u,%u, count=%u,%u\n", + vbi->sampling_rate, vbi->offset, + vbi->samples_per_line, + (vbi->sample_format & 0xff), + (vbi->sample_format >> 8) & 0xff, + (vbi->sample_format >> 16) & 0xff, + (vbi->sample_format >> 24) & 0xff, + vbi->start[0], vbi->start[1], + vbi->count[0], vbi->count[1]); + break; + case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: + case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: + sliced = &p->fmt.sliced; + pr_cont(", service_set=0x%08x, io_size=%d\n", + sliced->service_set, sliced->io_size); + for (i = 0; i < 24; i++) + pr_debug("line[%02u]=0x%04x, 0x%04x\n", i, + sliced->service_lines[0][i], + sliced->service_lines[1][i]); + break; + case V4L2_BUF_TYPE_SDR_CAPTURE: + case V4L2_BUF_TYPE_SDR_OUTPUT: + sdr = &p->fmt.sdr; + pr_cont(", pixelformat=%c%c%c%c\n", + (sdr->pixelformat >> 0) & 0xff, + (sdr->pixelformat >> 8) & 0xff, + (sdr->pixelformat >> 16) & 0xff, + (sdr->pixelformat >> 24) & 0xff); + break; + case V4L2_BUF_TYPE_META_CAPTURE: + case V4L2_BUF_TYPE_META_OUTPUT: + meta = &p->fmt.meta; + pr_cont(", dataformat=%c%c%c%c, buffersize=%u\n", + (meta->dataformat >> 0) & 0xff, + (meta->dataformat >> 8) & 0xff, + (meta->dataformat >> 16) & 0xff, + (meta->dataformat >> 24) & 0xff, + meta->buffersize); + break; + } +} + static void v4l_print_framebuffer(const void *arg, bool write_only) { const struct v4l2_framebuffer *p = arg; @@ -947,11 +1023,15 @@ static int check_fmt(struct file *file, enum v4l2_buf_type type) switch (type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: if ((is_vid || is_tch) && is_rx && - (ops->vidioc_g_fmt_vid_cap || ops->vidioc_g_fmt_vid_cap_mplane)) + (ops->vidioc_g_fmt_vid_cap || + ops->vidioc_g_ext_fmt_vid_cap || + ops->vidioc_g_fmt_vid_cap_mplane)) return 0; break; case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - if (is_vid && is_rx && ops->vidioc_g_fmt_vid_cap_mplane) + if (is_vid && is_rx && + (ops->vidioc_g_fmt_vid_cap_mplane || + ops->vidioc_g_ext_fmt_vid_cap)) return 0; break; case V4L2_BUF_TYPE_VIDEO_OVERLAY: @@ -960,11 +1040,15 @@ static int check_fmt(struct file *file, enum v4l2_buf_type type) break; case V4L2_BUF_TYPE_VIDEO_OUTPUT: if (is_vid && is_tx && - (ops->vidioc_g_fmt_vid_out || ops->vidioc_g_fmt_vid_out_mplane)) + (ops->vidioc_g_fmt_vid_out || + ops->vidioc_g_ext_fmt_vid_out || + ops->vidioc_g_fmt_vid_out_mplane)) return 0; break; case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - if (is_vid && is_tx && ops->vidioc_g_fmt_vid_out_mplane) + if (is_vid && is_tx && + (ops->vidioc_g_ext_fmt_vid_out || + ops->vidioc_g_fmt_vid_out_mplane)) return 0; break; case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: @@ -1044,6 +1128,197 @@ static void v4l_sanitize_format(struct v4l2_format *fmt) sizeof(fmt->fmt.pix) - offset); } +int v4l2_ext_format_to_format(const struct v4l2_ext_format *e, + struct v4l2_format *f, bool mplane_cap, + bool strict) +{ + const struct v4l2_plane_ext_pix_format *pe; + struct v4l2_plane_pix_format *p; + unsigned int i; + + memset(f, 0, sizeof(*f)); + + switch (e->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + /* + * Make sure no modifier is required before doing the + * conversion. + */ + if (e->fmt.pix.modifier && strict) + return -EINVAL; + + if ((e->fmt.pix.num_planes > VIDEO_MAX_PLANES || + !e->fmt.pix.num_planes) && strict) + return -EINVAL; + + if (e->fmt.pix.num_planes > 1 && !mplane_cap && strict) + return -EINVAL; + + if (!mplane_cap) { + f->fmt.pix.width = e->fmt.pix.width; + f->fmt.pix.height = e->fmt.pix.height; + f->fmt.pix.pixelformat = e->fmt.pix.pixelformat; + f->fmt.pix.field = e->fmt.pix.field; + f->fmt.pix.colorspace = e->fmt.pix.colorspace; + f->fmt.pix.flags = e->fmt.pix.flags; + f->fmt.pix.ycbcr_enc = e->fmt.pix.ycbcr_enc; + f->fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC; + f->fmt.pix.quantization = e->fmt.pix.quantization; + pe = &e->fmt.pix.plane_fmt[0]; + f->fmt.pix.bytesperline = pe->bytesperline; + f->fmt.pix.sizeimage = pe->sizeimage; + f->type = e->type; + break; + } + + f->fmt.pix_mp.width = e->fmt.pix.width; + f->fmt.pix_mp.height = e->fmt.pix.height; + f->fmt.pix_mp.pixelformat = e->fmt.pix.pixelformat; + f->fmt.pix_mp.field = e->fmt.pix.field; + f->fmt.pix_mp.colorspace = e->fmt.pix.colorspace; + f->fmt.pix_mp.flags = e->fmt.pix.flags; + f->fmt.pix_mp.ycbcr_enc = e->fmt.pix.ycbcr_enc; + f->fmt.pix_mp.quantization = e->fmt.pix.quantization; + if (e->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + else + f->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + + for (i = 0; i < VIDEO_MAX_PLANES; i++) { + pe = &e->fmt.pix.plane_fmt[i]; + p = &f->fmt.pix_mp.plane_fmt[i]; + p->bytesperline = pe->bytesperline; + p->sizeimage = pe->sizeimage; + } + break; + + case V4L2_BUF_TYPE_VBI_CAPTURE: + case V4L2_BUF_TYPE_VBI_OUTPUT: + f->type = e->type; + f->fmt.vbi = e->fmt.vbi; + break; + + case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: + case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: + f->type = e->type; + f->fmt.sliced = e->fmt.sliced; + break; + + case V4L2_BUF_TYPE_SDR_CAPTURE: + case V4L2_BUF_TYPE_SDR_OUTPUT: + f->type = e->type; + f->fmt.sdr = e->fmt.sdr; + break; + + case V4L2_BUF_TYPE_META_CAPTURE: + case V4L2_BUF_TYPE_META_OUTPUT: + f->type = e->type; + f->fmt.meta = e->fmt.meta; + break; + + default: + return -EINVAL; + } + + return 0; +} +EXPORT_SYMBOL_GPL(v4l2_ext_format_to_format); + +int v4l2_format_to_ext_format(const struct v4l2_format *f, + struct v4l2_ext_format *e, bool strict) +{ + const struct v4l2_plane_pix_format *p; + struct v4l2_plane_ext_pix_format *pe; + unsigned int i; + + memset(e, 0, sizeof(*e)); + + switch (f->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + e->fmt.pix.width = f->fmt.pix.width; + e->fmt.pix.height = f->fmt.pix.height; + e->fmt.pix.pixelformat = f->fmt.pix.pixelformat; + e->fmt.pix.field = f->fmt.pix.field; + e->fmt.pix.colorspace = f->fmt.pix.colorspace; + e->fmt.pix.flags = f->fmt.pix.flags; + e->fmt.pix.ycbcr_enc = f->fmt.pix.ycbcr_enc; + e->fmt.pix.quantization = f->fmt.pix.quantization; + e->fmt.pix.num_planes = 1; + e->fmt.pix.plane_fmt[0].bytesperline = f->fmt.pix.bytesperline; + e->fmt.pix.plane_fmt[0].sizeimage = f->fmt.pix.sizeimage; + e->type = f->type; + break; + + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + if ((f->fmt.pix_mp.num_planes > VIDEO_MAX_PLANES || + !f->fmt.pix_mp.num_planes) && strict) + return -EINVAL; + + e->fmt.pix.width = f->fmt.pix_mp.width; + e->fmt.pix.height = f->fmt.pix_mp.height; + e->fmt.pix.pixelformat = f->fmt.pix_mp.pixelformat; + e->fmt.pix.field = f->fmt.pix_mp.field; + e->fmt.pix.colorspace = f->fmt.pix_mp.colorspace; + e->fmt.pix.flags = f->fmt.pix_mp.flags; + e->fmt.pix.ycbcr_enc = f->fmt.pix_mp.ycbcr_enc; + e->fmt.pix.quantization = f->fmt.pix_mp.quantization; + e->fmt.pix.num_planes = f->fmt.pix_mp.num_planes; + if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + e->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + else + e->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + + for (i = 0; i < VIDEO_MAX_PLANES; i++) { + pe = &e->fmt.pix.plane_fmt[i]; + p = &f->fmt.pix_mp.plane_fmt[i]; + pe->bytesperline = p->bytesperline; + pe->sizeimage = p->sizeimage; + } + break; + + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: + /* + * OVERLAY formats are not supported by the _EXT_FMT + * ioctl()s. + */ + return -EINVAL; + + case V4L2_BUF_TYPE_VBI_CAPTURE: + case V4L2_BUF_TYPE_VBI_OUTPUT: + e->type = f->type; + e->fmt.vbi = f->fmt.vbi; + break; + + case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: + case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: + e->type = f->type; + e->fmt.sliced = f->fmt.sliced; + break; + + case V4L2_BUF_TYPE_SDR_CAPTURE: + case V4L2_BUF_TYPE_SDR_OUTPUT: + e->type = f->type; + e->fmt.sdr = f->fmt.sdr; + break; + + case V4L2_BUF_TYPE_META_CAPTURE: + case V4L2_BUF_TYPE_META_OUTPUT: + e->type = f->type; + e->fmt.meta = f->fmt.meta; + break; + + default: + return -EINVAL; + } + + return 0; +} +EXPORT_SYMBOL_GPL(v4l2_format_to_ext_format); + static int v4l_querycap(const struct v4l2_ioctl_ops *ops, struct file *file, void *fh, void *arg) { @@ -1466,6 +1741,38 @@ static int v4l_enum_fmt(const struct v4l2_ioctl_ops *ops, return ret; } +static int v4l_g_fmt_ext_pix(const struct v4l2_ioctl_ops *ops, + struct file *file, void *fh, + struct v4l2_format *f) +{ + struct v4l2_ext_format ef = { + .type = f->type, + }; + int ret; + + switch (f->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + ret = ops->vidioc_g_ext_fmt_vid_cap(file, fh, &ef.fmt.pix); + break; + + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + ret = ops->vidioc_g_ext_fmt_vid_out(file, fh, &ef.fmt.pix); + break; + + default: + return -EINVAL; + } + + if (ret) + return ret; + + return v4l2_ext_format_to_format(&ef, f, + V4L2_TYPE_IS_MULTIPLANAR(f->type), + true); +} + static int v4l_g_fmt(const struct v4l2_ioctl_ops *ops, struct file *file, void *fh, void *arg) { @@ -1501,15 +1808,22 @@ static int v4l_g_fmt(const struct v4l2_ioctl_ops *ops, switch (p->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: - if (unlikely(!ops->vidioc_g_fmt_vid_cap)) - break; - p->fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC; - ret = ops->vidioc_g_fmt_vid_cap(file, fh, arg); - /* just in case the driver zeroed it again */ - p->fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC; - return ret; + if (ops->vidioc_g_fmt_vid_cap) { + p->fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC; + ret = ops->vidioc_g_fmt_vid_cap(file, fh, arg); + /* just in case the driver zeroed it again */ + p->fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC; + return ret; + } else if (ops->vidioc_g_ext_fmt_vid_cap) { + return v4l_g_fmt_ext_pix(ops, file, fh, p); + } + break; case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - return ops->vidioc_g_fmt_vid_cap_mplane(file, fh, arg); + if (ops->vidioc_g_fmt_vid_cap_mplane) + return ops->vidioc_g_fmt_vid_cap_mplane(file, fh, arg); + else if (ops->vidioc_g_ext_fmt_vid_cap) + return v4l_g_fmt_ext_pix(ops, file, fh, p); + break; case V4L2_BUF_TYPE_VIDEO_OVERLAY: return ops->vidioc_g_fmt_vid_overlay(file, fh, arg); case V4L2_BUF_TYPE_VBI_CAPTURE: @@ -1517,15 +1831,22 @@ static int v4l_g_fmt(const struct v4l2_ioctl_ops *ops, case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: return ops->vidioc_g_fmt_sliced_vbi_cap(file, fh, arg); case V4L2_BUF_TYPE_VIDEO_OUTPUT: - if (unlikely(!ops->vidioc_g_fmt_vid_out)) - break; - p->fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC; - ret = ops->vidioc_g_fmt_vid_out(file, fh, arg); - /* just in case the driver zeroed it again */ - p->fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC; - return ret; + if (ops->vidioc_g_fmt_vid_out) { + p->fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC; + ret = ops->vidioc_g_fmt_vid_out(file, fh, arg); + /* just in case the driver zeroed it again */ + p->fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC; + return ret; + } else if (ops->vidioc_g_ext_fmt_vid_out) { + return v4l_g_fmt_ext_pix(ops, file, fh, p); + } + break; case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - return ops->vidioc_g_fmt_vid_out_mplane(file, fh, arg); + if (ops->vidioc_g_fmt_vid_out_mplane) + return ops->vidioc_g_fmt_vid_out_mplane(file, fh, arg); + else if (ops->vidioc_g_ext_fmt_vid_out) + return v4l_g_fmt_ext_pix(ops, file, fh, p); + break; case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: return ops->vidioc_g_fmt_vid_out_overlay(file, fh, arg); case V4L2_BUF_TYPE_VBI_OUTPUT: @@ -1544,6 +1865,43 @@ static int v4l_g_fmt(const struct v4l2_ioctl_ops *ops, return -EINVAL; } +static int v4l_g_ext_fmt(const struct v4l2_ioctl_ops *ops, + struct file *file, void *fh, void *arg) +{ + struct v4l2_ext_format *ef = arg; + struct v4l2_format f = { + .type = ef->type, + }; + int ret; + + ret = check_fmt(file, ef->type); + if (ret) + return ret; + + memset(&ef->fmt, 0, sizeof(ef->fmt)); + + switch (ef->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + if (ops->vidioc_g_ext_fmt_vid_cap) + return ops->vidioc_g_ext_fmt_vid_cap(file, fh, + &ef->fmt.pix); + break; + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + if (ops->vidioc_g_ext_fmt_vid_out) + return ops->vidioc_g_ext_fmt_vid_out(file, fh, + &ef->fmt.pix); + break; + default: + break; + } + + ret = v4l_g_fmt(ops, file, fh, &f); + if (ret) + return ret; + + return v4l2_format_to_ext_format(&f, ef, true); +} + static void v4l_pix_format_touch(struct v4l2_pix_format *p) { /* @@ -1559,6 +1917,40 @@ static void v4l_pix_format_touch(struct v4l2_pix_format *p) p->xfer_func = 0; } +static int v4l_s_fmt_ext_pix(const struct v4l2_ioctl_ops *ops, + struct file *file, void *fh, + struct v4l2_format *f) +{ + struct v4l2_ext_format ef; + int ret; + + ret = v4l2_format_to_ext_format(f, &ef, false); + if (ret) + return ret; + + switch (f->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + ret = ops->vidioc_s_ext_fmt_vid_cap(file, fh, &ef.fmt.pix); + break; + + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + ret = ops->vidioc_s_ext_fmt_vid_out(file, fh, &ef.fmt.pix); + break; + + default: + return -EINVAL; + } + + if (ret) + return ret; + + return v4l2_ext_format_to_format(&ef, f, + V4L2_TYPE_IS_MULTIPLANAR(f->type), + true); +} + static int v4l_s_fmt(const struct v4l2_ioctl_ops *ops, struct file *file, void *fh, void *arg) { @@ -1577,23 +1969,31 @@ static int v4l_s_fmt(const struct v4l2_ioctl_ops *ops, switch (p->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: - if (unlikely(!ops->vidioc_s_fmt_vid_cap)) - break; - CLEAR_AFTER_FIELD(p, fmt.pix); - ret = ops->vidioc_s_fmt_vid_cap(file, fh, arg); - /* just in case the driver zeroed it again */ - p->fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC; + if (ops->vidioc_s_fmt_vid_cap) { + CLEAR_AFTER_FIELD(p, fmt.pix); + ret = ops->vidioc_s_fmt_vid_cap(file, fh, arg); + /* just in case the driver zeroed it again */ + p->fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC; + } else if (ops->vidioc_s_ext_fmt_vid_cap) { + ret = v4l_s_fmt_ext_pix(ops, file, fh, arg); + } else { + ret = -EINVAL; + } + if (vfd->vfl_type == VFL_TYPE_TOUCH) v4l_pix_format_touch(&p->fmt.pix); return ret; case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - if (unlikely(!ops->vidioc_s_fmt_vid_cap_mplane)) - break; - CLEAR_AFTER_FIELD(p, fmt.pix_mp.xfer_func); - for (i = 0; i < p->fmt.pix_mp.num_planes; i++) - CLEAR_AFTER_FIELD(&p->fmt.pix_mp.plane_fmt[i], - bytesperline); - return ops->vidioc_s_fmt_vid_cap_mplane(file, fh, arg); + if (ops->vidioc_s_fmt_vid_cap_mplane) { + CLEAR_AFTER_FIELD(p, fmt.pix_mp.xfer_func); + for (i = 0; i < p->fmt.pix_mp.num_planes; i++) + CLEAR_AFTER_FIELD(&p->fmt.pix_mp.plane_fmt[i], + bytesperline); + return ops->vidioc_s_fmt_vid_cap_mplane(file, fh, arg); + } else if (ops->vidioc_s_ext_fmt_vid_cap) { + return v4l_s_fmt_ext_pix(ops, file, fh, arg); + } + break; case V4L2_BUF_TYPE_VIDEO_OVERLAY: if (unlikely(!ops->vidioc_s_fmt_vid_overlay)) break; @@ -1610,21 +2010,27 @@ static int v4l_s_fmt(const struct v4l2_ioctl_ops *ops, CLEAR_AFTER_FIELD(p, fmt.sliced); return ops->vidioc_s_fmt_sliced_vbi_cap(file, fh, arg); case V4L2_BUF_TYPE_VIDEO_OUTPUT: - if (unlikely(!ops->vidioc_s_fmt_vid_out)) - break; - CLEAR_AFTER_FIELD(p, fmt.pix); - ret = ops->vidioc_s_fmt_vid_out(file, fh, arg); - /* just in case the driver zeroed it again */ - p->fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC; - return ret; + if (ops->vidioc_s_fmt_vid_out) { + CLEAR_AFTER_FIELD(p, fmt.pix); + ret = ops->vidioc_s_fmt_vid_out(file, fh, arg); + /* just in case the driver zeroed it again */ + p->fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC; + return ret; + } else if (ops->vidioc_s_ext_fmt_vid_out) { + return v4l_s_fmt_ext_pix(ops, file, fh, arg); + } + break; case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - if (unlikely(!ops->vidioc_s_fmt_vid_out_mplane)) - break; - CLEAR_AFTER_FIELD(p, fmt.pix_mp.xfer_func); - for (i = 0; i < p->fmt.pix_mp.num_planes; i++) - CLEAR_AFTER_FIELD(&p->fmt.pix_mp.plane_fmt[i], - bytesperline); - return ops->vidioc_s_fmt_vid_out_mplane(file, fh, arg); + if (ops->vidioc_s_fmt_vid_out_mplane) { + CLEAR_AFTER_FIELD(p, fmt.pix_mp.xfer_func); + for (i = 0; i < p->fmt.pix_mp.num_planes; i++) + CLEAR_AFTER_FIELD(&p->fmt.pix_mp.plane_fmt[i], + bytesperline); + return ops->vidioc_s_fmt_vid_out_mplane(file, fh, arg); + } else if (ops->vidioc_s_ext_fmt_vid_out) { + return v4l_s_fmt_ext_pix(ops, file, fh, arg); + } + break; case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: if (unlikely(!ops->vidioc_s_fmt_vid_out_overlay)) break; @@ -1664,6 +2070,84 @@ static int v4l_s_fmt(const struct v4l2_ioctl_ops *ops, return -EINVAL; } +static int v4l_s_ext_fmt(const struct v4l2_ioctl_ops *ops, + struct file *file, void *fh, void *arg) +{ + struct video_device *vfd = video_devdata(file); + struct v4l2_ext_format *ef = arg; + struct v4l2_format f; + int ret; + + ret = check_fmt(file, ef->type); + if (ret) + return ret; + + switch (ef->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + if (ops->vidioc_s_ext_fmt_vid_cap) + return ops->vidioc_s_ext_fmt_vid_cap(file, fh, + &ef->fmt.pix); + break; + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + if (ops->vidioc_s_ext_fmt_vid_out) + return ops->vidioc_s_ext_fmt_vid_out(file, fh, + &ef->fmt.pix); + break; + default: + break; + } + + ret = v4l2_ext_format_to_format(ef, &f, + vfd->device_caps & + (V4L2_CAP_VIDEO_CAPTURE_MPLANE | + V4L2_CAP_VIDEO_OUTPUT_MPLANE | + V4L2_CAP_VIDEO_M2M_MPLANE), + false); + if (ret) + return ret; + + ret = v4l_s_fmt(ops, file, fh, &f); + if (ret) + return ret; + + return v4l2_format_to_ext_format(&f, ef, true); +} + +static int v4l_try_fmt_ext_pix(const struct v4l2_ioctl_ops *ops, + struct file *file, void *fh, + struct v4l2_format *f) +{ + struct v4l2_ext_format ef; + int ret; + + ret = v4l2_format_to_ext_format(f, &ef, false); + if (ret) + return ret; + + switch (f->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + ret = ops->vidioc_try_ext_fmt_vid_cap(file, fh, &ef.fmt.pix); + break; + + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + ret = ops->vidioc_try_ext_fmt_vid_out(file, fh, &ef.fmt.pix); + break; + + default: + return -EINVAL; + } + + if (ret) + return ret; + + return v4l2_ext_format_to_format(&ef, f, + V4L2_TYPE_IS_MULTIPLANAR(f->type), + true); + +} + static int v4l_try_fmt(const struct v4l2_ioctl_ops *ops, struct file *file, void *fh, void *arg) { @@ -1679,23 +2163,32 @@ static int v4l_try_fmt(const struct v4l2_ioctl_ops *ops, switch (p->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: - if (unlikely(!ops->vidioc_try_fmt_vid_cap)) - break; - CLEAR_AFTER_FIELD(p, fmt.pix); - ret = ops->vidioc_try_fmt_vid_cap(file, fh, arg); - /* just in case the driver zeroed it again */ - p->fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC; - if (vfd->vfl_type == VFL_TYPE_TOUCH) - v4l_pix_format_touch(&p->fmt.pix); - return ret; + if (ops->vidioc_try_fmt_vid_cap) { + CLEAR_AFTER_FIELD(p, fmt.pix); + ret = ops->vidioc_try_fmt_vid_cap(file, fh, arg); + /* just in case the driver zeroed it again */ + p->fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC; + if (vfd->vfl_type == VFL_TYPE_TOUCH) + v4l_pix_format_touch(&p->fmt.pix); + return ret; + } else if (ops->vidioc_try_ext_fmt_vid_cap) { + ret = v4l_try_fmt_ext_pix(ops, file, fh, p); + if (vfd->vfl_type == VFL_TYPE_TOUCH) + v4l_pix_format_touch(&p->fmt.pix); + return ret; + } + break; case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - if (unlikely(!ops->vidioc_try_fmt_vid_cap_mplane)) - break; - CLEAR_AFTER_FIELD(p, fmt.pix_mp.xfer_func); - for (i = 0; i < p->fmt.pix_mp.num_planes; i++) - CLEAR_AFTER_FIELD(&p->fmt.pix_mp.plane_fmt[i], - bytesperline); - return ops->vidioc_try_fmt_vid_cap_mplane(file, fh, arg); + if (ops->vidioc_try_fmt_vid_cap_mplane) { + CLEAR_AFTER_FIELD(p, fmt.pix_mp.xfer_func); + for (i = 0; i < p->fmt.pix_mp.num_planes; i++) + CLEAR_AFTER_FIELD(&p->fmt.pix_mp.plane_fmt[i], + bytesperline); + return ops->vidioc_try_fmt_vid_cap_mplane(file, fh, arg); + } else if (ops->vidioc_try_ext_fmt_vid_cap) { + return v4l_try_fmt_ext_pix(ops, file, fh, p); + } + break; case V4L2_BUF_TYPE_VIDEO_OVERLAY: if (unlikely(!ops->vidioc_try_fmt_vid_overlay)) break; @@ -1712,21 +2205,27 @@ static int v4l_try_fmt(const struct v4l2_ioctl_ops *ops, CLEAR_AFTER_FIELD(p, fmt.sliced); return ops->vidioc_try_fmt_sliced_vbi_cap(file, fh, arg); case V4L2_BUF_TYPE_VIDEO_OUTPUT: - if (unlikely(!ops->vidioc_try_fmt_vid_out)) - break; - CLEAR_AFTER_FIELD(p, fmt.pix); - ret = ops->vidioc_try_fmt_vid_out(file, fh, arg); - /* just in case the driver zeroed it again */ - p->fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC; - return ret; + if (ops->vidioc_try_fmt_vid_out) { + CLEAR_AFTER_FIELD(p, fmt.pix); + ret = ops->vidioc_try_fmt_vid_out(file, fh, arg); + /* just in case the driver zeroed it again */ + p->fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC; + return ret; + } else if (ops->vidioc_try_ext_fmt_vid_cap) { + return v4l_try_fmt_ext_pix(ops, file, fh, p); + } + break; case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - if (unlikely(!ops->vidioc_try_fmt_vid_out_mplane)) - break; - CLEAR_AFTER_FIELD(p, fmt.pix_mp.xfer_func); - for (i = 0; i < p->fmt.pix_mp.num_planes; i++) - CLEAR_AFTER_FIELD(&p->fmt.pix_mp.plane_fmt[i], - bytesperline); - return ops->vidioc_try_fmt_vid_out_mplane(file, fh, arg); + if (ops->vidioc_try_fmt_vid_out_mplane) { + CLEAR_AFTER_FIELD(p, fmt.pix_mp.xfer_func); + for (i = 0; i < p->fmt.pix_mp.num_planes; i++) + CLEAR_AFTER_FIELD(&p->fmt.pix_mp.plane_fmt[i], + bytesperline); + return ops->vidioc_try_fmt_vid_out_mplane(file, fh, arg); + } else if (ops->vidioc_try_ext_fmt_vid_cap) { + return v4l_try_fmt_ext_pix(ops, file, fh, p); + } + break; case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: if (unlikely(!ops->vidioc_try_fmt_vid_out_overlay)) break; @@ -1766,6 +2265,49 @@ static int v4l_try_fmt(const struct v4l2_ioctl_ops *ops, return -EINVAL; } +static int v4l_try_ext_fmt(const struct v4l2_ioctl_ops *ops, + struct file *file, void *fh, void *arg) +{ + struct video_device *vfd = video_devdata(file); + struct v4l2_ext_format *ef = arg; + struct v4l2_format f; + int ret; + + ret = check_fmt(file, ef->type); + if (ret) + return ret; + + switch (ef->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + if (ops->vidioc_try_ext_fmt_vid_cap) + return ops->vidioc_try_ext_fmt_vid_cap(file, fh, + &ef->fmt.pix); + break; + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + if (ops->vidioc_try_ext_fmt_vid_out) + return ops->vidioc_try_ext_fmt_vid_out(file, fh, + &ef->fmt.pix); + break; + default: + break; + } + + ret = v4l2_ext_format_to_format(ef, &f, + vfd->device_caps & + (V4L2_CAP_VIDEO_CAPTURE_MPLANE | + V4L2_CAP_VIDEO_OUTPUT_MPLANE | + V4L2_CAP_VIDEO_M2M_MPLANE), + false); + if (ret) + return ret; + + ret = v4l_try_fmt(ops, file, fh, &f); + if (ret) + return ret; + + return v4l2_format_to_ext_format(&f, ef, true); +} + static int v4l_streamon(const struct v4l2_ioctl_ops *ops, struct file *file, void *fh, void *arg) { @@ -2690,7 +3232,9 @@ static const struct v4l2_ioctl_info v4l2_ioctls[] = { IOCTL_INFO(VIDIOC_QUERYCAP, v4l_querycap, v4l_print_querycap, 0), IOCTL_INFO(VIDIOC_ENUM_FMT, v4l_enum_fmt, v4l_print_fmtdesc, INFO_FL_CLEAR(v4l2_fmtdesc, type)), IOCTL_INFO(VIDIOC_G_FMT, v4l_g_fmt, v4l_print_format, 0), + IOCTL_INFO(VIDIOC_G_EXT_FMT, v4l_g_ext_fmt, v4l_print_ext_format, 0), IOCTL_INFO(VIDIOC_S_FMT, v4l_s_fmt, v4l_print_format, INFO_FL_PRIO), + IOCTL_INFO(VIDIOC_S_EXT_FMT, v4l_s_ext_fmt, v4l_print_ext_format, INFO_FL_PRIO), IOCTL_INFO(VIDIOC_REQBUFS, v4l_reqbufs, v4l_print_requestbuffers, INFO_FL_PRIO | INFO_FL_QUEUE), IOCTL_INFO(VIDIOC_QUERYBUF, v4l_querybuf, v4l_print_buffer, INFO_FL_QUEUE | INFO_FL_CLEAR(v4l2_buffer, length)), IOCTL_INFO(VIDIOC_G_FBUF, v4l_stub_g_fbuf, v4l_print_framebuffer, 0), @@ -2737,6 +3281,7 @@ static const struct v4l2_ioctl_info v4l2_ioctls[] = { IOCTL_INFO(VIDIOC_S_JPEGCOMP, v4l_stub_s_jpegcomp, v4l_print_jpegcompression, INFO_FL_PRIO), IOCTL_INFO(VIDIOC_QUERYSTD, v4l_querystd, v4l_print_std, 0), IOCTL_INFO(VIDIOC_TRY_FMT, v4l_try_fmt, v4l_print_format, 0), + IOCTL_INFO(VIDIOC_TRY_EXT_FMT, v4l_try_ext_fmt, v4l_print_ext_format, 0), IOCTL_INFO(VIDIOC_ENUMAUDIO, v4l_stub_enumaudio, v4l_print_audio, INFO_FL_CLEAR(v4l2_audio, index)), IOCTL_INFO(VIDIOC_ENUMAUDOUT, v4l_stub_enumaudout, v4l_print_audioout, INFO_FL_CLEAR(v4l2_audioout, index)), IOCTL_INFO(VIDIOC_G_PRIORITY, v4l_g_priority, v4l_print_u32, 0), diff --git a/include/media/v4l2-ioctl.h b/include/media/v4l2-ioctl.h index 4bba65a59d46..39ac07fbc7b7 100644 --- a/include/media/v4l2-ioctl.h +++ b/include/media/v4l2-ioctl.h @@ -48,11 +48,16 @@ struct v4l2_fh; * @vidioc_g_fmt_vid_cap: pointer to the function that implements * :ref:`VIDIOC_G_FMT ` ioctl logic for video capture * in single plane mode + * @vidioc_g_ext_fmt_vid_cap: pointer to the function that implements + * :ref:`VIDIOC_G_EXT_FMT ` ioctl logic for video + * capture * @vidioc_g_fmt_vid_overlay: pointer to the function that implements * :ref:`VIDIOC_G_FMT ` ioctl logic for video overlay * @vidioc_g_fmt_vid_out: pointer to the function that implements * :ref:`VIDIOC_G_FMT ` ioctl logic for video out * in single plane mode + * @vidioc_g_ext_fmt_vid_out: pointer to the function that implements + * :ref:`VIDIOC_G_EXT_FMT ` ioctl logic for video out * @vidioc_g_fmt_vid_out_overlay: pointer to the function that implements * :ref:`VIDIOC_G_FMT ` ioctl logic for video overlay output * @vidioc_g_fmt_vbi_cap: pointer to the function that implements @@ -82,11 +87,16 @@ struct v4l2_fh; * @vidioc_s_fmt_vid_cap: pointer to the function that implements * :ref:`VIDIOC_S_FMT ` ioctl logic for video capture * in single plane mode + * @vidioc_s_ext_fmt_vid_cap: pointer to the function that implements + * :ref:`VIDIOC_S_EXT_FMT ` ioctl logic for video + * capture * @vidioc_s_fmt_vid_overlay: pointer to the function that implements * :ref:`VIDIOC_S_FMT ` ioctl logic for video overlay * @vidioc_s_fmt_vid_out: pointer to the function that implements * :ref:`VIDIOC_S_FMT ` ioctl logic for video out * in single plane mode + * @vidioc_s_ext_fmt_vid_out: pointer to the function that implements + * :ref:`VIDIOC_S_EXT_FMT ` ioctl logic for video out * @vidioc_s_fmt_vid_out_overlay: pointer to the function that implements * :ref:`VIDIOC_S_FMT ` ioctl logic for video overlay output * @vidioc_s_fmt_vbi_cap: pointer to the function that implements @@ -116,11 +126,16 @@ struct v4l2_fh; * @vidioc_try_fmt_vid_cap: pointer to the function that implements * :ref:`VIDIOC_TRY_FMT ` ioctl logic for video capture * in single plane mode + * @vidioc_try_ext_fmt_vid_cap: pointer to the function that implements + * :ref:`VIDIOC_TRY_EXT_FMT ` ioctl logic for video + capture * @vidioc_try_fmt_vid_overlay: pointer to the function that implements * :ref:`VIDIOC_TRY_FMT ` ioctl logic for video overlay * @vidioc_try_fmt_vid_out: pointer to the function that implements * :ref:`VIDIOC_TRY_FMT ` ioctl logic for video out * in single plane mode + * @vidioc_try_ext_fmt_vid_out: pointer to the function that implements + * :ref:`VIDIOC_TRY_EXT_FMT ` ioctl logic for video out * @vidioc_try_fmt_vid_out_overlay: pointer to the function that implements * :ref:`VIDIOC_TRY_FMT ` ioctl logic for video overlay * output @@ -319,10 +334,14 @@ struct v4l2_ioctl_ops { /* VIDIOC_G_FMT handlers */ int (*vidioc_g_fmt_vid_cap)(struct file *file, void *fh, struct v4l2_format *f); + int (*vidioc_g_ext_fmt_vid_cap)(struct file *file, void *fh, + struct v4l2_ext_pix_format *f); int (*vidioc_g_fmt_vid_overlay)(struct file *file, void *fh, struct v4l2_format *f); int (*vidioc_g_fmt_vid_out)(struct file *file, void *fh, struct v4l2_format *f); + int (*vidioc_g_ext_fmt_vid_out)(struct file *file, void *fh, + struct v4l2_ext_pix_format *f); int (*vidioc_g_fmt_vid_out_overlay)(struct file *file, void *fh, struct v4l2_format *f); int (*vidioc_g_fmt_vbi_cap)(struct file *file, void *fh, @@ -349,10 +368,14 @@ struct v4l2_ioctl_ops { /* VIDIOC_S_FMT handlers */ int (*vidioc_s_fmt_vid_cap)(struct file *file, void *fh, struct v4l2_format *f); + int (*vidioc_s_ext_fmt_vid_cap)(struct file *file, void *fh, + struct v4l2_ext_pix_format *f); int (*vidioc_s_fmt_vid_overlay)(struct file *file, void *fh, struct v4l2_format *f); int (*vidioc_s_fmt_vid_out)(struct file *file, void *fh, struct v4l2_format *f); + int (*vidioc_s_ext_fmt_vid_out)(struct file *file, void *fh, + struct v4l2_ext_pix_format *f); int (*vidioc_s_fmt_vid_out_overlay)(struct file *file, void *fh, struct v4l2_format *f); int (*vidioc_s_fmt_vbi_cap)(struct file *file, void *fh, @@ -379,10 +402,14 @@ struct v4l2_ioctl_ops { /* VIDIOC_TRY_FMT handlers */ int (*vidioc_try_fmt_vid_cap)(struct file *file, void *fh, struct v4l2_format *f); + int (*vidioc_try_ext_fmt_vid_cap)(struct file *file, void *fh, + struct v4l2_ext_pix_format *f); int (*vidioc_try_fmt_vid_overlay)(struct file *file, void *fh, struct v4l2_format *f); int (*vidioc_try_fmt_vid_out)(struct file *file, void *fh, struct v4l2_format *f); + int (*vidioc_try_ext_fmt_vid_out)(struct file *file, void *fh, + struct v4l2_ext_pix_format *f); int (*vidioc_try_fmt_vid_out_overlay)(struct file *file, void *fh, struct v4l2_format *f); int (*vidioc_try_fmt_vbi_cap)(struct file *file, void *fh, @@ -724,4 +751,10 @@ long int video_usercopy(struct file *file, unsigned int cmd, long int video_ioctl2(struct file *file, unsigned int cmd, unsigned long int arg); +int v4l2_format_to_ext_format(const struct v4l2_format *f, + struct v4l2_ext_format *e, bool strict); +int v4l2_ext_format_to_format(const struct v4l2_ext_format *e, + struct v4l2_format *f, + bool mplane_cap, bool strict); + #endif /* _V4L2_IOCTL_H */ diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index 530638dffd93..c7b169de1c7b 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -2196,6 +2196,55 @@ struct v4l2_pix_format_mplane { __u8 reserved[7]; } __attribute__ ((packed)); +/** + * struct v4l2_plane_ext_pix_format - additional, per-plane format definition + * @sizeimage: maximum size in bytes required for data, for which + * this plane will be used + * @bytesperline: distance in bytes between the leftmost pixels in two + * adjacent lines + */ +struct v4l2_plane_ext_pix_format { + __u32 sizeimage; + __u32 bytesperline; +}; + +/** + * struct v4l2_ext_pix_format - extended single/multiplanar format definition + * @width: image width in pixels + * @height: image height in pixels + * @field: enum v4l2_field; field order (for interlaced video) + * @pixelformat: little endian four character code (fourcc) + * @modifier: modifier applied to the format (used for tiled formats and other + * kind of HW-specific formats, like compressed formats) + * @colorspace: enum v4l2_colorspace; supplemental to pixelformat + * @num_planes: number of planes for this format. Should be equal to 1 + * for single-planar formats and greater than 1 for + * multiplanar ones + * @plane_fmt: per-plane information + * @flags: format flags (V4L2_PIX_FMT_FLAG_*) + * @ycbcr_enc: enum v4l2_ycbcr_encoding, Y'CbCr encoding + * @hsv_enc: enum v4l2_hsv_encoding, HSV encoding + * @quantization: enum v4l2_quantization, colorspace quantization + * @xfer_func: enum v4l2_xfer_func, colorspace transfer function + */ +struct v4l2_ext_pix_format { + __u32 width; + __u32 height; + __u32 field; + __u32 pixelformat; + __u64 modifier; + __u32 colorspace; + __u32 num_planes; + struct v4l2_plane_ext_pix_format plane_fmt[VIDEO_MAX_PLANES]; + __u8 flags; + union { + __u8 ycbcr_enc; + __u8 hsv_enc; + }; + __u8 quantization; + __u8 xfer_func; +}; + /** * struct v4l2_sdr_format - SDR format definition * @pixelformat: little endian four character code (fourcc) @@ -2241,6 +2290,35 @@ struct v4l2_format { } fmt; }; +/** + * struct v4l2_ext_format - extended stream data format + * @type: enum v4l2_buf_type; type of the data stream. + * V4L2_BUF_TYPE_VIDEO[_OUTPUT]_OVERLAY and + * V4L2_BUF_TYPE_VIDEO_{CAPTURE,OUTPUT}_MPLANE are not supported + * @pix: definition of an image format. Used for + * V4L2_BUF_TYPE_VIDEO_{CAPTURE,OUTPUT} types + * @vbi: raw VBI capture or output parameters. Used for + * V4L2_BUF_TYPE_VBI_{CAPTURE,OUTPUT} types + * @sliced: sliced VBI capture or output parameters. Used for + * V4L2_BUF_TYPE_SLICED_VBI_{CAPTURE,OUTPUT} types. + * @sdr: SDR capture or output parameters. Used for + * V4L2_BUF_TYPE_SDR_{CAPTURE,OUTPUT} types + * @meta: meta capture or output parameters. Used for + * V4L2_BUF_TYPE_META_{CAPTURE,OUTPUT} types + * @raw_data: placeholder for future extensions and custom formats + */ +struct v4l2_ext_format { + __u32 type; + union { + struct v4l2_ext_pix_format pix; + struct v4l2_vbi_format vbi; + struct v4l2_sliced_vbi_format sliced; + struct v4l2_sdr_format sdr; + struct v4l2_meta_format meta; + __u8 raw_data[200]; + } fmt; +}; + /* Stream type-dependent parameters */ struct v4l2_streamparm { @@ -2505,6 +2583,9 @@ struct v4l2_create_buffers { #define VIDIOC_QUERY_EXT_CTRL _IOWR('V', 103, struct v4l2_query_ext_ctrl) +#define VIDIOC_G_EXT_FMT _IOWR('V', 104, struct v4l2_ext_format) +#define VIDIOC_S_EXT_FMT _IOWR('V', 105, struct v4l2_ext_format) +#define VIDIOC_TRY_EXT_FMT _IOWR('V', 106, struct v4l2_ext_format) /* Reminder: when adding new ioctls please add support for them to drivers/media/v4l2-core/v4l2-compat-ioctl32.c as well! */ From patchwork Tue Oct 8 09:11:15 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Boris Brezillon X-Patchwork-Id: 11179197 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 2E31E15AB for ; Tue, 8 Oct 2019 09:11:30 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id F2A24218DE for ; Tue, 8 Oct 2019 09:11:29 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729928AbfJHJL3 (ORCPT ); Tue, 8 Oct 2019 05:11:29 -0400 Received: from bhuna.collabora.co.uk ([46.235.227.227]:42858 "EHLO bhuna.collabora.co.uk" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729740AbfJHJL3 (ORCPT ); Tue, 8 Oct 2019 05:11:29 -0400 Received: from localhost.localdomain (unknown [IPv6:2a01:e0a:2c:6930:5cf4:84a1:2763:fe0d]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) (Authenticated sender: bbrezillon) by bhuna.collabora.co.uk (Postfix) with ESMTPSA id A1A1628F7FA; Tue, 8 Oct 2019 10:11:25 +0100 (BST) From: Boris Brezillon To: Mauro Carvalho Chehab , Hans Verkuil , Laurent Pinchart , Sakari Ailus , linux-media@vger.kernel.org Cc: Tomasz Figa , Hirokazu Honda , Nicolas Dufresne , Brian Starkey , kernel@collabora.com, Boris Brezillon Subject: [RFC PATCH v3 2/6] media: v4l2: Add extended buffer operations Date: Tue, 8 Oct 2019 11:11:15 +0200 Message-Id: <20191008091119.7294-3-boris.brezillon@collabora.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20191008091119.7294-1-boris.brezillon@collabora.com> References: <20191008091119.7294-1-boris.brezillon@collabora.com> MIME-Version: 1.0 Sender: linux-media-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org From: Hans Verkuil Those extended buffer ops have several purpose: 1/ Fix y2038 issues by converting the timestamp into an u64 counting the number of ns elapsed since 1970 2/ Unify single/multiplanar handling 3/ Add a new start offset field to each v4l2 plane buffer info struct to support the case where a single buffer object is storing all planes data, each one being placed at a different offset New hooks are created in v4l2_ioctl_ops so that drivers can start using these new objects. The core takes care of converting new ioctls requests to old ones if the driver does not support the new hooks, and vice versa. Note that the timecode field is gone, since there doesn't seem to be in-kernel users, but can be added back in the reserved area if needed. Signed-off-by: Hans Verkuil Signed-off-by: Boris Brezillon --- Changes in v3: - Rebased on top of media/master (post 5.4-rc1) Changes in v2: - Add reserved space to v4l2_ext_buffer so that new fields can be added later on --- drivers/media/v4l2-core/v4l2-dev.c | 30 +- drivers/media/v4l2-core/v4l2-ioctl.c | 428 +++++++++++++++++++++++++-- include/media/v4l2-ioctl.h | 30 ++ include/uapi/linux/videodev2.h | 130 ++++++++ 4 files changed, 591 insertions(+), 27 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c index 9aad715537b3..35c8caccd025 100644 --- a/drivers/media/v4l2-core/v4l2-dev.c +++ b/drivers/media/v4l2-core/v4l2-dev.c @@ -696,12 +696,30 @@ static void determine_valid_ioctls(struct video_device *vdev) if (is_vid || is_vbi || is_sdr || is_tch) { /* ioctls valid for video, metadata, vbi or sdr */ SET_VALID_IOCTL(ops, VIDIOC_REQBUFS, vidioc_reqbufs); - SET_VALID_IOCTL(ops, VIDIOC_QUERYBUF, vidioc_querybuf); - SET_VALID_IOCTL(ops, VIDIOC_QBUF, vidioc_qbuf); - SET_VALID_IOCTL(ops, VIDIOC_EXPBUF, vidioc_expbuf); - SET_VALID_IOCTL(ops, VIDIOC_DQBUF, vidioc_dqbuf); - SET_VALID_IOCTL(ops, VIDIOC_CREATE_BUFS, vidioc_create_bufs); - SET_VALID_IOCTL(ops, VIDIOC_PREPARE_BUF, vidioc_prepare_buf); + if (ops->vidioc_querybuf || ops->vidioc_ext_querybuf) { + set_bit(_IOC_NR(VIDIOC_QUERYBUF), valid_ioctls); + set_bit(_IOC_NR(VIDIOC_EXT_QUERYBUF), valid_ioctls); + } + if (ops->vidioc_qbuf || ops->vidioc_ext_qbuf) { + set_bit(_IOC_NR(VIDIOC_QBUF), valid_ioctls); + set_bit(_IOC_NR(VIDIOC_EXT_QBUF), valid_ioctls); + } + if (ops->vidioc_expbuf || ops->vidioc_ext_expbuf) { + set_bit(_IOC_NR(VIDIOC_EXPBUF), valid_ioctls); + set_bit(_IOC_NR(VIDIOC_EXT_EXPBUF), valid_ioctls); + } + if (ops->vidioc_dqbuf || ops->vidioc_ext_dqbuf) { + set_bit(_IOC_NR(VIDIOC_DQBUF), valid_ioctls); + set_bit(_IOC_NR(VIDIOC_EXT_DQBUF), valid_ioctls); + } + if (ops->vidioc_create_bufs || ops->vidioc_ext_create_bufs) { + set_bit(_IOC_NR(VIDIOC_CREATE_BUFS), valid_ioctls); + set_bit(_IOC_NR(VIDIOC_EXT_CREATE_BUFS), valid_ioctls); + } + if (ops->vidioc_prepare_buf || ops->vidioc_ext_prepare_buf) { + set_bit(_IOC_NR(VIDIOC_PREPARE_BUF), valid_ioctls); + set_bit(_IOC_NR(VIDIOC_EXT_PREPARE_BUF), valid_ioctls); + } SET_VALID_IOCTL(ops, VIDIOC_STREAMON, vidioc_streamon); SET_VALID_IOCTL(ops, VIDIOC_STREAMOFF, vidioc_streamoff); } diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index 78e14c1dc76f..356218e44ccb 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -579,6 +579,25 @@ static void v4l_print_buffer(const void *arg, bool write_only) tc->type, tc->flags, tc->frames, *(__u32 *)tc->userbits); } +static void v4l_print_ext_buffer(const void *arg, bool write_only) +{ + const struct v4l2_ext_buffer *p = arg; + const struct v4l2_ext_plane *plane; + int i; + + pr_cont("%lld index=%d, type=%s, flags=0x%08x, field=%s, sequence=%d, memory=%s\n", + p->timestamp, p->index, prt_names(p->type, v4l2_type_names), + p->flags, prt_names(p->field, v4l2_field_names), + p->sequence, prt_names(p->memory, v4l2_memory_names)); + + for (i = 0; i < p->num_planes; ++i) { + plane = &p->planes[i]; + pr_debug("plane %d: bytesused=%d, data_offset=0x%08x, offset/userptr=0x%llx, length=%d\n", + i, plane->bytesused, plane->data_offset, + plane->m.userptr, plane->length); + } +} + static void v4l_print_exportbuffer(const void *arg, bool write_only) { const struct v4l2_exportbuffer *p = arg; @@ -588,6 +607,18 @@ static void v4l_print_exportbuffer(const void *arg, bool write_only) p->index, p->plane, p->flags); } +static void v4l_print_ext_exportbuffer(const void *arg, bool write_only) +{ + const struct v4l2_ext_exportbuffer *p = arg; + unsigned int i; + + pr_cont("type=%s, index=%u, first_plane=%u num_planes=%u, flags=%08x\n", + prt_names(p->type, v4l2_type_names), p->index, p->first_plane, + p->num_planes, p->flags); + for (i = p->first_plane; i < p->first_plane + p->num_planes; ++i) + pr_debug("plane %u: fd=%d\n", i, p->fds[i]); +} + static void v4l_print_create_buffers(const void *arg, bool write_only) { const struct v4l2_create_buffers *p = arg; @@ -598,6 +629,15 @@ static void v4l_print_create_buffers(const void *arg, bool write_only) v4l_print_format(&p->format, write_only); } +static void v4l_print_ext_create_buffers(const void *arg, bool write_only) +{ + const struct v4l2_ext_create_buffers *p = arg; + + pr_cont("index=%d, count=%d, memory=%s, ", p->index, p->count, + prt_names(p->memory, v4l2_memory_names)); + v4l_print_ext_format(&p->format, write_only); +} + static void v4l_print_streamparm(const void *arg, bool write_only) { const struct v4l2_streamparm *p = arg; @@ -1319,6 +1359,123 @@ int v4l2_format_to_ext_format(const struct v4l2_format *f, } EXPORT_SYMBOL_GPL(v4l2_format_to_ext_format); +int v4l2_ext_buffer_to_buffer(const struct v4l2_ext_buffer *e, + struct v4l2_buffer *b, bool mplane_cap) +{ + u64 nsecs; + + if (!mplane_cap && e->num_planes > 1) + return -EINVAL; + + memset(b, 0, sizeof(*b)); + + b->index = e->index; + b->flags = e->flags; + b->field = e->field; + b->sequence = e->sequence; + b->memory = e->memory; + b->request_fd = e->request_fd; + b->timestamp.tv_sec = div64_u64_rem(e->timestamp, NSEC_PER_SEC, &nsecs); + b->timestamp.tv_usec = (u32)nsecs / NSEC_PER_USEC; + if (mplane_cap) { + unsigned int i; + + if (e->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + b->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + else + b->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + + b->length = e->num_planes; + for (i = 0; i < e->num_planes; i++) { + if (b->memory == V4L2_MEMORY_DMABUF) { + if (e->planes[i].m.dmabuf.offset) + return -EINVAL; + + b->m.planes[i].m.fd = e->planes[i].m.dmabuf.fd; + } else { + b->m.planes[i].m.userptr = e->planes[i].m.userptr; + } + b->m.planes[i].length = e->planes[i].length; + b->m.planes[i].bytesused = e->planes[i].bytesused; + b->m.planes[i].data_offset = e->planes[i].data_offset; + memset(b->m.planes[i].reserved, 0, + sizeof(b->m.planes[i].reserved)); + } + } else { + b->type = e->type; + b->bytesused = e->planes[0].bytesused; + b->length = e->planes[0].length; + if (b->memory == V4L2_MEMORY_DMABUF) { + if (e->planes[0].m.dmabuf.offset) + return -EINVAL; + + b->m.fd = e->planes[0].m.dmabuf.fd; + } else { + b->m.userptr = e->planes[0].m.userptr; + } + } + + return 0; +} +EXPORT_SYMBOL_GPL(v4l2_ext_buffer_to_buffer); + +int v4l2_buffer_to_ext_buffer(const struct v4l2_buffer *b, + struct v4l2_ext_buffer *e) +{ + memset(e, 0, sizeof(*e)); + + e->index = b->index; + e->flags = b->flags; + e->field = b->field; + e->sequence = b->sequence; + e->memory = b->memory; + e->request_fd = b->request_fd; + e->timestamp = b->timestamp.tv_sec * NSEC_PER_SEC + + b->timestamp.tv_usec * NSEC_PER_USEC; + if (V4L2_TYPE_IS_MULTIPLANAR(b->type)) { + unsigned int i; + + if (!b->m.planes) + return -EINVAL; + + if (b->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + e->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + else + e->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + + e->num_planes = b->length; + for (i = 0; i < e->num_planes; i++) { + if (b->memory == V4L2_MEMORY_DMABUF) { + e->planes[i].m.dmabuf.fd = b->m.planes[i].m.fd; + e->planes[i].m.dmabuf.offset = 0; + } else { + e->planes[i].m.userptr = b->m.planes[i].m.userptr; + } + e->planes[i].length = b->m.planes[i].length; + e->planes[i].bytesused = b->m.planes[i].bytesused; + e->planes[i].data_offset = b->m.planes[i].data_offset; + memset(e->planes[i].reserved, 0, + sizeof(e->planes[i].reserved)); + } + } else { + e->type = b->type; + e->num_planes = 1; + e->planes[0].bytesused = b->bytesused; + e->planes[0].length = b->length; + if (b->memory == V4L2_MEMORY_DMABUF) { + e->planes[0].m.dmabuf.fd = b->m.fd; + e->planes[0].m.dmabuf.offset = 0; + } else { + e->planes[0].m.userptr = b->m.userptr; + } + e->planes[0].m.userptr = b->m.userptr; + e->planes[0].data_offset = 0; + } + + return 0; +} +EXPORT_SYMBOL_GPL(v4l2_buffer_to_ext_buffer); + static int v4l_querycap(const struct v4l2_ioctl_ops *ops, struct file *file, void *fh, void *arg) { @@ -2506,31 +2663,109 @@ static int v4l_reqbufs(const struct v4l2_ioctl_ops *ops, return ops->vidioc_reqbufs(file, fh, p); } -static int v4l_querybuf(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) +static int v4l_do_buf_op(int (*op)(struct file *, void *, + struct v4l2_buffer *), + int (*ext_op)(struct file *, void *, + struct v4l2_ext_buffer *), + struct file *file, void *fh, struct v4l2_buffer *b) { - struct v4l2_buffer *p = arg; - int ret = check_fmt(file, p->type); + struct v4l2_ext_buffer eb; + int ret; - return ret ? ret : ops->vidioc_querybuf(file, fh, p); + ret = check_fmt(file, b->type); + if (ret) + return ret; + + if (op) + return op(file, fh, b); + + ret = v4l2_buffer_to_ext_buffer(b, &eb); + if (ret) + return ret; + + ret = ext_op(file, fh, &eb); + if (ret) + return ret; + + v4l2_ext_buffer_to_buffer(&eb, b, V4L2_TYPE_IS_MULTIPLANAR(b->type)); + return 0; +} + +static int v4l_do_ext_buf_op(int (*op)(struct file *, void *, + struct v4l2_buffer *), + int (*ext_op)(struct file *, void *, + struct v4l2_ext_buffer *), + struct file *file, void *fh, + struct v4l2_ext_buffer *eb) +{ + struct video_device *vdev = video_devdata(file); + struct v4l2_buffer b; + bool mplane_cap; + int ret; + + ret = check_fmt(file, eb->type); + if (ret) + return ret; + + if (ext_op) + return ext_op(file, fh, eb); + + mplane_cap = !!(vdev->device_caps & + (V4L2_CAP_VIDEO_CAPTURE_MPLANE | + V4L2_CAP_VIDEO_OUTPUT_MPLANE | + V4L2_CAP_VIDEO_M2M_MPLANE)); + ret = v4l2_ext_buffer_to_buffer(eb, &b, mplane_cap); + if (ret) + return ret; + + ret = op(file, fh, &b); + if (ret) + return ret; + + v4l2_buffer_to_ext_buffer(&b, eb); + return 0; +} + +static int v4l_querybuf(const struct v4l2_ioctl_ops *ops, + struct file *file, void *fh, void *arg) +{ + return v4l_do_buf_op(ops->vidioc_querybuf, ops->vidioc_ext_querybuf, + file, fh, arg); +} + +static int v4l_ext_querybuf(const struct v4l2_ioctl_ops *ops, + struct file *file, void *fh, void *arg) +{ + return v4l_do_ext_buf_op(ops->vidioc_querybuf, + ops->vidioc_ext_querybuf, file, fh, arg); } static int v4l_qbuf(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) + struct file *file, void *fh, void *arg) { - struct v4l2_buffer *p = arg; - int ret = check_fmt(file, p->type); + return v4l_do_buf_op(ops->vidioc_qbuf, ops->vidioc_ext_qbuf, + file, fh, arg); +} - return ret ? ret : ops->vidioc_qbuf(file, fh, p); +static int v4l_ext_qbuf(const struct v4l2_ioctl_ops *ops, + struct file *file, void *fh, void *arg) +{ + return v4l_do_ext_buf_op(ops->vidioc_qbuf, ops->vidioc_ext_qbuf, + file, fh, arg); } static int v4l_dqbuf(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) + struct file *file, void *fh, void *arg) { - struct v4l2_buffer *p = arg; - int ret = check_fmt(file, p->type); + return v4l_do_buf_op(ops->vidioc_dqbuf, ops->vidioc_ext_dqbuf, + file, fh, arg); +} - return ret ? ret : ops->vidioc_dqbuf(file, fh, p); +static int v4l_ext_dqbuf(const struct v4l2_ioctl_ops *ops, + struct file *file, void *fh, void *arg) +{ + return v4l_do_ext_buf_op(ops->vidioc_dqbuf, ops->vidioc_ext_dqbuf, + file, fh, arg); } static int v4l_create_bufs(const struct v4l2_ioctl_ops *ops, @@ -2546,7 +2781,27 @@ static int v4l_create_bufs(const struct v4l2_ioctl_ops *ops, v4l_sanitize_format(&create->format); - ret = ops->vidioc_create_bufs(file, fh, create); + if (ops->vidioc_create_bufs) { + ret = ops->vidioc_create_bufs(file, fh, create); + } else { + struct v4l2_ext_create_buffers ecreate = { + .count = create->count, + .memory = create->memory, + }; + + ret = v4l2_format_to_ext_format(&create->format, + &ecreate.format, true); + if (ret) + return ret; + + ret = ops->vidioc_ext_create_bufs(file, fh, &ecreate); + if (ret) + return ret; + + create->index = ecreate.index; + create->count = ecreate.count; + create->capabilities = ecreate.capabilities; + } if (create->format.type == V4L2_BUF_TYPE_VIDEO_CAPTURE || create->format.type == V4L2_BUF_TYPE_VIDEO_OUTPUT) @@ -2555,13 +2810,59 @@ static int v4l_create_bufs(const struct v4l2_ioctl_ops *ops, return ret; } -static int v4l_prepare_buf(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) +static int v4l_ext_create_bufs(const struct v4l2_ioctl_ops *ops, + struct file *file, void *fh, void *arg) { - struct v4l2_buffer *b = arg; - int ret = check_fmt(file, b->type); + struct v4l2_ext_create_buffers *ecreate = arg; + struct video_device *vdev = video_devdata(file); + struct v4l2_create_buffers create = { + .count = ecreate->count, + .memory = ecreate->memory, + }; + bool mplane_cap; + int ret; - return ret ? ret : ops->vidioc_prepare_buf(file, fh, b); + ret = check_fmt(file, ecreate->format.type); + if (ret) + return ret; + + if (ops->vidioc_ext_create_bufs) + return ops->vidioc_ext_create_bufs(file, fh, ecreate); + + mplane_cap = !!(vdev->device_caps & + (V4L2_CAP_VIDEO_CAPTURE_MPLANE | + V4L2_CAP_VIDEO_OUTPUT_MPLANE | + V4L2_CAP_VIDEO_M2M_MPLANE)); + ret = v4l2_ext_format_to_format(&ecreate->format, + &create.format, mplane_cap, true); + if (ret) + return ret; + + ret = v4l_create_bufs(ops, file, fh, &create); + if (ret) + return ret; + + ecreate->index = create.index; + ecreate->count = create.count; + ecreate->capabilities = create.capabilities; + + return 0; +} + +static int v4l_prepare_buf(const struct v4l2_ioctl_ops *ops, + struct file *file, void *fh, void *arg) +{ + return v4l_do_buf_op(ops->vidioc_prepare_buf, + ops->vidioc_ext_prepare_buf, + file, fh, arg); +} + +static int v4l_ext_prepare_buf(const struct v4l2_ioctl_ops *ops, + struct file *file, void *fh, void *arg) +{ + return v4l_do_ext_buf_op(ops->vidioc_prepare_buf, + ops->vidioc_ext_prepare_buf, + file, fh, arg); } static int v4l_g_parm(const struct v4l2_ioctl_ops *ops, @@ -3159,6 +3460,86 @@ static int v4l_enum_freq_bands(const struct v4l2_ioctl_ops *ops, return -ENOTTY; } +static int v4l_expbuf(const struct v4l2_ioctl_ops *ops, struct file *file, + void *fh, void *arg) +{ + struct v4l2_exportbuffer *b = arg; + struct v4l2_ext_exportbuffer eb = { + .type = b->type, + .index = b->index, + .first_plane = b->plane, + .num_planes = 1, + .flags = b->flags, + }; + int ret; + + if (ops->vidioc_expbuf) + return ops->vidioc_expbuf(file, fh, b); + + if (b->plane >= VIDEO_MAX_PLANES) + return -EINVAL; + + ret = ops->vidioc_ext_expbuf(file, fh, &eb); + if (ret) + return ret; + + b->fd = eb.fds[b->plane]; + return 0; +} + +static int v4l_ext_expbuf(const struct v4l2_ioctl_ops *ops, + struct file *file, void *fh, void *arg) +{ + struct v4l2_ext_exportbuffer *eb = arg; + unsigned int i; + int ret; + + if (eb->first_plane >= VIDEO_MAX_PLANES || + eb->num_planes > VIDEO_MAX_PLANES || + eb->first_plane + eb->num_planes > VIDEO_MAX_PLANES) + return -EINVAL; + + if (ops->vidioc_ext_expbuf) + return ops->vidioc_ext_expbuf(file, fh, eb); + + for (i = eb->first_plane; i < eb->first_plane + eb->num_planes; i++) { + struct v4l2_exportbuffer b = { + .type = eb->type, + .index = eb->index, + .plane = i, + .flags = eb->flags, + }; + + ret = ops->vidioc_expbuf(file, fh, &b); + if (ret) + goto err_put_dmabufs; + + eb->fds[i] = b.fd; + } + + return 0; + +err_put_dmabufs: + for (i = eb->first_plane; i < eb->first_plane + eb->num_planes; i++) { + struct dma_buf *dmabuf; + + if (eb->fds[i] <= 0) + break; + + /* + * We must call dma_buf_put() twice because we got one + * reference taken at dmabuf creation time one taken when + * calling dma_buf_get(). + * FIXME: not entirely sure this works correctly. + */ + dmabuf = dma_buf_get(eb->fds[i]); + dma_buf_put(dmabuf); + dma_buf_put(dmabuf); + } + + return ret; +} + struct v4l2_ioctl_info { unsigned int ioctl; u32 flags; @@ -3201,7 +3582,6 @@ struct v4l2_ioctl_info { DEFINE_V4L_STUB_FUNC(g_fbuf) DEFINE_V4L_STUB_FUNC(s_fbuf) -DEFINE_V4L_STUB_FUNC(expbuf) DEFINE_V4L_STUB_FUNC(g_std) DEFINE_V4L_STUB_FUNC(g_audio) DEFINE_V4L_STUB_FUNC(s_audio) @@ -3237,12 +3617,16 @@ static const struct v4l2_ioctl_info v4l2_ioctls[] = { IOCTL_INFO(VIDIOC_S_EXT_FMT, v4l_s_ext_fmt, v4l_print_ext_format, INFO_FL_PRIO), IOCTL_INFO(VIDIOC_REQBUFS, v4l_reqbufs, v4l_print_requestbuffers, INFO_FL_PRIO | INFO_FL_QUEUE), IOCTL_INFO(VIDIOC_QUERYBUF, v4l_querybuf, v4l_print_buffer, INFO_FL_QUEUE | INFO_FL_CLEAR(v4l2_buffer, length)), + IOCTL_INFO(VIDIOC_EXT_QUERYBUF, v4l_ext_querybuf, v4l_print_ext_buffer, INFO_FL_QUEUE | INFO_FL_CLEAR(v4l2_ext_buffer, num_planes)), IOCTL_INFO(VIDIOC_G_FBUF, v4l_stub_g_fbuf, v4l_print_framebuffer, 0), IOCTL_INFO(VIDIOC_S_FBUF, v4l_stub_s_fbuf, v4l_print_framebuffer, INFO_FL_PRIO), IOCTL_INFO(VIDIOC_OVERLAY, v4l_overlay, v4l_print_u32, INFO_FL_PRIO), IOCTL_INFO(VIDIOC_QBUF, v4l_qbuf, v4l_print_buffer, INFO_FL_QUEUE), - IOCTL_INFO(VIDIOC_EXPBUF, v4l_stub_expbuf, v4l_print_exportbuffer, INFO_FL_QUEUE | INFO_FL_CLEAR(v4l2_exportbuffer, flags)), + IOCTL_INFO(VIDIOC_EXT_QBUF, v4l_ext_qbuf, v4l_print_ext_buffer, INFO_FL_QUEUE), + IOCTL_INFO(VIDIOC_EXPBUF, v4l_expbuf, v4l_print_exportbuffer, INFO_FL_QUEUE | INFO_FL_CLEAR(v4l2_exportbuffer, flags)), + IOCTL_INFO(VIDIOC_EXT_EXPBUF, v4l_ext_expbuf, v4l_print_ext_exportbuffer, INFO_FL_QUEUE | INFO_FL_CLEAR(v4l2_exportbuffer, flags)), IOCTL_INFO(VIDIOC_DQBUF, v4l_dqbuf, v4l_print_buffer, INFO_FL_QUEUE), + IOCTL_INFO(VIDIOC_EXT_DQBUF, v4l_ext_dqbuf, v4l_print_ext_buffer, INFO_FL_QUEUE), IOCTL_INFO(VIDIOC_STREAMON, v4l_streamon, v4l_print_buftype, INFO_FL_PRIO | INFO_FL_QUEUE), IOCTL_INFO(VIDIOC_STREAMOFF, v4l_streamoff, v4l_print_buftype, INFO_FL_PRIO | INFO_FL_QUEUE), IOCTL_INFO(VIDIOC_G_PARM, v4l_g_parm, v4l_print_streamparm, INFO_FL_CLEAR(v4l2_streamparm, type)), @@ -3307,7 +3691,9 @@ static const struct v4l2_ioctl_info v4l2_ioctls[] = { IOCTL_INFO(VIDIOC_SUBSCRIBE_EVENT, v4l_subscribe_event, v4l_print_event_subscription, 0), IOCTL_INFO(VIDIOC_UNSUBSCRIBE_EVENT, v4l_unsubscribe_event, v4l_print_event_subscription, 0), IOCTL_INFO(VIDIOC_CREATE_BUFS, v4l_create_bufs, v4l_print_create_buffers, INFO_FL_PRIO | INFO_FL_QUEUE), + IOCTL_INFO(VIDIOC_EXT_CREATE_BUFS, v4l_ext_create_bufs, v4l_print_ext_create_buffers, INFO_FL_PRIO | INFO_FL_QUEUE), IOCTL_INFO(VIDIOC_PREPARE_BUF, v4l_prepare_buf, v4l_print_buffer, INFO_FL_QUEUE), + IOCTL_INFO(VIDIOC_EXT_PREPARE_BUF, v4l_ext_prepare_buf, v4l_print_ext_buffer, INFO_FL_QUEUE), IOCTL_INFO(VIDIOC_ENUM_DV_TIMINGS, v4l_stub_enum_dv_timings, v4l_print_enum_dv_timings, INFO_FL_CLEAR(v4l2_enum_dv_timings, pad)), IOCTL_INFO(VIDIOC_QUERY_DV_TIMINGS, v4l_stub_query_dv_timings, v4l_print_dv_timings, INFO_FL_ALWAYS_COPY), IOCTL_INFO(VIDIOC_DV_TIMINGS_CAP, v4l_stub_dv_timings_cap, v4l_print_dv_timings_cap, INFO_FL_CLEAR(v4l2_dv_timings_cap, pad)), diff --git a/include/media/v4l2-ioctl.h b/include/media/v4l2-ioctl.h index 39ac07fbc7b7..f7e375d38602 100644 --- a/include/media/v4l2-ioctl.h +++ b/include/media/v4l2-ioctl.h @@ -168,16 +168,28 @@ struct v4l2_fh; * :ref:`VIDIOC_REQBUFS ` ioctl * @vidioc_querybuf: pointer to the function that implements * :ref:`VIDIOC_QUERYBUF ` ioctl + * @vidioc_ext_querybuf: pointer to the function that implements + * :ref:`VIDIOC_EXT_QUERYBUF ` ioctl * @vidioc_qbuf: pointer to the function that implements * :ref:`VIDIOC_QBUF ` ioctl + * @vidioc_ext_qbuf: pointer to the function that implements + * :ref:`VIDIOC_EXT_QBUF ` ioctl * @vidioc_expbuf: pointer to the function that implements * :ref:`VIDIOC_EXPBUF ` ioctl + * @vidioc_ext_expbuf: pointer to the function that implements + * :ref:`VIDIOC_EXT_EXPBUF ` ioctl * @vidioc_dqbuf: pointer to the function that implements * :ref:`VIDIOC_DQBUF ` ioctl + * @vidioc_ext_dqbuf: pointer to the function that implements + * :ref:`VIDIOC_EXT_DQBUF ` ioctl * @vidioc_create_bufs: pointer to the function that implements * :ref:`VIDIOC_CREATE_BUFS ` ioctl + * @vidioc_ext_create_bufs: pointer to the function that implements + * :ref:`VIDIOC_EXT_CREATE_BUFS ` ioctl * @vidioc_prepare_buf: pointer to the function that implements * :ref:`VIDIOC_PREPARE_BUF ` ioctl + * @vidioc_ext_prepare_buf: pointer to the function that implements + * :ref:`VIDIOC_EXT_PREPARE_BUF ` ioctl * @vidioc_overlay: pointer to the function that implements * :ref:`VIDIOC_OVERLAY ` ioctl * @vidioc_g_fbuf: pointer to the function that implements @@ -438,17 +450,29 @@ struct v4l2_ioctl_ops { struct v4l2_requestbuffers *b); int (*vidioc_querybuf)(struct file *file, void *fh, struct v4l2_buffer *b); + int (*vidioc_ext_querybuf)(struct file *file, void *fh, + struct v4l2_ext_buffer *b); int (*vidioc_qbuf)(struct file *file, void *fh, struct v4l2_buffer *b); + int (*vidioc_ext_qbuf)(struct file *file, void *fh, + struct v4l2_ext_buffer *b); int (*vidioc_expbuf)(struct file *file, void *fh, struct v4l2_exportbuffer *e); + int (*vidioc_ext_expbuf)(struct file *file, void *fh, + struct v4l2_ext_exportbuffer *e); int (*vidioc_dqbuf)(struct file *file, void *fh, struct v4l2_buffer *b); + int (*vidioc_ext_dqbuf)(struct file *file, void *fh, + struct v4l2_ext_buffer *b); int (*vidioc_create_bufs)(struct file *file, void *fh, struct v4l2_create_buffers *b); + int (*vidioc_ext_create_bufs)(struct file *file, void *fh, + struct v4l2_ext_create_buffers *b); int (*vidioc_prepare_buf)(struct file *file, void *fh, struct v4l2_buffer *b); + int (*vidioc_ext_prepare_buf)(struct file *file, void *fh, + struct v4l2_ext_buffer *b); int (*vidioc_overlay)(struct file *file, void *fh, unsigned int i); int (*vidioc_g_fbuf)(struct file *file, void *fh, @@ -757,4 +781,10 @@ int v4l2_ext_format_to_format(const struct v4l2_ext_format *e, struct v4l2_format *f, bool mplane_cap, bool strict); +int v4l2_ext_buffer_to_buffer(const struct v4l2_ext_buffer *e, + struct v4l2_buffer *b, + bool mplane_cap); +int v4l2_buffer_to_ext_buffer(const struct v4l2_buffer *b, + struct v4l2_ext_buffer *e); + #endif /* _V4L2_IOCTL_H */ diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index c7b169de1c7b..33c8348df13f 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -953,6 +953,49 @@ struct v4l2_plane { __u32 reserved[11]; }; +/** + * struct v4l2_ext_plane - extended plane buffer info + * @bytesused: number of bytes occupied by data in the plane (payload) + * @length: size of this plane (NOT the payload) in bytes + * @mem_offset: when memory in the associated struct v4l2_ext_buffer is + * V4L2_MEMORY_MMAP, equals the offset from the start of the + * device memory for this plane (or is a "cookie" that should be + * passed to mmap() called on the video node) + * @userptr: when memory is V4L2_MEMORY_USERPTR, a userspace pointer pointing + * to this plane + * @dmabuf.fd: when memory is V4L2_MEMORY_DMABUF, a userspace file descriptor + * associated with this plane + * @dmabuf.offset: where the plane starts inside the DMABUF buffer. All planes + * might share the same buffer object. In this case we need to + * know where the plane start inside this buffer. + * @data_offset: offset in the plane to the start of data; usually 0, unless + * there is a header in front of the data. data_offset is + * relative to start_offset, so absolute data_offset is actually + * start_offset + data_offset + * + * + * Multi-planar buffers consist of one or more planes, e.g. an YCbCr buffer + * with two planes can have one plane for Y, and another for interleaved CbCr + * components. Each plane can reside in a separate memory buffer, or even in + * a completely separate memory node (e.g. in embedded devices). + * Note that this struct is also used for uni-planar buffers, but in that case + * you'll only have one plane defined. + */ +struct v4l2_ext_plane { + __u32 bytesused; + __u32 length; + union { + __u32 mem_offset; + __u64 userptr; + struct { + __s32 fd; + __u32 offset; + } dmabuf; + } m; + __u32 data_offset; + __u32 reserved[10]; +}; + /** * struct v4l2_buffer - video buffer info * @index: id number of the buffer @@ -1010,6 +1053,40 @@ struct v4l2_buffer { }; }; +/** + * struct v4l2_ext_buffer - extended video buffer info + * @index: id number of the buffer + * @type: enum v4l2_buf_type; buffer type. _MPLANE and _OVERLAY formats are + * invalid + * @flags: buffer informational flags + * @field: enum v4l2_field; field order of the image in the buffer + * @timestamp: frame timestamp + * @sequence: sequence count of this frame + * @memory: enum v4l2_memory; the method, in which the actual video data is + * passed + * @planes: per-plane buffer information + * @num_planes: number of plane buffers + * @request_fd: fd of the request that this buffer should use + * @reserved: some extra space reserved to add future fields (like timecode). + * Must be set to 0 + * + * Contains data exchanged by application and driver using one of the Streaming + * I/O methods. + */ +struct v4l2_ext_buffer { + __u32 index; + __u32 type; + __u32 flags; + __u32 field; + __u64 timestamp; + __u32 sequence; + __u32 memory; + struct v4l2_ext_plane planes[VIDEO_MAX_PLANES]; + __u32 num_planes; + __u32 request_fd; + __u32 reserved[10]; +}; + /** * v4l2_timeval_to_ns - Convert timeval to nanoseconds * @ts: pointer to the timeval variable to be converted @@ -1087,6 +1164,35 @@ struct v4l2_exportbuffer { __u32 reserved[11]; }; +/** + * struct v4l2_ext_exportbuffer - export of video buffer as DMABUF file + * descriptor using extended format + * + * @index: id number of the buffer + * @type: enum v4l2_buf_type; buffer type + * @flags: flags for newly created file(s), currently only O_CLOEXEC is + * supported, refer to manual of open syscall for more details + * @first_plane: first plane to export. Most likely set to 0 + * @num_planes: number of planes to export. Most set to the number of planes + * attached to the buffer + * @fds: file descriptors associated with DMABUF (set by driver). Note that all + * planes might share the same buffer and then be returned the same FD + * + * Contains data used for exporting a video buffer as DMABUF file descriptor. + * The buffer is identified by a 'cookie' returned by VIDIOC_QUERYBUF + * (identical to the cookie used to mmap() the buffer to userspace). All + * reserved fields must be set to zero. + */ +struct v4l2_ext_exportbuffer { + __u32 type; /* enum v4l2_buf_type */ + __u32 index; + __u32 flags; + __u32 first_plane; + __u32 num_planes; + __s32 fds[VIDEO_MAX_PLANES]; + __u32 reserved; +}; + /* * O V E R L A Y P R E V I E W */ @@ -2483,6 +2589,23 @@ struct v4l2_create_buffers { __u32 reserved[7]; }; +/** + * struct v4l2_ext_create_buffers - VIDIOC_EXT_CREATE_BUFS argument + * @index: on return, index of the first created buffer + * @count: entry: number of requested buffers, + * return: number of created buffers + * @memory: enum v4l2_memory; buffer memory type + * @capabilities: capabilities of this buffer type. + * @format: frame format, for which buffers are requested + */ +struct v4l2_ext_create_buffers { + __u32 index; + __u32 count; + __u32 memory; + __u32 capabilities; + struct v4l2_ext_format format; +}; + /* * I O C T L C O D E S F O R V I D E O D E V I C E S * @@ -2586,6 +2709,13 @@ struct v4l2_create_buffers { #define VIDIOC_G_EXT_FMT _IOWR('V', 104, struct v4l2_ext_format) #define VIDIOC_S_EXT_FMT _IOWR('V', 105, struct v4l2_ext_format) #define VIDIOC_TRY_EXT_FMT _IOWR('V', 106, struct v4l2_ext_format) +#define VIDIOC_EXT_CREATE_BUFS _IOWR('V', 107, struct v4l2_ext_create_buffers) +#define VIDIOC_EXT_QUERYBUF _IOWR('V', 108, struct v4l2_ext_buffer) +#define VIDIOC_EXT_QBUF _IOWR('V', 109, struct v4l2_ext_buffer) +#define VIDIOC_EXT_DQBUF _IOWR('V', 110, struct v4l2_ext_buffer) +#define VIDIOC_EXT_PREPARE_BUF _IOWR('V', 111, struct v4l2_ext_buffer) +#define VIDIOC_EXT_EXPBUF _IOWR('V', 112, struct v4l2_ext_exportbuffer) + /* Reminder: when adding new ioctls please add support for them to drivers/media/v4l2-core/v4l2-compat-ioctl32.c as well! */ From patchwork Tue Oct 8 09:11:16 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Boris Brezillon X-Patchwork-Id: 11179199 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 6BAAA14DB for ; Tue, 8 Oct 2019 09:11:30 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 4C4B721721 for ; Tue, 8 Oct 2019 09:11:30 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729935AbfJHJL3 (ORCPT ); Tue, 8 Oct 2019 05:11:29 -0400 Received: from bhuna.collabora.co.uk ([46.235.227.227]:42874 "EHLO bhuna.collabora.co.uk" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729767AbfJHJL3 (ORCPT ); Tue, 8 Oct 2019 05:11:29 -0400 Received: from localhost.localdomain (unknown [IPv6:2a01:e0a:2c:6930:5cf4:84a1:2763:fe0d]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) (Authenticated sender: bbrezillon) by bhuna.collabora.co.uk (Postfix) with ESMTPSA id 280A528F7FC; Tue, 8 Oct 2019 10:11:26 +0100 (BST) From: Boris Brezillon To: Mauro Carvalho Chehab , Hans Verkuil , Laurent Pinchart , Sakari Ailus , linux-media@vger.kernel.org Cc: Tomasz Figa , Hirokazu Honda , Nicolas Dufresne , Brian Starkey , kernel@collabora.com, Boris Brezillon Subject: [RFC PATCH v3 3/6] media: videobuf2: Expose helpers to implement the _ext_fmt and _ext_buf hooks Date: Tue, 8 Oct 2019 11:11:16 +0200 Message-Id: <20191008091119.7294-4-boris.brezillon@collabora.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20191008091119.7294-1-boris.brezillon@collabora.com> References: <20191008091119.7294-1-boris.brezillon@collabora.com> MIME-Version: 1.0 Sender: linux-media-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org The VB2 layer is used by a lot of drivers. Patch it to support the _EXT_FMT and _EXT_BUF ioctls in order to ease conversion of existing drivers to these new APIs. Note that internally, the VB2 core is now only using ext structs and old APIs are supported through conversion wrappers. Signed-off-by: Boris Brezillon --- Changes in v3: - Rebased on top of media/master (post 5.4-rc1) Changes in v2: - New patch --- .../media/common/videobuf2/videobuf2-core.c | 2 + .../media/common/videobuf2/videobuf2-v4l2.c | 534 +++++++++++------- include/media/videobuf2-core.h | 6 +- include/media/videobuf2-v4l2.h | 26 +- 4 files changed, 352 insertions(+), 216 deletions(-) diff --git a/drivers/media/common/videobuf2/videobuf2-core.c b/drivers/media/common/videobuf2/videobuf2-core.c index 4489744fbbd9..898d01b4dcb4 100644 --- a/drivers/media/common/videobuf2/videobuf2-core.c +++ b/drivers/media/common/videobuf2/videobuf2-core.c @@ -1181,6 +1181,7 @@ static int __prepare_dmabuf(struct vb2_buffer *vb) vb->planes[plane].length = 0; vb->planes[plane].m.fd = 0; vb->planes[plane].data_offset = 0; + vb->planes[plane].dbuf_offset = 0; /* Acquire each plane's memory */ mem_priv = call_ptr_memop(vb, attach_dmabuf, @@ -1224,6 +1225,7 @@ static int __prepare_dmabuf(struct vb2_buffer *vb) vb->planes[plane].length = planes[plane].length; vb->planes[plane].m.fd = planes[plane].m.fd; vb->planes[plane].data_offset = planes[plane].data_offset; + vb->planes[plane].dbuf_offset = planes[plane].dbuf_offset; } if (reacquired) { diff --git a/drivers/media/common/videobuf2/videobuf2-v4l2.c b/drivers/media/common/videobuf2/videobuf2-v4l2.c index 5a9ba3846f0a..ac5ba5f0a254 100644 --- a/drivers/media/common/videobuf2/videobuf2-v4l2.c +++ b/drivers/media/common/videobuf2/videobuf2-v4l2.c @@ -29,6 +29,7 @@ #include #include #include +#include #include @@ -54,22 +55,14 @@ module_param(debug, int, 0644); /* * __verify_planes_array() - verify that the planes array passed in struct - * v4l2_buffer from userspace can be safely used + * v4l2_ext_buffer from userspace can be safely used */ -static int __verify_planes_array(struct vb2_buffer *vb, const struct v4l2_buffer *b) +static int __verify_planes_array(struct vb2_buffer *vb, + const struct v4l2_ext_buffer *b) { - if (!V4L2_TYPE_IS_MULTIPLANAR(b->type)) - return 0; - - /* Is memory for copying plane information present? */ - if (b->m.planes == NULL) { - dprintk(1, "multi-planar buffer passed but planes array not provided\n"); - return -EINVAL; - } - - if (b->length < vb->num_planes || b->length > VB2_MAX_PLANES) { + if (b->num_planes < vb->num_planes || b->num_planes > VB2_MAX_PLANES) { dprintk(1, "incorrect planes array length, expected %d, got %d\n", - vb->num_planes, b->length); + vb->num_planes, b->num_planes); return -EINVAL; } @@ -85,7 +78,8 @@ static int __verify_planes_array_core(struct vb2_buffer *vb, const void *pb) * __verify_length() - Verify that the bytesused value for each plane fits in * the plane length and that the data offset doesn't exceed the bytesused value. */ -static int __verify_length(struct vb2_buffer *vb, const struct v4l2_buffer *b) +static int __verify_length(struct vb2_buffer *vb, + const struct v4l2_ext_buffer *b) { unsigned int length; unsigned int bytesused; @@ -94,27 +88,19 @@ static int __verify_length(struct vb2_buffer *vb, const struct v4l2_buffer *b) if (!V4L2_TYPE_IS_OUTPUT(b->type)) return 0; - if (V4L2_TYPE_IS_MULTIPLANAR(b->type)) { - for (plane = 0; plane < vb->num_planes; ++plane) { - length = (b->memory == VB2_MEMORY_USERPTR || - b->memory == VB2_MEMORY_DMABUF) - ? b->m.planes[plane].length - : vb->planes[plane].length; - bytesused = b->m.planes[plane].bytesused - ? b->m.planes[plane].bytesused : length; + for (plane = 0; plane < vb->num_planes; ++plane) { + length = (b->memory == VB2_MEMORY_USERPTR || + b->memory == VB2_MEMORY_DMABUF) ? + b->planes[plane].length : + vb->planes[plane].length; + bytesused = b->planes[plane].bytesused ? + b->planes[plane].bytesused : length; - if (b->m.planes[plane].bytesused > length) - return -EINVAL; + if (b->planes[plane].bytesused > length) + return -EINVAL; - if (b->m.planes[plane].data_offset > 0 && - b->m.planes[plane].data_offset >= bytesused) - return -EINVAL; - } - } else { - length = (b->memory == VB2_MEMORY_USERPTR) - ? b->length : vb->planes[0].length; - - if (b->bytesused > length) + if (b->planes[plane].data_offset > 0 && + b->planes[plane].data_offset >= bytesused) return -EINVAL; } @@ -133,21 +119,12 @@ static void __init_vb2_v4l2_buffer(struct vb2_buffer *vb) static void __copy_timestamp(struct vb2_buffer *vb, const void *pb) { - const struct v4l2_buffer *b = pb; - struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + const struct v4l2_ext_buffer *b = pb; struct vb2_queue *q = vb->vb2_queue; - if (q->is_output) { - /* - * For output buffers copy the timestamp if needed, - * and the timecode field and flag if needed. - */ - if (q->copy_timestamp) - vb->timestamp = v4l2_timeval_to_ns(&b->timestamp); - vbuf->flags |= b->flags & V4L2_BUF_FLAG_TIMECODE; - if (b->flags & V4L2_BUF_FLAG_TIMECODE) - vbuf->timecode = b->timecode; - } + /* For output buffers copy the timestamp if needed. */ + if (q->is_output && q->copy_timestamp) + vb->timestamp = b->timestamp; }; static void vb2_warn_zero_bytesused(struct vb2_buffer *vb) @@ -166,7 +143,8 @@ static void vb2_warn_zero_bytesused(struct vb2_buffer *vb) pr_warn("use the actual size instead.\n"); } -static int vb2_fill_vb2_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b) +static int vb2_fill_vb2_v4l2_buffer(struct vb2_buffer *vb, + struct v4l2_ext_buffer *b) { struct vb2_queue *q = vb->vb2_queue; struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); @@ -195,110 +173,61 @@ static int vb2_fill_vb2_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b vbuf->sequence = 0; vbuf->request_fd = -1; - if (V4L2_TYPE_IS_MULTIPLANAR(b->type)) { - switch (b->memory) { - case VB2_MEMORY_USERPTR: - for (plane = 0; plane < vb->num_planes; ++plane) { - planes[plane].m.userptr = - b->m.planes[plane].m.userptr; - planes[plane].length = - b->m.planes[plane].length; - } - break; - case VB2_MEMORY_DMABUF: - for (plane = 0; plane < vb->num_planes; ++plane) { - planes[plane].m.fd = - b->m.planes[plane].m.fd; - planes[plane].length = - b->m.planes[plane].length; - } - break; - default: - for (plane = 0; plane < vb->num_planes; ++plane) { - planes[plane].m.offset = - vb->planes[plane].m.offset; - planes[plane].length = - vb->planes[plane].length; - } - break; + switch (b->memory) { + case VB2_MEMORY_USERPTR: + for (plane = 0; plane < vb->num_planes; ++plane) { + planes[plane].m.userptr = b->planes[plane].m.userptr; + planes[plane].length = b->planes[plane].length; } - - /* Fill in driver-provided information for OUTPUT types */ - if (V4L2_TYPE_IS_OUTPUT(b->type)) { - /* - * Will have to go up to b->length when API starts - * accepting variable number of planes. - * - * If bytesused == 0 for the output buffer, then fall - * back to the full buffer size. In that case - * userspace clearly never bothered to set it and - * it's a safe assumption that they really meant to - * use the full plane sizes. - * - * Some drivers, e.g. old codec drivers, use bytesused == 0 - * as a way to indicate that streaming is finished. - * In that case, the driver should use the - * allow_zero_bytesused flag to keep old userspace - * applications working. - */ - for (plane = 0; plane < vb->num_planes; ++plane) { - struct vb2_plane *pdst = &planes[plane]; - struct v4l2_plane *psrc = &b->m.planes[plane]; - - if (psrc->bytesused == 0) - vb2_warn_zero_bytesused(vb); - - if (vb->vb2_queue->allow_zero_bytesused) - pdst->bytesused = psrc->bytesused; - else - pdst->bytesused = psrc->bytesused ? - psrc->bytesused : pdst->length; - pdst->data_offset = psrc->data_offset; - } + break; + case VB2_MEMORY_DMABUF: + for (plane = 0; plane < vb->num_planes; ++plane) { + planes[plane].m.fd = b->planes[plane].m.dmabuf.fd; + planes[plane].dbuf_offset = b->planes[plane].m.dmabuf.offset; + planes[plane].length = b->planes[plane].length; } - } else { + break; + default: + for (plane = 0; plane < vb->num_planes; ++plane) { + planes[plane].m.offset = vb->planes[plane].m.offset; + planes[plane].length = vb->planes[plane].length; + } + break; + } + + /* Fill in driver-provided information for OUTPUT types */ + if (V4L2_TYPE_IS_OUTPUT(b->type)) { /* - * Single-planar buffers do not use planes array, - * so fill in relevant v4l2_buffer struct fields instead. - * In videobuf we use our internal V4l2_planes struct for - * single-planar buffers as well, for simplicity. + * Will have to go up to b->length when API starts + * accepting variable number of planes. * - * If bytesused == 0 for the output buffer, then fall back - * to the full buffer size as that's a sensible default. + * If bytesused == 0 for the output buffer, then fall + * back to the full buffer size. In that case + * userspace clearly never bothered to set it and + * it's a safe assumption that they really meant to + * use the full plane sizes. * - * Some drivers, e.g. old codec drivers, use bytesused == 0 as - * a way to indicate that streaming is finished. In that case, - * the driver should use the allow_zero_bytesused flag to keep - * old userspace applications working. + * Some drivers, e.g. old codec drivers, use bytesused == 0 + * as a way to indicate that streaming is finished. + * In that case, the driver should use the + * allow_zero_bytesused flag to keep old userspace + * applications working. */ - switch (b->memory) { - case VB2_MEMORY_USERPTR: - planes[0].m.userptr = b->m.userptr; - planes[0].length = b->length; - break; - case VB2_MEMORY_DMABUF: - planes[0].m.fd = b->m.fd; - planes[0].length = b->length; - break; - default: - planes[0].m.offset = vb->planes[0].m.offset; - planes[0].length = vb->planes[0].length; - break; - } + for (plane = 0; plane < vb->num_planes; ++plane) { + struct vb2_plane *pdst = &planes[plane]; + struct v4l2_ext_plane *psrc = &b->planes[plane]; - planes[0].data_offset = 0; - if (V4L2_TYPE_IS_OUTPUT(b->type)) { - if (b->bytesused == 0) + if (psrc->bytesused == 0) vb2_warn_zero_bytesused(vb); if (vb->vb2_queue->allow_zero_bytesused) - planes[0].bytesused = b->bytesused; + pdst->bytesused = psrc->bytesused; else - planes[0].bytesused = b->bytesused ? - b->bytesused : planes[0].length; - } else - planes[0].bytesused = 0; - + pdst->bytesused = psrc->bytesused ? + psrc->bytesused : + pdst->length; + pdst->data_offset = psrc->data_offset; + } } /* Zero flags that we handle */ @@ -331,8 +260,21 @@ static int vb2_fill_vb2_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b return 0; } +enum v4l2_buf_type vb2_ext_qtype(struct vb2_queue *q) +{ + if (!q->is_multiplanar) + return q->type; + + if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + return V4L2_BUF_TYPE_VIDEO_CAPTURE; + else if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) + return V4L2_BUF_TYPE_VIDEO_OUTPUT; + + return q->type; +} + static int vb2_queue_or_prepare_buf(struct vb2_queue *q, struct media_device *mdev, - struct v4l2_buffer *b, bool is_prepare, + struct v4l2_ext_buffer *b, bool is_prepare, struct media_request **p_req) { const char *opname = is_prepare ? "prepare_buf" : "qbuf"; @@ -341,7 +283,7 @@ static int vb2_queue_or_prepare_buf(struct vb2_queue *q, struct media_device *md struct vb2_buffer *vb; int ret; - if (b->type != q->type) { + if (b->type != vb2_ext_qtype(q)) { dprintk(1, "%s: invalid buffer type\n", opname); return -EINVAL; } @@ -458,12 +400,12 @@ static int vb2_queue_or_prepare_buf(struct vb2_queue *q, struct media_device *md } /* - * __fill_v4l2_buffer() - fill in a struct v4l2_buffer with information to be - * returned to userspace + * __fill_v4l2_buffer() - fill in a struct v4l2_ext_buffer with information to + * be returned to userspace */ static void __fill_v4l2_buffer(struct vb2_buffer *vb, void *pb) { - struct v4l2_buffer *b = pb; + struct v4l2_ext_buffer *b = pb; struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); struct vb2_queue *q = vb->vb2_queue; unsigned int plane; @@ -472,50 +414,35 @@ static void __fill_v4l2_buffer(struct vb2_buffer *vb, void *pb) b->index = vb->index; b->type = vb->type; b->memory = vb->memory; - b->bytesused = 0; b->flags = vbuf->flags; b->field = vbuf->field; - b->timestamp = ns_to_timeval(vb->timestamp); - b->timecode = vbuf->timecode; + b->timestamp = vb->timestamp; b->sequence = vbuf->sequence; - b->reserved2 = 0; b->request_fd = 0; + memset(b->reserved, 0, sizeof(b->reserved)); - if (q->is_multiplanar) { - /* - * Fill in plane-related data if userspace provided an array - * for it. The caller has already verified memory and size. - */ - b->length = vb->num_planes; - for (plane = 0; plane < vb->num_planes; ++plane) { - struct v4l2_plane *pdst = &b->m.planes[plane]; - struct vb2_plane *psrc = &vb->planes[plane]; + /* + * Fill in plane-related data if userspace provided an array + * for it. The caller has already verified memory and size. + */ + b->num_planes = vb->num_planes; + for (plane = 0; plane < vb->num_planes; ++plane) { + struct v4l2_ext_plane *pdst = &b->planes[plane]; + struct vb2_plane *psrc = &vb->planes[plane]; - pdst->bytesused = psrc->bytesused; - pdst->length = psrc->length; - if (q->memory == VB2_MEMORY_MMAP) - pdst->m.mem_offset = psrc->m.offset; - else if (q->memory == VB2_MEMORY_USERPTR) - pdst->m.userptr = psrc->m.userptr; - else if (q->memory == VB2_MEMORY_DMABUF) - pdst->m.fd = psrc->m.fd; - pdst->data_offset = psrc->data_offset; - memset(pdst->reserved, 0, sizeof(pdst->reserved)); + pdst->bytesused = psrc->bytesused; + pdst->length = psrc->length; + if (q->memory == VB2_MEMORY_MMAP) { + pdst->m.mem_offset = psrc->m.offset; + } else if (q->memory == VB2_MEMORY_USERPTR) { + pdst->m.userptr = psrc->m.userptr; + } else if (q->memory == VB2_MEMORY_DMABUF) { + pdst->m.dmabuf.fd = psrc->m.fd; + pdst->m.dmabuf.offset = psrc->dbuf_offset; } - } else { - /* - * We use length and offset in v4l2_planes array even for - * single-planar buffers, but userspace does not. - */ - b->length = vb->planes[0].length; - b->bytesused = vb->planes[0].bytesused; - if (q->memory == VB2_MEMORY_MMAP) - b->m.offset = vb->planes[0].m.offset; - else if (q->memory == VB2_MEMORY_USERPTR) - b->m.userptr = vb->planes[0].m.userptr; - else if (q->memory == VB2_MEMORY_DMABUF) - b->m.fd = vb->planes[0].m.fd; + pdst->data_offset = psrc->data_offset; + memset(pdst->reserved, 0, sizeof(pdst->reserved)); } /* @@ -610,6 +537,40 @@ int vb2_find_timestamp(const struct vb2_queue *q, u64 timestamp, } EXPORT_SYMBOL_GPL(vb2_find_timestamp); +#define vb2_buf_to_ext_buf_op(_name, ...) \ +({ \ + int ret; \ + \ + ret = v4l2_buffer_to_ext_buffer(b, &eb); \ + if (!ret) \ + ret = _name(__VA_ARGS__); \ + if (!ret) \ + v4l2_ext_buffer_to_buffer(&eb, b, q->is_multiplanar); \ + ret; \ +}) + +int vb2_ext_querybuf(struct vb2_queue *q, struct v4l2_ext_buffer *b) +{ + struct vb2_buffer *vb; + int ret; + + if (b->type != vb2_ext_qtype(q)) { + dprintk(1, "wrong buffer type\n"); + return -EINVAL; + } + + if (b->index >= q->num_buffers) { + dprintk(1, "buffer index out of range\n"); + return -EINVAL; + } + vb = q->bufs[b->index]; + ret = __verify_planes_array(vb, b); + if (!ret) + vb2_core_querybuf(q, b->index, b); + return ret; +} +EXPORT_SYMBOL(vb2_ext_querybuf); + /* * vb2_querybuf() - query video buffer information * @q: videobuf queue @@ -625,23 +586,9 @@ EXPORT_SYMBOL_GPL(vb2_find_timestamp); */ int vb2_querybuf(struct vb2_queue *q, struct v4l2_buffer *b) { - struct vb2_buffer *vb; - int ret; + struct v4l2_ext_buffer eb; - if (b->type != q->type) { - dprintk(1, "wrong buffer type\n"); - return -EINVAL; - } - - if (b->index >= q->num_buffers) { - dprintk(1, "buffer index out of range\n"); - return -EINVAL; - } - vb = q->bufs[b->index]; - ret = __verify_planes_array(vb, b); - if (!ret) - vb2_core_querybuf(q, b->index, b); - return ret; + return vb2_buf_to_ext_buf_op(vb2_ext_querybuf, q, &eb); } EXPORT_SYMBOL(vb2_querybuf); @@ -669,8 +616,8 @@ int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) } EXPORT_SYMBOL_GPL(vb2_reqbufs); -int vb2_prepare_buf(struct vb2_queue *q, struct media_device *mdev, - struct v4l2_buffer *b) +int vb2_ext_prepare_buf(struct vb2_queue *q, struct media_device *mdev, + struct v4l2_ext_buffer *b) { int ret; @@ -686,13 +633,23 @@ int vb2_prepare_buf(struct vb2_queue *q, struct media_device *mdev, return ret ? ret : vb2_core_prepare_buf(q, b->index, b); } +EXPORT_SYMBOL_GPL(vb2_ext_prepare_buf); + +int vb2_prepare_buf(struct vb2_queue *q, struct media_device *mdev, + struct v4l2_buffer *b) +{ + struct v4l2_ext_buffer eb; + + return vb2_buf_to_ext_buf_op(vb2_ext_prepare_buf, q, mdev, &eb); +} EXPORT_SYMBOL_GPL(vb2_prepare_buf); -int vb2_create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create) +int vb2_ext_create_bufs(struct vb2_queue *q, + struct v4l2_ext_create_buffers *create) { unsigned requested_planes = 1; unsigned requested_sizes[VIDEO_MAX_PLANES]; - struct v4l2_format *f = &create->format; + struct v4l2_ext_format *f = &create->format; int ret = vb2_verify_memory_type(q, create->memory, f->type); unsigned i; @@ -702,19 +659,15 @@ int vb2_create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create) return ret != -EBUSY ? ret : 0; switch (f->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - requested_planes = f->fmt.pix_mp.num_planes; + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + requested_planes = f->fmt.pix.num_planes; if (requested_planes == 0 || requested_planes > VIDEO_MAX_PLANES) return -EINVAL; for (i = 0; i < requested_planes; i++) requested_sizes[i] = - f->fmt.pix_mp.plane_fmt[i].sizeimage; - break; - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - case V4L2_BUF_TYPE_VIDEO_OUTPUT: - requested_sizes[0] = f->fmt.pix.sizeimage; + f->fmt.pix.plane_fmt[i].sizeimage; break; case V4L2_BUF_TYPE_VBI_CAPTURE: case V4L2_BUF_TYPE_VBI_OUTPUT: @@ -742,10 +695,34 @@ int vb2_create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create) return ret ? ret : vb2_core_create_bufs(q, create->memory, &create->count, requested_planes, requested_sizes); } +EXPORT_SYMBOL_GPL(vb2_ext_create_bufs); + +int vb2_create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create) +{ + struct v4l2_ext_create_buffers ecreate = { + .count = create->count, + .memory = create->memory, + }; + int ret; + + ret = v4l2_format_to_ext_format(&create->format, + &ecreate.format, true); + if (ret) + return ret; + + ret = vb2_ext_create_bufs(q, &ecreate); + if (ret) + return ret; + + create->index = ecreate.index; + create->count = ecreate.count; + create->capabilities = ecreate.capabilities; + return 0; +} EXPORT_SYMBOL_GPL(vb2_create_bufs); -int vb2_qbuf(struct vb2_queue *q, struct media_device *mdev, - struct v4l2_buffer *b) +int vb2_ext_qbuf(struct vb2_queue *q, struct media_device *mdev, + struct v4l2_ext_buffer *b) { struct media_request *req = NULL; int ret; @@ -763,9 +740,19 @@ int vb2_qbuf(struct vb2_queue *q, struct media_device *mdev, media_request_put(req); return ret; } +EXPORT_SYMBOL_GPL(vb2_ext_qbuf); + +int vb2_qbuf(struct vb2_queue *q, struct media_device *mdev, + struct v4l2_buffer *b) +{ + struct v4l2_ext_buffer eb; + + return vb2_buf_to_ext_buf_op(vb2_ext_qbuf, q, mdev, &eb); +} EXPORT_SYMBOL_GPL(vb2_qbuf); -int vb2_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, bool nonblocking) +int vb2_ext_dqbuf(struct vb2_queue *q, struct v4l2_ext_buffer *b, + bool nonblocking) { int ret; @@ -774,7 +761,7 @@ int vb2_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, bool nonblocking) return -EBUSY; } - if (b->type != q->type) { + if (b->type != vb2_ext_qtype(q)) { dprintk(1, "invalid buffer type\n"); return -EINVAL; } @@ -794,8 +781,17 @@ int vb2_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, bool nonblocking) return ret; } +EXPORT_SYMBOL_GPL(vb2_ext_dqbuf); + +int vb2_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, bool nonblocking) +{ + struct v4l2_ext_buffer eb; + + return vb2_buf_to_ext_buf_op(vb2_ext_dqbuf, q, &eb, nonblocking); +} EXPORT_SYMBOL_GPL(vb2_dqbuf); + int vb2_streamon(struct vb2_queue *q, enum v4l2_buf_type type) { if (vb2_fileio_is_active(q)) { @@ -823,6 +819,37 @@ int vb2_expbuf(struct vb2_queue *q, struct v4l2_exportbuffer *eb) } EXPORT_SYMBOL_GPL(vb2_expbuf); +int vb2_ext_expbuf(struct vb2_queue *q, struct v4l2_ext_exportbuffer *eb) +{ + unsigned int i; + int ret; + + for (i = eb->first_plane; i < eb->first_plane + eb->num_planes; i++) { + ret = vb2_core_expbuf(q, &eb->fds[i], eb->type, eb->index, + i, eb->flags); + if (ret) + goto err_put_dmabufs; + } + + return 0; + +err_put_dmabufs: + for (; i > eb->first_plane; i--) { + struct dma_buf *dmabuf; + + /* + * FIXME: Find a better way to close the FD returned by + * dma_buf_fb(). + */ + dmabuf = dma_buf_get(eb->fds[i - 1]); + dma_buf_put(dmabuf); + dma_buf_put(dmabuf); + } + + return ret; +} +EXPORT_SYMBOL_GPL(vb2_ext_expbuf); + int vb2_queue_init(struct vb2_queue *q) { /* @@ -951,6 +978,33 @@ int vb2_ioctl_create_bufs(struct file *file, void *priv, } EXPORT_SYMBOL_GPL(vb2_ioctl_create_bufs); +int vb2_ioctl_ext_create_bufs(struct file *file, void *priv, + struct v4l2_ext_create_buffers *p) +{ + struct video_device *vdev = video_devdata(file); + int res = vb2_verify_memory_type(vdev->queue, p->memory, + p->format.type); + + p->index = vdev->queue->num_buffers; + fill_buf_caps(vdev->queue, &p->capabilities); + /* + * If count == 0, then just check if memory and type are valid. + * Any -EBUSY result from vb2_verify_memory_type can be mapped to 0. + */ + if (p->count == 0) + return res != -EBUSY ? res : 0; + if (res) + return res; + if (vb2_queue_is_busy(vdev, file)) + return -EBUSY; + + res = vb2_ext_create_bufs(vdev->queue, p); + if (res == 0) + vdev->queue->owner = file->private_data; + return res; +} +EXPORT_SYMBOL_GPL(vb2_ioctl_ext_create_bufs); + int vb2_ioctl_prepare_buf(struct file *file, void *priv, struct v4l2_buffer *p) { @@ -962,6 +1016,17 @@ int vb2_ioctl_prepare_buf(struct file *file, void *priv, } EXPORT_SYMBOL_GPL(vb2_ioctl_prepare_buf); +int vb2_ioctl_ext_prepare_buf(struct file *file, void *priv, + struct v4l2_ext_buffer *p) +{ + struct video_device *vdev = video_devdata(file); + + if (vb2_queue_is_busy(vdev, file)) + return -EBUSY; + return vb2_ext_prepare_buf(vdev->queue, vdev->v4l2_dev->mdev, p); +} +EXPORT_SYMBOL_GPL(vb2_ioctl_ext_prepare_buf); + int vb2_ioctl_querybuf(struct file *file, void *priv, struct v4l2_buffer *p) { struct video_device *vdev = video_devdata(file); @@ -971,6 +1036,16 @@ int vb2_ioctl_querybuf(struct file *file, void *priv, struct v4l2_buffer *p) } EXPORT_SYMBOL_GPL(vb2_ioctl_querybuf); +int vb2_ioctl_ext_querybuf(struct file *file, void *priv, + struct v4l2_ext_buffer *p) +{ + struct video_device *vdev = video_devdata(file); + + /* No need to call vb2_queue_is_busy(), anyone can query buffers. */ + return vb2_ext_querybuf(vdev->queue, p); +} +EXPORT_SYMBOL_GPL(vb2_ioctl_ext_querybuf); + int vb2_ioctl_qbuf(struct file *file, void *priv, struct v4l2_buffer *p) { struct video_device *vdev = video_devdata(file); @@ -981,6 +1056,17 @@ int vb2_ioctl_qbuf(struct file *file, void *priv, struct v4l2_buffer *p) } EXPORT_SYMBOL_GPL(vb2_ioctl_qbuf); +int vb2_ioctl_ext_qbuf(struct file *file, void *priv, + struct v4l2_ext_buffer *p) +{ + struct video_device *vdev = video_devdata(file); + + if (vb2_queue_is_busy(vdev, file)) + return -EBUSY; + return vb2_ext_qbuf(vdev->queue, vdev->v4l2_dev->mdev, p); +} +EXPORT_SYMBOL_GPL(vb2_ioctl_ext_qbuf); + int vb2_ioctl_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p) { struct video_device *vdev = video_devdata(file); @@ -991,6 +1077,17 @@ int vb2_ioctl_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p) } EXPORT_SYMBOL_GPL(vb2_ioctl_dqbuf); +int vb2_ioctl_ext_dqbuf(struct file *file, void *priv, + struct v4l2_ext_buffer *p) +{ + struct video_device *vdev = video_devdata(file); + + if (vb2_queue_is_busy(vdev, file)) + return -EBUSY; + return vb2_ext_dqbuf(vdev->queue, p, file->f_flags & O_NONBLOCK); +} +EXPORT_SYMBOL_GPL(vb2_ioctl_ext_dqbuf); + int vb2_ioctl_streamon(struct file *file, void *priv, enum v4l2_buf_type i) { struct video_device *vdev = video_devdata(file); @@ -1021,6 +1118,17 @@ int vb2_ioctl_expbuf(struct file *file, void *priv, struct v4l2_exportbuffer *p) } EXPORT_SYMBOL_GPL(vb2_ioctl_expbuf); +int vb2_ioctl_ext_expbuf(struct file *file, void *priv, + struct v4l2_ext_exportbuffer *p) +{ + struct video_device *vdev = video_devdata(file); + + if (vb2_queue_is_busy(vdev, file)) + return -EBUSY; + return vb2_ext_expbuf(vdev->queue, p); +} +EXPORT_SYMBOL_GPL(vb2_ioctl_ext_expbuf); + /* v4l2_file_operations helpers */ int vb2_fop_mmap(struct file *file, struct vm_area_struct *vma) diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h index 640aabe69450..6411fb2c89fe 100644 --- a/include/media/videobuf2-core.h +++ b/include/media/videobuf2-core.h @@ -152,6 +152,8 @@ struct vb2_mem_ops { * @mem_priv: private data with this plane. * @dbuf: dma_buf - shared buffer object. * @dbuf_mapped: flag to show whether dbuf is mapped or not + * @dbuf_offset: offset where the plane starts. Usually 0, unless the buffer + * is shared by all planes of a multi-planar format. * @bytesused: number of bytes occupied by data in the plane (payload). * @length: size of this plane (NOT the payload) in bytes. * @min_length: minimum required size of this plane (NOT the payload) in bytes. @@ -175,6 +177,7 @@ struct vb2_plane { void *mem_priv; struct dma_buf *dbuf; unsigned int dbuf_mapped; + unsigned int dbuf_offset; unsigned int bytesused; unsigned int length; unsigned int min_length; @@ -440,7 +443,8 @@ struct vb2_ops { * struct vb2_buffer. * For V4L2 this is a &struct vb2_v4l2_buffer. * @fill_user_buffer: given a &vb2_buffer fill in the userspace structure. - * For V4L2 this is a &struct v4l2_buffer. + * For V4L2 this is a &struct v4l2_buffer or + * &struct v4l2_ext_buffer. * @fill_vb2_buffer: given a userspace structure, fill in the &vb2_buffer. * If the userspace structure is invalid, then this op * will return an error. diff --git a/include/media/videobuf2-v4l2.h b/include/media/videobuf2-v4l2.h index 8a10889dc2fd..99eff4639dc5 100644 --- a/include/media/videobuf2-v4l2.h +++ b/include/media/videobuf2-v4l2.h @@ -36,7 +36,7 @@ * @planes: plane information (userptr/fd, length, bytesused, data_offset). * * Should contain enough information to be able to cover all the fields - * of &struct v4l2_buffer at ``videodev2.h``. + * of &struct v4l2_buffer and &struct v4l2_ext_buffer at ``videodev2.h``. */ struct vb2_v4l2_buffer { struct vb2_buffer vb2_buf; @@ -72,6 +72,7 @@ int vb2_find_timestamp(const struct vb2_queue *q, u64 timestamp, unsigned int start_idx); int vb2_querybuf(struct vb2_queue *q, struct v4l2_buffer *b); +int vb2_ext_querybuf(struct vb2_queue *q, struct v4l2_ext_buffer *b); /** * vb2_reqbufs() - Wrapper for vb2_core_reqbufs() that also verifies @@ -92,6 +93,8 @@ int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req); * &v4l2_ioctl_ops->vidioc_create_bufs handler in driver */ int vb2_create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create); +int vb2_ext_create_bufs(struct vb2_queue *q, + struct v4l2_ext_create_buffers *create); /** * vb2_prepare_buf() - Pass ownership of a buffer from userspace to the kernel @@ -117,6 +120,8 @@ int vb2_create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create); */ int vb2_prepare_buf(struct vb2_queue *q, struct media_device *mdev, struct v4l2_buffer *b); +int vb2_ext_prepare_buf(struct vb2_queue *q, struct media_device *mdev, + struct v4l2_ext_buffer *b); /** * vb2_qbuf() - Queue a buffer from userspace @@ -143,6 +148,8 @@ int vb2_prepare_buf(struct vb2_queue *q, struct media_device *mdev, */ int vb2_qbuf(struct vb2_queue *q, struct media_device *mdev, struct v4l2_buffer *b); +int vb2_ext_qbuf(struct vb2_queue *q, struct media_device *mdev, + struct v4l2_ext_buffer *b); /** * vb2_expbuf() - Export a buffer as a file descriptor @@ -154,6 +161,7 @@ int vb2_qbuf(struct vb2_queue *q, struct media_device *mdev, * from &v4l2_ioctl_ops->vidioc_expbuf handler in driver. */ int vb2_expbuf(struct vb2_queue *q, struct v4l2_exportbuffer *eb); +int vb2_ext_expbuf(struct vb2_queue *q, struct v4l2_ext_exportbuffer *eb); /** * vb2_dqbuf() - Dequeue a buffer to the userspace @@ -180,6 +188,8 @@ int vb2_expbuf(struct vb2_queue *q, struct v4l2_exportbuffer *eb); * from &v4l2_ioctl_ops->vidioc_dqbuf handler in driver. */ int vb2_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, bool nonblocking); +int vb2_ext_dqbuf(struct vb2_queue *q, struct v4l2_ext_buffer *b, + bool nonblocking); /** * vb2_streamon - start streaming @@ -276,15 +286,27 @@ int vb2_ioctl_reqbufs(struct file *file, void *priv, struct v4l2_requestbuffers *p); int vb2_ioctl_create_bufs(struct file *file, void *priv, struct v4l2_create_buffers *p); +int vb2_ioctl_ext_create_bufs(struct file *file, void *priv, + struct v4l2_ext_create_buffers *p); int vb2_ioctl_prepare_buf(struct file *file, void *priv, struct v4l2_buffer *p); +int vb2_ioctl_ext_prepare_buf(struct file *file, void *priv, + struct v4l2_ext_buffer *p); int vb2_ioctl_querybuf(struct file *file, void *priv, struct v4l2_buffer *p); +int vb2_ioctl_ext_querybuf(struct file *file, void *priv, + struct v4l2_ext_buffer *p); int vb2_ioctl_qbuf(struct file *file, void *priv, struct v4l2_buffer *p); +int vb2_ioctl_ext_qbuf(struct file *file, void *priv, + struct v4l2_ext_buffer *p); int vb2_ioctl_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p); +int vb2_ioctl_ext_dqbuf(struct file *file, void *priv, + struct v4l2_ext_buffer *p); int vb2_ioctl_streamon(struct file *file, void *priv, enum v4l2_buf_type i); int vb2_ioctl_streamoff(struct file *file, void *priv, enum v4l2_buf_type i); int vb2_ioctl_expbuf(struct file *file, void *priv, - struct v4l2_exportbuffer *p); + struct v4l2_exportbuffer *p); +int vb2_ioctl_ext_expbuf(struct file *file, void *priv, + struct v4l2_ext_exportbuffer *p); /* struct v4l2_file_operations helpers */ From patchwork Tue Oct 8 09:11:17 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Boris Brezillon X-Patchwork-Id: 11179195 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 6B9D017D4 for ; Tue, 8 Oct 2019 09:11:29 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 4B056218AC for ; Tue, 8 Oct 2019 09:11:29 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729915AbfJHJL2 (ORCPT ); Tue, 8 Oct 2019 05:11:28 -0400 Received: from bhuna.collabora.co.uk ([46.235.227.227]:42890 "EHLO bhuna.collabora.co.uk" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728866AbfJHJL2 (ORCPT ); Tue, 8 Oct 2019 05:11:28 -0400 Received: from localhost.localdomain (unknown [IPv6:2a01:e0a:2c:6930:5cf4:84a1:2763:fe0d]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) (Authenticated sender: bbrezillon) by bhuna.collabora.co.uk (Postfix) with ESMTPSA id 9A57428F7F8; Tue, 8 Oct 2019 10:11:26 +0100 (BST) From: Boris Brezillon To: Mauro Carvalho Chehab , Hans Verkuil , Laurent Pinchart , Sakari Ailus , linux-media@vger.kernel.org Cc: Tomasz Figa , Hirokazu Honda , Nicolas Dufresne , Brian Starkey , kernel@collabora.com, Boris Brezillon Subject: [RFC PATCH v3 4/6] media: mediabus: Add an helper to convert a ext_pix format to an mbus_fmt Date: Tue, 8 Oct 2019 11:11:17 +0200 Message-Id: <20191008091119.7294-5-boris.brezillon@collabora.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20191008091119.7294-1-boris.brezillon@collabora.com> References: <20191008091119.7294-1-boris.brezillon@collabora.com> MIME-Version: 1.0 Sender: linux-media-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org Just a new version of v4l2_fill_mbus_format() to deal with the new v4l2_ext_pix_format struct. This is needed to convert the VIMC driver to the EXT_FMT/EXT_BUF iocts. Signed-off-by: Boris Brezillon --- Changes in v3: - Rebased on top of media/master (post 5.4-rc1) Changes in v2: - New patch --- include/media/v4l2-mediabus.h | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/include/media/v4l2-mediabus.h b/include/media/v4l2-mediabus.h index 45f88f0248c4..00de5ae05e84 100644 --- a/include/media/v4l2-mediabus.h +++ b/include/media/v4l2-mediabus.h @@ -182,4 +182,26 @@ v4l2_fill_mbus_format_mplane(struct v4l2_mbus_framefmt *mbus_fmt, mbus_fmt->xfer_func = pix_mp_fmt->xfer_func; } +/** + * v4l2_fill_mbus_format_ext - Ancillary routine that fills a &struct + * v4l2_mbus_framefmt from a &struct v4l2_ext_pix_format. + * + * @mbus_fmt: pointer to &struct v4l2_mbus_framefmt to be filled + * @pix_fmt: pointer to &struct v4l2_ext_pix_format to be used as model + * @code: data format code (from &enum v4l2_mbus_pixelcode) + */ +static inline void +v4l2_fill_mbus_format_ext(struct v4l2_mbus_framefmt *mbus_fmt, + const struct v4l2_ext_pix_format *pix_fmt, u32 code) +{ + mbus_fmt->width = pix_fmt->width; + mbus_fmt->height = pix_fmt->height; + mbus_fmt->field = pix_fmt->field; + mbus_fmt->colorspace = pix_fmt->colorspace; + mbus_fmt->ycbcr_enc = pix_fmt->ycbcr_enc; + mbus_fmt->quantization = pix_fmt->quantization; + mbus_fmt->xfer_func = pix_fmt->xfer_func; + mbus_fmt->code = code; +} + #endif From patchwork Tue Oct 8 09:11:18 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Boris Brezillon X-Patchwork-Id: 11179201 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 7C33415AB for ; Tue, 8 Oct 2019 09:11:31 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 417E621871 for ; Tue, 8 Oct 2019 09:11:31 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730013AbfJHJLa (ORCPT ); Tue, 8 Oct 2019 05:11:30 -0400 Received: from bhuna.collabora.co.uk ([46.235.227.227]:42896 "EHLO bhuna.collabora.co.uk" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729879AbfJHJL3 (ORCPT ); Tue, 8 Oct 2019 05:11:29 -0400 Received: from localhost.localdomain (unknown [IPv6:2a01:e0a:2c:6930:5cf4:84a1:2763:fe0d]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) (Authenticated sender: bbrezillon) by bhuna.collabora.co.uk (Postfix) with ESMTPSA id 0E05628F7FF; Tue, 8 Oct 2019 10:11:27 +0100 (BST) From: Boris Brezillon To: Mauro Carvalho Chehab , Hans Verkuil , Laurent Pinchart , Sakari Ailus , linux-media@vger.kernel.org Cc: Tomasz Figa , Hirokazu Honda , Nicolas Dufresne , Brian Starkey , kernel@collabora.com, Boris Brezillon Subject: [RFC PATCH v3 5/6] media: vivid: Convert the capture and output drivers to EXT_FMT/EXT_BUF Date: Tue, 8 Oct 2019 11:11:18 +0200 Message-Id: <20191008091119.7294-6-boris.brezillon@collabora.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20191008091119.7294-1-boris.brezillon@collabora.com> References: <20191008091119.7294-1-boris.brezillon@collabora.com> MIME-Version: 1.0 Sender: linux-media-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org This should simplify things a bit as we now have a single implementation instead of the MPLANE and !MPLANE versions. Signed-off-by: Boris Brezillon --- Changes in v3: - Rebased on top of media/master (post 5.4-rc1) Changes in v2: - New patch --- drivers/media/platform/vivid/vivid-core.c | 30 ++- drivers/media/platform/vivid/vivid-vid-cap.c | 171 +++++----------- drivers/media/platform/vivid/vivid-vid-cap.h | 15 +- drivers/media/platform/vivid/vivid-vid-out.c | 195 +++++++------------ drivers/media/platform/vivid/vivid-vid-out.h | 15 +- 5 files changed, 142 insertions(+), 284 deletions(-) diff --git a/drivers/media/platform/vivid/vivid-core.c b/drivers/media/platform/vivid/vivid-core.c index 53315c8dd2bb..502c1bf6f272 100644 --- a/drivers/media/platform/vivid/vivid-core.c +++ b/drivers/media/platform/vivid/vivid-core.c @@ -501,20 +501,14 @@ static const struct v4l2_ioctl_ops vivid_ioctl_ops = { .vidioc_querycap = vidioc_querycap, .vidioc_enum_fmt_vid_cap = vivid_enum_fmt_vid, - .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, - .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, - .vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt_vid_cap_mplane, - .vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt_vid_cap_mplane, - .vidioc_s_fmt_vid_cap_mplane = vidioc_s_fmt_vid_cap_mplane, + .vidioc_g_ext_fmt_vid_cap = vivid_g_fmt_vid_cap, + .vidioc_try_ext_fmt_vid_cap = vivid_try_fmt_vid_cap, + .vidioc_s_ext_fmt_vid_cap = vivid_s_fmt_vid_cap, .vidioc_enum_fmt_vid_out = vivid_enum_fmt_vid, - .vidioc_g_fmt_vid_out = vidioc_g_fmt_vid_out, - .vidioc_try_fmt_vid_out = vidioc_try_fmt_vid_out, - .vidioc_s_fmt_vid_out = vidioc_s_fmt_vid_out, - .vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt_vid_out_mplane, - .vidioc_try_fmt_vid_out_mplane = vidioc_try_fmt_vid_out_mplane, - .vidioc_s_fmt_vid_out_mplane = vidioc_s_fmt_vid_out_mplane, + .vidioc_g_ext_fmt_vid_out = vivid_g_fmt_vid_out, + .vidioc_try_ext_fmt_vid_out = vivid_try_fmt_vid_out, + .vidioc_s_ext_fmt_vid_out = vivid_s_fmt_vid_out, .vidioc_g_selection = vidioc_g_selection, .vidioc_s_selection = vidioc_s_selection, @@ -559,12 +553,12 @@ static const struct v4l2_ioctl_ops vivid_ioctl_ops = { .vidioc_s_fbuf = vidioc_s_fbuf, .vidioc_reqbufs = vb2_ioctl_reqbufs, - .vidioc_create_bufs = vb2_ioctl_create_bufs, - .vidioc_prepare_buf = vb2_ioctl_prepare_buf, - .vidioc_querybuf = vb2_ioctl_querybuf, - .vidioc_qbuf = vb2_ioctl_qbuf, - .vidioc_dqbuf = vb2_ioctl_dqbuf, - .vidioc_expbuf = vb2_ioctl_expbuf, + .vidioc_ext_create_bufs = vb2_ioctl_ext_create_bufs, + .vidioc_ext_prepare_buf = vb2_ioctl_ext_prepare_buf, + .vidioc_ext_querybuf = vb2_ioctl_ext_querybuf, + .vidioc_ext_qbuf = vb2_ioctl_ext_qbuf, + .vidioc_ext_dqbuf = vb2_ioctl_ext_dqbuf, + .vidioc_ext_expbuf = vb2_ioctl_ext_expbuf, .vidioc_streamon = vb2_ioctl_streamon, .vidioc_streamoff = vb2_ioctl_streamoff, diff --git a/drivers/media/platform/vivid/vivid-vid-cap.c b/drivers/media/platform/vivid/vivid-vid-cap.c index 2d030732feac..980ec26a512b 100644 --- a/drivers/media/platform/vivid/vivid-vid-cap.c +++ b/drivers/media/platform/vivid/vivid-vid-cap.c @@ -521,28 +521,27 @@ static unsigned vivid_quantization_cap(struct vivid_dev *dev) } int vivid_g_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) + struct v4l2_ext_pix_format *f) { struct vivid_dev *dev = video_drvdata(file); - struct v4l2_pix_format_mplane *mp = &f->fmt.pix_mp; unsigned p; - mp->width = dev->fmt_cap_rect.width; - mp->height = dev->fmt_cap_rect.height; - mp->field = dev->field_cap; - mp->pixelformat = dev->fmt_cap->fourcc; - mp->colorspace = vivid_colorspace_cap(dev); - mp->xfer_func = vivid_xfer_func_cap(dev); + f->width = dev->fmt_cap_rect.width; + f->height = dev->fmt_cap_rect.height; + f->field = dev->field_cap; + f->pixelformat = dev->fmt_cap->fourcc; + f->colorspace = vivid_colorspace_cap(dev); + f->xfer_func = vivid_xfer_func_cap(dev); if (dev->fmt_cap->color_enc == TGP_COLOR_ENC_HSV) - mp->hsv_enc = vivid_hsv_enc_cap(dev); + f->hsv_enc = vivid_hsv_enc_cap(dev); else - mp->ycbcr_enc = vivid_ycbcr_enc_cap(dev); - mp->quantization = vivid_quantization_cap(dev); - mp->num_planes = dev->fmt_cap->buffers; - for (p = 0; p < mp->num_planes; p++) { - mp->plane_fmt[p].bytesperline = tpg_g_bytesperline(&dev->tpg, p); - mp->plane_fmt[p].sizeimage = - (tpg_g_line_width(&dev->tpg, p) * mp->height) / + f->ycbcr_enc = vivid_ycbcr_enc_cap(dev); + f->quantization = vivid_quantization_cap(dev); + f->num_planes = dev->fmt_cap->buffers; + for (p = 0; p < f->num_planes; p++) { + f->plane_fmt[p].bytesperline = tpg_g_bytesperline(&dev->tpg, p); + f->plane_fmt[p].sizeimage = + (tpg_g_line_width(&dev->tpg, p) * f->height) / dev->fmt_cap->vdownsampling[p] + dev->fmt_cap->data_offset[p]; } @@ -550,31 +549,30 @@ int vivid_g_fmt_vid_cap(struct file *file, void *priv, } int vivid_try_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) + struct v4l2_ext_pix_format *f) { - struct v4l2_pix_format_mplane *mp = &f->fmt.pix_mp; - struct v4l2_plane_pix_format *pfmt = mp->plane_fmt; struct vivid_dev *dev = video_drvdata(file); + struct v4l2_plane_ext_pix_format *pfmt = f->plane_fmt; const struct vivid_fmt *fmt; unsigned bytesperline, max_bpl; unsigned factor = 1; unsigned w, h; unsigned p; - fmt = vivid_get_format(dev, mp->pixelformat); + fmt = vivid_get_format(dev, f->pixelformat); if (!fmt) { dprintk(dev, 1, "Fourcc format (0x%08x) unknown.\n", - mp->pixelformat); - mp->pixelformat = V4L2_PIX_FMT_YUYV; - fmt = vivid_get_format(dev, mp->pixelformat); + f->pixelformat); + f->pixelformat = V4L2_PIX_FMT_YUYV; + fmt = vivid_get_format(dev, f->pixelformat); } - mp->field = vivid_field_cap(dev, mp->field); + f->field = vivid_field_cap(dev, f->field); if (vivid_is_webcam(dev)) { const struct v4l2_frmsize_discrete *sz = v4l2_find_nearest_size(webcam_sizes, VIVID_WEBCAM_SIZES, width, - height, mp->width, mp->height); + height, f->width, f->height); w = sz->width; h = sz->height; @@ -585,14 +583,14 @@ int vivid_try_fmt_vid_cap(struct file *file, void *priv, w = dev->src_rect.width; h = dev->src_rect.height; } - if (V4L2_FIELD_HAS_T_OR_B(mp->field)) + if (V4L2_FIELD_HAS_T_OR_B(f->field)) factor = 2; if (vivid_is_webcam(dev) || (!dev->has_scaler_cap && !dev->has_crop_cap && !dev->has_compose_cap)) { - mp->width = w; - mp->height = h / factor; + f->width = w; + f->height = h / factor; } else { - struct v4l2_rect r = { 0, 0, mp->width, mp->height * factor }; + struct v4l2_rect r = { 0, 0, f->width, f->height * factor }; v4l2_rect_set_min_size(&r, &vivid_min_rect); v4l2_rect_set_max_size(&r, &vivid_max_rect); @@ -605,16 +603,16 @@ int vivid_try_fmt_vid_cap(struct file *file, void *priv, } else if (!dev->has_scaler_cap && !dev->has_crop_cap) { v4l2_rect_set_min_size(&r, &dev->src_rect); } - mp->width = r.width; - mp->height = r.height / factor; + f->width = r.width; + f->height = r.height / factor; } /* This driver supports custom bytesperline values */ - mp->num_planes = fmt->buffers; + f->num_planes = fmt->buffers; for (p = 0; p < fmt->buffers; p++) { /* Calculate the minimum supported bytesperline value */ - bytesperline = (mp->width * fmt->bit_depth[p]) >> 3; + bytesperline = (f->width * fmt->bit_depth[p]) >> 3; /* Calculate the maximum supported bytesperline value */ max_bpl = (MAX_ZOOM * MAX_WIDTH * fmt->bit_depth[p]) >> 3; @@ -623,31 +621,27 @@ int vivid_try_fmt_vid_cap(struct file *file, void *priv, if (pfmt[p].bytesperline < bytesperline) pfmt[p].bytesperline = bytesperline; - pfmt[p].sizeimage = (pfmt[p].bytesperline * mp->height) / + pfmt[p].sizeimage = (pfmt[p].bytesperline * f->height) / fmt->vdownsampling[p] + fmt->data_offset[p]; - - memset(pfmt[p].reserved, 0, sizeof(pfmt[p].reserved)); } for (p = fmt->buffers; p < fmt->planes; p++) - pfmt[0].sizeimage += (pfmt[0].bytesperline * mp->height * + pfmt[0].sizeimage += (pfmt[0].bytesperline * f->height * (fmt->bit_depth[p] / fmt->vdownsampling[p])) / (fmt->bit_depth[0] / fmt->vdownsampling[0]); - mp->colorspace = vivid_colorspace_cap(dev); + f->colorspace = vivid_colorspace_cap(dev); if (fmt->color_enc == TGP_COLOR_ENC_HSV) - mp->hsv_enc = vivid_hsv_enc_cap(dev); + f->hsv_enc = vivid_hsv_enc_cap(dev); else - mp->ycbcr_enc = vivid_ycbcr_enc_cap(dev); - mp->xfer_func = vivid_xfer_func_cap(dev); - mp->quantization = vivid_quantization_cap(dev); - memset(mp->reserved, 0, sizeof(mp->reserved)); + f->ycbcr_enc = vivid_ycbcr_enc_cap(dev); + f->xfer_func = vivid_xfer_func_cap(dev); + f->quantization = vivid_quantization_cap(dev); return 0; } int vivid_s_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) + struct v4l2_ext_pix_format *f) { - struct v4l2_pix_format_mplane *mp = &f->fmt.pix_mp; struct vivid_dev *dev = video_drvdata(file); struct v4l2_rect *crop = &dev->crop_cap; struct v4l2_rect *compose = &dev->compose_cap; @@ -665,20 +659,21 @@ int vivid_s_fmt_vid_cap(struct file *file, void *priv, return -EBUSY; } - if (dev->overlay_cap_owner && dev->fb_cap.fmt.pixelformat != mp->pixelformat) { + if (dev->overlay_cap_owner && + dev->fb_cap.fmt.pixelformat != f->pixelformat) { dprintk(dev, 1, "overlay is active, can't change pixelformat\n"); return -EBUSY; } - dev->fmt_cap = vivid_get_format(dev, mp->pixelformat); - if (V4L2_FIELD_HAS_T_OR_B(mp->field)) + dev->fmt_cap = vivid_get_format(dev, f->pixelformat); + if (V4L2_FIELD_HAS_T_OR_B(f->field)) factor = 2; /* Note: the webcam input doesn't support scaling, cropping or composing */ if (!vivid_is_webcam(dev) && (dev->has_scaler_cap || dev->has_crop_cap || dev->has_compose_cap)) { - struct v4l2_rect r = { 0, 0, mp->width, mp->height }; + struct v4l2_rect r = { 0, 0, f->width, f->height }; if (dev->has_scaler_cap) { if (dev->has_compose_cap) @@ -739,99 +734,39 @@ int vivid_s_fmt_vid_cap(struct file *file, void *priv, } else if (vivid_is_webcam(dev)) { /* Guaranteed to be a match */ for (i = 0; i < ARRAY_SIZE(webcam_sizes); i++) - if (webcam_sizes[i].width == mp->width && - webcam_sizes[i].height == mp->height) + if (webcam_sizes[i].width == f->width && + webcam_sizes[i].height == f->height) break; dev->webcam_size_idx = i; if (dev->webcam_ival_idx >= 2 * (VIVID_WEBCAM_SIZES - i)) dev->webcam_ival_idx = 2 * (VIVID_WEBCAM_SIZES - i) - 1; vivid_update_format_cap(dev, false); } else { - struct v4l2_rect r = { 0, 0, mp->width, mp->height }; + struct v4l2_rect r = { 0, 0, f->width, f->height }; v4l2_rect_set_size_to(compose, &r); r.height *= factor; v4l2_rect_set_size_to(crop, &r); } - dev->fmt_cap_rect.width = mp->width; - dev->fmt_cap_rect.height = mp->height; - tpg_s_buf_height(&dev->tpg, mp->height); + dev->fmt_cap_rect.width = f->width; + dev->fmt_cap_rect.height = f->height; + tpg_s_buf_height(&dev->tpg, f->height); tpg_s_fourcc(&dev->tpg, dev->fmt_cap->fourcc); for (p = 0; p < tpg_g_buffers(&dev->tpg); p++) - tpg_s_bytesperline(&dev->tpg, p, mp->plane_fmt[p].bytesperline); - dev->field_cap = mp->field; + tpg_s_bytesperline(&dev->tpg, p, f->plane_fmt[p].bytesperline); + dev->field_cap = f->field; if (dev->field_cap == V4L2_FIELD_ALTERNATE) tpg_s_field(&dev->tpg, V4L2_FIELD_TOP, true); else tpg_s_field(&dev->tpg, dev->field_cap, false); tpg_s_crop_compose(&dev->tpg, &dev->crop_cap, &dev->compose_cap); if (vivid_is_sdtv_cap(dev)) - dev->tv_field_cap = mp->field; + dev->tv_field_cap = f->field; tpg_update_mv_step(&dev->tpg); return 0; } -int vidioc_g_fmt_vid_cap_mplane(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct vivid_dev *dev = video_drvdata(file); - - if (!dev->multiplanar) - return -ENOTTY; - return vivid_g_fmt_vid_cap(file, priv, f); -} - -int vidioc_try_fmt_vid_cap_mplane(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct vivid_dev *dev = video_drvdata(file); - - if (!dev->multiplanar) - return -ENOTTY; - return vivid_try_fmt_vid_cap(file, priv, f); -} - -int vidioc_s_fmt_vid_cap_mplane(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct vivid_dev *dev = video_drvdata(file); - - if (!dev->multiplanar) - return -ENOTTY; - return vivid_s_fmt_vid_cap(file, priv, f); -} - -int vidioc_g_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct vivid_dev *dev = video_drvdata(file); - - if (dev->multiplanar) - return -ENOTTY; - return fmt_sp2mp_func(file, priv, f, vivid_g_fmt_vid_cap); -} - -int vidioc_try_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct vivid_dev *dev = video_drvdata(file); - - if (dev->multiplanar) - return -ENOTTY; - return fmt_sp2mp_func(file, priv, f, vivid_try_fmt_vid_cap); -} - -int vidioc_s_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct vivid_dev *dev = video_drvdata(file); - - if (dev->multiplanar) - return -ENOTTY; - return fmt_sp2mp_func(file, priv, f, vivid_s_fmt_vid_cap); -} - int vivid_vid_cap_g_selection(struct file *file, void *priv, struct v4l2_selection *sel) { diff --git a/drivers/media/platform/vivid/vivid-vid-cap.h b/drivers/media/platform/vivid/vivid-vid-cap.h index 1e422a59eeab..7c9fc5c787b5 100644 --- a/drivers/media/platform/vivid/vivid-vid-cap.h +++ b/drivers/media/platform/vivid/vivid-vid-cap.h @@ -17,15 +17,12 @@ extern const char * const vivid_ctrl_standard_strings[]; extern const struct vb2_ops vivid_vid_cap_qops; -int vivid_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f); -int vivid_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f); -int vivid_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f); -int vidioc_g_fmt_vid_cap_mplane(struct file *file, void *priv, struct v4l2_format *f); -int vidioc_try_fmt_vid_cap_mplane(struct file *file, void *priv, struct v4l2_format *f); -int vidioc_s_fmt_vid_cap_mplane(struct file *file, void *priv, struct v4l2_format *f); -int vidioc_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f); -int vidioc_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f); -int vidioc_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f); +int vivid_g_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_ext_pix_format *f); +int vivid_try_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_ext_pix_format *f); +int vivid_s_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_ext_pix_format *f); int vivid_vid_cap_g_selection(struct file *file, void *priv, struct v4l2_selection *sel); int vivid_vid_cap_s_selection(struct file *file, void *fh, struct v4l2_selection *s); int vivid_vid_cap_g_pixelaspect(struct file *file, void *priv, int type, struct v4l2_fract *f); diff --git a/drivers/media/platform/vivid/vivid-vid-out.c b/drivers/media/platform/vivid/vivid-vid-out.c index a0364ac497f9..792f3949870a 100644 --- a/drivers/media/platform/vivid/vivid-vid-out.c +++ b/drivers/media/platform/vivid/vivid-vid-out.c @@ -315,59 +315,57 @@ static enum tpg_pixel_aspect vivid_get_pixel_aspect(const struct vivid_dev *dev) } int vivid_g_fmt_vid_out(struct file *file, void *priv, - struct v4l2_format *f) + struct v4l2_ext_pix_format *f) { struct vivid_dev *dev = video_drvdata(file); - struct v4l2_pix_format_mplane *mp = &f->fmt.pix_mp; const struct vivid_fmt *fmt = dev->fmt_out; unsigned p; - mp->width = dev->fmt_out_rect.width; - mp->height = dev->fmt_out_rect.height; - mp->field = dev->field_out; - mp->pixelformat = fmt->fourcc; - mp->colorspace = dev->colorspace_out; - mp->xfer_func = dev->xfer_func_out; - mp->ycbcr_enc = dev->ycbcr_enc_out; - mp->quantization = dev->quantization_out; - mp->num_planes = fmt->buffers; - for (p = 0; p < mp->num_planes; p++) { - mp->plane_fmt[p].bytesperline = dev->bytesperline_out[p]; - mp->plane_fmt[p].sizeimage = - mp->plane_fmt[p].bytesperline * mp->height + + f->width = dev->fmt_out_rect.width; + f->height = dev->fmt_out_rect.height; + f->field = dev->field_out; + f->pixelformat = fmt->fourcc; + f->colorspace = dev->colorspace_out; + f->xfer_func = dev->xfer_func_out; + f->ycbcr_enc = dev->ycbcr_enc_out; + f->quantization = dev->quantization_out; + f->num_planes = fmt->buffers; + for (p = 0; p < f->num_planes; p++) { + f->plane_fmt[p].bytesperline = dev->bytesperline_out[p]; + f->plane_fmt[p].sizeimage = + f->plane_fmt[p].bytesperline * f->height + fmt->data_offset[p]; } for (p = fmt->buffers; p < fmt->planes; p++) { unsigned stride = dev->bytesperline_out[p]; - mp->plane_fmt[0].sizeimage += - (stride * mp->height) / fmt->vdownsampling[p]; + f->plane_fmt[0].sizeimage += + (stride * f->height) / fmt->vdownsampling[p]; } return 0; } int vivid_try_fmt_vid_out(struct file *file, void *priv, - struct v4l2_format *f) + struct v4l2_ext_pix_format *f) { struct vivid_dev *dev = video_drvdata(file); + struct v4l2_plane_ext_pix_format *pfmt = f->plane_fmt; struct v4l2_bt_timings *bt = &dev->dv_timings_out.bt; - struct v4l2_pix_format_mplane *mp = &f->fmt.pix_mp; - struct v4l2_plane_pix_format *pfmt = mp->plane_fmt; const struct vivid_fmt *fmt; unsigned bytesperline, max_bpl; unsigned factor = 1; unsigned w, h; unsigned p; - fmt = vivid_get_format(dev, mp->pixelformat); + fmt = vivid_get_format(dev, f->pixelformat); if (!fmt) { dprintk(dev, 1, "Fourcc format (0x%08x) unknown.\n", - mp->pixelformat); - mp->pixelformat = V4L2_PIX_FMT_YUYV; - fmt = vivid_get_format(dev, mp->pixelformat); + f->pixelformat); + f->pixelformat = V4L2_PIX_FMT_YUYV; + fmt = vivid_get_format(dev, f->pixelformat); } - mp->field = vivid_field_out(dev, mp->field); + f->field = vivid_field_out(dev, f->field); if (vivid_is_svid_out(dev)) { w = 720; h = (dev->std_out & V4L2_STD_525_60) ? 480 : 576; @@ -375,13 +373,13 @@ int vivid_try_fmt_vid_out(struct file *file, void *priv, w = dev->sink_rect.width; h = dev->sink_rect.height; } - if (V4L2_FIELD_HAS_T_OR_B(mp->field)) + if (V4L2_FIELD_HAS_T_OR_B(f->field)) factor = 2; if (!dev->has_scaler_out && !dev->has_crop_out && !dev->has_compose_out) { - mp->width = w; - mp->height = h / factor; + f->width = w; + f->height = h / factor; } else { - struct v4l2_rect r = { 0, 0, mp->width, mp->height * factor }; + struct v4l2_rect r = { 0, 0, f->width, f->height * factor }; v4l2_rect_set_min_size(&r, &vivid_min_rect); v4l2_rect_set_max_size(&r, &vivid_max_rect); @@ -394,16 +392,16 @@ int vivid_try_fmt_vid_out(struct file *file, void *priv, } else if (!dev->has_scaler_out && !dev->has_compose_out) { v4l2_rect_set_min_size(&r, &dev->sink_rect); } - mp->width = r.width; - mp->height = r.height / factor; + f->width = r.width; + f->height = r.height / factor; } /* This driver supports custom bytesperline values */ - mp->num_planes = fmt->buffers; + f->num_planes = fmt->buffers; for (p = 0; p < fmt->buffers; p++) { /* Calculate the minimum supported bytesperline value */ - bytesperline = (mp->width * fmt->bit_depth[p]) >> 3; + bytesperline = (f->width * fmt->bit_depth[p]) >> 3; /* Calculate the maximum supported bytesperline value */ max_bpl = (MAX_ZOOM * MAX_WIDTH * fmt->bit_depth[p]) >> 3; @@ -412,42 +410,39 @@ int vivid_try_fmt_vid_out(struct file *file, void *priv, if (pfmt[p].bytesperline < bytesperline) pfmt[p].bytesperline = bytesperline; - pfmt[p].sizeimage = (pfmt[p].bytesperline * mp->height) / + pfmt[p].sizeimage = (pfmt[p].bytesperline * f->height) / fmt->vdownsampling[p] + fmt->data_offset[p]; - memset(pfmt[p].reserved, 0, sizeof(pfmt[p].reserved)); } for (p = fmt->buffers; p < fmt->planes; p++) - pfmt[0].sizeimage += (pfmt[0].bytesperline * mp->height * + pfmt[0].sizeimage += (pfmt[0].bytesperline * f->height * (fmt->bit_depth[p] / fmt->vdownsampling[p])) / (fmt->bit_depth[0] / fmt->vdownsampling[0]); - mp->xfer_func = V4L2_XFER_FUNC_DEFAULT; - mp->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; - mp->quantization = V4L2_QUANTIZATION_DEFAULT; + f->xfer_func = V4L2_XFER_FUNC_DEFAULT; + f->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; + f->quantization = V4L2_QUANTIZATION_DEFAULT; if (vivid_is_svid_out(dev)) { - mp->colorspace = V4L2_COLORSPACE_SMPTE170M; + f->colorspace = V4L2_COLORSPACE_SMPTE170M; } else if (dev->dvi_d_out || !(bt->flags & V4L2_DV_FL_IS_CE_VIDEO)) { - mp->colorspace = V4L2_COLORSPACE_SRGB; + f->colorspace = V4L2_COLORSPACE_SRGB; if (dev->dvi_d_out) - mp->quantization = V4L2_QUANTIZATION_LIM_RANGE; + f->quantization = V4L2_QUANTIZATION_LIM_RANGE; } else if (bt->width == 720 && bt->height <= 576) { - mp->colorspace = V4L2_COLORSPACE_SMPTE170M; - } else if (mp->colorspace != V4L2_COLORSPACE_SMPTE170M && - mp->colorspace != V4L2_COLORSPACE_REC709 && - mp->colorspace != V4L2_COLORSPACE_OPRGB && - mp->colorspace != V4L2_COLORSPACE_BT2020 && - mp->colorspace != V4L2_COLORSPACE_SRGB) { - mp->colorspace = V4L2_COLORSPACE_REC709; + f->colorspace = V4L2_COLORSPACE_SMPTE170M; + } else if (f->colorspace != V4L2_COLORSPACE_SMPTE170M && + f->colorspace != V4L2_COLORSPACE_REC709 && + f->colorspace != V4L2_COLORSPACE_OPRGB && + f->colorspace != V4L2_COLORSPACE_BT2020 && + f->colorspace != V4L2_COLORSPACE_SRGB) { + f->colorspace = V4L2_COLORSPACE_REC709; } - memset(mp->reserved, 0, sizeof(mp->reserved)); return 0; } int vivid_s_fmt_vid_out(struct file *file, void *priv, - struct v4l2_format *f) + struct v4l2_ext_pix_format *f) { - struct v4l2_pix_format_mplane *mp = &f->fmt.pix_mp; struct vivid_dev *dev = video_drvdata(file); struct v4l2_rect *crop = &dev->crop_out; struct v4l2_rect *compose = &dev->compose_out; @@ -461,10 +456,10 @@ int vivid_s_fmt_vid_out(struct file *file, void *priv, if (vb2_is_busy(q) && (vivid_is_svid_out(dev) || - mp->width != dev->fmt_out_rect.width || - mp->height != dev->fmt_out_rect.height || - mp->pixelformat != dev->fmt_out->fourcc || - mp->field != dev->field_out)) { + f->width != dev->fmt_out_rect.width || + f->height != dev->fmt_out_rect.height || + f->pixelformat != dev->fmt_out->fourcc || + f->field != dev->field_out)) { dprintk(dev, 1, "%s device busy\n", __func__); return -EBUSY; } @@ -477,12 +472,12 @@ int vivid_s_fmt_vid_out(struct file *file, void *priv, if (vb2_is_busy(q)) goto set_colorspace; - dev->fmt_out = vivid_get_format(dev, mp->pixelformat); - if (V4L2_FIELD_HAS_T_OR_B(mp->field)) + dev->fmt_out = vivid_get_format(dev, f->pixelformat); + if (V4L2_FIELD_HAS_T_OR_B(f->field)) factor = 2; if (dev->has_scaler_out || dev->has_crop_out || dev->has_compose_out) { - struct v4l2_rect r = { 0, 0, mp->width, mp->height }; + struct v4l2_rect r = { 0, 0, f->width, f->height }; if (dev->has_scaler_out) { if (dev->has_crop_out) @@ -541,30 +536,30 @@ int vivid_s_fmt_vid_out(struct file *file, void *priv, crop->height /= factor; } } else { - struct v4l2_rect r = { 0, 0, mp->width, mp->height }; + struct v4l2_rect r = { 0, 0, f->width, f->height }; v4l2_rect_set_size_to(crop, &r); r.height /= factor; v4l2_rect_set_size_to(compose, &r); } - dev->fmt_out_rect.width = mp->width; - dev->fmt_out_rect.height = mp->height; - for (p = 0; p < mp->num_planes; p++) - dev->bytesperline_out[p] = mp->plane_fmt[p].bytesperline; + dev->fmt_out_rect.width = f->width; + dev->fmt_out_rect.height = f->height; + for (p = 0; p < f->num_planes; p++) + dev->bytesperline_out[p] = f->plane_fmt[p].bytesperline; for (p = dev->fmt_out->buffers; p < dev->fmt_out->planes; p++) dev->bytesperline_out[p] = (dev->bytesperline_out[0] * dev->fmt_out->bit_depth[p]) / dev->fmt_out->bit_depth[0]; - dev->field_out = mp->field; + dev->field_out = f->field; if (vivid_is_svid_out(dev)) - dev->tv_field_out = mp->field; + dev->tv_field_out = f->field; set_colorspace: - dev->colorspace_out = mp->colorspace; - dev->xfer_func_out = mp->xfer_func; - dev->ycbcr_enc_out = mp->ycbcr_enc; - dev->quantization_out = mp->quantization; + dev->colorspace_out = f->colorspace; + dev->xfer_func_out = f->xfer_func; + dev->ycbcr_enc_out = f->ycbcr_enc; + dev->quantization_out = f->quantization; if (dev->loop_video) { vivid_send_source_change(dev, SVID); vivid_send_source_change(dev, HDMI); @@ -572,66 +567,6 @@ int vivid_s_fmt_vid_out(struct file *file, void *priv, return 0; } -int vidioc_g_fmt_vid_out_mplane(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct vivid_dev *dev = video_drvdata(file); - - if (!dev->multiplanar) - return -ENOTTY; - return vivid_g_fmt_vid_out(file, priv, f); -} - -int vidioc_try_fmt_vid_out_mplane(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct vivid_dev *dev = video_drvdata(file); - - if (!dev->multiplanar) - return -ENOTTY; - return vivid_try_fmt_vid_out(file, priv, f); -} - -int vidioc_s_fmt_vid_out_mplane(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct vivid_dev *dev = video_drvdata(file); - - if (!dev->multiplanar) - return -ENOTTY; - return vivid_s_fmt_vid_out(file, priv, f); -} - -int vidioc_g_fmt_vid_out(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct vivid_dev *dev = video_drvdata(file); - - if (dev->multiplanar) - return -ENOTTY; - return fmt_sp2mp_func(file, priv, f, vivid_g_fmt_vid_out); -} - -int vidioc_try_fmt_vid_out(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct vivid_dev *dev = video_drvdata(file); - - if (dev->multiplanar) - return -ENOTTY; - return fmt_sp2mp_func(file, priv, f, vivid_try_fmt_vid_out); -} - -int vidioc_s_fmt_vid_out(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct vivid_dev *dev = video_drvdata(file); - - if (dev->multiplanar) - return -ENOTTY; - return fmt_sp2mp_func(file, priv, f, vivid_s_fmt_vid_out); -} - int vivid_vid_out_g_selection(struct file *file, void *priv, struct v4l2_selection *sel) { diff --git a/drivers/media/platform/vivid/vivid-vid-out.h b/drivers/media/platform/vivid/vivid-vid-out.h index 8d56314f4ea1..b84dc578af36 100644 --- a/drivers/media/platform/vivid/vivid-vid-out.h +++ b/drivers/media/platform/vivid/vivid-vid-out.h @@ -12,15 +12,12 @@ extern const struct vb2_ops vivid_vid_out_qops; void vivid_update_format_out(struct vivid_dev *dev); -int vivid_g_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f); -int vivid_try_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f); -int vivid_s_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f); -int vidioc_g_fmt_vid_out_mplane(struct file *file, void *priv, struct v4l2_format *f); -int vidioc_try_fmt_vid_out_mplane(struct file *file, void *priv, struct v4l2_format *f); -int vidioc_s_fmt_vid_out_mplane(struct file *file, void *priv, struct v4l2_format *f); -int vidioc_g_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f); -int vidioc_try_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f); -int vidioc_s_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f); +int vivid_g_fmt_vid_out(struct file *file, void *priv, + struct v4l2_ext_pix_format *f); +int vivid_try_fmt_vid_out(struct file *file, void *priv, + struct v4l2_ext_pix_format *f); +int vivid_s_fmt_vid_out(struct file *file, void *priv, + struct v4l2_ext_pix_format *f); int vivid_vid_out_g_selection(struct file *file, void *priv, struct v4l2_selection *sel); int vivid_vid_out_s_selection(struct file *file, void *fh, struct v4l2_selection *s); int vivid_vid_out_g_pixelaspect(struct file *file, void *priv, int type, struct v4l2_fract *f); From patchwork Tue Oct 8 09:11:19 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Boris Brezillon X-Patchwork-Id: 11179205 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 14C4014DB for ; Tue, 8 Oct 2019 09:11:32 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id E7CE821721 for ; Tue, 8 Oct 2019 09:11:31 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729944AbfJHJLa (ORCPT ); Tue, 8 Oct 2019 05:11:30 -0400 Received: from bhuna.collabora.co.uk ([46.235.227.227]:42916 "EHLO bhuna.collabora.co.uk" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729893AbfJHJL3 (ORCPT ); Tue, 8 Oct 2019 05:11:29 -0400 Received: from localhost.localdomain (unknown [IPv6:2a01:e0a:2c:6930:5cf4:84a1:2763:fe0d]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) (Authenticated sender: bbrezillon) by bhuna.collabora.co.uk (Postfix) with ESMTPSA id 866AB28F7F9; Tue, 8 Oct 2019 10:11:27 +0100 (BST) From: Boris Brezillon To: Mauro Carvalho Chehab , Hans Verkuil , Laurent Pinchart , Sakari Ailus , linux-media@vger.kernel.org Cc: Tomasz Figa , Hirokazu Honda , Nicolas Dufresne , Brian Starkey , kernel@collabora.com, Boris Brezillon Subject: [RFC PATCH v3 6/6] media: vimc: Implement the ext_fmt and ext_buf hooks Date: Tue, 8 Oct 2019 11:11:19 +0200 Message-Id: <20191008091119.7294-7-boris.brezillon@collabora.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20191008091119.7294-1-boris.brezillon@collabora.com> References: <20191008091119.7294-1-boris.brezillon@collabora.com> MIME-Version: 1.0 Sender: linux-media-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org Convert the driver to the _ext_fmt and _ext_buf API. Signed-off-by: Boris Brezillon --- Changes in v3: - Rebased on top of media/master (post 5.4-rc1) Changes in v2: - New patch --- drivers/media/platform/vimc/vimc-capture.c | 65 +++++++++++----------- drivers/media/platform/vimc/vimc-common.c | 4 +- drivers/media/platform/vimc/vimc-common.h | 2 +- 3 files changed, 36 insertions(+), 35 deletions(-) diff --git a/drivers/media/platform/vimc/vimc-capture.c b/drivers/media/platform/vimc/vimc-capture.c index 602f80323031..8a9d0039bf6e 100644 --- a/drivers/media/platform/vimc/vimc-capture.c +++ b/drivers/media/platform/vimc/vimc-capture.c @@ -16,7 +16,7 @@ struct vimc_cap_device { struct vimc_ent_device ved; struct video_device vdev; struct device *dev; - struct v4l2_pix_format format; + struct v4l2_ext_pix_format format; struct vb2_queue queue; struct list_head buf_list; /* @@ -32,12 +32,13 @@ struct vimc_cap_device { struct vimc_stream stream; }; -static const struct v4l2_pix_format fmt_default = { +static const struct v4l2_ext_pix_format fmt_default = { .width = 640, .height = 480, .pixelformat = V4L2_PIX_FMT_RGB24, .field = V4L2_FIELD_NONE, .colorspace = V4L2_COLORSPACE_DEFAULT, + .num_planes = 1, }; struct vimc_cap_buffer { @@ -63,7 +64,7 @@ static int vimc_cap_querycap(struct file *file, void *priv, } static void vimc_cap_get_format(struct vimc_ent_device *ved, - struct v4l2_pix_format *fmt) + struct v4l2_ext_pix_format *fmt) { struct vimc_cap_device *vcap = container_of(ved, struct vimc_cap_device, ved); @@ -72,19 +73,18 @@ static void vimc_cap_get_format(struct vimc_ent_device *ved, } static int vimc_cap_g_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) + struct v4l2_ext_pix_format *f) { struct vimc_cap_device *vcap = video_drvdata(file); - f->fmt.pix = vcap->format; + *f = vcap->format; return 0; } static int vimc_cap_try_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) + struct v4l2_ext_pix_format *format) { - struct v4l2_pix_format *format = &f->fmt.pix; const struct vimc_pix_map *vpix; format->width = clamp_t(u32, format->width, VIMC_FRAME_MIN_WIDTH, @@ -99,8 +99,10 @@ static int vimc_cap_try_fmt_vid_cap(struct file *file, void *priv, vpix = vimc_pix_map_by_pixelformat(format->pixelformat); } /* TODO: Add support for custom bytesperline values */ - format->bytesperline = format->width * vpix->bpp; - format->sizeimage = format->bytesperline * format->height; + format->num_planes = 1; + format->plane_fmt[0].bytesperline = format->width * vpix->bpp; + format->plane_fmt[0].sizeimage = format->plane_fmt[0].bytesperline * + format->height; if (format->field == V4L2_FIELD_ANY) format->field = fmt_default.field; @@ -111,7 +113,7 @@ static int vimc_cap_try_fmt_vid_cap(struct file *file, void *priv, } static int vimc_cap_s_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) + struct v4l2_ext_pix_format *f) { struct vimc_cap_device *vcap = video_drvdata(file); int ret; @@ -133,12 +135,10 @@ static int vimc_cap_s_fmt_vid_cap(struct file *file, void *priv, vcap->format.quantization, vcap->format.xfer_func, vcap->format.ycbcr_enc, /* new */ - f->fmt.pix.width, f->fmt.pix.height, - f->fmt.pix.pixelformat, f->fmt.pix.colorspace, - f->fmt.pix.quantization, f->fmt.pix.xfer_func, - f->fmt.pix.ycbcr_enc); + f->width, f->height, f->pixelformat, f->colorspace, + f->quantization, f->xfer_func, f->ycbcr_enc); - vcap->format = f->fmt.pix; + vcap->format = *f; return 0; } @@ -193,19 +193,19 @@ static const struct v4l2_file_operations vimc_cap_fops = { static const struct v4l2_ioctl_ops vimc_cap_ioctl_ops = { .vidioc_querycap = vimc_cap_querycap, - .vidioc_g_fmt_vid_cap = vimc_cap_g_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = vimc_cap_s_fmt_vid_cap, - .vidioc_try_fmt_vid_cap = vimc_cap_try_fmt_vid_cap, + .vidioc_g_ext_fmt_vid_cap = vimc_cap_g_fmt_vid_cap, + .vidioc_s_ext_fmt_vid_cap = vimc_cap_s_fmt_vid_cap, + .vidioc_try_ext_fmt_vid_cap = vimc_cap_try_fmt_vid_cap, .vidioc_enum_fmt_vid_cap = vimc_cap_enum_fmt_vid_cap, .vidioc_enum_framesizes = vimc_cap_enum_framesizes, .vidioc_reqbufs = vb2_ioctl_reqbufs, - .vidioc_create_bufs = vb2_ioctl_create_bufs, - .vidioc_prepare_buf = vb2_ioctl_prepare_buf, - .vidioc_querybuf = vb2_ioctl_querybuf, - .vidioc_qbuf = vb2_ioctl_qbuf, - .vidioc_dqbuf = vb2_ioctl_dqbuf, - .vidioc_expbuf = vb2_ioctl_expbuf, + .vidioc_ext_create_bufs = vb2_ioctl_ext_create_bufs, + .vidioc_ext_prepare_buf = vb2_ioctl_ext_prepare_buf, + .vidioc_ext_querybuf = vb2_ioctl_ext_querybuf, + .vidioc_ext_qbuf = vb2_ioctl_ext_qbuf, + .vidioc_ext_dqbuf = vb2_ioctl_ext_dqbuf, + .vidioc_ext_expbuf = vb2_ioctl_ext_expbuf, .vidioc_streamon = vb2_ioctl_streamon, .vidioc_streamoff = vb2_ioctl_streamoff, }; @@ -286,10 +286,11 @@ static int vimc_cap_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, struct vimc_cap_device *vcap = vb2_get_drv_priv(vq); if (*nplanes) - return sizes[0] < vcap->format.sizeimage ? -EINVAL : 0; + return sizes[0] < vcap->format.plane_fmt[0].sizeimage ? + -EINVAL : 0; /* We don't support multiplanes for now */ *nplanes = 1; - sizes[0] = vcap->format.sizeimage; + sizes[0] = vcap->format.plane_fmt[0].sizeimage; return 0; } @@ -297,7 +298,7 @@ static int vimc_cap_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, static int vimc_cap_buffer_prepare(struct vb2_buffer *vb) { struct vimc_cap_device *vcap = vb2_get_drv_priv(vb->vb2_queue); - unsigned long size = vcap->format.sizeimage; + unsigned long size = vcap->format.plane_fmt[0].sizeimage; if (vb2_plane_size(vb, 0) < size) { dev_err(vcap->dev, "%s: buffer too small (%lu < %lu)\n", @@ -374,11 +375,11 @@ static void *vimc_cap_process_frame(struct vimc_ent_device *ved, vbuf = vb2_plane_vaddr(&vimc_buf->vb2.vb2_buf, 0); - memcpy(vbuf, frame, vcap->format.sizeimage); + memcpy(vbuf, frame, vcap->format.plane_fmt[0].sizeimage); /* Set it as ready */ vb2_set_plane_payload(&vimc_buf->vb2.vb2_buf, 0, - vcap->format.sizeimage); + vcap->format.plane_fmt[0].sizeimage); vb2_buffer_done(&vimc_buf->vb2.vb2_buf, VB2_BUF_STATE_DONE); return NULL; } @@ -443,9 +444,9 @@ struct vimc_ent_device *vimc_cap_add(struct vimc_device *vimc, /* Set default frame format */ vcap->format = fmt_default; vpix = vimc_pix_map_by_pixelformat(vcap->format.pixelformat); - vcap->format.bytesperline = vcap->format.width * vpix->bpp; - vcap->format.sizeimage = vcap->format.bytesperline * - vcap->format.height; + vcap->format.plane_fmt[0].bytesperline = vcap->format.width * vpix->bpp; + vcap->format.plane_fmt[0].sizeimage = vcap->format.plane_fmt[0].bytesperline * + vcap->format.height; /* Fill the vimc_ent_device struct */ vcap->ved.ent = &vcap->vdev.entity; diff --git a/drivers/media/platform/vimc/vimc-common.c b/drivers/media/platform/vimc/vimc-common.c index a3120f4f7a90..c10cb3e9b934 100644 --- a/drivers/media/platform/vimc/vimc-common.c +++ b/drivers/media/platform/vimc/vimc-common.c @@ -268,14 +268,14 @@ static int vimc_get_mbus_format(struct media_pad *pad, entity); struct vimc_ent_device *ved = video_get_drvdata(vdev); const struct vimc_pix_map *vpix; - struct v4l2_pix_format vdev_fmt; + struct v4l2_ext_pix_format vdev_fmt; if (!ved->vdev_get_format) return -ENOIOCTLCMD; ved->vdev_get_format(ved, &vdev_fmt); vpix = vimc_pix_map_by_pixelformat(vdev_fmt.pixelformat); - v4l2_fill_mbus_format(&fmt->format, &vdev_fmt, vpix->code); + v4l2_fill_mbus_format_ext(&fmt->format, &vdev_fmt, vpix->code); } else { return -EINVAL; } diff --git a/drivers/media/platform/vimc/vimc-common.h b/drivers/media/platform/vimc/vimc-common.h index 698db7c07645..21bbe31c8029 100644 --- a/drivers/media/platform/vimc/vimc-common.h +++ b/drivers/media/platform/vimc/vimc-common.h @@ -113,7 +113,7 @@ struct vimc_ent_device { void * (*process_frame)(struct vimc_ent_device *ved, const void *frame); void (*vdev_get_format)(struct vimc_ent_device *ved, - struct v4l2_pix_format *fmt); + struct v4l2_ext_pix_format *fmt); }; /**