V4L/DVB (6584): Fix read() method
authorMauro Carvalho Chehab <mchehab@infradead.org>
Sun, 11 Nov 2007 04:13:49 +0000 (01:13 -0300)
committerMauro Carvalho Chehab <mchehab@infradead.org>
Fri, 25 Jan 2008 21:02:07 +0000 (19:02 -0200)
Backport read() fixes from Markus Rechberger.

Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
drivers/media/video/em28xx/em28xx-video.c
drivers/media/video/em28xx/em28xx.h

index f0191779a8e2c9588c4b120cfed18160721df999..8a4d221a4fe4d30e28ebae3de6c43e4cd4978435 100644 (file)
@@ -416,6 +416,9 @@ em28xx_v4l2_read(struct file *filp, char __user * buf, size_t count,
        struct em28xx_fh *fh = filp->private_data;
        struct em28xx *dev = fh->dev;
 
+       /* FIXME: read() is not prepared to allow changing the video
+          resolution while streaming. Seems a bug at em28xx_set_fmt
+        */
 
        if (unlikely(res_get(fh) < 0))
                return -EBUSY;
@@ -498,25 +501,36 @@ em28xx_v4l2_read(struct file *filp, char __user * buf, size_t count,
                        mutex_unlock(&dev->lock);
                        return -ENODEV;
                }
+               dev->video_bytesread = 0;
        }
 
        f = list_entry(dev->outqueue.prev, struct em28xx_frame_t, frame);
 
-       spin_lock_irqsave(&dev->queue_lock, lock_flags);
-       list_for_each_entry(i, &dev->outqueue, frame)
-           i->state = F_UNUSED;
-       INIT_LIST_HEAD(&dev->outqueue);
-       spin_unlock_irqrestore(&dev->queue_lock, lock_flags);
-
        em28xx_queue_unusedframes(dev);
 
        if (count > f->buf.length)
                count = f->buf.length;
 
-       if (copy_to_user(buf, f->bufmem, count)) {
-               mutex_unlock(&dev->lock);
+       if ((dev->video_bytesread + count) > dev->frame_size)
+               count = dev->frame_size - dev->video_bytesread;
+
+       if (copy_to_user(buf, f->bufmem+dev->video_bytesread, count)) {
+               em28xx_err("Error while copying to user\n");
                return -EFAULT;
        }
+       dev->video_bytesread += count;
+
+       if (dev->video_bytesread == dev->frame_size) {
+               spin_lock_irqsave(&dev->queue_lock, lock_flags);
+               list_for_each_entry(i, &dev->outqueue, frame)
+                                   i->state = F_UNUSED;
+               INIT_LIST_HEAD(&dev->outqueue);
+               spin_unlock_irqrestore(&dev->queue_lock, lock_flags);
+
+               em28xx_queue_unusedframes(dev);
+               dev->video_bytesread = 0;
+       }
+
        *f_pos += count;
 
        mutex_unlock(&dev->lock);
index 3efc05d2df678567d7b751842c68dde7d2ea4c51..672880383de8970c02a573ee25f68206f196406a 100644 (file)
@@ -260,6 +260,7 @@ struct em28xx {
        int vscale;             /* vertical scale factor (see datasheet) */
        int interlaced;         /* 1=interlace fileds, 0=just top fileds */
        int type;
+       unsigned int video_bytesread;   /* Number of bytes read */
 
        unsigned long hash;     /* eeprom hash - for boards with generic ID */
        unsigned long i2c_hash; /* i2c devicelist hash - for boards with generic ID */
@@ -268,6 +269,7 @@ struct em28xx {
        enum em28xx_dev_state state;
        enum em28xx_stream_state stream;
        enum em28xx_io_method io;
+
        /* locks */
        struct mutex lock;
        spinlock_t queue_lock;