Browse Source

V4L/DVB (6584): Fix read() method

Backport read() fixes from Markus Rechberger.

Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Mauro Carvalho Chehab 17 years ago
parent
commit
9e31ced888
2 changed files with 24 additions and 8 deletions
  1. 22 8
      drivers/media/video/em28xx/em28xx-video.c
  2. 2 0
      drivers/media/video/em28xx/em28xx.h

+ 22 - 8
drivers/media/video/em28xx/em28xx-video.c

@@ -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);

+ 2 - 0
drivers/media/video/em28xx/em28xx.h

@@ -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;