Hi,

I've updated the videodev patch set.  The core part of the redesign is
attached below for comments.  It is also available here:
        http://bytesex.org/patches/2.5/10_videodev-2.5.6-pre2.diff

The 2.4 version of the patch (which is slightly different because
it keeps the old stuff for backward compatibility) is here:
        http://bytesex.org/patches/10_videodev-2.4.19-pre2.diff

I've also updated most v4l drivers (including usb cams this time)
to the new videodev interface.  Changes are available as individual,
per driver patches from:
        http://bytesex.org/patches/2.5/

There is also one big patch with all changes:
        http://bytesex.org/patches/2.5/patch-2.5.6-pre2-kraxel.gz

Comments?  Bugs?  I plan to feed this to Linus soon ...

  Gerd

==============================[ cut here ]==============================

This patch is a redesign for videodev.[ch].  Changes:

- drop the function pointers (read/write/mmap/poll/...) from struct
  video_device, use struct file_operations directly instead.
  Dispatching to different drivers by minor number is done the same way
  soundcore.o handles this: swap file->f_fops at open() time.

- also drop the now obsolete video_red/write/mmap/poll/...  functions
  from videodev.c

- provide a video_generic_ioctl() function which can (and should) be
  used by v4l drivers to handle copying from and to userspace.

- provide video_exclusive_open/release functions which can be used by
  v4l drivers to make sure only one process at a time opens the
  device.  They can be hooked directly into struct file_operations if
  some driver has nothing to initialize at open time (which is true
  for many drivers in drivers/media/radio/).

--- linux-2.5.6-pre2/drivers/media/video/videodev.c     Fri Mar  1 20:00:52 2002
+++ linux/drivers/media/video/videodev.c        Fri Mar  1 20:01:31 2002
@@ -25,15 +25,13 @@
 #include <linux/mm.h>
 #include <linux/string.h>
 #include <linux/errno.h>
-#include <linux/videodev.h>
 #include <linux/init.h>
-
+#include <linux/kmod.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
 #include <asm/semaphore.h>
 
-#include <linux/kmod.h>
-
+#include <linux/videodev.h>
 
 #define VIDEO_NUM_DEVICES      256 
 
@@ -62,61 +60,20 @@
 
 #endif /* CONFIG_PROC_FS && CONFIG_VIDEO_PROC_FS */
 
-
-/*
- *     Read will do some smarts later on. Buffer pin etc.
- */
- 
-static ssize_t video_read(struct file *file,
-       char *buf, size_t count, loff_t *ppos)
-{
-       struct video_device *vfl=video_device[minor(file->f_dentry->d_inode->i_rdev)];
-       if(vfl->read)
-               return vfl->read(vfl, buf, count, file->f_flags&O_NONBLOCK);
-       else
-               return -EINVAL;
-}
-
-
-/*
- *     Write for now does nothing. No reason it shouldnt do overlay setting
- *     for some boards I guess..
- */
-
-static ssize_t video_write(struct file *file, const char *buf, 
-       size_t count, loff_t *ppos)
-{
-       struct video_device *vfl=video_device[minor(file->f_dentry->d_inode->i_rdev)];
-       if(vfl->write)
-               return vfl->write(vfl, buf, count, file->f_flags&O_NONBLOCK);
-       else
-               return 0;
-}
-
-/*
- *     Poll to see if we're readable, can probably be used for timing on incoming
- *     frames, etc..
- */
-
-static unsigned int video_poll(struct file *file, poll_table * wait)
+struct video_device* video_devdata(struct file *file)
 {
-       struct video_device *vfl=video_device[minor(file->f_dentry->d_inode->i_rdev)];
-       if(vfl->poll)
-               return vfl->poll(vfl, file, wait);
-       else
-               return 0;
+       return video_device[minor(file->f_dentry->d_inode->i_rdev)];
 }
 
-
 /*
  *     Open a video device.
  */
