mmap内存映射 --- 字符设备驱动,用户空间和内核空间映射到同一个物理内存
内存映射可实现用户程序对设备驱动内存的直接存取
示例代码: 驱动层
#include <linux/init.h> #include <linux/module.h> #include <linux/miscdevice.h> #include <linux/fs.h> #include <linux/slab.h> //定义kmalloc接口 #include <asm/io.h> //定义virt_to_phys接口 #include <linux/mm.h> //remap_pfn_range #include <linux/vmalloc.h> #include <linux/delay.h> #define MM_SIZE 4096 static char *buf= NULL; static int tiny4412_open(struct inode *my_indoe, struct file *my_file) { buf=(char *)kmalloc(MM_SIZE,GFP_KERNEL);//内核申请内存只能按页申请,申请该内存以便后面把它当作虚拟设备 if(buf==NULL) { printk("error!\n"); return 0; } strcpy(buf,"123456789"); printk("open ok\n"); return 0; } static int tiny4412_release(struct inode *my_indoe, struct file *my_file) { printk("驱动层打印=%s\n",buf); kfree(buf); /*释放空间*/ printk("open release\n"); return 0; } static int tiny4412_mmap(struct file *myfile, struct vm_area_struct *vma) { vma->vm_flags |= VM_IO;//表示对设备IO空间的映射 vma->vm_flags |= VM_RESERVED;//标志该内存区不能被换出,在设备驱动中虚拟页和物理页的关系应该是长期的,应该保留起来,不能随便被别的虚拟页换出 vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); //修改访问保护属性 if(remap_pfn_range(vma,//虚拟内存区域,即设备地址将要映射到这里 vma->vm_start,//虚拟空间的起始地址 virt_to_phys(buf)>>PAGE_SHIFT,//与物理内存对应的页帧号,物理地址右移12位 vma->vm_end - vma->vm_start,//映射区域大小,一般是页大小的整数倍 vma->vm_page_prot))//保护属性, { return -EAGAIN; } printk("tiny4412_mmap ok\n"); return 0; } static struct file_operations tiny4412_fops= { .open=tiny4412_open, .release=tiny4412_release, .mmap=tiny4412_mmap }; static struct miscdevice misc={ .minor=255, .name="tiny4412_mmap", // /dev/下的名称 .fops=&tiny4412_fops, }; static int __init hello_init(void) { /*1. 注册杂项字符设备*/ misc_register(&misc); printk("hello_init 驱动安装成功!\n"); return 0; } static void __exit hello_exit(void) { /*2. 注销*/ misc_deregister(&misc); printk("hello_exit驱动卸载成功!\n"); } module_init(hello_init); module_exit(hello_exit); MODULE_AUTHOR("www.wanbangee.com"); //声明驱动的作者 MODULE_DESCRIPTION("hello 模块测试"); //描述当前驱动功能 MODULE_LICENSE("GPL"); //驱动许可证。支持的协议GPL。
示例代码: 应用层
#include <stdio.h> #include <sys/mman.h> unsigned char *fbmem=NULL; unsigned char buff[10]; int main(int argc,char**argv) { int fd; fd=open("/dev/tiny4412_mmap",2); if(fd<0) { printf("驱动打开失败!\n"); return -1; } fbmem =(unsigned char *)mmap(NULL,4096,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0); if(fbmem==NULL) { printf("映射错误!\n"); } printf("应用层打印1=%s\n",fbmem); //打印出123456789 memcpy(fbmem,"987654321",10); //向映射空间拷贝数据 memcpy(buff,fbmem,10); //将映射空间的数据拷贝出来 printf("应用层打印2=%s\n",buff); //打印出987654321 close(fd); return 0; }