2010-10-11 17:59:36 +04:00
/*
* videobuf2 - dma - contig . c - DMA contig 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:59:36 +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/slab.h>
# include <linux/dma-mapping.h>
# include <media/videobuf2-core.h>
# include <media/videobuf2-memops.h>
struct vb2_dc_conf {
struct device * dev ;
} ;
struct vb2_dc_buf {
struct vb2_dc_conf * conf ;
void * vaddr ;
2011-08-29 10:20:56 +04:00
dma_addr_t dma_addr ;
2010-10-11 17:59:36 +04:00
unsigned long size ;
struct vm_area_struct * vma ;
atomic_t refcount ;
struct vb2_vmarea_handler handler ;
} ;
static void vb2_dma_contig_put ( void * buf_priv ) ;
static void * vb2_dma_contig_alloc ( void * alloc_ctx , unsigned long size )
{
struct vb2_dc_conf * conf = alloc_ctx ;
struct vb2_dc_buf * buf ;
buf = kzalloc ( sizeof * buf , GFP_KERNEL ) ;
if ( ! buf )
return ERR_PTR ( - ENOMEM ) ;
2011-08-29 10:20:56 +04:00
buf - > vaddr = dma_alloc_coherent ( conf - > dev , size , & buf - > dma_addr ,
2010-10-11 17:59:36 +04:00
GFP_KERNEL ) ;
if ( ! buf - > vaddr ) {
dev_err ( conf - > dev , " dma_alloc_coherent of size %ld failed \n " ,
2011-03-22 15:29:32 +03:00
size ) ;
2010-10-11 17:59:36 +04:00
kfree ( buf ) ;
return ERR_PTR ( - ENOMEM ) ;
}
buf - > conf = conf ;
buf - > size = size ;
buf - > handler . refcount = & buf - > refcount ;
buf - > handler . put = vb2_dma_contig_put ;
buf - > handler . arg = buf ;
atomic_inc ( & buf - > refcount ) ;
return buf ;
}
static void vb2_dma_contig_put ( void * buf_priv )
{
struct vb2_dc_buf * buf = buf_priv ;
if ( atomic_dec_and_test ( & buf - > refcount ) ) {
dma_free_coherent ( buf - > conf - > dev , buf - > size , buf - > vaddr ,
2011-08-29 10:20:56 +04:00
buf - > dma_addr ) ;
2010-10-11 17:59:36 +04:00
kfree ( buf ) ;
}
}
static void * vb2_dma_contig_cookie ( void * buf_priv )
{
struct vb2_dc_buf * buf = buf_priv ;
2011-08-29 10:20:56 +04:00
return & buf - > dma_addr ;
2010-10-11 17:59:36 +04:00
}
static void * vb2_dma_contig_vaddr ( void * buf_priv )
{
struct vb2_dc_buf * buf = buf_priv ;
if ( ! buf )
return 0 ;
return buf - > vaddr ;
}
static unsigned int vb2_dma_contig_num_users ( void * buf_priv )
{
struct vb2_dc_buf * buf = buf_priv ;
return atomic_read ( & buf - > refcount ) ;
}
static int vb2_dma_contig_mmap ( void * buf_priv , struct vm_area_struct * vma )
{
struct vb2_dc_buf * buf = buf_priv ;
if ( ! buf ) {
printk ( KERN_ERR " No buffer to map \n " ) ;
return - EINVAL ;
}
2011-08-29 10:20:56 +04:00
return vb2_mmap_pfn_range ( vma , buf - > dma_addr , buf - > size ,
2010-10-11 17:59:36 +04:00
& vb2_common_vm_ops , & buf - > handler ) ;
}
static void * vb2_dma_contig_get_userptr ( void * alloc_ctx , unsigned long vaddr ,
unsigned long size , int write )
{
struct vb2_dc_buf * buf ;
struct vm_area_struct * vma ;
2011-08-29 10:20:56 +04:00
dma_addr_t dma_addr = 0 ;
2010-10-11 17:59:36 +04:00
int ret ;
buf = kzalloc ( sizeof * buf , GFP_KERNEL ) ;
if ( ! buf )
return ERR_PTR ( - ENOMEM ) ;
2011-08-29 10:20:56 +04:00
ret = vb2_get_contig_userptr ( vaddr , size , & vma , & dma_addr ) ;
2010-10-11 17:59:36 +04:00
if ( ret ) {
printk ( KERN_ERR " Failed acquiring VMA for vaddr 0x%08lx \n " ,
vaddr ) ;
kfree ( buf ) ;
return ERR_PTR ( ret ) ;
}
buf - > size = size ;
2011-08-29 10:20:56 +04:00
buf - > dma_addr = dma_addr ;
2010-10-11 17:59:36 +04:00
buf - > vma = vma ;
return buf ;
}
static void vb2_dma_contig_put_userptr ( void * mem_priv )
{
struct vb2_dc_buf * buf = mem_priv ;
if ( ! buf )
return ;
vb2_put_vma ( buf - > vma ) ;
kfree ( buf ) ;
}
const struct vb2_mem_ops vb2_dma_contig_memops = {
. alloc = vb2_dma_contig_alloc ,
. put = vb2_dma_contig_put ,
. cookie = vb2_dma_contig_cookie ,
. vaddr = vb2_dma_contig_vaddr ,
. mmap = vb2_dma_contig_mmap ,
. get_userptr = vb2_dma_contig_get_userptr ,
. put_userptr = vb2_dma_contig_put_userptr ,
. num_users = vb2_dma_contig_num_users ,
} ;
EXPORT_SYMBOL_GPL ( vb2_dma_contig_memops ) ;
void * vb2_dma_contig_init_ctx ( struct device * dev )
{
struct vb2_dc_conf * conf ;
conf = kzalloc ( sizeof * conf , GFP_KERNEL ) ;
if ( ! conf )
return ERR_PTR ( - ENOMEM ) ;
conf - > dev = dev ;
return conf ;
}
EXPORT_SYMBOL_GPL ( vb2_dma_contig_init_ctx ) ;
void vb2_dma_contig_cleanup_ctx ( void * alloc_ctx )
{
kfree ( alloc_ctx ) ;
}
EXPORT_SYMBOL_GPL ( vb2_dma_contig_cleanup_ctx ) ;
MODULE_DESCRIPTION ( " DMA-contig memory handling routines for videobuf2 " ) ;
2011-03-13 21:23:32 +03:00
MODULE_AUTHOR ( " Pawel Osciak <pawel@osciak.com> " ) ;
2010-10-11 17:59:36 +04:00
MODULE_LICENSE ( " GPL " ) ;