@@ -136,6 +136,7 @@ static int videobuf_dma_init_user_locked(struct videobuf_dmabuf *dma,
{
unsigned long first,last;
int err, rw = 0;
+ struct vm_area_struct *vma;
dma->direction = direction;
switch (dma->direction) {
@@ -153,6 +154,23 @@ static int videobuf_dma_init_user_locked(struct videobuf_dmabuf *dma,
last = ((data+size-1) & PAGE_MASK) >> PAGE_SHIFT;
dma->offset = data & ~PAGE_MASK;
dma->nr_pages = last-first+1;
+
+ /* In case the buffer is user-allocated and is actually an IO buffer for
+ some other hardware, we cannot map pages for it. It in fact behaves
+ the same as an overlay. */
+ vma = find_vma (current->mm, data);
+ if (vma && (vma->vm_flags & VM_IO)) {
+ /* Only a single contiguous buffer is supported. */
+ if (vma->vm_end < data + size) {
+ dprintk(1, "init user: non-contiguous IO buffer.\n");
+ return -EFAULT; /* same error that get_user_pages() would give */
+ }
+ dma->bus_addr = (vma->vm_pgoff << PAGE_SHIFT) + (data - vma->vm_start);
+ dprintk(1,"init user IO [0x%lx+0x%lx => %d pages at 0x%x]\n",
+ data, size, dma->nr_pages, dma->bus_addr);
+ return 0;
+ }
+
dma->pages = kmalloc(dma->nr_pages * sizeof(struct page*),
GFP_KERNEL);
if (NULL == dma->pages)