ioremap、 mmap

ioremap----------内核空间物理地址到虚拟地址映射
mmap----------用户空间虚拟地址到物理地址映射

一、映射方式

几乎每一种外设都是通过读写设备上的寄存器来进行的,通常包括控制寄存器、状态寄存器和数据寄存器三大类,外设的寄存器通常被连续地编址。根据CPU体系结构的不同,CPU对IO端口的编址方式有两种:

a – I/O 映射方式(I/O-mapped)

典型地,如X86处理器为外设专门实现了一个单独的地址空间,称为"I/O地址空间"或者"I/O端口空间",CPU通过专门的I/O指令(如X86的IN和OUT指令)来访问这一空间中的地址单元。

b – 内存映射方式(Memory-mapped)

RISC指令系统的CPU(如ARM、PowerPC等)通常只实现一个物理地址空间,外设I/O端口成为内存的一部分。此时,CPU可以象访问一个内存单元那样访问外设I/O端口,而不需要设立专门的外设I/O指令。


Linux下内存空间有4G 分为用户空间(3G)和内核空间(1G)
ioremap() -----将IO口的物理地址映射到内核空间的虚拟地址的一种方式
mmap() -----将物理地址映射到用户空间 常用在显存映射到用户空间增加读写效率

二、ioremap()申请映射

void __iomem *ioremap (unsigned long phys_addr, unsigned long size)
phys_addr:物理地址  
size: 申请映射从phys_addr开始后的size 个
void __iomem *:返回的数据类型   之后直接对此变量进行操作

void __iomem * mmio;
mmio = ioremap(HW_PINCTRL_DOUT0_SET,OFFSET_REG);

三、iounmap()释放映射

void iounmap(void *addr);
addr  : 申请时返回的数据变量

iounmap(mmio);

四、led驱动

使用ioremap来进行对led的操作
1、io方向

static int mx1909_gpio_direction(int pin, unsigned int input)
{
	int group,offset;

	group = pin/32;
	offset = pin%32;

	if (input)
		__raw_writel(1 << offset, mmio +(HW_PINCTRL_DOE0_CLR-HW_PINCTRL_DOUT0_SET)+(0x10*group));
	else
		__raw_writel(1 << offset, mmio +(HW_PINCTRL_DOE0_SET-HW_PINCTRL_DOUT0_SET)+(0x10*group));

	return 0;
}

2、获取io状态

static int mx1909_gpio_get(int pin)
{
	int group,offset;
	unsigned int data;
	
	group = pin/32;
	offset = pin%32;

	data = __raw_readl(mmio +(HW_PINCTRL_DIN0-HW_PINCTRL_DOUT0_SET)+(0x10*group));
	
	return (data>>pin)&0x01;
}

3、对io进行赋值

static void mx1909_gpio_set(int pin, int data)
{
	int group,offset;

	group = pin/32;
	offset = pin%32;

	if (data)
		__raw_writel(1 << offset, mmio +(HW_PINCTRL_DOUT0_SET-HW_PINCTRL_DOUT0_SET)+(0x10*group));
	else
		__raw_writel(1 << offset, mmio +(HW_PINCTRL_DOUT0_CLR-HW_PINCTRL_DOUT0_SET)+(0x10*group));
}

五、用户mmap

mmap系统调用使得进程之间通过映射同一个普通文件实现共享内存,普通文件被映射到进程地址空间后,进程可以像访问普通内存一样对文件进行访问,不必再调用read和write等。
主要应用在用户空间与内核空间大数据的拷贝、比如:camera 预览 拍照录像 LCD显示

1、用户mmap申请

void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset); 
start:映射区的开始地址 
length:映射区的长度 
prot:期望的内存保护标志 
—-PROT_EXEC //页内容可以被执行 -PROT_READ //页内容可以被读取 -PROT_WRITE //页可以被写入 -PROT_NONE //页不可访问 
flags:指定映射对象的类型 
—-MAP_FIXED 
—-MAP_SHARED 与其它所有映射这个对象的进程共享映射空间 
—-MAP_PRIVATE 建立一个写入时拷贝的私有映射。内存区域的写入不会影响到原
文件 
—-MAP_ANONYMOUS 匿名映射,映射区不与任何文件关联 
fd:如果MAP_ANONYMOUS被设定,为了兼容问题,其值应为-1 
offset:被映射对象内容的起点

2、用户释放 munmap

int munmap(void *start, size_t length); 

3、内核里的mmap

内核空间的mmap函数原型为:

在file_operations结构体里有其成员,需要字符设备作为桥梁

int (*map)(struct file *filp, struct vm_area_struct *vma); 

参数struct vm_area_struct就是内核为我们找到的用户空间的
进程虚拟内存区域,这就是我驱动程序需要映射到设备内存的地址。

作用是实现用户进程中的地址与内核中物理页面的映射

mmap函数原型内需要的操作remap_pfn_range():

使用remap_pfn_range一次建立所有页表;
int remap_pfn_range(struct vm_area_struct *vma, 
					unsigned long addr,
					unsigned long pfn, //物理地址,如为虚地址应通过virt_to_phys()进行转换
					unsigned long size, 
					pgprot_t prot)

vma:用户虚拟内存区域指针, 用户进程创建一个VMA区域
addr:用户虚拟地址的起始值----vma->vm_start
pfn:对应虚拟地址应当被映射的物理地址所在的物理页帧号,可将物理地址
>>PAGE_SHIFT得到。 LINUX 的页,一页占用4KB,所以PAGE_SHIFT等于12
size:要映射的区域的大小---- vma->vm_end-vma->vm_start
prot:VMA的保护属性---PAGE_SHARED
  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值