Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2634834
  • 博文数量: 333
  • 博客积分: 4817
  • 博客等级: 上校
  • 技术积分: 4413
  • 用 户 组: 普通用户
  • 注册时间: 2011-02-28 10:51
文章分类

全部博文(333)

文章存档

2017年(20)

2016年(57)

2015年(27)

2014年(20)

2013年(21)

2012年(164)

2011年(24)

分类: LINUX

2016-12-20 14:55:58

转载: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

  1. #include   
  2. #include   
  3. #include   
  4. #include   
  5. #include   
  6. #include   
  7. #include   
  8. #include   
  9. #include   
  10. #include   
  11. #include   
  12. #include   
  13. #include   
  14. #include   
  15. #include   
  16. #include   
  17.   
  18. #include "cma_mem.h"  
  19.   
  20. #define DEVICE_NAME "cma_mem"   
  21.   
  22.   
  23. enum cma_status{  
  24.     UNKNOW_STATUS = 0,  
  25.     HAVE_ALLOCED = 1,  
  26.     HAVE_MMAPED =2,  
  27. };  
  28.   
  29. struct cmamem_dev {  
  30.     unsigned int count;  
  31.     struct miscdevice dev;  
  32.     struct mutex cmamem_lock;  
  33.     struct list_head info_list;  
  34. };  
  35.   
  36. struct current_status{  
  37.         int status;  
  38.         int id_count;  
  39.         dma_addr_t phy_base;  
  40. };  
  41.   
  42. static struct current_status cmamem_status;  
  43. static struct cmamem_dev cmamem_dev;  
  44. static struct cmamem_info cma_info[32];  
  45. static long cmamem_ioctl(struct file *file, unsigned int cmd, unsigned long arg)  
  46. {  
  47.   
  48.     int ret = 0;  
  49.     int size = 0;  
  50.     dma_addr_t map_dma;  
  51.   
  52.     switch(cmd){  
  53.         case CMEM_ALLOCATE:  
  54.         {  
  55.             printk(KERN_ERR"cmamem_ioctl:CMEM_ALLOCATE\n");  
  56.             cmamem_status.id_count = cmamem_dev.count++;  
  57.             cma_info[cmamem_status.id_count].id = cmamem_status.id_count;  
  58.             if ((ret = copy_from_user(&cma_info[cmamem_status.id_count], (void __user *)arg,  
  59.             sizeof(struct cmamem_info))))  
  60.             {  
  61.                 printk(KERN_ERR"cmamem_ioctl:CMEM_ALLOCATE:copy_from_user error:%d\n", ret);  
  62.                 ret = -EFAULT;  
  63.                 goto err;  
  64.             }  
  65.       
  66.             size = cma_info[cmamem_status.id_count].len;  
  67.             size = PAGE_ALIGN(size);  
  68.             if(size == 0)  
  69.             {  
  70.                 printk(KERN_ERR"size is 0\n");  
  71.                 ret = -ENOMEM;  
  72.                 goto err;  
  73.             }  
  74.             printk(KERN_ERR"cmamem_ioctl:CMEM_ALLOCATE:start alloc:%d,size:%d\n", cmamem_status.id_count, cma_info[cmamem_status.id_count].len);  
  75.             cma_info[cmamem_status.id_count].mem_base = (unsigned int)dma_alloc_writecombine(NULL, size, &map_dma, GFP_KERNEL);  
  76.             if (!cma_info[cmamem_status.id_count].mem_base){  
  77.                 printk(KERN_ERR "dma alloc fail:%d!\n", __LINE__);  
  78.                 ret = -ENOMEM;  
  79.                 goto err;  
  80.             }  
  81.               
  82.             printk(KERN_ERR"map_dma:0x%08x,size:%d\n", map_dma, size);  
  83.               
  84.             cma_info[cmamem_status.id_count].phy_base = map_dma;  
  85.             cmamem_status.phy_base = map_dma;  
  86.   
  87.             mutex_lock(&cmamem_dev.cmamem_lock);  
  88.               
  89.             cmamem_status.status = HAVE_ALLOCED;  
  90.               
  91.             mutex_unlock(&cmamem_dev.cmamem_lock);  
  92.             break;  
  93.         }  
  94.         default:  
  95.         {  
  96.             printk(KERN_INFO "cma mem not support command\n");  
  97.             break;  
  98.         }  
  99.     }  
  100.     err:  
  101.     return ret;  
  102. }  
  103.   
  104.   
  105. static int cmamem_mmap(struct file *filp, struct vm_area_struct *vma)  
  106. {  
  107.     unsigned long start = vma->vm_start;  
  108.     unsigned long size = vma->vm_end - vma->vm_start;  
  109.     unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;  
  110.     unsigned long page, pos;  
  111.   
  112.       
  113.     //dump_stack();  
  114.   
  115.     if(cmamem_status.status != HAVE_ALLOCED)  
  116.     {  
  117.         printk(KERN_ERR"%s, you should allocted memory firstly\n", __func__);  
  118.         return -EINVAL;   
  119.     }  
  120.       
  121.       
  122.     printk( "start=0x%08x offset=0x%08x\n", (unsigned int)start, (unsigned int)offset );  
  123.   
  124.     pos = (unsigned long)cmamem_status.phy_base + offset;  
  125.     page = pos >> PAGE_SHIFT ;  
  126.     if( remap_pfn_range( vma, start, page, size, PAGE_SHARED )) {  
  127.         return -EAGAIN;  
  128.     }  
  129.     else{  
  130.         printk( "remap_pfn_range %u\n success\n", (unsigned int)page );  
  131.     }  
  132.     vma->vm_flags &= ~VM_IO;   
  133.     vma->vm_flags |=  (VM_DONTEXPAND | VM_DONTDUMP);  
  134.       
  135.     return 0;  
  136. }  
  137.   
  138. static struct file_operations dev_fops = {    
  139.     .owner          = THIS_MODULE,    
  140.     .unlocked_ioctl = cmamem_ioctl,    
  141.     .mmap = cmamem_mmap,  
  142. };  
  143.   
  144. static int __init cmamem_init(void)  
  145. {  
  146.     printk(KERN_ERR"%s\n", __func__);  
  147.     mutex_init(&cmamem_dev.cmamem_lock);  
  148.     INIT_LIST_HEAD(&cmamem_dev.info_list);  
  149.     cmamem_dev.count = 0;  
  150.     cmamem_dev.dev.name = DEVICE_NAME;  
  151.     cmamem_dev.dev.minor = MISC_DYNAMIC_MINOR;  
  152.     cmamem_dev.dev.fops = &dev_fops;  
  153.       
  154.     cmamem_status.status = UNKNOW_STATUS;  
  155.     cmamem_status.id_count = -1;  
  156.     cmamem_status.phy_base = 0;  
  157.       
  158.       
  159.     return misc_register(&cmamem_dev.dev);  
  160. }  
  161.   
  162. static void __exit cmamem_exit(void)    
  163. {    
  164.     printk(KERN_ERR"%s\n", __func__);  
  165.     misc_deregister(&cmamem_dev.dev);    
  166. }   
  167.   
  168.   
  169. module_init(cmamem_init);  
  170. module_exit(cmamem_exit);  
  171. MODULE_LICENSE("GPL");  

