完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
很多时候我们驱动和应用要共享一段存储空间 我个人理解是,copy_to_user 只是用来传递数据,当应用需要实时读取数据时,就要共享内存了 编写驱动 驱动程序要做的事情有 3 点: ① 确定物理地址 ② 确定属性:是否使用 cache、buffer ③ 建立映射关系 在file_operation里面建立mmap 进行mmap的函数编写 这样在驱动程序的内存空间就被建立了映射,用应用程序访问读取,都行 应用程序编写 打开驱动的文件 进行buf的读取 应用程序里mmap共享属性分析 设立私有属性为 MAP_SHARED(使用) 把程序进行编译,驱动进行编译,进行运行,发现数据相同,说明进行映射 多个APP都调用mmap映射同一块内存时, 对内存的修改大家都可以看到。 就是说多个APP、驱动程序实际上访问的都是同一块内存 设立私有属性为 MAP_PRIVATE 进行运行 创建一个copy on write的私有映射。 * 当APP对该内存进行修改时,其他程序是看不到这些修改的。 * 就是当APP写内存时, 内核会先创建一个拷贝给这个APP, * 这个拷贝是这个APP私有的, 其他APP、驱动无法访问。 源码 hello_drv.c #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* 1. 确定主设备号 */ static int major = 0; static char *kernel_buf; static struct class *hello_class; static int bufsiz = 1024*8; #define MIN(a, b) (a < b ? a : b) /* 3. 实现对应的open/read/write等函数,填入file_operations结构体 */ static ssize_t hello_drv_read (struct file *file, char __user *buf, size_t size, loff_t *offset) { int err; printk("%s %s line %dn", __FILE__, __FUNCTION__, __LINE__); err = copy_to_user(buf, kernel_buf, MIN(bufsiz, size)); return MIN(bufsiz, size); } static ssize_t hello_drv_write (struct file *file, const char __user *buf, size_t size, loff_t *offset) { int err; printk("%s %s line %dn", __FILE__, __FUNCTION__, __LINE__); err = copy_from_user(kernel_buf, buf, MIN(1024, size)); return MIN(1024, size); } static int hello_drv_mmap(struct file *file, struct vm_area_struct *vma) { /* 获得物理地址 */ unsigned long phy = virt_to_phys(kernel_buf); /* 设置属性: cache, buffer */ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); /* map进行映射 */ if (remap_pfn_range(vma, vma->vm_start, phy >> PAGE_SHIFT, vma->vm_end - vma->vm_start, vma->vm_page_prot)) { printk("mmap remap_pfn_range failedn"); return -ENOBUFS; } return 0; } static int hello_drv_open (struct inode *node, struct file *file) { printk("%s %s line %dn", __FILE__, __FUNCTION__, __LINE__); return 0; } static int hello_drv_close (struct inode *node, struct file *file) { printk("%s %s line %dn", __FILE__, __FUNCTION__, __LINE__); return 0; } /* 2. 定义自己的file_operations结构体 */ static struct file_operations hello_drv = { .owner = THIS_MODULE, .open = hello_drv_open, .read = hello_drv_read, .write = hello_drv_write, .release = hello_drv_close, .mmap = hello_drv_mmap,//放入内存映射 }; /* 4. 把file_operations结构体告诉内核:注册驱动程序 */ /* 5. 谁来注册驱动程序啊?得有一个入口函数:安装驱动程序时,就会去调用这个入口函数 */ static int __init hello_init(void) { int err; kernel_buf = kmalloc(bufsiz, GFP_KERNEL);//分配虚拟地址 strcpy(kernel_buf, "old"); printk("%s %s line %dn", __FILE__, __FUNCTION__, __LINE__); major = register_chrdev(0, "hello", &hello_drv); /* /dev/hello */ hello_class = class_create(THIS_MODULE, "hello_class"); err = PTR_ERR(hello_class); if (IS_ERR(hello_class)) { printk("%s %s line %dn", __FILE__, __FUNCTION__, __LINE__); unregister_chrdev(major, "hello"); return -1; } device_create(hello_class, NULL, MKDEV(major, 0), NULL, "hello"); /* /dev/hello */ return 0; } /* 6. 有入口函数就应该有出口函数:卸载驱动程序时,就会去调用这个出口函数 */ static void __exit hello_exit(void) { printk("%s %s line %dn", __FILE__, __FUNCTION__, __LINE__); device_destroy(hello_class, MKDEV(major, 0)); class_destroy(hello_class); unregister_chrdev(major, "hello"); kfree(kernel_buf); } /* 7. 其他完善:提供设备信息,自动创建设备节点 */ module_init(hello_init); module_exit(hello_exit); MODULE_LICENSE("GPL"); hello_drv_test.c #include #include #include #include #include #include #include #include /* * ./hello_drv_test */ int main(int argc, char **argv) { int fd; char *buf; int len; char str[1024]; /* 1. 打开文件 */ fd = open("/dev/hello", O_RDWR); if (fd == -1) { printf("can not open file /dev/hellon"); return -1; } /* 2. mmap * MAP_SHARED : 多个APP都调用mmap映射同一块内存时, 对内存的修改大家都可以看到。 * 就是说多个APP、驱动程序实际上访问的都是同一块内存 * MAP_PRIVATE : 创建一个copy on write的私有映射。 * 当APP对该内存进行修改时,其他程序是看不到这些修改的。 * 就是当APP写内存时, 内核会先创建一个拷贝给这个APP, * 这个拷贝是这个APP私有的, 其他APP、驱动无法访问。 */ buf = mmap(NULL, 1024*8, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); /// // mmap(虚拟地址,地址大小,读写属性,私有属性,映射文件fd,偏移地址) if (buf == MAP_FAILED) { printf("can not mmap file /dev/hellon"); return -1; } printf("mmap address = 0x%xn", buf); printf("buf origin data = %sn", buf); /* old */ /* 3. write 拷贝数据 */ strcpy(buf, "new"); /* 4. read & compare */ /* 对于MAP_SHARED映射: str = "new" * 对于MAP_PRIVATE映射: str = "old" */ read(fd, str, 1024); if (strcmp(buf, str) == 0) { /* 对于MAP_SHARED映射,APP写的数据驱动可见 * APP和驱动访问的是同一个内存块 */ printf("compare ok!n"); } else { /* 对于MAP_PRIVATE映射,APP写数据时, 是写入原来内存块的"拷贝" */ printf("compare err!n"); printf("str = %s!n", str); /* old */ printf("buf = %s!n", buf); /* new */ } while (1) { sleep(10); /* cat /proc/pid/maps */ } munmap(buf, 1024*8); close(fd); return 0; } 原作者:鸭鸭打瞌睡 |
|
相关推荐
1个回答
|
|
|
|
你正在撰写答案
如果你是对答案或其他答案精选点评或询问,请使用“评论”功能。
787 浏览 0 评论
飞凌嵌入式ElfBoard ELF 1板卡-mfgtools烧录流程介绍之烧写所需镜像
888 浏览 0 评论
飞凌嵌入式ElfBoard ELF 1板卡-mfgtools烧录流程之烧写方法
608 浏览 0 评论
飞凌嵌入式ElfBoard ELF 1板卡-内核编译之初次编译
905 浏览 0 评论
飞凌嵌入式ElfBoard ELF 1板卡-内核源代码的目录结构和文件说明
821 浏览 0 评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-23 06:13 , Processed in 0.727336 second(s), Total 71, Slave 54 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号