[PATCH] nommu: remap_pfn_range: fix addr parameter check

2012-09-12 Thread Bob Liu
The addr parameter may not page aligned eg. when it's come from
vfb_mmap():vma->vm_start in video driver.

This patch fix the check in remap_pfn_range() else some driver like v4l2 will
fail in this function while calling mmap() on nommu arch like blackfin and st.

Reported-by: Bhupesh SHARMA 
Reported-by: Scott Jiang 
Signed-off-by: Bob Liu 
---
 mm/nommu.c |2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/mm/nommu.c b/mm/nommu.c
index d4b0c10..5d6068b 100644
--- a/mm/nommu.c
+++ b/mm/nommu.c
@@ -1819,7 +1819,7 @@ struct page *follow_page(struct vm_area_struct *vma, 
unsigned long address,
 int remap_pfn_range(struct vm_area_struct *vma, unsigned long addr,
unsigned long pfn, unsigned long size, pgprot_t prot)
 {
-   if (addr != (pfn << PAGE_SHIFT))
+   if ((addr & PAGE_MASK) != (pfn << PAGE_SHIFT))
return -EINVAL;
 
vma->vm_flags |= VM_IO | VM_RESERVED | VM_PFNMAP;
-- 
1.7.9.5


--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH] drivers:media:video:uvc: fix uvc_v4l2_get_unmapped_area for NOMMU

2012-05-14 Thread Bob Liu
Hi Laurent,

On Tue, May 15, 2012 at 9:01 AM, Bob Liu  wrote:
> Hi Laurent,
>
> On Mon, May 14, 2012 at 7:31 PM, Laurent Pinchart
>  wrote:
>> Hi Bob,
>>
>> On Monday 14 May 2012 18:23:59 Bob Liu wrote:
>>> Fix uvc_v4l2_get_unmapped_area() for NOMMU arch like blackfin after
>>> framework updated to use videobuf2.
>>
>> Thank you for the patch, but I'm afraid you're too late. The fix is already
>> queued for v3.5 :-)
>
> It doesn't matter.

Sorry for my misunderstanding. I've seen the fix in the queue for v3.5.
Please ignore my noise.

