diff options
Diffstat (limited to 'drivers/staging/media/imx/imx-media-capture.c')
-rw-r--r-- | drivers/staging/media/imx/imx-media-capture.c | 119 |
1 files changed, 102 insertions, 17 deletions
diff --git a/drivers/staging/media/imx/imx-media-capture.c b/drivers/staging/media/imx/imx-media-capture.c index b37e1186eb2f..9703c85b19c4 100644 --- a/drivers/staging/media/imx/imx-media-capture.c +++ b/drivers/staging/media/imx/imx-media-capture.c @@ -203,21 +203,14 @@ static int capture_g_fmt_vid_cap(struct file *file, void *fh, return 0; } -static int capture_try_fmt_vid_cap(struct file *file, void *fh, - struct v4l2_format *f) +static int __capture_try_fmt_vid_cap(struct capture_priv *priv, + struct v4l2_subdev_format *fmt_src, + struct v4l2_format *f, + struct v4l2_rect *compose) { - struct capture_priv *priv = video_drvdata(file); - struct v4l2_subdev_format fmt_src; const struct imx_media_pixfmt *cc, *cc_src; - int ret; - - fmt_src.pad = priv->src_sd_pad; - fmt_src.which = V4L2_SUBDEV_FORMAT_ACTIVE; - ret = v4l2_subdev_call(priv->src_sd, pad, get_fmt, NULL, &fmt_src); - if (ret) - return ret; - cc_src = imx_media_find_ipu_format(fmt_src.format.code, CS_SEL_ANY); + cc_src = imx_media_find_ipu_format(fmt_src->format.code, CS_SEL_ANY); if (cc_src) { u32 fourcc, cs_sel; @@ -231,7 +224,7 @@ static int capture_try_fmt_vid_cap(struct file *file, void *fh, cc = imx_media_find_format(fourcc, cs_sel, false); } } else { - cc_src = imx_media_find_mbus_format(fmt_src.format.code, + cc_src = imx_media_find_mbus_format(fmt_src->format.code, CS_SEL_ANY, true); if (WARN_ON(!cc_src)) return -EINVAL; @@ -239,15 +232,48 @@ static int capture_try_fmt_vid_cap(struct file *file, void *fh, cc = cc_src; } - imx_media_mbus_fmt_to_pix_fmt(&f->fmt.pix, &fmt_src.format, cc); + /* allow IDMAC interweave but enforce field order from source */ + if (V4L2_FIELD_IS_INTERLACED(f->fmt.pix.field)) { + switch (fmt_src->format.field) { + case V4L2_FIELD_SEQ_TB: + fmt_src->format.field = V4L2_FIELD_INTERLACED_TB; + break; + case V4L2_FIELD_SEQ_BT: + fmt_src->format.field = V4L2_FIELD_INTERLACED_BT; + break; + default: + break; + } + } + + imx_media_mbus_fmt_to_pix_fmt(&f->fmt.pix, compose, + &fmt_src->format, cc); return 0; } +static int capture_try_fmt_vid_cap(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct capture_priv *priv = video_drvdata(file); + struct v4l2_subdev_format fmt_src; + int ret; + + fmt_src.pad = priv->src_sd_pad; + fmt_src.which = V4L2_SUBDEV_FORMAT_ACTIVE; + ret = v4l2_subdev_call(priv->src_sd, pad, get_fmt, NULL, &fmt_src); + if (ret) + return ret; + + return __capture_try_fmt_vid_cap(priv, &fmt_src, f, NULL); +} + static int capture_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f) { struct capture_priv *priv = video_drvdata(file); + struct v4l2_subdev_format fmt_src; + struct v4l2_rect compose; int ret; if (vb2_is_busy(&priv->q)) { @@ -255,13 +281,20 @@ static int capture_s_fmt_vid_cap(struct file *file, void *fh, return -EBUSY; } - ret = capture_try_fmt_vid_cap(file, priv, f); + fmt_src.pad = priv->src_sd_pad; + fmt_src.which = V4L2_SUBDEV_FORMAT_ACTIVE; + ret = v4l2_subdev_call(priv->src_sd, pad, get_fmt, NULL, &fmt_src); + if (ret) + return ret; + + ret = __capture_try_fmt_vid_cap(priv, &fmt_src, f, &compose); if (ret) return ret; priv->vdev.fmt.fmt.pix = f->fmt.pix; priv->vdev.cc = imx_media_find_format(f->fmt.pix.pixelformat, CS_SEL_ANY, true); + priv->vdev.compose = compose; return 0; } @@ -290,6 +323,36 @@ static int capture_s_std(struct file *file, void *fh, v4l2_std_id std) return v4l2_subdev_call(priv->src_sd, video, s_std, std); } +static int capture_g_selection(struct file *file, void *fh, + struct v4l2_selection *s) +{ + struct capture_priv *priv = video_drvdata(file); + + switch (s->target) { + case V4L2_SEL_TGT_COMPOSE: + case V4L2_SEL_TGT_COMPOSE_DEFAULT: + case V4L2_SEL_TGT_COMPOSE_BOUNDS: + /* The compose rectangle is fixed to the source format. */ + s->r = priv->vdev.compose; + break; + case V4L2_SEL_TGT_COMPOSE_PADDED: + /* + * The hardware writes with a configurable but fixed DMA burst + * size. If the source format width is not burst size aligned, + * the written frame contains padding to the right. + */ + s->r.left = 0; + s->r.top = 0; + s->r.width = priv->vdev.fmt.fmt.pix.width; + s->r.height = priv->vdev.fmt.fmt.pix.height; + break; + default: + return -EINVAL; + } + + return 0; +} + static int capture_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a) { @@ -335,6 +398,21 @@ static int capture_s_parm(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); + case V4L2_EVENT_SOURCE_CHANGE: + return v4l2_src_change_event_subscribe(fh, sub); + case V4L2_EVENT_CTRL: + return v4l2_ctrl_subscribe_event(fh, sub); + default: + return -EINVAL; + } +} + static const struct v4l2_ioctl_ops capture_ioctl_ops = { .vidioc_querycap = vidioc_querycap, @@ -350,6 +428,8 @@ static const struct v4l2_ioctl_ops capture_ioctl_ops = { .vidioc_g_std = capture_g_std, .vidioc_s_std = capture_s_std, + .vidioc_g_selection = capture_g_selection, + .vidioc_g_parm = capture_g_parm, .vidioc_s_parm = capture_s_parm, @@ -362,6 +442,9 @@ static const struct v4l2_ioctl_ops capture_ioctl_ops = { .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, }; /* @@ -572,7 +655,8 @@ static struct video_device capture_videodev = { }; void imx_media_capture_device_set_format(struct imx_media_video_dev *vdev, - struct v4l2_pix_format *pix) + const struct v4l2_pix_format *pix, + const struct v4l2_rect *compose) { struct capture_priv *priv = to_capture_priv(vdev); @@ -580,6 +664,7 @@ void imx_media_capture_device_set_format(struct imx_media_video_dev *vdev, priv->vdev.fmt.fmt.pix = *pix; priv->vdev.cc = imx_media_find_format(pix->pixelformat, CS_SEL_ANY, true); + priv->vdev.compose = *compose; mutex_unlock(&priv->mutex); } EXPORT_SYMBOL_GPL(imx_media_capture_device_set_format); @@ -685,7 +770,7 @@ int imx_media_capture_device_register(struct imx_media_video_dev *vdev) } vdev->fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - imx_media_mbus_fmt_to_pix_fmt(&vdev->fmt.fmt.pix, + imx_media_mbus_fmt_to_pix_fmt(&vdev->fmt.fmt.pix, &vdev->compose, &fmt_src.format, NULL); vdev->cc = imx_media_find_format(vdev->fmt.fmt.pix.pixelformat, CS_SEL_ANY, false); |