Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=a3a048cea301baba5d451991074a85dc20a8f228
Commit:     a3a048cea301baba5d451991074a85dc20a8f228
Parent:     2c94a674e059e89252d58da655efa4e798be4d48
Author:     Mauro Carvalho Chehab <[EMAIL PROTECTED]>
AuthorDate: Sat Nov 10 22:21:01 2007 -0300
Committer:  Mauro Carvalho Chehab <[EMAIL PROTECTED]>
CommitDate: Fri Jan 25 19:02:06 2008 -0200

    V4L/DVB (6582): Fix em28xx to allow multiple open
    
    Allows shared access support for em28xx. Just one userspace application is
    allowed to get stream. The other(s) application(s) can change V4L2 controls,
    set video standards, etc.
    
    This patch were splited from Markus Rechberger's tree and backported to 
2.6.17
    by Pádraig Brady.
    
    The original patch were ported to the latest em28xx version and had 
CodingStyle
    corrected to solve the issues pointed by scripts/checkpatch.pl.
    
    Thanks to Pádraig Brady <[EMAIL PROTECTED]> for pointing this.
    
    Signed-off-by: Mauro Carvalho Chehab <[EMAIL PROTECTED]>
---
 drivers/media/video/em28xx/em28xx-video.c |  124 +++++++++++++++++------------
 drivers/media/video/em28xx/em28xx.h       |    6 ++
 2 files changed, 79 insertions(+), 51 deletions(-)

diff --git a/drivers/media/video/em28xx/em28xx-video.c 
b/drivers/media/video/em28xx/em28xx-video.c
index b43edc3..5b17ca9 100644
--- a/drivers/media/video/em28xx/em28xx-video.c
+++ b/drivers/media/video/em28xx/em28xx-video.c
@@ -234,6 +234,7 @@ static int em28xx_v4l2_open(struct inode *inode, struct 
file *filp)
        int minor = iminor(inode);
        int errCode = 0;
        struct em28xx *h,*dev = NULL;