>
>>
>>> Signed-off-by: Bob Liu 
>>> ---
>>>  drivers/media/video/uvc/uvc_queue.c |   30 --
>>>  drivers/media/video/uvc/uvc_v4l2.c  |    2 +-
>>>  2 files changed, 1 insertions(+), 31 deletions(-)
>>>
>>> diff --git a/drivers/media/video/uvc/uvc_queue.c
>>> b/drivers/media/video/uvc/uvc_queue.c index 518f77d..30be060 100644
>>> --- a/drivers/media/video/uvc/uvc_queue.c
>>> +++ b/drivers/media/video/uvc/uvc_queue.c
>>> @@ -237,36 +237,6 @@ int uvc_queue_allocated(struct uvc_video_queue *queue)
>>>       return allocated;
>>>  }
>>>
>>> -#ifndef CONFIG_MMU
>>> -/*
>>> - * Get unmapped area.
>>> - *
>>> - * NO-MMU arch need this function to make mmap() work correctly.
>>> - */
>>> -unsigned long uvc_queue_get_unmapped_area(struct uvc_video_queue *queue,
>>> -             unsigned long pgoff)
>>> -{
>>> -     struct uvc_buffer *buffer;
>>> -     unsigned int i;
>>> -     unsigned long ret;
>>> -
>>> -     mutex_lock(&queue->mutex);
>>> -     for (i = 0; i < queue->count; ++i) {
>>> -             buffer = &queue->buffer[i];
>>> -             if ((buffer->buf.m.offset >> PAGE_SHIFT) == pgoff)
>>> -                     break;
>>> -     }
>>> -     if (i == queue->count) {
>>> -             ret = -EINVAL;
>>> -             goto done;
>>> -     }
>>> -     ret = (unsigned long)buf->mem;
>>> -done:
>>> -     mutex_unlock(&queue->mutex);
>>> -     return ret;
>>> -}
>>> -#endif
>>> -
>>>  /*
>>>   * Enable or disable the video buffers queue.
>>>   *
>>> diff --git a/drivers/media/video/uvc/uvc_v4l2.c
>>> b/drivers/media/video/uvc/uvc_v4l2.c index 2ae4f88..506d3d6 100644
>>> --- a/drivers/media/video/uvc/uvc_v4l2.c
>>> +++ b/drivers/media/video/uvc/uvc_v4l2.c
>>> @@ -1067,7 +1067,7 @@ static unsigned long uvc_v4l2_get_unmapped_area(struct
>>> file *file,
>>>
>>>       uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_get_unmapped_area\n");
>>>
>>> -     return uvc_queue_get_unmapped_area(&stream->queue, pgoff);
>>> +     return vb2_get_unmapped_area(&stream->queue, addr, len, pgoff, flags);
>>
>> Just for the record you would have needed to take the queue->mutex around the
>> vb2_get_unmapped_area() call here.
>>
>
> okay, i'll send out v2 soon, please queue it for next window.
> Thank you.
>
>>>  }
>>>  #endif
>>
>> --
>> Regards,
>>
>> Laurent Pinchart
>>
>
> --
> Regards,
> --Bob

-- 
Regards,
--Bob
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH] drivers:media:video:uvc: fix uvc_v4l2_get_unmapped_area for NOMMU

2012-05-14 Thread Bob Liu
Hi Laurent,

On Mon, May 14, 2012 at 7:31 PM, Laurent Pinchart
 wrote:
> Hi Bob,
>
> On Monday 14 May 2012 18:23:59 Bob Liu wrote:
>> Fix uvc_v4l2_get_unmapped_area() for NOMMU arch like blackfin after
>> framework updated to use videobuf2.
>
> Thank you for the patch, but I'm afraid you're too late. The fix is already
> queued for v3.5 :-)

It doesn't matter.

>
>> Signed-off-by: Bob Liu 
>> ---
>>  drivers/media/video/uvc/uvc_queue.c |   30 --
>>  drivers/media/video/uvc/uvc_v4l2.c  |    2 +-
>>  2 files changed, 1 insertions(+), 31 deletions(-)
>>
>> diff --git a/drivers/media/video/uvc/uvc_queue.c
>> b/drivers/media/video/uvc/uvc_queue.c index 518f77d..30be060 100644
>> --- a/drivers/media/video/uvc/uvc_queue.c
>> +++ b/drivers/media/video/uvc/uvc_queue.c
>> @@ -237,36 +237,6 @@ int uvc_queue_allocated(struct uvc_video_queue *queue)
>>       return allocated;
>>  }
>>
>> -#ifndef CONFIG_MMU
>> -/*
>> - * Get unmapped area.
>> - *
>> - * NO-MMU arch need this function to make mmap() work correctly.
>> - */
>> -unsigned long uvc_queue_get_unmapped_area(struct uvc_video_queue *queue,
>> -             unsigned long pgoff)
>> -{
>> -     struct uvc_buffer *buffer;
>> -     unsigned int i;
>> -     unsigned long ret;
>> -
>> -     mutex_lock(&queue->mutex);
>> -     for (i = 0; i < queue->count; ++i) {
>> -             buffer = &queue->buffer[i];
>> -             if ((buffer->buf.m.offset >> PAGE_SHIFT) == pgoff)
>> -                     break;
>> -     }
>> -     if (i == queue->count) {
>> -             ret = -EINVAL;
>> -             goto done;
>> -     }
>> -     ret = (unsigned long)buf->mem;
>> -done:
>> -     mutex_unlock(&queue->mutex);
>> -     return ret;
>> -}
>> -#endif
>> -
>>  /*
>>   * Enable or disable the video buffers queue.
>>   *
>> diff --git a/drivers/media/video/uvc/uvc_v4l2.c
>> b/drivers/media/video/uvc/uvc_v4l2.c index 2ae4f88..506d3d6 100644
>> --- a/drivers/media/video/uvc/uvc_v4l2.c
>> +++ b/drivers/media/video/uvc/uvc_v4l2.c
>> @@ -1067,7 +1067,7 @@ static unsigned long uvc_v4l2_get_unmapped_area(struct
>> file *file,
>>
>>       uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_get_unmapped_area\n");
>>
>> -     return uvc_queue_get_unmapped_area(&stream->queue, pgoff);
>> +     return vb2_get_unmapped_area(&stream->queue, addr, len, pgoff, flags);
>
> Just for the record you would have needed to take the queue->mutex around the
> vb2_get_unmapped_area() call here.
>

okay, i'll send out v2 soon, please queue it for next window.
Thank you.

>>  }
>>  #endif
>
> --
> Regards,
>
> Laurent Pinchart
>

-- 
Regards,
--Bob
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH] drivers:media:video:uvc: fix uvc_v4l2_get_unmapped_area for NOMMU

2012-05-14 Thread Bob Liu
Fix uvc_v4l2_get_unmapped_area() for NOMMU arch like blackfin after framework
updated to use videobuf2.

Signed-off-by: Bob Liu 
---
 drivers/media/video/uvc/uvc_queue.c |   30 --
 drivers/media/video/uvc/uvc_v4l2.c  |2 +-
 2 files changed, 1 insertions(+), 31 deletions(-)

diff --git a/drivers/media/video/uvc/uvc_queue.c 
b/drivers/media/video/uvc/uvc_queue.c
index 518f77d..30be060 100644
--- a/drivers/media/video/uvc/uvc_queue.c
+++ b/drivers/media/video/uvc/uvc_queue.c
@@ -237,36 +237,6 @@ int uvc_queue_allocated(struct uvc_video_queue *queue)
return allocated;
 }
 
-#ifndef CONFIG_MMU
-/*
- * Get unmapped area.
- *
- * NO-MMU arch need this function to make mmap() work correctly.
- */
-unsigned long uvc_queue_get_unmapped_area(struct uvc_video_queue *queue,
-   unsigned long pgoff)
-{
-   struct uvc_buffer *buffer;
-   unsigned int i;
-   unsigned long ret;
-
-   mutex_lock(&queue->mutex);
-   for (i = 0; i < queue->count; ++i) {
-   buffer = &queue->buffer[i];
-   if ((buffer->buf.m.offset >> PAGE_SHIFT) == pgoff)
-   break;
-   }
-   if (i == queue->count) {
-   ret = -EINVAL;
-   goto done;
-   }
-   ret = (unsigned long)buf->mem;
-done:
-   mutex_unlock(&queue->mutex);
-   return ret;
-}
-#endif
-
 /*
  * Enable or disable the video buffers queue.
  *
diff --git a/drivers/media/video/uvc/uvc_v4l2.c 
b/drivers/media/video/uvc/uvc_v4l2.c
index 2ae4f88..506d3d6 100644
--- a/drivers/media/video/uvc/uvc_v4l2.c
+++ b/drivers/media/video/uvc/uvc_v4l2.c
@@ -1067,7 +1067,7 @@ static unsigned long uvc_v4l2_get_unmapped_area(struct 
file *file,
 
uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_get_unmapped_area\n");
 
-   return uvc_queue_get_unmapped_area(&stream->queue, pgoff);
+   return vb2_get_unmapped_area(&stream->queue, addr, len, pgoff, flags);
 }
 #endif
 
-- 
1.6.3.3


--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 1/2] V4L/DVB: v4l2-dev: revert commit c29fcff3daafbf46d64a543c1950bbd206ad8c1c

2011-05-06 Thread Bob Liu
On Fri, May 6, 2011 at 4:22 PM, Laurent Pinchart
 wrote:
> Hi Bob,
>
> On Friday 29 April 2011 12:11:34 Bob Liu wrote:
>> Revert commit:
>> V4L/DVB: v4l2-dev: remove get_unmapped_area(c29fcff3daafbf46d64a543c1950bb)
>> to restore NOMMU arch supporting.
>>
>> Signed-off-by: Bob Liu 
>
> git provides a 'git revert' command to revert patches. It formats the commit

Sorry, I haven't use 'git revert' before.

> message in a standard way. I'll use it instead of applying this patch to my
> tree and I'll keep your SoB line (unless you object to that).
>

Okay, Thanks a lot.

>> ---
>>  drivers/media/video/v4l2-dev.c |   18 ++
>>  include/media/v4l2-dev.h       |    2 ++
>>  2 files changed, 20 insertions(+), 0 deletions(-)
>>
>> diff --git a/drivers/media/video/v4l2-dev.c
>> b/drivers/media/video/v4l2-dev.c index 6dc7196..19d5ae2 100644
>> --- a/drivers/media/video/v4l2-dev.c
>> +++ b/drivers/media/video/v4l2-dev.c
>> @@ -352,6 +352,23 @@ static long v4l2_ioctl(struct file *filp, unsigned int
>> cmd, unsigned long arg) return ret;
>>  }
>>
>> +#ifdef CONFIG_MMU
>> +#define v4l2_get_unmapped_area NULL
>> +#else
>> +static unsigned long v4l2_get_unmapped_area(struct file *filp,
>> +             unsigned long addr, unsigned long len, unsigned long pgoff,
>> +             unsigned long flags)
>> +{
>> +     struct video_device *vdev = video_devdata(filp);
>> +
>> +     if (!vdev->fops->get_unmapped_area)
>> +             return -ENOSYS;
>> +     if (!video_is_registered(vdev))
>> +             return -ENODEV;
>> +     return vdev->fops->get_unmapped_area(filp, addr, len, pgoff, flags);
>> +}
>> +#endif
>> +
>>  static int v4l2_mmap(struct file *filp, struct vm_area_struct *vm)
>>  {
>>       struct video_device *vdev = video_devdata(filp);
>> @@ -454,6 +471,7 @@ static const struct file_operations v4l2_fops = {
>>       .read = v4l2_read,
>>       .write = v4l2_write,
>>       .open = v4l2_open,
>> +     .get_unmapped_area = v4l2_get_unmapped_area,
>>       .mmap = v4l2_mmap,
>>       .unlocked_ioctl = v4l2_ioctl,
>>  #ifdef CONFIG_COMPAT
>> diff --git a/include/media/v4l2-dev.h b/include/media/v4l2-dev.h
>> index 8266d5a..93e96fb 100644
>> --- a/include/media/v4l2-dev.h
>> +++ b/include/media/v4l2-dev.h
>> @@ -62,6 +62,8 @@ struct v4l2_file_operations {
>>       unsigned int (*poll) (struct file *, struct poll_table_struct *);
>>       long (*ioctl) (struct file *, unsigned int, unsigned long);
>>       long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
>> +     unsigned long (*get_unmapped_area) (struct file *, unsigned long,
>> +                             unsigned long, unsigned long, unsigned long);
>>       int (*mmap) (struct file *, struct vm_area_struct *);
>>       int (*open) (struct file *);
>>       int (*release) (struct file *);
>
> --
> Regards,
>
> Laurent Pinchart
>

-- 
Regards,
--Bob
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 1/2] V4L/DVB: v4l2-dev: revert commit c29fcff3daafbf46d64a543c1950bbd206ad8c1c

2011-04-29 Thread Bob Liu
Revert commit:
V4L/DVB: v4l2-dev: remove get_unmapped_area(c29fcff3daafbf46d64a543c1950bb)
to restore NOMMU arch supporting.

Signed-off-by: Bob Liu 
---
 drivers/media/video/v4l2-dev.c |   18 ++
 include/media/v4l2-dev.h   |2 ++
 2 files changed, 20 insertions(+), 0 deletions(-)

diff --git a/drivers/media/video/v4l2-dev.c b/drivers/media/video/v4l2-dev.c
index 6dc7196..19d5ae2 100644
--- a/drivers/media/video/v4l2-dev.c
+++ b/drivers/media/video/v4l2-dev.c
@@ -352,6 +352,23 @@ static long v4l2_ioctl(struct file *filp, unsigned int 
cmd, unsigned long arg)
return ret;
 }
 
+#ifdef CONFIG_MMU
+#define v4l2_get_unmapped_area NULL
+#else
+static unsigned long v4l2_get_unmapped_area(struct file *filp,
+   unsigned long addr, unsigned long len, unsigned long pgoff,
+   unsigned long flags)
+{
+   struct video_device *vdev = video_devdata(filp);
+
+   if (!vdev->fops->get_unmapped_area)
+   return -ENOSYS;
+   if (!video_is_registered(vdev))
+   return -ENODEV;
+   return vdev->fops->get_unmapped_area(filp, addr, len, pgoff, flags);
+}
+#endif
+
 static int v4l2_mmap(struct file *filp, struct vm_area_struct *vm)
 {
struct video_device *vdev = video_devdata(filp);
@@ -454,6 +471,7 @@ static const struct file_operations v4l2_fops = {
.read = v4l2_read,
.write = v4l2_write,
.open = v4l2_open,
+   .get_unmapped_area = v4l2_get_unmapped_area,
.mmap = v4l2_mmap,
.unlocked_ioctl = v4l2_ioctl,
 #ifdef CONFIG_COMPAT
diff --git a/include/media/v4l2-dev.h b/include/media/v4l2-dev.h
index 8266d5a..93e96fb 100644
--- a/include/media/v4l2-dev.h
+++ b/include/media/v4l2-dev.h
@@ -62,6 +62,8 @@ struct v4l2_file_operations {
unsigned int (*poll) (struct file *, struct poll_table_struct *);
long (*ioctl) (struct file *, unsigned int, unsigned long);
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
+   unsigned long (*get_unmapped_area) (struct file *, unsigned long,
+   unsigned long, unsigned long, unsigned long);
int (*mmap) (struct file *, struct vm_area_struct *);
int (*open) (struct file *);
int (*release) (struct file *);
-- 
1.6.3.3


--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 2/2] media:uvc_driver: Add support for NOMMU arch

2011-04-29 Thread Bob Liu
Add support to uvc driver for NOMMU arch including add function
uvc_queue_get_unmapped_area() and make some changes in uvc_queue_mmap().
So that uvc camera can be used on nommu arch like blackfin.

Signed-off-by: Bob Liu 
---
 drivers/media/video/uvc/uvc_queue.c |   34 +-
 drivers/media/video/uvc/uvc_v4l2.c  |   17 +
 drivers/media/video/uvc/uvcvideo.h  |4 
 3 files changed, 54 insertions(+), 1 deletions(-)

diff --git a/drivers/media/video/uvc/uvc_queue.c 
b/drivers/media/video/uvc/uvc_queue.c
index f14581b..109a063 100644
--- a/drivers/media/video/uvc/uvc_queue.c
+++ b/drivers/media/video/uvc/uvc_queue.c
@@ -424,7 +424,7 @@ int uvc_queue_mmap(struct uvc_video_queue *queue, struct 
vm_area_struct *vma)
break;
}
 
-   if (i == queue->count || size != queue->buf_size) {
+   if (i == queue->count || PAGE_ALIGN(size) != queue->buf_size) {
ret = -EINVAL;
goto done;
}
@@ -436,6 +436,7 @@ int uvc_queue_mmap(struct uvc_video_queue *queue, struct 
vm_area_struct *vma)
vma->vm_flags |= VM_IO;
 
addr = (unsigned long)queue->mem + buffer->buf.m.offset;
+#ifdef CONFIG_MMU
while (size > 0) {
page = vmalloc_to_page((void *)addr);
if ((ret = vm_insert_page(vma, start, page)) < 0)
@@ -445,6 +446,7 @@ int uvc_queue_mmap(struct uvc_video_queue *queue, struct 
vm_area_struct *vma)
addr += PAGE_SIZE;
size -= PAGE_SIZE;
}
+#endif
 
vma->vm_ops = &uvc_vm_ops;
vma->vm_private_data = buffer;
@@ -488,6 +490,36 @@ done:
return mask;
 }
 
+#ifndef CONFIG_MMU
+/*
+ * Get unmapped area.
+ *
+ * NO-MMU arch need this function to make mmap() work correctly.
+ */
+unsigned long uvc_queue_get_unmapped_area(struct uvc_video_queue *queue,
+   unsigned long pgoff)
+{
+   struct uvc_buffer *buffer;
+   unsigned int i;
+   unsigned long ret;
+
+   mutex_lock(&queue->mutex);
+   for (i = 0; i < queue->count; ++i) {
+   buffer = &queue->buffer[i];
+   if ((buffer->buf.m.offset >> PAGE_SHIFT) == pgoff)
+   break;
+   }
+   if (i == queue->count) {
+   ret = -EINVAL;
+   goto done;
+   }
+   ret = (unsigned long)queue->mem + buffer->buf.m.offset;
+done:
+   mutex_unlock(&queue->mutex);
+   return ret;
+}
+#endif
+
 /*
  * Enable or disable the video buffers queue.
  *
diff --git a/drivers/media/video/uvc/uvc_v4l2.c 
b/drivers/media/video/uvc/uvc_v4l2.c
index 9005a8d..d0da5d0 100644
--- a/drivers/media/video/uvc/uvc_v4l2.c
+++ b/drivers/media/video/uvc/uvc_v4l2.c
@@ -1081,6 +1081,20 @@ static unsigned int uvc_v4l2_poll(struct file *file, 
poll_table *wait)
return uvc_queue_poll(&stream->queue, file, wait);
 }
 
+#ifndef CONFIG_MMU
+static unsigned long uvc_v4l2_get_unmapped_area(struct file *file,
+   unsigned long addr, unsigned long len, unsigned long pgoff,
+   unsigned long flags)
+{
+   struct uvc_fh *handle = file->private_data;
+   struct uvc_streaming *stream = handle->stream;
+
+   uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_get_unmapped_area\n");
+
+   return uvc_queue_get_unmapped_area(&stream->queue, pgoff);
+}
+#endif
+
 const struct v4l2_file_operations uvc_fops = {
.owner  = THIS_MODULE,
.open   = uvc_v4l2_open,
@@ -1089,5 +1103,8 @@ const struct v4l2_file_operations uvc_fops = {
.read   = uvc_v4l2_read,
.mmap   = uvc_v4l2_mmap,
.poll   = uvc_v4l2_poll,
+#ifndef CONFIG_MMU
+   .get_unmapped_area = uvc_v4l2_get_unmapped_area,
+#endif
 };
 
diff --git a/drivers/media/video/uvc/uvcvideo.h 
b/drivers/media/video/uvc/uvcvideo.h
index 45f01e7..6aa63c0 100644
--- a/drivers/media/video/uvc/uvcvideo.h
+++ b/drivers/media/video/uvc/uvcvideo.h
@@ -580,6 +580,10 @@ extern int uvc_queue_mmap(struct uvc_video_queue *queue,
struct vm_area_struct *vma);
 extern unsigned int uvc_queue_poll(struct uvc_video_queue *queue,
struct file *file, poll_table *wait);
+#ifndef CONFIG_MMU
+extern unsigned long uvc_queue_get_unmapped_area(struct uvc_video_queue *queue,
+   unsigned long pgoff);
+#endif
 extern int uvc_queue_allocated(struct uvc_video_queue *queue);
 static inline int uvc_queue_streaming(struct uvc_video_queue *queue)
 {
-- 
1.6.3.3


--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v4] media:uvc_driver: add uvc support on no-mmu arch

2011-04-22 Thread Bob Liu
UVC driver used to have partial no-mmu arch support, but it's removed by
commit c29fcff3daafbf46d64a543c1950bbd206ad8c1c.

This patch added them back and expanded to fully support no-mmu arch, so that
uvc cameras can be used on no-mmu platforms like Blackfin.

Signed-off-by: Bob Liu 
---
 drivers/media/video/uvc/uvc_queue.c |   26 +-
 drivers/media/video/uvc/uvc_v4l2.c  |   13 +
 drivers/media/video/uvc/uvcvideo.h  |6 ++
 drivers/media/video/v4l2-dev.c  |   18 ++
 include/media/v4l2-dev.h|2 ++
 5 files changed, 64 insertions(+), 1 deletions(-)

diff --git a/drivers/media/video/uvc/uvc_queue.c 
b/drivers/media/video/uvc/uvc_queue.c
index f14581b..caf8f6f 100644
--- a/drivers/media/video/uvc/uvc_queue.c
+++ b/drivers/media/video/uvc/uvc_queue.c
@@ -424,7 +424,7 @@ int uvc_queue_mmap(struct uvc_video_queue *queue, struct 
vm_area_struct *vma)
break;
}
 
-   if (i == queue->count || size != queue->buf_size) {
+   if (i == queue->count || PAGE_ALIGN(size) != queue->buf_size) {
ret = -EINVAL;
goto done;
}
@@ -436,6 +436,7 @@ int uvc_queue_mmap(struct uvc_video_queue *queue, struct 
vm_area_struct *vma)
vma->vm_flags |= VM_IO;
 
addr = (unsigned long)queue->mem + buffer->buf.m.offset;
+#ifdef CONFIG_MMU
while (size > 0) {
page = vmalloc_to_page((void *)addr);
if ((ret = vm_insert_page(vma, start, page)) < 0)
@@ -445,6 +446,7 @@ int uvc_queue_mmap(struct uvc_video_queue *queue, struct 
vm_area_struct *vma)
addr += PAGE_SIZE;
size -= PAGE_SIZE;
}
+#endif
 
vma->vm_ops = &uvc_vm_ops;
vma->vm_private_data = buffer;
@@ -489,6 +491,28 @@ done:
 }
 
 /*
+ * Get unmapped area.
+ *
+ * NO-MMU arch need this function to make mmap() work correctly.
+ */
+unsigned long uvc_queue_get_unmapped_area(struct uvc_video_queue *queue,
+   unsigned long addr, unsigned long len, unsigned long pgoff)
+{
+   struct uvc_buffer *buffer;
+   unsigned int i;
+
+   mutex_lock(&queue->mutex);
+   for (i = 0; i < queue->count; ++i) {
+   buffer = &queue->buffer[i];
+   if ((buffer->buf.m.offset >> PAGE_SHIFT) == pgoff)
+   break;
+   }
+   addr = (unsigned long)queue->mem + buffer->buf.m.offset;
+   mutex_unlock(&queue->mutex);
+   return addr;
+}
+
+/*
  * Enable or disable the video buffers queue.
  *
  * The queue must be enabled before starting video acquisition and must be
diff --git a/drivers/media/video/uvc/uvc_v4l2.c 
b/drivers/media/video/uvc/uvc_v4l2.c
index 9005a8d..9efab61 100644
--- a/drivers/media/video/uvc/uvc_v4l2.c
+++ b/drivers/media/video/uvc/uvc_v4l2.c
@@ -1081,6 +1081,18 @@ static unsigned int uvc_v4l2_poll(struct file *file, 
poll_table *wait)
return uvc_queue_poll(&stream->queue, file, wait);
 }
 
+static unsigned long uvc_v4l2_get_unmapped_area(struct file *file,
+   unsigned long addr, unsigned long len, unsigned long pgoff,
+   unsigned long flags)
+{
+   struct uvc_fh *handle = file->private_data;
+   struct uvc_streaming *stream = handle->stream;
+
+   uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_get_unmapped_area\n");
+
+   return uvc_queue_get_unmapped_area(&stream->queue, addr, len, pgoff);
+}
+
 const struct v4l2_file_operations uvc_fops = {
.owner  = THIS_MODULE,
.open   = uvc_v4l2_open,
@@ -1089,5 +1101,6 @@ const struct v4l2_file_operations uvc_fops = {
.read   = uvc_v4l2_read,
.mmap   = uvc_v4l2_mmap,
.poll   = uvc_v4l2_poll,
+   .get_unmapped_area = uvc_v4l2_get_unmapped_area,
 };
 
diff --git a/drivers/media/video/uvc/uvcvideo.h 
b/drivers/media/video/uvc/uvcvideo.h
index 45f01e7..48a2378 100644
--- a/drivers/media/video/uvc/uvcvideo.h
+++ b/drivers/media/video/uvc/uvcvideo.h
@@ -580,6 +580,12 @@ extern int uvc_queue_mmap(struct uvc_video_queue *queue,
struct vm_area_struct *vma);
 extern unsigned int uvc_queue_poll(struct uvc_video_queue *queue,
struct file *file, poll_table *wait);
+#ifdef CONFIG_MMU
+#define uvc_queue_get_unmapped_area NULL
+#else
+extern unsigned long uvc_queue_get_unmapped_area(struct uvc_video_queue *queue,
+   unsigned long addr, unsigned long len, unsigned long pgoff);
+#endif
 extern int uvc_queue_allocated(struct uvc_video_queue *queue);
 static inline int uvc_queue_streaming(struct uvc_video_queue *queue)
 {
diff --git a/drivers/media/video/v4l2-dev.c b/drivers/media/video/v4l2-dev.c
index 498e674..221e73f 100644
--- a/drivers/media/video/v4l2-dev.c
+++ b/drivers/media/video/v4l2-dev.c
@@ -368,6 +368,23 @@ static int v4l2_mmap(struct file *filp, s

Re: [PATCH v3] media:uvc_driver: add uvc support on no-mmu arch

2011-04-21 Thread Bob Liu
On Thu, Apr 21, 2011 at 5:47 PM, Daniel Glöckner  wrote:
> On Thu, Apr 21, 2011 at 04:20:36PM +0800, Bob Liu wrote:
>> > on mmu systems do_mmap_pgoff contains a len = PAGE_ALIGN(len); line.
>> > If we depend on this behavior, why not do it here as well and get rid
>> > of the #ifdef?
>> >
>>
>> If do it in do_mmap_pgoff() the whole system will be effected, I am
>> not sure whether
>> it's correct and needed for other subsystem.
>
> With "here" I was referring to uvc_queue_mmap.
>

I am sorry, I didn't get your idea. You mean using  PAGE_ALIGN() here for both
mmu and no-mmu arch ?

>> >> +     addr = (unsigned long)queue->mem + buffer->buf.m.offset;
>> >> +     ret = addr;
>> >
>> > Why the intermediate step using addr?
>> >
>>
>> If don't return addr, do_mmap_pgoff() will return failure and we can't
>> setup vma correctly.
>> See mm/nommu.c line 1386(add = file->f_op->get_unmmapped_area() ).
>
> I know, but why not do
>        ret = (unsigned long)queue->mem + buffer->buf.m.offset;
> instead?
>

Okay.
Thanks

-- 
Regards,
--Bob
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH v3] media:uvc_driver: add uvc support on no-mmu arch

2011-04-21 Thread Bob Liu
On Thu, Apr 21, 2011 at 3:59 PM, Daniel Glöckner  wrote:
> Hi Bob,
>
> On Thu, Apr 21, 2011 at 11:17:42AM +0800, Bob Liu wrote:
>> +#ifdef CONFIG_MMU
>>       if (i == queue->count || size != queue->buf_size) {
>> +#else
>> +     if (i == queue->count || PAGE_ALIGN(size) != queue->buf_size) {
>> +#endif
>
> on mmu systems do_mmap_pgoff contains a len = PAGE_ALIGN(len); line.
> If we depend on this behavior, why not do it here as well and get rid
> of the #ifdef?
>

If do it in do_mmap_pgoff() the whole system will be effected, I am
not sure whether
it's correct and needed for other subsystem.

>> +unsigned long uvc_queue_get_unmapped_area(struct uvc_video_queue *queue,
>> +             unsigned long addr, unsigned long len, unsigned long pgoff)
>> +{
>> +     struct uvc_buffer *buffer;
>> +     unsigned int i;
>> +     int ret = 0;
>
> You still didn't change ret to unsigned long.
>

Oh, Sorry. My fault.

>> +     addr = (unsigned long)queue->mem + buffer->buf.m.offset;
>> +     ret = addr;
>
> Why the intermediate step using addr?
>

If don't return addr, do_mmap_pgoff() will return failure and we can't
setup vma correctly.
See mm/nommu.c line 1386(add = file->f_op->get_unmmapped_area() ).

>> diff --git a/drivers/media/video/v4l2-dev.c b/drivers/media/video/v4l2-dev.c
>> index 498e674..221e73f 100644
>> --- a/drivers/media/video/v4l2-dev.c
>> +++ b/drivers/media/video/v4l2-dev.c
>> @@ -368,6 +368,23 @@ static int v4l2_mmap(struct file *filp, struct 
>> vm_area_struct *vm)
>>       return ret;
>>  }
>>
>> +#ifdef CONFIG_MMU
>> +#define v4l2_get_unmapped_area NULL
>> +#else
>> +static unsigned long v4l2_get_unmapped_area(struct file *filp,
>> +             unsigned long addr, unsigned long len, unsigned long pgoff,
>> +             unsigned long flags)
>> +{
>> +     struct video_device *vdev = video_devdata(filp);
>> +
>> +     if (!vdev->fops->get_unmapped_area)
>> +             return -ENOSYS;
>> +     if (!video_is_registered(vdev))
>> +             return -ENODEV;
>> +     return vdev->fops->get_unmapped_area(filp, addr, len, pgoff, flags);
>> +}
>> +#endif
>> +
>>  /* Override for the open function */
>>  static int v4l2_open(struct inode *inode, struct file *filp)
>>  {
>> @@ -452,6 +469,7 @@ static const struct file_operations v4l2_fops = {
>>       .write = v4l2_write,
>>       .open = v4l2_open,
>>       .mmap = v4l2_mmap,
>> +     .get_unmapped_area = v4l2_get_unmapped_area,
>>       .unlocked_ioctl = v4l2_ioctl,
>>  #ifdef CONFIG_COMPAT
>>       .compat_ioctl = v4l2_compat_ioctl32,
>> diff --git a/include/media/v4l2-dev.h b/include/media/v4l2-dev.h
>> index 8266d5a..0616a43 100644
>> --- a/include/media/v4l2-dev.h
>> +++ b/include/media/v4l2-dev.h
>> @@ -63,6 +63,8 @@ struct v4l2_file_operations {
>>       long (*ioctl) (struct file *, unsigned int, unsigned long);
>>       long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
>>       int (*mmap) (struct file *, struct vm_area_struct *);
>> +     unsigned long (*get_unmapped_area) (struct file *, unsigned long,
>> +                     unsigned long, unsigned long, unsigned long);
>>       int (*open) (struct file *);
>>       int (*release) (struct file *);
>>  };
>
> I'd prefer a git revert c29fcff3daafbf46d64a543c1950bbd206ad8c1c for
> this block instead of reverting it together with the UVC changes.
>

Okay, I will confirm that and do it.

Thanks a lot for your review.

-- 
Regards,
--Bob
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v3] media:uvc_driver: add uvc support on no-mmu arch

2011-04-20 Thread Bob Liu
UVC driver used to have partial no-mmu arch support, but it's removed by
commit c29fcff3daafbf46d64a543c1950bbd206ad8c1c.

This patch added them back and expanded to fully support no-mmu arch, so that
uvc cameras can be used on no-mmu platforms like Blackfin.

Signed-off-by: Bob Liu 
---
 drivers/media/video/uvc/uvc_queue.c |   30 ++
 drivers/media/video/uvc/uvc_v4l2.c  |   13 +
 drivers/media/video/uvc/uvcvideo.h  |6 ++
 drivers/media/video/v4l2-dev.c  |   18 ++
 include/media/v4l2-dev.h|2 ++
 5 files changed, 69 insertions(+), 0 deletions(-)

diff --git a/drivers/media/video/uvc/uvc_queue.c 
b/drivers/media/video/uvc/uvc_queue.c
index f14581b..448a753 100644
--- a/drivers/media/video/uvc/uvc_queue.c
+++ b/drivers/media/video/uvc/uvc_queue.c
@@ -424,7 +424,11 @@ int uvc_queue_mmap(struct uvc_video_queue *queue, struct 
vm_area_struct *vma)
break;
}
 
