From: Pawel Osciak <pawel@xxxxxxxxxx> Drivers that support only one variant of API - single- or multi-planar - can still be used by applications that support the other variant in most cases. This adds a conversion layer for buffer types for such situations. Signed-off-by: Pawel Osciak <pawel@xxxxxxxxxx> Signed-off-by: Marek Szyprowski <m.szyprowski@xxxxxxxxxxx> --- drivers/media/video/v4l2-ioctl.c | 206 +++++++++++++++++++++++++++++++++---- 1 files changed, 183 insertions(+), 23 deletions(-) diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c index 5d46aa2..fee8b94 100644 --- a/drivers/media/video/v4l2-ioctl.c +++ b/drivers/media/video/v4l2-ioctl.c @@ -605,27 +605,21 @@ static int check_fmt(const struct v4l2_ioctl_ops *ops, enum v4l2_buf_type type) switch (type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: if (ops->vidioc_g_fmt_vid_cap || ops->vidioc_g_fmt_vid_cap_mplane) return 0; break; - case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - if (ops->vidioc_g_fmt_vid_cap_mplane) - return 0; - break; case V4L2_BUF_TYPE_VIDEO_OVERLAY: if (ops->vidioc_g_fmt_vid_overlay) return 0; break; case V4L2_BUF_TYPE_VIDEO_OUTPUT: + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: if (ops->vidioc_g_fmt_vid_out || ops->vidioc_g_fmt_vid_out_mplane) return 0; break; - case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - if (ops->vidioc_g_fmt_vid_out_mplane) - return 0; - break; case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: if (ops->vidioc_g_fmt_vid_out_overlay) return 0; @@ -654,6 +648,64 @@ static int check_fmt(const struct v4l2_ioctl_ops *ops, enum v4l2_buf_type type) return -EINVAL; } +static enum v4l2_buf_type convert_type(const struct v4l2_ioctl_ops *ops, + enum v4l2_buf_type type) +{ + if (ops == NULL) + return type; + + switch (type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + if (!ops->vidioc_g_fmt_vid_cap + && ops->vidioc_g_fmt_vid_cap_mplane) + return V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + break; + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + if (!ops->vidioc_g_fmt_vid_cap_mplane + && ops->vidioc_g_fmt_vid_cap) + return V4L2_BUF_TYPE_VIDEO_CAPTURE; + break; + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + if (!ops->vidioc_g_fmt_vid_out + && ops->vidioc_g_fmt_vid_out_mplane) + return V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + break; + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + if (!ops->vidioc_g_fmt_vid_out_mplane + && ops->vidioc_g_fmt_vid_out) + return V4L2_BUF_TYPE_VIDEO_OUTPUT; + break; + default: + break; + } + + return type; +} + +static int type_sp_to_mp(enum v4l2_buf_type t_sp, enum v4l2_buf_type *t_mp) +{ + if (t_sp == V4L2_BUF_TYPE_VIDEO_CAPTURE) + *t_mp = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + else if (t_sp == V4L2_BUF_TYPE_VIDEO_OUTPUT) + *t_mp = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + else + return -EINVAL; + + return 0; +} + +static int type_mp_to_sp(enum v4l2_buf_type t_mp, enum v4l2_buf_type *t_sp) +{ + if (t_mp == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + *t_sp = V4L2_BUF_TYPE_VIDEO_CAPTURE; + else if (t_mp == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) + *t_sp = V4L2_BUF_TYPE_VIDEO_OUTPUT; + else + return -EINVAL; + + return 0; +} + /** * fmt_sp_to_mp() - Convert a single-plane format to its multi-planar 1-plane * equivalent @@ -663,13 +715,11 @@ static int fmt_sp_to_mp(const struct v4l2_format *f_sp, { struct v4l2_pix_format_mplane *pix_mp = &f_mp->fmt.pix_mp; const struct v4l2_pix_format *pix = &f_sp->fmt.pix; + int ret; - if (f_sp->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) - f_mp->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; - else if (f_sp->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) - f_mp->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; - else - return -EINVAL; + ret = type_sp_to_mp(f_sp->type, &f_mp->type); + if (ret) + return ret; pix_mp->width = pix->width; pix_mp->height = pix->height; @@ -692,13 +742,11 @@ static int fmt_mp_to_sp(const struct v4l2_format *f_mp, { const struct v4l2_pix_format_mplane *pix_mp = &f_mp->fmt.pix_mp; struct v4l2_pix_format *pix = &f_sp->fmt.pix; + int ret; - if (f_mp->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) - f_sp->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - else if (f_mp->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) - f_sp->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; - else - return -EINVAL; + ret = type_mp_to_sp(f_mp->type, &f_sp->type); + if (ret) + return ret; pix->width = pix_mp->width; pix->height = pix_mp->height; @@ -711,6 +759,48 @@ static int fmt_mp_to_sp(const struct v4l2_format *f_mp, return 0; } +static int buf_sp_to_mp(const struct v4l2_buffer *b_sp, + struct v4l2_buffer *b_mp) +{ + int ret; + + memcpy(b_mp, b_sp, sizeof *b_mp); + ret = type_sp_to_mp(b_sp->type, &b_mp->type); + if (ret) + return ret; + b_mp->m.planes[0].length = b_sp->length; + b_mp->m.planes[0].bytesused = b_mp->bytesused; + b_mp->length = 1; + memcpy(&b_mp->m.planes[0].m, &b_sp->m, sizeof(struct v4l2_plane)); + + return 0; +} + +static int buf_mp_to_sp(const struct v4l2_buffer *b_mp, + struct v4l2_buffer *b_sp) +{ + int ret; + + memcpy(b_sp, b_mp, sizeof *b_sp); + ret = type_mp_to_sp(b_mp->type, &b_sp->type); + if (ret) + return ret; + b_sp->length = b_mp->m.planes[0].length; + b_sp->bytesused = b_mp->m.planes[0].bytesused; + memcpy(&b_sp->m, &b_mp->m.planes[0].m, sizeof(struct v4l2_plane)); + + return 0; +} + +static int convert_buffer(const struct v4l2_buffer *b_src, + struct v4l2_buffer *b_dst) +{ + if (V4L2_TYPE_IS_MULTIPLANAR(b_src->type)) + return buf_mp_to_sp(b_src, b_dst); + else + return buf_sp_to_mp(b_src, b_dst); +} + static long __video_do_ioctl(struct file *file, unsigned int cmd, void *arg) { @@ -718,6 +808,9 @@ static long __video_do_ioctl(struct file *file, const struct v4l2_ioctl_ops *ops = vfd->ioctl_ops; void *fh = file->private_data; struct v4l2_format f_copy; + enum v4l2_buf_type old_type; + struct v4l2_buffer buf_copy; + struct v4l2_plane buf_copy_planes[VIDEO_MAX_PLANES]; long ret = -EINVAL; if (ops == NULL) { @@ -726,6 +819,8 @@ static long __video_do_ioctl(struct file *file, return -EINVAL; } + buf_copy.m.planes = buf_copy_planes; + #ifdef CONFIG_VIDEO_V4L1_COMPAT /******************************************************** All other V4L1 calls are handled by v4l1_compat module. @@ -1241,11 +1336,15 @@ static long __video_do_ioctl(struct file *file, if (p->type < V4L2_BUF_TYPE_PRIVATE) CLEAR_AFTER_FIELD(p, memory); + old_type = p->type; + p->type = convert_type(ops, p->type); + ret = ops->vidioc_reqbufs(file, fh, p); dbgarg(cmd, "count=%d, type=%s, memory=%s\n", p->count, prt_names(p->type, v4l2_type_names), prt_names(p->memory, v4l2_memory_names)); + p->type = old_type; break; } case VIDIOC_QUERYBUF: @@ -1258,7 +1357,17 @@ static long __video_do_ioctl(struct file *file, if (ret) break; - ret = ops->vidioc_querybuf(file, fh, p); + buf_copy.type = convert_type(ops, p->type); + if (p->type != buf_copy.type) { + ret = convert_buffer(p, &buf_copy); + if (ret) + break; + ret = ops->vidioc_querybuf(file, fh, &buf_copy); + if (!ret) + ret = convert_buffer(&buf_copy, p); + } else { + ret = ops->vidioc_querybuf(file, fh, p); + } if (!ret) dbgbuf(cmd, vfd, p); break; @@ -1273,7 +1382,17 @@ static long __video_do_ioctl(struct file *file, if (ret) break; - ret = ops->vidioc_qbuf(file, fh, p); + buf_copy.type = convert_type(ops, p->type); + if (p->type != buf_copy.type) { + ret = convert_buffer(p, &buf_copy); + if (ret) + break; + ret = ops->vidioc_qbuf(file, fh, &buf_copy); + if (!ret) + ret = convert_buffer(&buf_copy, p); + } else { + ret = ops->vidioc_qbuf(file, fh, p); + } if (!ret) dbgbuf(cmd, vfd, p); break; @@ -1288,7 +1407,17 @@ static long __video_do_ioctl(struct file *file, if (ret) break; - ret = ops->vidioc_dqbuf(file, fh, p); + buf_copy.type = convert_type(ops, p->type); + if (p->type != buf_copy.type) { + ret = convert_buffer(p, &buf_copy); + if (ret) + break; + ret = ops->vidioc_dqbuf(file, fh, &buf_copy); + if (!ret) + ret = convert_buffer(&buf_copy, p); + } else { + ret = ops->vidioc_dqbuf(file, fh, p); + } if (!ret) dbgbuf(cmd, vfd, p); break; @@ -1337,6 +1466,9 @@ static long __video_do_ioctl(struct file *file, if (!ops->vidioc_streamon) break; dbgarg(cmd, "type=%s\n", prt_names(i, v4l2_type_names)); + + i = convert_type(ops, i); + ret = ops->vidioc_streamon(file, fh, i); break; } @@ -1347,6 +1479,9 @@ static long __video_do_ioctl(struct file *file, if (!ops->vidioc_streamoff) break; dbgarg(cmd, "type=%s\n", prt_names(i, v4l2_type_names)); + + i = convert_type(ops, i); + ret = ops->vidioc_streamoff(file, fh, i); break; } @@ -1811,9 +1946,14 @@ static long __video_do_ioctl(struct file *file, break; dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names)); + + old_type = p->type; + p->type = convert_type(ops, p->type); + ret = ops->vidioc_g_crop(file, fh, p); if (!ret) dbgrect(vfd, "", &p->c); + p->type = old_type; break; } case VIDIOC_S_CROP: @@ -1824,7 +1964,12 @@ static long __video_do_ioctl(struct file *file, break; dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names)); dbgrect(vfd, "", &p->c); + + old_type = p->type; + p->type = convert_type(ops, p->type); + ret = ops->vidioc_s_crop(file, fh, p); + p->type = old_type; break; } case VIDIOC_CROPCAP: @@ -1836,11 +1981,16 @@ static long __video_do_ioctl(struct file *file, break; dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names)); + + old_type = p->type; + p->type = convert_type(ops, p->type); + ret = ops->vidioc_cropcap(file, fh, p); if (!ret) { dbgrect(vfd, "bounds ", &p->bounds); dbgrect(vfd, "defrect ", &p->defrect); } + p->type = old_type; break; } case VIDIOC_G_JPEGCOMP: @@ -1914,7 +2064,12 @@ static long __video_do_ioctl(struct file *file, ret = check_fmt(ops, p->type); if (ret) break; + + old_type = p->type; + p->type = convert_type(ops, p->type); + ret = ops->vidioc_g_parm(file, fh, p); + p->type = old_type; } else { v4l2_std_id std = vfd->current_norm; @@ -1945,7 +2100,12 @@ static long __video_do_ioctl(struct file *file, break; dbgarg(cmd, "type=%d\n", p->type); + + old_type = p->type; + p->type = convert_type(ops, p->type); + ret = ops->vidioc_s_parm(file, fh, p); + p->type = old_type; break; } case VIDIOC_G_TUNER: -- 1.7.1.569.g6f426 -- To unsubscribe from this list: send the line "unsubscribe linux-media" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html