Show a patch.

GET /api/1.1/patches/15851/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 15851,
    "url": "https://patchwork.libcamera.org/api/1.1/patches/15851/?format=api",
    "web_url": "https://patchwork.libcamera.org/patch/15851/",
    "project": {
        "id": 1,
        "url": "https://patchwork.libcamera.org/api/1.1/projects/1/?format=api",
        "name": "libcamera",
        "link_name": "libcamera",
        "list_id": "libcamera_core",
        "list_email": "libcamera-devel@lists.libcamera.org",
        "web_url": "",
        "scm_url": "",
        "webscm_url": ""
    },
    "msgid": "<20220510115147.19360-12-laurent.pinchart@ideasonboard.com>",
    "date": "2022-05-10T11:51:08",
    "name": "[libcamera-devel,11/50] staging: media: imx: imx7-media-csi: Import video device helpers",
    "commit_ref": null,
    "pull_url": null,
    "state": "not-applicable",
    "archived": false,
    "hash": "6e370f62d9c6bf72f97122a2c9f537b2436d704f",
    "submitter": {
        "id": 2,
        "url": "https://patchwork.libcamera.org/api/1.1/people/2/?format=api",
        "name": "Laurent Pinchart",
        "email": "laurent.pinchart@ideasonboard.com"
    },
    "delegate": null,
    "mbox": "https://patchwork.libcamera.org/patch/15851/mbox/",
    "series": [
        {
            "id": 3106,
            "url": "https://patchwork.libcamera.org/api/1.1/series/3106/?format=api",
            "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=3106",
            "date": "2022-05-10T11:50:57",
            "name": "staging: media: imx: Prepare destaging of imx7-media-csi",
            "version": 1,
            "mbox": "https://patchwork.libcamera.org/series/3106/mbox/"
        }
    ],
    "comments": "https://patchwork.libcamera.org/api/patches/15851/comments/",
    "check": "pending",
    "checks": "https://patchwork.libcamera.org/api/patches/15851/checks/",
    "tags": {},
    "headers": {
        "Return-Path": "<libcamera-devel-bounces@lists.libcamera.org>",
        "X-Original-To": "parsemail@patchwork.libcamera.org",
        "Delivered-To": "parsemail@patchwork.libcamera.org",
        "Received": [
            "from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 9407BC326C\n\tfor <parsemail@patchwork.libcamera.org>;\n\tTue, 10 May 2022 11:52:13 +0000 (UTC)",
            "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 3652E65676;\n\tTue, 10 May 2022 13:52:13 +0200 (CEST)",
            "from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 6686F65652\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 10 May 2022 13:52:06 +0200 (CEST)",
            "from pendragon.lan (62-78-145-57.bb.dnainternet.fi [62.78.145.57])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 77143824;\n\tTue, 10 May 2022 13:52:05 +0200 (CEST)"
        ],
        "DKIM-Signature": [
            "v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org;\n\ts=mail; t=1652183533;\n\tbh=SW6QXUPRxmJIzxkMVklssylI/Qn6MNYwgfUhiDE5yfM=;\n\th=To:Date:In-Reply-To:References:Subject:List-Id:List-Unsubscribe:\n\tList-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc:\n\tFrom;\n\tb=ihJ5jiSbDGD58R9i9YIRm9dRLMuunSc31pYU3Ign5G4idoxXdkVOGLBy0p562x9/W\n\t/iH/bY8Bd1AJNJbYDdKzzdW5tHDkN8PVnPp5ClqjuKCe2ckgCoI/8Sk6tfZMmV/LvS\n\t/tgBxzc8SNC/+DWWdaXAqAa03KK9SVT2F+4jWAKebVW+i9xDe8dWyoIeulDEJinHd1\n\txxcBkW3grgMn0l6vZs5g9TH84nb2i+doVoni0Vu+/KR0NjlVkBg+Mp6+o/U71szt/c\n\teCliJX5HYIInvr8JjIdL+/v5df0TeP6t+z0Gum3Dl9QyQ14El/m4s05jIlXvBwmmg5\n\tXoTEvx0zHSjEg==",
            "v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1652183526;\n\tbh=SW6QXUPRxmJIzxkMVklssylI/Qn6MNYwgfUhiDE5yfM=;\n\th=From:To:Cc:Subject:Date:In-Reply-To:References:From;\n\tb=QPISc5Sa2dcqMHy99crHYTtnoAsWZ2ae0J7NhOza81yZdAQTjW703I+RDaz+OHdmh\n\tfr1YgTSmApRoTDdxz8evDK+60zOFVOdPEfBtJftOqNCTbjoyMUiBoEAEJSQMU1wFAL\n\tUNgQuFltE6mlYaZgoD18v/pxgtY80/rwglb0nPuE="
        ],
        "Authentication-Results": "lancelot.ideasonboard.com; dkim=pass (1024-bit key; \n\tunprotected) header.d=ideasonboard.com\n\theader.i=@ideasonboard.com\n\theader.b=\"QPISc5Sa\"; dkim-atps=neutral",
        "To": "libcamera-devel@lists.libcamera.org",
        "Date": "Tue, 10 May 2022 14:51:08 +0300",
        "Message-Id": "<20220510115147.19360-12-laurent.pinchart@ideasonboard.com>",
        "X-Mailer": "git-send-email 2.35.1",
        "In-Reply-To": "<20220510115147.19360-1-laurent.pinchart@ideasonboard.com>",
        "References": "<20220510115147.19360-1-laurent.pinchart@ideasonboard.com>",
        "MIME-Version": "1.0",
        "Content-Transfer-Encoding": "8bit",
        "Subject": "[libcamera-devel] [PATCH 11/50] staging: media: imx:\n\timx7-media-csi: Import video device helpers",
        "X-BeenThere": "libcamera-devel@lists.libcamera.org",
        "X-Mailman-Version": "2.1.29",
        "Precedence": "list",
        "List-Id": "<libcamera-devel.lists.libcamera.org>",
        "List-Unsubscribe": "<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>",
        "List-Archive": "<https://lists.libcamera.org/pipermail/libcamera-devel/>",
        "List-Post": "<mailto:libcamera-devel@lists.libcamera.org>",
        "List-Help": "<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>",
        "List-Subscribe": "<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>",
        "From": "Laurent Pinchart via libcamera-devel\n\t<libcamera-devel@lists.libcamera.org>",
        "Reply-To": "Laurent Pinchart <laurent.pinchart@ideasonboard.com>",
        "Cc": "Martin Kepplinger <martin.kepplinger@puri.sm>, kernel@pengutronix.de,\n\tDorota Czaplejewicz <dorota.czaplejewicz@puri.sm>,\n\tAlexander Stein <alexander.stein@ew.tq-group.com>,\n\tRui Miguel Silva <rmfrfs@gmail.com>,\n\tPhilipp Zabel <p.zabel@pengutronix.de>, \n\tSteve Longerbeam <slongerbeam@gmail.com>",
        "Errors-To": "libcamera-devel-bounces@lists.libcamera.org",
        "Sender": "\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"
    },
    "content": "To prepare for code refactoring, copy the video device helper code used\nby this driver verbatim from imx-media-capture. Rename some functions to\navoid name clashes, and leave the legacy ioctls out as they're not used\nby the imx7-media-csi driver. No functional change included.\n\nSigned-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n---\n drivers/staging/media/imx/imx7-media-csi.c | 712 ++++++++++++++++++++-\n 1 file changed, 702 insertions(+), 10 deletions(-)",
    "diff": "diff --git a/drivers/staging/media/imx/imx7-media-csi.c b/drivers/staging/media/imx/imx7-media-csi.c\nindex e7dcb602afae..63f291684e79 100644\n--- a/drivers/staging/media/imx/imx7-media-csi.c\n+++ b/drivers/staging/media/imx/imx7-media-csi.c\n@@ -17,11 +17,15 @@\n #include <linux/pinctrl/consumer.h>\n #include <linux/platform_device.h>\n #include <linux/regmap.h>\n+#include <linux/slab.h>\n+#include <linux/spinlock.h>\n #include <linux/types.h>\n \n+#include <media/v4l2-ctrls.h>\n #include <media/v4l2-device.h>\n #include <media/v4l2-event.h>\n #include <media/v4l2-fwnode.h>\n+#include <media/v4l2-ioctl.h>\n #include <media/v4l2-mc.h>\n #include <media/v4l2-subdev.h>\n #include <media/videobuf2-dma-contig.h>\n@@ -335,6 +339,9 @@ static void imx7_csi_update_buf(struct imx7_csi *csi, dma_addr_t phys,\n \t\timx7_csi_reg_write(csi, phys, CSI_CSIDMASA_FB1);\n }\n \n+static struct imx_media_buffer *\n+imx7_media_capture_device_next_buf(struct imx_media_video_dev *vdev);\n+\n static void imx7_csi_setup_vb2_buf(struct imx7_csi *csi)\n {\n \tstruct imx_media_video_dev *vdev = csi->vdev;\n@@ -344,7 +351,7 @@ static void imx7_csi_setup_vb2_buf(struct imx7_csi *csi)\n \tint i;\n \n \tfor (i = 0; i < 2; i++) {\n-\t\tbuf = imx_media_capture_device_next_buf(vdev);\n+\t\tbuf = imx7_media_capture_device_next_buf(vdev);\n \t\tif (buf) {\n \t\t\tcsi->active_vb2_buf[i] = buf;\n \t\t\tvb2_buf = &buf->vbuf.vb2_buf;\n@@ -646,7 +653,7 @@ static void imx7_csi_vb2_buf_done(struct imx7_csi *csi)\n \tcsi->frame_sequence++;\n \n \t/* get next queued buffer */\n-\tnext = imx_media_capture_device_next_buf(vdev);\n+\tnext = imx7_media_capture_device_next_buf(vdev);\n \tif (next) {\n \t\tphys = vb2_dma_contig_plane_dma_addr(&next->vbuf.vb2_buf, 0);\n \t\tcsi->active_vb2_buf[csi->buf_num] = next;\n@@ -716,6 +723,691 @@ static irqreturn_t imx7_csi_irq_handler(int irq, void *data)\n \treturn IRQ_HANDLED;\n }\n \n+/* -----------------------------------------------------------------------------\n+ * Video Capture Device\n+ */\n+\n+#define IMX_CAPTURE_NAME \"imx-capture\"\n+\n+struct capture_priv {\n+\tstruct imx_media_dev *md;\t\t/* Media device */\n+\tstruct device *dev;\t\t\t/* Physical device */\n+\n+\tstruct imx_media_video_dev vdev;\t/* Video device */\n+\tstruct media_pad vdev_pad;\t\t/* Video device pad */\n+\n+\tstruct v4l2_subdev *src_sd;\t\t/* Source subdev */\n+\tint src_sd_pad;\t\t\t\t/* Source subdev pad */\n+\n+\tstruct mutex mutex;\t\t\t/* Protect vdev operations */\n+\n+\tstruct vb2_queue q;\t\t\t/* The videobuf2 queue */\n+\tstruct list_head ready_q;\t\t/* List of queued buffers */\n+\tspinlock_t q_lock;\t\t\t/* Protect ready_q */\n+\n+\tstruct v4l2_ctrl_handler ctrl_hdlr;\t/* Controls inherited from subdevs */\n+\n+\tbool legacy_api;\t\t\t/* Use the legacy (pre-MC) API */\n+};\n+\n+#define to_capture_priv(v) container_of(v, struct capture_priv, vdev)\n+\n+/* In bytes, per queue */\n+#define VID_MEM_LIMIT\tSZ_64M\n+\n+/* -----------------------------------------------------------------------------\n+ * Video Capture Device - IOCTLs\n+ */\n+\n+static const struct imx_media_pixfmt *capture_find_format(u32 code, u32 fourcc)\n+{\n+\tconst struct imx_media_pixfmt *cc;\n+\n+\tcc = imx_media_find_ipu_format(code, PIXFMT_SEL_YUV_RGB);\n+\tif (cc) {\n+\t\tenum imx_pixfmt_sel fmt_sel = cc->cs == IPUV3_COLORSPACE_YUV\n+\t\t\t\t\t    ? PIXFMT_SEL_YUV : PIXFMT_SEL_RGB;\n+\n+\t\tcc = imx_media_find_pixel_format(fourcc, fmt_sel);\n+\t\tif (!cc) {\n+\t\t\timx_media_enum_pixel_formats(&fourcc, 0, fmt_sel, 0);\n+\t\t\tcc = imx_media_find_pixel_format(fourcc, fmt_sel);\n+\t\t}\n+\n+\t\treturn cc;\n+\t}\n+\n+\treturn imx_media_find_mbus_format(code, PIXFMT_SEL_ANY);\n+}\n+\n+static int capture_querycap(struct file *file, void *fh,\n+\t\t\t    struct v4l2_capability *cap)\n+{\n+\tstruct capture_priv *priv = video_drvdata(file);\n+\n+\tstrscpy(cap->driver, IMX_CAPTURE_NAME, sizeof(cap->driver));\n+\tstrscpy(cap->card, IMX_CAPTURE_NAME, sizeof(cap->card));\n+\tsnprintf(cap->bus_info, sizeof(cap->bus_info),\n+\t\t \"platform:%s\", dev_name(priv->dev));\n+\n+\treturn 0;\n+}\n+\n+static int capture_enum_fmt_vid_cap(struct file *file, void *fh,\n+\t\t\t\t    struct v4l2_fmtdesc *f)\n+{\n+\treturn imx_media_enum_pixel_formats(&f->pixelformat, f->index,\n+\t\t\t\t\t    PIXFMT_SEL_ANY, f->mbus_code);\n+}\n+\n+static int capture_enum_framesizes(struct file *file, void *fh,\n+\t\t\t\t   struct v4l2_frmsizeenum *fsize)\n+{\n+\tconst struct imx_media_pixfmt *cc;\n+\n+\tif (fsize->index > 0)\n+\t\treturn -EINVAL;\n+\n+\tcc = imx_media_find_pixel_format(fsize->pixel_format, PIXFMT_SEL_ANY);\n+\tif (!cc)\n+\t\treturn -EINVAL;\n+\n+\t/*\n+\t * TODO: The constraints are hardware-specific and may depend on the\n+\t * pixel format. This should come from the driver using\n+\t * imx_media_capture.\n+\t */\n+\tfsize->type = V4L2_FRMSIZE_TYPE_CONTINUOUS;\n+\tfsize->stepwise.min_width = 1;\n+\tfsize->stepwise.max_width = 65535;\n+\tfsize->stepwise.min_height = 1;\n+\tfsize->stepwise.max_height = 65535;\n+\tfsize->stepwise.step_width = 1;\n+\tfsize->stepwise.step_height = 1;\n+\n+\treturn 0;\n+}\n+\n+static int capture_g_fmt_vid_cap(struct file *file, void *fh,\n+\t\t\t\t struct v4l2_format *f)\n+{\n+\tstruct capture_priv *priv = video_drvdata(file);\n+\n+\tf->fmt.pix = priv->vdev.fmt;\n+\n+\treturn 0;\n+}\n+\n+static const struct imx_media_pixfmt *\n+__capture_try_fmt(struct v4l2_pix_format *pixfmt, struct v4l2_rect *compose)\n+{\n+\tstruct v4l2_mbus_framefmt fmt_src;\n+\tconst struct imx_media_pixfmt *cc;\n+\n+\t/*\n+\t * Find the pixel format, default to the first supported format if not\n+\t * found.\n+\t */\n+\tcc = imx_media_find_pixel_format(pixfmt->pixelformat, PIXFMT_SEL_ANY);\n+\tif (!cc) {\n+\t\timx_media_enum_pixel_formats(&pixfmt->pixelformat, 0,\n+\t\t\t\t\t     PIXFMT_SEL_ANY, 0);\n+\t\tcc = imx_media_find_pixel_format(pixfmt->pixelformat,\n+\t\t\t\t\t\t PIXFMT_SEL_ANY);\n+\t}\n+\n+\t/* Allow IDMAC interweave but enforce field order from source. */\n+\tif (V4L2_FIELD_IS_INTERLACED(pixfmt->field)) {\n+\t\tswitch (pixfmt->field) {\n+\t\tcase V4L2_FIELD_SEQ_TB:\n+\t\t\tpixfmt->field = V4L2_FIELD_INTERLACED_TB;\n+\t\t\tbreak;\n+\t\tcase V4L2_FIELD_SEQ_BT:\n+\t\t\tpixfmt->field = V4L2_FIELD_INTERLACED_BT;\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\n+\tv4l2_fill_mbus_format(&fmt_src, pixfmt, 0);\n+\timx_media_mbus_fmt_to_pix_fmt(pixfmt, &fmt_src, cc);\n+\n+\tif (compose) {\n+\t\tcompose->width = fmt_src.width;\n+\t\tcompose->height = fmt_src.height;\n+\t}\n+\n+\treturn cc;\n+}\n+\n+static int capture_try_fmt_vid_cap(struct file *file, void *fh,\n+\t\t\t\t   struct v4l2_format *f)\n+{\n+\t__capture_try_fmt(&f->fmt.pix, NULL);\n+\treturn 0;\n+}\n+\n+static int capture_s_fmt_vid_cap(struct file *file, void *fh,\n+\t\t\t\t struct v4l2_format *f)\n+{\n+\tstruct capture_priv *priv = video_drvdata(file);\n+\tconst struct imx_media_pixfmt *cc;\n+\n+\tif (vb2_is_busy(&priv->q)) {\n+\t\tdev_err(priv->dev, \"%s queue busy\\n\", __func__);\n+\t\treturn -EBUSY;\n+\t}\n+\n+\tcc = __capture_try_fmt(&f->fmt.pix, &priv->vdev.compose);\n+\n+\tpriv->vdev.cc = cc;\n+\tpriv->vdev.fmt = f->fmt.pix;\n+\n+\treturn 0;\n+}\n+\n+static int capture_g_selection(struct file *file, void *fh,\n+\t\t\t       struct v4l2_selection *s)\n+{\n+\tstruct capture_priv *priv = video_drvdata(file);\n+\n+\tswitch (s->target) {\n+\tcase V4L2_SEL_TGT_COMPOSE:\n+\tcase V4L2_SEL_TGT_COMPOSE_DEFAULT:\n+\tcase V4L2_SEL_TGT_COMPOSE_BOUNDS:\n+\t\t/* The compose rectangle is fixed to the source format. */\n+\t\ts->r = priv->vdev.compose;\n+\t\tbreak;\n+\tcase V4L2_SEL_TGT_COMPOSE_PADDED:\n+\t\t/*\n+\t\t * The hardware writes with a configurable but fixed DMA burst\n+\t\t * size. If the source format width is not burst size aligned,\n+\t\t * the written frame contains padding to the right.\n+\t\t */\n+\t\ts->r.left = 0;\n+\t\ts->r.top = 0;\n+\t\ts->r.width = priv->vdev.fmt.width;\n+\t\ts->r.height = priv->vdev.fmt.height;\n+\t\tbreak;\n+\tdefault:\n+\t\treturn -EINVAL;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int capture_subscribe_event(struct v4l2_fh *fh,\n+\t\t\t\t   const struct v4l2_event_subscription *sub)\n+{\n+\tswitch (sub->type) {\n+\tcase V4L2_EVENT_IMX_FRAME_INTERVAL_ERROR:\n+\t\treturn v4l2_event_subscribe(fh, sub, 0, NULL);\n+\tdefault:\n+\t\treturn -EINVAL;\n+\t}\n+}\n+\n+static const struct v4l2_ioctl_ops capture_ioctl_ops = {\n+\t.vidioc_querycap\t\t= capture_querycap,\n+\n+\t.vidioc_enum_fmt_vid_cap\t= capture_enum_fmt_vid_cap,\n+\t.vidioc_enum_framesizes\t\t= capture_enum_framesizes,\n+\n+\t.vidioc_g_fmt_vid_cap\t\t= capture_g_fmt_vid_cap,\n+\t.vidioc_try_fmt_vid_cap\t\t= capture_try_fmt_vid_cap,\n+\t.vidioc_s_fmt_vid_cap\t\t= capture_s_fmt_vid_cap,\n+\n+\t.vidioc_g_selection\t\t= capture_g_selection,\n+\n+\t.vidioc_reqbufs\t\t\t= vb2_ioctl_reqbufs,\n+\t.vidioc_create_bufs\t\t= vb2_ioctl_create_bufs,\n+\t.vidioc_prepare_buf\t\t= vb2_ioctl_prepare_buf,\n+\t.vidioc_querybuf\t\t= vb2_ioctl_querybuf,\n+\t.vidioc_qbuf\t\t\t= vb2_ioctl_qbuf,\n+\t.vidioc_dqbuf\t\t\t= vb2_ioctl_dqbuf,\n+\t.vidioc_expbuf\t\t\t= vb2_ioctl_expbuf,\n+\t.vidioc_streamon\t\t= vb2_ioctl_streamon,\n+\t.vidioc_streamoff\t\t= vb2_ioctl_streamoff,\n+\n+\t.vidioc_subscribe_event\t\t= capture_subscribe_event,\n+\t.vidioc_unsubscribe_event\t= v4l2_event_unsubscribe,\n+};\n+\n+/* -----------------------------------------------------------------------------\n+ * Video Capture Device - Queue Operations\n+ */\n+\n+static int capture_queue_setup(struct vb2_queue *vq,\n+\t\t\t       unsigned int *nbuffers,\n+\t\t\t       unsigned int *nplanes,\n+\t\t\t       unsigned int sizes[],\n+\t\t\t       struct device *alloc_devs[])\n+{\n+\tstruct capture_priv *priv = vb2_get_drv_priv(vq);\n+\tstruct v4l2_pix_format *pix = &priv->vdev.fmt;\n+\tunsigned int count = *nbuffers;\n+\n+\tif (vq->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)\n+\t\treturn -EINVAL;\n+\n+\tif (*nplanes) {\n+\t\tif (*nplanes != 1 || sizes[0] < pix->sizeimage)\n+\t\t\treturn -EINVAL;\n+\t\tcount += vq->num_buffers;\n+\t}\n+\n+\tcount = min_t(__u32, VID_MEM_LIMIT / pix->sizeimage, count);\n+\n+\tif (*nplanes)\n+\t\t*nbuffers = (count < vq->num_buffers) ? 0 :\n+\t\t\tcount - vq->num_buffers;\n+\telse\n+\t\t*nbuffers = count;\n+\n+\t*nplanes = 1;\n+\tsizes[0] = pix->sizeimage;\n+\n+\treturn 0;\n+}\n+\n+static int capture_buf_init(struct vb2_buffer *vb)\n+{\n+\tstruct imx_media_buffer *buf = to_imx_media_vb(vb);\n+\n+\tINIT_LIST_HEAD(&buf->list);\n+\n+\treturn 0;\n+}\n+\n+static int capture_buf_prepare(struct vb2_buffer *vb)\n+{\n+\tstruct vb2_queue *vq = vb->vb2_queue;\n+\tstruct capture_priv *priv = vb2_get_drv_priv(vq);\n+\tstruct v4l2_pix_format *pix = &priv->vdev.fmt;\n+\n+\tif (vb2_plane_size(vb, 0) < pix->sizeimage) {\n+\t\tdev_err(priv->dev,\n+\t\t\t\"data will not fit into plane (%lu < %lu)\\n\",\n+\t\t\tvb2_plane_size(vb, 0), (long)pix->sizeimage);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tvb2_set_plane_payload(vb, 0, pix->sizeimage);\n+\n+\treturn 0;\n+}\n+\n+static void capture_buf_queue(struct vb2_buffer *vb)\n+{\n+\tstruct capture_priv *priv = vb2_get_drv_priv(vb->vb2_queue);\n+\tstruct imx_media_buffer *buf = to_imx_media_vb(vb);\n+\tunsigned long flags;\n+\n+\tspin_lock_irqsave(&priv->q_lock, flags);\n+\n+\tlist_add_tail(&buf->list, &priv->ready_q);\n+\n+\tspin_unlock_irqrestore(&priv->q_lock, flags);\n+}\n+\n+static int capture_validate_fmt(struct capture_priv *priv)\n+{\n+\tstruct v4l2_subdev_format fmt_src;\n+\tconst struct imx_media_pixfmt *cc;\n+\tint ret;\n+\n+\t/* Retrieve the media bus format on the source subdev. */\n+\tfmt_src.pad = priv->src_sd_pad;\n+\tfmt_src.which = V4L2_SUBDEV_FORMAT_ACTIVE;\n+\tret = v4l2_subdev_call(priv->src_sd, pad, get_fmt, NULL, &fmt_src);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\t/*\n+\t * Verify that the media bus size matches the size set on the video\n+\t * node. It is sufficient to check the compose rectangle size without\n+\t * checking the rounded size from vdev.fmt, as the rounded size is\n+\t * derived directly from the compose rectangle size, and will thus\n+\t * always match if the compose rectangle matches.\n+\t */\n+\tif (priv->vdev.compose.width != fmt_src.format.width ||\n+\t    priv->vdev.compose.height != fmt_src.format.height)\n+\t\treturn -EPIPE;\n+\n+\t/*\n+\t * Verify that the media bus code is compatible with the pixel format\n+\t * set on the video node.\n+\t */\n+\tcc = capture_find_format(fmt_src.format.code, 0);\n+\tif (!cc || priv->vdev.cc->cs != cc->cs)\n+\t\treturn -EPIPE;\n+\n+\treturn 0;\n+}\n+\n+static int capture_start_streaming(struct vb2_queue *vq, unsigned int count)\n+{\n+\tstruct capture_priv *priv = vb2_get_drv_priv(vq);\n+\tstruct imx_media_buffer *buf, *tmp;\n+\tunsigned long flags;\n+\tint ret;\n+\n+\tret = capture_validate_fmt(priv);\n+\tif (ret) {\n+\t\tdev_err(priv->dev, \"capture format not valid\\n\");\n+\t\tgoto return_bufs;\n+\t}\n+\n+\tret = imx_media_pipeline_set_stream(priv->md, &priv->src_sd->entity,\n+\t\t\t\t\t    true);\n+\tif (ret) {\n+\t\tdev_err(priv->dev, \"pipeline start failed with %d\\n\", ret);\n+\t\tgoto return_bufs;\n+\t}\n+\n+\treturn 0;\n+\n+return_bufs:\n+\tspin_lock_irqsave(&priv->q_lock, flags);\n+\tlist_for_each_entry_safe(buf, tmp, &priv->ready_q, list) {\n+\t\tlist_del(&buf->list);\n+\t\tvb2_buffer_done(&buf->vbuf.vb2_buf, VB2_BUF_STATE_QUEUED);\n+\t}\n+\tspin_unlock_irqrestore(&priv->q_lock, flags);\n+\treturn ret;\n+}\n+\n+static void capture_stop_streaming(struct vb2_queue *vq)\n+{\n+\tstruct capture_priv *priv = vb2_get_drv_priv(vq);\n+\tstruct imx_media_buffer *frame;\n+\tstruct imx_media_buffer *tmp;\n+\tunsigned long flags;\n+\tint ret;\n+\n+\tret = imx_media_pipeline_set_stream(priv->md, &priv->src_sd->entity,\n+\t\t\t\t\t    false);\n+\tif (ret)\n+\t\tdev_warn(priv->dev, \"pipeline stop failed with %d\\n\", ret);\n+\n+\t/* release all active buffers */\n+\tspin_lock_irqsave(&priv->q_lock, flags);\n+\tlist_for_each_entry_safe(frame, tmp, &priv->ready_q, list) {\n+\t\tlist_del(&frame->list);\n+\t\tvb2_buffer_done(&frame->vbuf.vb2_buf, VB2_BUF_STATE_ERROR);\n+\t}\n+\tspin_unlock_irqrestore(&priv->q_lock, flags);\n+}\n+\n+static const struct vb2_ops capture_qops = {\n+\t.queue_setup\t = capture_queue_setup,\n+\t.buf_init        = capture_buf_init,\n+\t.buf_prepare\t = capture_buf_prepare,\n+\t.buf_queue\t = capture_buf_queue,\n+\t.wait_prepare\t = vb2_ops_wait_prepare,\n+\t.wait_finish\t = vb2_ops_wait_finish,\n+\t.start_streaming = capture_start_streaming,\n+\t.stop_streaming  = capture_stop_streaming,\n+};\n+\n+/* -----------------------------------------------------------------------------\n+ * Video Capture Device - File Operations\n+ */\n+\n+static int capture_open(struct file *file)\n+{\n+\tstruct capture_priv *priv = video_drvdata(file);\n+\tstruct video_device *vfd = priv->vdev.vfd;\n+\tint ret;\n+\n+\tif (mutex_lock_interruptible(&priv->mutex))\n+\t\treturn -ERESTARTSYS;\n+\n+\tret = v4l2_fh_open(file);\n+\tif (ret) {\n+\t\tdev_err(priv->dev, \"v4l2_fh_open failed\\n\");\n+\t\tgoto out;\n+\t}\n+\n+\tret = v4l2_pipeline_pm_get(&vfd->entity);\n+\tif (ret)\n+\t\tv4l2_fh_release(file);\n+\n+out:\n+\tmutex_unlock(&priv->mutex);\n+\treturn ret;\n+}\n+\n+static int capture_release(struct file *file)\n+{\n+\tstruct capture_priv *priv = video_drvdata(file);\n+\tstruct video_device *vfd = priv->vdev.vfd;\n+\tstruct vb2_queue *vq = &priv->q;\n+\n+\tmutex_lock(&priv->mutex);\n+\n+\tif (file->private_data == vq->owner) {\n+\t\tvb2_queue_release(vq);\n+\t\tvq->owner = NULL;\n+\t}\n+\n+\tv4l2_pipeline_pm_put(&vfd->entity);\n+\n+\tv4l2_fh_release(file);\n+\tmutex_unlock(&priv->mutex);\n+\treturn 0;\n+}\n+\n+static const struct v4l2_file_operations capture_fops = {\n+\t.owner\t\t= THIS_MODULE,\n+\t.open\t\t= capture_open,\n+\t.release\t= capture_release,\n+\t.poll\t\t= vb2_fop_poll,\n+\t.unlocked_ioctl\t= video_ioctl2,\n+\t.mmap\t\t= vb2_fop_mmap,\n+};\n+\n+/* -----------------------------------------------------------------------------\n+ * Video Capture Device - Init & Cleanup\n+ */\n+\n+static struct imx_media_buffer *\n+imx7_media_capture_device_next_buf(struct imx_media_video_dev *vdev)\n+{\n+\tstruct capture_priv *priv = to_capture_priv(vdev);\n+\tstruct imx_media_buffer *buf = NULL;\n+\tunsigned long flags;\n+\n+\tspin_lock_irqsave(&priv->q_lock, flags);\n+\n+\t/* get next queued buffer */\n+\tif (!list_empty(&priv->ready_q)) {\n+\t\tbuf = list_entry(priv->ready_q.next, struct imx_media_buffer,\n+\t\t\t\t list);\n+\t\tlist_del(&buf->list);\n+\t}\n+\n+\tspin_unlock_irqrestore(&priv->q_lock, flags);\n+\n+\treturn buf;\n+}\n+\n+static int capture_init_format(struct capture_priv *priv)\n+{\n+\tstruct v4l2_subdev_format fmt_src = {\n+\t\t.pad = priv->src_sd_pad,\n+\t\t.which = V4L2_SUBDEV_FORMAT_ACTIVE,\n+\t};\n+\tstruct imx_media_video_dev *vdev = &priv->vdev;\n+\tint ret;\n+\n+\tif (priv->legacy_api) {\n+\t\tret = v4l2_subdev_call(priv->src_sd, pad, get_fmt, NULL,\n+\t\t\t\t       &fmt_src);\n+\t\tif (ret) {\n+\t\t\tdev_err(priv->dev, \"failed to get source format\\n\");\n+\t\t\treturn ret;\n+\t\t}\n+\t} else {\n+\t\tfmt_src.format.code = MEDIA_BUS_FMT_UYVY8_2X8;\n+\t\tfmt_src.format.width = IMX_MEDIA_DEF_PIX_WIDTH;\n+\t\tfmt_src.format.height = IMX_MEDIA_DEF_PIX_HEIGHT;\n+\t}\n+\n+\timx_media_mbus_fmt_to_pix_fmt(&vdev->fmt, &fmt_src.format, NULL);\n+\tvdev->compose.width = fmt_src.format.width;\n+\tvdev->compose.height = fmt_src.format.height;\n+\n+\tvdev->cc = imx_media_find_pixel_format(vdev->fmt.pixelformat,\n+\t\t\t\t\t       PIXFMT_SEL_ANY);\n+\n+\treturn 0;\n+}\n+\n+static int imx7_media_capture_device_register(struct imx_media_video_dev *vdev,\n+\t\t\t\t\t      u32 link_flags)\n+{\n+\tstruct capture_priv *priv = to_capture_priv(vdev);\n+\tstruct v4l2_subdev *sd = priv->src_sd;\n+\tstruct v4l2_device *v4l2_dev = sd->v4l2_dev;\n+\tstruct video_device *vfd = vdev->vfd;\n+\tint ret;\n+\n+\t/* get media device */\n+\tpriv->md = container_of(v4l2_dev->mdev, struct imx_media_dev, md);\n+\n+\tvfd->v4l2_dev = v4l2_dev;\n+\n+\t/* Initialize the default format and compose rectangle. */\n+\tret = capture_init_format(priv);\n+\tif (ret < 0)\n+\t\treturn ret;\n+\n+\t/* Register the video device. */\n+\tret = video_register_device(vfd, VFL_TYPE_VIDEO, -1);\n+\tif (ret) {\n+\t\tdev_err(priv->dev, \"Failed to register video device\\n\");\n+\t\treturn ret;\n+\t}\n+\n+\tdev_info(priv->dev, \"Registered %s as /dev/%s\\n\", vfd->name,\n+\t\t video_device_node_name(vfd));\n+\n+\t/* Create the link from the src_sd devnode pad to device node. */\n+\tif (link_flags & MEDIA_LNK_FL_IMMUTABLE)\n+\t\tlink_flags |= MEDIA_LNK_FL_ENABLED;\n+\tret = media_create_pad_link(&sd->entity, priv->src_sd_pad,\n+\t\t\t\t    &vfd->entity, 0, link_flags);\n+\tif (ret) {\n+\t\tdev_err(priv->dev, \"failed to create link to device node\\n\");\n+\t\tvideo_unregister_device(vfd);\n+\t\treturn ret;\n+\t}\n+\n+\t/* Add vdev to the video devices list. */\n+\timx_media_add_video_device(priv->md, vdev);\n+\n+\treturn 0;\n+}\n+\n+static void imx7_media_capture_device_unregister(struct imx_media_video_dev *vdev)\n+{\n+\tstruct capture_priv *priv = to_capture_priv(vdev);\n+\tstruct video_device *vfd = priv->vdev.vfd;\n+\n+\tmedia_entity_cleanup(&vfd->entity);\n+\tvideo_unregister_device(vfd);\n+}\n+\n+static struct imx_media_video_dev *\n+imx7_media_capture_device_init(struct device *dev, struct v4l2_subdev *src_sd,\n+\t\t\t       int pad, bool legacy_api)\n+{\n+\tstruct capture_priv *priv;\n+\tstruct video_device *vfd;\n+\tstruct vb2_queue *vq;\n+\tint ret;\n+\n+\tpriv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);\n+\tif (!priv)\n+\t\treturn ERR_PTR(-ENOMEM);\n+\n+\tpriv->src_sd = src_sd;\n+\tpriv->src_sd_pad = pad;\n+\tpriv->dev = dev;\n+\tpriv->legacy_api = legacy_api;\n+\n+\tmutex_init(&priv->mutex);\n+\tINIT_LIST_HEAD(&priv->ready_q);\n+\tspin_lock_init(&priv->q_lock);\n+\n+\t/* Allocate and initialize the video device. */\n+\tvfd = video_device_alloc();\n+\tif (!vfd)\n+\t\treturn ERR_PTR(-ENOMEM);\n+\n+\tvfd->fops = &capture_fops;\n+\tvfd->ioctl_ops = &capture_ioctl_ops;\n+\tvfd->minor = -1;\n+\tvfd->release = video_device_release;\n+\tvfd->vfl_dir = VFL_DIR_RX;\n+\tvfd->tvnorms = V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM;\n+\tvfd->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING\n+\t\t\t | (!legacy_api ? V4L2_CAP_IO_MC : 0);\n+\tvfd->lock = &priv->mutex;\n+\tvfd->queue = &priv->q;\n+\n+\tsnprintf(vfd->name, sizeof(vfd->name), \"%s capture\", src_sd->name);\n+\n+\tvideo_set_drvdata(vfd, priv);\n+\tpriv->vdev.vfd = vfd;\n+\tINIT_LIST_HEAD(&priv->vdev.list);\n+\n+\t/* Initialize the video device pad. */\n+\tpriv->vdev_pad.flags = MEDIA_PAD_FL_SINK;\n+\tret = media_entity_pads_init(&vfd->entity, 1, &priv->vdev_pad);\n+\tif (ret) {\n+\t\tvideo_device_release(vfd);\n+\t\treturn ERR_PTR(ret);\n+\t}\n+\n+\t/* Initialize the vb2 queue. */\n+\tvq = &priv->q;\n+\tvq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;\n+\tvq->io_modes = VB2_MMAP | VB2_DMABUF;\n+\tvq->drv_priv = priv;\n+\tvq->buf_struct_size = sizeof(struct imx_media_buffer);\n+\tvq->ops = &capture_qops;\n+\tvq->mem_ops = &vb2_dma_contig_memops;\n+\tvq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;\n+\tvq->lock = &priv->mutex;\n+\tvq->min_buffers_needed = 2;\n+\tvq->dev = priv->dev;\n+\n+\tret = vb2_queue_init(vq);\n+\tif (ret) {\n+\t\tdev_err(priv->dev, \"vb2_queue_init failed\\n\");\n+\t\tvideo_device_release(vfd);\n+\t\treturn ERR_PTR(ret);\n+\t}\n+\n+\tif (legacy_api) {\n+\t\t/* Initialize the control handler. */\n+\t\tv4l2_ctrl_handler_init(&priv->ctrl_hdlr, 0);\n+\t\tvfd->ctrl_handler = &priv->ctrl_hdlr;\n+\t}\n+\n+\treturn &priv->vdev;\n+}\n+\n+static void imx7_media_capture_device_remove(struct imx_media_video_dev *vdev)\n+{\n+\tstruct capture_priv *priv = to_capture_priv(vdev);\n+\n+\tv4l2_ctrl_handler_free(&priv->ctrl_hdlr);\n+}\n+\n /* -----------------------------------------------------------------------------\n  * V4L2 Subdev Operations\n  */\n@@ -1049,13 +1741,13 @@ static int imx7_csi_registered(struct v4l2_subdev *sd)\n \tstruct imx7_csi *csi = v4l2_get_subdevdata(sd);\n \tint ret;\n \n-\tcsi->vdev = imx_media_capture_device_init(csi->sd.dev, &csi->sd,\n-\t\t\t\t\t\t  IMX7_CSI_PAD_SRC, false);\n+\tcsi->vdev = imx7_media_capture_device_init(csi->sd.dev, &csi->sd,\n+\t\t\t\t\t\t   IMX7_CSI_PAD_SRC, false);\n \tif (IS_ERR(csi->vdev))\n \t\treturn PTR_ERR(csi->vdev);\n \n-\tret = imx_media_capture_device_register(csi->vdev,\n-\t\t\t\t\t\tMEDIA_LNK_FL_IMMUTABLE);\n+\tret = imx7_media_capture_device_register(csi->vdev,\n+\t\t\t\t\t\t MEDIA_LNK_FL_IMMUTABLE);\n \tif (ret)\n \t\tgoto err_remove;\n \n@@ -1070,9 +1762,9 @@ static int imx7_csi_registered(struct v4l2_subdev *sd)\n \treturn 0;\n \n err_unreg:\n-\timx_media_capture_device_unregister(csi->vdev);\n+\timx7_media_capture_device_unregister(csi->vdev);\n err_remove:\n-\timx_media_capture_device_remove(csi->vdev);\n+\timx7_media_capture_device_remove(csi->vdev);\n \treturn ret;\n }\n \n@@ -1080,8 +1772,8 @@ static void imx7_csi_unregistered(struct v4l2_subdev *sd)\n {\n \tstruct imx7_csi *csi = v4l2_get_subdevdata(sd);\n \n-\timx_media_capture_device_unregister(csi->vdev);\n-\timx_media_capture_device_remove(csi->vdev);\n+\timx7_media_capture_device_unregister(csi->vdev);\n+\timx7_media_capture_device_remove(csi->vdev);\n }\n \n static const struct v4l2_subdev_video_ops imx7_csi_video_ops = {\n",
    "prefixes": [
        "libcamera-devel",
        "11/50"
    ]
}