+#ifdef CONFIG_MMU
if (i == queue->count || size != queue->buf_size) {
+#else
+   if (i == queue->count || PAGE_ALIGN(size) != queue->buf_size) {
+#endif
ret = -EINVAL;
goto done;
}
@@ -436,6 +440,7 @@ int uvc_queue_mmap(struct uvc_video_queue *queue, struct 
vm_area_struct *vma)
vma->vm_flags |= VM_IO;
 
addr = (unsigned long)queue->mem + buffer->buf.m.offset;
+#ifdef CONFIG_MMU
while (size > 0) {
page = vmalloc_to_page((void *)addr);
if ((ret = vm_insert_page(vma, start, page)) < 0)
@@ -445,6 +450,7 @@ int uvc_queue_mmap(struct uvc_video_queue *queue, struct 
vm_area_struct *vma)
addr += PAGE_SIZE;
size -= PAGE_SIZE;
}
+#endif
 
vma->vm_ops = &uvc_vm_ops;
vma->vm_private_data = buffer;
@@ -489,6 +495,30 @@ done:
 }
 
 /*
+ * Get unmapped area.
+ *
+ * NO-MMU arch need this function to make mmap() work correctly.
+ */
+unsigned long uvc_queue_get_unmapped_area(struct uvc_video_queue *queue,
+   unsigned long addr, unsigned long len, unsigned long pgoff)
+{
+   struct uvc_buffer *buffer;
+   unsigned int i;
+   int ret = 0;
+
+   mutex_lock(&queue->mutex);
+   for (i = 0; i < queue->count; ++i) {
+   buffer = &queue->buffer[i];
+   if ((buffer->buf.m.offset >> PAGE_SHIFT) == pgoff)
+   break;
+   }
+   addr = (unsigned long)queue->mem + buffer->buf.m.offset;
+   ret = addr;
+   mutex_unlock(&queue->mutex);
+   return ret;
+}
+
+/*
  * Enable or disable the video buffers queue.
  *
  * The queue must be enabled before starting video acquisition and must be
diff --git a/drivers/media/video/uvc/uvc_v4l2.c 
b/drivers/media/video/uvc/uvc_v4l2.c
index 9005a8d..9efab61 100644
--- a/drivers/media/video/uvc/uvc_v4l2.c
+++ b/drivers/media/video/uvc/uvc_v4l2.c
@@ -1081,6 +1081,18 @@ static unsigned int uvc_v4l2_poll(struct file *file, 
poll_table *wait)
return uvc_queue_poll(&stream->queue, file, wait);
 }
 
+static unsigned long uvc_v4l2_get_unmapped_area(struct file *file,
+   unsigned long addr, unsigned long len, unsigned long pgoff,
+   unsigned long flags)
+{
+   struct uvc_fh *handle = file->private_data;
+   struct uvc_streaming *stream = handle->stream;
+
+   uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_get_unmapped_area\n");
+
+   return uvc_queue_get_unmapped_area(&stream->queue, addr, len, pgoff);
+}
+
 const struct v4l2_file_operations uvc_fops = {
.owner  = THIS_MODULE,
.open   = uvc_v4l2_open,
@@ -1089,5 +1101,6 @@ const struct v4l2_file_operations uvc_fops = {
.read   = uvc_v4l2_read,
.mmap   = uvc_v4l2_mmap,
.poll   = uvc_v4l2_poll,
+   .get_unmapped_area = uvc_v4l2_get_unmapped_area,
 };
 
diff --git a/drivers/media/video/uvc/uvcvideo.h 
b/drivers/media/video/uvc/uvcvideo.h
index 45f01e7..48a2378 100644
--- a/drivers/media/video/uvc/uvcvideo.h
+++ b/drivers/media/video/uvc/uvcvideo.h
@@ -580,6 +580,12 @@ extern int uvc_queue_mmap(struct uvc_video_queue *queue,
struct vm_area_struct *vma);
 extern unsigned int uvc_queue_poll(struct uvc_video_queue *queue,
struct file *file, poll_table *wait);
+#ifdef CONFIG_MMU
+#define uvc_queue_get_unmapped_area NULL
+#else
+extern unsigned long uvc_queue_get_unmapped_area(struct uvc_video_queue *queue,
+   unsigned long addr, unsigned long len, unsigned long pgoff);
+#endif
 extern int uvc_queue_allocated(struct uvc_video_queue *queue);
 static inline int uvc_queue_streaming(struct uvc_video_queue *queue)
 {
diff --git a/drivers/media/video/v4l2-dev.c b/drivers/media/video/v4l2-dev.c
index 498e674..221e73f 100644
--- a/drivers/media/video/v4l2-dev.c
+++ b/driv

Re: Fwd: [PATCH v2] media: uvc_driver: add NO-MMU arch support

2011-04-20 Thread Bob Liu
On Wed, Apr 20, 2011 at 4:59 PM, Daniel Glöckner  wrote:
> On Wed, Apr 20, 2011 at 02:02:41PM +0800, Bob Liu wrote:
>> -- Forwarded message --
>
> Forwarding broke tabs.
>

Hi, Daniel
Thanks for your review, I will make a new patch later.

>> @@ -445,6 +446,20 @@ int uvc_queue_mmap(struct uvc_video_queue *queue,
>> struct vm_area_struct *vma)
>>                addr += PAGE_SIZE;
>>                size -= PAGE_SIZE;
>>        }
>> +#else
>> +       if (i == queue->count ||
>> +                       PAGE_ALIGN(size) != queue->buf_size) {
>
> Why do you need to round up size on nommu?
>

If didn't round up, it always return  -EINVAL.
I don't know why config-mmu doesn't have this problem.

I use luvcview for testing and added some print, you can see that size
always != queue->buf_size.
So we need round up.

root:/> luvcview -f yuv -s 320x240 -i 30
luvcview 0.2.4

SDL information:
  Video driver: fbcon
  Hardware surfaces are available (382k video memory)
Device information:
  Device path:  /dev/video0
Stream settings:
  Frame format: YUYV
  Frame size:   320x240
  Fsaiz e tis  03x2f5800, align size is 0x26000, bufsize is 0x26000

size is 0x25800, align size is 0x26000, bufsize is 0x26000
Unable to map buffer: Invalid argument
 Init v4L2 failed !! exit fatal
root:/>

>> +               ret = -EINVAL;
>> +               goto done;
>> +       }
>> +
>> +       /* documentation/nommu-mmap.txt */
>
> I don't see where Documentation/nommu-mmap.txt provides any information
> on the following line(s).
>