-
 static int video_open(struct inode *inode, struct file *file)
 {
        unsigned int minor = minor(inode->i_rdev);
-       int err, retval = 0;
+       int err = 0;
        struct video_device *vfl;
+       struct file_operations *old_fops;
        
        if(minor>=VIDEO_NUM_DEVICES)
                return -ENODEV;
@@ -129,88 +86,115 @@
                request_module(modname);
                vfl=video_device[minor];
                if (vfl==NULL) {
-                       retval = -ENODEV;
+                       err = -ENODEV;
                        goto error_out;
                }
        }
-       if(vfl->busy) {
-               retval = -EBUSY;
-               goto error_out;
+       unlock_kernel();
+
+       old_fops = file->f_op;
+       file->f_op = fops_get(vfl->fops);
+       if(file->f_op->open)
+               err = file->f_op->open(inode,file);
+       if (err) {
+               fops_put(file->f_op);
+               file->f_op = fops_get(old_fops);
        }
-       vfl->busy=1;            /* In case vfl->open sleeps */
-       
-       if(vfl->owner)
-               __MOD_INC_USE_COUNT(vfl->owner);
+       fops_put(old_fops);
+       return err;
        
-       if(vfl->open)
-       {
-               err=vfl->open(vfl,0);   /* Tell the device it is open */
-               if(err)
-               {
-                       vfl->busy=0;
-                       if(vfl->owner)
-                               __MOD_DEC_USE_COUNT(vfl->owner);
-                       
-                       unlock_kernel();
-                       return err;
-               }
-       }
-       unlock_kernel();
-       return 0;
 error_out:
        unlock_kernel();
-       return retval;
+       return err;
 }
 
 /*
- *     Last close of a video for Linux device
+ * ioctl helper function -- handles userspace copying
  */
