【IMX6ULL驱动开发学习】19.mmap内存映射

这篇具有很好参考价值的文章主要介绍了【IMX6ULL驱动开发学习】19.mmap内存映射。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

mmap将一个文件或者其它对象映射进内存,使得应用层可以直接读取到驱动层的数据,无需通过copy_to_user函数
可以用于像LCD这样的外设, 需要读写大量数据的

一、应用层

mmap用法:

  • 用open系统调用打开文件, 并返回描述符fd.
  • 用mmap建立内存映射, 并返回映射首地址指针start.
  • 对映射(文件)进行各种操作, 显示(printf), 修改(strcpy、memncpy、sprintf、直接修改等).
  • munmap(void *start, size_t lenght)关闭内存映射.
  • close系统调用关闭文件fd.

mmap函数:

void *mmap(void *addr, size_t length, int prot, int flags,
                  int fd, off_t offset);
参数 含义
addr 指向欲映射的内存起始地址,通常设为 NULL
代表让系统自动选定地址,映射成功后返回该地址
length 代表将文件中多大的部分映射到内存。
prot 映射区域的保护方式。可以为以下几种方式的组合:
PROT_EXEC 映射区域可被执行
PROT_READ 映射区域可被读取
PROT_WRITE 映射区域可被写入
PROT_NONE 映射区域不能存取
flags 影响映射区域的各种特性。
在调用mmap()时必须要指定MAP_SHAREDMAP_PRIVATE
fd 要映射到内存中的文件描述符。
如果使用匿名内存映射时,即flags中设置了MAP_ANONYMOUS,fd设为-1。
有些系统不支持匿名内存映射,则可以使用fopen打开/dev/zero文件,
然后对该文件进行映射,可以同样达到匿名内存映射的效果。
offset 文件映射的偏移量,通常设置为0
代表从文件最前方开始对应,offset必须是分页大小的整数倍。

内存映射之后对内存进行读写,可以用write、read,但是效率低,可以直接对mmap函数返回的地址进行操作
使用 strcpy 等字符串处理函数即可


应用程序示例:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <sys/mman.h>

#define   MMSIZE   128

int main(int argc, char *argv[])
{
    int len;
    char wr_buf[] = "hello mmap";
	char read_buf[1024];
	char *start;

	...
	...
	
    /*open*/
    int fd;
    fd = open(argv[1], O_RDWR);
    if(fd < 0){
        printf("open failed\n");
        return -2;
    }
	printf("pid = %d\n", getpid());
	/* 将文件映射到进程的虚拟内存空间 */
	start = mmap(NULL, MMSIZE, PROT_READ | PROT_WRITE, 
		         MAP_SHARED, fd, 0);
	printf("mmap address = 0x%x\n", start);
	/* 写数据 */
	strcpy(start, wr_buf);
	/* 读数据 */
	strcpy(read_buf, start);
//	read(fd, read_buf, MMSIZE);

	printf("new data = %s\n", start);
	printf("old data = %s\n", read_buf);
	while(1){
		sleep(5);
	}
	munmap(start, MMSIZE);
    close(fd);
    return 0;
}

二、驱动层

  • 首先,驱动程序先分配好一段内存
  • 接着用户进程通过库函数mmap()来告诉内核要将多大的内存映射到内核空间
  • 内核经过一系列函数调用后调用对应的驱动程序的file_operation中指定的xxx_mmap函数
  • 在xxx_mmap函数中调用remap_pfn_range()来建立映射关系。

驱动程序示例:

......
......

#define   MM_SIZE   1024 * 8
#define   MIN(x,y)  (x < y ? x : y)

static char *buf = NULL;

static ssize_t hello_read (struct file *filp, char  *buff, size_t size, loff_t *offset)
{
	int err;
	err = copy_to_user(buff, buf, MIN(MM_SIZE, size));
	return MIN(MM_SIZE, size);
}

static int hello_mmap (struct file *filp, struct vm_area_struct *vma)
{	
	/*设置属性: cache,buffer */
	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;  
    }  
    return 0;
}

/*定义 file_operations 结构体*/
static const struct file_operations hello_drv = {
	.read		= hello_read,
	.open		= hello_open,
	.mmap 		= hello_mmap,
	......
	......
};

/*入口函数*/
static int hello_init(void)
{
	//内核申请内存只能按页申请,申请该内存以便后面把它当作虚拟设备
	buf = kmalloc(MM_SIZE, GFP_KERNEL);
	strcpy(buf, "abc");  //先放入一些数据
	......
	......
	
	return 0;
}

/*退出函数*/
static void hello_exit(void)
{
	kfree(buf);
	......
	......
}	

......
......


三、测试

直接口述吧
当mmap的参数为MAP_SHARED时,使用strcpy和read读取的数据和写入的相同;
当mmap的参数为MAP_PRIVATE时,使用strcpy读取的数据和写入的相同,read的数据和写入的不同(因为read到的是原内存的数据,MAP_PRIVATE标志会使得在写入内存数据时,内核会自动把内存空间拷贝一份,从而read到的是原来的内存,而写入的数据写入到了拷贝的新内存中)
【IMX6ULL驱动开发学习】19.mmap内存映射,IMX6ULL,驱动开发,imx6ull,mmap,内存映射,Linux驱动,驱动文章来源地址https://www.toymoban.com/news/detail-573059.html

到了这里,关于【IMX6ULL驱动开发学习】19.mmap内存映射的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【IMX6ULL驱动开发学习】08.IMX6ULL通过GPIO子系统函数点亮LED

    通过GPIO子系统函数点亮LED 1、GPIO子系统函数 1.1 确定 led 的GPIO标号,查看内核中的gpiochip 查看 gpiochip ,以正点原子的IMX6ULL阿尔法开发板为例 查看原理图,发现led接的引脚是 GPIO1_IO3,对应 /sys/kernel/debug/gpio 中的 gpiochip0 组,gpiochip0 组从0开始算起, 所以 GPIO1_IO3 对应的标号就

    2024年02月10日
    浏览(78)
  • 【IMX6ULL驱动开发学习】03.设置IMX6ULL开发板与虚拟机在同一网段(设置开发板静态IP)

    为什么要设置IMX6ULL与虚拟机通信? 因为要把在虚拟机下编译的文件传到IMX6ULL开发板上运行 设置好同一网段,可以互ping后,可以参考这篇博客,实现开发板与虚拟机的文件互传 IMX6ULL开发板与虚拟机互传文件 一、设置windows有线网卡 二、配置虚拟机双网卡(原本有一个NAT网卡

    2024年02月07日
    浏览(69)
  • 【IMX6ULL驱动开发学习】11.Linux之SPI驱动

    参考:驱动程序开发:SPI设备驱动_spi驱动_邓家文007的博客-CSDN博客 目录 一、SPI驱动简介 1.1 SPI架构概述 1.2 SPI适配器(控制器)数据结构 1.2 SPI设备数据结构 1.3 SIP设备驱动 1.4 接口函数  二、SPI驱动模板 SPI驱动框架和I2C驱动框架是十分相似的,不同的是因为SPI是通过片选引

    2024年02月11日
    浏览(54)
  • 【IMX6ULL驱动开发学习】12.Linux驱动之设备树

    承接上一篇博客 【IMX6ULL驱动开发学习】11.驱动设计之面向对象_分层思想(学习设备树过渡部分) 代码获取: https://gitee.com/chenshao777/imx6-ull_-drivers 我后面将三个层合并了(实际上只有前两层),合并成一个dev_drv.c了,暂时没有加GPIO操作,只是个框架 合并前的代码在 11.butt

    2024年02月13日
    浏览(47)
  • iMX6ULL驱动开发 | 让imx6ull开发板支持usb接口FC游戏手柄

    手边有一闲置的linux开发板iMX6ULL一直在吃灰,不用来搞点事情,总觉得对不住它。业余打发时间就玩起来吧,总比刷某音强。从某多多上买来一个usb接口的游戏手柄,让开发板支持以下它,后续就可以接着在上面玩童年经典游戏啦。  我使用的是正点原子的I.MX6U-ALPHA 开发板,

    2024年02月14日
    浏览(54)
  • 【IMX6ULL驱动开发学习】12.Linux SPI驱动实战:DAC驱动设计流程

    基础回顾: 【IMX6ULL驱动开发学习】10.Linux I2C驱动实战:AT24C02驱动设计流程_阿龙还在写代码的博客-CSDN博客 【IMX6ULL驱动开发学习】11.Linux之SPI驱动_阿龙还在写代码的博客-CSDN博客 查看芯片手册,有两种DAC数据格式,12位和16位,这里选用16位数据(2字节)编写驱动。  重点在

    2024年02月11日
    浏览(56)
  • 【IMX6ULL驱动开发学习】11.驱动设计之面向对象_分层思想(学习设备树过渡部分)

    一个 可移植性好 的驱动程序,应该有三个部分组成 1、驱动框架程序(xxx_drv.c) — 对接应用层的 open read write 函数,不做GPIO具体操作 2、硬件操作程序(xxx_chip_gpio.c)— 执行具体的GPIO操作,初始化、读写 3、硬件资源定义程序(xxx_board.c,这在之后就过渡成了设备树)— 为

    2024年02月11日
    浏览(45)
  • 【IMX6ULL驱动开发学习】14.Linux驱动开发 - GPIO中断(设备树 + GPIO子系统)

    代码自取 【14.key_tree_pinctrl_gpios_interrupt】: https://gitee.com/chenshao777/imx6-ull_-drivers 主要接口函数: 1. of_gpio_count (获得GPIO的数量) 2. kzalloc (向内核申请空间) 3. of_get_gpio (获取GPIO子系统标号) 4. gpio_to_irq (根据GPIO子系统标号得到软件中断号) 5. request_irq (根据软件中断号

    2024年02月12日
    浏览(51)
  • 【IMX6ULL驱动开发学习】10.设置uboot使用网络加载zImage和dtb

    首先根据这篇博客,保证自己的开发板与Ubuntu主机处于同一个网段,并且可以ping通 【IMX6ULL驱动开发学习】03.设置IMX6ULL开发板与虚拟机在同一网段 1. 在uboot中设置网络 首先启动自己的板子进入Linux系统,使用 ifconfig 命令或者 ifconfig -a 命令查看自己网卡的地址 我的网卡地址是

    2024年02月11日
    浏览(61)
  • 【IMX6ULL驱动开发学习】01.编写第一个hello驱动+自动创建设备节点(不涉及硬件操作)

    目录 一、驱动程序编写流程 二、代码编写 2.1 驱动程序hello_drv.c 2.2 测试程序 2.3 编写驱动程序的Makefile 三、上机实验 3.1 NFS 挂载 3.2 测试示例 构造file_operations结构体 在里面填充open/read/write/ioctl成员 注册file_operations结构体 int major = register_chrdev(0, \\\"name\\\", fops); 入口函数:调用

    2024年02月13日
    浏览(42)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包