Store the formats in per-entity request data. The get and set format operations are completely handled by the V4L2 core with help of the try format driver operation. Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@xxxxxxxxxxxxxxxx> --- drivers/media/v4l2-core/v4l2-ioctl.c | 121 +++++++++++++++++++++++++++++++++++ include/media/v4l2-dev.h | 13 ++++ 2 files changed, 134 insertions(+) diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index 8b310e534c7e..40723fd3787f 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -1345,6 +1345,119 @@ static int v4l_enum_fmt(const struct v4l2_ioctl_ops *ops, return ret; } +#if defined(CONFIG_MEDIA_CONTROLLER) +static void vdev_request_data_release(struct media_entity_request_data *data) +{ + struct video_device_request_data *vdata = + to_video_device_request_data(data); + + kfree(vdata); +} + +static int vdev_request_format(struct video_device *vdev, unsigned int req_id, + struct media_device_request **_req, + struct v4l2_pix_format_mplane **_fmt) +{ + struct media_entity_request_data *data; + struct video_device_request_data *vdata; + struct media_device_request *req; + + if (!vdev->v4l2_dev || !vdev->v4l2_dev->mdev) + return -EINVAL; + + req = media_device_request_find(vdev->v4l2_dev->mdev, req_id); + if (!req) + return -EINVAL; + + *_req = req; + + data = media_device_request_get_entity_data(req, &vdev->entity); + if (data) { + vdata = to_video_device_request_data(data); + *_fmt = &vdata->format; + return 0; + } + + vdata = kzalloc(sizeof(*vdata), GFP_KERNEL); + if (!vdata) { + media_device_request_put(req); + return -ENOMEM; + } + + vdata->data.release = vdev_request_data_release; + + media_device_request_set_entity_data(req, &vdev->entity, &vdata->data); + + *_fmt = &vdata->format; + return 0; +} + +static int v4l_g_req_mplane_fmt(const struct v4l2_ioctl_ops *ops, + struct file *file, void *fh, + struct v4l2_format *fmt) +{ + struct video_device *vdev = video_devdata(file); + struct v4l2_pix_format_mplane *format; + struct media_device_request *req; + int ret; + + ret = vdev_request_format(vdev, fmt->fmt.pix_mp.request, + &req, &format); + if (ret < 0) + return ret; + + fmt->fmt.pix_mp = *format; + media_device_request_put(req); + return 0; +} + +static int v4l_s_req_mplane_fmt(const struct v4l2_ioctl_ops *ops, + struct file *file, void *fh, + struct v4l2_format *fmt) +{ + int (*try_op)(struct file *file, void *fh, struct v4l2_format *fmt); + struct video_device *vdev = video_devdata(file); + struct v4l2_pix_format_mplane *format; + struct media_device_request *req; + int ret; + + if (fmt->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + try_op = ops->vidioc_try_fmt_vid_cap_mplane; + else + try_op = ops->vidioc_try_fmt_vid_out_mplane; + + if (unlikely(!try_op)) + return -ENOSYS; + + ret = try_op(file, fh, fmt); + if (ret < 0) + return ret; + + ret = vdev_request_format(vdev, fmt->fmt.pix_mp.request, + &req, &format); + if (ret < 0) + return ret; + + *format = fmt->fmt.pix_mp; + media_device_request_put(req); + return 0; +} +#else +static int v4l_g_req_mplane_fmt(const struct v4l2_ioctl_ops *ops, + struct file *file, void *fh, + struct v4l2_format *fmt) +{ + return -ENOSYS; +} + +static int v4l_s_req_mplane_fmt(const struct v4l2_ioctl_ops *ops, + struct file *file, void *fh, + struct v4l2_format *fmt) +{ + return -ENOSYS; +} +#endif + static int v4l_g_fmt(const struct v4l2_ioctl_ops *ops, struct file *file, void *fh, void *arg) { @@ -1392,6 +1505,8 @@ static int v4l_g_fmt(const struct v4l2_ioctl_ops *ops, case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: if (unlikely(!is_rx || !is_vid || !ops->vidioc_g_fmt_vid_cap_mplane)) break; + if (p->fmt.pix_mp.request) + return v4l_g_req_mplane_fmt(ops, file, fh, p); return ops->vidioc_g_fmt_vid_cap_mplane(file, fh, arg); case V4L2_BUF_TYPE_VIDEO_OVERLAY: if (unlikely(!is_rx || !is_vid || !ops->vidioc_g_fmt_vid_overlay)) @@ -1416,6 +1531,8 @@ static int v4l_g_fmt(const struct v4l2_ioctl_ops *ops, case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: if (unlikely(!is_tx || !is_vid || !ops->vidioc_g_fmt_vid_out_mplane)) break; + if (p->fmt.pix_mp.request) + return v4l_g_req_mplane_fmt(ops, file, fh, p); return ops->vidioc_g_fmt_vid_out_mplane(file, fh, arg); case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: if (unlikely(!is_tx || !is_vid || !ops->vidioc_g_fmt_vid_out_overlay)) @@ -1467,6 +1584,8 @@ static int v4l_s_fmt(const struct v4l2_ioctl_ops *ops, if (unlikely(!is_rx || !is_vid || !ops->vidioc_s_fmt_vid_cap_mplane)) break; CLEAR_AFTER_FIELD(p, fmt.pix_mp); + if (p->fmt.pix_mp.request) + return v4l_s_req_mplane_fmt(ops, file, fh, p); return ops->vidioc_s_fmt_vid_cap_mplane(file, fh, arg); case V4L2_BUF_TYPE_VIDEO_OVERLAY: if (unlikely(!is_rx || !is_vid || !ops->vidioc_s_fmt_vid_overlay)) @@ -1495,6 +1614,8 @@ static int v4l_s_fmt(const struct v4l2_ioctl_ops *ops, if (unlikely(!is_tx || !is_vid || !ops->vidioc_s_fmt_vid_out_mplane)) break; CLEAR_AFTER_FIELD(p, fmt.pix_mp); + if (p->fmt.pix_mp.request) + return v4l_s_req_mplane_fmt(ops, file, fh, p); return ops->vidioc_s_fmt_vid_out_mplane(file, fh, arg); case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: if (unlikely(!is_tx || !is_vid || !ops->vidioc_s_fmt_vid_out_overlay)) diff --git a/include/media/v4l2-dev.h b/include/media/v4l2-dev.h index acbcd2f5fe7f..9fb386a6e505 100644 --- a/include/media/v4l2-dev.h +++ b/include/media/v4l2-dev.h @@ -233,4 +233,17 @@ static inline int video_is_registered(struct video_device *vdev) return test_bit(V4L2_FL_REGISTERED, &vdev->flags); } +#if defined(CONFIG_MEDIA_CONTROLLER) +struct video_device_request_data { + struct media_entity_request_data data; + struct v4l2_pix_format_mplane format; +}; + +static inline struct video_device_request_data * +to_video_device_request_data(struct media_entity_request_data *data) +{ + return container_of(data, struct video_device_request_data, data); +} +#endif + #endif /* _V4L2_DEV_H */ -- 2.4.10