summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLaurent Pinchart <laurent.pinchart@ideasonboard.com>2021-02-15 05:26:51 +0100
committerMauro Carvalho Chehab <mchehab+huawei@kernel.org>2021-03-11 11:59:49 +0100
commitb41e932604257d162f3f9223d8659c755b5a66a8 (patch)
treedff553f346b7d3fff327569d073a9ecdcf6b6147
parent5e14568ccbdf62955b30459f78f96195be37bf20 (diff)
downloadlinux-stable-b41e932604257d162f3f9223d8659c755b5a66a8.tar.gz
linux-stable-b41e932604257d162f3f9223d8659c755b5a66a8.tar.bz2
linux-stable-b41e932604257d162f3f9223d8659c755b5a66a8.zip
media: imx: capture: Decouple video node from source with MC-centric API
When operating in MC-centric mode, the behaviour of video nodes shall not be influenced by the active configuration of the source subdev. Add a set of ioctl handlers that implement this mode, and select them when support for the legacy API is not requested. Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Reviewed-by: Rui Miguel Silva <rmfrfs@gmail.com> Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl> Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
-rw-r--r--drivers/staging/media/imx/imx-media-capture.c161
1 files changed, 155 insertions, 6 deletions
diff --git a/drivers/staging/media/imx/imx-media-capture.c b/drivers/staging/media/imx/imx-media-capture.c
index 700e99d02523..99133b7ffa5f 100644
--- a/drivers/staging/media/imx/imx-media-capture.c
+++ b/drivers/staging/media/imx/imx-media-capture.c
@@ -55,7 +55,7 @@ struct capture_priv {
#define VID_MEM_LIMIT SZ_64M
/* -----------------------------------------------------------------------------
- * Common Video IOCTLs
+ * MC-Centric Video IOCTLs
*/
static const struct imx_media_pixfmt *capture_find_format(u32 code, u32 fourcc)
@@ -92,6 +92,41 @@ static int capture_querycap(struct file *file, void *fh,
return 0;
}
+static int capture_enum_fmt_vid_cap(struct file *file, void *fh,
+ struct v4l2_fmtdesc *f)
+{
+ return imx_media_enum_pixel_formats(&f->pixelformat, f->index,
+ PIXFMT_SEL_ANY, 0);
+}
+
+static int capture_enum_framesizes(struct file *file, void *fh,
+ struct v4l2_frmsizeenum *fsize)
+{
+ const struct imx_media_pixfmt *cc;
+
+ if (fsize->index > 0)
+ return -EINVAL;
+
+ cc = imx_media_find_pixel_format(fsize->pixel_format, PIXFMT_SEL_ANY);
+ if (!cc)
+ return -EINVAL;
+
+ /*
+ * TODO: The constraints are hardware-specific and may depend on the
+ * pixel format. This should come from the driver using
+ * imx_media_capture.
+ */
+ fsize->type = V4L2_FRMSIZE_TYPE_CONTINUOUS;
+ fsize->stepwise.min_width = 1;
+ fsize->stepwise.max_width = 65535;
+ fsize->stepwise.min_height = 1;
+ fsize->stepwise.max_height = 65535;
+ fsize->stepwise.step_width = 1;
+ fsize->stepwise.step_height = 1;
+
+ return 0;
+}
+
static int capture_g_fmt_vid_cap(struct file *file, void *fh,
struct v4l2_format *f)
{
@@ -102,6 +137,75 @@ static int capture_g_fmt_vid_cap(struct file *file, void *fh,
return 0;
}
+static const struct imx_media_pixfmt *
+__capture_try_fmt(struct v4l2_pix_format *pixfmt, struct v4l2_rect *compose)
+{
+ struct v4l2_mbus_framefmt fmt_src;
+ const struct imx_media_pixfmt *cc;
+
+ /*
+ * Find the pixel format, default to the first supported format if not
+ * found.
+ */
+ cc = imx_media_find_pixel_format(pixfmt->pixelformat, PIXFMT_SEL_ANY);
+ if (!cc) {
+ imx_media_enum_pixel_formats(&pixfmt->pixelformat, 0,
+ PIXFMT_SEL_ANY, 0);
+ cc = imx_media_find_pixel_format(pixfmt->pixelformat,
+ PIXFMT_SEL_ANY);
+ }
+
+ /* Allow IDMAC interweave but enforce field order from source. */
+ if (V4L2_FIELD_IS_INTERLACED(pixfmt->field)) {
+ switch (pixfmt->field) {
+ case V4L2_FIELD_SEQ_TB:
+ pixfmt->field = V4L2_FIELD_INTERLACED_TB;
+ break;
+ case V4L2_FIELD_SEQ_BT:
+ pixfmt->field = V4L2_FIELD_INTERLACED_BT;
+ break;
+ default:
+ break;
+ }
+ }
+
+ v4l2_fill_mbus_format(&fmt_src, pixfmt, 0);
+ imx_media_mbus_fmt_to_pix_fmt(pixfmt, &fmt_src, cc);
+
+ if (compose) {
+ compose->width = fmt_src.width;
+ compose->height = fmt_src.height;
+ }
+
+ return cc;
+}
+
+static int capture_try_fmt_vid_cap(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ __capture_try_fmt(&f->fmt.pix, NULL);
+ return 0;
+}
+
+static int capture_s_fmt_vid_cap(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ struct capture_priv *priv = video_drvdata(file);
+ const struct imx_media_pixfmt *cc;
+
+ if (vb2_is_busy(&priv->q)) {
+ dev_err(priv->dev, "%s queue busy\n", __func__);
+ return -EBUSY;
+ }
+
+ cc = __capture_try_fmt(&f->fmt.pix, &priv->vdev.compose);
+
+ priv->vdev.cc = cc;
+ priv->vdev.fmt = f->fmt.pix;
+
+ return 0;
+}
+
static int capture_g_selection(struct file *file, void *fh,
struct v4l2_selection *s)
{
@@ -132,6 +236,43 @@ static int capture_g_selection(struct file *file, void *fh,
return 0;
}
+static int capture_subscribe_event(struct v4l2_fh *fh,
+ const struct v4l2_event_subscription *sub)
+{
+ switch (sub->type) {
+ case V4L2_EVENT_IMX_FRAME_INTERVAL_ERROR:
+ return v4l2_event_subscribe(fh, sub, 0, NULL);
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct v4l2_ioctl_ops capture_ioctl_ops = {
+ .vidioc_querycap = capture_querycap,
+
+ .vidioc_enum_fmt_vid_cap = capture_enum_fmt_vid_cap,
+ .vidioc_enum_framesizes = capture_enum_framesizes,
+
+ .vidioc_g_fmt_vid_cap = capture_g_fmt_vid_cap,
+ .vidioc_try_fmt_vid_cap = capture_try_fmt_vid_cap,
+ .vidioc_s_fmt_vid_cap = capture_s_fmt_vid_cap,
+
+ .vidioc_g_selection = capture_g_selection,
+
+ .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_streamon = vb2_ioctl_streamon,
+ .vidioc_streamoff = vb2_ioctl_streamoff,
+
+ .vidioc_subscribe_event = capture_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+};
+
/* -----------------------------------------------------------------------------
* Legacy Video IOCTLs
*/
@@ -734,10 +875,17 @@ static int capture_init_format(struct capture_priv *priv)
struct imx_media_video_dev *vdev = &priv->vdev;
int ret;
- ret = v4l2_subdev_call(priv->src_sd, pad, get_fmt, NULL, &fmt_src);
- if (ret) {
- dev_err(priv->dev, "failed to get source format\n");
- return ret;
+ if (priv->legacy_api) {
+ ret = v4l2_subdev_call(priv->src_sd, pad, get_fmt, NULL,
+ &fmt_src);
+ if (ret) {
+ dev_err(priv->dev, "failed to get source format\n");
+ return ret;
+ }
+ } else {
+ fmt_src.format.code = MEDIA_BUS_FMT_UYVY8_2X8;
+ fmt_src.format.width = IMX_MEDIA_DEF_PIX_WIDTH;
+ fmt_src.format.height = IMX_MEDIA_DEF_PIX_HEIGHT;
}
imx_media_mbus_fmt_to_pix_fmt(&vdev->fmt, &fmt_src.format, NULL);
@@ -832,7 +980,8 @@ imx_media_capture_device_init(struct device *dev, struct v4l2_subdev *src_sd,
return ERR_PTR(-ENOMEM);
vfd->fops = &capture_fops;
- vfd->ioctl_ops = &capture_legacy_ioctl_ops;
+ vfd->ioctl_ops = legacy_api ? &capture_legacy_ioctl_ops
+ : &capture_ioctl_ops;
vfd->minor = -1;
vfd->release = video_device_release;
vfd->vfl_dir = VFL_DIR_RX;