@@ -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: