Merge branch 'stable/drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/konrad/xen
[pandora-kernel.git] / drivers / media / video / cx18 / cx18-ioctl.c
index 4f041c0..e80134f 100644 (file)
@@ -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;
@@ -684,14 +695,10 @@ static int cx18_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
 
        cx18_call_all(cx, tuner, g_tuner, vt);
 
-       if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) {
+       if (vt->type == V4L2_TUNER_RADIO)
                strlcpy(vt->name, "cx18 Radio Tuner", sizeof(vt->name));
-               vt->type = V4L2_TUNER_RADIO;
-       } else {
+       else
                strlcpy(vt->name, "cx18 TV Tuner", sizeof(vt->name));
-               vt->type = V4L2_TUNER_ANALOG_TV;
-       }
-
        return 0;
 }
 
@@ -863,6 +870,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 +1199,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)