V4L/DVB: gscpa_sonixb: limit ov7630 max framerate at 640x480
[safe/jmp/linux-2.6] / drivers / media / video / v4l2-ioctl.c
index 140ef92..4b11257 100644 (file)
@@ -8,7 +8,7 @@
  * as published by the Free Software Foundation; either version
  * 2 of the License, or (at your option) any later version.
  *
- * Authors:    Alan Cox, <alan@redhat.com> (version 1)
+ * Authors:    Alan Cox, <alan@lxorguk.ukuu.org.uk> (version 1)
  *              Mauro Carvalho Chehab <mchehab@infradead.org> (version 2)
  */
 
@@ -17,6 +17,7 @@
 #include <linux/kernel.h>
 
 #define __OLD_VIDIOC_ /* To allow fixing old calls */
+#include <linux/videodev.h>
 #include <linux/videodev2.h>
 
 #ifdef CONFIG_VIDEO_V4L1
@@ -24,7 +25,7 @@
 #endif
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
-#include <linux/video_decoder.h>
+#include <media/v4l2-chip-ident.h>
 
 #define dbgarg(cmd, fmt, arg...) \
                do {                                                    \
                        printk(KERN_DEBUG "%s: " fmt, vfd->name, ## arg);\
                } while (0)
 
+#define dbgarg3(fmt, arg...) \
+               do {                                                    \
+                   if (vfd->debug & V4L2_DEBUG_IOCTL_ARG)              \
+                       printk(KERN_CONT "%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;
@@ -100,25 +113,27 @@ const char *v4l2_norm_to_name(v4l2_std_id id)
 }
 EXPORT_SYMBOL(v4l2_norm_to_name);
 
+/* Returns frame period for the given standard */
+void v4l2_video_std_frame_period(int id, struct v4l2_fract *frameperiod)
+{
+       if (id & V4L2_STD_525_60) {
+               frameperiod->numerator = 1001;
+               frameperiod->denominator = 30000;
+       } else {
+               frameperiod->numerator = 1;
+               frameperiod->denominator = 25;
+       }
+}
+EXPORT_SYMBOL(v4l2_video_std_frame_period);
+
 /* Fill in the fields of a v4l2_standard structure according to the
    'id' and 'transmission' parameters.  Returns negative on error.  */
 int v4l2_video_std_construct(struct v4l2_standard *vs,
                             int id, const char *name)
 {
-       u32 index = vs->index;
-
-       memset(vs, 0, sizeof(struct v4l2_standard));
-       vs->index = index;
-       vs->id    = id;
-       if (id & V4L2_STD_525_60) {
-               vs->frameperiod.numerator = 1001;
-               vs->frameperiod.denominator = 30000;
-               vs->framelines = 525;
-       } else {
-               vs->frameperiod.numerator = 1;
-               vs->frameperiod.denominator = 25;
-               vs->framelines = 625;
-       }
+       vs->id = id;
+       v4l2_video_std_frame_period(id, &vs->frameperiod);
+       vs->framelines = (id & V4L2_STD_525_60) ? 525 : 625;
        strlcpy(vs->name, name, sizeof(vs->name));
        return 0;
 }
@@ -266,51 +281,18 @@ static const char *v4l2_ioctls[] = {
        [_IOC_NR(VIDIOC_DBG_S_REGISTER)]   = "VIDIOC_DBG_S_REGISTER",
        [_IOC_NR(VIDIOC_DBG_G_REGISTER)]   = "VIDIOC_DBG_G_REGISTER",
 
-       [_IOC_NR(VIDIOC_G_CHIP_IDENT)]     = "VIDIOC_G_CHIP_IDENT",
+       [_IOC_NR(VIDIOC_DBG_G_CHIP_IDENT)] = "VIDIOC_DBG_G_CHIP_IDENT",
        [_IOC_NR(VIDIOC_S_HW_FREQ_SEEK)]   = "VIDIOC_S_HW_FREQ_SEEK",
 #endif
+       [_IOC_NR(VIDIOC_ENUM_DV_PRESETS)]  = "VIDIOC_ENUM_DV_PRESETS",
+       [_IOC_NR(VIDIOC_S_DV_PRESET)]      = "VIDIOC_S_DV_PRESET",
+       [_IOC_NR(VIDIOC_G_DV_PRESET)]      = "VIDIOC_G_DV_PRESET",
+       [_IOC_NR(VIDIOC_QUERY_DV_PRESET)]  = "VIDIOC_QUERY_DV_PRESET",
+       [_IOC_NR(VIDIOC_S_DV_TIMINGS)]     = "VIDIOC_S_DV_TIMINGS",
+       [_IOC_NR(VIDIOC_G_DV_TIMINGS)]     = "VIDIOC_G_DV_TIMINGS",
 };
 #define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls)
 
-static const char *v4l2_int_ioctls[] = {
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-       [_IOC_NR(DECODER_GET_CAPABILITIES)]    = "DECODER_GET_CAPABILITIES",
-       [_IOC_NR(DECODER_GET_STATUS)]          = "DECODER_GET_STATUS",
-       [_IOC_NR(DECODER_SET_NORM)]            = "DECODER_SET_NORM",
-       [_IOC_NR(DECODER_SET_INPUT)]           = "DECODER_SET_INPUT",
-       [_IOC_NR(DECODER_SET_OUTPUT)]          = "DECODER_SET_OUTPUT",
-       [_IOC_NR(DECODER_ENABLE_OUTPUT)]       = "DECODER_ENABLE_OUTPUT",
-       [_IOC_NR(DECODER_SET_PICTURE)]         = "DECODER_SET_PICTURE",
-       [_IOC_NR(DECODER_SET_GPIO)]            = "DECODER_SET_GPIO",
-       [_IOC_NR(DECODER_INIT)]                = "DECODER_INIT",
-       [_IOC_NR(DECODER_SET_VBI_BYPASS)]      = "DECODER_SET_VBI_BYPASS",
-       [_IOC_NR(DECODER_DUMP)]                = "DECODER_DUMP",
-#endif
-       [_IOC_NR(AUDC_SET_RADIO)]              = "AUDC_SET_RADIO",
-
-       [_IOC_NR(TUNER_SET_TYPE_ADDR)]         = "TUNER_SET_TYPE_ADDR",
-       [_IOC_NR(TUNER_SET_STANDBY)]           = "TUNER_SET_STANDBY",
-       [_IOC_NR(TUNER_SET_CONFIG)]            = "TUNER_SET_CONFIG",
-
-       [_IOC_NR(VIDIOC_INT_S_TUNER_MODE)]     = "VIDIOC_INT_S_TUNER_MODE",
-       [_IOC_NR(VIDIOC_INT_RESET)]            = "VIDIOC_INT_RESET",
-       [_IOC_NR(VIDIOC_INT_AUDIO_CLOCK_FREQ)] = "VIDIOC_INT_AUDIO_CLOCK_FREQ",
-       [_IOC_NR(VIDIOC_INT_DECODE_VBI_LINE)]  = "VIDIOC_INT_DECODE_VBI_LINE",
-       [_IOC_NR(VIDIOC_INT_S_VBI_DATA)]       = "VIDIOC_INT_S_VBI_DATA",
-       [_IOC_NR(VIDIOC_INT_G_VBI_DATA)]       = "VIDIOC_INT_G_VBI_DATA",
-       [_IOC_NR(VIDIOC_INT_I2S_CLOCK_FREQ)]   = "VIDIOC_INT_I2S_CLOCK_FREQ",
-       [_IOC_NR(VIDIOC_INT_S_STANDBY)]        = "VIDIOC_INT_S_STANDBY",
-       [_IOC_NR(VIDIOC_INT_S_AUDIO_ROUTING)]  = "VIDIOC_INT_S_AUDIO_ROUTING",
-       [_IOC_NR(VIDIOC_INT_G_AUDIO_ROUTING)]  = "VIDIOC_INT_G_AUDIO_ROUTING",
-       [_IOC_NR(VIDIOC_INT_S_VIDEO_ROUTING)]  = "VIDIOC_INT_S_VIDEO_ROUTING",
-       [_IOC_NR(VIDIOC_INT_G_VIDEO_ROUTING)]  = "VIDIOC_INT_G_VIDEO_ROUTING",
-       [_IOC_NR(VIDIOC_INT_S_CRYSTAL_FREQ)]   = "VIDIOC_INT_S_CRYSTAL_FREQ",
-       [_IOC_NR(VIDIOC_INT_INIT)]             = "VIDIOC_INT_INIT",
-       [_IOC_NR(VIDIOC_INT_G_STD_OUTPUT)]     = "VIDIOC_INT_G_STD_OUTPUT",
-       [_IOC_NR(VIDIOC_INT_S_STD_OUTPUT)]     = "VIDIOC_INT_S_STD_OUTPUT",
-};
-#define V4L2_INT_IOCTLS ARRAY_SIZE(v4l2_int_ioctls)
-
 /* Common ioctl debug function. This function can be used by
    external ioctl messages as well as internal V4L ioctl */
 void v4l_printk_ioctl(unsigned int cmd)
@@ -319,12 +301,8 @@ void v4l_printk_ioctl(unsigned int cmd)
 
        switch (_IOC_TYPE(cmd)) {
        case 'd':
-               if (_IOC_NR(cmd) >= V4L2_INT_IOCTLS) {
-                       type = "v4l2_int";
-                       break;
-               }
-               printk("%s", v4l2_int_ioctls[_IOC_NR(cmd)]);
-               return;
+               type = "v4l2_int";
+               break;
 #ifdef CONFIG_VIDEO_V4L1_COMPAT
        case 'v':
                if (_IOC_NR(cmd) >= V4L1_IOCTLS) {
@@ -392,16 +370,14 @@ video_fix_command(unsigned int cmd)
 /*
  * Obsolete usercopy function - Should be removed soon
  */
-int
-video_usercopy(struct inode *inode, struct file *file,
-              unsigned int cmd, unsigned long arg,
-              int (*func)(struct inode *inode, struct file *file,
-                          unsigned int cmd, void *arg))
+long
+video_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
+               v4l2_kioctl func)
 {
        char    sbuf[128];
        void    *mbuf = NULL;
        void    *parg = NULL;
-       int     err  = -EINVAL;
+       long    err  = -EINVAL;
        int     is_ext_ctrl;
        size_t  ctrls_size = 0;
        void __user *user_ptr = NULL;
@@ -458,7 +434,7 @@ video_usercopy(struct inode *inode, struct file *file,
        }
 
        /* call driver */
-       err = func(inode, file, cmd, parg);
+       err = func(file, cmd, parg);
        if (err == -ENOIOCTLCMD)
                err = -EINVAL;
        if (is_ext_ctrl) {
@@ -543,11 +519,12 @@ static inline void v4l_print_ext_ctrls(unsigned int cmd,
        dbgarg(cmd, "");
        printk(KERN_CONT "class=0x%x", c->ctrl_class);
        for (i = 0; i < c->count; i++) {
-               if (show_vals)
+               if (show_vals && !c->controls[i].size)
                        printk(KERN_CONT " id/val=0x%x/0x%x",
                                c->controls[i].id, c->controls[i].value);
                else
-                       printk(KERN_CONT " id=0x%x", c->controls[i].id);
+                       printk(KERN_CONT " id=0x%x,size=%u",
+                               c->controls[i].id, c->controls[i].size);
        }
        printk(KERN_CONT "\n");
 };
@@ -558,10 +535,9 @@ static inline int check_ext_ctrls(struct v4l2_ext_controls *c, int allow_priv)
 
        /* zero the reserved fields */
        c->reserved[0] = c->reserved[1] = 0;
-       for (i = 0; i < c->count; i++) {
+       for (i = 0; i < c->count; i++)
                c->controls[i].reserved2[0] = 0;
-               c->controls[i].reserved2[1] = 0;
-       }
+
        /* V4L2_CID_PRIVATE_BASE cannot be used as control class
           when using extended controls.
           Only when passed in through VIDIOC_G_CTRL and VIDIOC_S_CTRL
@@ -586,52 +562,52 @@ 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;
        }
        return -EINVAL;
 }
 
-static int __video_do_ioctl(struct inode *inode, struct file *file,
+static long __video_do_ioctl(struct file *file,
                unsigned int cmd, void *arg)
 {
        struct video_device *vfd = video_devdata(file);
        const struct v4l2_ioctl_ops *ops = vfd->ioctl_ops;
-       void                 *fh = file->private_data;
-       int                  ret = -EINVAL;
+       void *fh = file->private_data;
+       long ret = -EINVAL;
 
        if ((vfd->debug & V4L2_DEBUG_IOCTL) &&
                                !(vfd->debug & V4L2_DEBUG_IOCTL_ARG)) {
@@ -656,8 +632,6 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
        if (cmd == VIDIOCGMBUF) {
                struct video_mbuf *p = arg;
 
-               memset(p, 0, sizeof(*p));
-
                if (!ops->vidiocgmbuf)
                        return ret;
                ret = ops->vidiocgmbuf(file, fh, p);
@@ -675,7 +649,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
         V4L2 ioctls.
         ********************************************************/
        if (_IOC_TYPE(cmd) == 'v' && _IOC_NR(cmd) < BASE_VIDIOCPRIVATE)
-               return v4l_compat_translate_ioctl(inode, file, cmd, arg,
+               return v4l_compat_translate_ioctl(file, cmd, arg,
                                                __video_do_ioctl);
 #endif
 
@@ -684,7 +658,6 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
        case VIDIOC_QUERYCAP:
        {
                struct v4l2_capability *cap = (struct v4l2_capability *)arg;
-               memset(cap, 0, sizeof(*cap));
 
                if (!ops->vidioc_querycap)
                        break;
@@ -727,16 +700,8 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
        case VIDIOC_ENUM_FMT:
        {
                struct v4l2_fmtdesc *f = arg;
-               enum v4l2_buf_type type;
-               unsigned int index;
-
-               index = f->index;
-               type  = f->type;
-               memset(f, 0, sizeof(*f));
-               f->index = index;
-               f->type  = type;
 
-               switch (type) {
+               switch (f->type) {
                case V4L2_BUF_TYPE_VIDEO_CAPTURE:
                        if (ops->vidioc_enum_fmt_vid_cap)
                                ret = ops->vidioc_enum_fmt_vid_cap(file, fh, f);
@@ -746,18 +711,6 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
                                ret = ops->vidioc_enum_fmt_vid_overlay(file,
                                        fh, f);
                        break;
-#if 1
-               /* V4L2_BUF_TYPE_VBI_CAPTURE should not support VIDIOC_ENUM_FMT
-                * according to the spec. The bttv and saa7134 drivers support
-                * it though, so just warn that this is deprecated and will be
-                * removed in the near future. */
-               case V4L2_BUF_TYPE_VBI_CAPTURE:
-                       if (ops->vidioc_enum_fmt_vbi_cap) {
-                               printk(KERN_WARNING "vidioc_enum_fmt_vbi_cap will be removed in 2.6.28!\n");
-                               ret = ops->vidioc_enum_fmt_vbi_cap(file, fh, f);
-                       }
-                       break;
-#endif
                case V4L2_BUF_TYPE_VIDEO_OUTPUT:
                        if (ops->vidioc_enum_fmt_vid_out)
                                ret = ops->vidioc_enum_fmt_vid_out(file, fh, f);
@@ -785,8 +738,6 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
        {
                struct v4l2_format *f = (struct v4l2_format *)arg;
 
-               memset(f->fmt.raw_data, 0, sizeof(f->fmt.raw_data));
-
                /* FIXME: Should be one dump per type */
                dbgarg(cmd, "type=%s\n", prt_names(f->type, v4l2_type_names));
 
@@ -849,44 +800,53 @@ static int __video_do_ioctl(struct inode *inode, 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);
@@ -903,46 +863,55 @@ static int __video_do_ioctl(struct inode *inode, 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);
@@ -965,6 +934,9 @@ static int __video_do_ioctl(struct inode *inode, 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,
@@ -1102,7 +1074,6 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
                        return -EINVAL;
 
                v4l2_video_std_construct(p, curr_id, descr);
-               p->index = index;
 
                dbgarg(cmd, "index=%d, id=0x%Lx, name=%s, fps=%d/%d, "
                                "framelines=%d\n", p->index,
@@ -1122,8 +1093,10 @@ static int __video_do_ioctl(struct inode *inode, 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);
@@ -1167,12 +1140,22 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
        case VIDIOC_ENUMINPUT:
        {
                struct v4l2_input *p = arg;
-               int i = p->index;
+
+               /*
+                * We set the flags for CAP_PRESETS, CAP_CUSTOM_TIMINGS &
+                * CAP_STD here based on ioctl handler provided by the
+                * driver. If the driver doesn't support these
+                * for a specific input, it must override these flags.
+                */
+               if (ops->vidioc_s_std)
+                       p->capabilities |= V4L2_IN_CAP_STD;
+               if (ops->vidioc_s_dv_preset)
+                       p->capabilities |= V4L2_IN_CAP_PRESETS;
+               if (ops->vidioc_s_dv_timings)
+                       p->capabilities |= V4L2_IN_CAP_CUSTOM_TIMINGS;
 
                if (!ops->vidioc_enum_input)
                        break;
-               memset(p, 0, sizeof(*p));
-               p->index = i;
 
                ret = ops->vidioc_enum_input(file, fh, p);
                if (!ret)
@@ -1211,12 +1194,22 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
        case VIDIOC_ENUMOUTPUT:
        {
                struct v4l2_output *p = arg;
-               int i = p->index;
 
                if (!ops->vidioc_enum_output)
                        break;
-               memset(p, 0, sizeof(*p));
-               p->index = i;
+
+               /*
+                * We set the flags for CAP_PRESETS, CAP_CUSTOM_TIMINGS &
+                * CAP_STD here based on ioctl handler provided by the
+                * driver. If the driver doesn't support these
+                * for a specific output, it must override these flags.
+                */
+               if (ops->vidioc_s_std)
+                       p->capabilities |= V4L2_OUT_CAP_STD;
+               if (ops->vidioc_s_dv_preset)
+                       p->capabilities |= V4L2_OUT_CAP_PRESETS;
+               if (ops->vidioc_s_dv_timings)
+                       p->capabilities |= V4L2_OUT_CAP_CUSTOM_TIMINGS;
 
                ret = ops->vidioc_enum_output(file, fh, p);
                if (!ret)
@@ -1392,13 +1385,10 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
        case VIDIOC_G_AUDIO:
        {
                struct v4l2_audio *p = arg;
-               __u32 index = p->index;
 
                if (!ops->vidioc_g_audio)
                        break;
 
-               memset(p, 0, sizeof(*p));
-               p->index = index;
                ret = ops->vidioc_g_audio(file, fh, p);
                if (!ret)
                        dbgarg(cmd, "index=%d, name=%s, capability=0x%x, "
@@ -1440,7 +1430,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
 
                if (!ops->vidioc_g_audout)
                        break;
-               dbgarg(cmd, "Enum for index=%d\n", p->index);
+
                ret = ops->vidioc_g_audout(file, fh, p);
                if (!ret)
                        dbgarg2("index=%d, name=%s, capability=%d, "
@@ -1496,6 +1486,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
 
                if (!ops->vidioc_g_crop)
                        break;
+
                dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names));
                ret = ops->vidioc_g_crop(file, fh, p);
                if (!ret)
@@ -1520,6 +1511,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
                /*FIXME: Should also show v4l2_fract pixelaspect */
                if (!ops->vidioc_cropcap)
                        break;
+
                dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names));
                ret = ops->vidioc_cropcap(file, fh, p);
                if (!ret) {
@@ -1534,6 +1526,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
 
                if (!ops->vidioc_g_jpegcomp)
                        break;
+
                ret = ops->vidioc_g_jpegcomp(file, fh, p);
                if (!ret)
                        dbgarg(cmd, "quality=%d, APPn=%d, "
@@ -1574,7 +1567,6 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
 
                if (!ops->vidioc_encoder_cmd)
                        break;
-               memset(&p->raw, 0, sizeof(p->raw));
                ret = ops->vidioc_encoder_cmd(file, fh, p);
                if (!ret)
                        dbgarg(cmd, "cmd=%d, flags=%x\n", p->cmd, p->flags);
@@ -1586,7 +1578,6 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
 
                if (!ops->vidioc_try_encoder_cmd)
                        break;
-               memset(&p->raw, 0, sizeof(p->raw));
                ret = ops->vidioc_try_encoder_cmd(file, fh, p);
                if (!ret)
                        dbgarg(cmd, "cmd=%d, flags=%x\n", p->cmd, p->flags);
@@ -1595,24 +1586,26 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
        case VIDIOC_G_PARM:
        {
                struct v4l2_streamparm *p = arg;
-               __u32 type = p->type;
-
-               memset(p, 0, sizeof(*p));
-               p->type = type;
 
                if (ops->vidioc_g_parm) {
+                       ret = check_fmt(ops, p->type);
+                       if (ret)
+                               break;
                        ret = ops->vidioc_g_parm(file, fh, p);
                } else {
-                       struct v4l2_standard s;
+                       v4l2_std_id std = vfd->current_norm;
 
                        if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
                                return -EINVAL;
 
-                       v4l2_video_std_construct(&s, vfd->current_norm,
-                                                v4l2_norm_to_name(vfd->current_norm));
-
-                       p->parm.capture.timeperframe = s.frameperiod;
                        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);
@@ -1624,6 +1617,10 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
 
                if (!ops->vidioc_s_parm)
                        break;
+               ret = check_fmt(ops, p->type);
+               if (ret)
+                       break;
+
                dbgarg(cmd, "type=%d\n", p->type);
                ret = ops->vidioc_s_parm(file, fh, p);
                break;
@@ -1631,14 +1628,10 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
        case VIDIOC_G_TUNER:
        {
                struct v4l2_tuner *p = arg;
-               __u32 index = p->index;
 
                if (!ops->vidioc_g_tuner)
                        break;
 
-               memset(p, 0, sizeof(*p));
-               p->index = index;
-
                ret = ops->vidioc_g_tuner(file, fh, p);
                if (!ret)
                        dbgarg(cmd, "index=%d, name=%s, type=%d, "
@@ -1675,8 +1668,6 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
                if (!ops->vidioc_g_frequency)
                        break;
 
-               memset(p->reserved, 0, sizeof(p->reserved));
-
                ret = ops->vidioc_g_frequency(file, fh, p);
                if (!ret)
                        dbgarg(cmd, "tuner=%d, type=%d, frequency=%d\n",
@@ -1697,12 +1688,13 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
        case VIDIOC_G_SLICED_VBI_CAP:
        {
                struct v4l2_sliced_vbi_cap *p = arg;
-               __u32 type = p->type;
 
                if (!ops->vidioc_g_sliced_vbi_cap)
                        break;
-               memset(p, 0, sizeof(*p));
-               p->type = type;
+
+               /* Clear up to type, everything after type is zerod already */
+               memset(p, 0, offsetof(struct v4l2_sliced_vbi_cap, type));
+
                dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names));
                ret = ops->vidioc_g_sliced_vbi_cap(file, fh, p);
                if (!ret)
@@ -1719,7 +1711,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
        case VIDIOC_DBG_G_REGISTER:
        {
-               struct v4l2_register *p = arg;
+               struct v4l2_dbg_register *p = arg;
 
                if (!capable(CAP_SYS_ADMIN))
                        ret = -EPERM;
@@ -1729,7 +1721,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
        }
        case VIDIOC_DBG_S_REGISTER:
        {
-               struct v4l2_register *p = arg;
+               struct v4l2_dbg_register *p = arg;
 
                if (!capable(CAP_SYS_ADMIN))
                        ret = -EPERM;
@@ -1738,12 +1730,14 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
                break;
        }
 #endif
-       case VIDIOC_G_CHIP_IDENT:
+       case VIDIOC_DBG_G_CHIP_IDENT:
        {
-               struct v4l2_chip_ident *p = arg;
+               struct v4l2_dbg_chip_ident *p = arg;
 
                if (!ops->vidioc_g_chip_ident)
                        break;
+               p->ident = V4L2_IDENT_NONE;
+               p->revision = 0;
                ret = ops->vidioc_g_chip_ident(file, fh, p);
                if (!ret)
                        dbgarg(cmd, "chip_ident=%u, revision=0x%x\n", p->ident, p->revision);
@@ -1761,6 +1755,193 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
                ret = ops->vidioc_s_hw_freq_seek(file, fh, p);
                break;
        }
+       case VIDIOC_ENUM_FRAMESIZES:
+       {
+               struct v4l2_frmsizeenum *p = arg;
+
+               if (!ops->vidioc_enum_framesizes)
+                       break;
+
+               ret = ops->vidioc_enum_framesizes(file, fh, p);
+               dbgarg(cmd,
+                       "index=%d, pixelformat=%c%c%c%c, type=%d ",
+                       p->index,
+                       (p->pixel_format & 0xff),
+                       (p->pixel_format >>  8) & 0xff,
+                       (p->pixel_format >> 16) & 0xff,
+                       (p->pixel_format >> 24) & 0xff,
+                       p->type);
+               switch (p->type) {
+               case V4L2_FRMSIZE_TYPE_DISCRETE:
+                       dbgarg3("width = %d, height=%d\n",
+                               p->discrete.width, p->discrete.height);
+                       break;
+               case V4L2_FRMSIZE_TYPE_STEPWISE:
+                       dbgarg3("min %dx%d, max %dx%d, step %dx%d\n",
+                               p->stepwise.min_width,  p->stepwise.min_height,
+                               p->stepwise.step_width, p->stepwise.step_height,
+                               p->stepwise.max_width,  p->stepwise.max_height);
+                       break;
+               case V4L2_FRMSIZE_TYPE_CONTINUOUS:
+                       dbgarg3("continuous\n");
+                       break;
+               default:
+                       dbgarg3("- Unknown type!\n");
+               }
+
+               break;
+       }
+       case VIDIOC_ENUM_FRAMEINTERVALS:
+       {
+               struct v4l2_frmivalenum *p = arg;
+
+               if (!ops->vidioc_enum_frameintervals)
+                       break;
+
+               ret = ops->vidioc_enum_frameintervals(file, fh, p);
+               dbgarg(cmd,
+                       "index=%d, pixelformat=%d, width=%d, height=%d, type=%d ",
+                       p->index, p->pixel_format,
+                       p->width, p->height, p->type);
+               switch (p->type) {
+               case V4L2_FRMIVAL_TYPE_DISCRETE:
+                       dbgarg2("fps=%d/%d\n",
+                               p->discrete.numerator,
+                               p->discrete.denominator);
+                       break;
+               case V4L2_FRMIVAL_TYPE_STEPWISE:
+                       dbgarg2("min=%d/%d, max=%d/%d, step=%d/%d\n",
+                               p->stepwise.min.numerator,
+                               p->stepwise.min.denominator,
+                               p->stepwise.max.numerator,
+                               p->stepwise.max.denominator,
+                               p->stepwise.step.numerator,
+                               p->stepwise.step.denominator);
+                       break;
+               case V4L2_FRMIVAL_TYPE_CONTINUOUS:
+                       dbgarg2("continuous\n");
+                       break;
+               default:
+                       dbgarg2("- Unknown type!\n");
+               }
+               break;
+       }
+       case VIDIOC_ENUM_DV_PRESETS:
+       {
+               struct v4l2_dv_enum_preset *p = arg;
+
+               if (!ops->vidioc_enum_dv_presets)
+                       break;
+
+               ret = ops->vidioc_enum_dv_presets(file, fh, p);
+               if (!ret)
+                       dbgarg(cmd,
+                               "index=%d, preset=%d, name=%s, width=%d,"
+                               " height=%d ",
+                               p->index, p->preset, p->name, p->width,
+                               p->height);
+               break;
+       }
+       case VIDIOC_S_DV_PRESET:
+       {
+               struct v4l2_dv_preset *p = arg;
+
+               if (!ops->vidioc_s_dv_preset)
+                       break;
+
+               dbgarg(cmd, "preset=%d\n", p->preset);
+               ret = ops->vidioc_s_dv_preset(file, fh, p);
+               break;
+       }
+       case VIDIOC_G_DV_PRESET:
+       {
+               struct v4l2_dv_preset *p = arg;
+
+               if (!ops->vidioc_g_dv_preset)
+                       break;
+
+               ret = ops->vidioc_g_dv_preset(file, fh, p);
+               if (!ret)
+                       dbgarg(cmd, "preset=%d\n", p->preset);
+               break;
+       }
+       case VIDIOC_QUERY_DV_PRESET:
+       {
+               struct v4l2_dv_preset *p = arg;
+
+               if (!ops->vidioc_query_dv_preset)
+                       break;
+
+               ret = ops->vidioc_query_dv_preset(file, fh, p);
+               if (!ret)
+                       dbgarg(cmd, "preset=%d\n", p->preset);
+               break;
+       }
+       case VIDIOC_S_DV_TIMINGS:
+       {
+               struct v4l2_dv_timings *p = arg;
+
+               if (!ops->vidioc_s_dv_timings)
+                       break;
+
+               switch (p->type) {
+               case V4L2_DV_BT_656_1120:
+                       dbgarg2("bt-656/1120:interlaced=%d, pixelclock=%lld,"
+                               " width=%d, height=%d, polarities=%x,"
+                               " hfrontporch=%d, hsync=%d, hbackporch=%d,"
+                               " vfrontporch=%d, vsync=%d, vbackporch=%d,"
+                               " il_vfrontporch=%d, il_vsync=%d,"
+                               " il_vbackporch=%d\n",
+                               p->bt.interlaced, p->bt.pixelclock,
+                               p->bt.width, p->bt.height, p->bt.polarities,
+                               p->bt.hfrontporch, p->bt.hsync,
+                               p->bt.hbackporch, p->bt.vfrontporch,
+                               p->bt.vsync, p->bt.vbackporch,
+                               p->bt.il_vfrontporch, p->bt.il_vsync,
+                               p->bt.il_vbackporch);
+                       ret = ops->vidioc_s_dv_timings(file, fh, p);
+                       break;
+               default:
+                       dbgarg2("Unknown type %d!\n", p->type);
+                       break;
+               }
+               break;
+       }
+       case VIDIOC_G_DV_TIMINGS:
+       {
+               struct v4l2_dv_timings *p = arg;
+
+               if (!ops->vidioc_g_dv_timings)
+                       break;
+
+               ret = ops->vidioc_g_dv_timings(file, fh, p);
+               if (!ret) {
+                       switch (p->type) {
+                       case V4L2_DV_BT_656_1120:
+                               dbgarg2("bt-656/1120:interlaced=%d,"
+                                       " pixelclock=%lld,"
+                                       " width=%d, height=%d, polarities=%x,"
+                                       " hfrontporch=%d, hsync=%d,"
+                                       " hbackporch=%d, vfrontporch=%d,"
+                                       " vsync=%d, vbackporch=%d,"
+                                       " il_vfrontporch=%d, il_vsync=%d,"
+                                       " il_vbackporch=%d\n",
+                                       p->bt.interlaced, p->bt.pixelclock,
+                                       p->bt.width, p->bt.height,
+                                       p->bt.polarities, p->bt.hfrontporch,
+                                       p->bt.hsync, p->bt.hbackporch,
+                                       p->bt.vfrontporch, p->bt.vsync,
+                                       p->bt.vbackporch, p->bt.il_vfrontporch,
+                                       p->bt.il_vsync, p->bt.il_vbackporch);
+                               break;
+                       default:
+                               dbgarg2("Unknown type %d!\n", p->type);
+                               break;
+                       }
+               }
+               break;
+       }
+
        default:
        {
                if (!ops->vidioc_default)
@@ -1773,20 +1954,59 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
        if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) {
                if (ret < 0) {
                        v4l_print_ioctl(vfd->name, cmd);
-                       printk(KERN_CONT " error %d\n", ret);
+                       printk(KERN_CONT " error %ld\n", ret);
                }
        }
 
        return ret;
 }
 
-int video_ioctl2(struct inode *inode, struct file *file,
+/* In some cases, only a few fields are used as input, i.e. when the app sets
+ * "index" and then the driver fills in the rest of the structure for the thing
+ * with that index.  We only need to copy up the first non-input field.  */
+static unsigned long cmd_input_size(unsigned int cmd)
+{
+       /* Size of structure up to and including 'field' */
+#define CMDINSIZE(cmd, type, field)                            \
+       case VIDIOC_##cmd:                                      \
+               return offsetof(struct v4l2_##type, field) +    \
+                       sizeof(((struct v4l2_##type *)0)->field);
+
+       switch (cmd) {
+               CMDINSIZE(ENUM_FMT,             fmtdesc,        type);
+               CMDINSIZE(G_FMT,                format,         type);
+               CMDINSIZE(QUERYBUF,             buffer,         type);
+               CMDINSIZE(G_PARM,               streamparm,     type);
+               CMDINSIZE(ENUMSTD,              standard,       index);
+               CMDINSIZE(ENUMINPUT,            input,          index);
+               CMDINSIZE(G_CTRL,               control,        id);
+               CMDINSIZE(G_TUNER,              tuner,          index);
+               CMDINSIZE(QUERYCTRL,            queryctrl,      id);
+               CMDINSIZE(QUERYMENU,            querymenu,      index);
+               CMDINSIZE(ENUMOUTPUT,           output,         index);
+               CMDINSIZE(G_MODULATOR,          modulator,      index);
+               CMDINSIZE(G_FREQUENCY,          frequency,      tuner);
+               CMDINSIZE(CROPCAP,              cropcap,        type);
+               CMDINSIZE(G_CROP,               crop,           type);
+               CMDINSIZE(ENUMAUDIO,            audio,          index);
+               CMDINSIZE(ENUMAUDOUT,           audioout,       index);
+               CMDINSIZE(ENCODER_CMD,          encoder_cmd,    flags);
+               CMDINSIZE(TRY_ENCODER_CMD,      encoder_cmd,    flags);
+               CMDINSIZE(G_SLICED_VBI_CAP,     sliced_vbi_cap, type);
+               CMDINSIZE(ENUM_FRAMESIZES,      frmsizeenum,    pixel_format);
+               CMDINSIZE(ENUM_FRAMEINTERVALS,  frmivalenum,    height);
+       default:
+               return _IOC_SIZE(cmd);
+       }
+}
+
+long video_ioctl2(struct file *file,
               unsigned int cmd, unsigned long arg)
 {
        char    sbuf[128];
        void    *mbuf = NULL;
        void    *parg = NULL;
-       int     err  = -EINVAL;
+       long    err  = -EINVAL;
        int     is_ext_ctrl;
        size_t  ctrls_size = 0;
        void __user *user_ptr = NULL;
@@ -1798,13 +2018,7 @@ int video_ioctl2(struct inode *inode, struct file *file,
                       cmd == VIDIOC_TRY_EXT_CTRLS);
 
        /*  Copy arguments into temp kernel buffer  */
-       switch (_IOC_DIR(cmd)) {
-       case _IOC_NONE:
-               parg = NULL;
-               break;
-       case _IOC_READ:
-       case _IOC_WRITE:
-       case (_IOC_WRITE | _IOC_READ):
+       if (_IOC_DIR(cmd) != _IOC_NONE) {
                if (_IOC_SIZE(cmd) <= sizeof(sbuf)) {
                        parg = sbuf;
                } else {
@@ -1816,10 +2030,19 @@ int video_ioctl2(struct inode *inode, struct file *file,
                }
 
                err = -EFAULT;
-               if (_IOC_DIR(cmd) & _IOC_WRITE)
-                       if (copy_from_user(parg, (void __user *)arg, _IOC_SIZE(cmd)))
+               if (_IOC_DIR(cmd) & _IOC_WRITE) {
+                       unsigned long n = cmd_input_size(cmd);
+
+                       if (copy_from_user(parg, (void __user *)arg, n))
                                goto out;
-               break;
+
+                       /* zero out anything we don't copy from userspace */
+                       if (n < _IOC_SIZE(cmd))
+                               memset((u8 *)parg + n, 0, _IOC_SIZE(cmd) - n);
+               } else {
+                       /* read-only ioctl */
+                       memset(parg, 0, _IOC_SIZE(cmd));
+               }
        }
 
        if (is_ext_ctrl) {
@@ -1844,7 +2067,7 @@ int video_ioctl2(struct inode *inode, struct file *file,
        }
 
        /* Handles IOCTL */
-       err = __video_do_ioctl(inode, file, cmd, parg);
+       err = __video_do_ioctl(file, cmd, parg);
        if (err == -ENOIOCTLCMD)
                err = -EINVAL;
        if (is_ext_ctrl) {