I will rm it, sorry for that.

>> +       vma->vm_flags |= VM_IO | VM_MAYSHARE;
>> +
>> +       addr = (unsigned long)queue->mem + buffer->buf.m.offset;
>> +       vma->vm_start = addr;
>> +       vma->vm_end = addr +  queue->buf_size;
>
> You don't need to do this here. vm_start and vm_end have already been
> modified like this by do_mmap_pgoff after get_unmapped_area had been
> called.
>

will rm also.

>> +#endif
>>
>>        vma->vm_ops = &uvc_vm_ops;
>>        vma->vm_private_data = buffer;
>> @@ -489,6 +504,38 @@ done:
>>  }
>>
>>  /*
>> + * Get unmapped area.
>> + *
>> + * NO-MMU arch need this function to make mmap() work correctly.
>> + */
>> +unsigned long uvc_queue_get_unmapped_area(struct uvc_video_queue *queue,
>> +               unsigned long addr, unsigned long len, unsigned long pgoff)
>> +{
>> +       struct uvc_buffer *buffer;
>> +       unsigned int i;
>> +       int ret = 0;
>
> ret should be an unsigned long. You later try to store a pointer in
> there.
>

okay.

>> +
>> +       mutex_lock(&queue->mutex);
>> +       for (i = 0; i < queue->count; ++i) {
>> +               buffer = &queue->buffer[i];
>> +               if ((buffer->buf.m.offset >> PAGE_SHIFT) == pgoff)
>> +                       break;
>> +       }
>> +
>> +       if (i == queue->count ||
>> +                       PAGE_ALIGN(len) != queue->buf_size) {
>> +               ret = -EINVAL;
>> +               goto done;
>> +       }
>> +
>> +       addr = (unsigned long)queue->mem + buffer->buf.m.offset;
>> +       ret = addr;
>> +done:
>> +       mutex_unlock(&queue->mutex);
>> +       return ret;
>> +}
>> +
>> +/*
>>  * Enable or disable the video buffers queue.
>>  *
>>  * The queue must be enabled before starting video acquisition and must be
>> diff --git a/drivers/media/video/uvc/uvc_v4l2.c
>> b/drivers/media/video/uvc/uvc_v4l2.c
>> index 9005a8d..9efab61 100644
>> --- a/drivers/media/video/uvc/uvc_v4l2.c
>> +++ b/drivers/media/video/uvc/uvc_v4l2.c
>> @@ -1081,6 +1081,18 @@ static unsigned int uvc_v4l2_poll(struct file
>> *file, poll_table *wait)
>>        return uvc_queue_poll(&stream->queue, file, wait);
>>  }
>>
>> +static unsigned long uvc_v4l2_get_unmapped_area(struct file *file,
>> +               unsigned long addr, unsigned long len, unsigned long pgoff,
>> +               unsigned long flags)
>> +{
>> +       struct uvc_fh *handle = file->private_data;
>> +       struct uvc_streaming *stream = handle->stream;
>> +
>> +       uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_get_unmapped_area\n");
>> +
>> +       return uvc_queue_get_unmapped_area(&stream->queue, addr, len, pgoff);
>> +}
>> +
>>  const struct v4l2_file_operations uvc_fops = {
>>        .owner          = THIS_MODULE,
>>        .open     

Fwd: [PATCH v2] media: uvc_driver: add NO-MMU arch support

2011-04-19 Thread Bob Liu
-- Forwarded message --
From: Bob Liu 
Date: Fri, Apr 8, 2011 at 7:16 PM
Subject: [PATCH v2] media: uvc_driver: add NO-MMU arch support
To: linux-ker...@vger.kernel.org
Cc: mche...@redhat.com, hverk...@xs4all.nl,
laurent.pinch...@ideasonboard.com,
sakari.ai...@maxwell.research.nokia.com, martin_ru...@logitech.com,
ja...@redhat.com, t...@kernel.org, a...@arndb.de, fweis...@gmail.com,
ag...@denx.de, gre...@suse.de, Bob Liu 


UVC driver used to have partial no-mmu arch support, but it's removed by
commit c29fcff3daafbf46d64a543c1950bbd206ad8c1c.

This patch added them back and expanded to fully support no-mmu arch, so that
uvc cameras can be used on no-mmu platforms like Blackfin.

Signed-off-by: Bob Liu 
---
 drivers/media/video/uvc/uvc_queue.c |   47 +++
 drivers/media/video/uvc/uvc_v4l2.c  |   13 +
 drivers/media/video/uvc/uvcvideo.h  |    6 
 drivers/media/video/v4l2-dev.c      |   18 +
 include/media/v4l2-dev.h            |    2 +
 5 files changed, 86 insertions(+), 0 deletions(-)

diff --git a/drivers/media/video/uvc/uvc_queue.c
b/drivers/media/video/uvc/uvc_queue.c
index f14581b..e505afe 100644
--- a/drivers/media/video/uvc/uvc_queue.c
+++ b/drivers/media/video/uvc/uvc_queue.c
@@ -424,6 +424,7 @@ int uvc_queue_mmap(struct uvc_video_queue *queue,
struct vm_area_struct *vma)
                       break;
       }

+#ifdef CONFIG_MMU
       if (i == queue->count || size != queue->buf_size) {
               ret = -EINVAL;
               goto done;
@@ -445,6 +446,20 @@ int uvc_queue_mmap(struct uvc_video_queue *queue,
struct vm_area_struct *vma)
               addr += PAGE_SIZE;
               size -= PAGE_SIZE;
       }
+#else
+       if (i == queue->count ||
+                       PAGE_ALIGN(size) != queue->buf_size) {
+               ret = -EINVAL;
+               goto done;
+       }
+
+       /* documentation/nommu-mmap.txt */
+       vma->vm_flags |= VM_IO | VM_MAYSHARE;
+
+       addr = (unsigned long)queue->mem + buffer->buf.m.offset;
+       vma->vm_start = addr;
+       vma->vm_end = addr +  queue->buf_size;
+#endif

       vma->vm_ops = &uvc_vm_ops;
       vma->vm_private_data = buffer;
