V4L/DVB (4861): Remove the need of a STD array for drivers using video_ioctl2
[safe/jmp/linux-2.6] / drivers / media / video / videodev.c
index 3178353..1be7127 100644 (file)
  */
 
 #define dbgarg(cmd, fmt, arg...) \
-               if (vfd->debug & V4L2_DEBUG_IOCTL_ARG)                  \
+               if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) {                \
                        printk (KERN_DEBUG "%s: ",  vfd->name);         \
                        v4l_printk_ioctl(cmd);                          \
-                       printk (KERN_DEBUG "%s: " fmt, vfd->name, ## arg);
+                       printk (KERN_DEBUG "%s: " fmt, vfd->name, ## arg); \
+               }
 
 #define dbgarg2(fmt, arg...) \
                if (vfd->debug & V4L2_DEBUG_IOCTL_ARG)                  \
@@ -37,7 +38,6 @@
 #include <linux/init.h>
 #include <linux/kmod.h>
 #include <linux/slab.h>
-#include <linux/devfs_fs_kernel.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
 
@@ -105,7 +105,7 @@ static DEFINE_MUTEX(videodev_lock);
 
 struct video_device* video_devdata(struct file *file)
 {
-       return video_device[iminor(file->f_dentry->d_inode)];
+       return video_device[iminor(file->f_path.dentry->d_inode)];
 }
 
 /*
@@ -428,6 +428,10 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
                v4l_print_ioctl(vfd->name, cmd);
        }
 
+       if (_IOC_TYPE(cmd)=='v')
+               return v4l_compat_translate_ioctl(inode,file,cmd,arg,
+                                               __video_do_ioctl);
+
        switch(cmd) {
        /* --- capabilities ------------------------------------------ */
        case VIDIOC_QUERYCAP:
@@ -740,13 +744,13 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
        case VIDIOC_DQBUF:
        {
                struct v4l2_buffer *p=arg;
-               if (!vfd->vidioc_qbuf)
+               if (!vfd->vidioc_dqbuf)
                        break;
                ret = check_fmt (vfd, p->type);
                if (ret)
                        break;
 
-               ret=vfd->vidioc_qbuf(file, fh, p);
+               ret=vfd->vidioc_dqbuf(file, fh, p);
                if (!ret)
                        dbgbuf(cmd,vfd,p);
                break;
@@ -761,7 +765,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
                ret=vfd->vidioc_overlay(file, fh, *i);
                break;
        }
-#ifdef HAVE_V4L1
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
        /* --- streaming capture ------------------------------------- */
        case VIDIOCGMBUF:
        {
@@ -829,20 +833,85 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
        case VIDIOC_ENUMSTD:
        {
                struct v4l2_standard *p = arg;
-               unsigned int index = p->index;
+               v4l2_std_id id = vfd->tvnorms,curr_id=0;
+               unsigned int index = p->index,i;
 
-               if (!vfd->tvnormsize) {
-                       printk (KERN_WARNING "%s: no TV norms defined!\n",
-                                               vfd->name);
+               if (index<0) {
+                       ret=-EINVAL;
                        break;
                }
 
-               if (index<=0 || index >= vfd->tvnormsize) {
-                       ret=-EINVAL;
-                       break;
+               /* Return norm array on a canonical way */
+               for (i=0;i<= index && id; i++) {
+                       if ( (id & V4L2_STD_PAL) == V4L2_STD_PAL) {
+                               curr_id = V4L2_STD_PAL;
+                       } else if ( (id & V4L2_STD_PAL_BG) == V4L2_STD_PAL_BG) {
+                               curr_id = V4L2_STD_PAL_BG;
+                       } else if ( (id & V4L2_STD_PAL_DK) == V4L2_STD_PAL_DK) {
+                               curr_id = V4L2_STD_PAL_DK;
+                       } else if ( (id & V4L2_STD_PAL_B) == V4L2_STD_PAL_B) {
+                               curr_id = V4L2_STD_PAL_B;
+                       } else if ( (id & V4L2_STD_PAL_B1) == V4L2_STD_PAL_B1) {
+                               curr_id = V4L2_STD_PAL_B1;
+                       } else if ( (id & V4L2_STD_PAL_G) == V4L2_STD_PAL_G) {
+                               curr_id = V4L2_STD_PAL_G;
+                       } else if ( (id & V4L2_STD_PAL_H) == V4L2_STD_PAL_H) {
+                               curr_id = V4L2_STD_PAL_H;
+                       } else if ( (id & V4L2_STD_PAL_I) == V4L2_STD_PAL_I) {
+                               curr_id = V4L2_STD_PAL_I;
+                       } else if ( (id & V4L2_STD_PAL_D) == V4L2_STD_PAL_D) {
+                               curr_id = V4L2_STD_PAL_D;
+                       } else if ( (id & V4L2_STD_PAL_D1) == V4L2_STD_PAL_D1) {
+                               curr_id = V4L2_STD_PAL_D1;
+                       } else if ( (id & V4L2_STD_PAL_K) == V4L2_STD_PAL_K) {
+                               curr_id = V4L2_STD_PAL_K;
+                       } else if ( (id & V4L2_STD_PAL_M) == V4L2_STD_PAL_M) {
+                               curr_id = V4L2_STD_PAL_M;
+                       } else if ( (id & V4L2_STD_PAL_N) == V4L2_STD_PAL_N) {
+                               curr_id = V4L2_STD_PAL_N;
+                       } else if ( (id & V4L2_STD_PAL_Nc) == V4L2_STD_PAL_Nc) {
+                               curr_id = V4L2_STD_PAL_Nc;
+                       } else if ( (id & V4L2_STD_PAL_60) == V4L2_STD_PAL_60) {
+                               curr_id = V4L2_STD_PAL_60;
+                       } else if ( (id & V4L2_STD_NTSC) == V4L2_STD_NTSC) {
+                               curr_id = V4L2_STD_NTSC;
+                       } else if ( (id & V4L2_STD_NTSC_M) == V4L2_STD_NTSC_M) {
+                               curr_id = V4L2_STD_NTSC_M;
+                       } else if ( (id & V4L2_STD_NTSC_M_JP) == V4L2_STD_NTSC_M_JP) {
+                               curr_id = V4L2_STD_NTSC_M_JP;
+                       } else if ( (id & V4L2_STD_NTSC_443) == V4L2_STD_NTSC_443) {
+                               curr_id = V4L2_STD_NTSC_443;
+                       } else if ( (id & V4L2_STD_NTSC_M_KR) == V4L2_STD_NTSC_M_KR) {
+                               curr_id = V4L2_STD_NTSC_M_KR;
+                       } else if ( (id & V4L2_STD_SECAM) == V4L2_STD_SECAM) {
+                               curr_id = V4L2_STD_SECAM;
+                       } else if ( (id & V4L2_STD_SECAM_DK) == V4L2_STD_SECAM_DK) {
+                               curr_id = V4L2_STD_SECAM_DK;
+                       } else if ( (id & V4L2_STD_SECAM_B) == V4L2_STD_SECAM_B) {
+                               curr_id = V4L2_STD_SECAM_B;
+                       } else if ( (id & V4L2_STD_SECAM_D) == V4L2_STD_SECAM_D) {
+                               curr_id = V4L2_STD_SECAM_D;
+                       } else if ( (id & V4L2_STD_SECAM_G) == V4L2_STD_SECAM_G) {
+                               curr_id = V4L2_STD_SECAM_G;
+                       } else if ( (id & V4L2_STD_SECAM_H) == V4L2_STD_SECAM_H) {
+                               curr_id = V4L2_STD_SECAM_H;
+                       } else if ( (id & V4L2_STD_SECAM_K) == V4L2_STD_SECAM_K) {
+                               curr_id = V4L2_STD_SECAM_K;
+                       } else if ( (id & V4L2_STD_SECAM_K1) == V4L2_STD_SECAM_K1) {
+                               curr_id = V4L2_STD_SECAM_K1;
+                       } else if ( (id & V4L2_STD_SECAM_L) == V4L2_STD_SECAM_L) {
+                               curr_id = V4L2_STD_SECAM_L;
+                       } else if ( (id & V4L2_STD_SECAM_LC) == V4L2_STD_SECAM_LC) {
+                               curr_id = V4L2_STD_SECAM_LC;
+                       } else {
+                               break;
+                       }
+                       id &= ~curr_id;
                }
-               v4l2_video_std_construct(p, vfd->tvnorms[p->index].id,
-                                        vfd->tvnorms[p->index].name);
+               if (i<=index)
+                       return -EINVAL;
+
+               v4l2_video_std_construct(p, curr_id,v4l2_norm_to_name(curr_id));
                p->index = index;
 
                dbgarg (cmd, "index=%d, id=%Ld, name=%s, fps=%d/%d, "
@@ -868,39 +937,23 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
        }
        case VIDIOC_S_STD:
        {
-               v4l2_std_id *id = arg;
-               unsigned int i;
-
-               if (!vfd->tvnormsize) {
-                       printk (KERN_WARNING "%s: no TV norms defined!\n",
-                                               vfd->name);
-                       break;
-               }
+               v4l2_std_id *id = arg,norm;
 
                dbgarg (cmd, "value=%Lu\n", (long long unsigned) *id);
 
-               /* First search for exact match */
-               for (i = 0; i < vfd->tvnormsize; i++)
-                       if (*id == vfd->tvnorms[i].id)
-                               break;
-               /* Then for a generic video std that contains desired std */
-               if (i == vfd->tvnormsize)
-                       for (i = 0; i < vfd->tvnormsize; i++)
-                               if (*id & vfd->tvnorms[i].id)
-                                       break;
-               if (i == vfd->tvnormsize) {
+               norm = (*id) & vfd->tvnorms;
+               if ( vfd->tvnorms && !norm)     /* Check if std is supported */
                        break;
-               }
 
                /* Calls the specific handler */
                if (vfd->vidioc_s_std)
-                       ret=vfd->vidioc_s_std(file, fh, i);
+                       ret=vfd->vidioc_s_std(file, fh, &norm);
                else
                        ret=-EINVAL;
 
                /* Updates standard information */
-               if (!ret)
-                       vfd->current_norm=*id;
+               if (ret>=0)
+                       vfd->current_norm=norm;
 
                break;
        }
@@ -1088,9 +1141,13 @@ 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 (!vfd->vidioc_g_audio)
                        break;
+
+               memset(p,0,sizeof(*p));
+               p->index=index;
                dbgarg(cmd, "Get for index=%d\n", p->index);
                ret=vfd->vidioc_g_audio(file, fh, p);
                if (!ret)
@@ -1284,9 +1341,23 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
        case VIDIOC_G_PARM:
        {
                struct v4l2_streamparm *p=arg;
-               if (!vfd->vidioc_g_parm)
-                       break;
-               ret=vfd->vidioc_g_parm(file, fh, p);
+               if (vfd->vidioc_g_parm) {
+                       ret=vfd->vidioc_g_parm(file, fh, p);
+               } else {
+                       struct v4l2_standard s;
+
+                       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));
+
+                       memset(p,0,sizeof(*p));
+
+                       p->parm.capture.timeperframe = s.frameperiod;
+                       ret=0;
+               }
+
                dbgarg (cmd, "type=%d\n", p->type);
                break;
        }
@@ -1302,8 +1373,14 @@ 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 (!vfd->vidioc_g_tuner)
                        break;
+
+               memset(p,0,sizeof(*p));
+               p->index=index;
+
                ret=vfd->vidioc_g_tuner(file, fh, p);
                if (!ret)
                        dbgarg (cmd, "index=%d, name=%s, type=%d, "
@@ -1336,6 +1413,9 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
                struct v4l2_frequency *p=arg;
                if (!vfd->vidioc_g_frequency)
                        break;
+
+               memset(p,0,sizeof(*p));
+
                ret=vfd->vidioc_g_frequency(file, fh, p);
                if (!ret)
                        dbgarg (cmd, "tuner=%d, type=%d, frequency=%d\n",
@@ -1369,12 +1449,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
                ret=vfd->vidioc_log_status(file, fh);
                break;
        }
-
-       /* --- Others --------------------------------------------- */
-
-       default:
-               ret=v4l_compat_translate_ioctl(inode,file,cmd,arg,__video_do_ioctl);
-       }
+       } /* switch */
 
        if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) {
                if (ret<0) {
@@ -1513,6 +1588,7 @@ int video_register_device(struct video_device *vfd, int type, int nr)
        int i=0;
        int base;
        int end;
+       int ret;
        char *name_base;
 
        switch(type)
@@ -1538,6 +1614,8 @@ int video_register_device(struct video_device *vfd, int type, int nr)
                        name_base = "radio";
                        break;
                default:
+                       printk(KERN_ERR "%s called with unknown type: %d\n",
+                              __FUNCTION__, type);
                        return -1;
        }
 
@@ -1571,11 +1649,19 @@ int video_register_device(struct video_device *vfd, int type, int nr)
                vfd->class_dev.dev = vfd->dev;
        vfd->class_dev.class       = &video_class;
        vfd->class_dev.devt        = MKDEV(VIDEO_MAJOR, vfd->minor);
-       sprintf(vfd->devfs_name, "%s%d", name_base, i - base);
-       strlcpy(vfd->class_dev.class_id, vfd->devfs_name, BUS_ID_SIZE);
-       class_device_register(&vfd->class_dev);
-       class_device_create_file(&vfd->class_dev,
-                               &class_device_attr_name);
+       sprintf(vfd->class_dev.class_id, "%s%d", name_base, i - base);
+       ret = class_device_register(&vfd->class_dev);
+       if (ret < 0) {
+               printk(KERN_ERR "%s: class_device_register failed\n",
+                      __FUNCTION__);
+               goto fail_minor;
+       }
+       ret = class_device_create_file(&vfd->class_dev, &class_device_attr_name);
+       if (ret < 0) {
+               printk(KERN_ERR "%s: class_device_create_file 'name' failed\n",
+                      __FUNCTION__);
+               goto fail_classdev;
+       }
 
 #if 1
        /* needed until all drivers are fixed */
@@ -1585,6 +1671,15 @@ int video_register_device(struct video_device *vfd, int type, int nr)
                       "http://lwn.net/Articles/36850/\n", vfd->name);
 #endif
        return 0;
+
+fail_classdev:
+       class_device_unregister(&vfd->class_dev);
+fail_minor:
+       mutex_lock(&videodev_lock);
+       video_device[vfd->minor] = NULL;
+       vfd->minor = -1;
+       mutex_unlock(&videodev_lock);
+       return ret;
 }
 
 /**