+int
+video_generic_ioctl(struct inode *inode, struct file *file,
+                   unsigned int cmd, unsigned long arg)
+{
+       struct  video_device *vfl = video_devdata(file);
+       char    sbuf[128];
+       void    *mbuf = NULL;
+       void    *parg = NULL;
+       int     err  = -EINVAL;
        
-static int video_release(struct inode *inode, struct file *file)
-{
-       struct video_device *vfl;
-       lock_kernel();
-       vfl=video_device[minor(inode->i_rdev)];
-       if(vfl->close)
-               vfl->close(vfl);
-       vfl->busy=0;
-       if(vfl->owner)
-               __MOD_DEC_USE_COUNT(vfl->owner);
-       unlock_kernel();
-       return 0;
-}
+       if (vfl->kernel_ioctl == NULL)
+               return -EINVAL;
 
-static int video_ioctl(struct inode *inode, struct file *file,
-       unsigned int cmd, unsigned long arg)
-{
-       struct video_device *vfl=video_device[minor(inode->i_rdev)];
-       int err=vfl->ioctl(vfl, cmd, (void *)arg);
+       /*  Copy arguments into temp kernel buffer  */
+       switch (_IOC_DIR(cmd)) {
+       case _IOC_NONE:
+               parg = (void *)arg;
+               break;
+       case _IOC_READ: /* some v4l ioctls are marked wrong ... */
+       case _IOC_WRITE:
+       case (_IOC_WRITE | _IOC_READ):
+               if (_IOC_SIZE(cmd) <= sizeof(sbuf)) {
+                       parg = sbuf;
+               } else {
+                       /* too big to allocate from stack */
+                       mbuf = kmalloc(_IOC_SIZE(cmd),GFP_KERNEL);
+                       if (NULL == mbuf)
+                               return -ENOMEM;
+                       parg = mbuf;
+               }
+               
+               err = -EFAULT;
+               if (copy_from_user(parg, (void *)arg, _IOC_SIZE(cmd)))
+                       goto out;
+               break;
+       }
 
-       if(err!=-ENOIOCTLCMD)
-               return err;
-       
-       switch(cmd)
+       /* call driver */
+       err = vfl->kernel_ioctl(inode, file, cmd, parg);
+       if (err == -ENOIOCTLCMD)
+               err = -EINVAL;
+       if (err < 0)
+               goto out;
+
+       /*  Copy results into user buffer  */
+       switch (_IOC_DIR(cmd))
        {
-               default:
-                       return -EINVAL;
+       case _IOC_READ:
+       case (_IOC_WRITE | _IOC_READ):
+               if (copy_to_user((void *)arg, parg, _IOC_SIZE(cmd)))
+                       err = -EFAULT;
+               break;
        }
+
+out:
+       if (mbuf)
+               kfree(mbuf);
+       return err;
 }
 
 /*
- *     We need to do MMAP support
+ * open/release helper functions -- handle exclusive opens
  */
-  
-int video_mmap(struct file *file, struct vm_area_struct *vma)
+extern int video_exclusive_open(struct inode *inode, struct file *file)
 {
-       int ret = -EINVAL;
-       struct video_device *vfl=video_device[minor(file->f_dentry->d_inode->i_rdev)];
-       if(vfl->mmap) {
-               lock_kernel();
-               ret = vfl->mmap(vma, vfl, (char *)vma->vm_start, 
-                               (unsigned long)(vma->vm_end-vma->vm_start));
-               unlock_kernel();
+       struct  video_device *vfl = video_devdata(file);
+       int retval = 0;
+
+       down(&vfl->lock);
+       if (vfl->users) {
+               retval = -EBUSY;
+       } else {
+               vfl->users++;
        }
-       return ret;
+       up(&vfl->lock);
+       return retval;
+}
+
+extern int video_exclusive_release(struct inode *inode, struct file *file)
+{
+       struct  video_device *vfl = video_devdata(file);
+       
+       vfl->users--;
+       return 0;
 }
 
 /*
@@ -398,7 +382,6 @@
 {
        int i=0;
        int base;
-       int err;
        int end;
        char *name_base;
        char name[16];
@@ -452,17 +435,7 @@
        vfd->minor=i;
        up(&videodev_register_lock);
 
-       /* The init call may sleep so we book the slot out
-          then call */
        MOD_INC_USE_COUNT;
-       if(vfd->initialize) {
-               err=vfd->initialize(vfd);
-               if(err<0) {
-                       video_device[i]=NULL;
-                       MOD_DEC_USE_COUNT;
-                       return err;
-               }
-       }
        sprintf (name, "v4l/%s%d", name_base, i - base);
        /*
         *      Start the device root only. Anything else
@@ -474,6 +447,7 @@
                                S_IFCHR | S_IRUSR | S_IWUSR,
                                &video_fops,
                                NULL);
+       init_MUTEX(&vfd->lock);
        
 #if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
        sprintf (name, "%s%d", name_base, i - base);
@@ -509,13 +483,7 @@
 {
        owner:          THIS_MODULE,
        llseek:         no_llseek,
-       read:           video_read,
-       write:          video_write,
-       ioctl:          video_ioctl,
-       mmap:           video_mmap,
        open:           video_open,
-       release:        video_release,
-       poll:           video_poll,
 };
 
 /*
@@ -540,12 +508,9 @@
 
 static void __exit videodev_exit(void)
 {
-#ifdef MODULE          
 #if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
        videodev_proc_destroy ();
 #endif
-#endif
-       
        devfs_unregister_chrdev(VIDEO_MAJOR, "video_capture");
 }
 
@@ -554,6 +519,10 @@
 
 EXPORT_SYMBOL(video_register_device);
 EXPORT_SYMBOL(video_unregister_device);
+EXPORT_SYMBOL(video_devdata);
+EXPORT_SYMBOL(video_generic_ioctl);
+EXPORT_SYMBOL(video_exclusive_open);
+EXPORT_SYMBOL(video_exclusive_release);
 
 MODULE_AUTHOR("Alan Cox");
 MODULE_DESCRIPTION("Device registrar for Video4Linux drivers");
--- linux-2.5.6-pre2/include/linux/videodev.h   Fri Mar  1 20:00:56 2002
+++ linux/include/linux/videodev.h      Fri Mar  1 20:13:34 2002
@@ -4,6 +4,18 @@
 #include <linux/types.h>
 #include <linux/version.h>
 
+#if 0
+/*
+ * v4l2 is still work-in-progress, integration planed for 2.5.x
+ *   v4l2 project homepage:   http://www.thedirks.org/v4l2/
+ *   patches available from:  http://bytesex.org/patches/
+ */ 
+# define HAVE_V4L2 1
+# include <linux/videodev2.h>
+#else
+# undef HAVE_V4L2
+#endif
+
 #ifdef __KERNEL__
 
 #include <linux/poll.h>
@@ -13,24 +25,25 @@
 struct video_device
 {
        struct module *owner;
-       char name[32];
-       int type;
+       char name[32];
+       int type;       /* v4l1 */
+       int type2;      /* v4l2 */
        int hardware;
+       int minor;
 
-       int (*open)(struct video_device *, int mode);
-       void (*close)(struct video_device *);
-       long (*read)(struct video_device *, char *, unsigned long, int noblock);
-       /* Do we need a write method ? */
-       long (*write)(struct video_device *, const char *, unsigned long, int noblock);
-#if LINUX_VERSION_CODE >= 0x020100
-       unsigned int (*poll)(struct video_device *, struct file *, poll_table *);
-#endif
-       int (*ioctl)(struct video_device *, unsigned int , void *);
-       int (*mmap)(struct vm_area_struct *vma, struct video_device *, const char *, 
unsigned long);
-       int (*initialize)(struct video_device *);       
+       /* new interface -- we will use file_operations directly
+        * like soundcore does.
+        * kernel_ioctl() will be called by video_generic_ioctl.
+        * video_generic_ioctl() does the userspace copying of the
+        * ioctl arguments */
+       struct file_operations *fops;
+       int (*kernel_ioctl)(struct inode *inode, struct file *file,
+                           unsigned int cmd, void *arg);
        void *priv;             /* Used to be 'private' but that upsets C++ */
-       int busy;
-       int minor;
+
+       /* for videodev.c intenal usage -- don't touch */
+       int users;
+       struct semaphore lock;
        devfs_handle_t devfs_handle;
 };
 
@@ -43,8 +56,13 @@
 #define VFL_TYPE_VTX           3
 
 extern void video_unregister_device(struct video_device *);
-#endif
+extern struct video_device* video_devdata(struct file*);
 
+extern int video_exclusive_open(struct inode *inode, struct file *file);
+extern int video_exclusive_release(struct inode *inode, struct file *file);
+extern int video_generic_ioctl(struct inode *inode, struct file *file,
+                              unsigned int cmd, unsigned long arg);
+#endif /* __KERNEL__ */
 
 #define VID_TYPE_CAPTURE       1       /* Can capture */
 #define VID_TYPE_TUNER         2       /* Can tune */
@@ -150,6 +168,7 @@
 #define VIDEO_AUDIO_VOLUME     4
 #define VIDEO_AUDIO_BASS       8
 #define VIDEO_AUDIO_TREBLE     16      
+#define VIDEO_AUDIO_BALANCE    32
        char    name[16];
 #define VIDEO_SOUND_MONO       1
 #define VIDEO_SOUND_STEREO     2
@@ -379,4 +398,10 @@
 #define VID_HARDWARE_MEYE      32      /* Sony Vaio MotionEye cameras */
 #define VID_HARDWARE_CPIA2     33
 
-#endif
+#endif /* __LINUX_VIDEODEV_H */
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */



_______________________________________________
Video4linux-list mailing list
[EMAIL PROTECTED]
https://listman.redhat.com/mailman/listinfo/video4linux-list

Reply via email to