summaryrefslogtreecommitdiff
path: root/drivers/media/video/cx18/cx18-ioctl.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video/cx18/cx18-ioctl.c')
-rw-r--r--drivers/media/video/cx18/cx18-ioctl.c144
1 files changed, 136 insertions, 8 deletions
diff --git a/drivers/media/video/cx18/cx18-ioctl.c b/drivers/media/video/cx18/cx18-ioctl.c
index 4f041c033c54..1933d4d11bf2 100644
--- a/drivers/media/video/cx18/cx18-ioctl.c
+++ b/drivers/media/video/cx18/cx18-ioctl.c
@@ -150,6 +150,7 @@ static int cx18_g_fmt_vid_cap(struct file *file, void *fh,
{
struct cx18_open_id *id = fh2id(fh);
struct cx18 *cx = id->cx;
+ struct cx18_stream *s = &cx->streams[id->type];
struct v4l2_pix_format *pixfmt = &fmt->fmt.pix;
pixfmt->width = cx->cxhdl.width;
@@ -158,9 +159,13 @@ static int cx18_g_fmt_vid_cap(struct file *file, void *fh,
pixfmt->field = V4L2_FIELD_INTERLACED;
pixfmt->priv = 0;
if (id->type == CX18_ENC_STREAM_TYPE_YUV) {
- pixfmt->pixelformat = V4L2_PIX_FMT_HM12;
- /* YUV size is (Y=(h*720) + UV=(h*(720/2))) */
- pixfmt->sizeimage = pixfmt->height * 720 * 3 / 2;
+ pixfmt->pixelformat = s->pixelformat;
+ /* HM12 YUV size is (Y=(h*720) + UV=(h*(720/2)))
+ UYUV YUV size is (Y=(h*720) + UV=(h*(720))) */
+ if (s->pixelformat == V4L2_PIX_FMT_HM12)
+ pixfmt->sizeimage = pixfmt->height * 720 * 3 / 2;
+ else
+ pixfmt->sizeimage = pixfmt->height * 720 * 2;
pixfmt->bytesperline = 720;
} else {
pixfmt->pixelformat = V4L2_PIX_FMT_MPEG;
@@ -237,7 +242,6 @@ static int cx18_try_fmt_vid_cap(struct file *file, void *fh,
h = min(h, cx->is_50hz ? 576 : 480);
h = max(h, min_h);
- cx18_g_fmt_vid_cap(file, fh, fmt);
fmt->fmt.pix.width = w;
fmt->fmt.pix.height = h;
return 0;
@@ -274,6 +278,7 @@ static int cx18_s_fmt_vid_cap(struct file *file, void *fh,
struct cx18_open_id *id = fh2id(fh);
struct cx18 *cx = id->cx;
struct v4l2_mbus_framefmt mbus_fmt;
+ struct cx18_stream *s = &cx->streams[id->type];
int ret;
int w, h;
@@ -283,12 +288,15 @@ static int cx18_s_fmt_vid_cap(struct file *file, void *fh,
w = fmt->fmt.pix.width;
h = fmt->fmt.pix.height;
- if (cx->cxhdl.width == w && cx->cxhdl.height == h)
+ if (cx->cxhdl.width == w && cx->cxhdl.height == h &&
+ s->pixelformat == fmt->fmt.pix.pixelformat)
return 0;
if (atomic_read(&cx->ana_capturing) > 0)
return -EBUSY;
+ s->pixelformat = fmt->fmt.pix.pixelformat;
+
mbus_fmt.width = cx->cxhdl.width = w;
mbus_fmt.height = cx->cxhdl.height = h;
mbus_fmt.code = V4L2_MBUS_FMT_FIXED;
@@ -540,16 +548,19 @@ static int cx18_g_crop(struct file *file, void *fh, struct v4l2_crop *crop)
static int cx18_enum_fmt_vid_cap(struct file *file, void *fh,
struct v4l2_fmtdesc *fmt)
{
- static struct v4l2_fmtdesc formats[] = {
+ static const struct v4l2_fmtdesc formats[] = {
{ 0, V4L2_BUF_TYPE_VIDEO_CAPTURE, 0,
"HM12 (YUV 4:1:1)", V4L2_PIX_FMT_HM12, { 0, 0, 0, 0 }
},
{ 1, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FMT_FLAG_COMPRESSED,
"MPEG", V4L2_PIX_FMT_MPEG, { 0, 0, 0, 0 }
- }
+ },
+ { 2, V4L2_BUF_TYPE_VIDEO_CAPTURE, 0,
+ "UYVY 4:2:2", V4L2_PIX_FMT_UYVY, { 0, 0, 0, 0 }
+ },
};
- if (fmt->index > 1)
+ if (fmt->index > ARRAY_SIZE(formats) - 1)
return -EINVAL;
*fmt = formats[fmt->index];
return 0;
@@ -863,6 +874,117 @@ static int cx18_g_enc_index(struct file *file, void *fh,
return 0;
}
+static struct videobuf_queue *cx18_vb_queue(struct cx18_open_id *id)
+{
+ struct videobuf_queue *q = NULL;
+ struct cx18 *cx = id->cx;
+ struct cx18_stream *s = &cx->streams[id->type];
+
+ switch (s->vb_type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ q = &s->vbuf_q;
+ break;
+ case V4L2_BUF_TYPE_VBI_CAPTURE:
+ break;
+ default:
+ break;
+ }
+ return q;
+}
+
+static int cx18_streamon(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ struct cx18_open_id *id = file->private_data;
+ struct cx18 *cx = id->cx;
+ struct cx18_stream *s = &cx->streams[id->type];
+
+ /* Start the hardware only if we're the video device */
+ if ((s->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
+ (s->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE))
+ return -EINVAL;
+
+ if (id->type != CX18_ENC_STREAM_TYPE_YUV)
+ return -EINVAL;
+
+ /* Establish a buffer timeout */
+ mod_timer(&s->vb_timeout, msecs_to_jiffies(2000) + jiffies);
+
+ return videobuf_streamon(cx18_vb_queue(id));
+}
+
+static int cx18_streamoff(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ struct cx18_open_id *id = file->private_data;
+ struct cx18 *cx = id->cx;
+ struct cx18_stream *s = &cx->streams[id->type];
+
+ /* Start the hardware only if we're the video device */
+ if ((s->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
+ (s->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE))
+ return -EINVAL;
+
+ if (id->type != CX18_ENC_STREAM_TYPE_YUV)
+ return -EINVAL;
+
+ return videobuf_streamoff(cx18_vb_queue(id));
+}
+
+static int cx18_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *rb)
+{
+ struct cx18_open_id *id = file->private_data;
+ struct cx18 *cx = id->cx;
+ struct cx18_stream *s = &cx->streams[id->type];
+
+ if ((s->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
+ (s->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE))
+ return -EINVAL;
+
+ return videobuf_reqbufs(cx18_vb_queue(id), rb);
+}
+
+static int cx18_querybuf(struct file *file, void *priv,
+ struct v4l2_buffer *b)
+{
+ struct cx18_open_id *id = file->private_data;
+ struct cx18 *cx = id->cx;
+ struct cx18_stream *s = &cx->streams[id->type];
+
+ if ((s->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
+ (s->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE))
+ return -EINVAL;
+
+ return videobuf_querybuf(cx18_vb_queue(id), b);
+}
+
+static int cx18_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
+{
+ struct cx18_open_id *id = file->private_data;
+ struct cx18 *cx = id->cx;
+ struct cx18_stream *s = &cx->streams[id->type];
+
+ if ((s->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
+ (s->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE))
+ return -EINVAL;
+
+ return videobuf_qbuf(cx18_vb_queue(id), b);
+}
+
+static int cx18_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
+{
+ struct cx18_open_id *id = file->private_data;
+ struct cx18 *cx = id->cx;
+ struct cx18_stream *s = &cx->streams[id->type];
+
+ if ((s->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
+ (s->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE))
+ return -EINVAL;
+
+ return videobuf_dqbuf(cx18_vb_queue(id), b, file->f_flags & O_NONBLOCK);
+}
+
static int cx18_encoder_cmd(struct file *file, void *fh,
struct v4l2_encoder_cmd *enc)
{
@@ -1081,6 +1203,12 @@ static const struct v4l2_ioctl_ops cx18_ioctl_ops = {
.vidioc_s_register = cx18_s_register,
#endif
.vidioc_default = cx18_default,
+ .vidioc_streamon = cx18_streamon,
+ .vidioc_streamoff = cx18_streamoff,
+ .vidioc_reqbufs = cx18_reqbufs,
+ .vidioc_querybuf = cx18_querybuf,
+ .vidioc_qbuf = cx18_qbuf,
+ .vidioc_dqbuf = cx18_dqbuf,
};
void cx18_set_funcs(struct video_device *vdev)