cma_mem.h
  1. #ifndef _CMA_MEM_H_  
  2. #define _CMA_MEM_H_  
  3.   
  4. #define CMEM_IOCTL_MAGIC 'm'  
  5. #define CMEM_GET_PHYS       _IOW(CMEM_IOCTL_MAGIC, 1, unsigned int)  
  6. #define CMEM_MAP        _IOW(CMEM_IOCTL_MAGIC, 2, unsigned int)  
  7. #define CMEM_GET_SIZE       _IOW(CMEM_IOCTL_MAGIC, 3, unsigned int)  
  8. #define CMEM_UNMAP      _IOW(CMEM_IOCTL_MAGIC, 4, unsigned int)  
  9.   
  10. #define CMEM_ALLOCATE       _IOW(CMEM_IOCTL_MAGIC, 5, unsigned int)  
  11.   
  12. #define CMEM_CONNECT        _IOW(CMEM_IOCTL_MAGIC, 6, unsigned int)  
  13.   
  14. #define CMEM_GET_TOTAL_SIZE _IOW(CMEM_IOCTL_MAGIC, 7, unsigned int)  
  15. #define CMEM_CACHE_FLUSH    _IOW(CMEM_IOCTL_MAGIC, 8, unsigned int)  
  16.   
  17.   
  18. struct cmamem_info {  
  19.     char *name;  
  20.     char is_cache;  
  21.     unsigned int id;  
  22.     unsigned int offset;  
  23.     unsigned int len;  
  24.     unsigned int phy_base;  
  25.     unsigned int mem_base;  
  26. //  struct list_head list;  
  27. };  
  28.   
  29.   
  30.   
  31.   
  32. #endif  
Makefile
  1. KERN_DIR = /work/kernel/linux-3.9.7  
  2.   
  3. all:  
  4.     make -C $(KERN_DIR) M=`pwd` modules   
  5.   
  6. clean:  
  7.     make -C $(KERN_DIR) M=`pwd` modules clean  
  8.     rm -rf modules.order  
  9.   
  10. obj-m   += cma_mem.o  


用户测试程序
  1. #include   
  2. #include   
  3. #include   
  4. #include   
  5. #include   
  6. #include   
  7. #include   
  8. #include   
  9. #include   
  10. #include   
  11. #include   
  12. #include   
  13. #include   
  14. #include   
  15. #include   
  16. #include   
  17.   
  18. #define CMEM_IOCTL_MAGIC 'm'  
  19. #define CMEM_GET_PHYS       _IOW(CMEM_IOCTL_MAGIC, 1, unsigned int)  
  20. #define CMEM_MAP        _IOW(CMEM_IOCTL_MAGIC, 2, unsigned int)  
  21. #define CMEM_GET_SIZE       _IOW(CMEM_IOCTL_MAGIC, 3, unsigned int)  
  22. #define CMEM_UNMAP      _IOW(CMEM_IOCTL_MAGIC, 4, unsigned int)  
  23.   
  24. #define CMEM_ALLOCATE       _IOW(CMEM_IOCTL_MAGIC, 5, unsigned int)  
  25.   
  26. #define CMEM_CONNECT        _IOW(CMEM_IOCTL_MAGIC, 6, unsigned int)  
  27.   
  28. #define CMEM_GET_TOTAL_SIZE _IOW(CMEM_IOCTL_MAGIC, 7, unsigned int)  
  29. #define CMEM_CACHE_FLUSH    _IOW(CMEM_IOCTL_MAGIC, 8, unsigned int)  
  30.   
  31.   
  32. struct cmamem_info {  
  33.     char *name;  
  34.     char is_cache;  
  35.     unsigned long id;  
  36.     unsigned long offset;  
  37.     unsigned long len;  
  38.     unsigned long phy_base;  
  39.     unsigned long mem_base;  
  40. //  struct list_head list;  
  41. };  
  42.   
  43. int main()  
  44. {  
  45.     int cmem_fd;  
  46.     void *cmem_base;  
  47.     unsigned int size;  
  48.     struct cmamem_info region;  
  49.     int i;  
  50.     cmem_fd = open("/dev/cma_mem", O_RDWR, 0);//打开设备,为了操作硬件引擎,要noncache的  
  51.     printf("cmem_fd:%d\n", cmem_fd);  
  52.     if (cmem_fd >= 0)    
  53.     {         
  54.   
  55.         memset(®ion, 0x00, sizeof(struct cmamem_info));  
  56.         region.len = 800 * 480 * 4;  
  57.         if (ioctl(cmem_fd, CMEM_ALLOCATE, ®ion) < 0) //获取全部空间              
  58.         {     
  59.             perror("PMEM_GET_TOTAL_SIZE failed\n");  
  60.             return -1;  
  61.         }  
  62.          
  63.         size = region.len;  
  64.           
  65.         cmem_base = mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, cmem_fd, 0);//mmap操作  
  66.         printf("cmem_base:0x%08x,region.len:0x%08x offset:0x%08x\n",(unsigned int)cmem_base, region.len, region.offset);  
  67.         if (cmem_base == MAP_FAILED)              
  68.         {   cmem_base = 0;  
  69.             close(cmem_fd);  
  70.             cmem_fd = -1;  
  71.             perror("mmap pmem error!\n");  
  72.         }  
  73.         for(i = 0; i < 10; i++)  
  74.         ((unsigned int *)cmem_base)[i] = i;  
  75.         printf("pmem_base:0x%08x\n", cmem_base);  
  76.         for(i = 0; i < 10; i++)  
  77.         printf("%d\n", ((unsigned int *)cmem_base)[i]);  
  78.           
  79.     }  
  80.     close(cmem_fd);  
  81.     return 0;  

阅读(3116) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~