转载:http://blog.csdn.net/liujia2100/article/details/37915645
背景:
在多媒体和图像处理等应用中,经常用到大块内存,尤其是硬件编解码,需要内核分配大块的物理连续内存。
这里希望通过把从内核分配的连续物理内存映射到用户空间,在用户空间经过处理,又可以入队到驱动中。
前提:
Kernel Config中 根据需求配置和调整CMA的大小。
方法:
(一)
1、驱动注册misc设备;
2、驱动实现IOCTL的内存分配,使用dma_alloc_writecombine从CMA中拿出一个内存;
3、驱动实现mmap,通过remap_pfn_range,把上面第二步dma分配到的物理内存映射到用户空间;
(二)
1、用户打开设备节点/dev/cma_mem;
2、通过ioctl命令,设置需要分配的大小;
3、通过mmap映射;
环境:
-3.9.7
arm-linux-gcc 4.5.1
s5pv210
源码:
驱动
cma_mem.c
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
-
#include "cma_mem.h"
-
-
#define DEVICE_NAME "cma_mem"
-
-
-
enum cma_status{
-
UNKNOW_STATUS = 0,
-
HAVE_ALLOCED = 1,
-
HAVE_MMAPED =2,
-
};
-
-
struct cmamem_dev {
-
unsigned int count;
-
struct miscdevice dev;
-
struct mutex cmamem_lock;
-
struct list_head info_list;
-
};
-
-
struct current_status{
-
int status;
-
int id_count;
-
dma_addr_t phy_base;
-
};
-
-
static struct current_status cmamem_status;
-
static struct cmamem_dev cmamem_dev;
-
static struct cmamem_info cma_info[32];
-
static long cmamem_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
-
{
-
-
int ret = 0;
-
int size = 0;
-
dma_addr_t map_dma;
-
-
switch(cmd){
-
case CMEM_ALLOCATE:
-
{
-
printk(KERN_ERR"cmamem_ioctl:CMEM_ALLOCATE\n");
-
cmamem_status.id_count = cmamem_dev.count++;
-
cma_info[cmamem_status.id_count].id = cmamem_status.id_count;
-
if ((ret = copy_from_user(&cma_info[cmamem_status.id_count], (void __user *)arg,
-
sizeof(struct cmamem_info))))
-
{
-
printk(KERN_ERR"cmamem_ioctl:CMEM_ALLOCATE:copy_from_user error:%d\n", ret);
-
ret = -EFAULT;
-
goto err;
-
}
-
-
size = cma_info[cmamem_status.id_count].len;
-
size = PAGE_ALIGN(size);
-
if(size == 0)
-
{
-
printk(KERN_ERR"size is 0\n");
-
ret = -ENOMEM;
-
goto err;
-
}
-
printk(KERN_ERR"cmamem_ioctl:CMEM_ALLOCATE:start alloc:%d,size:%d\n", cmamem_status.id_count, cma_info[cmamem_status.id_count].len);
-
cma_info[cmamem_status.id_count].mem_base = (unsigned int)dma_alloc_writecombine(NULL, size, &map_dma, GFP_KERNEL);
-
if (!cma_info[cmamem_status.id_count].mem_base){
-
printk(KERN_ERR "dma alloc fail:%d!\n", __LINE__);
-
ret = -ENOMEM;
-
goto err;
-
}
-
-
printk(KERN_ERR"map_dma:0x%08x,size:%d\n", map_dma, size);
-
-
cma_info[cmamem_status.id_count].phy_base = map_dma;
-
cmamem_status.phy_base = map_dma;
-
-
mutex_lock(&cmamem_dev.cmamem_lock);
-
-
cmamem_status.status = HAVE_ALLOCED;
-
-
mutex_unlock(&cmamem_dev.cmamem_lock);
-
break;
-
}
-
default:
-
{
-
printk(KERN_INFO "cma mem not support command\n");
-
break;
-
}
-
}
-
err:
-
return ret;
-
}
-
-
-
static int cmamem_mmap(struct file *filp, struct vm_area_struct *vma)
-
{
-
unsigned long start = vma->vm_start;
-
unsigned long size = vma->vm_end - vma->vm_start;
-
unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
-
unsigned long page, pos;
-
-
-
-
-
if(cmamem_status.status != HAVE_ALLOCED)
-
{
-
printk(KERN_ERR"%s, you should allocted memory firstly\n", __func__);
-
return -EINVAL;
-
}
-
-
-
printk( "start=0x%08x offset=0x%08x\n", (unsigned int)start, (unsigned int)offset );
-
-
pos = (unsigned long)cmamem_status.phy_base + offset;
-
page = pos >> PAGE_SHIFT ;
-
if( remap_pfn_range( vma, start, page, size, PAGE_SHARED )) {
-
return -EAGAIN;
-
}
-
else{
-
printk( "remap_pfn_range %u\n success\n", (unsigned int)page );
-
}
-
vma->vm_flags &= ~VM_IO;
-
vma->vm_flags |= (VM_DONTEXPAND | VM_DONTDUMP);
-
-
return 0;
-
}
-
-
static struct file_operations dev_fops = {
-
.owner = THIS_MODULE,
-
.unlocked_ioctl = cmamem_ioctl,
-
.mmap = cmamem_mmap,
-
};
-
-
static int __init cmamem_init(void)
-
{
-
printk(KERN_ERR"%s\n", __func__);
-
mutex_init(&cmamem_dev.cmamem_lock);
-
INIT_LIST_HEAD(&cmamem_dev.info_list);
-
cmamem_dev.count = 0;
-
cmamem_dev.dev.name = DEVICE_NAME;
-
cmamem_dev.dev.minor = MISC_DYNAMIC_MINOR;
-
cmamem_dev.dev.fops = &dev_fops;
-
-
cmamem_status.status = UNKNOW_STATUS;
-
cmamem_status.id_count = -1;
-
cmamem_status.phy_base = 0;
-
-
-
return misc_register(&cmamem_dev.dev);
-
}
-
-
static void __exit cmamem_exit(void)
-
{
-
printk(KERN_ERR"%s\n", __func__);
-
misc_deregister(&cmamem_dev.dev);
-
}
-
-
-
module_init(cmamem_init);
-
module_exit(cmamem_exit);
-
MODULE_LICENSE("GPL");
cma_mem.h
-
#ifndef _CMA_MEM_H_
-
#define _CMA_MEM_H_
-
-
#define CMEM_IOCTL_MAGIC 'm'
-
#define CMEM_GET_PHYS _IOW(CMEM_IOCTL_MAGIC, 1, unsigned int)
-
#define CMEM_MAP _IOW(CMEM_IOCTL_MAGIC, 2, unsigned int)
-
#define CMEM_GET_SIZE _IOW(CMEM_IOCTL_MAGIC, 3, unsigned int)
-
#define CMEM_UNMAP _IOW(CMEM_IOCTL_MAGIC, 4, unsigned int)
-
-
#define CMEM_ALLOCATE _IOW(CMEM_IOCTL_MAGIC, 5, unsigned int)
-
-
#define CMEM_CONNECT _IOW(CMEM_IOCTL_MAGIC, 6, unsigned int)
-
-
#define CMEM_GET_TOTAL_SIZE _IOW(CMEM_IOCTL_MAGIC, 7, unsigned int)
-
#define CMEM_CACHE_FLUSH _IOW(CMEM_IOCTL_MAGIC, 8, unsigned int)
-
-
-
struct cmamem_info {
-
char *name;
-
char is_cache;
-
unsigned int id;
-
unsigned int offset;
-
unsigned int len;
-
unsigned int phy_base;
-
unsigned int mem_base;
-
-
};
-
-
-
-
-
#endif
Makefile
-
KERN_DIR = /work/kernel/linux-3.9.7
-
-
all:
-
make -C $(KERN_DIR) M=`pwd` modules
-
-
clean:
-
make -C $(KERN_DIR) M=`pwd` modules clean
-
rm -rf modules.order
-
-
obj-m += cma_mem.o
用户测试程序
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
-
#define CMEM_IOCTL_MAGIC 'm'
-
#define CMEM_GET_PHYS _IOW(CMEM_IOCTL_MAGIC, 1, unsigned int)
-
#define CMEM_MAP _IOW(CMEM_IOCTL_MAGIC, 2, unsigned int)
-
#define CMEM_GET_SIZE _IOW(CMEM_IOCTL_MAGIC, 3, unsigned int)
-
#define CMEM_UNMAP _IOW(CMEM_IOCTL_MAGIC, 4, unsigned int)
-
-
#define CMEM_ALLOCATE _IOW(CMEM_IOCTL_MAGIC, 5, unsigned int)
-
-
#define CMEM_CONNECT _IOW(CMEM_IOCTL_MAGIC, 6, unsigned int)
-
-
#define CMEM_GET_TOTAL_SIZE _IOW(CMEM_IOCTL_MAGIC, 7, unsigned int)
-
#define CMEM_CACHE_FLUSH _IOW(CMEM_IOCTL_MAGIC, 8, unsigned int)
-
-
-
struct cmamem_info {
-
char *name;
-
char is_cache;
-
unsigned long id;
-
unsigned long offset;
-
unsigned long len;
-
unsigned long phy_base;
-
unsigned long mem_base;
-
-
};
-
-
int main()
-
{
-
int cmem_fd;
-
void *cmem_base;
-
unsigned int size;
-
struct cmamem_info region;
-
int i;
-
cmem_fd = open("/dev/cma_mem", O_RDWR, 0);
-
printf("cmem_fd:%d\n", cmem_fd);
-
if (cmem_fd >= 0)
-
{
-
-
memset(®ion, 0x00, sizeof(struct cmamem_info));
-
region.len = 800 * 480 * 4;
-
if (ioctl(cmem_fd, CMEM_ALLOCATE, ®ion) < 0)
-
{
-
perror("PMEM_GET_TOTAL_SIZE failed\n");
-
return -1;
-
}
-
-
size = region.len;
-
-
cmem_base = mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, cmem_fd, 0);
-
printf("cmem_base:0x%08x,region.len:0x%08x offset:0x%08x\n",(unsigned int)cmem_base, region.len, region.offset);
-
if (cmem_base == MAP_FAILED)
-
{ cmem_base = 0;
-
close(cmem_fd);
-
cmem_fd = -1;
-
perror("mmap pmem error!\n");
-
}
-
for(i = 0; i < 10; i++)
-
((unsigned int *)cmem_base)[i] = i;
-
printf("pmem_base:0x%08x\n", cmem_base);
-
for(i = 0; i < 10; i++)
-
printf("%d\n", ((unsigned int *)cmem_base)[i]);
-
-
}
-
close(cmem_fd);
-
return 0;
-
}
阅读(3102) | 评论(0) | 转发(0) |