2010-10-11 17:58:53 +04:00
/*
* videobuf2 - vmalloc . c - vmalloc memory allocator for videobuf2
*
* Copyright ( C ) 2010 Samsung Electronics
*
2011-03-13 21:23:32 +03:00
* Author : Pawel Osciak < pawel @ osciak . com >
2010-10-11 17:58:53 +04:00
*
* 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/module.h>
# include <linux/mm.h>
# include <linux/slab.h>
# include <linux/vmalloc.h>
# include <media/videobuf2-core.h>
# include <media/videobuf2-memops.h>
struct vb2_vmalloc_buf {
void * vaddr ;
unsigned long size ;
atomic_t refcount ;
struct vb2_vmarea_handler handler ;
} ;
static void vb2_vmalloc_put ( void * buf_priv ) ;
static void * vb2_vmalloc_alloc ( void * alloc_ctx , unsigned long size )
{
struct vb2_vmalloc_buf * buf ;
buf = kzalloc ( sizeof * buf , GFP_KERNEL ) ;
if ( ! buf )
return NULL ;
buf - > size = size ;
buf - > vaddr = vmalloc_user ( buf - > size ) ;
buf - > handler . refcount = & buf - > refcount ;
buf - > handler . put = vb2_vmalloc_put ;
buf - > handler . arg = buf ;
if ( ! buf - > vaddr ) {
printk ( KERN_ERR " vmalloc of size %ld failed \n " , buf - > size ) ;
kfree ( buf ) ;
return NULL ;
}
atomic_inc ( & buf - > refcount ) ;
printk ( KERN_DEBUG " Allocated vmalloc buffer of size %ld at vaddr=%p \n " ,
buf - > size , buf - > vaddr ) ;
return buf ;
}
static void vb2_vmalloc_put ( void * buf_priv )
{
struct vb2_vmalloc_buf * buf = buf_priv ;
if ( atomic_dec_and_test ( & buf - > refcount ) ) {
printk ( KERN_DEBUG " %s: Freeing vmalloc mem at vaddr=%p \n " ,
__func__ , buf - > vaddr ) ;
vfree ( buf - > vaddr ) ;
kfree ( buf ) ;
}
}
static void * vb2_vmalloc_vaddr ( void * buf_priv )
{
struct vb2_vmalloc_buf * buf = buf_priv ;
BUG_ON ( ! buf ) ;
if ( ! buf - > vaddr ) {
printk ( KERN_ERR " Address of an unallocated plane requested \n " ) ;
return NULL ;
}
return buf - > vaddr ;
}
static unsigned int vb2_vmalloc_num_users ( void * buf_priv )
{
struct vb2_vmalloc_buf * buf = buf_priv ;
return atomic_read ( & buf - > refcount ) ;
}
static int vb2_vmalloc_mmap ( void * buf_priv , struct vm_area_struct * vma )
{
struct vb2_vmalloc_buf * buf = buf_priv ;
int ret ;
if ( ! buf ) {
printk ( KERN_ERR " No memory to map \n " ) ;
return - EINVAL ;
}
ret = remap_vmalloc_range ( vma , buf - > vaddr , 0 ) ;
if ( ret ) {
printk ( KERN_ERR " Remapping vmalloc memory, error: %d \n " , ret ) ;
return ret ;
}
/*
* Make sure that vm_areas for 2 buffers won ' t be merged together
*/
vma - > vm_flags | = VM_DONTEXPAND ;
/*
* Use common vm_area operations to track buffer refcount .
*/
vma - > vm_private_data = & buf - > handler ;
vma - > vm_ops = & vb2_common_vm_ops ;
vma - > vm_ops - > open ( vma ) ;
return 0 ;
}
const struct vb2_mem_ops vb2_vmalloc_memops = {
. alloc = vb2_vmalloc_alloc ,
. put = vb2_vmalloc_put ,
. vaddr = vb2_vmalloc_vaddr ,
. mmap = vb2_vmalloc_mmap ,
. num_users = vb2_vmalloc_num_users ,
} ;
EXPORT_SYMBOL_GPL ( vb2_vmalloc_memops ) ;
MODULE_DESCRIPTION ( " vmalloc memory handling routines for videobuf2 " ) ;
2011-03-13 21:23:32 +03:00
MODULE_AUTHOR ( " Pawel Osciak <pawel@osciak.com> " ) ;
2010-10-11 17:58:53 +04:00
MODULE_LICENSE ( " GPL " ) ;