summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrandon Philips <brandon@ifup.org>2008-04-02 11:10:59 -0700
committerBrandon Philips <brandon@ifup.org>2008-04-02 11:10:59 -0700
commit12d05113a10be2078e72039a301b3d3902d29248 (patch)
treecfe42c1a425ec1fa570fcd183cc02dfb34cf1638
parente2c76fa02753f7c3ed102dbca09fdf17926e6085 (diff)
downloadmediapointer-dvb-s2-12d05113a10be2078e72039a301b3d3902d29248.tar.gz
mediapointer-dvb-s2-12d05113a10be2078e72039a301b3d3902d29248.tar.bz2
videobuf-vmalloc.c: Fix hack of postponing mmap on remap failure
In videobuf-vmalloc.c remap_vmalloc_range is failing when applications are trying to mmap buffers immediately after reqbuf. It fails because the vmalloc area isn't setup until the first QBUF when drivers call iolock. This patch introduces mmap_setup to the qtype_ops and it is called in __videobuf_mmap_setup if the buffer type is mmap. In the case of vmalloc buffers this calls iolock, and sets the state to idle. I don't think this is needed for dma-sg buffers and it defaults to a no-op for everything but vmalloc. Signed-off-by: Brandon Philips <bphilips@suse.de> --- linux/drivers/media/video/videobuf-core.c | 29 +++++++----------- linux/drivers/media/video/videobuf-vmalloc.c | 43 +++++++++++++-------------- linux/include/media/videobuf-core.h | 3 + 3 files changed, 35 insertions(+), 40 deletions(-)
-rw-r--r--linux/drivers/media/video/videobuf-core.c29
-rw-r--r--linux/drivers/media/video/videobuf-vmalloc.c43
-rw-r--r--linux/include/media/videobuf-core.h3
3 files changed, 35 insertions, 40 deletions
diff --git a/linux/drivers/media/video/videobuf-core.c b/linux/drivers/media/video/videobuf-core.c
index 47af78a06..994dd7ab3 100644
--- a/linux/drivers/media/video/videobuf-core.c
+++ b/linux/drivers/media/video/videobuf-core.c
@@ -92,25 +92,17 @@ int videobuf_iolock(struct videobuf_queue *q, struct videobuf_buffer *vb,
MAGIC_CHECK(vb->magic, MAGIC_BUFFER);
MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
- /* This is required to avoid OOPS on some cases,
- since mmap_mapper() method should be called before _iolock.
- On some cases, the mmap_mapper() is called only after scheduling.
- */
- if (vb->memory == V4L2_MEMORY_MMAP) {
- wait_event_timeout(vb->done, q->is_mmapped,
- msecs_to_jiffies(100));
- if (!q->is_mmapped) {
- printk(KERN_ERR
- "Error: mmap_mapper() never called!\n");
- return -EINVAL;
- }
- }
-
return CALL(q, iolock, q, vb, fbuf);
}
/* --------------------------------------------------------------------- */
+static int videobuf_mmap_setup_default(struct videobuf_queue *q,
+ struct videobuf_buffer *vb)
+{
+ return 0;
+}
+
void videobuf_queue_core_init(struct videobuf_queue *q,
struct videobuf_queue_ops *ops,
@@ -132,6 +124,9 @@ void videobuf_queue_core_init(struct videobuf_queue *q,
q->priv_data = priv;
q->int_ops = int_ops;
+ if (!q->int_ops->mmap_setup)
+ q->int_ops->mmap_setup = videobuf_mmap_setup_default;
+
/* All buffer operations are mandatory */
BUG_ON(!q->ops->buf_setup);
BUG_ON(!q->ops->buf_prepare);
@@ -304,8 +299,6 @@ static int __videobuf_mmap_free(struct videobuf_queue *q)
rc = CALL(q, mmap_free, q);
- q->is_mmapped = 0;
-
if (rc < 0)
return rc;
@@ -357,6 +350,9 @@ static int __videobuf_mmap_setup(struct videobuf_queue *q,
switch (memory) {
case V4L2_MEMORY_MMAP:
q->bufs[i]->boff = bsize * i;
+ err = q->int_ops->mmap_setup(q, q->bufs[i]);
+ if (err)
+ break;
break;
case V4L2_MEMORY_USERPTR:
case V4L2_MEMORY_OVERLAY:
@@ -1028,7 +1024,6 @@ int videobuf_mmap_mapper(struct videobuf_queue *q,
mutex_lock(&q->vb_lock);
retval = CALL(q, mmap_mapper, q, vma);
- q->is_mmapped = 1;
mutex_unlock(&q->vb_lock);
return retval;
diff --git a/linux/drivers/media/video/videobuf-vmalloc.c b/linux/drivers/media/video/videobuf-vmalloc.c
index 3ce1c92fc..3bc7308af 100644
--- a/linux/drivers/media/video/videobuf-vmalloc.c
+++ b/linux/drivers/media/video/videobuf-vmalloc.c
@@ -152,21 +152,26 @@ static int __videobuf_iolock (struct videobuf_queue* q,
(unsigned long)mem->vmalloc,
pages << PAGE_SHIFT);
- /* It seems that some kernel versions need to do remap *after*
- the mmap() call
- */
- if (mem->vma) {
- int retval=remap_vmalloc_range(mem->vma, mem->vmalloc,0);
- kfree(mem->vma);
- mem->vma=NULL;
- if (retval<0) {
- dprintk(1,"mmap app bug: remap_vmalloc_range area %p error %d\n",
- mem->vmalloc,retval);
- return retval;
+ return 0;
+}
+
+static int __videobuf_mmap_setup(struct videobuf_queue *q,
+ struct videobuf_buffer *vb)
+{
+ int retval = 0;
+ BUG_ON(vb->memory != V4L2_MEMORY_MMAP);
+ if (vb->state == VIDEOBUF_NEEDS_INIT) {
+ /* bsize == size since the buffer needs to be large enough to
+ * hold an entire frame, not the case in the read case for
+ * example*/
+ vb->size = vb->bsize;
+ retval = __videobuf_iolock(q, vb, NULL);
+ if (!retval) {
+ /* Don't IOLOCK later */
+ vb->state = VIDEOBUF_IDLE;
}
}
-
- return 0;
+ return retval;
}
static int __videobuf_sync(struct videobuf_queue *q,
@@ -239,15 +244,8 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q,
/* Try to remap memory */
retval=remap_vmalloc_range(vma, mem->vmalloc,0);
if (retval<0) {
- dprintk(1,"mmap: postponing remap_vmalloc_range\n");
-
- mem->vma=kmalloc(sizeof(*vma),GFP_KERNEL);
- if (!mem->vma) {
- kfree(map);
- q->bufs[first]->map=NULL;
- return -ENOMEM;
- }
- memcpy(mem->vma,vma,sizeof(*vma));
+ dprintk(1, "mmap: failed to remap_vmalloc_range\n");
+ return -EINVAL;
}
dprintk(1,"mmap %p: q=%p %08lx-%08lx (%lx) pgoff %08lx buf %d\n",
@@ -315,6 +313,7 @@ static struct videobuf_qtype_ops qops = {
.alloc = __videobuf_alloc,
.iolock = __videobuf_iolock,
.sync = __videobuf_sync,
+ .mmap_setup = __videobuf_mmap_setup,
.mmap_free = __videobuf_mmap_free,
.mmap_mapper = __videobuf_mmap_mapper,
.video_copy_to_user = __videobuf_copy_to_user,
diff --git a/linux/include/media/videobuf-core.h b/linux/include/media/videobuf-core.h
index b94057eac..7c80e8adf 100644
--- a/linux/include/media/videobuf-core.h
+++ b/linux/include/media/videobuf-core.h
@@ -144,6 +144,8 @@ struct videobuf_qtype_ops {
int vbihack,
int nonblocking);
int (*mmap_free) (struct videobuf_queue *q);
+ int (*mmap_setup) (struct videobuf_queue *q,
+ struct videobuf_buffer *vb);
int (*mmap_mapper) (struct videobuf_queue *q,
struct vm_area_struct *vma);
};
@@ -168,7 +170,6 @@ struct videobuf_queue {
unsigned int streaming:1;
unsigned int reading:1;
- unsigned int is_mmapped:1;
/* capture via mmap() + ioctl(QBUF/DQBUF) */
struct list_head stream;