Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6
[pandora-kernel.git] / drivers / media / video / v4l2-ioctl.c
index 88f10d6..f2afc4e 100644 (file)
                        printk(KERN_DEBUG "%s: " fmt, vfd->name, ## arg);\
                } while (0)
 
+/* Zero out the end of the struct pointed to by p.  Everthing after, but
+ * not including, the specified field is cleared. */
+#define CLEAR_AFTER_FIELD(p, field) \
+       memset((u8 *)(p) + offsetof(typeof(*(p)), field) + sizeof((p)->field), \
+       0, sizeof(*(p)) - offsetof(typeof(*(p)), field) - sizeof((p)->field))
+
 struct std_descr {
        v4l2_std_id std;
        const char *descr;
@@ -544,39 +550,39 @@ static int check_fmt(const struct v4l2_ioctl_ops *ops, enum v4l2_buf_type type)
 
        switch (type) {
        case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-               if (ops->vidioc_try_fmt_vid_cap)
+               if (ops->vidioc_g_fmt_vid_cap)
                        return 0;
                break;
        case V4L2_BUF_TYPE_VIDEO_OVERLAY:
-               if (ops->vidioc_try_fmt_vid_overlay)
+               if (ops->vidioc_g_fmt_vid_overlay)
                        return 0;
                break;
        case V4L2_BUF_TYPE_VIDEO_OUTPUT:
-               if (ops->vidioc_try_fmt_vid_out)
+               if (ops->vidioc_g_fmt_vid_out)
                        return 0;
                break;
        case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
-               if (ops->vidioc_try_fmt_vid_out_overlay)
+               if (ops->vidioc_g_fmt_vid_out_overlay)
                        return 0;
                break;
        case V4L2_BUF_TYPE_VBI_CAPTURE:
-               if (ops->vidioc_try_fmt_vbi_cap)
+               if (ops->vidioc_g_fmt_vbi_cap)
                        return 0;
                break;
        case V4L2_BUF_TYPE_VBI_OUTPUT:
-               if (ops->vidioc_try_fmt_vbi_out)
+               if (ops->vidioc_g_fmt_vbi_out)
                        return 0;
                break;
        case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
-               if (ops->vidioc_try_fmt_sliced_vbi_cap)
+               if (ops->vidioc_g_fmt_sliced_vbi_cap)
                        return 0;
                break;
        case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
-               if (ops->vidioc_try_fmt_sliced_vbi_out)
+               if (ops->vidioc_g_fmt_sliced_vbi_out)
                        return 0;
                break;
        case V4L2_BUF_TYPE_PRIVATE:
-               if (ops->vidioc_try_fmt_type_private)
+               if (ops->vidioc_g_fmt_type_private)
                        return 0;
                break;
        }
@@ -782,44 +788,53 @@ static long __video_do_ioctl(struct file *file,
 
                switch (f->type) {
                case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+                       CLEAR_AFTER_FIELD(f, fmt.pix);
                        v4l_print_pix_fmt(vfd, &f->fmt.pix);
                        if (ops->vidioc_s_fmt_vid_cap)
                                ret = ops->vidioc_s_fmt_vid_cap(file, fh, f);
                        break;
                case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+                       CLEAR_AFTER_FIELD(f, fmt.win);
                        if (ops->vidioc_s_fmt_vid_overlay)
                                ret = ops->vidioc_s_fmt_vid_overlay(file,
                                                                    fh, f);
                        break;
                case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+                       CLEAR_AFTER_FIELD(f, fmt.pix);
                        v4l_print_pix_fmt(vfd, &f->fmt.pix);
                        if (ops->vidioc_s_fmt_vid_out)
                                ret = ops->vidioc_s_fmt_vid_out(file, fh, f);
                        break;
                case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
+                       CLEAR_AFTER_FIELD(f, fmt.win);
                        if (ops->vidioc_s_fmt_vid_out_overlay)
                                ret = ops->vidioc_s_fmt_vid_out_overlay(file,
                                        fh, f);
                        break;
                case V4L2_BUF_TYPE_VBI_CAPTURE:
+                       CLEAR_AFTER_FIELD(f, fmt.vbi);
                        if (ops->vidioc_s_fmt_vbi_cap)
                                ret = ops->vidioc_s_fmt_vbi_cap(file, fh, f);
                        break;
                case V4L2_BUF_TYPE_VBI_OUTPUT:
+                       CLEAR_AFTER_FIELD(f, fmt.vbi);
                        if (ops->vidioc_s_fmt_vbi_out)
                                ret = ops->vidioc_s_fmt_vbi_out(file, fh, f);
                        break;
                case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+                       CLEAR_AFTER_FIELD(f, fmt.sliced);
                        if (ops->vidioc_s_fmt_sliced_vbi_cap)
                                ret = ops->vidioc_s_fmt_sliced_vbi_cap(file,
                                                                        fh, f);
                        break;
                case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+                       CLEAR_AFTER_FIELD(f, fmt.sliced);
                        if (ops->vidioc_s_fmt_sliced_vbi_out)
                                ret = ops->vidioc_s_fmt_sliced_vbi_out(file,
                                                                        fh, f);
                        break;
                case V4L2_BUF_TYPE_PRIVATE:
+                       /* CLEAR_AFTER_FIELD(f, fmt.raw_data); <- does nothing */
                        if (ops->vidioc_s_fmt_type_private)
                                ret = ops->vidioc_s_fmt_type_private(file,
                                                                fh, f);
@@ -836,46 +851,55 @@ static long __video_do_ioctl(struct file *file,
                                                v4l2_type_names));
                switch (f->type) {
                case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+                       CLEAR_AFTER_FIELD(f, fmt.pix);
                        if (ops->vidioc_try_fmt_vid_cap)
                                ret = ops->vidioc_try_fmt_vid_cap(file, fh, f);
                        if (!ret)
                                v4l_print_pix_fmt(vfd, &f->fmt.pix);
                        break;
                case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+                       CLEAR_AFTER_FIELD(f, fmt.win);
                        if (ops->vidioc_try_fmt_vid_overlay)
                                ret = ops->vidioc_try_fmt_vid_overlay(file,
                                        fh, f);
                        break;
                case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+                       CLEAR_AFTER_FIELD(f, fmt.pix);
                        if (ops->vidioc_try_fmt_vid_out)
                                ret = ops->vidioc_try_fmt_vid_out(file, fh, f);
                        if (!ret)
                                v4l_print_pix_fmt(vfd, &f->fmt.pix);
                        break;
                case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
+                       CLEAR_AFTER_FIELD(f, fmt.win);
                        if (ops->vidioc_try_fmt_vid_out_overlay)
                                ret = ops->vidioc_try_fmt_vid_out_overlay(file,
                                       fh, f);
                        break;
                case V4L2_BUF_TYPE_VBI_CAPTURE:
+                       CLEAR_AFTER_FIELD(f, fmt.vbi);
                        if (ops->vidioc_try_fmt_vbi_cap)
                                ret = ops->vidioc_try_fmt_vbi_cap(file, fh, f);
                        break;
                case V4L2_BUF_TYPE_VBI_OUTPUT:
+                       CLEAR_AFTER_FIELD(f, fmt.vbi);
                        if (ops->vidioc_try_fmt_vbi_out)
                                ret = ops->vidioc_try_fmt_vbi_out(file, fh, f);
                        break;
                case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+                       CLEAR_AFTER_FIELD(f, fmt.sliced);
                        if (ops->vidioc_try_fmt_sliced_vbi_cap)
                                ret = ops->vidioc_try_fmt_sliced_vbi_cap(file,
                                                                fh, f);
                        break;
                case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+                       CLEAR_AFTER_FIELD(f, fmt.sliced);
                        if (ops->vidioc_try_fmt_sliced_vbi_out)
                                ret = ops->vidioc_try_fmt_sliced_vbi_out(file,
                                                                fh, f);
                        break;
                case V4L2_BUF_TYPE_PRIVATE:
+                       /* CLEAR_AFTER_FIELD(f, fmt.raw_data); <- does nothing */
                        if (ops->vidioc_try_fmt_type_private)
                                ret = ops->vidioc_try_fmt_type_private(file,
                                                                fh, f);
@@ -898,6 +922,9 @@ static long __video_do_ioctl(struct file *file,
                if (ret)
                        break;
 
+               if (p->type < V4L2_BUF_TYPE_PRIVATE)
+                       CLEAR_AFTER_FIELD(p, memory);
+
                ret = ops->vidioc_reqbufs(file, fh, p);
                dbgarg(cmd, "count=%d, type=%s, memory=%s\n",
                                p->count,
@@ -1054,8 +1081,10 @@ static long __video_do_ioctl(struct file *file,
                /* Calls the specific handler */
                if (ops->vidioc_g_std)
                        ret = ops->vidioc_g_std(file, fh, id);
-               else
+               else if (vfd->current_norm)
                        *id = vfd->current_norm;
+               else
+                       ret = -EINVAL;
 
                if (!ret)
                        dbgarg(cmd, "std=0x%08Lx\n", (long long unsigned)*id);
@@ -1526,12 +1555,19 @@ static long __video_do_ioctl(struct file *file,
                                break;
                        ret = ops->vidioc_g_parm(file, fh, p);
                } else {
+                       v4l2_std_id std = vfd->current_norm;
+
                        if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
                                return -EINVAL;
 
-                       v4l2_video_std_frame_period(vfd->current_norm,
-                                                   &p->parm.capture.timeperframe);
                        ret = 0;
+                       if (ops->vidioc_g_std)
+                               ret = ops->vidioc_g_std(file, fh, &std);
+                       else if (std == 0)
+                               ret = -EINVAL;
+                       if (ret == 0)
+                               v4l2_video_std_frame_period(std,
+                                                   &p->parm.capture.timeperframe);
                }
 
                dbgarg(cmd, "type=%d\n", p->type);