+       struct em28xx_fh *fh;
 
        list_for_each_entry(h, &em28xx_devlist, devlist) {
                if (h->vdev->minor == minor) {
@@ -251,19 +252,17 @@ static int em28xx_v4l2_open(struct inode *inode, struct 
file *filp)
        em28xx_videodbg("open minor=%d type=%s users=%d\n",
                                minor,v4l2_type_names[dev->type],dev->users);
 
-       mutex_lock(&dev->lock);
+       fh = kzalloc(sizeof(struct em28xx_fh), GFP_KERNEL);
 
-       if (dev->users) {
-               em28xx_warn("this driver can be opened only once\n");
-               mutex_unlock(&dev->lock);
-               return -EBUSY;
+       if (!fh) {
+               em28xx_errdev("em28xx-video.c: Out of memory?!\n");
+               return -ENOMEM;
        }
+       mutex_lock(&dev->lock);
+       fh->dev = dev;
+       filp->private_data = fh;
 
-       spin_lock_init(&dev->queue_lock);
-       init_waitqueue_head(&dev->wait_frame);
-       init_waitqueue_head(&dev->wait_stream);
-
-       if (dev->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+       if (dev->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->users == 0) {
                em28xx_set_alternate(dev);
 
                dev->width = norm_maxw(dev);
@@ -277,26 +276,16 @@ static int em28xx_v4l2_open(struct inode *inode, struct 
file *filp)
                em28xx_capture_start(dev, 1);
                em28xx_resolution_set(dev);
 
-               /* device needs to be initialized before isoc transfer */
-               video_mux(dev, 0);
 
                /* start the transfer */
                errCode = em28xx_init_isoc(dev);
                if (errCode)
                        goto err;
 
+               em28xx_empty_framequeues(dev);
        }
 
        dev->users++;
-       filp->private_data = dev;
-       dev->io = IO_NONE;
-       dev->stream = STREAM_OFF;
-       dev->num_frames = 0;
-
-       /* prepare queues */
-       em28xx_empty_framequeues(dev);
-
-       dev->state |= DEV_INITIALIZED;
 
 err:
        mutex_unlock(&dev->lock);
@@ -333,34 +322,41 @@ static void em28xx_release_resources(struct em28xx *dev)
  */
 static int em28xx_v4l2_close(struct inode *inode, struct file *filp)
 {
-       int errCode;
-       struct em28xx *dev=filp->private_data;
+       struct em28xx_fh *fh  = filp->private_data;
+       struct em28xx    *dev = fh->dev;
+       int              errCode;
 
        em28xx_videodbg("users=%d\n", dev->users);
 
        mutex_lock(&dev->lock);
+       if (fh->reader == 1)
+              fh->reader = 0;
 
-       em28xx_uninit_isoc(dev);
+       if (dev->users == 1) {
+               dev->reader = 0;
 
-       em28xx_release_buffers(dev);
+               em28xx_uninit_isoc(dev);
+               em28xx_release_buffers(dev);
 
-       /* the device is already disconnect, free the remaining resources */
-       if (dev->state & DEV_DISCONNECTED) {
-               em28xx_release_resources(dev);
-               mutex_unlock(&dev->lock);
-               kfree(dev);
-               return 0;
-       }
+               /* the device is already disconnect,
+                  free the remaining resources */
+               if (dev->state & DEV_DISCONNECTED) {
+                       em28xx_release_resources(dev);
+                       mutex_unlock(&dev->lock);
+                       kfree(dev);
+                       return 0;
+               }
 
-       /* set alternate 0 */
-       dev->alt = 0;
-       em28xx_videodbg("setting alternate 0\n");
-       errCode = usb_set_interface(dev->udev, 0, 0);
-       if (errCode < 0) {
-               em28xx_errdev ("cannot change alternate number to 0 
(error=%i)\n",
-                    errCode);
+               /* set alternate 0 */
+               dev->alt = 0;
+               em28xx_videodbg("setting alternate 0\n");
+               errCode = usb_set_interface(dev->udev, 0, 0);
+               if (errCode < 0) {
+                       em28xx_errdev("cannot change alternate number to "
+                                       "0 (error=%i)\n", errCode);
+               }
        }
-
+       kfree(fh);
        dev->users--;
        wake_up_interruptible_nr(&dev->open, 1);
        mutex_unlock(&dev->lock);
@@ -378,13 +374,19 @@ em28xx_v4l2_read(struct file *filp, char __user * buf, 
size_t count,
        struct em28xx_frame_t *f, *i;
        unsigned long lock_flags;
        int ret = 0;
-       struct em28xx *dev = filp->private_data;
+       struct em28xx_fh *fh = filp->private_data;
+       struct em28xx *dev = fh->dev;
 
        mutex_lock(&dev->lock);
 
-       if (dev->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+       if (dev->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
                em28xx_videodbg("V4l2_Buf_type_videocapture is set\n");
+
+       if (dev->reader > 0 && fh->reader == 0) {
+               mutex_unlock(&dev->lock);
+               return -EBUSY;
        }
+
        if (dev->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
                em28xx_videodbg("V4L2_BUF_TYPE_VBI_CAPTURE is set\n");
                em28xx_videodbg("not supported yet! ...\n");
@@ -423,6 +425,9 @@ em28xx_v4l2_read(struct file *filp, char __user * buf, 
size_t count,
                                " the device again to choose the read 
method\n");
                mutex_unlock(&dev->lock);
                return -EINVAL;
+       } else {
+               dev->reader = 1;
+               fh->reader = 1;
        }
 
        if (dev->io == IO_NONE) {
@@ -491,7 +496,8 @@ em28xx_v4l2_read(struct file *filp, char __user * buf, 
size_t count,
 static unsigned int em28xx_v4l2_poll(struct file *filp, poll_table * wait)
 {
        unsigned int mask = 0;
-       struct em28xx *dev = filp->private_data;
+       struct em28xx_fh *fh = filp->private_data;
+       struct em28xx *dev = fh->dev;
 
        mutex_lock(&dev->lock);
 
@@ -559,15 +565,23 @@ static struct vm_operations_struct em28xx_vm_ops = {
  */
 static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
 {
-       unsigned long size = vma->vm_end - vma->vm_start,
-           start = vma->vm_start;
-       void *pos;
-       u32 i;
-
-       struct em28xx *dev = filp->private_data;
+       struct em28xx_fh *fh    = filp->private_data;
+       struct em28xx    *dev   = fh->dev;
+       unsigned long    size   = vma->vm_end - vma->vm_start;
+       unsigned long    start  = vma->vm_start;
+       void             *pos;
+       u32              i;
 
        mutex_lock(&dev->lock);
 
+       if (dev->reader > 0 && fh->reader == 0) {
+               mutex_unlock(&dev->lock);
+               return -EBUSY;
+       } else {
+               dev->reader = 1;
+               fh->reader = 1;
+       }
+
        if (dev->state & DEV_DISCONNECTED) {
                em28xx_videodbg("mmap: device not present\n");
                mutex_unlock(&dev->lock);
@@ -918,6 +932,7 @@ static int em28xx_do_ioctl(struct inode *inode, struct file 
*filp,
                           struct em28xx *dev, unsigned int cmd, void *arg,
                           v4l2_kioctl driver_ioctl)
 {
+       struct em28xx_fh *fh = filp->private_data;
        int ret;
 
        switch (cmd) {
@@ -1227,6 +1242,8 @@ static int em28xx_do_ioctl(struct inode *inode, struct 
file *filp,
                                return ret;
                        }
                }
+
+               fh->reader = 0;
                em28xx_empty_framequeues(dev);
                mutex_unlock(&dev->lock);
 
@@ -1248,7 +1265,8 @@ static int em28xx_do_ioctl(struct inode *inode, struct 
file *filp,
 static int em28xx_video_do_ioctl(struct inode *inode, struct file *filp,
                                 unsigned int cmd, void *arg)
 {
-       struct em28xx *dev = filp->private_data;
+       struct em28xx_fh *fh = filp->private_data;
+       struct em28xx *dev   = fh->dev;
 
        if (!dev)
                return -ENODEV;
@@ -1456,7 +1474,8 @@ static int em28xx_v4l2_ioctl(struct inode *inode, struct 
file *filp,
                             unsigned int cmd, unsigned long arg)
 {
        int ret = 0;
-       struct em28xx *dev = filp->private_data;
+       struct em28xx_fh *fh = filp->private_data;
+       struct em28xx *dev   = fh->dev;
 
        if (dev->state & DEV_DISCONNECTED) {
                em28xx_errdev("v4l2 ioctl: device not present\n");
@@ -1503,7 +1522,10 @@ static int em28xx_init_dev(struct em28xx **devhandle, 
struct usb_device *udev,
 
        dev->udev = udev;
        mutex_init(&dev->lock);
+       spin_lock_init(&dev->queue_lock);
        init_waitqueue_head(&dev->open);
+       init_waitqueue_head(&dev->wait_frame);
+       init_waitqueue_head(&dev->wait_stream);
 
        dev->em28xx_write_regs = em28xx_write_regs;
        dev->em28xx_read_reg = em28xx_read_reg;
diff --git a/drivers/media/video/em28xx/em28xx.h 
b/drivers/media/video/em28xx/em28xx.h
index c2531da..f8ad0f4 100644
--- a/drivers/media/video/em28xx/em28xx.h
+++ b/drivers/media/video/em28xx/em28xx.h
@@ -258,6 +258,7 @@ struct em28xx {
        int vscale;             /* vertical scale factor (see datasheet) */
        int interlaced;         /* 1=interlace fileds, 0=just top fileds */
        int type;
+       unsigned int reader:1;
 
        unsigned long hash;     /* eeprom hash - for boards with generic ID */
        unsigned long i2c_hash; /* i2c devicelist hash - for boards with 
generic ID */
@@ -294,6 +295,11 @@ struct em28xx {
        int (*em28xx_read_reg_req) (struct em28xx * dev, u8 req, u16 reg);
 };
 
+struct em28xx_fh {
+       struct em28xx *dev;
+       unsigned int  reader:1;
+};
+
 /* Provided by em28xx-i2c.c */
 
 void em28xx_i2c_call_clients(struct em28xx *dev, unsigned int cmd, void *arg);
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to