Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 241756
b: refs/heads/master
c: 004cc37
h: refs/heads/master
v: v3
  • Loading branch information
Marek Szyprowski authored and Mauro Carvalho Chehab committed Mar 21, 2011
1 parent 9e01fb9 commit c8786d5
Show file tree
Hide file tree
Showing 5 changed files with 282 additions and 1 deletion.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: e23ccc0ad9258634e6d52cedf473b35dc34416c7
refs/heads/master: 004cc3781c40a577b0349eef825efaaebc42dd43
3 changes: 3 additions & 0 deletions trunk/drivers/media/video/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ config V4L2_MEM2MEM_DEV
config VIDEOBUF2_CORE
tristate

config VIDEOBUF2_MEMOPS
tristate

#
# Multimedia Video device configuration
#
Expand Down
1 change: 1 addition & 0 deletions trunk/drivers/media/video/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ obj-$(CONFIG_VIDEOBUF_DVB) += videobuf-dvb.o
obj-$(CONFIG_VIDEO_BTCX) += btcx-risc.o

obj-$(CONFIG_VIDEOBUF2_CORE) += videobuf2-core.o
obj-$(CONFIG_VIDEOBUF2_MEMOPS) += videobuf2-memops.o

obj-$(CONFIG_V4L2_MEM2MEM_DEV) += v4l2-mem2mem.o

Expand Down
232 changes: 232 additions & 0 deletions trunk/drivers/media/video/videobuf2-memops.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,232 @@
/*
* videobuf2-memops.c - generic memory handling routines for videobuf2
*
* Copyright (C) 2010 Samsung Electronics
*
* Author: Pawel Osciak <p.osciak@samsung.com>
* Marek Szyprowski <m.szyprowski@samsung.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation.
*/

#include <linux/slab.h>
#include <linux/module.h>
#include <linux/dma-mapping.h>
#include <linux/vmalloc.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/file.h>
#include <linux/slab.h>

#include <media/videobuf2-core.h>
#include <media/videobuf2-memops.h>

/**
* vb2_get_vma() - acquire and lock the virtual memory area
* @vma: given virtual memory area
*
* This function attempts to acquire an area mapped in the userspace for
* the duration of a hardware operation. The area is "locked" by performing
* the same set of operation that are done when process calls fork() and
* memory areas are duplicated.
*
* Returns a copy of a virtual memory region on success or NULL.
*/
struct vm_area_struct *vb2_get_vma(struct vm_area_struct *vma)
{
struct vm_area_struct *vma_copy;

vma_copy = kmalloc(sizeof(*vma_copy), GFP_KERNEL);
if (vma_copy == NULL)
return NULL;

if (vma->vm_ops && vma->vm_ops->open)
vma->vm_ops->open(vma);

if (vma->vm_file)
get_file(vma->vm_file);

memcpy(vma_copy, vma, sizeof(*vma));

vma_copy->vm_mm = NULL;
vma_copy->vm_next = NULL;
vma_copy->vm_prev = NULL;

return vma_copy;
}

/**
* vb2_put_userptr() - release a userspace virtual memory area
* @vma: virtual memory region associated with the area to be released
*
* This function releases the previously acquired memory area after a hardware
* operation.
*/
void vb2_put_vma(struct vm_area_struct *vma)
{
if (!vma)
return;

if (vma->vm_file)
fput(vma->vm_file);

if (vma->vm_ops && vma->vm_ops->close)
vma->vm_ops->close(vma);

kfree(vma);
}

/**
* vb2_get_contig_userptr() - lock physically contiguous userspace mapped memory
* @vaddr: starting virtual address of the area to be verified
* @size: size of the area
* @res_paddr: will return physical address for the given vaddr
* @res_vma: will return locked copy of struct vm_area for the given area
*
* This function will go through memory area of size @size mapped at @vaddr and
* verify that the underlying physical pages are contiguous. If they are
* contiguous the virtual memory area is locked and a @res_vma is filled with
* the copy and @res_pa set to the physical address of the buffer.
*
* Returns 0 on success.
*/
int vb2_get_contig_userptr(unsigned long vaddr, unsigned long size,
struct vm_area_struct **res_vma, dma_addr_t *res_pa)
{
struct mm_struct *mm = current->mm;
struct vm_area_struct *vma;
unsigned long offset, start, end;
unsigned long this_pfn, prev_pfn;
dma_addr_t pa = 0;
int ret = -EFAULT;

start = vaddr;
offset = start & ~PAGE_MASK;
end = start + size;

down_read(&mm->mmap_sem);
vma = find_vma(mm, start);

if (vma == NULL || vma->vm_end < end)
goto done;

for (prev_pfn = 0; start < end; start += PAGE_SIZE) {
ret = follow_pfn(vma, start, &this_pfn);
if (ret)
goto done;

if (prev_pfn == 0)
pa = this_pfn << PAGE_SHIFT;
else if (this_pfn != prev_pfn + 1) {
ret = -EFAULT;
goto done;
}
prev_pfn = this_pfn;
}

/*
* Memory is contigous, lock vma and return to the caller
*/
*res_vma = vb2_get_vma(vma);
if (*res_vma == NULL) {
ret = -ENOMEM;
goto done;
}
*res_pa = pa + offset;
ret = 0;

done:
up_read(&mm->mmap_sem);
return ret;
}