@@ -489,6 +504,38 @@ done:
 }

 /*
+ * Get unmapped area.
+ *
+ * NO-MMU arch need this function to make mmap() work correctly.
+ */
+unsigned long uvc_queue_get_unmapped_area(struct uvc_video_queue *queue,
+               unsigned long addr, unsigned long len, unsigned long pgoff)
+{
+       struct uvc_buffer *buffer;
+       unsigned int i;
+       int ret = 0;
+
+       mutex_lock(&queue->mutex);
+       for (i = 0; i < queue->count; ++i) {
+               buffer = &queue->buffer[i];
+               if ((buffer->buf.m.offset >> PAGE_SHIFT) == pgoff)
+                       break;
+       }
+
+       if (i == queue->count ||
+                       PAGE_ALIGN(len) != queue->buf_size) {
+               ret = -EINVAL;
+               goto done;
+       }
+
+       addr = (unsigned long)queue->mem + buffer->buf.m.offset;
+       ret = addr;
+done:
+       mutex_unlock(&queue->mutex);
+       return ret;
+}
+
+/*
 * Enable or disable the video buffers queue.
 *
 * The queue must be enabled before starting video acquisition and must be
diff --git a/drivers/media/video/uvc/uvc_v4l2.c
b/drivers/media/video/uvc/uvc_v4l2.c
index 9005a8d..9efab61 100644
--- a/drivers/media/video/uvc/uvc_v4l2.c
+++ b/drivers/media/video/uvc/uvc_v4l2.c
@@ -1081,6 +1081,18 @@ static unsigned int uvc_v4l2_poll(struct file
*file, poll_table *wait)
       return uvc_queue_poll(&stream->queue, file, wait);
 }

+static unsigned long uvc_v4l2_get_unmapped_area(struct file *file,
+               unsigned long addr, unsigned long len, unsigned long pgoff,
+               unsigned long flags)
+{
+       struct uvc_fh *handle = file->private_data;
+       struct uvc_streaming *stream = handle->stream;
+
+       uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_get_unmapped_area\n");
+
+       return uvc_queue_get_unmapped_area(&stream->queue, addr, len, pgoff);
+}
+
 const struct v4l2_file_operations uvc_fops = {
       .owner          = THIS_MODULE,
       .open           = uvc_v4l2_open,
@@ -1089,5 +1101,6 @@ const struct v4l2_file_operations uvc_fops = {
       .read           = uvc_v4l2_read,
       .mmap           = uvc_v4l2_mmap,
       .poll           = uvc_v4l2_poll,
+       .get_unmapped_area = uvc_v4l2_get_unmapped_area,
 };

diff --git a/drivers/media/video/uvc/uvcvideo.h
b/drivers/media/video/uvc/uvcvideo.h
index 45f01e7..48a2378 100644
--- a/drivers/media/video/uvc/uvcvideo.h
+++ b/drivers/media/video/uvc/uvcvideo.h
@@ -580,6 +580,12 @@ extern int uvc_queue_mmap(struct uvc_video_queue *queue,
               struct vm_area_struct *vma);
 extern unsigned int uvc_queue_poll(struct uvc_video_queue *queue,
               struct file *file, poll_table *wait);
+