From e0c1e01aabf66d47f4903f4b6d439258faa880af Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 13 Apr 2008 11:54:05 -0300 Subject: videobuf: revert changeset #7490:5b77f099a151 From: Mauro Carvalho Chehab This changeset were supposed to optimize mmap() support on vmalloc. However, it just broke mmap() on real devices. Revert the changeset to make mmap() to work again. Signed-off-by: Mauro Carvalho Chehab --- 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, 40 insertions(+), 35 deletions(-) (limited to 'linux') diff --git a/linux/drivers/media/video/videobuf-core.c b/linux/drivers/media/video/videobuf-core.c index 7138410fa..52d9a766c 100644 --- a/linux/drivers/media/video/videobuf-core.c +++ b/linux/drivers/media/video/videobuf-core.c @@ -92,17 +92,25 @@ 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, @@ -124,9 +132,6 @@ 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,6 +309,8 @@ static int __videobuf_mmap_free(struct videobuf_queue *q) rc = CALL(q, mmap_free, q); + q->is_mmapped = 0; + if (rc < 0) return rc; @@ -355,9 +362,6 @@ 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: @@ -1080,6 +1084,7 @@ 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 9e6ff640e..6cdd27d55 100644 --- a/linux/drivers/media/video/videobuf-vmalloc.c +++ b/linux/drivers/media/video/videobuf-vmalloc.c @@ -152,26 +152,21 @@ static int __videobuf_iolock (struct videobuf_queue* q, (unsigned long)mem->vmalloc, pages << PAGE_SHIFT); - 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; + /* 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 retval; + + return 0; } static int __videobuf_sync(struct videobuf_queue *q, @@ -244,8 +239,15 @@ 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: failed to remap_vmalloc_range\n"); - return -EINVAL; + 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 %p: q=%p %08lx-%08lx (%lx) pgoff %08lx buf %d\n", @@ -313,7 +315,6 @@ 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 18b0ba615..ea269cec4 100644 --- a/linux/include/media/videobuf-core.h +++ b/linux/include/media/videobuf-core.h @@ -144,8 +144,6 @@ 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); }; @@ -172,6 +170,7 @@ 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; -- cgit v1.2.3