diff options
author | Mauro Carvalho Chehab <mchehab@infradead.org> | 2007-11-11 02:13:49 -0200 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@infradead.org> | 2007-11-11 02:13:49 -0200 |
commit | d739e8d4ecb372bce6fd3fcb5417e509f6356914 (patch) | |
tree | 464b6e9287c5c86e65d574a75b456fc8f4cc68e0 /linux/drivers/media/video/em28xx | |
parent | cab6c5e66d150f790c08e02b7d29b2ca207af15e (diff) | |
download | mediapointer-dvb-s2-d739e8d4ecb372bce6fd3fcb5417e509f6356914.tar.gz mediapointer-dvb-s2-d739e8d4ecb372bce6fd3fcb5417e509f6356914.tar.bz2 |
Fix read() method
From: Mauro Carvalho Chehab <mchehab@infradead.org>
Backport read() fixes from Markus Reichberger.
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Diffstat (limited to 'linux/drivers/media/video/em28xx')
-rw-r--r-- | linux/drivers/media/video/em28xx/em28xx-video.c | 30 | ||||
-rw-r--r-- | linux/drivers/media/video/em28xx/em28xx.h | 2 |
2 files changed, 24 insertions, 8 deletions
diff --git a/linux/drivers/media/video/em28xx/em28xx-video.c b/linux/drivers/media/video/em28xx/em28xx-video.c index 55a494727..daad789f1 100644 --- a/linux/drivers/media/video/em28xx/em28xx-video.c +++ b/linux/drivers/media/video/em28xx/em28xx-video.c @@ -444,6 +444,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; @@ -526,25 +529,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); diff --git a/linux/drivers/media/video/em28xx/em28xx.h b/linux/drivers/media/video/em28xx/em28xx.h index a568ee47c..75eff52ff 100644 --- a/linux/drivers/media/video/em28xx/em28xx.h +++ b/linux/drivers/media/video/em28xx/em28xx.h @@ -263,6 +263,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 */ @@ -271,6 +272,7 @@ struct em28xx { enum em28xx_dev_state state; enum em28xx_stream_state stream; enum em28xx_io_method io; + /* locks */ #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,15) struct mutex lock; |