/**
* vb2_mmap_pfn_range() - map physical pages to userspace
* @vma: virtual memory region for the mapping
* @paddr: starting physical address of the memory to be mapped
* @size: size of the memory to be mapped
* @vm_ops: vm operations to be assigned to the created area
* @priv: private data to be associated with the area
*
* Returns 0 on success.
*/
int vb2_mmap_pfn_range(struct vm_area_struct *vma, unsigned long paddr,
unsigned long size,
const struct vm_operations_struct *vm_ops,
void *priv)
{
int ret;

size = min_t(unsigned long, vma->vm_end - vma->vm_start, size);

vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
ret = remap_pfn_range(vma, vma->vm_start, paddr >> PAGE_SHIFT,
size, vma->vm_page_prot);
if (ret) {
printk(KERN_ERR "Remapping memory failed, error: %d\n", ret);
return ret;
}

vma->vm_flags |= VM_DONTEXPAND | VM_RESERVED;
vma->vm_private_data = priv;
vma->vm_ops = vm_ops;

vma->vm_ops->open(vma);

printk(KERN_DEBUG "%s: mapped paddr 0x%08lx at 0x%08lx, size %ld\n",
__func__, paddr, vma->vm_start, size);

return 0;
}

/**
* vb2_common_vm_open() - increase refcount of the vma
* @vma: virtual memory region for the mapping
*
* This function adds another user to the provided vma. It expects
* struct vb2_vmarea_handler pointer in vma->vm_private_data.
*/
static void vb2_common_vm_open(struct vm_area_struct *vma)
{
struct vb2_vmarea_handler *h = vma->vm_private_data;

printk(KERN_DEBUG "%s: %p, refcount: %d, vma: %08lx-%08lx\n",
__func__, h, atomic_read(h->refcount), vma->vm_start,
vma->vm_end);

atomic_inc(h->refcount);
}

/**
* vb2_common_vm_close() - decrease refcount of the vma
* @vma: virtual memory region for the mapping
*
* This function releases the user from the provided vma. It expects
* struct vb2_vmarea_handler pointer in vma->vm_private_data.
*/
static void vb2_common_vm_close(struct vm_area_struct *vma)
{
struct vb2_vmarea_handler *h = vma->vm_private_data;

printk(KERN_DEBUG "%s: %p, refcount: %d, vma: %08lx-%08lx\n",
__func__, h, atomic_read(h->refcount), vma->vm_start,
vma->vm_end);

h->put(h->arg);
}

/**
* vb2_common_vm_ops - common vm_ops used for tracking refcount of mmaped
* video buffers
*/
const struct vm_operations_struct vb2_common_vm_ops = {
.open = vb2_common_vm_open,
.close = vb2_common_vm_close,
};
EXPORT_SYMBOL_GPL(vb2_common_vm_ops);

MODULE_DESCRIPTION("common memory handling routines for videobuf2");
MODULE_AUTHOR("Pawel Osciak");
MODULE_LICENSE("GPL");
45 changes: 45 additions & 0 deletions trunk/include/media/videobuf2-memops.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* videobuf2-memops.h - generic memory handling routines for videobuf2
*
* Copyright (C) 2010 Samsung Electronics
*
* Author: Pawel Osciak <p.osciak@samsung.com>
* Marek Szyprowski <m.szyprowski@samsung.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation.
*/

#ifndef _MEDIA_VIDEOBUF2_MEMOPS_H
#define _MEDIA_VIDEOBUF2_MEMOPS_H

#include <media/videobuf2-core.h>

/**
* vb2_vmarea_handler - common vma refcount tracking handler
* @refcount: pointer to refcount entry in the buffer
* @put: callback to function that decreases buffer refcount
* @arg: argument for @put callback
*/
struct vb2_vmarea_handler {
atomic_t *refcount;
void (*put)(void *arg);
void *arg;
};

extern const struct vm_operations_struct vb2_common_vm_ops;

int vb2_get_contig_userptr(unsigned long vaddr, unsigned long size,
struct vm_area_struct **res_vma, dma_addr_t *res_pa);

int vb2_mmap_pfn_range(struct vm_area_struct *vma, unsigned long paddr,
unsigned long size,
const struct vm_operations_struct *vm_ops,
void *priv);

struct vm_area_struct *vb2_get_vma(struct vm_area_struct *vma);
void vb2_put_vma(struct vm_area_struct *vma);


#endif

0 comments on commit c8786d5

Please sign in to comment.