@@ -66,6 +66,10 @@ static unsigned n_devs = 1;
module_param(n_devs, uint, 0644);
MODULE_PARM_DESC(n_devs, "number of video devices to create");
+static bool multiplanar;
+module_param(multiplanar, bool, 0644);
+MODULE_PARM_DESC(multiplanar, "select multiplanar formats");
+
static unsigned debug;
module_param(debug, uint, 0644);
MODULE_PARM_DESC(debug, "activates debug info");
@@ -160,6 +164,15 @@ static const struct vivi_fmt formats[] = {
},
};
+static const struct vivi_fmt mplane_formats[] = {
+ {
+ .name = "4:2:2, planar, YUV",
+ .fourcc = V4L2_PIX_FMT_YUV422M,
+ .depth = 16,
+ .is_yuv = true,
+ },
+};
+
static const struct vivi_fmt *__get_format(u32 pixelformat)
{
const struct vivi_fmt *fmt;
@@ -168,13 +181,17 @@ static const struct vivi_fmt *__get_format(u32 pixelformat)
for (k = 0; k < ARRAY_SIZE(formats); k++) {
fmt = &formats[k];
if (fmt->fourcc == pixelformat)
- break;
+ return fmt;
}
- if (k == ARRAY_SIZE(formats))
+ if (!multiplanar)
return NULL;
-
- return &formats[k];
+ for (k = 0; k < ARRAY_SIZE(mplane_formats); k++) {
+ fmt = &mplane_formats[k];
+ if (fmt->fourcc == pixelformat)
+ return fmt;
+ }
+ return NULL;
}
static const struct vivi_fmt *get_format(struct v4l2_format *f)
@@ -348,6 +365,7 @@ static void precalculate_bars(struct vivi_dev *dev)
case V4L2_PIX_FMT_UYVY:
case V4L2_PIX_FMT_YVYU:
case V4L2_PIX_FMT_VYUY:
+ case V4L2_PIX_FMT_YUV422M:
case V4L2_PIX_FMT_RGB24:
case V4L2_PIX_FMT_BGR24:
case V4L2_PIX_FMT_RGB32:
@@ -368,7 +386,7 @@ static void precalculate_bars(struct vivi_dev *dev)
}
/* 'odd' is true for pixels 1, 3, 5, etc. and false for pixels 0, 2, 4, etc. */
-static void gen_twopix(struct vivi_dev *dev, u8 *buf, int colorpos, bool odd)
+static void gen_twopix(struct vivi_dev *dev, u8 *buf, int colorpos, unsigned plane, bool odd)
{
u8 r_y, g_u, b_v;
u8 alpha = dev->alpha_component;
@@ -383,6 +401,7 @@ static void gen_twopix(struct vivi_dev *dev, u8 *buf, int colorpos, bool odd)
p = buf + color;
switch (dev->fmt->fourcc) {
+ case V4L2_PIX_FMT_YUV422M:
case V4L2_PIX_FMT_YUYV:
switch (color) {
case 0:
@@ -538,11 +557,26 @@ static void precalculate_line(struct vivi_dev *dev)
int wend = (colorpos+1) * dev->width / 8;
int w;
- gen_twopix(dev, &pix[0], colorpos % 8, 0);
- gen_twopix(dev, &pix[pixsize], colorpos % 8, 1);
-
- for (w = wstart/2*2, pos = dev->line + w*pixsize; w < wend; w += 2, pos += pixsize2)
- memcpy(pos, pix, pixsize2);
+ gen_twopix(dev, &pix[0], colorpos % 8, 0, 0);
+ gen_twopix(dev, &pix[pixsize], colorpos % 8, 0, 1);
+
+ if (dev->fmt->fourcc == V4L2_PIX_FMT_YUV422M) {
+ u8 tmp;
+
+ /* Change YUYV to YYUV */
+ tmp = pix[1];
+ pix[1] = pix[2];
+ pix[2] = tmp;
+ for (w = wstart/2*2, pos = dev->line + w*pixsize; w < wend; w += 2, pos += pixsize)
+ memcpy(pos, pix, pixsize);
+ for (w = wstart/2*2, pos = dev->line + MAX_WIDTH * 2 + w*pixsize/2; w < wend; w += 2, pos += pixsize / 2)
+ memcpy(pos, pix + 1, pixsize / 2);
+ for (w = wstart/2*2, pos = dev->line + MAX_WIDTH * 4 + w*pixsize/2; w < wend; w += 2, pos += pixsize / 2)
+ memcpy(pos, pix + 2, pixsize / 2);
+ } else {
+ for (w = wstart/2*2, pos = dev->line + w*pixsize; w < wend; w += 2, pos += pixsize2)
+ memcpy(pos, pix, pixsize2);
+ }
}
}
@@ -600,6 +634,7 @@ static void gen_text(struct vivi_dev *dev, char *basep,
static void vivi_fillbuff(struct vivi_dev *dev, struct vivi_buffer *buf)
{
int stride = dev->width * dev->pixelsize;
+ unsigned planes = 1;
int hmax = dev->height;
void *vbuf = vb2_plane_vaddr(&buf->vb, 0);
unsigned ms;
@@ -611,15 +646,38 @@ static void vivi_fillbuff(struct vivi_dev *dev, struct vivi_buffer *buf)
if (!vbuf)
return;
- linestart = dev->line + (dev->mv_count % dev->width) * dev->pixelsize;
+ if (dev->fmt->fourcc == V4L2_PIX_FMT_YUV422M)
+ planes = 3;
+
+ if (planes > 1) {
+ void *vbuf1 = vb2_plane_vaddr(&buf->vb, 1);
+ void *vbuf2 = vb2_plane_vaddr(&buf->vb, 2);
+
+ memset(vbuf, 128, 128);
+ vbuf += 128;
+ linestart = dev->line + (dev->mv_count % dev->width) * dev->pixelsize / 2;
+ for (h = 0; h < hmax; h++)
+ memcpy(vbuf + h * stride / 2, linestart, stride / 2);
- for (h = 0; h < hmax; h++)
- memcpy(vbuf + h * stride, linestart, stride);
+ linestart = dev->line + MAX_WIDTH * 2 + ((dev->mv_count % dev->width) * dev->pixelsize) / 4;
+ for (h = 0; h < hmax; h++)
+ memcpy(vbuf1 + h * stride / 4, linestart, stride / 4);
+
+ linestart = dev->line + MAX_WIDTH * 4 + ((dev->mv_count % dev->width) * dev->pixelsize) / 4;
+ for (h = 0; h < hmax; h++)
+ memcpy(vbuf2 + h * stride / 4, linestart, stride / 4);
+ goto done;
+ } else {
+ linestart = dev->line + (dev->mv_count % dev->width) * dev->pixelsize;
+
+ for (h = 0; h < hmax; h++)
+ memcpy(vbuf + h * stride, linestart, stride);
+ }
/* Updates stream time */
- gen_twopix(dev, (u8 *)&dev->textbg, TEXT_BLACK, /*odd=*/ 0);
- gen_twopix(dev, (u8 *)&dev->textfg, WHITE, /*odd=*/ 0);
+ gen_twopix(dev, (u8 *)&dev->textbg, TEXT_BLACK, 0, /*odd=*/ 0);
+ gen_twopix(dev, (u8 *)&dev->textfg, WHITE, 0, /*odd=*/ 0);
dev->ms += jiffies_to_msecs(jiffies - dev->jiffies);
dev->jiffies = jiffies;
@@ -669,6 +727,7 @@ static void vivi_fillbuff(struct vivi_dev *dev, struct vivi_buffer *buf)
dev->mv_count += 2;
+done:
buf->vb.v4l2_buf.field = V4L2_FIELD_INTERLACED;
buf->vb.v4l2_buf.sequence = dev->seq_count++;
v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp);
@@ -822,8 +881,10 @@ static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
return -EINVAL;
}
- *nplanes = 1;
+ if (vq->num_buffers + *nbuffers < 2)
+ *nbuffers = 2 - vq->num_buffers;
+ *nplanes = 1;
sizes[0] = size;
/*
@@ -872,6 +933,121 @@ static int buffer_prepare(struct vb2_buffer *vb)
return 0;
}
+static int queue_setup_mplane(struct vb2_queue *vq, const struct v4l2_format *fmt,
+ unsigned int *nbuffers, unsigned int *nplanes,
+ unsigned int sizes[], void *alloc_ctxs[])
+{
+ struct vivi_dev *dev = vb2_get_drv_priv(vq);
+ unsigned planes = 1;
+ unsigned size = dev->width * dev->height * dev->pixelsize;
+
+ if (dev->fmt->fourcc == V4L2_PIX_FMT_YUV422M)
+ planes = 3;
+ if (fmt) {
+ if (fmt->fmt.pix_mp.num_planes != planes)
+ return -EINVAL;
+ sizes[0] = fmt->fmt.pix_mp.plane_fmt[0].sizeimage;
+ if (planes == 3) {
+ sizes[1] = fmt->fmt.pix_mp.plane_fmt[1].sizeimage;
+ sizes[2] = fmt->fmt.pix_mp.plane_fmt[2].sizeimage;
+ if (sizes[0] < dev->width * dev->height + 128 ||
+ sizes[1] < dev->width * dev->height / 2 ||
+ sizes[2] < dev->width * dev->height / 2)
+ return -EINVAL;
+ } else if (sizes[0] < size) {
+ return -EINVAL;
+ }
+ } else {
+ if (planes == 3) {
+ sizes[0] = dev->width * dev->height + 128;
+ sizes[1] = sizes[0] / 2;
+ sizes[2] = sizes[0] / 2;
+ } else {
+ sizes[0] = size;
+ }
+ }
+
+ if (vq->num_buffers + *nbuffers < 2)
+ *nbuffers = 2 - vq->num_buffers;
+
+ *nplanes = planes;
+
+ /*
+ * videobuf2-vmalloc allocator is context-less so no need to set
+ * alloc_ctxs array.
+ */
+
+ if (planes == 3)
+ dprintk(dev, 1, "%s, count=%d, sizes=%u, %u, %u\n", __func__,
+ *nbuffers, sizes[0], sizes[1], sizes[2]);
+ else
+ dprintk(dev, 1, "%s, count=%d, size=%u\n", __func__,
+ *nbuffers, sizes[0]);
+
+ return 0;
+}
+
+static int buffer_prepare_mplane(struct vb2_buffer *vb)
+{
+ struct vivi_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
+ unsigned long size;
+ unsigned planes = 1;
+
+ dprintk(dev, 1, "%s, field=%d\n", __func__, vb->v4l2_buf.field);
+
+ if (WARN_ON(NULL == dev->fmt))
+ return -EINVAL;
+
+ /*
+ * Theses properties only change when queue is idle, see s_fmt.
+ * The below checks should not be performed here, on each
+ * buffer_prepare (i.e. on each qbuf). Most of the code in this function
+ * should thus be moved to buffer_init and s_fmt.
+ */
+ if (dev->width < 48 || dev->width > MAX_WIDTH ||
+ dev->height < 32 || dev->height > MAX_HEIGHT)
+ return -EINVAL;
+
+ if (dev->fmt->fourcc == V4L2_PIX_FMT_YUV422M)
+ planes = 3;
+ size = dev->width * dev->height;
+ if (planes == 3) {
+ if (vb2_plane_size(vb, 0) < size + 128) {
+ dprintk(dev, 1, "%s data will not fit into plane 0 (%lu < %lu)\n",
+ __func__, vb2_plane_size(vb, 0), size);
+ return -EINVAL;
+ }
+ if (vb2_plane_size(vb, 1) < size / 4) {
+ dprintk(dev, 1, "%s data will not fit into plane 1 (%lu < %lu)\n",
+ __func__, vb2_plane_size(vb, 1), size / 4);
+ return -EINVAL;
+ }
+ if (vb2_plane_size(vb, 2) < size / 4) {
+ dprintk(dev, 1, "%s data will not fit into plane 2 (%lu < %lu)\n",
+ __func__, vb2_plane_size(vb, 2), size / 4);
+ return -EINVAL;
+ }
+
+ vb2_set_plane_payload(vb, 0, size + 128);
+ vb->v4l2_planes[0].data_offset = 128;
+ vb2_set_plane_payload(vb, 1, size / 2);
+ vb2_set_plane_payload(vb, 2, size / 2);
+ } else {
+ size *= dev->pixelsize;
+ if (vb2_plane_size(vb, 0) < size) {
+ dprintk(dev, 1, "%s data will not fit into plane (%lu < %lu)\n",
+ __func__, vb2_plane_size(vb, 0), size);
+ return -EINVAL;
+ }
+ vb2_set_plane_payload(vb, 0, size);
+ }
+
+ precalculate_bars(dev);
+ precalculate_line(dev);
+
+ return 0;
+}
+
static void buffer_queue(struct vb2_buffer *vb)
{
struct vivi_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
@@ -936,6 +1112,16 @@ static const struct vb2_ops vivi_video_qops = {
.wait_finish = vivi_lock,
};
+static const struct vb2_ops vivi_video_mplane_qops = {
+ .queue_setup = queue_setup_mplane,
+ .buf_prepare = buffer_prepare_mplane,
+ .buf_queue = buffer_queue,
+ .start_streaming = start_streaming,
+ .stop_streaming = stop_streaming,
+ .wait_prepare = vivi_unlock,
+ .wait_finish = vivi_lock,
+};
+
/* ------------------------------------------------------------------
IOCTL vidioc handling
------------------------------------------------------------------*/
@@ -948,8 +1134,9 @@ static int vidioc_querycap(struct file *file, void *priv,
strcpy(cap->card, "vivi");
snprintf(cap->bus_info, sizeof(cap->bus_info),
"platform:%s", dev->v4l2_dev.name);
- cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING |
- V4L2_CAP_READWRITE;
+ cap->device_caps = multiplanar ? V4L2_CAP_VIDEO_CAPTURE_MPLANE :
+ V4L2_CAP_VIDEO_CAPTURE;
+ cap->device_caps |= V4L2_CAP_STREAMING | V4L2_CAP_READWRITE;
cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
@@ -1041,6 +1228,123 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
return 0;
}
+static int vidioc_enum_fmt_vid_cap_mplane(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ const struct vivi_fmt *fmt;
+
+ if (f->index >= ARRAY_SIZE(formats) + ARRAY_SIZE(mplane_formats))
+ return -EINVAL;
+
+ if (f->index < ARRAY_SIZE(formats))
+ fmt = &formats[f->index];
+ else
+ fmt = &mplane_formats[f->index - ARRAY_SIZE(formats)];
+
+ strlcpy(f->description, fmt->name, sizeof(f->description));
+ f->pixelformat = fmt->fourcc;
+ return 0;
+}
+
+static int vidioc_g_fmt_vid_cap_mplane(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct vivi_dev *dev = video_drvdata(file);
+ struct v4l2_pix_format_mplane *mp = &f->fmt.pix_mp;
+
+ mp->width = dev->width;
+ mp->height = dev->height;
+ mp->field = V4L2_FIELD_INTERLACED;
+ mp->pixelformat = dev->fmt->fourcc;
+ if (dev->fmt->is_yuv)
+ mp->colorspace = V4L2_COLORSPACE_SMPTE170M;
+ else
+ mp->colorspace = V4L2_COLORSPACE_SRGB;
+ if (dev->fmt->fourcc == V4L2_PIX_FMT_YUV422M) {
+ mp->num_planes = 3;
+ mp->plane_fmt[0].sizeimage = mp->width * mp->height + 128;
+ mp->plane_fmt[0].bytesperline = mp->width;
+ mp->plane_fmt[1].sizeimage = mp->width * mp->height / 2;
+ mp->plane_fmt[1].bytesperline = mp->width / 2;
+ mp->plane_fmt[2].sizeimage = mp->width * mp->height / 2;
+ mp->plane_fmt[2].bytesperline = mp->width / 2;
+ } else {
+ mp->num_planes = 1;
+ mp->plane_fmt[0].bytesperline = (mp->width * dev->fmt->depth) >> 3;
+ mp->plane_fmt[0].sizeimage =
+ mp->height * mp->plane_fmt[0].bytesperline;
+ }
+ return 0;
+}
+
+static int vidioc_try_fmt_vid_cap_mplane(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct v4l2_pix_format_mplane *mp = &f->fmt.pix_mp;
+ struct vivi_dev *dev = video_drvdata(file);
+ const struct vivi_fmt *fmt;
+
+ fmt = get_format(f);
+ if (!fmt) {
+ dprintk(dev, 1, "Fourcc format (0x%08x) unknown.\n",
+ mp->pixelformat);
+ mp->pixelformat = V4L2_PIX_FMT_YUV422M;
+ fmt = get_format(f);
+ }
+
+ mp->field = V4L2_FIELD_INTERLACED;
+ v4l_bound_align_image(&mp->width, 48, MAX_WIDTH, 2,
+ &mp->height, 32, MAX_HEIGHT, 0, 0);
+ if (fmt->fourcc == V4L2_PIX_FMT_YUV422M) {
+ mp->num_planes = 3;
+ memset(mp->plane_fmt, 0,
+ mp->num_planes * sizeof(mp->plane_fmt[0]));
+ mp->plane_fmt[0].sizeimage = mp->width * mp->height + 128;
+ mp->plane_fmt[0].bytesperline = mp->width;
+ mp->plane_fmt[1].sizeimage = mp->width * mp->height / 2;
+ mp->plane_fmt[1].bytesperline = mp->width / 2;
+ mp->plane_fmt[2].sizeimage = mp->width * mp->height / 2;
+ mp->plane_fmt[2].bytesperline = mp->width / 2;
+ } else {
+ mp->num_planes = 1;
+ memset(mp->plane_fmt, 0,
+ mp->num_planes * sizeof(mp->plane_fmt[0]));
+ mp->plane_fmt[0].bytesperline = (mp->width * fmt->depth) >> 3;
+ mp->plane_fmt[0].sizeimage =
+ mp->height * mp->plane_fmt[0].bytesperline;
+ }
+ if (fmt->is_yuv)
+ mp->colorspace = V4L2_COLORSPACE_SMPTE170M;
+ else
+ mp->colorspace = V4L2_COLORSPACE_SRGB;
+ memset(mp->reserved, 0, sizeof(mp->reserved));
+ return 0;
+}
+
+static int vidioc_s_fmt_vid_cap_mplane(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct v4l2_pix_format_mplane *mp = &f->fmt.pix_mp;
+ struct vivi_dev *dev = video_drvdata(file);
+ struct vb2_queue *q = &dev->vb_vidq;
+ int ret = vidioc_try_fmt_vid_cap_mplane(file, priv, f);
+
+ if (ret < 0)
+ return ret;
+
+ if (vb2_is_busy(q)) {
+ dprintk(dev, 1, "%s device busy\n", __func__);
+ return -EBUSY;
+ }
+
+ dev->fmt = get_format(f);
+ dev->pixelsize = dev->fmt->depth / 8;
+ dev->width = mp->width;
+ dev->height = mp->height;
+
+ return 0;
+}
+
static int vidioc_enum_framesizes(struct file *file, void *fh,
struct v4l2_frmsizeenum *fsize)
{
@@ -1141,7 +1445,8 @@ static int vidioc_g_parm(struct file *file, void *priv,
{
struct vivi_dev *dev = video_drvdata(file);
- if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ if (parm->type != multiplanar ? V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE :
+ V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
@@ -1159,7 +1464,8 @@ static int vidioc_s_parm(struct file *file, void *priv,
struct vivi_dev *dev = video_drvdata(file);
struct v4l2_fract tpf;
- if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ if (parm->type != multiplanar ? V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE :
+ V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
tpf = parm->parm.capture.timeperframe;
@@ -1313,7 +1619,7 @@ static const struct v4l2_file_operations vivi_fops = {
.release = vb2_fop_release,
.read = vb2_fop_read,
.poll = vb2_fop_poll,
- .unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */
+ .unlocked_ioctl = video_ioctl2,
.mmap = vb2_fop_mmap,
};
@@ -1330,6 +1636,7 @@ static const struct v4l2_ioctl_ops vivi_ioctl_ops = {
.vidioc_querybuf = vb2_ioctl_querybuf,
.vidioc_qbuf = vb2_ioctl_qbuf,
.vidioc_dqbuf = vb2_ioctl_dqbuf,
+ .vidioc_expbuf = vb2_ioctl_expbuf,
.vidioc_enum_input = vidioc_enum_input,
.vidioc_g_input = vidioc_g_input,
.vidioc_s_input = vidioc_s_input,
@@ -1343,11 +1650,31 @@ static const struct v4l2_ioctl_ops vivi_ioctl_ops = {
.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
};
-static const struct video_device vivi_template = {
- .name = "vivi",
- .fops = &vivi_fops,
- .ioctl_ops = &vivi_ioctl_ops,
- .release = video_device_release_empty,
+static const struct v4l2_ioctl_ops vivi_mplanar_ioctl_ops = {
+ .vidioc_querycap = vidioc_querycap,
+ .vidioc_enum_fmt_vid_cap_mplane = vidioc_enum_fmt_vid_cap_mplane,
+ .vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt_vid_cap_mplane,
+ .vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt_vid_cap_mplane,
+ .vidioc_s_fmt_vid_cap_mplane = vidioc_s_fmt_vid_cap_mplane,
+ .vidioc_enum_framesizes = vidioc_enum_framesizes,
+ .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_enum_input = vidioc_enum_input,
+ .vidioc_g_input = vidioc_g_input,
+ .vidioc_s_input = vidioc_s_input,
+ .vidioc_enum_frameintervals = vidioc_enum_frameintervals,
+ .vidioc_g_parm = vidioc_g_parm,
+ .vidioc_s_parm = vidioc_s_parm,
+ .vidioc_streamon = vb2_ioctl_streamon,
+ .vidioc_streamoff = vb2_ioctl_streamoff,
+ .vidioc_log_status = v4l2_ctrl_log_status,
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
};
/* -----------------------------------------------------------------
@@ -1436,11 +1763,12 @@ static int __init vivi_create_instance(int inst)
/* initialize queue */
q = &dev->vb_vidq;
- q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ q->type = multiplanar ? V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE :
+ V4L2_BUF_TYPE_VIDEO_CAPTURE;
q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ;
q->drv_priv = dev;
q->buf_struct_size = sizeof(struct vivi_buffer);
- q->ops = &vivi_video_qops;
+ q->ops = multiplanar ? &vivi_video_mplane_qops : &vivi_video_qops;
q->mem_ops = &vb2_vmalloc_memops;
q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
@@ -1455,8 +1783,10 @@ static int __init vivi_create_instance(int inst)
init_waitqueue_head(&dev->vidq.wq);
vfd = &dev->vdev;
- *vfd = vivi_template;
- vfd->debug = debug;
+ strlcpy(vfd->name, "vivi", sizeof(vfd->name));
+ vfd->fops = &vivi_fops;
+ vfd->ioctl_ops = multiplanar ? &vivi_mplanar_ioctl_ops : &vivi_ioctl_ops;
+ vfd->release = video_device_release_empty;
vfd->v4l2_dev = &dev->v4l2_dev;
vfd->queue = q;
set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags);
@@ -356,6 +356,7 @@ struct v4l2_pix_format {
/* three non contiguous planes - Y, Cb, Cr */
#define V4L2_PIX_FMT_YUV420M v4l2_fourcc('Y', 'M', '1', '2') /* 12 YUV420 planar */
#define V4L2_PIX_FMT_YVU420M v4l2_fourcc('Y', 'M', '2', '1') /* 12 YVU420 planar */
+#define V4L2_PIX_FMT_YUV422M v4l2_fourcc('4', '2', '2', 'M') /* 16 YVU422 planar */
/* Bayer formats - see http://www.siliconimaging.com/RGB%20Bayer.htm */
#define V4L2_PIX_FMT_SBGGR8 v4l2_fourcc('B', 'A', '8', '1') /* 8 BGBG.. GRGR.. */